|
|
|
#include "Unit.h"
|
|
|
|
#include "Constant.h"
|
|
|
|
#include "olcUTIL_Geometry2D.h"
|
|
|
|
#include "TileManager.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
BasicUnit::BasicUnit(vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
|
|
|
|
:Unit({
|
|
|
|
{HEALTH,4},
|
|
|
|
{RANGE,2},
|
|
|
|
{ATKSPD,2},
|
|
|
|
{MOVESPD,3},
|
|
|
|
{PROCEDURE,1},
|
|
|
|
},pos,*IMAGES[VIRUS_IMG1],friendly,moveable){}
|
|
|
|
|
|
|
|
|
|
|
|
void BasicUnit::Attack(Unit&victim){
|
|
|
|
victim<<=1;
|
|
|
|
}
|
|
|
|
|
|
|
|
BasicUnit2::BasicUnit2(vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
|
|
|
|
:Unit({
|
|
|
|
{RANGE,2},
|
|
|
|
{ATKSPD,2},
|
|
|
|
{MOVESPD,3},
|
|
|
|
{PROCEDURE,1},
|
|
|
|
{HEALTH,4},
|
|
|
|
},pos,*IMAGES[VIRUS_IMG1],friendly,moveable){}
|
|
|
|
|
|
|
|
void BasicUnit2::Attack(Unit&victim){
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
LeftShifter::LeftShifter(vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
|
|
|
|
:Unit({
|
|
|
|
{RANGE,2},
|
|
|
|
{ATKSPD,2},
|
|
|
|
{MOVESPD,3},
|
|
|
|
{PROCEDURE,1},
|
|
|
|
{HEALTH,4},
|
|
|
|
},pos,*IMAGES[LEFT_SHIFTER],friendly,moveable){}
|
|
|
|
|
|
|
|
void LeftShifter::Attack(Unit&victim){
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
RightShifter::RightShifter(vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
|
|
|
|
:Unit({
|
|
|
|
{HEALTH,4},
|
|
|
|
{RANGE,2},
|
|
|
|
{ATKSPD,2},
|
|
|
|
{MOVESPD,3},
|
|
|
|
{PROCEDURE,1},
|
|
|
|
},pos,*IMAGES[RIGHT_SHIFTER],friendly,moveable){}
|
|
|
|
|
|
|
|
void RightShifter::Attack(Unit&victim){
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
BitRestorer::BitRestorer(vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
|
|
|
|
:Unit({
|
|
|
|
{PROCEDURE,6},
|
|
|
|
{RANGE,1},
|
|
|
|
{ATKSPD,1},
|
|
|
|
{MOVESPD,1},
|
|
|
|
{HEALTH,2},
|
|
|
|
},pos,*IMAGES[BIT_RESTORER],friendly,moveable){}
|
|
|
|
|
|
|
|
void BitRestorer::Attack(Unit&victim){
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
MemorySwapper::MemorySwapper(vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
|
|
|
|
:Unit({
|
|
|
|
{RANGE,3},
|
|
|
|
{ATKSPD,1},
|
|
|
|
{HEALTH,3},
|
|
|
|
{PROCEDURE,3},
|
|
|
|
{MOVESPD,2},
|
|
|
|
},pos,*IMAGES[MEMORY_SWAPPER],friendly,moveable){}
|
|
|
|
|
|
|
|
void MemorySwapper::Attack(Unit&victim){
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Corrupter::Corrupter(vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
|
|
|
|
:Unit({
|
|
|
|
{ATKSPD,3},
|
|
|
|
{RANGE,1},
|
|
|
|
{PROCEDURE,8},
|
|
|
|
{MOVESPD,4},
|
|
|
|
{HEALTH,4},
|
|
|
|
},pos,*IMAGES[CORRUPTER],friendly,moveable){}
|
|
|
|
|
|
|
|
void Corrupter::Attack(Unit&victim){
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
MemoryAllocator::MemoryAllocator(vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
|
|
|
|
:Unit({
|
|
|
|
{RANGE,1},
|
|
|
|
{ATKSPD,1},
|
|
|
|
{MOVESPD,1},
|
|
|
|
{PROCEDURE,1},
|
|
|
|
{HEALTH,1},
|
|
|
|
},pos,*IMAGES[UNIT_ALLOCATOR],friendly){}
|
|
|
|
|
|
|
|
void MemoryAllocator::Attack(Unit&victim){
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
RAMBank::RAMBank(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly)
|
|
|
|
:Unit({
|
|
|
|
{RANGE,0},
|
|
|
|
{ATKSPD,0},
|
|
|
|
{MOVESPD,0},
|
|
|
|
{PROCEDURE,25},
|
|
|
|
{HEALTH,16},
|
|
|
|
},pos,*IMAGES[RAM_BANK],friendly,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){
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void RAMBank::Update(PixelGameEngine*pge){
|
|
|
|
pge->SetDrawTarget(img.Sprite());
|
|
|
|
for(int y=0;y<img.Sprite()->height;y++){
|
|
|
|
for(int x=0;x<img.Sprite()->width;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<Image,std::unique_ptr<Renderable>>&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::vector<Memory>memory,vf2d pos,Renderable&img,bool friendly,bool moveable)
|
|
|
|
:pos(pos),ghostPos(pos),img(img),friendly(friendly),moveable(moveable){
|
|
|
|
int marker=0;
|
|
|
|
for(Memory&mem:memory){
|
|
|
|
for(int i=0;i<mem.size;i++){
|
|
|
|
this->memory.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::Draw(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&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<Image,std::unique_ptr<Renderable>>&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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
for(int i=0;i<GetMemorySize();i++){
|
|
|
|
CheckColor(i,col);
|
|
|
|
|
|
|
|
game.FillRectDecal({float(initialBarX)+i*CONSTANT::BAR_SQUARE_SIZE.x,
|
|
|
|
float(initialBarY)},CONSTANT::BAR_SQUARE_SIZE,ghostMemory[i]?col:col/4);
|
|
|
|
game.DrawRectDecal({float(initialBarX)+i*CONSTANT::BAR_SQUARE_SIZE.x,
|
|
|
|
float(initialBarY)},CONSTANT::BAR_SQUARE_SIZE,BLACK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int Unit::GetBits(Marker&m){
|
|
|
|
int activeBits=0;
|
|
|
|
for(int i=0;i<m.size;i++){
|
|
|
|
if(memory[i+m.index]){
|
|
|
|
activeBits++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return activeBits;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Unit::GetHealth(){
|
|
|
|
return GetBits(health);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Unit::GetRange(){
|
|
|
|
return GetBits(range);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Unit::GetAtkSpd(){
|
|
|
|
return GetBits(atkSpd);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Unit::GetMoveSpd(){
|
|
|
|
return GetBits(moveSpd);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Unit::GetProcedure(){
|
|
|
|
return GetBits(procedure);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Unit::GetMemorySize(){
|
|
|
|
return memory.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Unit::_Update(PixelGameEngine*pge){
|
|
|
|
if(!target.expired()){
|
|
|
|
auto ptrTarget=target.lock();
|
|
|
|
if(!InRange(ptrTarget)){
|
|
|
|
SetPos(GetPos()+(ptrTarget->GetPos()-pos).norm()*GetMoveSpd()*24*pge->GetElapsedTime());
|
|
|
|
} else {
|
|
|
|
//TODO Attack here.
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
if(targetLoc!=CONSTANT::UNSELECTED){
|
|
|
|
float dist=geom2d::line<float>(pos,targetLoc).length();
|
|
|
|
if(dist>24){
|
|
|
|
SetPos(GetPos()+(targetLoc-pos).norm()*GetMoveSpd()*24*pge->GetElapsedTime());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!IsFriendly()){
|
|
|
|
if(changeDirTimer==0){
|
|
|
|
changeDirTimer=rand()%30;
|
|
|
|
switch(rand()%4){
|
|
|
|
case 0:{
|
|
|
|
movementVel={16,0};
|
|
|
|
}break;
|
|
|
|
case 1:{
|
|
|
|
movementVel={0,16};
|
|
|
|
}break;
|
|
|
|
case 2:{
|
|
|
|
movementVel={-16,0};
|
|
|
|
}break;
|
|
|
|
case 3:{
|
|
|
|
movementVel={0,-16};
|
|
|
|
}break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SetPos(GetPos()+movementVel*pge->GetElapsedTime());
|
|
|
|
changeDirTimer=std::max(0.f,changeDirTimer-pge->GetElapsedTime());
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!GhostInFogOfWar()&&InFogOfWar()){
|
|
|
|
HideGhost();
|
|
|
|
}
|
|
|
|
|
|
|
|
reloadTimer=std::max(0.f,reloadTimer-pge->GetElapsedTime());
|
|
|
|
|
|
|
|
Update(pge);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<bool> operator <<(Unit&u,const int n){
|
|
|
|
std::vector<bool>tempMem=u.memory;
|
|
|
|
for(int i=0;i<u.GetMemorySize()-1;i++){
|
|
|
|
tempMem[i]=tempMem[i+1];
|
|
|
|
}
|
|
|
|
tempMem[u.GetMemorySize()-1]=0;
|
|
|
|
return tempMem;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<bool> operator >>(Unit&u,const int n){
|
|
|
|
std::vector<bool>tempMem=u.memory;
|
|
|
|
for(int i=1;i<u.GetMemorySize();i++){
|
|
|
|
tempMem[i]=tempMem[i-1];
|
|
|
|
}
|
|
|
|
tempMem[0]=0;
|
|
|
|
return tempMem;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Unit::IsFriendly(){
|
|
|
|
return friendly;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Unit::IsSelected(){
|
|
|
|
return selected;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Unit::Select(){
|
|
|
|
selected=true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Unit::Deselect(){
|
|
|
|
selected=false;
|
|
|
|
}
|
|
|
|
|
|
|
|
vf2d Unit::GetPos(){
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Unit::IsDead(){
|
|
|
|
return dead;
|
|
|
|
}
|
|
|
|
|
|
|
|
vf2d Unit::GetUnitSize(){
|
|
|
|
return img.Sprite()->Size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Unit::SetTargetUnit(std::weak_ptr<Unit>target){
|
|
|
|
this->target=target;
|
|
|
|
this->targetLoc=CONSTANT::UNSELECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Unit::SetTargetLocation(vf2d targetLoc){
|
|
|
|
this->target.reset();
|
|
|
|
this->targetLoc=targetLoc;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Unit::InRange(std::shared_ptr<Unit>target){
|
|
|
|
float dist=geom2d::line(GetPos(),target->GetPos()).length();
|
|
|
|
return dist<24*(GetRange()+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Unit::InRange(vf2d pos){
|
|
|
|
float dist=geom2d::line(GetPos(),pos).length();
|
|
|
|
return dist<24*(GetRange()+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Unit::SetPos(vf2d newPos){
|
|
|
|
pos=newPos;
|
|
|
|
if(!InFogOfWar()){
|
|
|
|
ghostPos=pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Unit::AttemptAttack(Unit*unit){
|
|
|
|
if(reloadTimer>0)return;
|
|
|
|
Unit*finalTarget=nullptr;
|
|
|
|
if(unit!=nullptr){
|
|
|
|
finalTarget=unit;
|
|
|
|
if(!target.expired()){
|
|
|
|
auto ptrTarget=target.lock();
|
|
|
|
if(InRange(ptrTarget)){
|
|
|
|
finalTarget=ptrTarget.get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(finalTarget!=nullptr){
|
|
|
|
if(InRange(finalTarget->GetPos())){
|
|
|
|
_Attack(finalTarget); //Call the parent function first, followed by the child.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Unit::Update(PixelGameEngine*pge){}
|
|
|
|
|
|
|
|
void Unit::_Attack(Unit*finalTarget){
|
|
|
|
Attack(*finalTarget);
|
|
|
|
reloadTimer=1.f/(GetAtkSpd()/2.f);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|