mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2025-12-16 12:08:36 +00:00
204 lines
5.2 KiB
C++
204 lines
5.2 KiB
C++
#include "ht.h"
|
|
|
|
namespace wi {
|
|
|
|
// UNDONE: load/save
|
|
|
|
BuildMgr::BuildMgr()
|
|
{
|
|
m_pbldeFirst = NULL;
|
|
}
|
|
|
|
BuildMgr::~BuildMgr()
|
|
{
|
|
BuildEntry *pblde = m_pbldeFirst;
|
|
while (pblde != NULL) {
|
|
BuildEntry *pbldeT = pblde;
|
|
pblde = pblde->pbldeNext;
|
|
delete pbldeT;
|
|
}
|
|
}
|
|
|
|
// Add the requested UnitType to the build list. The specified UnitGroup
|
|
// will be notified when the Unit is built.
|
|
|
|
bool BuildMgr::BuildUnit(UnitType ut, UnitGroup *pug, int nArea)
|
|
{
|
|
BuildEntry *pblde = new BuildEntry;
|
|
Assert(pblde != NULL, "out of memory!");
|
|
if (pblde == NULL)
|
|
return false;
|
|
|
|
pblde->ut = ut;
|
|
pblde->pug = pug;
|
|
pblde->nArea = nArea;
|
|
pblde->gidBuilder = kgidNull;
|
|
|
|
// Miners have special priority and jump to the head of list.
|
|
// This is to reduce the likelihood that level AI will run out
|
|
// of money because the player destroyed its Miners
|
|
|
|
if (pblde->ut == kutGalaxMiner) {
|
|
pblde->pbldeNext = m_pbldeFirst;
|
|
m_pbldeFirst = pblde;
|
|
return true;
|
|
}
|
|
|
|
// Link the new BuildEntry to the end of the build list so it will be built
|
|
// chronologically after previous requests. (Not strictly though, because it
|
|
// may be possible to start building this Unit sooner than a Unit earlier on
|
|
// the list because that Unit relies on a Builder type that isn't available).
|
|
|
|
pblde->pbldeNext = NULL;
|
|
BuildEntry **ppblde = &m_pbldeFirst;
|
|
while (*ppblde != NULL)
|
|
ppblde = &((*ppblde)->pbldeNext);
|
|
*ppblde = pblde;
|
|
|
|
return true;
|
|
}
|
|
|
|
// BuilderGobs call this method when they have completed building a Unit
|
|
|
|
void BuildMgr::OnBuilt(UnitGob *punt, BuilderGob *pbldr)
|
|
{
|
|
UnitType utBuilt = punt->GetConsts()->ut;
|
|
Gid gidBuilder = pbldr->GetId();
|
|
Player *pplrBuilt = punt->GetOwner();
|
|
|
|
BuildEntry **ppblde = &m_pbldeFirst;
|
|
while (*ppblde != NULL) {
|
|
BuildEntry *pblde = *ppblde;
|
|
|
|
// Match the built Unit with the right BuildEntry (must be of correct
|
|
// UnitType, produced by the expected BuilderGob which must be owned
|
|
// by the UnitGroup's owner)
|
|
|
|
if (utBuilt == pblde->ut && gidBuilder == pblde->gidBuilder && pplrBuilt == pblde->pug->GetOwner()) {
|
|
|
|
// Unlink BuildEntry
|
|
|
|
*ppblde = pblde->pbldeNext;
|
|
|
|
// Yay, it's been built!
|
|
|
|
pblde->pug->OnBuilt(punt);
|
|
|
|
delete pblde;
|
|
return;
|
|
}
|
|
|
|
ppblde = &((*ppblde)->pbldeNext);
|
|
}
|
|
}
|
|
|
|
// OPT: Doesn't need to be called every Simulation::Update
|
|
|
|
void BuildMgr::Update()
|
|
{
|
|
if (m_pbldeFirst == NULL)
|
|
return;
|
|
|
|
for (BuildEntry *pblde = m_pbldeFirst; pblde != NULL; pblde = pblde->pbldeNext) {
|
|
|
|
// if gidBuilder is invalid/inactive or is no longer owned by the same side
|
|
// clear gidBuilder
|
|
|
|
BuilderGob *pbldr = (BuilderGob *)ggobm.GetGob(pblde->gidBuilder);
|
|
if (pbldr == NULL || pbldr->GetOwner() != pblde->pug->GetOwner())
|
|
pblde->gidBuilder = kgidNull;
|
|
}
|
|
|
|
// Check each BuilderGob to see if it can build one of the BuildEntries
|
|
// (it must be idle, owned by the same side, and be the right type of builder)
|
|
|
|
// Scan the Gob list looking for BuilderGobs
|
|
|
|
Gob *pgob = ggobm.GetFirstGob();
|
|
for (; pgob != NULL; pgob = ggobm.GetNextGob(pgob)) {
|
|
|
|
// Is this a Structure?
|
|
|
|
if (!(pgob->GetFlags() & kfGobStructure))
|
|
continue; // no
|
|
|
|
StructGob *pstru = (StructGob *)pgob;
|
|
StructConsts *pstruc = (StructConsts *)pstru->GetConsts();
|
|
|
|
// Is it a Builder?
|
|
|
|
if (!(pstruc->um & kumBuilder))
|
|
continue; // no
|
|
|
|
// Is this builder busy?
|
|
|
|
BuilderGob *pbldr = (BuilderGob *)pstru;
|
|
if (pbldr->IsBuildInProgress())
|
|
continue; // yes
|
|
|
|
// Let's see if it can build any of the UnitTypes we have pending
|
|
|
|
Player *pplrBuilderOwner = pbldr->GetOwner();
|
|
BuilderConsts *pbldrc = (BuilderConsts *)pbldr->GetConsts();
|
|
|
|
for (BuildEntry *pblde = m_pbldeFirst; pblde != NULL; pblde = pblde->pbldeNext) {
|
|
|
|
// Is this entry already being built?
|
|
|
|
if (pblde->gidBuilder != kgidNull)
|
|
continue; // yes
|
|
|
|
// Does the Player wanting to build own the builder?
|
|
|
|
if (pblde->pug->GetOwner() != pplrBuilderOwner)
|
|
continue; // no
|
|
|
|
// Can this builder build the type we want?
|
|
|
|
UnitMask um = (1 << pblde->ut);
|
|
if (pbldrc->umCanBuild & um) {
|
|
// Yes!
|
|
|
|
if (um & kumStructures) {
|
|
// Check to see if limits have been reached
|
|
|
|
if (!ggobm.IsBelowLimit(knLimitStruct, pplrBuilderOwner))
|
|
continue; // limit reached
|
|
|
|
// Ok
|
|
|
|
Message msg;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.mid = kmidBuildOtherCommand;
|
|
msg.smidSender = ksmidNull;
|
|
msg.smidReceiver = pbldr->GetId();
|
|
msg.BuildOtherCommand.ut = pblde->ut;
|
|
TRect trc;
|
|
ggobm.GetAreaRect(pblde->nArea, &trc);
|
|
|
|
// Is space required by the structure free?
|
|
|
|
StructConsts *pstruc = (StructConsts *)gapuntc[pblde->ut];
|
|
if (gsim.GetLevel()->GetTerrainMap()->IsOccupied(trc.left, trc.top, pstruc->ctxReserve, pstruc->ctyReserve, kbfStructure | kbfMobileUnit))
|
|
continue; // no
|
|
|
|
msg.BuildOtherCommand.wpt.wx = WcFromTc(trc.left);
|
|
msg.BuildOtherCommand.wpt.wy = WcFromTc(trc.top);
|
|
gsmm.SendMsg(&msg);
|
|
|
|
} else {
|
|
// Check to see if limits have been reached
|
|
|
|
if (!ggobm.IsBelowLimit(knLimitMobileUnit, pplrBuilderOwner))
|
|
continue; // limit reached
|
|
|
|
pbldr->Build(pblde->ut);
|
|
}
|
|
pblde->gidBuilder = pbldr->GetId();
|
|
break; // Move on to the next BuilderGob for any remaining BuildEntries
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace wi
|