diff --git a/olcCodeJam2023Entry/Image.h b/olcCodeJam2023Entry/Image.h index d79000e..88c5357 100644 --- a/olcCodeJam2023Entry/Image.h +++ b/olcCodeJam2023Entry/Image.h @@ -32,5 +32,10 @@ enum Image{ SPD_ICON, RESOURCE, MEMORY_COLLECTION_POINT_HIGHLIGHT, + MEMORY_GUARD, + REFRESHER, + TURRET, + PLATFORM, + GUARD_ICON, }; diff --git a/olcCodeJam2023Entry/Unit.cpp b/olcCodeJam2023Entry/Unit.cpp index 7dea115..0b94f40 100644 --- a/olcCodeJam2023Entry/Unit.cpp +++ b/olcCodeJam2023Entry/Unit.cpp @@ -10,7 +10,7 @@ std::string LeftShifter::unitName="Left Shifter"; std::string LeftShifter::unitDescription="Memory Shifts target memory 1 bit to the left."; std::vector LeftShifter::resourceCost={{RANGE,2},{ATKSPD,2},{MOVESPD,3},{PROCEDURE,1},{HEALTH,4}}; LeftShifter::LeftShifter(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) - :Unit(pge,UnitType::LeftShifter,LeftShifter::resourceCost,pos,12,*IMAGES[LEFT_SHIFTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} + :Unit(pge,LeftShifter::resourceCost,pos,12,*IMAGES[LEFT_SHIFTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} void LeftShifter::Attack(Unit&victim,std::vector>&otherUnits){ victim<<=1; @@ -20,7 +20,7 @@ std::string RightShifter::unitName="Right Shifter"; std::string RightShifter::unitDescription="Memory Shifts target memory 1 bit to the right."; std::vector RightShifter::resourceCost={{HEALTH,4},{RANGE,2},{ATKSPD,2},{MOVESPD,3},{PROCEDURE,1}}; RightShifter::RightShifter(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) - :Unit(pge,UnitType::RightShifter,RightShifter::resourceCost,pos,12,*IMAGES[RIGHT_SHIFTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} + :Unit(pge,RightShifter::resourceCost,pos,12,*IMAGES[RIGHT_SHIFTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} void RightShifter::Attack(Unit&victim,std::vector>&otherUnits){ victim>>=1; @@ -30,7 +30,7 @@ std::string BitRestorer::unitName="Bit Restorer"; std::string BitRestorer::unitDescription="Randomly restores 1 missing bit to a target."; std::vector BitRestorer::resourceCost={{PROCEDURE,6},{RANGE,1},{ATKSPD,1},{MOVESPD,1},{HEALTH,2}}; BitRestorer::BitRestorer(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) - :Unit(pge,UnitType::BitRestorer,BitRestorer::resourceCost,pos,12,*IMAGES[BIT_RESTORER],CONSTANT::HEALER_TARGET_COL,CONSTANT::HEALER_ATTACK_COL,friendly,moveable,true,false){} + :Unit(pge,BitRestorer::resourceCost,pos,12,*IMAGES[BIT_RESTORER],CONSTANT::HEALER_TARGET_COL,CONSTANT::HEALER_ATTACK_COL,friendly,moveable,true,false){} void BitRestorer::Attack(Unit&victim,std::vector>&otherUnits){ std::vectoremptyMemoryPositions; @@ -72,19 +72,43 @@ std::string MemorySwapper::unitName="Memory Swapper"; std::string MemorySwapper::unitDescription="Flips the orientation of all bits of a target around."; std::vector MemorySwapper::resourceCost={{RANGE,3},{ATKSPD,1},{HEALTH,3},{PROCEDURE,3},{MOVESPD,2}}; MemorySwapper::MemorySwapper(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) - :Unit(pge,UnitType::MemorySwapper,MemorySwapper::resourceCost,pos,12,*IMAGES[MEMORY_SWAPPER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable,true){ + :Unit(pge,MemorySwapper::resourceCost,pos,12,*IMAGES[MEMORY_SWAPPER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable,true){ autoAcquireFriendlyTarget=false; } void MemorySwapper::Attack(Unit&victim,std::vector>&otherUnits){ - + std::vectoroldMemory=victim.memory; + for(int i=0;iorder; + for(int i=0;i<5;i++){ + int lowestInd=999999; + Marker*lowest; + if(victim.health.indexindex;} + if(victim.range.indexindex;} + if(victim.atkSpd.indexindex;} + if(victim.moveSpd.indexindex;} + if(victim.procedure.indexindex;} + + order.push_back(lowest); + lowest->index=9999999; + } + std::reverse(order.begin(),order.end()); + int i=0; + int marker=0; + while(markerindex=marker; + marker+=order[i]->size; + i++; + } } std::string Corrupter::unitName="Corrupter"; std::string Corrupter::unitDescription="Chooses a random bit and negates it on a target."; std::vector Corrupter::resourceCost={{ATKSPD,3},{RANGE,1},{PROCEDURE,8},{MOVESPD,4},{HEALTH,4}}; Corrupter::Corrupter(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) - :Unit(pge,UnitType::Corrupter,Corrupter::resourceCost,pos,12,*IMAGES[CORRUPTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} + :Unit(pge,Corrupter::resourceCost,pos,12,*IMAGES[CORRUPTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} void Corrupter::Attack(Unit&victim,std::vector>&otherUnits){ //Chooses a bit at random and corrupts it. @@ -96,7 +120,7 @@ std::string MemoryAllocator::unitName="Memory Allocator"; std::string MemoryAllocator::unitDescription="A unit that builds other units."; std::vector MemoryAllocator::resourceCost={{RANGE,1},{ATKSPD,1},{MOVESPD,1},{PROCEDURE,1},{HEALTH,1}}; MemoryAllocator::MemoryAllocator(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) - :Unit(pge,UnitType::MemoryAllocator,MemoryAllocator::resourceCost,pos,12,*IMAGES[UNIT_ALLOCATOR],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,true,false){ + :Unit(pge,MemoryAllocator::resourceCost,pos,12,*IMAGES[UNIT_ALLOCATOR],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,true,false){ isAllocator=true; } @@ -141,7 +165,7 @@ std::string RAMBank::unitName="RAM Bank"; std::string RAMBank::unitDescription="Allows for the construction of Memory Allocators."; std::vector RAMBank::resourceCost={{RANGE,0},{ATKSPD,0},{MOVESPD,0},{PROCEDURE,25},{HEALTH,16}}; RAMBank::RAMBank(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly) - :Unit(pge,UnitType::RAMBank,RAMBank::resourceCost,pos,41,*IMAGES[RAM_BANK],WHITE,WHITE,friendly,false + :Unit(pge,RAMBank::resourceCost,pos,41,*IMAGES[RAM_BANK],WHITE,WHITE,friendly,false ,false,false ),randomOffset({util::random(128),util::random(128)}),matrixImg(*IMAGES[MATRIX]), originalImg(*IMAGES[RAM_BANK]){ @@ -250,8 +274,56 @@ bool RAMBank::ClickHandled(TileTransformedView&game,Resources&player_resources,s return false; } -Unit::Unit(PixelGameEngine*pge,UnitType type,std::vectormemory,vf2d pos,float radius,Renderable&img,Pixel targetLineColor,Pixel attackingLineColor,bool friendly,bool moveable,bool friendlyInteractable,bool enemyInteractable) -:pos(pos),type(type),radius(radius),ghostPos(pos),img(img),targetLineCol(targetLineColor),attackingLineCol(attackingLineColor),friendly(friendly),moveable(moveable),friendlyInteractable(friendlyInteractable),enemyInteractable(enemyInteractable){ +std::string _Platform::unitName="Corrupter"; +std::string _Platform::unitDescription="Chooses a random bit and negates it on a target."; +std::vector _Platform::resourceCost={{ATKSPD,3},{RANGE,1},{PROCEDURE,8},{MOVESPD,4},{HEALTH,4}}; +_Platform::_Platform(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) + :Unit(pge,_Platform::resourceCost,pos,24,*IMAGES[PLATFORM],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} + +void _Platform::Attack(Unit&victim,std::vector>&otherUnits){}; + +std::string Refresher::unitName="Refresher"; +std::string Refresher::unitDescription="Repairs missing bits for all surrounding units."; +std::vector Refresher::resourceCost={{ATKSPD,3},{RANGE,1},{PROCEDURE,8},{MOVESPD,4},{HEALTH,4}}; +Refresher::Refresher(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) + :Unit(pge,Refresher::resourceCost,pos,24,*IMAGES[REFRESHER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} + +void Refresher::Attack(Unit&victim,std::vector>&otherUnits){ + //Chooses a bit at random and corrupts it. + int randomBit=rand()%victim.memory.size(); + victim.memory[randomBit]=victim.ghostMemory[randomBit]=false; +} + +std::string Turret::unitName="Turret"; +std::string Turret::unitDescription="Automatically targets attack and movement speed memory ranges before others."; +std::vector Turret::resourceCost={{ATKSPD,4},{RANGE,5},{HEALTH,6},{PROCEDURE,16}}; +Turret::Turret(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) + :Unit(pge,Turret::resourceCost,pos,24,*IMAGES[TURRET],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} + +void Turret::Attack(Unit&victim,std::vector>&otherUnits){ + //Chooses a bit at random and corrupts it. + int randomBit=rand()%victim.memory.size(); + victim.memory[randomBit]=victim.ghostMemory[randomBit]=false; +} + +std::string MemoryGuard::unitName="Memory Guard"; +std::string MemoryGuard::unitDescription="Reduces the chance of bit modification for all surrounding units by 30%"; +std::vector MemoryGuard::resourceCost={{HEALTH,10},{ATKSPD,4},{RANGE,4},{PROCEDURE,12}}; +MemoryGuard::MemoryGuard(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) + :Unit(pge,MemoryGuard::resourceCost,pos,24,*IMAGES[MEMORY_GUARD],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,false + ,true,false){} + +void MemoryGuard::Attack(Unit&victim,std::vector>&otherUnits){ + target.reset(); //Doesn't acquire a target. + for(auto&u:otherUnits){ + if(IsFriendly()==u->IsFriendly()&&InRange(u.get())){ + u->SetGuardTime(3); + } + } +} + +Unit::Unit(PixelGameEngine*pge,std::vectormemory,vf2d pos,float radius,Renderable&img,Pixel targetLineColor,Pixel attackingLineColor,bool friendly,bool moveable,bool friendlyInteractable,bool enemyInteractable) +:pos(pos),radius(radius),ghostPos(pos),img(img),targetLineCol(targetLineColor),attackingLineCol(attackingLineColor),friendly(friendly),moveable(moveable),friendlyInteractable(friendlyInteractable),enemyInteractable(enemyInteractable){ int marker=0; for(Memory&mem:memory){ for(int i=0;i>&SO } reloadTimer=std::max(0.f,reloadTimer-pge->GetElapsedTime()); + guardTime=std::max(0.f,guardTime-pge->GetElapsedTime()); lineShift-=pge->GetElapsedTime(); if(lineShift<-25)lineShift+=25; @@ -793,4 +866,16 @@ void Unit::SetBuildUnit(float buildTime,std::unique_ptrfinalUnit){ bool Unit::IsBuilding(){ return buildTime>0; +} + +void Unit::SetGuardTime(float time){ + guardTime=time; +} + +bool Unit::IsGuarded(){ + return guardTime>0; +} + +void Unit::SaveMemory(){ + savedMemory=memory; } \ No newline at end of file diff --git a/olcCodeJam2023Entry/Unit.h b/olcCodeJam2023Entry/Unit.h index 07e571e..40c06f3 100644 --- a/olcCodeJam2023Entry/Unit.h +++ b/olcCodeJam2023Entry/Unit.h @@ -22,6 +22,10 @@ enum class UnitType{ Corrupter, MemoryAllocator, RAMBank, + MemoryGuard, + Refresher, + Turret, + _Platform, }; struct Marker{ @@ -36,7 +40,7 @@ struct Memory{ struct Unit{ public: - Unit(PixelGameEngine*pge,UnitType type,std::vectormemory,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::vectormemory,vf2d pos,float radius,Renderable&img,Pixel targetLineColor,Pixel attackingLineColor,bool friendly=false,bool moveable=true,bool friendlyInteractable=false,bool enemyInteractable=true); int GetHealth(); int GetRange(); int GetAtkSpd(); @@ -45,6 +49,7 @@ public: int GetMemorySize(); std::vectormemory; std::vectorghostMemory; + std::vectorsavedMemory; virtual void Update(PixelGameEngine*pge,std::map>&SOUNDS,std::vector>&queuedUnits); virtual void Attack(Unit&victim,std::vector>&otherUnits)=0; virtual void Draw(TileTransformedView&game,std::map>&IMAGES); @@ -87,6 +92,14 @@ public: bool IsAllocator(); void SetBuildUnit(float buildTime,std::unique_ptrfinalUnit); bool IsBuilding(); + void SetGuardTime(float time); + bool IsGuarded(); + void SaveMemory(); + Marker health={}; + Marker range={}; + Marker atkSpd={}; + Marker moveSpd={}; + Marker procedure={}; std::vector& operator <<=(const int n){ for(int i=0;itarget; std::weak_ptrappliedTarget; vf2d targetLoc=CONSTANT::UNSELECTED; @@ -151,6 +159,7 @@ private: std::weak_ptrself_ptr; float collectionTime=0; UnitType type; + float guardTime=0; }; struct LeftShifter:Unit{ @@ -224,4 +233,36 @@ struct RAMBank:Unit{ static std::vector resourceCost; static std::string unitName; static std::string unitDescription; +}; + +struct _Platform:Unit{ + _Platform(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly=false,bool moveable=true); + void Attack(Unit&victim,std::vector>&otherUnits)override; + static std::vector resourceCost; + static std::string unitName; + static std::string unitDescription; +}; + +struct MemoryGuard:Unit{ + MemoryGuard(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly=false,bool moveable=true); + void Attack(Unit&victim,std::vector>&otherUnits)override; + static std::vector resourceCost; + static std::string unitName; + static std::string unitDescription; +}; + +struct Refresher:Unit{ + Refresher(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly=false,bool moveable=true); + void Attack(Unit&victim,std::vector>&otherUnits)override; + static std::vector resourceCost; + static std::string unitName; + static std::string unitDescription; +}; + +struct Turret:Unit{ + Turret(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly=false,bool moveable=true); + void Attack(Unit&victim,std::vector>&otherUnits)override; + static std::vector resourceCost; + static std::string unitName; + static std::string unitDescription; }; \ No newline at end of file diff --git a/olcCodeJam2023Entry/VirusAttack.cpp b/olcCodeJam2023Entry/VirusAttack.cpp index bc10581..45114b4 100644 --- a/olcCodeJam2023Entry/VirusAttack.cpp +++ b/olcCodeJam2023Entry/VirusAttack.cpp @@ -55,6 +55,11 @@ void VirusAttack::InitializeImages(){ LoadImage(SPD_ICON,"assets/spd_icon.png"); LoadImage(RESOURCE,"assets/material.png"); LoadImage(MEMORY_COLLECTION_POINT_HIGHLIGHT,"assets/memory_collection_point_highlight.png"); + LoadImage(MEMORY_GUARD,"assets/memoryguard.png"); + LoadImage(REFRESHER,"assets/refresher.png"); + LoadImage(TURRET,"assets/turret.png"); + LoadImage(PLATFORM,"assets/platform.png"); + LoadImage(GUARD_ICON,"assets/shieldIcon.png"); } void VirusAttack::InitializeLevelData(){ @@ -76,6 +81,7 @@ void VirusAttack::InitializeLevelData(){ 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++){ @@ -173,6 +179,14 @@ void VirusAttack::LoadLevel(LevelName level){ TranslateUnit(Corrupter) TranslateUnit(MemoryAllocator) TranslateUnit(RAMBank) + TranslateUnit(_Platform) + TranslateUnit(MemoryGuard) + TranslateUnit(Refresher) + TranslateUnit(Turret) + default:{ + std::cout<<"Could not load unit type "< key){return key.second<=0;}); for(auto&u:units){ + u->SaveMemory(); std::weak_ptrclosestUnit; float closestDist=999999; for(auto&u2:units){ @@ -604,6 +619,9 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){ 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); @@ -650,6 +668,22 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){ 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->ghostMemory[changedBit]=u->savedMemory[changedBit]; + } + } + } return true; } diff --git a/olcCodeJam2023Entry/assets/memoryguard.png b/olcCodeJam2023Entry/assets/memoryguard.png new file mode 100644 index 0000000..b1db5d2 Binary files /dev/null and b/olcCodeJam2023Entry/assets/memoryguard.png differ diff --git a/olcCodeJam2023Entry/assets/platform.png b/olcCodeJam2023Entry/assets/platform.png new file mode 100644 index 0000000..83a86c5 Binary files /dev/null and b/olcCodeJam2023Entry/assets/platform.png differ diff --git a/olcCodeJam2023Entry/assets/refresher.png b/olcCodeJam2023Entry/assets/refresher.png new file mode 100644 index 0000000..ff8f7a5 Binary files /dev/null and b/olcCodeJam2023Entry/assets/refresher.png differ diff --git a/olcCodeJam2023Entry/assets/shieldIcon.png b/olcCodeJam2023Entry/assets/shieldIcon.png new file mode 100644 index 0000000..563876d Binary files /dev/null and b/olcCodeJam2023Entry/assets/shieldIcon.png differ diff --git a/olcCodeJam2023Entry/assets/turret.png b/olcCodeJam2023Entry/assets/turret.png new file mode 100644 index 0000000..0f306c3 Binary files /dev/null and b/olcCodeJam2023Entry/assets/turret.png differ