From 2d63b9c5cc12a218371f19c321cff07f1a7511b7 Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Sat, 2 Sep 2023 13:52:10 -0500 Subject: [PATCH] Implement Game State, transparent button, transparent image button, scenarios 2-8, bugfixes. --- olcCodeJam2023Entry/Constant.cpp | 4 +- olcCodeJam2023Entry/Constant.h | 2 + olcCodeJam2023Entry/GameState.h | 8 + olcCodeJam2023Entry/Image.h | 2 + olcCodeJam2023Entry/Info.txt | 6 +- olcCodeJam2023Entry/Level.h | 1 + olcCodeJam2023Entry/Scenario.cpp | 326 +++++++++++++++- olcCodeJam2023Entry/Scenario.h | 32 +- olcCodeJam2023Entry/Unit.cpp | 5 + olcCodeJam2023Entry/Unit.h | 2 + olcCodeJam2023Entry/VirusAttack.cpp | 351 +++++++++++------- olcCodeJam2023Entry/VirusAttack.h | 29 +- olcCodeJam2023Entry/assets/restart.png | Bin 0 -> 10443 bytes olcCodeJam2023Entry/assets/restartHover.png | Bin 0 -> 772 bytes .../olcCodeJam2023Entry.vcxproj | 1 + .../olcCodeJam2023Entry.vcxproj.filters | 3 + olcCodeJam2023Entry/olcPGEX_QuickGUI.h | 120 +++++- olcCodeJam2023Entry/olcPGEX_SplashScreen.h | 4 +- olcCodeJam2023Entry/olcPGEX_TransformedView.h | 6 + 19 files changed, 751 insertions(+), 151 deletions(-) create mode 100644 olcCodeJam2023Entry/GameState.h create mode 100644 olcCodeJam2023Entry/assets/restart.png create mode 100644 olcCodeJam2023Entry/assets/restartHover.png diff --git a/olcCodeJam2023Entry/Constant.cpp b/olcCodeJam2023Entry/Constant.cpp index 0b45008..f67ec54 100644 --- a/olcCodeJam2023Entry/Constant.cpp +++ b/olcCodeJam2023Entry/Constant.cpp @@ -38,4 +38,6 @@ std::string CONSTANT::MEMORY_ALLOCATOR_BOX_DISPLAY_STRING="Creates a memory allo std::string CONSTANT::MEMORY_ALLOCATOR_BOX_HEADER_STRING="Memory Allocator"; Pixel CONSTANT::INCREASE_VALUE_COLOR={7, 223, 247}; -Pixel CONSTANT::DECREASE_VALUE_COLOR={201, 30, 30}; \ No newline at end of file +Pixel CONSTANT::DECREASE_VALUE_COLOR={201, 30, 30}; + +float CONSTANT::RESTART_BUTTON_HOLD_TIME=2.5; \ No newline at end of file diff --git a/olcCodeJam2023Entry/Constant.h b/olcCodeJam2023Entry/Constant.h index 58a2745..eaa1cec 100644 --- a/olcCodeJam2023Entry/Constant.h +++ b/olcCodeJam2023Entry/Constant.h @@ -43,4 +43,6 @@ public: static Pixel INCREASE_VALUE_COLOR; static Pixel DECREASE_VALUE_COLOR; + + static float RESTART_BUTTON_HOLD_TIME; }; \ No newline at end of file diff --git a/olcCodeJam2023Entry/GameState.h b/olcCodeJam2023Entry/GameState.h new file mode 100644 index 0000000..00b0cac --- /dev/null +++ b/olcCodeJam2023Entry/GameState.h @@ -0,0 +1,8 @@ +#pragma once + + +enum class GameState{ + MAIN_MENU, + GAMEPLAY, + COMPLETED +}; \ No newline at end of file diff --git a/olcCodeJam2023Entry/Image.h b/olcCodeJam2023Entry/Image.h index 75a574e..0250038 100644 --- a/olcCodeJam2023Entry/Image.h +++ b/olcCodeJam2023Entry/Image.h @@ -42,5 +42,7 @@ enum Image{ SEGMENT_BAR, HOODED_FIGURE, SPOOK_HOODED_FIGURE, + RESTART, + RESTART_HOVER, }; diff --git a/olcCodeJam2023Entry/Info.txt b/olcCodeJam2023Entry/Info.txt index c921e44..442cb90 100644 --- a/olcCodeJam2023Entry/Info.txt +++ b/olcCodeJam2023Entry/Info.txt @@ -102,7 +102,8 @@ Stage 4: [Pan over to a collection point] But we can collect bits from the system using these collection points. Simply bring over any unit to these and attach them to it. They will start providing you with system resources to make what you need. -(After attaching a unit to a collection point...) + Remember that the system has limited memory available. You'll always be fighting for free space from the system. +(After attaching two units to collection points...) 2 Left shifters wander into the area. [Pan over to the RAM bank] An ambush...? I, WHAT? -- THIS IS NOT- @@ -128,6 +129,9 @@ Stage 8: (New Scenario Objective: -Defeat all enemy units) + +Create a Restart feature. + Distribution of Collection Points: HEALTH 60 ATKSPD 21 diff --git a/olcCodeJam2023Entry/Level.h b/olcCodeJam2023Entry/Level.h index 67a4e28..d55ad2f 100644 --- a/olcCodeJam2023Entry/Level.h +++ b/olcCodeJam2023Entry/Level.h @@ -33,6 +33,7 @@ struct CPData{ //Large: 1280 struct Level{ + LevelName name=STAGE1; vi2d size={1,1}; Resources player_starting_resources; Resources enemy_starting_resources; diff --git a/olcCodeJam2023Entry/Scenario.cpp b/olcCodeJam2023Entry/Scenario.cpp index c8395e3..905ae9d 100644 --- a/olcCodeJam2023Entry/Scenario.cpp +++ b/olcCodeJam2023Entry/Scenario.cpp @@ -3,19 +3,37 @@ Scenario::Scenario(VirusAttack*game) :game(game){ - dialog.SetVisible(false); } void Scenario::Start(){} void Scenario::_Update(){ initialWaitTimer=std::max(0.f,initialWaitTimer-game->GetElapsedTime()); + waitToContinueTimer=std::max(0.f,waitToContinueTimer-game->GetElapsedTime()); + if(missionCompleted){ + missionCompletedTimer+=game->GetElapsedTime(); + if(game->GetKey(SPACE).bPressed){ + NextLevel(); + } + } + if(!missionCompleted&&MissionCompleted()){ + missionCompleted=true; + waitToContinueTimer=3; + } Update(); } void Scenario::_Draw(){ if(game->objective.length()>0){ - game->DrawShadowStringDecal({4,24},"Objective:"); - game->DrawShadowStringDecal({6,36},game->objective); + game->DrawShadowStringDecal({4,24},missionCompleted?"Objective Complete!":"Objective:",missionCompleted?GREEN:WHITE); + vf2d textSize=game->GetTextSize(game->objective); + game->DrawShadowStringDecal({6,36},game->objective,missionCompleted?GREEN:WHITE); + if(missionCompleted&&initialWaitTimer==0){ + game->FillRectDecal(vf2d{6,36}+vf2d{0,textSize.y/2-1},{textSize.x,3}); + std::string continueText="< Press [Spacebar] to continue >"; + vf2d textScale={2,3}; + vf2d textSize=game->GetTextSizeProp(continueText)*textScale; + game->DrawShadowStringPropDecal(game->GetScreenSize()/2-textSize/2+vf2d{0,72},continueText,{255,255,255,uint8_t(abs(sin(2*missionCompletedTimer))*255)},{0,0,0,uint8_t(abs(sin(2*missionCompletedTimer))*255)},textScale); + } } Draw(); } @@ -38,12 +56,18 @@ void Scenario::MoveCamera(){ camera.Update(game->GetElapsedTime()); } +void Scenario::NextLevel(){} + Stage1::Stage1(VirusAttack*game) :Scenario(game){} void Stage1::Start(){ + state=0; + missionCompleted=false; + dialog.SetVisible(false); game->unitMetersGreyedOut=true; game->playerInControl=false; + game->guideEnabled=false; camera=utils::Camera2D(game->GetScreenSize(),game->game.GetWorldOffset()); camera.SetLazyFollowRate(1); camera.SetMode(utils::Camera2D::Mode::LazyFollow); @@ -97,7 +121,7 @@ void Stage1::Update(){ } }break; case 6:{ - DisplayDialog("The yellow bars represent a unit's Health memory allocation. Make sure there's always at least 1 bit of it."); + DisplayDialog("The yellow bars represent a unit's Health memory allocation. Eliminate it from enemies, and make sure you have at least 1 bit of it."); if(dialog.bPressed){ state=7; } @@ -119,6 +143,300 @@ void Stage1::Update(){ }break; } } +bool Stage1::MissionCompleted(){ + for(auto&u:game->units){ + if(!u->IsFriendly()&&u->IsRAMBank()){ + return false; + } + } + return true; +} void Stage1::Draw(){ dialog.UpdateAndDraw({24,64},game,game->player_resources,game->IMAGES,game->GetTotalUsedMemory(),game->currentLevel->availableMemory); +} +void Stage1::NextLevel(){ + game->levelToLoad=STAGE2; +} + + +Stage2::Stage2(VirusAttack*game) + :Scenario(game){} + +void Stage2::Start(){ + state=0; + missionCompleted=false; + dialog.SetVisible(false); + game->unitMetersGreyedOut=true; + game->limitedBuildOptions=true; + game->guideEnabled=false; + game->playerInControl=false; + camera=utils::Camera2D(game->GetScreenSize(),game->game.GetWorldOffset()); + camera.SetLazyFollowRate(1); + camera.SetMode(utils::Camera2D::Mode::LazyFollow); +} + +void Stage2::Update(){ + switch(state){ + case 0:{ + DisplayDialog("I am the test dialog."); + if(dialog.bPressed){ + dialog.SetVisible(false); + state=1; + } + }break; + } +} +bool Stage2::MissionCompleted(){ + for(auto&u:game->units){ + if(!u->IsFriendly()&&u->IsRAMBank()){ + return false; + } + } + return true; +} +void Stage2::Draw(){ + dialog.UpdateAndDraw({24,64},game,game->player_resources,game->IMAGES,game->GetTotalUsedMemory(),game->currentLevel->availableMemory); +} +void Stage2::NextLevel(){ + game->levelToLoad=STAGE3; +} + +Stage3::Stage3(VirusAttack*game) + :Scenario(game){} + +void Stage3::Start(){ + state=0; + missionCompleted=false; + dialog.SetVisible(false); + game->unitMetersGreyedOut=false; + game->limitedBuildOptions=true; + game->guideEnabled=false; + game->playerInControl=false; + camera=utils::Camera2D(game->GetScreenSize(),game->game.GetWorldOffset()); + camera.SetLazyFollowRate(1); + camera.SetMode(utils::Camera2D::Mode::LazyFollow); +} + +void Stage3::Update(){ + switch(state){ + case 0:{ + DisplayDialog("I am the test dialog."); + if(dialog.bPressed){ + dialog.SetVisible(false); + state=1; + } + }break; + } +} +bool Stage3::MissionCompleted(){ + for(auto&u:game->units){ + if(!u->IsFriendly()&&u->IsRAMBank()){ + return false; + } + } + return true; +} +void Stage3::Draw(){ + dialog.UpdateAndDraw({24,64},game,game->player_resources,game->IMAGES,game->GetTotalUsedMemory(),game->currentLevel->availableMemory); +} +void Stage3::NextLevel(){ + game->levelToLoad=STAGE4; +} + +Stage4::Stage4(VirusAttack*game) + :Scenario(game){} + +void Stage4::Start(){ + state=0; + missionCompleted=false; + dialog.SetVisible(false); + game->unitMetersGreyedOut=false; + game->limitedBuildOptions=false; + game->guideEnabled=true; + game->playerInControl=false; + camera=utils::Camera2D(game->GetScreenSize(),game->game.GetWorldOffset()); + camera.SetLazyFollowRate(1); + camera.SetMode(utils::Camera2D::Mode::LazyFollow); +} + +void Stage4::Update(){ + switch(state){ + case 0:{ + DisplayDialog("I am the test dialog."); + if(dialog.bPressed){ + dialog.SetVisible(false); + state=1; + } + }break; + } +} +bool Stage4::MissionCompleted(){ + for(auto&u:game->units){ + if(!u->IsFriendly()&&u->IsRAMBank()){ + return false; + } + } + return true; +} +void Stage4::Draw(){ + dialog.UpdateAndDraw({24,64},game,game->player_resources,game->IMAGES,game->GetTotalUsedMemory(),game->currentLevel->availableMemory); +} +void Stage4::NextLevel(){ + game->levelToLoad=STAGE5; +} + +Stage5::Stage5(VirusAttack*game) + :Scenario(game){} + +void Stage5::Start(){ + state=0; + missionCompleted=false; + dialog.SetVisible(false); + game->unitMetersGreyedOut=false; + game->limitedBuildOptions=false; + game->guideEnabled=true; + game->playerInControl=true; + camera=utils::Camera2D(game->GetScreenSize(),game->game.GetWorldOffset()); + camera.SetLazyFollowRate(1); + camera.SetMode(utils::Camera2D::Mode::LazyFollow); +} + +void Stage5::Update(){ + switch(state){ + case 0:{ + SetObjective("Defeat all enemy units."); + state=1; + }break; + } +} +bool Stage5::MissionCompleted(){ + for(auto&u:game->units){ + if(!u->IsFriendly()&&u->IsRAMBank()){ + return false; + } + } + return true; +} +void Stage5::Draw(){ + dialog.UpdateAndDraw({24,64},game,game->player_resources,game->IMAGES,game->GetTotalUsedMemory(),game->currentLevel->availableMemory); +} +void Stage5::NextLevel(){ + game->levelToLoad=STAGE6; +} + +Stage6::Stage6(VirusAttack*game) + :Scenario(game){} + +void Stage6::Start(){ + state=0; + missionCompleted=false; + dialog.SetVisible(false); + game->unitMetersGreyedOut=false; + game->limitedBuildOptions=false; + game->guideEnabled=true; + game->playerInControl=true; + camera=utils::Camera2D(game->GetScreenSize(),game->game.GetWorldOffset()); + camera.SetLazyFollowRate(1); + camera.SetMode(utils::Camera2D::Mode::LazyFollow); +} + +void Stage6::Update(){ + switch(state){ + case 0:{ + SetObjective("Defeat all enemy units."); + state=1; + }break; + } +} +bool Stage6::MissionCompleted(){ + for(auto&u:game->units){ + if(!u->IsFriendly()&&u->IsRAMBank()){ + return false; + } + } + return true; +} +void Stage6::Draw(){ + dialog.UpdateAndDraw({24,64},game,game->player_resources,game->IMAGES,game->GetTotalUsedMemory(),game->currentLevel->availableMemory); +} +void Stage6::NextLevel(){ + game->levelToLoad=STAGE7; +} + +Stage7::Stage7(VirusAttack*game) + :Scenario(game){} + +void Stage7::Start(){ + state=0; + missionCompleted=false; + dialog.SetVisible(false); + game->unitMetersGreyedOut=false; + game->limitedBuildOptions=false; + game->guideEnabled=true; + game->playerInControl=true; + camera=utils::Camera2D(game->GetScreenSize(),game->game.GetWorldOffset()); + camera.SetLazyFollowRate(1); + camera.SetMode(utils::Camera2D::Mode::LazyFollow); +} + +void Stage7::Update(){ + switch(state){ + case 0:{ + SetObjective("Defeat all enemy units."); + state=1; + }break; + } +} +bool Stage7::MissionCompleted(){ + for(auto&u:game->units){ + if(!u->IsFriendly()&&u->IsRAMBank()){ + return false; + } + } + return true; +} +void Stage7::Draw(){ + dialog.UpdateAndDraw({24,64},game,game->player_resources,game->IMAGES,game->GetTotalUsedMemory(),game->currentLevel->availableMemory); +} +void Stage7::NextLevel(){ + game->levelToLoad=STAGE8; +} + +Stage8::Stage8(VirusAttack*game) + :Scenario(game){} + +void Stage8::Start(){ + state=0; + missionCompleted=false; + dialog.SetVisible(false); + game->unitMetersGreyedOut=false; + game->limitedBuildOptions=false; + game->guideEnabled=true; + game->playerInControl=true; + camera=utils::Camera2D(game->GetScreenSize(),game->game.GetWorldOffset()); + camera.SetLazyFollowRate(1); + camera.SetMode(utils::Camera2D::Mode::LazyFollow); +} + +void Stage8::Update(){ + switch(state){ + case 0:{ + SetObjective("Defeat all enemy units."); + state=1; + }break; + } +} +bool Stage8::MissionCompleted(){ + for(auto&u:game->units){ + if(!u->IsFriendly()&&u->IsRAMBank()){ + return false; + } + } + return true; +} +void Stage8::Draw(){ + dialog.UpdateAndDraw({24,64},game,game->player_resources,game->IMAGES,game->GetTotalUsedMemory(),game->currentLevel->availableMemory); +} +void Stage8::NextLevel(){ + game->state=GameState::COMPLETED; } \ No newline at end of file diff --git a/olcCodeJam2023Entry/Scenario.h b/olcCodeJam2023Entry/Scenario.h index 91d89a0..18d020b 100644 --- a/olcCodeJam2023Entry/Scenario.h +++ b/olcCodeJam2023Entry/Scenario.h @@ -14,6 +14,8 @@ public: void SetObjective(std::string objective); void SetupCameraTarget(vf2d pos); void MoveCamera(); + virtual bool MissionCompleted()=0; + virtual void NextLevel(); protected: VirusAttack*game; int state=0; @@ -21,12 +23,28 @@ protected: float initialWaitTimer=3; utils::Camera2D camera; vf2d cameraTargetPos={}; + bool missionCompleted=false; + float waitToContinueTimer=0; + float missionCompletedTimer=0; }; -class Stage1:public Scenario{ -public: - Stage1(VirusAttack*game); - void Start()override; - void Update()override; - void Draw()override; -}; \ No newline at end of file +#define SetupStage(StageClass) \ + class StageClass:public Scenario{ \ + public: \ + StageClass(VirusAttack*game); \ + void Start()override; \ + void Update()override; \ + bool MissionCompleted()override; \ + void Draw()override; \ + void NextLevel()override; \ + }; + +SetupStage(Stage1) +SetupStage(Stage2) +SetupStage(Stage3) +SetupStage(Stage4) +SetupStage(Stage5) +SetupStage(Stage6) +SetupStage(Stage7) +SetupStage(Stage8) + diff --git a/olcCodeJam2023Entry/Unit.cpp b/olcCodeJam2023Entry/Unit.cpp index b20f590..fe679f7 100644 --- a/olcCodeJam2023Entry/Unit.cpp +++ b/olcCodeJam2023Entry/Unit.cpp @@ -189,6 +189,7 @@ RAMBank::RAMBank(PixelGameEngine*pge,vf2d pos,std::map>&otherUnits){ @@ -972,4 +973,8 @@ bool Unit::IsAttached(){ Unit*Unit::GetBuildUnit(){ return buildTransformUnit.get(); +} + +bool Unit::IsRAMBank(){ + return isRAMBank; } \ No newline at end of file diff --git a/olcCodeJam2023Entry/Unit.h b/olcCodeJam2023Entry/Unit.h index c454008..7802f4e 100644 --- a/olcCodeJam2023Entry/Unit.h +++ b/olcCodeJam2023Entry/Unit.h @@ -97,6 +97,7 @@ public: void SaveMemory(); bool IsPlatform(); bool IsAttached(); + bool IsRAMBank(); Unit*GetBuildUnit(); Marker health={}; Marker range={}; @@ -135,6 +136,7 @@ protected: bool isPlatform=false; std::unique_ptrbuildTransformUnit; float buildTime=0; + bool isRAMBank=false; private: Renderable targetingLine; Renderable attackingLine; diff --git a/olcCodeJam2023Entry/VirusAttack.cpp b/olcCodeJam2023Entry/VirusAttack.cpp index 6e1e4a9..de2d7a7 100644 --- a/olcCodeJam2023Entry/VirusAttack.cpp +++ b/olcCodeJam2023Entry/VirusAttack.cpp @@ -5,7 +5,7 @@ #define AUDIO_SOURCE_IMPLEMENTATION #define OLC_PGEX_QUICKGUI -//#define SPLASH_ENABLED +#define SPLASH_ENABLED #ifdef SPLASH_ENABLED #define OLC_PGEX_SPLASHSCREEN #endif @@ -64,6 +64,8 @@ void VirusAttack::InitializeImages(){ LoadImage(SEGMENT_BAR,"assets/segmentBar.png",false,false); LoadImage(HOODED_FIGURE,"assets/hooded_figure.png"); LoadImage(SPOOK_HOODED_FIGURE,"assets/spook_hooded_figure.png"); + LoadImage(RESTART,"assets/restart.png"); + LoadImage(RESTART_HOVER,"assets/restartHover.png"); } void VirusAttack::InitializeLevelData(){ @@ -71,6 +73,7 @@ void VirusAttack::InitializeLevelData(){ { //Stage 1 data. LevelName stage=STAGE1; + levelData[stage].name=stage; levelData[stage].cameraStart={96,96}; levelData[stage].worldZoom={1,1}; levelData[stage].scenario=scenarios[0]; @@ -93,12 +96,13 @@ void VirusAttack::InitializeLevelData(){ { //Stage 2 data. LevelName stage=STAGE2; + levelData[stage].name=stage; levelData[stage].cameraStart={96,96}; levelData[stage].worldZoom={1,1}; levelData[stage].size={16,16}; levelData[stage].scenario=scenarios[1]; levelData[stage].levelColor=DARK_GREEN; - levelData[stage].bgm=Sound::COSMOS; + levelData[stage].bgm=Sound::GRAVITY; levelData[stage].player_starting_resources={10,10,10,10,10}; levelData[stage].enemy_starting_resources={0,0,0,0,0}; { @@ -129,6 +133,7 @@ bool VirusAttack::OnUserCreate(){ memoryAllocatorBox.Initialize(CONSTANT::MEMORY_ALLOCATOR_BOX_DISPLAY_STRING,{},CONSTANT::MEMORY_ALLOCATOR_BOX_HEADER_STRING); memoryAllocatorBox.SetVisible(false); platformCreationBox.SetVisible(false); + restartBox.SetVisible(false); IMAGES[MINIMAP_OUTLINE]=std::make_unique(); IMAGES[MINIMAP_OUTLINE]->Create(64,64); @@ -212,6 +217,8 @@ void VirusAttack::LoadLevel(LevelName level){ } void VirusAttack::InitializeGUIs(){ + restartButton=new QuickGUI::TransparentImageButton(restartManager,*IMAGES[RESTART],*IMAGES[RESTART_HOVER],{1,1},{float(ScreenWidth()-32),12.f},{28,28}); + unitCreationList.colNormal = olc::DARK_GREEN; unitCreationList.colHover = olc::GREEN; unitCreationList.colClick = olc::YELLOW; @@ -233,11 +240,22 @@ void VirusAttack::InitializeGUIs(){ unitCreationList.DisplayAllControls(false); platformCreationList.DisplayAllControls(false); + + campaignStartButton=new QuickGUI::TransparentButton(mainMenu,"Start Campaign",{float(ScreenWidth()/2)-120.f,80+47.5f*0+10},{240,24},CONSTANT::INCREASE_VALUE_COLOR); + audioToggleButton=new QuickGUI::TransparentButton(mainMenu,"Audio: On",{float(ScreenWidth()/2)-120.f,80+47.5f*1+10},{240,24},CONSTANT::INCREASE_VALUE_COLOR); + difficultyToggleButton=new QuickGUI::TransparentButton(mainMenu,"Difficulty: Normal",{float(ScreenWidth()/2)-120.f,80+47.5f*2+10},{240,24},CONSTANT::INCREASE_VALUE_COLOR); + exitGameButton=new QuickGUI::TransparentButton(mainMenu,"Exit Game",{float(ScreenWidth()/2)-120.f,80+47.5f*3+10},{240,24},CONSTANT::INCREASE_VALUE_COLOR); } void VirusAttack::InitializeScenarios(){ scenarios.emplace_back(new Stage1(this)); - scenarios.emplace_back(new Stage1(this)); + scenarios.emplace_back(new Stage2(this)); + scenarios.emplace_back(new Stage3(this)); + scenarios.emplace_back(new Stage4(this)); + scenarios.emplace_back(new Stage5(this)); + scenarios.emplace_back(new Stage6(this)); + scenarios.emplace_back(new Stage7(this)); + scenarios.emplace_back(new Stage8(this)); } void VirusAttack::InitializeSounds(){ @@ -285,8 +303,9 @@ bool VirusAttack::UnitCreationClickHandled(){ CheckClick(MemoryGuard,memoryGuardButton,IsPlatform) return false; } -#define EnableAndHoverCheck(UnitClass,Button,box) \ - Button->Enable(CanAfford(player_resources,UnitClass::resourceCost)); \ +#define EnableAndHoverCheck(UnitClass,Button,box,limited) \ + Button->Enable(CanAfford(player_resources,UnitClass::resourceCost)&&(!limited||limited&&!limitedBuildOptions)); \ + if(limited&&!limitedBuildOptions){Button->bVisible=false;} \ if(Button->bHover){ \ box.Initialize(UnitClass::unitDescription, GetMousePos(), UnitClass::unitName,nullptr,{120,36},nullptr,UnitClass::resourceCost); \ hovering=true; \ @@ -295,19 +314,19 @@ bool VirusAttack::UnitCreationClickHandled(){ } else { \ box.SetBackgroundColor(VERY_DARK_GREY/2); \ } \ - } + } void VirusAttack::UpdateUnitCreationListGUI(bool allocatorSelected){ unitCreationList.DisplayAllControls(allocatorSelected); bool hovering=false; - EnableAndHoverCheck(LeftShifter,leftShifterButton,unitCreationBox) - EnableAndHoverCheck(RightShifter,rightShifterButton,unitCreationBox) - EnableAndHoverCheck(BitRestorer,bitRestorerButton,unitCreationBox) - EnableAndHoverCheck(MemorySwapper,memorySwapperButton,unitCreationBox) - EnableAndHoverCheck(BitRestorer,bitRestorerButton,unitCreationBox) - EnableAndHoverCheck(Corrupter,corrupterButton,unitCreationBox) - EnableAndHoverCheck(_Platform,platformButton,unitCreationBox) + EnableAndHoverCheck(LeftShifter,leftShifterButton,unitCreationBox,false) + EnableAndHoverCheck(RightShifter,rightShifterButton,unitCreationBox,false) + EnableAndHoverCheck(BitRestorer,bitRestorerButton,unitCreationBox,true) + EnableAndHoverCheck(MemorySwapper,memorySwapperButton,unitCreationBox,true) + EnableAndHoverCheck(BitRestorer,bitRestorerButton,unitCreationBox,true) + EnableAndHoverCheck(Corrupter,corrupterButton,unitCreationBox,true) + EnableAndHoverCheck(_Platform,platformButton,unitCreationBox,true) if(!hovering){ unitCreationBox.SetVisible(false); @@ -319,10 +338,10 @@ void VirusAttack::UpdateUnitCreationListGUI(bool allocatorSelected){ void VirusAttack::UpdatePlatformCreationListGUI(bool platformSelected){ platformCreationList.DisplayAllControls(platformSelected); bool hovering=false; - EnableAndHoverCheck(RAMBank,ramBankButton,platformCreationBox) - EnableAndHoverCheck(Refresher,refresherButton,platformCreationBox) - EnableAndHoverCheck(Turret,turretButton,platformCreationBox) - EnableAndHoverCheck(MemoryGuard,memoryGuardButton,platformCreationBox) + EnableAndHoverCheck(RAMBank,ramBankButton,platformCreationBox,false) + EnableAndHoverCheck(Refresher,refresherButton,platformCreationBox,true) + EnableAndHoverCheck(Turret,turretButton,platformCreationBox,true) + EnableAndHoverCheck(MemoryGuard,memoryGuardButton,platformCreationBox,true) if(!hovering){ platformCreationBox.SetVisible(false); @@ -649,144 +668,169 @@ void VirusAttack::RenderCollectionPoints(CollectionPoint*cp){ bool VirusAttack::OnUserUpdate(float fElapsedTime){ UpdateMatrixTexture(fElapsedTime); - if(playerInControl){ - HandleDraggingSelection(); - HandleRightClickMove(); - HandlePanAndZoom(fElapsedTime); - HandleMinimapClick(); - } - currentLevel->scenario->_Update(); - AL.vecPos=game.ScreenToWorld(GetScreenSize()/2); - AL.fSoundFXVolume=std::min(1.f,game.GetWorldScale().x); - AL.OnUserUpdate(fElapsedTime); - - for(auto&tile:TileManager::visibleTiles){ - tile.second-=fElapsedTime; - } + switch(state){ + #pragma region MAIN_MENU + case GameState::MAIN_MENU:{ + mainMenu.Update(this); + mainMenu.DrawDecal(this); + }break; + #pragma endregion + #pragma region GAMEPLAY + case GameState::GAMEPLAY:{ + if(playerInControl){ + HandleDraggingSelection(); + HandleRightClickMove(); + HandlePanAndZoom(fElapsedTime); + HandleMinimapClick(); + } + restartManager.Update(this); + HandleRestartButton(fElapsedTime); + PerformLevelTransition(fElapsedTime); + currentLevel->scenario->_Update(); + AL.vecPos=game.ScreenToWorld(GetScreenSize()/2); + AL.fSoundFXVolume=std::min(1.f,game.GetWorldScale().x); + AL.OnUserUpdate(fElapsedTime); + + for(auto&tile:TileManager::visibleTiles){ + tile.second-=fElapsedTime; + } - std::erase_if(TileManager::visibleTiles,[](std::pair key){return key.second<=0;}); + std::erase_if(TileManager::visibleTiles,[](std::pair key){return key.second<=0;}); - CalculateUsedMemory(); - for(auto&u:units){ - u->SaveMemory(); - std::weak_ptrclosestUnit; - float closestDist=999999; - for(auto&u2:units){ - IdentifyClosestTarget(closestUnit,closestDist,u,u2); - CollisionChecking(u,u2); - } - if(u->IsFriendly()){ - for(int y=-2;y<3;y++){ - for(int x=-2;x<3;x++){ - if(abs(x)+abs(y)<=2){ - TileManager::visibleTiles[u->GetPos()/24/4+vi2d(x,y)]=5; + CalculateUsedMemory(); + for(auto&u:units){ + u->SaveMemory(); + std::weak_ptrclosestUnit; + float closestDist=999999; + for(auto&u2:units){ + IdentifyClosestTarget(closestUnit,closestDist,u,u2); + CollisionChecking(u,u2); } + if(u->IsFriendly()){ + for(int y=-2;y<3;y++){ + for(int x=-2;x<3;x++){ + if(abs(x)+abs(y)<=2){ + TileManager::visibleTiles[u->GetPos()/24/4+vi2d(x,y)]=5; + } + } + } + } + u->AttemptAttack(u,closestUnit,units,debuffIcons,IMAGES); + u->_Update(this,SOUNDS,player_resources,enemy_resources,queuedUnits,resourceGainTimer,resourceGainIcons,IMAGES); } - } - } - u->AttemptAttack(u,closestUnit,units,debuffIcons,IMAGES); - u->_Update(this,SOUNDS,player_resources,enemy_resources,queuedUnits,resourceGainTimer,resourceGainIcons,IMAGES); - } - std::erase_if(units,[&](std::shared_ptru){ - if(u->GetHealth()==0){ - u->OnDeath(SOUNDS); - deathAnimations.emplace_back(std::make_unique(this,u->GetPos(),u->GetImage(),*IMAGES[MATRIX],u->IsFriendly())); - return true; - } else { - return false; - } - }); - - for(auto&queuedUnit:queuedUnits){ - units.push_back(std::move(queuedUnit)); - } - - queuedUnits.clear(); - - DrawPartialDecal({0,0},GetScreenSize(),IMAGES[MATRIX]->Decal(),randomBackgroundOffset+game.GetWorldOffset()*(vf2d{32,32}/vf2d(GetScreenSize()))*game.GetWorldScale(),{32,32},Pixel{currentLevel->levelColor.r,currentLevel->levelColor.g,currentLevel->levelColor.b,164}/2); - game.DrawPartialDecal({0,0},WORLD_SIZE*CONSTANT::TILE_SIZE,IMAGES[TILE]->Decal(),{0,0},WORLD_SIZE*CONSTANT::TILE_SIZE,currentLevel->levelColor); + std::erase_if(units,[&](std::shared_ptru){ + if(u->GetHealth()==0){ + u->OnDeath(SOUNDS); + deathAnimations.emplace_back(std::make_unique(this,u->GetPos(),u->GetImage(),*IMAGES[MATRIX],u->IsFriendly())); + return true; + } else { + return false; + } + }); - for(auto&u:units){ - u->DrawRangeIndicator(this,game,IMAGES); - } + for(auto&queuedUnit:queuedUnits){ + units.push_back(std::move(queuedUnit)); + } - for(auto&u:units){ - u->Draw(game,IMAGES); - if(u->IsGuarded()){ - game.DrawDecal(u->GetPos()+vf2d{float(u->GetUnitSize().x/2),-float(u->GetUnitSize().y/2)}-vf2d{float(IMAGES[GUARD_ICON]->Sprite()->width),0.f}*0.375,IMAGES[GUARD_ICON]->Decal(),{0.375,0.375}); - } - } - for(auto&deadUnit:deathAnimations){ - deadUnit->Update(fElapsedTime); - deadUnit->Draw(game,this); - } + queuedUnits.clear(); - std::erase_if(deathAnimations,[](auto&u){return u->IsDone();}); + DrawPartialDecal({0,0},GetScreenSize(),IMAGES[MATRIX]->Decal(),randomBackgroundOffset+game.GetWorldOffset()*(vf2d{32,32}/vf2d(GetScreenSize()))*game.GetWorldScale(),{32,32},Pixel{currentLevel->levelColor.r,currentLevel->levelColor.g,currentLevel->levelColor.b,164}/2); + game.DrawPartialDecal({0,0},WORLD_SIZE*CONSTANT::TILE_SIZE,IMAGES[TILE]->Decal(),{0,0},WORLD_SIZE*CONSTANT::TILE_SIZE,currentLevel->levelColor); - for(auto&collectionPoint:collectionPoints){ - collectionPoint->Update(this,*IMAGES[MATRIX]); - RenderCollectionPoints(collectionPoint.get()); - } + for(auto&u:units){ + u->DrawRangeIndicator(this,game,IMAGES); + } - for(auto&u:units){ - u->DrawUnitDamageStats(this,game,IMAGES); - } + for(auto&u:units){ + u->Draw(game,IMAGES); + if(u->IsGuarded()){ + game.DrawDecal(u->GetPos()+vf2d{float(u->GetUnitSize().x/2),-float(u->GetUnitSize().y/2)}-vf2d{float(IMAGES[GUARD_ICON]->Sprite()->width),0.f}*0.375,IMAGES[GUARD_ICON]->Decal(),{0.375,0.375}); + } + } + for(auto&deadUnit:deathAnimations){ + deadUnit->Update(fElapsedTime); + deadUnit->Draw(game,this); + } - for(DebuffIcon&icon:debuffIcons){ - icon.Update(fElapsedTime); - icon.Draw(game); - } + std::erase_if(deathAnimations,[](auto&u){return u->IsDone();}); - for(ResourceGainIcon&icon:resourceGainIcons){ - icon.Update(fElapsedTime); - icon.Draw(game); - } + for(auto&collectionPoint:collectionPoints){ + collectionPoint->Update(this,*IMAGES[MATRIX]); + RenderCollectionPoints(collectionPoint.get()); + } - std::erase_if(debuffIcons,[](DebuffIcon&icon){return icon.lifetime<=0;}); - std::erase_if(resourceGainIcons,[](ResourceGainIcon&icon){return icon.lifetime<=0;}); + for(auto&u:units){ + u->DrawUnitDamageStats(this,game,IMAGES); + } - for(auto&u:units){ - u->_DrawHud(game,IMAGES,unitMetersGreyedOut); - } + for(DebuffIcon&icon:debuffIcons){ + icon.Update(fElapsedTime); + icon.Draw(game); + } - DrawSelectionRectangle(); - RenderFogOfWar(); + for(ResourceGainIcon&icon:resourceGainIcons){ + icon.Update(fElapsedTime); + icon.Draw(game); + } - unitCreationList.DrawDecal(this); - platformCreationList.DrawDecal(this); + std::erase_if(debuffIcons,[](DebuffIcon&icon){return icon.lifetime<=0;}); + std::erase_if(resourceGainIcons,[](ResourceGainIcon&icon){return icon.lifetime<=0;}); - DrawSystemMemoryBar(fElapsedTime); - DrawResourceBar(fElapsedTime); - DrawDecal({float(ScreenWidth()-74-IMAGES[GUIDE]->Sprite()->width*0.75),float(ScreenHeight()+6-IMAGES[GUIDE]->Sprite()->height*0.75)},IMAGES[GUIDE]->Decal(),{0.75,0.75}); - DrawMinimap(); - currentLevel->scenario->_Draw(); + for(auto&u:units){ + u->_DrawHud(game,IMAGES,unitMetersGreyedOut); + } - unitCreationBox.UpdateAndDraw(GetMousePos()+vi2d{8,-28},this,player_resources,IMAGES,GetTotalUsedMemory(),currentLevel->availableMemory); - testBox.UpdateAndDraw(GetMousePos()-testBox.GetSize()/2,this,player_resources,IMAGES,GetTotalUsedMemory(),currentLevel->availableMemory); - memoryAllocatorBox.UpdateAndDraw(GetMousePos()+vi2d{8,-28},this,player_resources,IMAGES,GetTotalUsedMemory(),currentLevel->availableMemory); - platformCreationBox.UpdateAndDraw(GetMousePos()+vi2d{8,-28},this,player_resources,IMAGES,GetTotalUsedMemory(),currentLevel->availableMemory); + DrawSelectionRectangle(); + RenderFogOfWar(); - std::sort(units.begin(),units.end(),[&](auto&u1,auto&u2){ - float dist1=geom2d::line(u1->GetGhostPos(),GetWorldMousePos()).length(); - float dist2=geom2d::line(u2->GetGhostPos(),GetWorldMousePos()).length(); - return dist1>dist2;}); + unitCreationList.DrawDecal(this); + platformCreationList.DrawDecal(this); + restartManager.DrawDecal(this); - for(auto&u:units){ - if(u->IsGuarded()){ - bool changeOccured=false; - int changedBit=-1; - for(int i=0;imemory.size();i++){ - if(u->memory[i]!=u->savedMemory[i]){ - changeOccured=true; - changedBit=i; - break; + DrawSystemMemoryBar(fElapsedTime); + DrawResourceBar(fElapsedTime); + if(guideEnabled){ + DrawDecal({float(ScreenWidth()-74-IMAGES[GUIDE]->Sprite()->width*0.75),float(ScreenHeight()+6-IMAGES[GUIDE]->Sprite()->height*0.75)},IMAGES[GUIDE]->Decal(),{0.75,0.75}); } - } - if(changeOccured&&util::random(1)<=0.3){ - u->memory[changedBit]=u->savedMemory[changedBit]; - } - } + DrawMinimap(); + currentLevel->scenario->_Draw(); + + unitCreationBox.UpdateAndDraw(GetMousePos()+vi2d{8,-28},this,player_resources,IMAGES,GetTotalUsedMemory(),currentLevel->availableMemory); + testBox.UpdateAndDraw(GetMousePos()-testBox.GetSize()/2,this,player_resources,IMAGES,GetTotalUsedMemory(),currentLevel->availableMemory); + memoryAllocatorBox.UpdateAndDraw(GetMousePos()+vi2d{8,-28},this,player_resources,IMAGES,GetTotalUsedMemory(),currentLevel->availableMemory); + platformCreationBox.UpdateAndDraw(GetMousePos()+vi2d{8,-28},this,player_resources,IMAGES,GetTotalUsedMemory(),currentLevel->availableMemory); + + std::sort(units.begin(),units.end(),[&](auto&u1,auto&u2){ + float dist1=geom2d::line(u1->GetGhostPos(),GetWorldMousePos()).length(); + float dist2=geom2d::line(u2->GetGhostPos(),GetWorldMousePos()).length(); + return dist1>dist2;}); + + for(auto&u:units){ + if(u->IsGuarded()){ + bool changeOccured=false; + int changedBit=-1; + for(int i=0;imemory.size();i++){ + if(u->memory[i]!=u->savedMemory[i]){ + changeOccured=true; + changedBit=i; + break; + } + } + if(changeOccured&&util::random(1)<=0.3){ + u->memory[changedBit]=u->savedMemory[changedBit]; + } + } + } + + DrawPartialDecal({0,0},GetScreenSize(),IMAGES[MATRIX]->Decal(),randomBackgroundOffset+game.GetWorldOffset()*(vf2d{32,32}/vf2d(GetScreenSize()))*game.GetWorldScale(),{32,32},Pixel{currentLevel->levelColor.r,currentLevel->levelColor.g,currentLevel->levelColor.b,uint8_t(levelForegroundFade*255)}/2); + }break; + #pragma endregion + #pragma region COMPLETED + case GameState::COMPLETED:{ + DrawPartialDecal({0,0},GetScreenSize(),IMAGES[MATRIX]->Decal(),randomBackgroundOffset+game.GetWorldOffset()*(vf2d{32,32}/vf2d(GetScreenSize()))*game.GetWorldScale(),{32,32},Pixel{currentLevel->levelColor.r,currentLevel->levelColor.g,currentLevel->levelColor.b,164}/2); + }break; + #pragma endregion } return true; } @@ -1031,6 +1075,45 @@ bool VirusAttack::OnUserDestroy(){ return true; } +void VirusAttack::PerformLevelTransition(float fElapsedTime){ + if(levelToLoad!=currentLevel->name||reloadLevel){ + levelForegroundFade=std::min(1.f,levelForegroundFade+fElapsedTime); + if(levelForegroundFade>=1){ + LoadLevel(levelToLoad); + reloadLevel=false; + } + }else + if(levelForegroundFade>0){ + levelForegroundFade=std::max(0.f,levelForegroundFade-fElapsedTime); + } +} + +void VirusAttack::RestartLevel(){ + reloadLevel=true; +} + +void VirusAttack::HandleRestartButton(float fElapsedTime){ + if(restartButton->bHover){ + restartBox.Initialize("Click and hold to restart the level.",GetMousePos()+vf2d{0,10},"Restart Level",nullptr,{72,1}); + restartBox.SetVisible(true); + if(restartButton->bPressed){ + restartButtonHeldDown=true; + } + if(restartButtonHeldDown){ + restartButtonHoldTime+=fElapsedTime; + if(restartButtonHoldTime>=CONSTANT::RESTART_BUTTON_HOLD_TIME){ + RestartLevel(); + restartButtonHeldDown=false; + restartButtonHoldTime=0; + } + } + }else{ + restartBox.SetVisible(false); + restartButtonHeldDown=false; + restartButtonHoldTime=0; + } +} + int main() { VirusAttack app; diff --git a/olcCodeJam2023Entry/VirusAttack.h b/olcCodeJam2023Entry/VirusAttack.h index 9386846..dea6478 100644 --- a/olcCodeJam2023Entry/VirusAttack.h +++ b/olcCodeJam2023Entry/VirusAttack.h @@ -5,6 +5,7 @@ #include "olcPGEX_AudioListener.h" #include "olcPGEX_AudioSource.h" #include "olcPGEX_SplashScreen.h" +#include "olcPGEX_QuickGUI.h" #include "Unit.h" #include "Constant.h" #include "Image.h" @@ -15,6 +16,7 @@ #include "Resources.h" #include "Textbox.h" #include "Level.h" +#include "GameState.h" class Scenario; @@ -28,6 +30,13 @@ class VirusAttack : public olc::PixelGameEngine { friend class Scenario; friend class Stage1; + friend class Stage2; + friend class Stage3; + friend class Stage4; + friend class Stage5; + friend class Stage6; + friend class Stage7; + friend class Stage8; private: #ifdef SPLASH_ENABLED SplashScreen splash; @@ -52,11 +61,18 @@ private: TileTransformedView game; - Textbox unitCreationBox,testBox,memoryAllocatorBox,platformCreationBox; + Textbox unitCreationBox,testBox,memoryAllocatorBox,platformCreationBox,restartBox; Level*currentLevel; std::maplevelData; + QuickGUI::Manager mainMenu; + QuickGUI::TransparentButton*campaignStartButton; + QuickGUI::TransparentButton*audioToggleButton; + QuickGUI::TransparentButton*difficultyToggleButton; + QuickGUI::TransparentButton*exitGameButton; + QuickGUI::Manager restartManager; + QuickGUI::TransparentImageButton*restartButton; QuickGUI::Manager unitCreationList; QuickGUI::ImageButton*leftShifterButton; QuickGUI::ImageButton*rightShifterButton; @@ -87,6 +103,14 @@ private: float memoryChangeTimer=2; bool unitMetersGreyedOut=false; //If true, all but health meters show up as dark grey. bool playerInControl=true; + float levelForegroundFade=0; + LevelName levelToLoad; + bool limitedBuildOptions=false; + bool guideEnabled=true; + bool reloadLevel=false; + bool restartButtonHeldDown=false; + float restartButtonHoldTime=0; + GameState state=GameState::MAIN_MENU; std::string objective=""; @@ -122,6 +146,9 @@ private: void DrawSystemMemoryBar(float fElapsedTime); void CalculateUsedMemory(); void InitializeScenarios(); + void PerformLevelTransition(float fElapsedTime); + void RestartLevel(); + void HandleRestartButton(float fElapsedTime); public: VirusAttack(); diff --git a/olcCodeJam2023Entry/assets/restart.png b/olcCodeJam2023Entry/assets/restart.png new file mode 100644 index 0000000000000000000000000000000000000000..0787e6c8bd0c031b902383f0bfb426bc275abc3b GIT binary patch literal 10443 zcmeHscTkht+HdGe?+8*t0O`Gk-g^fHM1_z92rWQDm)=2o6A(l?s8s3FJ0e9v=^atJ zC{5Z8?tS*zXYMz1=gi#izn#q6p7LAI^IOkav)*?_8|rJ25Hb(~000s#O;uyemGSzx zfsZ-6lPsnJ0JJ5(rsim4h!@b+9chbjf&|V6AhBl5KKELfBH{p|h>0NMq zeE9uhYqj-7rNYA393|J$0nb(zZzT1(Ou@;y+#>z@y?0(ZmU|x>_kGGPzbiznpoS_` z12m92gK-;^v*uHyMbWw6W?PMXC4O#&k1jsfkwYEGG+LiBDL=NQ|EUl*0&Qt;T~wSBB4c|MU-PQ^+|LE{UW#O?Ls@>;8FSN3B z^1O|rjqK%ntAzH)^F^a^^2o4CxAO+J&!^%CUX=-J2Mv~xHj-oT%iI?Gd*e`B!Go64 zQR7|FirX{2XJx|%)zgV}X`H_h=ccne>?P?rrZY=Es9Zy4x_S3`riQ&$bPBh6yZ`d| z8RBuH;JuKEb7Jj?QWmertQz-9VZ)EzxlSsZ8fBbXy7kOr$I(FT&e({mC@>?v3!GTNJ`;T3Skx|EJ4+{sHCZw%+~_yl>^+i`xJMRWK(nr zN8Dp>Q9PMFMbDXSFAUIoes8CgG}(;HzG_GkC7icQ8b9pl&L{h?7UHJxZm+!JD00(29HX1ef|zy1(Q@aDS>9uoW2C*$`nK`# z)y~}yV7Si(oRq67>c#p;w)FZmwFgVIPErOx;BV;DbsTB!=i?rE%g&jxu(YK4o!R>O z_TOx0(CFU3N!cH{JoH2y={UA(w9U6Ep)>9r~|A+MF(-rO`f&29=1OYHvA{BSR6dPHs% z+c96=pA%(gvrs0KR4)9*=%|iqD90*uZcj6#XmE>a=fho|VdYu^-Mton(vKZ;o2W9m zWPZ(*c>QU6x1Ntro7Y|09Y*|}`(mc+YWQoB)S`juq`O6OB&C@Qw}~m(c zH#CT%3`EUSnY`Lvm4m9x-j6)3st?SbZubkrQIThTKW=jvrT}LQjnV7Cb1N|#ON$VZ z&8$0~92^gCR#k{!-bnHRI>4O_e5Yb@qxz&qwER-OjF+@Eu)NeQyMN;VKP}JIpKpw6 zYxm{~Yxez$m)qNQ-p_}EUh6X)$J>&r2Ho zR3$3dTLTi>5{;(ouNij2_oARowQ6o?jqdkEZ$iFU=FL?*$aWr9*yu!Jkq*lk1=A_) z>3P0?#|2H}8Ty#bXHd>%#IQvmiJGdz_e<&8N|Kdl?P#?r5LSBP(0Y3O0- z`?)E4o1@Hp`nk(ljOzrbS=Dvg08Qt1(*XT4!7i(8Kb|;5OAxS5LUE6Jv{$NNE5=#EbydYbaTX&%5M3Y(@ zXpLjG7QVn)y{bA4QT>5U^O`oIJ|{@*7$=s(%*bo8I4<@>wf97~R;!YFl6LXH@(sbk zJM3_rr48IM^$6q=FGG>Vqe!#KdSPbPABok@V>7S6*6Jq3L+#KaB@ zA1)|ndN#K$Exy{ZD!x3Nj0z*5Fz&QrI>1cs+QCmEN4lk1ZR^>cF~iX6_hGfZJl|ttd~|6mt6r?SaLxR> zk@sSq<_tTk@$N2jZOGT>gaUq1Q9!KwGunE7u|nB;^<{)*oXH|{A%`Lb4c7iGQGVL& z)6cb0c=HjHxK+;ZhIii`kDRBr7#np^FVmAirdR_BW$Y?iHILrJ9Qd#^a?~FBi*rvo zx~zYaYpIE)I5?>)bh+0TU-N9lHC22yem`flEaR3%z>cS$Cqb0EDxO zR}~=Ivd{G`VbWU}L17j*rx-G+op)DBT#XaN^TsmV+`AHKYIw>ul$%Z$tow?YkF~w^ zj;K?!*X(0T(Q8y3#?wKmiTF~zN$!$356OB)!Td4kUJ{M5aml+q*-uJ1Z54< z%gH8M`-i)5|4J{z9Iu_MUbU3AkqirEDRr;k;5;+M@w zpYmZTKP~c6d3y77PW%NX_+-%T%mK^-H)Iv?Bup0F<4uC_Mkm0znOtY^#Q2#CE z1-YD1kPVqz{+@V2F&n9BrTtRZIxAm!{O#(71k@DZfCrC0Icqp~3@qm7=BVx@UO`x? zuAWRqAT7`xd|2I=BV2r`X{5`2Cgr7~RKaa3HkEk<5NGd3AHFrJXffPf{|HS95*F!XuENc#E2=FU42&LjTarx(zS- zDDqOp`)hjzuhd&y4VzhA8`)D+qpJn!f+N)-%hLA2N>HYfzDtW4XJqL)&R(Q^sv&N9 zc*$v)e8@>khMLJQL~vp5$WlaqVfXp~rRNrfxbtgi?8^+EC(iHeK&{4Z-KBv5C$cUf z2M;IjPcLrqMOO_vkrW2UI;i=3(J~q(P#f!@x(NnTWIELH?NLhWB2jaO?|-oOgv%PJ z#{GI**k>dh6)!^SMNL$UVuEqZGvpFTFm^8~%**M1s1_qlivbead0^e9>CQK7Hn-=< zU@KP?#ZC$?I;En5dEDR$)t@D@te=o$yf+o^TbPHBdQ$#IVs2pKaR~CQF9S;biTDCu zllWxI!?`p{tVbZ1$O{0dK^7lR8;@_=PUz;Mh7lQJ=yaH-sh6M_T5vjUvvNgvVCIXapAO4O}dCL!lu0XQB{3lRC-$=w$l?u`H83!2c!AUsoaG-(uG%T&JF>OvBbLKQwq`< zd*h)$nKHw?V;*w4y040qP-Kk0mwvys?>g z#X#8GZ&M#VAIT5Qx~*k>SH0t8^BEBo=4fp4jIZBH8eyjO$ZSc_IQ@1~*o@Km+t7h2 zr^#H6QJN=P&VHO-NoPsgs@)QI`^sQAq|MKZo>lhdEf}0?XW%DuB)*v;xyJ?ZoRxkB zU&4uDn~G@VOrwdM{3uuUb3zVn8binejb&yZQYx{x)aJdRiyuNFc>+swjcg#}UhD`| zq~6MmVBp~+A^BpC9hC)iquzVXX>6f^zW1JQB0%||NUtt#ZXBO-yAUi!6r|7u4@i5k zZ=ockm&lwe8y(i9fpem*^TzY_#m-RO==T*dg??b*%;|1cnnnXN#N7S~lZbzE67C!gWRh0glXC}(mTD~Q zD<2CLQ3kdzeSGRD#MFt^wX`x}4fEZR3k1-5T<$*;>2Wgv%11)BxU)6-*IqWobsMk6 z8?zmy!p1uzMz+vB?sGX>WKLCrV~2P{4>bjvp!=Yv1a|QYhYubc2paw&+{7PDZ*h2E zcAu|s63Peq`C7~!20=%>Npuq z(BwOM=|{W{lZ#00X|;S0rs4*zdNkQh@3D;6Pwt-U-YNS$YoboBm%o{yLXdVJEHqfjr<5X4sYjd_{IA#ORpZ64bV#6BUZ zHrb(`=cP2zlRGK8WKt)!V@-F&iMJtE*)??iwoN*L!20CnM^2Ay~p7l$bK6$6w#;Tc=sT^E{GJeX>Pp&P5 z%?@P+^!^C%Gho{xFpDnJb6~>S^ANj<$COsu9qkakZ{@NX_tlY_o`?Ad9O(IWG%#T4 zj5A?Kh+??m=RqRTgXpQxPZ(WeW+snU7V00D>Mt_ONhfs$XtI)=!u`q4T@00}3)--~ z%PMuh2@N(@;7{${W$m))OctU)M%<08*b5QmlF%L;Af|IS5JRD!I9FolFaZi!;2X@mdp056_lkKGKvyG#@Z1(_# z6M*}iBaPD>W@EtwFr*D!z}wjsv%vrW$SQcdLZFUtG|&cahj5Vt z?X|RnfC!iz$V^;MNY7OTZjaFPb%&ey>YGA+9id|3_;0#AYfZondE+}bl zInZxhY0Uk#SP%sKZGv``1DWd?0#%UiaG;ogn1B$!nm58z1SC%gly!&MN*k-H{|SM4 zk^|YJ(XP^hf?i%;0$!p5NOwCyVK5jhC?p~%BEpZc;79qmpdsG;E-1EZh(9n?;V7s( z!WE4`x&W^+AvQ=4v>XV8(F6Y#pR=o;-e2%8s6Sc2@FD08aTOF65E68D7W}&h3a#de z0r@ka|Iq_wirI$|G=`&)9_~=MnkU=^&GvT)81yfHR}Xim-|4`hf^a9eGsYB!X;t_? zn$*zJGyKcrngTn7v+Hj!4B7u-iALD|o2>tc?OO9YoxcZyasLbVKdk?i`)^~6m7boo zDiZ2(9iEn|9O$}zX&4fUfJy(p6_FB!N!Uo)@Iyr;q5NVJP%uA40uJT3g-M8t3rh%# z!bG8egVJ(Ap&>3%_%##;TmXT=5fK&<6@r5$`9)w-V16+$RFq#z!bXx`NK!;f0wM;J z#HjxUVc?FyR3*ge?@?Vt!7xz5VsNksSPIGy6Nh1<5r+!%gTW%g{BRf)0>IG(o1h`rdkcge71SQ$Vh6{}AAc6?zvPJjp%@@iB9dUZuoS-y7y{!LlN5pR zLm*%{zleyK4P0DE5(<_0BdfpAQAk^~7sMT|WQXAq!xg4Le{%)o`m?LJ|1%mdd-!!f zU?}4k0`vcyG7*sApUDbd&lvy8R#x!;;zRbg!QZABjNczJ%+!UM2?hU}3jgE_6YKxx z@6Uet-)sU1{HKxsir;_e`iHLnih=*i_@CxH6OFex1XfbFWKs${C!KcC+2IB7`T zudrBHsYm5X_aN*NN7+pqSEI8iHl@IjkjaX?v-)eIZiq@r$c+%{9%HU3L-ycHvX!sx zi5s=7ds1shbrZ+DMNDF@tQlvks9o@e-){KTg-K*n3#w0&ZW>mW;&ZXm-;@cp^shPD z&A0T<3G%6lFiqlcgt^UHkHLv5{ivN3@26_NqxxLg{OZvrb$h@m4Y4lU$Em4h51dhJ z4QrCV8{>dPT7p}xTe!Q;aSEZ69XITS90yWLT%4|&VawL*Sbc(33}v2Gc4ldjU!HA~ zL!(L+#f8{o8w3Z|_-$@NX{ZzX4ZbLe;~e3Y;-+$8nnMUP>XL_sMl4*!D*6Ja4Ag(g7D{9~h-`C`$v<`Equj1%?OPAUta<-lu zUo$ENdoGynknIaU76U(6(B+4J$FCxOh0PlUpaz0qtUl-1iiqmSudJxPK{lOFmF_IL zO~*Kf&}ShI2i{vDw~rOE)Pwi{*fnd*VhH=?`_f>G1sSrRL9|&0k^H`L&hd05y(K8~ zrbXMe#`obK?cZ5J{0TzccWGJHAoaSrvgU>9o^OL_l6w<6IP_jN*&CT3Q)Q{`3Ob#g ztPQqi`>ARr`OUs+c^c3@ZD(`;vIj6d&`X+Vz`WR&NoD&zCvbQDf`HlnP*#OVR|Zp{ O04+6r)e2?nkpBZf#QY5a literal 0 HcmV?d00001 diff --git a/olcCodeJam2023Entry/assets/restartHover.png b/olcCodeJam2023Entry/assets/restartHover.png new file mode 100644 index 0000000000000000000000000000000000000000..397712c8b8f88c2b20af61f10223f6fdc9a7931a GIT binary patch literal 772 zcmV+f1N;1mP)EX>4Tx04R}tkvm8OK@>%gQSpOfVG0q8E!0XI6_HdSia{_SF@nFs-HnNX>?Z6c z*jNg-0SiBkzrw~^TMJu35d47H+E^*th^%jtK!O+thB@4s`*`mT_zu&ia>eP8VsA|=I_vdPluev7GX~ID>>*R!2gh$tN zS;f1;esfKa3!e!OIMSf-gVK!>zbZ}^Sv8H{iABeS{lZ$Zij68Z*BncDM7TF@*;3y( zU*fpp4aHVEZyk_jTlX-^Wn@1ebQjpE-oF577%1 zt@i*rHsSoLq8U4Iu?1a^S>4f#QoU?nA^~rw@=XiSc>}FWrQFK*oZLf9vYNhzy?y9U zO6}zub2nG#_V1f=en0pCa@;7uVut_#00v@9M??Vs0RI60puMM)00009a7bBm001r{ z001r{0eGc9b^rhX2XskIMF-~z0ulizQ-HR4H;86s;nd$~VFLKc|2OH@_$ zUj*S9+h9?-Gj~c(RS + diff --git a/olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj.filters b/olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj.filters index cc833b1..1aacb4f 100644 --- a/olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj.filters +++ b/olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj.filters @@ -99,6 +99,9 @@ Header Files + + Header Files + diff --git a/olcCodeJam2023Entry/olcPGEX_QuickGUI.h b/olcCodeJam2023Entry/olcPGEX_QuickGUI.h index 95b8327..7a11d86 100644 --- a/olcCodeJam2023Entry/olcPGEX_QuickGUI.h +++ b/olcCodeJam2023Entry/olcPGEX_QuickGUI.h @@ -252,6 +252,31 @@ namespace olc::QuickGUI void DrawDecal(PixelGameEngine*pge) override; }; + // Creates a Button Control - a clickable, labelled rectangle + class TransparentButton : public Button + { + public: + TransparentButton(olc::QuickGUI::Manager& manager, // Associate with a Manager + const std::string& text, // Text to display + const olc::vf2d& pos, // Location of button top-left + const olc::vf2d& size, // Location of button top-left + const Pixel& hoverCol); // Size of button + + public: + // Position of button + olc::vf2d vPos; + // Size of button + olc::vf2d vSize; + // Text displayed on button + std::string sText; + Pixel hoverCol; + + public: // BaseControl overrides + void Draw(TileTransformedView&pge) override; + void DrawDecal(TileTransformedView&pge) override; + void DrawDecal(PixelGameEngine*pge) override; + }; + // Creates a Button Control - a clickable, labelled rectangle class CheckBox : public Button { @@ -290,6 +315,27 @@ namespace olc::QuickGUI void DrawDecal(PixelGameEngine*pge) override; }; + class TransparentImageButton : public ImageButton + { + public: + TransparentImageButton(olc::QuickGUI::Manager& manager, // Associate with a Manager + const olc::Renderable &icon, // Text to display + const olc::Renderable &iconHover, // Text to display + const olc::vf2d& iconScale, + const olc::vf2d& pos, // Location of button top-left + const olc::vf2d& size); // Size of button + + public: + const olc::Renderable& pIcon; + const olc::Renderable& pIconHover; + olc::vf2d iconScale; + + public: + void Draw(TileTransformedView&pge) override; + void DrawDecal(TileTransformedView&pge) override; + void DrawDecal(PixelGameEngine*pge) override; + }; + class ImageCheckBox : public ImageButton { public: @@ -750,8 +796,9 @@ namespace olc::QuickGUI vMouse.y >= vPos.y && vMouse.y < vPos.y + vSize.y; bPressed = false; bReleased = false; - if (m_state == State::Disabled || !bVisible) + if (m_state == State::Disabled || !bVisible) { return; + } float fElapsedTime = pge->GetElapsedTime(); @@ -866,6 +913,40 @@ namespace olc::QuickGUI } #pragma endregion +#pragma region TransparentButton + TransparentButton::TransparentButton(olc::QuickGUI::Manager& manager, const std::string& text, const olc::vf2d& pos, const olc::vf2d& size,const Pixel& hoverCol) + : Button(manager,text,pos,size),hoverCol(hoverCol) + { + vPos = pos; vSize = size; sText = text; + } + void TransparentButton::Draw(TileTransformedView&pge) + { + if (!bVisible) + return; + + pge.DrawRect(vPos, vSize - olc::vf2d(1, 1), m_manager.colBorder); + olc::vf2d vText = pge.GetPGE()->GetTextSize(sText); + //pge.DrawShadowString(vPos + (vSize - vText) * 0.5f, sText, m_manager.colText,{1,1},olc::PixelLerp(m_manager.colText, hoverCol, m_fTransition)); + } + + void TransparentButton::DrawDecal(TileTransformedView&pge) + { + if (!bVisible) + return; + + olc::vf2d vText = pge.GetPGE()->GetTextSizeProp(sText); + pge.DrawShadowStringPropDecal(vPos + (vSize - vText) * 0.5f, sText, m_manager.colText,olc::PixelLerp(BLACK, hoverCol, m_fTransition)); + } + + void TransparentButton::DrawDecal(PixelGameEngine*pge) + { + if (!bVisible) + return; + + olc::vf2d vText = pge->GetTextSizeProp(sText); + pge->DrawShadowStringPropDecal(vPos + (vSize - vText) * 0.5f, sText, m_manager.colText,olc::PixelLerp(BLACK, hoverCol, m_fTransition)); + } +#pragma endregion #pragma region ImageButton ImageButton::ImageButton(olc::QuickGUI::Manager& manager, const olc::Renderable& icon, const olc::vf2d& iconScale, const olc::vf2d& pos, const olc::vf2d& size) @@ -893,6 +974,43 @@ namespace olc::QuickGUI }; #pragma endregion +#pragma region TransparentImageButton + TransparentImageButton::TransparentImageButton(olc::QuickGUI::Manager& manager, const olc::Renderable& icon, const olc::Renderable& iconHover, const olc::vf2d& iconScale, const olc::vf2d& pos, const olc::vf2d& size) + : ImageButton(manager, icon, iconScale, pos, size), pIcon(icon), pIconHover(iconHover), iconScale(iconScale) + { + + } + + void TransparentImageButton::Draw(TileTransformedView&pge) + { + if (!bVisible) return; + //Button::Draw(pge); + if(bHover){ + pge.DrawSprite(vPos + olc::vi2d(4, 4), pIconHover.Sprite()); + } else { + pge.DrawSprite(vPos + olc::vi2d(4, 4), pIcon.Sprite()); + } + } + + void TransparentImageButton::DrawDecal(TileTransformedView&pge){ + if (!bVisible) return; + if(bHover){ + pge.DrawDecal(vPos + olc::vi2d(4, 4), pIconHover.Decal(), iconScale,m_state!=State::Disabled?WHITE:WHITE/4); + } else { + pge.DrawDecal(vPos + olc::vi2d(4, 4), pIcon.Decal(), iconScale,m_state!=State::Disabled?WHITE:WHITE/4); + } + } + + void TransparentImageButton::DrawDecal(PixelGameEngine*pge){ + if (!bVisible) return; + if(bHover){ + pge->DrawDecal(vPos + olc::vi2d(4, 4), pIconHover.Decal(), iconScale,m_state!=State::Disabled?WHITE:WHITE/4); + } else { + pge->DrawDecal(vPos + olc::vi2d(4, 4), pIcon.Decal(), iconScale,m_state!=State::Disabled?WHITE:WHITE/4); + } + }; +#pragma endregion + #pragma region ImageCheckBox ImageCheckBox::ImageCheckBox(olc::QuickGUI::Manager& manager, const olc::Renderable& gfx, const bool check, const olc::vf2d& pos, const olc::vf2d& size) diff --git a/olcCodeJam2023Entry/olcPGEX_SplashScreen.h b/olcCodeJam2023Entry/olcPGEX_SplashScreen.h index 2759970..e4e55f5 100644 --- a/olcCodeJam2023Entry/olcPGEX_SplashScreen.h +++ b/olcCodeJam2023Entry/olcPGEX_SplashScreen.h @@ -210,8 +210,8 @@ namespace olc pge->DrawPartialDecal(vScale * vBoom[y * spr.Sprite()->width + x].first * 2.0f, spr.Decal(), olc::vf2d(x, y), { 1, 1 }, vScale * 2.0f, olc::PixelF(1.0f, 1.0f, 1.0f, std::min(1.0f, std::max(4.0f - fParticleTime, 0.0f)))); } - olc::vi2d vSize = pge->GetTextSizeProp("Copyright OneLoneCoder.com 2022"); - pge->DrawStringPropDecal(olc::vf2d(float(pge->ScreenWidth()/2) - vSize.x/2, float(pge->ScreenHeight()) - vSize.y * 3.0f), "Copyright OneLoneCoder.com 2022", olc::PixelF(1.0f, 1.0f, 1.0f, 0.5f), olc::vf2d(1.0, 2.0f)); + olc::vi2d vSize = pge->GetTextSizeProp("Copyright OneLoneCoder.com 2023"); + pge->DrawStringPropDecal(olc::vf2d(float(pge->ScreenWidth()/2) - vSize.x/2, float(pge->ScreenHeight()) - vSize.y * 3.0f), "Copyright OneLoneCoder.com 2023", olc::PixelF(1.0f, 1.0f, 1.0f, 0.5f), olc::vf2d(1.0, 2.0f)); return true; } diff --git a/olcCodeJam2023Entry/olcPGEX_TransformedView.h b/olcCodeJam2023Entry/olcPGEX_TransformedView.h index 4c8d031..da0f16e 100644 --- a/olcCodeJam2023Entry/olcPGEX_TransformedView.h +++ b/olcCodeJam2023Entry/olcPGEX_TransformedView.h @@ -180,6 +180,7 @@ namespace olc // Draws a multiline string as a decal, with tiniting and scaling void DrawStringDecal(const olc::vf2d& pos, const std::string& sText, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); void DrawShadowStringDecal(const olc::vf2d & pos, const std::string & sText, const olc::Pixel col=olc::WHITE, const olc::Pixel shadowCol=olc::BLACK, const olc::vf2d & scale={1,1}, const float shadowSizeFactor=1); + void DrawShadowStringPropDecal(const olc::vf2d & pos, const std::string & sText, const olc::Pixel col=olc::WHITE, const olc::Pixel shadowCol=olc::BLACK, const olc::vf2d & scale={1,1}, const float shadowSizeFactor=1); void DrawStringPropDecal(const olc::vf2d& pos, const std::string& sText, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); // Draws a single shaded filled rectangle as a decal void FillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::WHITE); @@ -633,6 +634,11 @@ namespace olc pge->DrawShadowStringDecal(WorldToScreen(pos), sText, col, shadowCol, scale * m_vWorldScale * m_vRecipPixel, shadowSizeFactor); } + void TransformedView::DrawShadowStringPropDecal(const olc::vf2d & pos, const std::string & sText, const olc::Pixel col, const olc::Pixel shadowCol, const olc::vf2d & scale, const float shadowSizeFactor) + { + pge->DrawShadowStringPropDecal(WorldToScreen(pos), sText, col, shadowCol, scale * m_vWorldScale * m_vRecipPixel, shadowSizeFactor); + } + void TransformedView::DrawStringPropDecal(const olc::vf2d & pos, const std::string & sText, const olc::Pixel col, const olc::vf2d & scale ) { pge->DrawStringPropDecal(WorldToScreen(pos), sText, col, scale * m_vWorldScale * m_vRecipPixel);