You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
VirusAttack/olcCodeJam2023Entry/Unit.cpp

299 lines
5.8 KiB

#include "Unit.h"
#include "Constant.h"
#include "olcUTIL_Geometry2D.h"
#include "TileManager.h"
BasicUnit::BasicUnit(vf2d pos,Renderable&img,bool friendly)
:Unit({
{HEALTH,4},
{RANGE,2},
{ATKSPD,2},
{MOVESPD,3},
{PROCEDURE,1},
},pos,img,friendly){}
void BasicUnit::Attack(Unit&victim){
victim<<=1;
}
BasicUnit2::BasicUnit2(vf2d pos,Renderable&img,bool friendly)
:Unit({
{RANGE,2},
{ATKSPD,2},
{MOVESPD,3},
{PROCEDURE,1},
{HEALTH,4},
},pos,img,friendly){}
void BasicUnit2::Attack(Unit&victim){
}
Unit::Unit(std::vector<Memory>memory,vf2d pos,Renderable&img,bool friendly)
:pos(pos),ghostPos(pos),img(img),friendly(friendly){
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){
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,CONSTANT::SELECTION_CIRCLE.Decal(),0,CONSTANT::SELECTION_CIRCLE.Sprite()->Size()/2,vf2d(img.Sprite()->Size())/CONSTANT::SELECTION_CIRCLE.Sprite()->Size(),WHITE);
}
}
void Unit::DrawHud(TileTransformedView&game){
int initialBarX=ghostPos.x-GetMemorySize()/2*CONSTANT::BAR_SQUARE_SIZE.x;
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(float fElapsedTime){
if(!target.expired()){
auto ptrTarget=target.lock();
if(!InRange(ptrTarget)){
SetPos(GetPos()+(ptrTarget->GetPos()-pos).norm()*GetMoveSpd()*24*fElapsedTime);
} 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*fElapsedTime);
}
}
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*fElapsedTime);
changeDirTimer=std::max(0.f,changeDirTimer-fElapsedTime);
}
reloadTimer=std::max(0.f,reloadTimer-fElapsedTime);
}
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::_Attack(Unit*finalTarget){
Attack(*finalTarget);
reloadTimer=1.f/GetAtkSpd();
}
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;
}