Skip to content

Commit

Permalink
Ability to sentry units
Browse files Browse the repository at this point in the history
  • Loading branch information
jzeiber committed Nov 22, 2023
1 parent 3969a6f commit f3977a6
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 74 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Land units may disembark by moving from the sea unit to a land space

Water units that dock at a city will disembark their embarked units at that city (Land units in this situation maintain their movement points)

You may sentry a unit to skip them when cycling to the next unit in the menu. To select them while in sentry status you must scroll to the unit's position on the map and select next unit at loc. If an enemy moves within 4 spaces of unit it will automatically remove sentry status.

Selecting building "None" in a city production will convert 50% of excess resources into gold (It will still create the necessary resources for the upkeep of units from this city)

Cities will auto select which surrounding tiles to gather resources from. Food production is prioritized first.
Expand Down Expand Up @@ -64,7 +66,7 @@ Aqueduct - Allows city expanding beyond a population of 15 (must have granary as
- No fog of war
- No Science/Tech tree
- No government
- No sentry/fotifications/goto for units
- No fotifications/goto for units
- No diplomacy
- No trade routes
- No roads/land improvements
Expand Down
2 changes: 1 addition & 1 deletion bundle/index.html

Large diffs are not rendered by default.

Binary file modified cart/cart.wasm
Binary file not shown.
71 changes: 47 additions & 24 deletions src/src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,12 +211,12 @@ void Game::HandleChangeState()
}
}

int32_t Game::NextUnitIndex(const int8_t civindex, const int32_t currentunitindex) const
int32_t Game::NextUnitIndex(const int8_t civindex, const int32_t currentunitindex, const bool skipsentry) const
{
return NextUnitAtLocIndex(civindex,-999,-999,currentunitindex);
return NextUnitAtLocIndex(civindex,-999,-999,currentunitindex,skipsentry);
}

int32_t Game::NextUnitAtLocIndex(const int8_t civindex, const int32_t x, const int32_t y, const int32_t currentunitindex) const
int32_t Game::NextUnitAtLocIndex(const int8_t civindex, const int32_t x, const int32_t y, const int32_t currentunitindex, const bool skipsentry) const
{
const int32_t startindex=(currentunitindex>=0 && currentunitindex<countof(m_gamedata.m_unit) ? currentunitindex : 0);
int32_t idx;
Expand All @@ -226,7 +226,10 @@ int32_t Game::NextUnitAtLocIndex(const int8_t civindex, const int32_t x, const i
{
idx=0;
}
if(m_gamedata.m_unit[idx].owner==civindex && (m_gamedata.m_unit[idx].flags & UNIT_ALIVE)==UNIT_ALIVE && ((x==-999 && y==-999) || (m_gamedata.m_unit[idx].x==x && m_gamedata.m_unit[idx].y==y)))
if(m_gamedata.m_unit[idx].owner==civindex && (m_gamedata.m_unit[idx].flags & UNIT_ALIVE)
&& ((x==-999 && y==-999) || (m_gamedata.m_unit[idx].x==x && m_gamedata.m_unit[idx].y==y))
&& (skipsentry==false || !(m_gamedata.m_unit[idx].flags & UNIT_SENTRY))
)
{
return idx;
}
Expand Down Expand Up @@ -257,7 +260,7 @@ int32_t Game::UnitIndexAtLocation(const int8_t owneridx, const int32_t x, const
const MapCoord mc(m_gamedata.m_map->Width(),m_gamedata.m_map->Height(),x,y);
for(size_t i=0; i<countof(m_gamedata.m_unit); i++)
{
if(((m_gamedata.m_unit[i].flags & UNIT_ALIVE) == UNIT_ALIVE) && m_gamedata.m_unit[i].x==mc.X() && m_gamedata.m_unit[i].y==mc.Y() && (owneridx==-1 || owneridx==m_gamedata.m_unit[i].owner))
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) && m_gamedata.m_unit[i].x==mc.X() && m_gamedata.m_unit[i].y==mc.Y() && (owneridx==-1 || owneridx==m_gamedata.m_unit[i].owner))
{
return i;
}
Expand Down Expand Up @@ -356,7 +359,7 @@ void Game::EndGameTurn()
// adjust movement points for all units
for(size_t i=0; i<countof(m_gamedata.m_unit); i++)
{
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE)==UNIT_ALIVE)
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE))
{
m_gamedata.m_unit[i].movesleft=unitdata[m_gamedata.m_unit[i].type].moves;
}
Expand All @@ -381,7 +384,7 @@ void Game::EndGameTurn()
// make sure units have enough resouces from their home city - if not then disband them
for(size_t i=0; i<countof(m_gamedata.m_unit); i++)
{
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) == UNIT_ALIVE)
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE))
{
const int32_t ci=i/UNITS_PER_CITY;
// not enough resources - disband unit
Expand Down Expand Up @@ -542,6 +545,8 @@ void Game::EndGameTurn()
}
}

