Implement audio mixing
This commit is contained in:
Binary file not shown.
@@ -6,6 +6,15 @@ Room
|
|||||||
0D00DD0pD0
|
0D00DD0pD0
|
||||||
GGGGGGGGGG
|
GGGGGGGGGG
|
||||||
|
|
||||||
|
Room
|
||||||
|
5555555555
|
||||||
|
0000000000
|
||||||
|
0000000000
|
||||||
|
00t0000t00
|
||||||
|
0d00000p00
|
||||||
|
GGGGGGGGGG
|
||||||
|
|
||||||
|
|
||||||
Room
|
Room
|
||||||
5555555555
|
5555555555
|
||||||
00t00p0t00
|
00t00p0t00
|
||||||
@@ -14,6 +23,14 @@ Room
|
|||||||
000lggggl0
|
000lggggl0
|
||||||
GGGGggggGG
|
GGGGggggGG
|
||||||
|
|
||||||
|
Room
|
||||||
|
5555555555
|
||||||
|
00t00pdt00
|
||||||
|
000lGGGGl0
|
||||||
|
000lggggl0
|
||||||
|
000lggggl0
|
||||||
|
GGGGggggGG
|
||||||
|
|
||||||
Room
|
Room
|
||||||
0000000000
|
0000000000
|
||||||
00t00p0t00
|
00t00p0t00
|
||||||
@@ -22,6 +39,14 @@ Room
|
|||||||
0lDDDgDDDl
|
0lDDDgDDDl
|
||||||
GGGGGGGGGG
|
GGGGGGGGGG
|
||||||
|
|
||||||
|
Room
|
||||||
|
0000000000
|
||||||
|
00t00p0t00
|
||||||
|
0lg00g00gl
|
||||||
|
0l000g000l
|
||||||
|
0lDdDgDdDl
|
||||||
|
GGGGGGGGGG
|
||||||
|
|
||||||
Room
|
Room
|
||||||
0000000000
|
0000000000
|
||||||
00t0000t00
|
00t0000t00
|
||||||
@@ -29,3 +54,11 @@ Room
|
|||||||
00gggggg00
|
00gggggg00
|
||||||
0gggggggg0
|
0gggggggg0
|
||||||
GggggggggG
|
GggggggggG
|
||||||
|
|
||||||
|
Room
|
||||||
|
0000000000
|
||||||
|
00t0000t00
|
||||||
|
00000pd000
|
||||||
|
00gggggg00
|
||||||
|
0gggggggg0
|
||||||
|
GggggggggG
|
||||||
@@ -6,6 +6,14 @@ Room
|
|||||||
0tp00000t0
|
0tp00000t0
|
||||||
GGGGPPPPGG
|
GGGGPPPPGG
|
||||||
|
|
||||||
|
Room
|
||||||
|
0000000000
|
||||||
|
0000000000
|
||||||
|
00t00000t0
|
||||||
|
0000000000
|
||||||
|
0dp0000000
|
||||||
|
GGGGPPPPGG
|
||||||
|
|
||||||
Room
|
Room
|
||||||
0000000000
|
0000000000
|
||||||
0000000000
|
0000000000
|
||||||
@@ -21,3 +29,11 @@ Room
|
|||||||
0t000000t0
|
0t000000t0
|
||||||
000000p000
|
000000p000
|
||||||
GPPGPPGPPG
|
GPPGPPGPPG
|
||||||
|
|
||||||
|
Room
|
||||||
|
0000000000
|
||||||
|
0000000000
|
||||||
|
0000000000
|
||||||
|
0t000000t0
|
||||||
|
000d00p000
|
||||||
|
GPPGPPGPPG
|
||||||
|
|||||||
@@ -6,6 +6,15 @@ Room
|
|||||||
0000l0p000
|
0000l0p000
|
||||||
GGGGGGGGGG
|
GGGGGGGGGG
|
||||||
|
|
||||||
|
Room
|
||||||
|
0000l00000
|
||||||
|
0000l00000
|
||||||
|
0000l00000
|
||||||
|
0t00l000t0
|
||||||
|
000dldp000
|
||||||
|
GGGGGGGGGG
|
||||||
|
|
||||||
|
|
||||||
Room
|
Room
|
||||||
0000l00000
|
0000l00000
|
||||||
00t0l00t00
|
00t0l00t00
|
||||||
@@ -13,3 +22,11 @@ Room
|
|||||||
0l000000l0
|
0l000000l0
|
||||||
0l00p000l0
|
0l00p000l0
|
||||||
GGGGGGGGGG
|
GGGGGGGGGG
|
||||||
|
|
||||||
|
Room
|
||||||
|
0000l00000
|
||||||
|
00t0l00t00
|
||||||
|
0lggggggl0
|
||||||
|
0l000000l0
|
||||||
|
0ld0p000l0
|
||||||
|
GGGGGGGGGG
|
||||||
@@ -6,6 +6,14 @@ Room
|
|||||||
0p00l00000
|
0p00l00000
|
||||||
GGPPlPPPGG
|
GGPPlPPPGG
|
||||||
|
|
||||||
|
Room
|
||||||
|
0000l00000
|
||||||
|
0000l00000
|
||||||
|
0000l00000
|
||||||
|
0t00l000t0
|
||||||
|
0p00l0d000
|
||||||
|
GGPPlPPPGG
|
||||||
|
|
||||||
Room
|
Room
|
||||||
0000l00000
|
0000l00000
|
||||||
0t00l000t0
|
0t00l000t0
|
||||||
@@ -13,3 +21,11 @@ ggggggglgg
|
|||||||
0000000l00
|
0000000l00
|
||||||
0000l0pl00
|
0000l0pl00
|
||||||
GGPPlGGGGG
|
GGPPlGGGGG
|
||||||
|
|
||||||
|
Room
|
||||||
|
0000l00000
|
||||||
|
0t00l000t0
|
||||||
|
ggggggglgg
|
||||||
|
0000000l00
|
||||||
|
0d00l0pl00
|
||||||
|
GGPPlGGGGG
|
||||||
|
|||||||
+4
-3
@@ -3,17 +3,18 @@
|
|||||||
SRCS = \
|
SRCS = \
|
||||||
src/Alarm.cpp \
|
src/Alarm.cpp \
|
||||||
src/App.cpp \
|
src/App.cpp \
|
||||||
|
src/AudioManager.cpp \
|
||||||
src/Common.cpp \
|
src/Common.cpp \
|
||||||
|
src/DigitManager.cpp \
|
||||||
src/Entity.cpp \
|
src/Entity.cpp \
|
||||||
src/EntityManager.cpp \
|
src/EntityManager.cpp \
|
||||||
src/FileManager.cpp \
|
src/FileManager.cpp \
|
||||||
|
src/FontManager.cpp \
|
||||||
src/Gridmap.cpp \
|
src/Gridmap.cpp \
|
||||||
src/Main.cpp \
|
src/Main.cpp \
|
||||||
src/RenderManager.cpp \
|
src/RenderManager.cpp \
|
||||||
|
src/RoomEntity.cpp \
|
||||||
src/SpriteManager.cpp \
|
src/SpriteManager.cpp \
|
||||||
src/State.cpp \
|
src/State.cpp \
|
||||||
src/SurfaceManager.cpp \
|
src/SurfaceManager.cpp \
|
||||||
src/FontManager.cpp \
|
|
||||||
src/DigitManager.cpp \
|
|
||||||
src/RoomEntity.cpp \
|
|
||||||
src/Variable.cpp
|
src/Variable.cpp
|
||||||
+10
@@ -26,6 +26,7 @@ TApp::TApp() {
|
|||||||
EntityManager_ = std::make_unique<TEntityManager>(*RenderManager_, 1000 / 60);
|
EntityManager_ = std::make_unique<TEntityManager>(*RenderManager_, 1000 / 60);
|
||||||
FontManager_ = std::make_unique<TFontManager>(*SpriteManager_);
|
FontManager_ = std::make_unique<TFontManager>(*SpriteManager_);
|
||||||
DigitManager_ = std::make_unique<TDigitManager>(*SpriteManager_);
|
DigitManager_ = std::make_unique<TDigitManager>(*SpriteManager_);
|
||||||
|
AudioManager_ = std::make_unique<TAudioManager>(*FileManager_);
|
||||||
}
|
}
|
||||||
|
|
||||||
TApp::~TApp() {
|
TApp::~TApp() {
|
||||||
@@ -43,6 +44,7 @@ void TApp::Process() {
|
|||||||
RenderManager_->Reset();
|
RenderManager_->Reset();
|
||||||
EntityManager_->Run();
|
EntityManager_->Run();
|
||||||
RenderManager_->Run();
|
RenderManager_->Run();
|
||||||
|
AudioManager_->Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
int TApp::Run() {
|
int TApp::Run() {
|
||||||
@@ -86,6 +88,10 @@ TDigitManager& TApp::DigitManager() {
|
|||||||
return *DigitManager_;
|
return *DigitManager_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TAudioManager& TApp::AudioManager() {
|
||||||
|
return *AudioManager_;
|
||||||
|
}
|
||||||
|
|
||||||
const TFileManager& TApp::FileManager() const {
|
const TFileManager& TApp::FileManager() const {
|
||||||
return *FileManager_;
|
return *FileManager_;
|
||||||
}
|
}
|
||||||
@@ -114,4 +120,8 @@ const TDigitManager& TApp::DigitManager() const {
|
|||||||
return *DigitManager_;
|
return *DigitManager_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TAudioManager& TApp::AudioManager() const {
|
||||||
|
return *AudioManager_;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace NGame
|
} // namespace NGame
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include "AudioManager.h"
|
||||||
#include "DigitManager.h"
|
#include "DigitManager.h"
|
||||||
#include "EntityManager.h"
|
#include "EntityManager.h"
|
||||||
#include "FileManager.h"
|
#include "FileManager.h"
|
||||||
@@ -35,6 +36,7 @@ public:
|
|||||||
TSpriteManager& SpriteManager();
|
TSpriteManager& SpriteManager();
|
||||||
TFontManager& FontManager();
|
TFontManager& FontManager();
|
||||||
TDigitManager& DigitManager();
|
TDigitManager& DigitManager();
|
||||||
|
TAudioManager& AudioManager();
|
||||||
|
|
||||||
const TFileManager& FileManager() const;
|
const TFileManager& FileManager() const;
|
||||||
const TRenderManager& RenderManager() const;
|
const TRenderManager& RenderManager() const;
|
||||||
@@ -43,6 +45,7 @@ public:
|
|||||||
const TSpriteManager& SpriteManager() const;
|
const TSpriteManager& SpriteManager() const;
|
||||||
const TFontManager& FontManager() const;
|
const TFontManager& FontManager() const;
|
||||||
const TDigitManager& DigitManager() const;
|
const TDigitManager& DigitManager() const;
|
||||||
|
const TAudioManager& AudioManager() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TApp();
|
TApp();
|
||||||
@@ -57,6 +60,7 @@ private:
|
|||||||
std::unique_ptr<TSpriteManager> SpriteManager_;
|
std::unique_ptr<TSpriteManager> SpriteManager_;
|
||||||
std::unique_ptr<TFontManager> FontManager_;
|
std::unique_ptr<TFontManager> FontManager_;
|
||||||
std::unique_ptr<TDigitManager> DigitManager_;
|
std::unique_ptr<TDigitManager> DigitManager_;
|
||||||
|
std::unique_ptr<TAudioManager> AudioManager_;
|
||||||
TState State_;
|
TState State_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
#include "AudioManager.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace NGame {
|
||||||
|
|
||||||
|
TAudioManager::TAudioManager(TFileManager& fileManager)
|
||||||
|
: FileManager_(fileManager) {
|
||||||
|
|
||||||
|
SDL_AudioSpec desired;
|
||||||
|
desired.freq = 44100;
|
||||||
|
desired.format = AUDIO_F32;
|
||||||
|
desired.channels = 2;
|
||||||
|
desired.samples = 4096;
|
||||||
|
desired.callback = NULL;
|
||||||
|
|
||||||
|
Device_ = SDL_OpenAudioDevice(NULL, 0, &desired, NULL, 0);
|
||||||
|
if (!Device_) {
|
||||||
|
throw std::runtime_error("no audio device");
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream_ = SDL_NewAudioStream(AUDIO_U8, 1, 22050, AUDIO_F32, 2, 44100);
|
||||||
|
if (!Stream_) {
|
||||||
|
throw std::runtime_error("can't create audio stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < 16; ++i) {
|
||||||
|
Channels_[i].InUse = false;
|
||||||
|
}
|
||||||
|
SDL_PauseAudioDevice(Device_, SDL_FALSE);
|
||||||
|
|
||||||
|
LastTick_ = SDL_GetTicks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TAudioManager::Run() {
|
||||||
|
std::uint32_t currentTick = SDL_GetTicks();
|
||||||
|
|
||||||
|
Paint(Stream_, currentTick - LastTick_);
|
||||||
|
if (SDL_GetQueuedAudioSize(Device_) < 8192) {
|
||||||
|
const int bytesRemaining = SDL_AudioStreamAvailable(Stream_);
|
||||||
|
if (bytesRemaining > 0) {
|
||||||
|
const int samplesRemaining = SDL_min(bytesRemaining, 32 * 1024);
|
||||||
|
static Uint8 convertedBuffer[32 * 1024];
|
||||||
|
auto bytesRead = SDL_AudioStreamGet(Stream_, convertedBuffer, samplesRemaining);
|
||||||
|
SDL_QueueAudio(Device_, convertedBuffer, bytesRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LastTick_ = currentTick;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TAudioManager::Play(const std::string& path) {
|
||||||
|
TSound* sound = Load(path);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < 16; i++) {
|
||||||
|
if (Channels_[i].InUse) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Channels_[i].InUse = true;
|
||||||
|
Channels_[i].Position = 0;
|
||||||
|
Channels_[i].Sound = sound;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TAudioManager::Paint(SDL_AudioStream* stream, std::uint32_t ticks) {
|
||||||
|
std::uint8_t temporary[512];
|
||||||
|
std::size_t samples = std::min((ticks * 22050 + 999) / 1000, 512u);
|
||||||
|
|
||||||
|
// Mix
|
||||||
|
for (size_t i = 0; i < samples; ++i) {
|
||||||
|
int16_t accumulator = 0;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < 16; j++) {
|
||||||
|
auto& channel = Channels_[j];
|
||||||
|
if (!channel.InUse) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
accumulator += channel.Sound->Data[channel.Position];
|
||||||
|
accumulator -= 128;
|
||||||
|
channel.Position++;
|
||||||
|
|
||||||
|
if (channel.Position > channel.Sound->Size) {
|
||||||
|
channel.InUse = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accumulator += 128;
|
||||||
|
if (accumulator < 0) {
|
||||||
|
accumulator = 0;
|
||||||
|
}
|
||||||
|
if (accumulator > 255) {
|
||||||
|
accumulator = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
temporary[i] = accumulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output
|
||||||
|
if (samples > 0) {
|
||||||
|
SDL_AudioStreamPut(stream, temporary, samples * sizeof (std::uint8_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TAudioManager::TSound* TAudioManager::Load(const std::string& path) {
|
||||||
|
auto it = Sounds_.find(path);
|
||||||
|
if (it != Sounds_.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSound* newSound = new TSound;
|
||||||
|
auto data = FileManager_.Get(path);
|
||||||
|
SDL_RWops* rw = SDL_RWFromConstMem(data.data(), data.size());
|
||||||
|
if (!SDL_LoadWAV_RW(rw, 1, &newSound->Spec, &newSound->Data, &newSound->Size)) {
|
||||||
|
throw std::runtime_error("can't read WAV file " + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newSound->Spec.channels != 1) {
|
||||||
|
throw std::runtime_error("not mono WAV file " + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newSound->Spec.format != AUDIO_U8) {
|
||||||
|
throw std::runtime_error("not 8bit pcm WAV file " + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newSound->Spec.freq != 22050) {
|
||||||
|
throw std::runtime_error("not 22050hz WAV file " + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Sounds_[path] = newSound;
|
||||||
|
return newSound;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace NGame
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include "FileManager.h"
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
namespace NGame {
|
||||||
|
|
||||||
|
class TAudioManager {
|
||||||
|
public:
|
||||||
|
TAudioManager(TFileManager& fileManager);
|
||||||
|
DELETE_COPY(TAudioManager)
|
||||||
|
|
||||||
|
void Run();
|
||||||
|
void Play(const std::string& sound);
|
||||||
|
void Paint(SDL_AudioStream* stream, std::uint32_t ticks);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct TSound {
|
||||||
|
SDL_AudioSpec Spec;
|
||||||
|
std::uint8_t* Data;
|
||||||
|
std::uint32_t Size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TSoundChannel {
|
||||||
|
bool InUse;
|
||||||
|
TSound* Sound;
|
||||||
|
std::uint32_t Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
TSound* Load(const std::string& sound);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TFileManager& FileManager_;
|
||||||
|
TSoundChannel Channels_[16];
|
||||||
|
std::unordered_map<std::string, TSound*> Sounds_;
|
||||||
|
SDL_AudioDeviceID Device_;
|
||||||
|
SDL_AudioStream* Stream_;
|
||||||
|
std::uint32_t LastTick_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace NGame
|
||||||
+1
-1
@@ -53,7 +53,7 @@ static void MainLoop(void) {
|
|||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
SDL_Init(SDL_INIT_VIDEO);
|
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
|
||||||
|
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
|
|
||||||
|
|||||||
+143
-28
@@ -120,6 +120,8 @@ TExplosionEntity::TExplosionEntity(NGame::TEntity::TId id)
|
|||||||
SetSize({64, 64});
|
SetSize({64, 64});
|
||||||
Sprite_ = NGame::TApp::Instance()->SpriteManager().Get("Sprites/Light.txt");
|
Sprite_ = NGame::TApp::Instance()->SpriteManager().Get("Sprites/Light.txt");
|
||||||
Alarm_.Set(0, 50);
|
Alarm_.Set(0, 50);
|
||||||
|
|
||||||
|
App_->AudioManager().Play("Audio/Explosion2.wav");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TExplosionEntity::Update(std::uint32_t delta) {
|
void TExplosionEntity::Update(std::uint32_t delta) {
|
||||||
@@ -191,10 +193,15 @@ void TMineEntity::Update(std::uint32_t delta) {
|
|||||||
switch (State_) {
|
switch (State_) {
|
||||||
case Dormant:
|
case Dormant:
|
||||||
if (!entityManager.IsPlaceEmpty(Position() + Size() / 2 - TriggerRadius_ / 2, TriggerRadius_, HERO_GROUP)) {
|
if (!entityManager.IsPlaceEmpty(Position() + Size() / 2 - TriggerRadius_ / 2, TriggerRadius_, HERO_GROUP)) {
|
||||||
Remaining_ = rand() % 5 + 5;
|
if (App_->State().Variable("InstantMines").Bool()) {
|
||||||
if (!(Remaining_ % 2)) {
|
Remaining_ = 1;
|
||||||
Remaining_ += 1;
|
} else {
|
||||||
|
Remaining_ = rand() % 3 + 7;
|
||||||
|
if (!(Remaining_ % 2)) {
|
||||||
|
Remaining_ += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Alarm_.Set(0, 100);
|
Alarm_.Set(0, 100);
|
||||||
State_ = Active;
|
State_ = Active;
|
||||||
}
|
}
|
||||||
@@ -232,6 +239,9 @@ void TMineEntity::Alarm(NGame::TAlarm::TId id) {
|
|||||||
if (Remaining_) {
|
if (Remaining_) {
|
||||||
--Remaining_;
|
--Remaining_;
|
||||||
}
|
}
|
||||||
|
if (AlternateBlink_) {
|
||||||
|
App_->AudioManager().Play("Audio/Select.wav");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -671,8 +681,14 @@ THero::THero(NGame::TEntity::TId id)
|
|||||||
SetSize(NGame::Vec2i(4, 12));
|
SetSize(NGame::Vec2i(4, 12));
|
||||||
SetPosition(NGame::Vec2i(0, 0));
|
SetPosition(NGame::Vec2i(0, 0));
|
||||||
SetCollisionGroup(HERO_GROUP);
|
SetCollisionGroup(HERO_GROUP);
|
||||||
NGame::TApp::Instance()->RenderManager().EnableLight(true);
|
|
||||||
NGame::TApp::Instance()->RenderManager().SetDefaultLightColor(0, 0, 0);
|
if (App_->State().Variable("DarkLevel").Bool()) {
|
||||||
|
NGame::TApp::Instance()->RenderManager().EnableLight(true);
|
||||||
|
NGame::TApp::Instance()->RenderManager().SetDefaultLightColor(0, 0, 0);
|
||||||
|
} else {
|
||||||
|
NGame::TApp::Instance()->RenderManager().EnableLight(false);
|
||||||
|
NGame::TApp::Instance()->RenderManager().SetDefaultLightColor(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
Alarm_.Set(0, 100);
|
Alarm_.Set(0, 100);
|
||||||
|
|
||||||
@@ -687,6 +703,9 @@ THero::THero(NGame::TEntity::TId id)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RemainingTime_ = App_->State().Variable("Time").Double();
|
||||||
|
Grenades_ = App_->State().Variable("Grenades").Int();
|
||||||
}
|
}
|
||||||
|
|
||||||
void THero::Input(SDL_Event* event) {
|
void THero::Input(SDL_Event* event) {
|
||||||
@@ -781,16 +800,19 @@ void THero::Update(std::uint32_t delta) {
|
|||||||
Speed_.X = -100;
|
Speed_.X = -100;
|
||||||
}
|
}
|
||||||
if (KeysPressed_[static_cast<int>(EKeys::X)]) {
|
if (KeysPressed_[static_cast<int>(EKeys::X)]) {
|
||||||
auto entity = entityManager.MakeEntityByName("GrenadeEntity");
|
if (Grenades_) {
|
||||||
auto targetEntity = dynamic_cast<TGrenadeEntity*>(entity.get());
|
Grenades_--;
|
||||||
|
auto entity = entityManager.MakeEntityByName("GrenadeEntity");
|
||||||
|
auto targetEntity = dynamic_cast<TGrenadeEntity*>(entity.get());
|
||||||
|
|
||||||
targetEntity->SetPosition(Position());
|
targetEntity->SetPosition(Position());
|
||||||
if (FaceLeft_) {
|
if (FaceLeft_) {
|
||||||
targetEntity->SetSpeed({-300, 0});
|
targetEntity->SetSpeed({-300, 0});
|
||||||
} else {
|
} else {
|
||||||
targetEntity->SetSpeed({300, 0});
|
targetEntity->SetSpeed({300, 0});
|
||||||
|
}
|
||||||
|
entityManager.UpdateCollision(entity);
|
||||||
}
|
}
|
||||||
entityManager.UpdateCollision(entity);
|
|
||||||
}
|
}
|
||||||
if (KeysPressed_[static_cast<int>(EKeys::Up)]) {
|
if (KeysPressed_[static_cast<int>(EKeys::Up)]) {
|
||||||
auto otherIds = entityManager.CollisionList(Position(), Size(), PASSAGE_GROUP, Id());
|
auto otherIds = entityManager.CollisionList(Position(), Size(), PASSAGE_GROUP, Id());
|
||||||
@@ -798,18 +820,13 @@ void THero::Update(std::uint32_t delta) {
|
|||||||
for (auto otherId : otherIds) {
|
for (auto otherId : otherIds) {
|
||||||
auto other = entityManager.Entity(otherId);
|
auto other = entityManager.Entity(otherId);
|
||||||
if (dynamic_cast<TExitEntity*>(other.get())) {
|
if (dynamic_cast<TExitEntity*>(other.get())) {
|
||||||
|
App_->State().Variable("Time").SetDouble(RemainingTime_);
|
||||||
|
App_->State().Variable("Grenades").SetInt(Grenades_);
|
||||||
entityManager.AddToDeferred("EulaMenu");
|
entityManager.AddToDeferred("EulaMenu");
|
||||||
entityManager.Reset();
|
entityManager.Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (KeysPressed_[static_cast<int>(EKeys::C)]) {
|
|
||||||
auto entity = entityManager.MakeEntityByName("FloatingTextEntity");
|
|
||||||
auto targetEntity = dynamic_cast<TFloatingTextEntity*>(entity.get());
|
|
||||||
targetEntity->SetText("You died, LMAO");
|
|
||||||
targetEntity->SetColor(NGame::TFontManager::Red);
|
|
||||||
targetEntity->SetPosition(Position());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entityManager.IsPlaceEmpty(Position(), Size(), LADDER_GROUP)) {
|
if (!entityManager.IsPlaceEmpty(Position(), Size(), LADDER_GROUP)) {
|
||||||
if (KeysHeld_[static_cast<int>(EKeys::Up)] || KeysHeld_[static_cast<int>(EKeys::Down)]) {
|
if (KeysHeld_[static_cast<int>(EKeys::Up)] || KeysHeld_[static_cast<int>(EKeys::Down)]) {
|
||||||
@@ -829,6 +846,7 @@ void THero::Update(std::uint32_t delta) {
|
|||||||
if (KeysPressed_[static_cast<int>(EKeys::Z)]) {
|
if (KeysPressed_[static_cast<int>(EKeys::Z)]) {
|
||||||
Speed_.Y = -std::sqrt(2 * Gravity_ * (16 + (16 - Size().Y)));
|
Speed_.Y = -std::sqrt(2 * Gravity_ * (16 + (16 - Size().Y)));
|
||||||
State_ = EState::Jump;
|
State_ = EState::Jump;
|
||||||
|
App_->AudioManager().Play("Audio/jump.wav");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -972,6 +990,18 @@ void THero::Update(std::uint32_t delta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (State_ != EState::Dead) {
|
||||||
|
RemainingTime_ -= delta;
|
||||||
|
if (RemainingTime_ < 0) {
|
||||||
|
RemainingTime_ = 0;
|
||||||
|
App_->AudioManager().Play("Audio/Laser.wav");
|
||||||
|
State_ = EState::Dead;
|
||||||
|
if (!Alarm_.IsSet(1)) {
|
||||||
|
Alarm_.Set(1, 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Explictly check damage sources and flick the body around the screen
|
// Explictly check damage sources and flick the body around the screen
|
||||||
{
|
{
|
||||||
auto entityList = entityManager.CollisionList(Position(), Size(), DAMAGE_GROUP, Id());
|
auto entityList = entityManager.CollisionList(Position(), Size(), DAMAGE_GROUP, Id());
|
||||||
@@ -1009,6 +1039,7 @@ void THero::Update(std::uint32_t delta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (previousState != State_) {
|
if (previousState != State_) {
|
||||||
|
App_->AudioManager().Play("Audio/Laser.wav");
|
||||||
if (!Alarm_.IsSet(1)) {
|
if (!Alarm_.IsSet(1)) {
|
||||||
Alarm_.Set(1, 3000);
|
Alarm_.Set(1, 3000);
|
||||||
}
|
}
|
||||||
@@ -1067,7 +1098,11 @@ void THero::Update(std::uint32_t delta) {
|
|||||||
if (!moveResult.second.second) {
|
if (!moveResult.second.second) {
|
||||||
// Fall damage
|
// Fall damage
|
||||||
if (App_->State().Variable("FallDamage").Bool() && (Position().Y - LastStablePosition_.Y > 40)) {
|
if (App_->State().Variable("FallDamage").Bool() && (Position().Y - LastStablePosition_.Y > 40)) {
|
||||||
|
App_->AudioManager().Play("Audio/Laser.wav");
|
||||||
State_ = EState::Dead;
|
State_ = EState::Dead;
|
||||||
|
if (!Alarm_.IsSet(1)) {
|
||||||
|
Alarm_.Set(1, 3000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Speed_.Y = 0;
|
Speed_.Y = 0;
|
||||||
@@ -1123,6 +1158,16 @@ void THero::Draw() const {
|
|||||||
auto light = SpriteManager_.Get("Sprites/Light.txt");
|
auto light = SpriteManager_.Get("Sprites/Light.txt");
|
||||||
SpriteManager_.Draw(light, 0, Position() - (light->Frames[0].Size * 4 / 2), {4, 4});
|
SpriteManager_.Draw(light, 0, Position() - (light->Frames[0].Size * 4 / 2), {4, 4});
|
||||||
|
|
||||||
|
RenderManager_.SetLayer(NGame::TRenderManager::Interface);
|
||||||
|
RenderManager_.SetColor(0, 0, 0, 128);
|
||||||
|
RenderManager_.DrawRect({0, 0}, {320, 16}, true);
|
||||||
|
App_->DigitManager().Draw({320 - 48 - 2, 2}, RemainingTime_, 6, 3);
|
||||||
|
|
||||||
|
auto itemSprite = SpriteManager_.Get("Sprites/Grenade.txt");
|
||||||
|
for (std::size_t i = 0; i < Grenades_; i++) {
|
||||||
|
SpriteManager_.Draw(itemSprite, 0, NGame::Vec2i(200 + i * 8, 3));
|
||||||
|
}
|
||||||
|
|
||||||
if (!App_->State().Variable("NoCompas").Bool()) {
|
if (!App_->State().Variable("NoCompas").Bool()) {
|
||||||
auto heroCenter = RenderManager_.Camera() + RenderManager_.Size() / 2;
|
auto heroCenter = RenderManager_.Camera() + RenderManager_.Size() / 2;
|
||||||
auto delta = ExitPosition_ - heroCenter;
|
auto delta = ExitPosition_ - heroCenter;
|
||||||
@@ -1146,22 +1191,19 @@ void THero::Draw() const {
|
|||||||
index = 3;
|
index = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RenderManager_.SetLayer(NGame::TRenderManager::Interface);
|
|
||||||
screenPosition.X = std::min(std::max(screenPosition.X, 0), RenderManager_.Size().X - 16);
|
screenPosition.X = std::min(std::max(screenPosition.X, 0), RenderManager_.Size().X - 16);
|
||||||
screenPosition.Y = std::min(std::max(screenPosition.Y, 16), RenderManager_.Size().Y - 16);
|
screenPosition.Y = std::min(std::max(screenPosition.Y, 16), RenderManager_.Size().Y - 16);
|
||||||
|
|
||||||
auto arrow = SpriteManager_.Get("Sprites/Arrow.txt");
|
auto arrow = SpriteManager_.Get("Sprites/Arrow.txt");
|
||||||
SpriteManager_.Draw(arrow, index, screenPosition);
|
SpriteManager_.Draw(arrow, index, screenPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DisplayEnd_) {
|
if (DisplayEnd_) {
|
||||||
RenderManager_.SetLayer(NGame::TRenderManager::Interface);
|
App_->FontManager().Draw(NGame::TFontManager::Red, {4, 4}, "You are dead! Press X");
|
||||||
App_->FontManager().Draw(NGame::TFontManager::Red, {}, "You are dead! Press X");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FadeAmount_) {
|
if (FadeAmount_) {
|
||||||
RenderManager_.SetLayer(NGame::TRenderManager::Interface);
|
|
||||||
if (WhiteFade_) {
|
if (WhiteFade_) {
|
||||||
RenderManager_.SetColor(255, 255, 255, FadeAmount_);
|
RenderManager_.SetColor(255, 255, 255, FadeAmount_);
|
||||||
} else {
|
} else {
|
||||||
@@ -1174,6 +1216,9 @@ void THero::Draw() const {
|
|||||||
void THero::Alarm(NGame::TAlarm::TId id) {
|
void THero::Alarm(NGame::TAlarm::TId id) {
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
AlternateRun_ = !AlternateRun_;
|
AlternateRun_ = !AlternateRun_;
|
||||||
|
if (AlternateRun_ && Speed_.X && State_ == EState::Normal) {
|
||||||
|
App_->AudioManager().Play("Audio/Walk.wav");
|
||||||
|
}
|
||||||
} else if (id == 1) {
|
} else if (id == 1) {
|
||||||
DisplayEnd_ = true;
|
DisplayEnd_ = true;
|
||||||
}
|
}
|
||||||
@@ -1268,6 +1313,14 @@ void TMainMenu::Input(SDL_Event* event) {
|
|||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
if (event->key.keysym.sym == 'x') {
|
if (event->key.keysym.sym == 'x') {
|
||||||
|
App_->AudioManager().Play("Audio/Pickup.wav");
|
||||||
|
App_->State().Variable("Time").SetDouble(60000);
|
||||||
|
App_->State().Variable("FallDamage").SetBool(false);
|
||||||
|
App_->State().Variable("InstantMines").SetBool(false);
|
||||||
|
App_->State().Variable("LimitedGrenades").SetBool(false);
|
||||||
|
App_->State().Variable("DarkLevel").SetBool(false);
|
||||||
|
App_->State().Variable("NoCompas").SetBool(false);
|
||||||
|
App_->State().Variable("Grenades").SetInt(3);
|
||||||
App_->EntityManager().AddToDeferred("RoomEntity");
|
App_->EntityManager().AddToDeferred("RoomEntity");
|
||||||
App_->EntityManager().Reset();
|
App_->EntityManager().Reset();
|
||||||
}
|
}
|
||||||
@@ -1294,12 +1347,51 @@ TEulaMenu::TEulaMenu(NGame::TEntity::TId id)
|
|||||||
, RenderManager_(App_->RenderManager())
|
, RenderManager_(App_->RenderManager())
|
||||||
, SpriteManager_(App_->SpriteManager()) {
|
, SpriteManager_(App_->SpriteManager()) {
|
||||||
RenderManager_.EnableLight(false);
|
RenderManager_.EnableLight(false);
|
||||||
|
|
||||||
|
std::vector<std::string> toDisableTo;
|
||||||
|
|
||||||
|
if (!App_->State().Variable("FallDamage").Bool()) {
|
||||||
|
toDisableTo.push_back("FallDamage");
|
||||||
|
}
|
||||||
|
if (!App_->State().Variable("InstantMines").Bool()) {
|
||||||
|
toDisableTo.push_back("InstantMines");
|
||||||
|
}
|
||||||
|
if (!App_->State().Variable("LimitedGrenades").Bool()) {
|
||||||
|
toDisableTo.push_back("LimitedGrenades");
|
||||||
|
}
|
||||||
|
if (!App_->State().Variable("DarkLevel").Bool()) {
|
||||||
|
toDisableTo.push_back("DarkLevel");
|
||||||
|
}
|
||||||
|
if (!App_->State().Variable("NoCompas").Bool()) {
|
||||||
|
toDisableTo.push_back("NoCompas");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!toDisableTo.empty()) {
|
||||||
|
Choice_ = toDisableTo[rand() % toDisableTo.size()];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TEulaMenu::Input(SDL_Event* event) {
|
void TEulaMenu::Input(SDL_Event* event) {
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
if (event->key.keysym.sym == 'x') {
|
if (event->key.keysym.sym == 'x') {
|
||||||
|
if (!Choice_.empty()) {
|
||||||
|
App_->State().Variable(Choice_).SetBool(true);
|
||||||
|
|
||||||
|
if (!App_->State().Variable("LimitedGrenades").Bool()) {
|
||||||
|
App_->State().Variable("Grenades").SetInt(3);
|
||||||
|
}
|
||||||
|
App_->AudioManager().Play("Audio/PowerUp.wav");
|
||||||
|
App_->State().Variable("Time").SetDouble(App_->State().Variable("Time").Double() + 30000);
|
||||||
|
App_->EntityManager().AddToDeferred("RoomEntity");
|
||||||
|
App_->EntityManager().Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (event->key.keysym.sym == 'c') {
|
||||||
|
if (!App_->State().Variable("LimitedGrenades").Bool()) {
|
||||||
|
App_->State().Variable("Grenades").SetInt(3);
|
||||||
|
}
|
||||||
|
App_->AudioManager().Play("Audio/Pickup.wav");
|
||||||
App_->EntityManager().AddToDeferred("RoomEntity");
|
App_->EntityManager().AddToDeferred("RoomEntity");
|
||||||
App_->EntityManager().Reset();
|
App_->EntityManager().Reset();
|
||||||
}
|
}
|
||||||
@@ -1313,11 +1405,33 @@ void TEulaMenu::Update(std::uint32_t delta) {
|
|||||||
|
|
||||||
void TEulaMenu::Draw() const {
|
void TEulaMenu::Draw() const {
|
||||||
RenderManager_.SetLayer(NGame::TRenderManager::Interface);
|
RenderManager_.SetLayer(NGame::TRenderManager::Interface);
|
||||||
App_->FontManager().Draw(NGame::TFontManager::Gold, {}, "Press X to gain debuff and continue");
|
|
||||||
|
NGame::Vec2i position = {50, 50};
|
||||||
|
std::string text;
|
||||||
|
|
||||||
|
if (Choice_.empty()) {
|
||||||
|
text = "There is nothing that you can do";
|
||||||
|
text += "\n\nPress C to ingore";
|
||||||
|
App_->FontManager().Draw(NGame::TFontManager::Red, position, text);
|
||||||
|
} else {
|
||||||
|
if (Choice_ == "FallDamage") {
|
||||||
|
text = "Gain 30 seconds, but there will be\nfall damage";
|
||||||
|
} else if (Choice_ == "InstantMines") {
|
||||||
|
text = "Gain 30 seconds, but mines will explode\ninstantly";
|
||||||
|
} else if (Choice_ == "LimitedGrenades") {
|
||||||
|
text = "Gain 30 seconds, but grenades will\nno longer replenish";
|
||||||
|
} else if (Choice_ == "DarkLevel") {
|
||||||
|
text = "Gain 30 seconds, but the cave is now\nshrouded in darkness";
|
||||||
|
} else if (Choice_ == "NoCompas") {
|
||||||
|
text = "Gain 30 seconds, but you lose your compass";
|
||||||
|
}
|
||||||
|
text += "\n\nPress X to accept or C to ingore";
|
||||||
|
App_->FontManager().Draw(NGame::TFontManager::Gold, position, text);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TEulaMenu::Alarm(NGame::TAlarm::TId id) {
|
void TEulaMenu::Alarm(NGame::TAlarm::TId id) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TIntroMenu::TIntroMenu(NGame::TEntity::TId id)
|
TIntroMenu::TIntroMenu(NGame::TEntity::TId id)
|
||||||
@@ -1332,6 +1446,7 @@ void TIntroMenu::Input(SDL_Event* event) {
|
|||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
if (event->key.keysym.sym == 'x') {
|
if (event->key.keysym.sym == 'x') {
|
||||||
|
App_->AudioManager().Play("Audio/Pickup.wav");
|
||||||
App_->EntityManager().AddToDeferred("MainMenu");
|
App_->EntityManager().AddToDeferred("MainMenu");
|
||||||
App_->EntityManager().Reset();
|
App_->EntityManager().Reset();
|
||||||
}
|
}
|
||||||
@@ -1419,7 +1534,7 @@ TGrenadeEntity::TGrenadeEntity(NGame::TEntity::TId id)
|
|||||||
, SpriteManager_(App_->SpriteManager()) {
|
, SpriteManager_(App_->SpriteManager()) {
|
||||||
SetSize(9);
|
SetSize(9);
|
||||||
Sprite_ = NGame::TApp::Instance()->SpriteManager().Get("Sprites/Grenade.txt");
|
Sprite_ = NGame::TApp::Instance()->SpriteManager().Get("Sprites/Grenade.txt");
|
||||||
Alarm_.Set(0, 3000 + rand() % 1000);
|
Alarm_.Set(0, 1000 + rand() % 1000);
|
||||||
Alarm_.Set(1, 100);
|
Alarm_.Set(1, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -319,6 +319,8 @@ private:
|
|||||||
bool DisplayEnd_ = false;
|
bool DisplayEnd_ = false;
|
||||||
bool WhiteFade_ = false;
|
bool WhiteFade_ = false;
|
||||||
std::size_t FadeAmount_ = 0;
|
std::size_t FadeAmount_ = 0;
|
||||||
|
double RemainingTime_ = 0;
|
||||||
|
int Grenades_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TBackgroundTiler : public NGame::TEntity {
|
class TBackgroundTiler : public NGame::TEntity {
|
||||||
@@ -385,6 +387,7 @@ private:
|
|||||||
NGame::TApp* App_;
|
NGame::TApp* App_;
|
||||||
NGame::TSpriteManager& SpriteManager_;
|
NGame::TSpriteManager& SpriteManager_;
|
||||||
NGame::TRenderManager& RenderManager_;
|
NGame::TRenderManager& RenderManager_;
|
||||||
|
std::string Choice_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TIntroMenu : public NGame::TEntity {
|
class TIntroMenu : public NGame::TEntity {
|
||||||
|
|||||||
Reference in New Issue
Block a user