hostile-takeover/game/BuildMgr.cpp
2016-01-03 23:19:26 -08:00

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