diff --git a/olcCodeJam2023Entry/DebuffIcon.cpp b/olcCodeJam2023Entry/DebuffIcon.cpp index 5e2a4ea..3d32f03 100644 --- a/olcCodeJam2023Entry/DebuffIcon.cpp +++ b/olcCodeJam2023Entry/DebuffIcon.cpp @@ -8,4 +8,32 @@ void DebuffIcon::Update(float fElapsedTime){ void DebuffIcon::Draw(TileTransformedView&game){ game.DrawRotatedDecal(pos,icon->Decal(),0,icon->Sprite()->Size()/2,{1,1},{255,255,255,uint8_t((lifetime/CONSTANT::DEBUFFICON_LIFETIME)*255)}); game.DrawRotatedDecal(pos+vf2d{4,-4},redXIcon->Decal(),0,icon->Sprite()->Size()/2,{1,1},{255,255,255,uint8_t((lifetime/CONSTANT::DEBUFFICON_LIFETIME)*255)}); +} + +void ResourceGainIcon::Update(float fElapsedTime){ + pos.y-=6*fElapsedTime; + lifetime-=fElapsedTime; +} + +void ResourceGainIcon::Draw(TileTransformedView&game){ + Pixel col; + switch(type){ + case HEALTH:{ + col=CONSTANT::HEALTH_COLOR; + }break; + case RANGE:{ + col=CONSTANT::RANGE_COLOR; + }break; + case ATKSPD:{ + col=CONSTANT::ATKSPD_COLOR; + }break; + case MOVESPD:{ + col=CONSTANT::MOVESPD_COLOR; + }break; + case PROCEDURE:{ + col=CONSTANT::PROCEDURE_COLOR; + }break; + } + game.DrawRotatedDecal(pos,icon->Decal(),0,icon->Sprite()->Size()/2,{1,1},{col.r,col.g,col.b,uint8_t((lifetime/CONSTANT::DEBUFFICON_LIFETIME)*255)}); + game.DrawShadowStringDecal(pos-vf2d{-2,-2},"+1",col); } \ No newline at end of file diff --git a/olcCodeJam2023Entry/DebuffIcon.h b/olcCodeJam2023Entry/DebuffIcon.h index 2c25ac4..3b20580 100644 --- a/olcCodeJam2023Entry/DebuffIcon.h +++ b/olcCodeJam2023Entry/DebuffIcon.h @@ -2,6 +2,7 @@ #include "olcPixelGameEngine.h" #include "olcPGEX_TransformedView.h" #include "Constant.h" +#include "MemoryType.h" struct DebuffIcon{ Renderable*icon; @@ -10,4 +11,13 @@ struct DebuffIcon{ float lifetime=CONSTANT::DEBUFFICON_LIFETIME; void Update(float fElapsedTime); void Draw(TileTransformedView&game); +}; + +struct ResourceGainIcon{ + Renderable*icon; + MemoryType type; + vf2d pos; + float lifetime=CONSTANT::DEBUFFICON_LIFETIME; + void Update(float fElapsedTime); + void Draw(TileTransformedView&game); }; \ No newline at end of file diff --git a/olcCodeJam2023Entry/Info.txt b/olcCodeJam2023Entry/Info.txt index edc66ac..54fc4a8 100644 --- a/olcCodeJam2023Entry/Info.txt +++ b/olcCodeJam2023Entry/Info.txt @@ -91,7 +91,9 @@ Stage 3: I'll leave a guide by the map in case your memory betrays you. (Guide Enabled) (New Scenario Objective: - -Defeat all enemy units) + -Defeat all units) + (Upon uncovering units and going near them) + Oh oops, I guess there were no viruses in this sector. Let's move on then. Stage 4: (Start with 3 of the yellow resource) @@ -110,31 +112,22 @@ Stage 5: (New Scenario Objective: -Defeat all enemy units) +Stage 6: +(New Scenario Objective: + -Defeat all enemy units) + ... +Stage 7: + I see you have a few new tricks up your sleeve hacker. + Don't think it'll be that easy to get through this one... +(New Scenario Objective: + -Defeat all enemy units) +Stage 8: + You need to cease all operations, you are causing more harm than good. +(New Scenario Objective: + -Defeat all enemy units) -Tutorial -(Grey out non-important bars) - -Level 1: Basic Unit and Controls, move units towards enemy unit -Level 2: Introduce another Unit -Level 3: -Level 4: -Level 5: -Level 6: - -(Introduce one unit at a time) - -Memory Limits - -Minimap -Pause / Slow down time (Hotkeys to speed up/slow down time) - -Stage 1 -Stage 2 -Stage 3 -Stage 4 -Stage 5 - Hacking a Network Potential Songs: diff --git a/olcCodeJam2023Entry/Level.h b/olcCodeJam2023Entry/Level.h index 4ac6d50..cdcba13 100644 --- a/olcCodeJam2023Entry/Level.h +++ b/olcCodeJam2023Entry/Level.h @@ -8,6 +8,10 @@ enum LevelName{ STAGE2, STAGE3, STAGE4, + STAGE5, + STAGE6, + STAGE7, + STAGE8, }; struct UnitData{ @@ -31,4 +35,5 @@ struct Level{ Sound bgm=Sound::COSMOS; vf2d cameraStart={96,96}; vf2d worldZoom={1,1}; + Pixel levelColor=DARK_GREEN; }; \ No newline at end of file diff --git a/olcCodeJam2023Entry/Unit.cpp b/olcCodeJam2023Entry/Unit.cpp index 8ee2503..3448030 100644 --- a/olcCodeJam2023Entry/Unit.cpp +++ b/olcCodeJam2023Entry/Unit.cpp @@ -91,8 +91,10 @@ void MemorySwapper::Attack(Unit&victim,std::vector>&otherU if(victim.moveSpd.indexindex;} if(victim.procedure.indexindex;} - order.push_back(lowest); - lowest->index=9999999; + if(lowest!=nullptr){ + order.push_back(lowest); + lowest->index=9999999; + } } std::reverse(order.begin(),order.end()); int i=0; @@ -637,7 +639,7 @@ void Unit::_RunAI(PixelGameEngine*pge){ RunAI(pge); } -void Unit::_Update(PixelGameEngine*pge,std::map>&SOUNDS,Resources&player_resources,Resources&enemy_resources,std::vector>&queuedUnits,std::array&resourceGainTimer){ +void Unit::_Update(PixelGameEngine*pge,std::map>&SOUNDS,Resources&player_resources,Resources&enemy_resources,std::vector>&queuedUnits,std::array&resourceGainTimer,std::vector&resourceGainIcons,std::map>&IMAGES){ if(!target.expired()){ auto ptrTarget=target.lock(); if(!InRange(ptrTarget)&&CanMove()){ @@ -687,6 +689,7 @@ void Unit::_Update(PixelGameEngine*pge,std::map>&SO resourceGainTimer[4]=2; }break; } + resourceGainIcons.push_back({IMAGES[RESOURCE].get(),attachedPoint.lock()->type,GetPos()}); } } @@ -966,4 +969,8 @@ void Unit::SaveMemory(){ bool Unit::IsPlatform(){ return isPlatform&&attachedPoint.expired()&&buildTime<=0; +} + +bool Unit::IsAttached(){ + return !attachedPoint.expired(); } \ No newline at end of file diff --git a/olcCodeJam2023Entry/Unit.h b/olcCodeJam2023Entry/Unit.h index d3bc9aa..5049123 100644 --- a/olcCodeJam2023Entry/Unit.h +++ b/olcCodeJam2023Entry/Unit.h @@ -71,7 +71,7 @@ public: bool GhostInFogOfWar(); void HideGhost(); vf2d GetGhostPos(); - void _Update(PixelGameEngine*pge,std::map>&SOUNDS,Resources&player_resources,Resources&enemy_resources,std::vector>&queuedUnits,std::array&resourceGainTimer); + void _Update(PixelGameEngine*pge,std::map>&SOUNDS,Resources&player_resources,Resources&enemy_resources,std::vector>&queuedUnits,std::array&resourceGainTimer,std::vector&resourceGainIcons,std::map>&IMAGES); bool IsMoveable(); void DrawRangeIndicator(PixelGameEngine*pge,TileTransformedView&game,std::map>&IMAGES); bool CanInteractWithEnemies(); @@ -96,6 +96,7 @@ public: bool IsGuarded(); void SaveMemory(); bool IsPlatform(); + bool IsAttached(); Marker health={}; Marker range={}; Marker atkSpd={}; diff --git a/olcCodeJam2023Entry/VirusAttack.cpp b/olcCodeJam2023Entry/VirusAttack.cpp index 56b053d..6d16c87 100644 --- a/olcCodeJam2023Entry/VirusAttack.cpp +++ b/olcCodeJam2023Entry/VirusAttack.cpp @@ -65,52 +65,64 @@ void VirusAttack::InitializeImages(){ void VirusAttack::InitializeLevelData(){ #pragma region Stage 1 - //Stage 1 data. - levelData[STAGE1].size={64,64}; - levelData[STAGE1].bgm=Sound::BOSS2; - levelData[STAGE1].player_starting_resources={50,50,50,50,50}; - levelData[STAGE1].enemy_starting_resources={0,0,0,0,0}; { - std::vector&units=levelData[STAGE1].unitPlacement; - std::vector&collectionPoints=levelData[STAGE1].cpPlacement; - - units.push_back({UnitType::LeftShifter,vf2d{128,128},true}); - units.push_back({UnitType::RightShifter,vf2d{129,129},true}); - units.push_back({UnitType::BitRestorer,vf2d{130,130},true}); - units.push_back({UnitType::BitRestorer,vf2d{130,140},true}); - units.push_back({UnitType::MemorySwapper,vf2d{131,131},true}); - units.push_back({UnitType::Corrupter,vf2d{132,132},true}); - units.push_back({UnitType::MemoryAllocator,vf2d{133,133},true}); - units.push_back({UnitType::RAMBank,vf2d{134,134},true}); - units.push_back({UnitType::MemoryGuard,vf2d{200,134},true}); - - - for(int i=0;i<5;i++){ - collectionPoints.push_back({vf2d{32.f+48*i,32.f},0,MemoryType(i)}); - collectionPoints.push_back({vf2d{32.f,32.f+48*i},-PI/2,MemoryType(i)}); - } + //Stage 1 data. + LevelName stage=STAGE1; + levelData[stage].cameraStart={96,96}; + levelData[stage].worldZoom={1,1}; + levelData[stage].levelColor=DARK_RED; + levelData[stage].size={64,64}; + levelData[stage].bgm=Sound::BOSS2; + levelData[stage].player_starting_resources={50,50,50,50,50}; + levelData[stage].enemy_starting_resources={0,0,0,0,0}; + { + std::vector&units=levelData[stage].unitPlacement; + std::vector&collectionPoints=levelData[stage].cpPlacement; + + units.push_back({UnitType::LeftShifter,vf2d{128,128},true}); + units.push_back({UnitType::RightShifter,vf2d{129,129},true}); + units.push_back({UnitType::BitRestorer,vf2d{130,130},true}); + units.push_back({UnitType::BitRestorer,vf2d{130,140},true}); + units.push_back({UnitType::MemorySwapper,vf2d{131,131},true}); + units.push_back({UnitType::Corrupter,vf2d{132,132},true}); + units.push_back({UnitType::MemoryAllocator,vf2d{133,133},true}); + units.push_back({UnitType::RAMBank,vf2d{134,134},true}); + units.push_back({UnitType::MemoryGuard,vf2d{200,134},true}); + + + for(int i=0;i<5;i++){ + collectionPoints.push_back({vf2d{32.f+48*i,32.f},0,MemoryType(i)}); + collectionPoints.push_back({vf2d{32.f,32.f+48*i},-PI/2,MemoryType(i)}); + } - units.push_back({UnitType::RAMBank,vf2d{1200,1200},false}); + units.push_back({UnitType::RAMBank,vf2d{1200,1200},false}); - units.push_back({UnitType::RightShifter,vf2d{1260,1200},false}); - units.push_back({UnitType::RightShifter,vf2d{360,300},false}); - units.push_back({UnitType::RightShifter,vf2d{361,300},false}); + units.push_back({UnitType::RightShifter,vf2d{1260,1200},false}); + units.push_back({UnitType::RightShifter,vf2d{360,300},false}); + units.push_back({UnitType::RightShifter,vf2d{361,300},false}); + } } #pragma endregion #pragma region Stage 2 - //Stage 2 data. - levelData[STAGE2].size={16,16}; - levelData[STAGE2].bgm=Sound::COSMOS; - levelData[STAGE2].player_starting_resources={10,10,10,10,10}; - levelData[STAGE2].enemy_starting_resources={0,0,0,0,0}; { - std::vector&units=levelData[STAGE2].unitPlacement; - std::vector&collectionPoints=levelData[STAGE2].cpPlacement; - - units.push_back({UnitType::RAMBank,vf2d{134,134},true}); - - units.push_back({UnitType::RAMBank,vf2d{1200,1200},false}); - } + //Stage 2 data. + LevelName stage=STAGE2; + levelData[stage].cameraStart={96,96}; + levelData[stage].worldZoom={1,1}; + levelData[stage].size={16,16}; + levelData[stage].levelColor=DARK_GREEN; + levelData[stage].bgm=Sound::COSMOS; + levelData[stage].player_starting_resources={10,10,10,10,10}; + levelData[stage].enemy_starting_resources={0,0,0,0,0}; + { + std::vector&units=levelData[stage].unitPlacement; + std::vector&collectionPoints=levelData[stage].cpPlacement; + + units.push_back({UnitType::RAMBank,vf2d{134,134},true}); + + units.push_back({UnitType::RAMBank,vf2d{1200,1200},false}); + } + } #pragma endregion } @@ -203,6 +215,8 @@ void VirusAttack::LoadLevel(LevelName level){ for(auto&cp:selectedLevel.cpPlacement){ collectionPoints.push_back(std::make_unique(this,cp.pos,cp.rot,*IMAGES[MEMORY_COLLECTION_POINT],cp.type)); } + + randomBackgroundOffset={util::random(128),util::random(128)}; } void VirusAttack::InitializeGUIs(){ @@ -471,11 +485,35 @@ void VirusAttack::DrawMinimap(){ SetDrawTarget(IMAGES[MINIMAP_OUTLINE]->Sprite()); Clear(BLANK); DrawRect((game.GetWorldOffset()/worldPixelSize*64),viewingTilesPct*64/game.GetWorldScale()); + for(auto&cp:collectionPoints){ + Pixel col; + switch(cp->type){ + case HEALTH:{ + col=CONSTANT::HEALTH_COLOR; + }break; + case ATKSPD:{ + col=CONSTANT::ATKSPD_COLOR; + }break; + case MOVESPD:{ + col=CONSTANT::MOVESPD_COLOR; + }break; + case RANGE:{ + col=CONSTANT::RANGE_COLOR; + }break; + case PROCEDURE:{ + col=CONSTANT::PROCEDURE_COLOR; + }break; + } + FillCircle(cp->pos/worldPixelSize*64-vf2d{1,0},1,col); + DrawCircle(cp->pos/worldPixelSize*64-vf2d{1,0},1,BLACK); + } for(auto&u:units){ vf2d squareSize=u->GetUnitSize()/vf2d(WORLD_SIZE); squareSize.x=std::round(std::max(1.f,squareSize.x)); squareSize.y=std::round(std::max(1.f,squareSize.y)); - FillRect(u->GetGhostPos()/worldPixelSize*64-squareSize,squareSize*2,u->IsFriendly()?GREEN:RED); + float colorMult=1; + if(u->IsAttached()){colorMult=0.5;} + FillRect(u->GetGhostPos()/worldPixelSize*64-squareSize,squareSize*2,(u->IsFriendly()?GREEN:RED)*colorMult); } IMAGES[MINIMAP_OUTLINE]->Decal()->Update(); SetDrawTarget(nullptr); @@ -647,7 +685,7 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){ } } u->AttemptAttack(u,closestUnit,units,debuffIcons,IMAGES); - u->_Update(this,SOUNDS,player_resources,enemy_resources,queuedUnits,resourceGainTimer); + u->_Update(this,SOUNDS,player_resources,enemy_resources,queuedUnits,resourceGainTimer,resourceGainIcons,IMAGES); } std::erase_if(units,[&](std::shared_ptru){ @@ -666,7 +704,8 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){ queuedUnits.clear(); - game.DrawPartialDecal({0,0},WORLD_SIZE*CONSTANT::TILE_SIZE,IMAGES[TILE]->Decal(),{0,0},WORLD_SIZE*CONSTANT::TILE_SIZE,DARK_GREEN); + DrawPartialDecal({0,0},GetScreenSize(),IMAGES[MATRIX]->Decal(),randomBackgroundOffset,{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&u:units){ u->DrawRangeIndicator(this,game,IMAGES); @@ -699,7 +738,13 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){ icon.Draw(game); } + for(ResourceGainIcon&icon:resourceGainIcons){ + icon.Update(fElapsedTime); + icon.Draw(game); + } + 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->_DrawHud(game,IMAGES); @@ -765,7 +810,7 @@ void VirusAttack::RenderFogOfWar(){ for(int y=game.GetTopLeftTile().y/96-1;y<=game.GetBottomRightTile().y/96+1;y++){ for(int x=game.GetTopLeftTile().x/96-1;x<=game.GetBottomRightTile().x/96+1;x++){ if(TileManager::visibleTiles.count(vi2d{x,y})==0){ - if(x>=0&&y>=0&&x<=WORLD_SIZE.x*CONSTANT::TILE_SIZE.x&&y<=WORLD_SIZE.y*CONSTANT::TILE_SIZE.y){ + if(x>=0&&y>=0&&x>collectionPoints; std::vector>deathAnimations; std::vectordebuffIcons; + std::vectorresourceGainIcons; std::map>IMAGES; std::map>SOUNDS; @@ -69,6 +70,8 @@ private: std::vectoractiveLetters; std::arrayresourceGainTimer={0}; + vf2d randomBackgroundOffset; + vf2d startingDragPos=CONSTANT::UNSELECTED; void HandleDraggingSelection(); void DrawSelectionRectangle(); diff --git a/olcCodeJam2023Entry/olcPGEX_TransformedView.h b/olcCodeJam2023Entry/olcPGEX_TransformedView.h index 4e10242..4c8d031 100644 --- a/olcCodeJam2023Entry/olcPGEX_TransformedView.h +++ b/olcCodeJam2023Entry/olcPGEX_TransformedView.h @@ -179,6 +179,7 @@ namespace olc void DrawPartialRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale = { 1.0f, 1.0f }, const olc::Pixel& tint = olc::WHITE); // 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 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); @@ -627,6 +628,11 @@ namespace olc pge->DrawStringDecal(WorldToScreen(pos), sText, col, scale * m_vWorldScale * m_vRecipPixel); } + void TransformedView::DrawShadowStringDecal(const olc::vf2d & pos, const std::string & sText, const olc::Pixel col, const olc::Pixel shadowCol, const olc::vf2d & scale, const float shadowSizeFactor) + { + pge->DrawShadowStringDecal(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);