CheckSentry();

// TODO - go through cities - make sure production enough to handle units - if not then remove units until it is
// expand food storage and when hit max expand population
// add and built units
Expand Down Expand Up @@ -629,7 +634,7 @@ int32_t Game::FreeUnitIndex(const int32_t cityindex) const
{
for(size_t i=(cityindex*UNITS_PER_CITY); i<(cityindex*UNITS_PER_CITY)+UNITS_PER_CITY; i++)
{
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE)!=UNIT_ALIVE)
if(!(m_gamedata.m_unit[i].flags & UNIT_ALIVE))
{
return i;
}
Expand All @@ -643,7 +648,7 @@ int32_t Game::CityUnitCount(const uint8_t cityindex) const
int32_t count=0;
for(size_t i=(cityindex*UNITS_PER_CITY); i<(cityindex*UNITS_PER_CITY)+UNITS_PER_CITY; i++)
{
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) == UNIT_ALIVE)
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE))
{
count++;
}
Expand All @@ -657,7 +662,7 @@ bool Game::CanFoundCity(const uint8_t civindex, const int32_t settlerindex) cons
if(civindex<countof(m_gamedata.m_civ) && settlerindex>=0 && settlerindex<countof(m_gamedata.m_unit))
{
const Unit *u=&(m_gamedata.m_unit[settlerindex]);
if((u->flags & UNIT_ALIVE)==UNIT_ALIVE && u->type==UNITTYPE_SETTLER && u->owner==civindex && u->movesleft>0)
if((u->flags & UNIT_ALIVE) && u->type==UNITTYPE_SETTLER && u->owner==civindex && u->movesleft>0)
{
if(m_gamedata.m_map->GetBaseType(u->x,u->y)==BaseTerrain::BASETERRAIN_LAND && CityInRadius(-1,u->x,u->y,4)==-1)
{
Expand Down Expand Up @@ -694,7 +699,7 @@ bool Game::ExpandCity(const uint8_t playerindex, const int32_t settlerindex)
if(playerindex>=0 && playerindex<countof(m_gamedata.m_civ) && settlerindex>=0 && settlerindex<countof(m_gamedata.m_unit))
{
Unit *u=&(m_gamedata.m_unit[settlerindex]);
if((u->flags & UNIT_ALIVE)==UNIT_ALIVE && u->type==UNITTYPE_SETTLER && u->owner==PlayerCivIndex(playerindex))
if((u->flags & UNIT_ALIVE) && u->type==UNITTYPE_SETTLER && u->owner==PlayerCivIndex(playerindex))
{
int32_t ci=CityIndexAtLocation(u->x,u->y);
if(ci>=0)
Expand Down Expand Up @@ -766,7 +771,7 @@ int32_t Game::UnitCountAtLocation(const uint32_t x, const int32_t y) const
int32_t count=0;
for(size_t i=0; i<countof(m_gamedata.m_unit); i++)
{
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) == UNIT_ALIVE && m_gamedata.m_unit[i].x==x && m_gamedata.m_unit[i].y==y)
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) && m_gamedata.m_unit[i].x==x && m_gamedata.m_unit[i].y==y)
{
count++;
}
Expand Down Expand Up @@ -863,7 +868,7 @@ CityProduction Game::GetCityProduction(const int32_t cityidx) const
}
for(size_t i=(cityidx*UNITS_PER_CITY); i<(cityidx*UNITS_PER_CITY)+UNITS_PER_CITY; i++)
{
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE)==UNIT_ALIVE && m_gamedata.m_unit[i].owner==c->owner)
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) && m_gamedata.m_unit[i].owner==c->owner)
{
prod.unitupkeepfood+=unitdata[m_gamedata.m_unit[i].type].consumefood;
prod.unitupkeepresources+=unitdata[m_gamedata.m_unit[i].type].consumeresources;
Expand Down Expand Up @@ -952,7 +957,7 @@ int32_t Game::ShipAtLocation(const int32_t x, const int32_t y) const
{
for(size_t i=0; i<countof(m_gamedata.m_unit); i++)
{
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) == UNIT_ALIVE && (unitdata[m_gamedata.m_unit[i].type].flags & UNITDATA_MOVE_WATER) == UNITDATA_MOVE_WATER && m_gamedata.m_unit[i].x==x && m_gamedata.m_unit[i].y==y)
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) && (unitdata[m_gamedata.m_unit[i].type].flags & UNITDATA_MOVE_WATER) == UNITDATA_MOVE_WATER && m_gamedata.m_unit[i].x==x && m_gamedata.m_unit[i].y==y)
{
return i;
}
Expand Down Expand Up @@ -995,7 +1000,7 @@ int32_t Game::EnemyShipAtLocation(const uint8_t civindex, const int32_t x, const

int32_t Game::UnitEmbarkedShipIndex(const int32_t unitindex) const
{
if(unitindex>=0 && unitindex<countof(m_gamedata.m_unit) && (m_gamedata.m_unit[unitindex].flags & UNIT_ALIVE) == UNIT_ALIVE)
if(unitindex>=0 && unitindex<countof(m_gamedata.m_unit) && (m_gamedata.m_unit[unitindex].flags & UNIT_ALIVE))
{
const TerrainTile tt=m_gamedata.m_map->GetTile(m_gamedata.m_unit[unitindex].x,m_gamedata.m_unit[unitindex].y);

Expand All @@ -1005,7 +1010,7 @@ int32_t Game::UnitEmbarkedShipIndex(const int32_t unitindex) const
// check for the ship it's emarked on
for(size_t i=0; i<countof(m_gamedata.m_unit); i++)
{
if(i!=unitindex && (m_gamedata.m_unit[i].flags & UNIT_ALIVE) == UNIT_ALIVE && m_gamedata.m_unit[i].owner==m_gamedata.m_unit[unitindex].owner && (unitdata[m_gamedata.m_unit[i].type].flags & UNITDATA_MOVE_WATER)==UNITDATA_MOVE_WATER && m_gamedata.m_unit[i].x==m_gamedata.m_unit[unitindex].x && m_gamedata.m_unit[i].y==m_gamedata.m_unit[unitindex].y && unitdata[m_gamedata.m_unit[i].type].transport>0)
if(i!=unitindex && (m_gamedata.m_unit[i].flags & UNIT_ALIVE) && m_gamedata.m_unit[i].owner==m_gamedata.m_unit[unitindex].owner && (unitdata[m_gamedata.m_unit[i].type].flags & UNITDATA_MOVE_WATER)==UNITDATA_MOVE_WATER && m_gamedata.m_unit[i].x==m_gamedata.m_unit[unitindex].x && m_gamedata.m_unit[i].y==m_gamedata.m_unit[unitindex].y && unitdata[m_gamedata.m_unit[i].type].transport>0)
{
return i;
}
Expand Down Expand Up @@ -1045,7 +1050,7 @@ bool Game::MoveUnit(const uint8_t civindex, const int32_t unitindex, const int32



if((dx!=0 || dy!=0) && m_gamedata.m_currentcivturn==civindex && unitindex>=0 && unitindex<countof(m_gamedata.m_unit) && m_gamedata.m_unit[unitindex].owner==civindex && (m_gamedata.m_unit[unitindex].flags & UNIT_ALIVE) == UNIT_ALIVE && m_gamedata.m_unit[unitindex].movesleft>0)
if((dx!=0 || dy!=0) && m_gamedata.m_currentcivturn==civindex && unitindex>=0 && unitindex<countof(m_gamedata.m_unit) && m_gamedata.m_unit[unitindex].owner==civindex && (m_gamedata.m_unit[unitindex].flags & UNIT_ALIVE) && m_gamedata.m_unit[unitindex].movesleft>0)
{
// TODO - land to sea - embarkable ship at destination is good to move - enemy ship at location then attack
// TODO - sea unit - only 1 per tile
Expand All @@ -1063,7 +1068,7 @@ bool Game::MoveUnit(const uint8_t civindex, const int32_t unitindex, const int32
int32_t eucount=0; // enemy unit count at location
for(size_t i=0; i<countof(m_gamedata.m_unit); i++)
{
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) == UNIT_ALIVE && m_gamedata.m_unit[i].x==mc.X() && m_gamedata.m_unit[i].y==mc.Y() && m_gamedata.m_unit[i].owner!=u->owner)
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) && m_gamedata.m_unit[i].x==mc.X() && m_gamedata.m_unit[i].y==mc.Y() && m_gamedata.m_unit[i].owner!=u->owner)
{
eu=&(m_gamedata.m_unit[i]);
eucount++;
Expand Down Expand Up @@ -1224,7 +1229,7 @@ bool Game::MoveUnit(const uint8_t civindex, const int32_t unitindex, const int32
uint8_t tc=0;
for(size_t i=0; i<countof(m_gamedata.m_unit) && tc<unitdata[u->type].transport; i++)
{
if(i!=unitindex && ((m_gamedata.m_unit[i].flags & UNIT_ALIVE) == UNIT_ALIVE) && m_gamedata.m_unit[i].owner==u->owner && m_gamedata.m_unit[i].x==u->x && m_gamedata.m_unit[i].y==u->y)
if(i!=unitindex && (m_gamedata.m_unit[i].flags & UNIT_ALIVE) && m_gamedata.m_unit[i].owner==u->owner && m_gamedata.m_unit[i].x==u->x && m_gamedata.m_unit[i].y==u->y)
{
m_gamedata.m_unit[i].x=mc.X();
m_gamedata.m_unit[i].y=mc.Y();
Expand All @@ -1247,6 +1252,8 @@ bool Game::MoveUnit(const uint8_t civindex, const int32_t unitindex, const int32
u->movesleft=0;
}

CheckSentry(); // recheck all units sentry flags

// TODO - reset bad move count for this unit

return true;
Expand Down Expand Up @@ -1295,7 +1302,7 @@ bool Game::CivilizationAlive(const uint8_t civindex) const
}
for(size_t i=0; i<countof(m_gamedata.m_unit); i++)
{
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) == UNIT_ALIVE && m_gamedata.m_unit[i].owner==civindex)
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) && m_gamedata.m_unit[i].owner==civindex)
{
return true;
}
Expand All @@ -1313,7 +1320,7 @@ void Game::HandleAI(const uint8_t civindex)
int32_t watercount=0;
for(size_t i=0; i<countof(m_gamedata.m_unit); i++)
{
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) == UNIT_ALIVE && m_gamedata.m_unit[i].owner==civindex)
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) && m_gamedata.m_unit[i].owner==civindex)
{
if(m_gamedata.m_unit[i].type==UNITTYPE_SETTLER)
{
Expand Down Expand Up @@ -1739,7 +1746,7 @@ void Game::AIMilitaryLandUnit(const uint32_t unitindex)
bool wait=false;
int32_t cnt=0; // use for extra seed for random so we don't get stuck in a loop trying the same failed movement

while((u->flags & UNIT_ALIVE) == UNIT_ALIVE && u->movesleft>0 && wait==false && cnt<20)
while((u->flags & UNIT_ALIVE) && u->movesleft>0 && wait==false && cnt<20)
{
const int32_t cei=ClosestEnemyUnit(u->owner,u->x,u->y,true);
const int32_t cfi=ClosestFriendlyUnit(u->owner,u->x,u->y);
Expand Down Expand Up @@ -1893,7 +1900,7 @@ int32_t Game::ClosestEnemyUnit(const uint8_t civindex, const int32_t x, const in
int32_t closestdist=128*128;
for(size_t i=0; i<countof(m_gamedata.m_unit); i++)
{
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) == UNIT_ALIVE && m_gamedata.m_unit[i].owner!=civindex && (closest==-1 || Distance2(x,y,m_gamedata.m_unit[i].x,m_gamedata.m_unit[i].y)<closestdist))
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) && m_gamedata.m_unit[i].owner!=civindex && (closest==-1 || Distance2(x,y,m_gamedata.m_unit[i].x,m_gamedata.m_unit[i].y)<closestdist))
{
uint8_t dir;
if(musthavepath==false || (m_gamedata.m_pathfinder->Pathfind(x,y,m_gamedata.m_unit[i].x,m_gamedata.m_unit[i].y,dir)==true))
Expand All @@ -1912,7 +1919,7 @@ int32_t Game::ClosestFriendlyUnit(const uint8_t civindex, const int32_t x, const
int32_t closestdist=128*128;
for(size_t i=0; i<countof(m_gamedata.m_unit); i++)
{
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) == UNIT_ALIVE && m_gamedata.m_unit[i].owner==civindex && (closest==-1 || Distance2(x,y,m_gamedata.m_unit[i].x,m_gamedata.m_unit[i].y)<closestdist))
if((m_gamedata.m_unit[i].flags & UNIT_ALIVE) && m_gamedata.m_unit[i].owner==civindex && (closest==-1 || Distance2(x,y,m_gamedata.m_unit[i].x,m_gamedata.m_unit[i].y)<closestdist))
{
closest=i;
closestdist=Distance2(x,y,m_gamedata.m_unit[i].x,m_gamedata.m_unit[i].y);
Expand Down Expand Up @@ -2043,3 +2050,19 @@ bool Game::BaseTerrainInRadius(const int32_t x, const int32_t y, const int32_t r
}
return false;
}

void Game::CheckSentry()
{
for(size_t i=0; i<countof(m_gamedata.m_unit); i++)
{
if(m_gamedata.m_unit[i].flags & UNIT_ALIVE)
{
const int32_t ceu=ClosestEnemyUnit(m_gamedata.m_unit[i].owner,m_gamedata.m_unit[i].x,m_gamedata.m_unit[i].y,false);
// turn off sentry if cpu player controller or enemy 4 or fewer spaces away
if(m_gamedata.m_civplayernum[m_gamedata.m_unit[i].owner]==0 || (ceu>=0 && Distance2(m_gamedata.m_unit[i].x,m_gamedata.m_unit[i].y,m_gamedata.m_unit[ceu].x,m_gamedata.m_unit[ceu].y)<5))
{
m_gamedata.m_unit[i].flags&=~UNIT_SENTRY;
}
}
}
}
6 changes: 4 additions & 2 deletions src/src/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ class Game:public IUpdatable,public IDrawable,public IInputHandler

int8_t PlayerCivIndex(const int8_t playerindex) const; // return civ index for player index

int32_t NextUnitIndex(const int8_t civindex, const int32_t currentunitindex) const; // -1 for not found
int32_t NextUnitAtLocIndex(const int8_t civindex, const int32_t x, const int32_t y, const int32_t currentunitindex) const; // -1 for not found
int32_t NextUnitIndex(const int8_t civindex, const int32_t currentunitindex, bool skipsentry) const; // -1 for not found
int32_t NextUnitAtLocIndex(const int8_t civindex, const int32_t x, const int32_t y, const int32_t currentunitindex, const bool skipsentry) const; // -1 for not found
int32_t NextCityIndex(const int8_t civindex, const int32_t currentcityindex) const; // -1 for not found
int32_t UnitIndexAtLocation(const int8_t owneridx, const int32_t x, const int32_t y) const; // pass -1 for owner for any civ. returns first unit idx at location, -1 if not found
int32_t CityIndexAtLocation(const int32_t x, const int32_t y) const; // returns city idx at location, -1 if not found
Expand Down Expand Up @@ -127,4 +127,6 @@ class Game:public IUpdatable,public IDrawable,public IInputHandler

bool BaseTerrainInRadius(const int32_t x, const int32_t y, const int32_t r, const BaseTerrain::TerrainType terrain) const;

void CheckSentry(); // goes through eveny unit and checks if enemy is in range and removed sentry if set

};
4 changes: 2 additions & 2 deletions src/src/gamedata.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ enum UnitFlag
{
UNIT_ALIVE= 0b00000001,
UNIT_VETERAN= 0b00000010,
UNIT_ROGUE= 0b00000100,
UNIT_SENTRY= 0b00000100,
UNIT_AWAY= 0b00001000,
UNIT_SENTRY= 0b00010000,
UNIT_ROGUE= 0b00010000,
UNIT_MOVESLEFT= 0b11100000
};

Expand Down
3 changes: 2 additions & 1 deletion src/src/icondata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ const IconData icondata[]={
{/*ICON_EXPANDCITY,*/ "Expand City", 6, 1},
{/*ICON_CHANGEBUILD,*/ "Change Build", 6, 1},
{/*ICON_BUYBUILD,*/ "Buy", 5, 0},
{/*ICON_SELLIMPROVEMENTS,*/ "Sell Improvement", 6, 0}
{/*ICON_SELLIMPROVEMENTS,*/ "Sell Improvement", 6, 0},
{/*ICON_TOGGLESENTRY,*/ "Toggle Sentry", 9, 0}
};
3 changes: 2 additions & 1 deletion src/src/icondata.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ enum IconType
ICON_EXPANDCITY=13,
ICON_CHANGEBUILD=14,
ICON_BUYBUILD=15,
ICON_SELLIMPROVEMENT=16
ICON_SELLIMPROVEMENT=16,
ICON_TOGGLESENTRY=17
};

struct IconData
Expand Down
Loading

0 comments on commit f3977a6

Please sign in to comment.