diff --git a/olcCodeJam2023Entry/GameFlags.h b/olcCodeJam2023Entry/GameFlags.h index 338b4a0..b731f02 100644 --- a/olcCodeJam2023Entry/GameFlags.h +++ b/olcCodeJam2023Entry/GameFlags.h @@ -6,4 +6,5 @@ struct GameFlags{ bool limitedBuildOptions=false; bool guideEnabled=false; bool flashMemoryBar=false; + int difficulty=1; //0=Easy, 1=Normal, 2=Hard }; \ No newline at end of file diff --git a/olcCodeJam2023Entry/Info.txt b/olcCodeJam2023Entry/Info.txt index 1c18798..7f022d4 100644 --- a/olcCodeJam2023Entry/Info.txt +++ b/olcCodeJam2023Entry/Info.txt @@ -39,7 +39,7 @@ Fake allies the narrator forgot to switch over Day 9 Sounds/Music/Menus - Timer (Speedrun) Difficulty Selection Ending...Shows Four Seasons of Loneliness boss zoom out... -Easy Difficulty: AI generate no new resources. +Easy Difficulty: AI generate no new resources. Start with 100 of each. Normal Difficulty: AI generates resources at normal rate. Hard Difficulty: AI generates resources at x4 rate. @@ -153,4 +153,9 @@ Space - Gravity (Ambient 1) 1 Glorious Venture (Ending theme?) -Credits \ No newline at end of file +Credits + + +Finish Scenarios (End condition for the game) +Finish up main menu stuff (including credits) +AI stuff \ No newline at end of file diff --git a/olcCodeJam2023Entry/Scenario.cpp b/olcCodeJam2023Entry/Scenario.cpp index 7d47c98..77d2293 100644 --- a/olcCodeJam2023Entry/Scenario.cpp +++ b/olcCodeJam2023Entry/Scenario.cpp @@ -16,10 +16,11 @@ void Scenario::_Start(){ camera.SetTarget(targetPos); missionCompletedTimer=0; transitionToNextLevel=false; + setupEasyMode=false; Start(); } void Scenario::Start(){}; -void Scenario::_Update(){ +void Scenario::_Update(Resources&enemy_resources,std::vector>&collectionPoints,int availableMemory,std::vector>&queuedUnits,std::vector>&SOUNDS){ initialWaitTime=std::max(0.f,initialWaitTime-game.GetPGE()->GetElapsedTime()); missionFinishWaitTime=std::max(0.f,missionFinishWaitTime-game.GetPGE()->GetElapsedTime()); smallTimePass=std::min(1.f,smallTimePass+game.GetPGE()->GetElapsedTime()); @@ -31,10 +32,139 @@ void Scenario::_Update(){ } else { missionCompleted=MissionCompleted(); } + if(flags.playerInControl){ + RunAI(enemy_resources,collectionPoints,availableMemory,queuedUnits,SOUNDS); + } if(initialWaitTime==0){ Update(); } }; +void Scenario::RunAI(Resources&enemy_resources,std::vector>&collectionPoints,int availableMemory,std::vector>&queuedUnits,std::vector>&SOUNDS){ + if(!setupEasyMode&&flags.difficulty==0){ + enemy_resources={100,100,100,100,100}; + } + unitBuildTimer=std::max(0.f,unitBuildTimer-game.GetPGE()->GetElapsedTime()); + //See if there are collectors, if so send memory allocator units towards them. + for(auto cp:collectionPoints){ + if(cp->attachedUnit.expired()){ + if(cpCheckTimer.count(cp.get())==0||cpCheckTimer[cp.get()]<=0){ + for(auto&u:units){ + if(!u->IsFriendly()&&u->IsAllocator()&&u->attachTarget.expired()){ + //Tell this unit to move towards that collection point. + u->SetTargetCollectionPoint(cp,u); + break; + } + } + //Hasn't been checked recently. + cpCheckTimer[cp.get()]=60; + } + } + } + for(auto&key:cpCheckTimer){ + cpCheckTimer[key.first]=std::max(0.0f,game.GetPGE()->GetElapsedTime()); + } + int memoryAllocatorCount=0; + for(auto&u:units){ + if(!u->IsFriendly()&&u->IsAllocator()){ + memoryAllocatorCount++; + } + } + if(memoryAllocatorCount<3){ + for(auto&u:units){ + if(u->IsRAMBank()){ + AttemptBuild(UnitType::MemoryAllocator,u->GetPos(),MemoryAllocator::resourceCost,enemy_resources,availableMemory,queuedUnits); + } + } + } + + //Randomly turn memory allocators into other units. + if(unitBuildTimer==0){ + for(auto&u:units){ + if(!u->IsFriendly()&&u->IsAllocator()){ + std::arrayunitChoiceList={UnitType::LeftShifter,UnitType::LeftShifter,UnitType::RightShifter,UnitType::RightShifter, + UnitType::Corrupter,UnitType::MemorySwapper,UnitType::BitRestorer,UnitType::BitRestorer,UnitType::_Platform,UnitType::Corrupter}; + std::array,10>unitResourceCostList={LeftShifter::resourceCost,LeftShifter::resourceCost,RightShifter::resourceCost,RightShifter::resourceCost, + Corrupter::resourceCost,MemorySwapper::resourceCost,BitRestorer::resourceCost,BitRestorer::resourceCost,_Platform::resourceCost,Corrupter::resourceCost}; + int randomIndex=rand()%unitChoiceList.size(); + UnitType buildUnit=unitChoiceList[randomIndex]; + + int totalCost=0; + for(int i=0;i<5;i++){ + totalCost+=unitResourceCostList[randomIndex][i].size; + } + if(totalCost<=availableMemory){ + #define Build(type) \ + case UnitType::type:{ \ + u->SetBuildUnit(8,std::make_shared(game.GetPGE(),u->GetPos(),IMAGES,false),SOUNDS); \ + }break; + switch(buildUnit){ + Build(LeftShifter) + Build(RightShifter) + Build(BitRestorer) + Build(_Platform) + Build(Corrupter) + Build(MemorySwapper) + } + if(enemy_resources.health>0){enemy_resources.health=std::max(0,enemy_resources.health-totalCost);}else + if(enemy_resources.atkSpd>0){enemy_resources.atkSpd=std::max(0,enemy_resources.atkSpd-totalCost);}else + if(enemy_resources.moveSpd>0){enemy_resources.moveSpd=std::max(0,enemy_resources.moveSpd-totalCost);}else + if(enemy_resources.range>0){enemy_resources.range=std::max(0,enemy_resources.range-totalCost);}else + {enemy_resources.procedure=std::max(0,enemy_resources.procedure-totalCost); + } + } + } + switch(flags.difficulty){ + case 0:{ + unitBuildTimer=120; + }break; + case 1:{ + unitBuildTimer=60; + }break; + case 2:{ + unitBuildTimer=10; + }break; + } + } + } +} +/* +std::shared_ptrbuildUnit=std::make_shared(this,u->GetPos(),IMAGES,u->IsFriendly()); \ +u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit),SOUNDS); \ +*/ +bool Scenario::AttemptBuild(UnitType unit,vf2d pos,std::vector&resourceCost,Resources&enemy_resources,int availableMemory,std::vector>&queuedUnits){ + int enemyTotalResources=enemy_resources.atkSpd+enemy_resources.health+enemy_resources.moveSpd+enemy_resources.procedure+enemy_resources.range; + int totalCost=0; + for(int i=0;iavailableMemory)return false; + if(enemyTotalResources>=totalCost){ + if(enemy_resources.health>0){enemy_resources.health=std::max(0,enemy_resources.health-totalCost);}else + if(enemy_resources.atkSpd>0){enemy_resources.atkSpd=std::max(0,enemy_resources.atkSpd-totalCost);}else + if(enemy_resources.moveSpd>0){enemy_resources.moveSpd=std::max(0,enemy_resources.moveSpd-totalCost);}else + if(enemy_resources.range>0){enemy_resources.range=std::max(0,enemy_resources.range-totalCost);}else + {enemy_resources.procedure=std::max(0,enemy_resources.procedure-totalCost);} + #define TranslateUnit(type) \ + case UnitType::type:{ \ + queuedUnits.emplace_back(std::make_shared(game.GetPGE(),pos,IMAGES,false)); \ + }break; + switch(unit){ + TranslateUnit(MemoryAllocator) + TranslateUnit(LeftShifter) + TranslateUnit(RightShifter) + TranslateUnit(BitRestorer) + TranslateUnit(MemorySwapper) + TranslateUnit(Corrupter) + TranslateUnit(RAMBank) + TranslateUnit(MemoryGuard) + TranslateUnit(Refresher) + TranslateUnit(Turret) + TranslateUnit(_Platform) + } + } + return true; +} + bool Scenario::MissionCompleted(){return false;} void Scenario::Update(){}; void Scenario::Draw(){ diff --git a/olcCodeJam2023Entry/Scenario.h b/olcCodeJam2023Entry/Scenario.h index 2b7cafa..fb5deb0 100644 --- a/olcCodeJam2023Entry/Scenario.h +++ b/olcCodeJam2023Entry/Scenario.h @@ -14,9 +14,13 @@ public: void _Start(); void Draw(); virtual void Start(); - void _Update(); + void _Update(Resources&enemy_resources,std::vector>&collectionPoints,int availableMemory,std::vector>&queuedUnits,std::vector>&SOUNDS); bool transitionToNextLevel=false; LevelName nextLevel=LevelName::STAGE1; + void RunAI(Resources&enemy_resources,std::vector>&collectionPoints,int availableMemory,std::vector>&queuedUnits,std::vector>&SOUNDS); + bool setupEasyMode=false; + std::mapcpCheckTimer; + bool AttemptBuild(UnitType unit,vf2d pos,std::vector&resourceCost,Resources&enemy_resources,int availableMemory,std::vector>&queuedUnits); protected: void DisplayBox(std::string text,bool scaryHoodedFigure=false); void SetCameraTarget(vf2d pos,bool instant=false); @@ -39,6 +43,7 @@ protected: GameFlags&flags; std::string&objective; TileTransformedView&game; + float unitBuildTimer=0; }; class Stage1:public Scenario{ diff --git a/olcCodeJam2023Entry/Unit.h b/olcCodeJam2023Entry/Unit.h index 3cc7ba2..14791cc 100644 --- a/olcCodeJam2023Entry/Unit.h +++ b/olcCodeJam2023Entry/Unit.h @@ -33,6 +33,7 @@ struct Marker{ }; struct Unit{ + friend class Scenario; public: Unit(PixelGameEngine*pge,std::vectormemory,vf2d pos,float radius,Renderable&img,Pixel targetLineColor,Pixel attackingLineColor,bool friendly=false,bool moveable=true,bool friendlyInteractable=false,bool enemyInteractable=true); virtual~Unit(); diff --git a/olcCodeJam2023Entry/VirusAttack.cpp b/olcCodeJam2023Entry/VirusAttack.cpp index 8bfced5..84d06ea 100644 --- a/olcCodeJam2023Entry/VirusAttack.cpp +++ b/olcCodeJam2023Entry/VirusAttack.cpp @@ -180,6 +180,37 @@ void VirusAttack::InitializeLevelData(){ } } #pragma endregion + #pragma region Stage 4 + { + //Stage 4 data. + LevelName stage=STAGE4; + levelData[stage].name=stage; + levelData[stage].cameraStart={96,96}; + levelData[stage].worldZoom={1,1}; + levelData[stage].size={36,36}; + levelData[stage].levelColor=DARK_GREEN; + levelData[stage].bgm=Sound::GRAVITY; + levelData[stage].scenarioIndex=int(stage); + levelData[stage].availableMemory=300; + levelData[stage].player_starting_resources={3,0,0,0,0}; + levelData[stage].enemy_starting_resources={3,0,0,0,0}; + { + std::vector&units=levelData[stage].unitPlacement; + std::vector&collectionPoints=levelData[stage].cpPlacement; + + units.push_back({UnitType::RAMBank,vf2d{4*24,4*24},true}); + for(int i=0;i<5;i++){ + units.push_back({UnitType::MemoryAllocator,vf2d{4*24,6*24},true}); + } + + + for(int i=0;i<5;i++){ + units.push_back({UnitType::MemoryAllocator,vf2d{4*24,30*24},false}); + } + units.push_back({UnitType::RAMBank,vf2d{4*24,32*24},false}); + } + } + #pragma endregion } bool VirusAttack::OnUserCreate(){ @@ -857,7 +888,7 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){ if(flashTimer>1){ flashTimer--; } - SCENARIOS[currentScenario]->_Update(); + SCENARIOS[currentScenario]->_Update(enemy_resources,collectionPoints,currentLevel->availableMemory-GetTotalUsedMemory(),queuedUnits,SOUNDS); if(SCENARIOS[currentScenario]->transitionToNextLevel){ if(SCENARIOS[currentScenario]->nextLevel!=FINISH){ levelToLoad=SCENARIOS[currentScenario]->nextLevel;