Rudimentary AI.

master
sigonasr2 1 year ago
parent 1801f82248
commit ca3f00a924
  1. 1
      olcCodeJam2023Entry/GameFlags.h
  2. 9
      olcCodeJam2023Entry/Info.txt
  3. 132
      olcCodeJam2023Entry/Scenario.cpp
  4. 7
      olcCodeJam2023Entry/Scenario.h
  5. 1
      olcCodeJam2023Entry/Unit.h
  6. 33
      olcCodeJam2023Entry/VirusAttack.cpp

@ -6,4 +6,5 @@ struct GameFlags{
bool limitedBuildOptions=false; bool limitedBuildOptions=false;
bool guideEnabled=false; bool guideEnabled=false;
bool flashMemoryBar=false; bool flashMemoryBar=false;
int difficulty=1; //0=Easy, 1=Normal, 2=Hard
}; };

@ -39,7 +39,7 @@ Fake allies the narrator forgot to switch over
Day 9 Sounds/Music/Menus - Timer (Speedrun) Difficulty Selection Day 9 Sounds/Music/Menus - Timer (Speedrun) Difficulty Selection
Ending...Shows Four Seasons of Loneliness boss zoom out... 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. Normal Difficulty: AI generates resources at normal rate.
Hard Difficulty: AI generates resources at x4 rate. Hard Difficulty: AI generates resources at x4 rate.
@ -153,4 +153,9 @@ Space - Gravity (Ambient 1)
1 Glorious Venture (Ending theme?) 1 Glorious Venture (Ending theme?)
Credits Credits
Finish Scenarios (End condition for the game)
Finish up main menu stuff (including credits)
AI stuff

