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,10 +39,26 @@ Room
0lDDDgDDDl 0lDDDgDDDl
GGGGGGGGGG GGGGGGGGGG
Room
0000000000
00t00p0t00
0lg00g00gl
0l000g000l
0lDdDgDdDl
GGGGGGGGGG
Room Room
0000000000 0000000000
00t0000t00 00t0000t00
000D0pD000 000D0pD000
00gggggg00 00gggggg00
0gggggggg0 0gggggggg0
GggggggggG
Room
0000000000
00t0000t00
00000pd000
00gggggg00
0gggggggg0
GggggggggG 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,10 +6,27 @@ Room
0000l0p000 0000l0p000
GGGGGGGGGG GGGGGGGGGG
Room
0000l00000
0000l00000
0000l00000
0t00l000t0
000dldp000
GGGGGGGGGG
Room Room
0000l00000 0000l00000
00t0l00t00 00t0l00t00
0lggggggl0 0lggggggl0
0l000000l0 0l000000l0
0l00p000l0 0l00p000l0
GGGGGGGGGG
Room
0000l00000
00t0l00t00
0lggggggl0
0l000000l0
0ld0p000l0
GGGGGGGGGG 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 {