Implement audio mixing

This commit is contained in:
2025-07-20 13:49:53 +03:00
parent 10f9c47929
commit 72fbf406a7
22 changed files with 428 additions and 32 deletions
Binary file not shown.
+33
View File
@@ -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
+16
View File
@@ -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
+17
View File
@@ -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
+16
View File
@@ -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
View File
@@ -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
View File
@@ -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
+4
View File
@@ -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_;
}; };
+137
View File
@@ -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
+44
View File
@@ -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
View File
@@ -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
View File
@@ -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);
} }
+3
View File
@@ -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 {