@ -16,10 +16,11 @@ void Scenario::_Start(){
camera.SetTarget(targetPos); camera.SetTarget(targetPos);
missionCompletedTimer=0; missionCompletedTimer=0;
transitionToNextLevel=false; transitionToNextLevel=false;
setupEasyMode=false;
Start(); Start();
} }
void Scenario::Start(){}; void Scenario::Start(){};
void Scenario::_Update(){ void Scenario::_Update(Resources&enemy_resources,std::vector<std::shared_ptr<CollectionPoint>>&collectionPoints,int availableMemory,std::vector<std::shared_ptr<Unit>>&queuedUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS){
initialWaitTime=std::max(0.f,initialWaitTime-game.GetPGE()->GetElapsedTime()); initialWaitTime=std::max(0.f,initialWaitTime-game.GetPGE()->GetElapsedTime());
missionFinishWaitTime=std::max(0.f,missionFinishWaitTime-game.GetPGE()->GetElapsedTime()); missionFinishWaitTime=std::max(0.f,missionFinishWaitTime-game.GetPGE()->GetElapsedTime());
smallTimePass=std::min(1.f,smallTimePass+game.GetPGE()->GetElapsedTime()); smallTimePass=std::min(1.f,smallTimePass+game.GetPGE()->GetElapsedTime());
@ -31,10 +32,139 @@ void Scenario::_Update(){
} else { } else {
missionCompleted=MissionCompleted(); missionCompleted=MissionCompleted();
} }
if(flags.playerInControl){
RunAI(enemy_resources,collectionPoints,availableMemory,queuedUnits,SOUNDS);
}
if(initialWaitTime==0){ if(initialWaitTime==0){
Update(); Update();
} }
}; };
void Scenario::RunAI(Resources&enemy_resources,std::vector<std::shared_ptr<CollectionPoint>>&collectionPoints,int availableMemory,std::vector<std::shared_ptr<Unit>>&queuedUnits,std::vector<std::unique_ptr<Audio>>&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::array<UnitType,10>unitChoiceList={UnitType::LeftShifter,UnitType::LeftShifter,UnitType::RightShifter,UnitType::RightShifter,
UnitType::Corrupter,UnitType::MemorySwapper,UnitType::BitRestorer,UnitType::BitRestorer,UnitType::_Platform,UnitType::Corrupter};
std::array<std::vector<Memory>,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<type>(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_ptr<UnitClass>buildUnit=std::make_shared<UnitClass>(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<Memory>&resourceCost,Resources&enemy_resources,int availableMemory,std::vector<std::shared_ptr<Unit>>&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;i<resourceCost.size();i++){
totalCost+=resourceCost[i].size;
}
if(totalCost>availableMemory)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<type>(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;} bool Scenario::MissionCompleted(){return false;}
void Scenario::Update(){}; void Scenario::Update(){};
void Scenario::Draw(){ void Scenario::Draw(){

@ -14,9 +14,13 @@ public:
void _Start(); void _Start();
void Draw(); void Draw();
virtual void Start(); virtual void Start();
void _Update(); void _Update(Resources&enemy_resources,std::vector<std::shared_ptr<CollectionPoint>>&collectionPoints,int availableMemory,std::vector<std::shared_ptr<Unit>>&queuedUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS);
bool transitionToNextLevel=false; bool transitionToNextLevel=false;
LevelName nextLevel=LevelName::STAGE1; LevelName nextLevel=LevelName::STAGE1;
void RunAI(Resources&enemy_resources,std::vector<std::shared_ptr<CollectionPoint>>&collectionPoints,int availableMemory,std::vector<std::shared_ptr<Unit>>&queuedUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS);
bool setupEasyMode=false;
std::map<CollectionPoint*,float>cpCheckTimer;
bool AttemptBuild(UnitType unit,vf2d pos,std::vector<Memory>&resourceCost,Resources&enemy_resources,int availableMemory,std::vector<std::shared_ptr<Unit>>&queuedUnits);
protected: protected:
void DisplayBox(std::string text,bool scaryHoodedFigure=false); void DisplayBox(std::string text,bool scaryHoodedFigure=false);
void SetCameraTarget(vf2d pos,bool instant=false); void SetCameraTarget(vf2d pos,bool instant=false);
@ -39,6 +43,7 @@ protected:
GameFlags&flags; GameFlags&flags;
std::string&objective; std::string&objective;
TileTransformedView&game; TileTransformedView&game;
float unitBuildTimer=0;
}; };
class Stage1:public Scenario{ class Stage1:public Scenario{

@ -33,6 +33,7 @@ struct Marker{
}; };
struct Unit{ struct Unit{
friend class Scenario;
public: public:
Unit(PixelGameEngine*pge,std::vector<Memory>memory,vf2d pos,float radius,Renderable&img,Pixel targetLineColor,Pixel attackingLineColor,bool friendly=false,bool moveable=true,bool friendlyInteractable=false,bool enemyInteractable=true); Unit(PixelGameEngine*pge,std::vector<Memory>memory,vf2d pos,float radius,Renderable&img,Pixel targetLineColor,Pixel attackingLineColor,bool friendly=false,bool moveable=true,bool friendlyInteractable=false,bool enemyInteractable=true);
virtual~Unit(); virtual~Unit();

@ -180,6 +180,37 @@ void VirusAttack::InitializeLevelData(){
} }
} }
#pragma endregion #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<UnitData>&units=levelData[stage].unitPlacement;
std::vector<CPData>&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(){ bool VirusAttack::OnUserCreate(){
@ -857,7 +888,7 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){
if(flashTimer>1){ if(flashTimer>1){
flashTimer--; flashTimer--;
} }
SCENARIOS[currentScenario]->_Update(); SCENARIOS[currentScenario]->_Update(enemy_resources,collectionPoints,currentLevel->availableMemory-GetTotalUsedMemory(),queuedUnits,SOUNDS);
if(SCENARIOS[currentScenario]->transitionToNextLevel){ if(SCENARIOS[currentScenario]->transitionToNextLevel){
if(SCENARIOS[currentScenario]->nextLevel!=FINISH){ if(SCENARIOS[currentScenario]->nextLevel!=FINISH){
levelToLoad=SCENARIOS[currentScenario]->nextLevel; levelToLoad=SCENARIOS[currentScenario]->nextLevel;

Loading…
Cancel
Save