#include "Unit.h" #include "Constant.h" #include "olcUTIL_Geometry2D.h" #include "TileManager.h" #include "util.h" BasicUnit::BasicUnit(vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) :Unit({ {HEALTH,4}, {RANGE,2}, {ATKSPD,2}, {MOVESPD,3}, {PROCEDURE,1}, },pos,12,*IMAGES[VIRUS_IMG1],friendly,moveable){} void BasicUnit::Attack(Unit&victim,std::vector>&otherUnits){ victim<<=1; } BasicUnit2::BasicUnit2(vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) :Unit({ {RANGE,2}, {ATKSPD,2}, {MOVESPD,3}, {PROCEDURE,1}, {HEALTH,4}, },pos,12,*IMAGES[VIRUS_IMG1],friendly,moveable){} void BasicUnit2::Attack(Unit&victim,std::vector>&otherUnits){ victim>>=1; } LeftShifter::LeftShifter(vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) :Unit({ {RANGE,2}, {ATKSPD,2}, {MOVESPD,3}, {PROCEDURE,1}, {HEALTH,4}, },pos,12,*IMAGES[LEFT_SHIFTER],friendly,moveable){} void LeftShifter::Attack(Unit&victim,std::vector>&otherUnits){ victim<<=1; } RightShifter::RightShifter(vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) :Unit({ {HEALTH,4}, {RANGE,2}, {ATKSPD,2}, {MOVESPD,3}, {PROCEDURE,1}, },pos,12,*IMAGES[RIGHT_SHIFTER],friendly,moveable){} void RightShifter::Attack(Unit&victim,std::vector>&otherUnits){ victim>>=1; } BitRestorer::BitRestorer(vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) :Unit({ {PROCEDURE,6}, {RANGE,1}, {ATKSPD,1}, {MOVESPD,1}, {HEALTH,2}, },pos,12,*IMAGES[BIT_RESTORER],friendly,moveable,true,false){} void BitRestorer::Attack(Unit&victim,std::vector>&otherUnits){ std::vectoremptyMemoryPositions; for(int i=0;i>&otherUnits){ std::vectoremptyMemoryPositions; for(auto&u:otherUnits){ if(u.get()!=this&&u->IsFriendly()&&InRange(u)){ for(int i=0;iGetMemorySize();i++){ if(!u->memory[i]){ emptyMemoryPositions.emplace_back(i); } } if(emptyMemoryPositions.size()!=0){ int randomBit=emptyMemoryPositions[rand()%emptyMemoryPositions.size()]; u->memory[randomBit]=u->ghostMemory[randomBit]=true; return; } } } } MemorySwapper::MemorySwapper(vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) :Unit({ {RANGE,3}, {ATKSPD,1}, {HEALTH,3}, {PROCEDURE,3}, {MOVESPD,2}, },pos,12,*IMAGES[MEMORY_SWAPPER],friendly,moveable,true){} void MemorySwapper::Attack(Unit&victim,std::vector>&otherUnits){ } Corrupter::Corrupter(vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) :Unit({ {ATKSPD,3}, {RANGE,1}, {PROCEDURE,8}, {MOVESPD,4}, {HEALTH,4}, },pos,12,*IMAGES[CORRUPTER],friendly,moveable){} void Corrupter::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; } MemoryAllocator::MemoryAllocator(vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) :Unit({ {RANGE,1}, {ATKSPD,1}, {MOVESPD,1}, {PROCEDURE,1}, {HEALTH,1}, },pos,12,*IMAGES[UNIT_ALLOCATOR],friendly,true,false){} void MemoryAllocator::Attack(Unit&victim,std::vector>&otherUnits){ } RAMBank::RAMBank(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly) :Unit({ {RANGE,0}, {ATKSPD,0}, {MOVESPD,0}, {PROCEDURE,25}, {HEALTH,16}, },pos,41,*IMAGES[RAM_BANK],friendly,false ,false,false ),randomOffset({util::random(128),util::random(128)}),matrixImg(*IMAGES[MATRIX]), originalImg(*IMAGES[RAM_BANK]){ img.Create(IMAGES[RAM_BANK]->Sprite()->width,IMAGES[RAM_BANK]->Sprite()->height); pge->SetDrawTarget(img.Sprite()); pge->Clear(BLANK); pge->DrawSprite({0,0},IMAGES[RAM_BANK]->Sprite()); pge->SetDrawTarget(nullptr); } void RAMBank::Attack(Unit&victim,std::vector>&otherUnits){ } void RAMBank::Update(PixelGameEngine*pge){ pge->SetDrawTarget(img.Sprite()); for(int y=0;yheight;y++){ for(int x=0;xwidth;x++){ Pixel col = originalImg.Sprite()->GetPixel(x,y); if(col==WHITE){ pge->Draw(x,y,matrixImg.Sprite()->GetPixel(int(x+randomOffset.x),int(y+randomOffset.y))); } } } img.Decal()->Update(); pge->SetDrawTarget(nullptr); } void RAMBank::Draw(TileTransformedView&game,std::map>&IMAGES){ game.DrawRotatedDecal(GetGhostPos(),img.Decal(),0,img.Sprite()->Size()/2,{1,1},friendly?Pixel{192,192,255}:Pixel{255,192,192}); if(IsSelected()){ game.DrawRotatedDecal(GetGhostPos(),IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),WHITE); } } Unit::Unit(std::vectormemory,vf2d pos,float radius,Renderable&img,bool friendly,bool moveable,bool friendlyInteractable,bool enemyInteractable) :pos(pos),radius(radius),ghostPos(pos),img(img),friendly(friendly),moveable(moveable),friendlyInteractable(friendlyInteractable),enemyInteractable(enemyInteractable){ int marker=0; for(Memory&mem:memory){ for(int i=0;imemory.push_back(true); this->ghostMemory.push_back(true); } switch(mem.type){ case HEALTH:{ health.index=marker; health.size=mem.size; }break; case RANGE:{ range.index=marker; range.size=mem.size; }break; case ATKSPD:{ atkSpd.index=marker; atkSpd.size=mem.size; }break; case MOVESPD:{ moveSpd.index=marker; moveSpd.size=mem.size; }break; case PROCEDURE:{ procedure.index=marker; procedure.size=mem.size; }break; } marker+=mem.size; } } void Unit::DrawRangeIndicator(PixelGameEngine*pge,TileTransformedView&game,std::map>&IMAGES){ if(!CanInteractWithAllies()&&!CanInteractWithEnemies())return; float dist=geom2d::line(game.ScreenToWorld(pge->GetMousePos()),GetGhostPos()).length(); float range=12*(GetRange()+1); float totalRange=GetUnitSize().x/2+range; if(IsSelected()){ Pixel col; if(CanInteractWithAllies()&&!CanInteractWithEnemies()){ col={40,127,173}; } else { col={0,196,0}; } game.DrawRotatedDecal(GetGhostPos(),IMAGES[RANGE_INDICATOR]->Decal(),0,IMAGES[RANGE_INDICATOR]->Sprite()->Size()/2,{totalRange/12,totalRange/12},col); }else if(distDecal(),0,IMAGES[RANGE_INDICATOR]->Sprite()->Size()/2,{totalRange/12,totalRange/12},{col.r,col.g,col.b,uint8_t((1.f-(dist/(range*2)))*255)}); } } void Unit::Draw(TileTransformedView&game,std::map>&IMAGES){ game.DrawRotatedDecal(ghostPos,img.Decal(),0,img.Sprite()->Size()/2,{1,1},friendly?Pixel{192,192,255}:Pixel{255,192,192}); if(IsSelected()){ game.DrawRotatedDecal(ghostPos,IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),WHITE); } } void Unit::DrawHud(TileTransformedView&game,std::map>&IMAGES){ int initialBarX=ghostPos.x-GetMemorySize()/2*CONSTANT::BAR_SQUARE_SIZE.x-CONSTANT::BAR_SQUARE_SIZE.x/2; int initialBarY=ghostPos.y-CONSTANT::BAR_SQUARE_SIZE.y-img.Sprite()->height/2-2; Pixel col=0; auto CheckColor=[&](int i,Pixel&col){ if(health.index==i){ col=CONSTANT::HEALTH_COLOR; } if(range.index==i){ col=CONSTANT::RANGE_COLOR; } if(atkSpd.index==i){ col=CONSTANT::ATKSPD_COLOR; } if(moveSpd.index==i){ col=CONSTANT::MOVESPD_COLOR; } if(procedure.index==i){ col=CONSTANT::PROCEDURE_COLOR; } }; if(GetHealth()>0){ game.FillRectDecal(vf2d{float(initialBarX)+health.index*CONSTANT::BAR_SQUARE_SIZE.x, float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*health.size-1,2},CONSTANT::HEALTH_COLOR); } if(GetAtkSpd()>0){ game.FillRectDecal(vf2d{float(initialBarX)+atkSpd.index*CONSTANT::BAR_SQUARE_SIZE.x, float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*atkSpd.size-1,2},CONSTANT::ATKSPD_COLOR); } if(GetMoveSpd()>0){ game.FillRectDecal(vf2d{float(initialBarX)+moveSpd.index*CONSTANT::BAR_SQUARE_SIZE.x, float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*moveSpd.size-1,2},CONSTANT::MOVESPD_COLOR); } if(GetProcedure()>0){ game.FillRectDecal(vf2d{float(initialBarX)+procedure.index*CONSTANT::BAR_SQUARE_SIZE.x, float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*procedure.size-1,2},CONSTANT::PROCEDURE_COLOR); } if(GetRange()>0){ game.FillRectDecal(vf2d{float(initialBarX)+range.index*CONSTANT::BAR_SQUARE_SIZE.x, float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*range.size-1,2},CONSTANT::RANGE_COLOR); } for(int i=0;iGetPos()-pos).norm()*GetMoveSpd()*24*pge->GetElapsedTime()); } } else if(targetLoc!=CONSTANT::UNSELECTED){ float dist=geom2d::line(pos,targetLoc).length(); if(dist>24){ SetPos(GetPos()+(targetLoc-pos).norm()*GetMoveSpd()*24*pge->GetElapsedTime()); } } if(!IsFriendly()){ _RunAI(pge); } if(!GhostInFogOfWar()&&InFogOfWar()){ HideGhost(); } reloadTimer=std::max(0.f,reloadTimer-pge->GetElapsedTime()); Update(pge); } std::vector operator <<(Unit&u,const int n){ std::vectortempMem=u.memory; for(int i=0;i operator >>(Unit&u,const int n){ std::vectortempMem=u.memory; for(int i=1;itarget){ this->target=target; this->targetLoc=CONSTANT::UNSELECTED; } void Unit::SetTargetLocation(vf2d targetLoc){ this->target.reset(); this->targetLoc=targetLoc; } bool Unit::InRange(std::shared_ptrtarget){ return InRange(target.get()); } bool Unit::InRange(Unit*target){ float range=12*(GetRange()+1); float totalRange=GetUnitSize().x/2+range; return geom2d::overlaps(geom2d::circle{GetPos(),totalRange},geom2d::circle{target->GetPos(),target->GetUnitSize().x/2}); } bool Unit::InRange(vf2d pos){ float range=12*(GetRange()+1); float totalRange=GetUnitSize().x/2+range; return geom2d::overlaps(geom2d::circle{GetPos(),totalRange},geom2d::circle{pos,0.1}); } void Unit::SetPos(vf2d newPos){ pos=newPos; if(!InFogOfWar()){ ghostPos=pos; } } void Unit::AttemptAttack(std::weak_ptrattacker,std::weak_ptrunit,std::vector>&otherUnits){ if(reloadTimer>0)return; std::weak_ptrfinalTarget; if(!unit.expired()){ finalTarget=unit; if(!target.expired()){ auto ptrTarget=target.lock(); if(InRange(ptrTarget)){ finalTarget=ptrTarget; } } } if(!finalTarget.expired()){ if(InRange(finalTarget.lock())){ _Attack(attacker,finalTarget,otherUnits); //Call the parent function first, followed by the child. } } } void Unit::Update(PixelGameEngine*pge){} void Unit::Attacked(std::weak_ptrattacker){} void Unit::_Attacked(std::weak_ptrattacker){ Attacked(attacker); if(attacker.lock()->IsFriendly()!=IsFriendly()&&CanInteractWithEnemies()){ SetTargetUnit(attacker); } } void Unit::_Attack(std::weak_ptrattacker,std::weak_ptrfinalTarget,std::vector>&otherUnits){ if(GetAtkSpd()>0){ Attack(*finalTarget.lock(),otherUnits); finalTarget.lock()->_Attacked(attacker); reloadTimer=1.f/(GetAtkSpd()/2.f); if(GetCurrentTarget().expired()&&!IsFriendly()){ if(finalTarget.lock()->IsFriendly()!=IsFriendly()&&CanInteractWithEnemies()){ SetTargetUnit(finalTarget); } } } } bool Unit::InFogOfWar(){ return TileManager::visibleTiles.count(GetPos()/96)==0; } bool Unit::GhostInFogOfWar(){ return TileManager::visibleTiles.count(ghostPos/96)==0; } void Unit::HideGhost(){ ghostPos={99999,-99999}; } vf2d Unit::GetGhostPos(){ return ghostPos; } bool Unit::IsMoveable(){ return moveable; } bool Unit::CanInteractWithAllies(){ return friendlyInteractable; } bool Unit::CanInteractWithEnemies(){ return enemyInteractable; } Renderable&Unit::GetImage(){ return img; } std::weak_ptrUnit::GetCurrentTarget(){ return target; }