hostile-takeover/game/Miner.cpp
Nathan Fulton 489399dfb4 Rotate miner south west to enter processor
art2432 processor faces more towards the south west compared to the art824 processor which faced basically south. The coordinates used for the fakeMiner animation have been modified to compensate for this and the miner now rotates to the south west before entering.
2017-10-21 20:42:32 -04:00

922 lines
23 KiB
C++

#include "ht.h"
#include "wistrings.h"
namespace wi {
static MinerConsts gConsts;
AnimationData *MinerGob::s_panidVacuum = NULL;
#if defined(DEBUG_HELPERS)
char *MinerGob::GetName()
{
return "Miner";
}
#endif
static int s_anMovingStripIndices[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
bool MinerGob::InitClass(IniReader *pini)
{
s_panidVacuum = LoadAnimationData("vacuum.anir");
Assert(s_panidVacuum != NULL);
if (s_panidVacuum == NULL)
return false;
gConsts.gt = kgtGalaxMiner;
gConsts.ut = kutGalaxMiner;
gConsts.umPrerequisites = kumProcessor;
gConsts.wf |= kfUntcHasFullnessIndicator;
// Initialize the frame indices arrays
gConsts.anFiringStripIndices = s_anMovingStripIndices;
gConsts.anMovingStripIndices = s_anMovingStripIndices;
gConsts.anIdleStripIndices = s_anMovingStripIndices;
// Sound effects
gConsts.sfxImpact = ksfxNothing;
gConsts.sfxMine = ksfxGalaxMinerMine;
gConsts.sfxUnderAttack = ksfxGalaxMinerUnderAttack;
gConsts.sfxFire = ksfxNothing;
gConsts.sfxcDestroyed = ksfxcVehicleDestroyed;
gConsts.sfxcSelect = ksfxcMajor01Select;
gConsts.sfxcMove = ksfxcMajor01Move;
gConsts.sfxcAttack = ksfxcNothing;
return MobileUnitGob::InitClass(&gConsts, pini);
}
void MinerGob::ExitClass()
{
MobileUnitGob::ExitClass(&gConsts);
delete s_panidVacuum;
s_panidVacuum = NULL;
}
MinerGob::MinerGob() : MobileUnitGob(&gConsts)
{
m_aniVacuum.Init(s_panidVacuum);
StartAnimation(&m_aniVacuum, 0, 0, kfAniLoop);
m_nGalaxiteAmount = 0;
m_gidFavoriteProcessor = kgidNull;
m_tptGalaxite.tx = kxInvalid;
m_fMinerUnderAttack = false;
m_wfMunt &= ~kfMuntAggressivenessBits;
m_fHidden = false;
m_fAttemptingToDeliver = false;
}
#define knVerMinerGobState 2
bool MinerGob::LoadState(Stream *pstm)
{
byte nVer = pstm->ReadByte();
if (nVer != knVerMinerGobState)
return false;
m_nGalaxiteAmount = pstm->ReadWord();
m_cDelay = (char)pstm->ReadByte();
m_gidFavoriteProcessor = pstm->ReadWord();
m_tptGalaxite.tx = pstm->ReadWord();
m_tptGalaxite.ty = pstm->ReadWord();
m_fMinerUnderAttack = pstm->ReadByte() != 0 ? true : false;
m_fHidden = pstm->ReadByte() != 0 ? true : false;
m_fAttemptingToDeliver = pstm->ReadByte() != 0 ? true : false;
return MobileUnitGob::LoadState(pstm);
}
bool MinerGob::SaveState(Stream *pstm)
{
pstm->WriteByte(knVerMinerGobState);
pstm->WriteWord(m_nGalaxiteAmount);
pstm->WriteByte(m_cDelay);
pstm->WriteWord(m_gidFavoriteProcessor);
pstm->WriteWord(m_tptGalaxite.tx);
pstm->WriteWord(m_tptGalaxite.ty);
pstm->WriteByte(m_fMinerUnderAttack);
pstm->WriteByte(m_fHidden);
pstm->WriteByte(m_fAttemptingToDeliver);
return MobileUnitGob::SaveState(pstm);
}
// when the miner goes into the processor, we hide the miner gob and the
// processor gob draws it pulling in and out. Leave our spot marked occupied
// so it saves it for us. This is kindof half a deactivate.
void MinerGob::Hide(bool fHide)
{
if (m_fHidden == fHide)
return;
m_fHidden = fHide;
if (fHide) {
m_ff &= ~(kfGobActive | kfGobDrawFlashed);
// make sure this unit's menu is not left up
UnitConsts *puntc = GetUnitConsts(GetType());
Assert(puntc->pfrmMenu != NULL);
if (puntc->pfrmMenu->GetOwner() == (UnitGob *)this)
puntc->pfrmMenu->EndForm(kidcCancel);
Invalidate();
} else {
m_ff |= kfGobActive;
Invalidate();
}
}
// so far it's just an assert, but let's not violate the general rule that we
// don't deactivate inactive gobs.
void MinerGob::Deactivate()
{
if (m_fHidden)
m_ff |= kfGobActive;
MobileUnitGob::Deactivate();
}
void MinerGob::Draw(DibBitmap *pbm, int xViewOrigin, int yViewOrigin, int nLayer)
{
#ifdef DRAW_OCCUPIED_TILE_INDICATOR
{
WRect wrcT;
GetTilePaddedWRect(&wrcT);
Rect rcT;
rcT.FromWorldRect(&wrcT);
rcT.Offset(-xViewOrigin, -yViewOrigin);
DrawBorder(pbm, &rcT, 1, GetColor(kiclrWhite));
}
#endif
if (m_fHidden)
return;
MobileUnitGob::Draw(pbm, xViewOrigin, yViewOrigin, nLayer);
if (m_st == kstMinerSuck && nLayer == knLayerDepthSorted) {
// HACK: m_ani is dir16 but m_aniVacuum only has 8 strips, divide by 2
SetAnimationStrip(&m_aniVacuum, m_ani.GetStrip() / 2);
m_aniVacuum.Draw(pbm, PcFromUwc(m_wx) - xViewOrigin, PcFromUwc(m_wy) - yViewOrigin);
} else if (nLayer == knLayerSelection && (m_ff & kfGobSelected)) {
Rect rcT;
rcT.FromWorldRect(&m_pmuntc->wrcUIBounds);
rcT.Offset(PcFromUwc(m_wx) - xViewOrigin, PcFromUwc(m_wy) - yViewOrigin);
DrawFullnessIndicator(pbm, &rcT, m_nGalaxiteAmount / knGalaxiteValue / 2, knMinerGalaxiteMax / knGalaxiteValue / 2);
}
}
void MinerGob::InitMenu(Form *pfrm)
{
ButtonControl *pbtn = (ButtonControl *)pfrm->GetControlPtr(kidcDeliver);
pbtn->Show(GetGalaxiteAmount() != 0);
}
void MinerGob::OnMenuItemSelected(int idc)
{
switch (idc) {
case kidcDeliver:
{
// The player shouldn't have been able to select this command unless
// it can be carried out.
Assert(GetGalaxiteAmount() != 0);
Message msg;
msg.mid = kmidDeliverCommand;
msg.smidSender = m_gid;
msg.smidReceiver = m_gid;
msg.DeliverCommand.gidTarget = kgidNull;
msg.tDelivery = 0;
gcmdq.Enqueue(&msg);
gsndm.PlaySfx(ksfxGalaxMinerDeliver);
}
break;
}
}
bool MinerGob::IsValidTarget(Gob *pgobTarget)
{
// no soldier squishing this version
return (pgobTarget->GetType() == kgtProcessor && m_pplr == pgobTarget->GetOwner())
&& (pgobTarget->GetFlags() & kfGobActive);
}
void MinerGob::GetClippingBounds(Rect *prc)
{
UnitGob::GetClippingBounds(prc);
if (m_st == kstMinerSuck) {
// HACK: m_ani is dir16 but m_aniVacuum only has 8 strips, divide by 2
SetAnimationStrip(&m_aniVacuum, m_ani.GetStrip() / 2);
Rect rc;
m_aniVacuum.GetBounds(&rc);
rc.Offset(PcFromUwc(m_wx), PcFromUwc(m_wy));
prc->Union(&rc);
}
}
void MinerGob::SetTarget(Gid gid, WCoord wx, WCoord wy, WCoord wxCenter, WCoord wyCenter, TCoord tcRadius, WCoord wcMoveDistPerUpdate)
{
if (gid == kgidNull) {
// If the target is Galaxite then translate this command into a MineCommand
FogMap *pfogm = gsim.GetLevel()->GetFogMap();
if (pfogm->GetGalaxite(TcFromWc(wx), TcFromWc(wy)) != 0) {
// Play mine sfx - this is called in a move so the general unit
// move sound will also be called, and the mine sound is currently
// no different. Needs to somehow be an attack but SimUI.cpp
// only checks for mobile units as targets.
//if (m_pplr == gpplrLocal)
// gsndm.PlaySfx(m_pmnrc->sfxMine);
Message msg;
memset(&msg, 0, sizeof(msg));
msg.mid = kmidMineCommand;
msg.MineCommand.gidTarget = gid;
msg.MineCommand.wptTarget.wx = wx;
msg.MineCommand.wptTarget.wy = wy;
msg.smidReceiver = m_gid;
gcmdq.Enqueue(&msg);
return;
}
// If target is not Galaxite let the MobileUnitGob handle command
MobileUnitGob::SetTarget(gid, wx, wy, wxCenter, wyCenter, tcRadius, wcMoveDistPerUpdate);
return;
}
// If the target no longer exists, discard the command
Gob *pgobTarget = ggobm.GetGob(gid);
if (pgobTarget == NULL)
return;
// If target is not a friendly processor let the MobileUnitGob handle command differentiation
if (pgobTarget->GetType() != kgtProcessor || !IsAlly(pgobTarget->GetSide())) {
MobileUnitGob::SetTarget(gid, wx, wy, wxCenter, wyCenter, tcRadius, wcMoveDistPerUpdate);
return;
}
// Play deliver sfx
gsndm.PlaySfx(ksfxGalaxMinerDeliver);
// Flash the target Gob
if (m_pplr == gpplrLocal)
pgobTarget->Flash();
Message msg;
memset(&msg, 0, sizeof(msg));
msg.mid = kmidDeliverCommand;
msg.MineCommand.gidTarget = gid;
msg.MineCommand.wptTarget.wx = wx;
msg.MineCommand.wptTarget.wy = wy;
msg.smidReceiver = m_gid;
gcmdq.Enqueue(&msg);
}
void MinerGob::Mine(WCoord wx, WCoord wy)
{
Assert(!InTransition());
//temp
if (!(m_ff & kfGobActive)) {
Assert();
}
// If we aren't being told to where to mine and we don't already
// have a previous mining location then find a new place to mine.
if (wx == kwxInvalid) {
if (m_tptGalaxite.tx == kxInvalid) {
SetState(kstMinerFindGalaxite);
} else {
// Go to Galaxite closest to the previous location
FogMap *pfogm = gsim.GetLevel()->GetFogMap();
if (pfogm->FindNearestGalaxite(m_tptGalaxite.tx, m_tptGalaxite.ty,
&m_tptGalaxite, (m_pplr->GetFlags() & kfPlrComputer) != 0 || ggame.IsMultiplayer())) {
m_wptTarget.wx = WcFromTc(m_tptGalaxite.tx);
m_wptTarget.wy = WcFromTc(m_tptGalaxite.ty);
SetState(kstMinerApproachGalaxite);
} else {
// If no Galaxite found, just stay where we are (NOTE:
// where we are is in the way of any other Miners trying
// to use the same Processor!)
gsim.GetLevel()->GetTriggerMgr()->SetConditionTrue(knMinerCantFindGalaxiteCondition, GetSideMask(GetSide()));
if (m_pplr == gpplrLocal)
ShowAlert(kidsMinerNeedsGalaxite);
SetState(kstGuard);
}
}
} else {
// Stash mine parameters to be picked up by the Mine state
m_wptTarget.wx = wx;
m_wptTarget.wy = wy;
m_tptGalaxite.tx = TcFromWc(m_wptTarget.wx);
m_tptGalaxite.ty = TcFromWc(m_wptTarget.wy);
SetState(kstMinerApproachGalaxite);
}
}
void MinerGob::PerformAction(char *szAction)
{
int nUnitAction;
if (IniScanf(szAction, "%d", &nUnitAction) == 0) {
Assert(false);
return;
}
if (nUnitAction == knMineUnitAction) {
SendMineCommand(m_gid, kwxInvalid, kwxInvalid);
return;
}
// Don't override this action, let base handle it
MobileUnitGob::PerformAction(szAction);
}
/*
MinerGob pseudo-code
-----------------
Inherit all MobileUnitGob message and state handlers
OnDeliverCommand {
> Deliver() // Galaxite to Processor
=> Mine(last mining position)
}
OnMineCommand(target) {
=> Mine(target)
}
Mine(target) {
if no target
target = nearest (reachable?) Galaxite tile
1> move within range of target
while true {
while not full {
do {
target = nearest (reachable?) Galaxite tile
if on top of target
2> move off target, forcefully
else
3> move within range of target, forcefully
} while target tile has no Galaxite
4> rotate to face the tile to mine from
do {
5> take Galaxite from target
} while not full AND target has Galaxite
}
6> Deliver() // Galaxite to Processor
7> move to last mining position
}
}
Deliver() {
if preferred Processor no longer exists {
find the closest friendly Processor
if no Processors exist
abort Delivery (set state to Guard)
}
> move to position in front of Processor
> rotate for entry
notify Processor of Galaxite delivery
> wait for Galaxite to be processed
}
*/
int MinerGob::ProcessStateMachineMessage(State st, Message *pmsg)
{
BeginStateMachine
OnMsg(kmidHit)
// It is possible to be hit by a shot AFTER the process of
// being pulled into a Processor has begun. We don't want the
// Processor to have to deal with its 'taken' Miner being
// destroyed so when this happens we just ignore the hit.
// UNDONE: this should be considered along with the general
// fix of removing the MinerGob when the Processor takes it
// and adding it back when the delivery is done.
if (!(m_ff & kfGobActive))
return knHandled;
// If we've been hit, announce it to the user
if (gpplrLocal == m_pplr) {
// After what interval?
if (!m_fMinerUnderAttack) {
m_fMinerUnderAttack = true;
gsndm.PlaySfx(ksfxGalaxMinerUnderAttack);
// update status
ShowAlert(kidsMinerUnderAttack);
}
}
return MobileUnitGob::ProcessStateMachineMessage(st, pmsg);
OnMsg(kmidDeliverCommand)
// Return to specified Processor. If Processor is gone pick the
// closest one and deliver there.
// If a path is being followed we have to wait until a tile center is
// reached before acting on a deliver command.
if (InTransition()) {
m_msgPending = *pmsg;
m_wfMunt |= kfMuntCommandPending;
} else {
// Use the deliver target. If that no longer exists, find the closest processor
Gob *pgobTarget = NULL;
m_gidTarget = pmsg->DeliverCommand.gidTarget;
if (m_gidTarget != kgidNull)
pgobTarget = ggobm.GetGob(m_gidTarget);
if (pgobTarget == NULL) {
m_gidTarget = FindClosestProcessor();
if (m_gidTarget != kgidNull)
pgobTarget = ggobm.GetGob(m_gidTarget);
}
// Stash deliver parameters to be picked up by the MinerMoveToProcessor state
if (pgobTarget != NULL && !(pgobTarget->GetFlags() & kfGobBeingBuilt)) {
m_gidFavoriteProcessor = pgobTarget->GetId();
// Adjust target x/y to point to the center of the tile
// closest to the Processor's entrance.
pgobTarget->GetPosition(&m_wptTarget);
m_wptTarget.wx += kwcTileHalf;
m_wptTarget.wy += (kwcTile * 2) + kwcTileHalf;
SetState(kstMinerMoveToProcessor);
} else {
SetState(kstGuard);
}
}
OnMsg(kmidMineCommand)
// If a path is being followed we have to wait until a tile center is
// reached before acting on a deliver command.
if (InTransition()) {
m_msgPending = *pmsg;
m_wfMunt |= kfMuntCommandPending;
} else {
Mine(pmsg->MineCommand.wptTarget.wx, pmsg->MineCommand.wptTarget.wy);
}
OnMsg(kmidAttackCommand)
// UNDONE: Miners don't have an attack at the moment so they ignore
// their auto-response impulses to chase their attacker
// DO NOTHING (override Unit's Attack response)
//-----------------------------------------------------------------------
State(kstMinerMoveToProcessor)
OnEnter
MoveEnter(true);
OnExit
MoveExit();
OnUpdate
switch (MoveUpdate()) {
case knMoveTargetReached:
{
// let's take a second look at our target to be sure it was not
// destroyed or taken over whilst we were enroute
Gob *pgobProcessor = ggobm.GetGob(m_gidTarget);
if (pgobProcessor != NULL && m_pplr == pgobProcessor->GetOwner()) {
SetState(kstMinerRotateForEntry);
} else {
// Our processor is gone. See if we can find another
Gid gid = FindClosestProcessor();
if (gid != kgidNull) {
SendDeliverCommand(gid);
} else {
SetState(kstGuard);
}
}
}
break;
case knMoveStuck:
// The processor will look for candidate miners when possible.
// It'll know this miner wants to deliver because of the m_fAttemptingToDeliver
// flag.
m_fAttemptingToDeliver = true;
SetState(kstGuard);
break;
}
// DefUpdate(); // called inside of MoveUpdate()
State(kstMinerRotateForEntry)
OnUpdate
m_unvl.MinSkip();
// Rotate to face south west
if (m_dir != kdir16SW) {
m_dir = TurnToward16(kdir16SW, m_dir);
StartAnimation(&m_ani, m_pmuntc->anMovingStripIndices[m_dir], 0, kfAniLoop | kfAniIgnoreFirstAdvance);
} else {
// When facing south west send message to Processor and switch to
// guard state
Gob *pgobProcessor = ggobm.GetGob(m_gidTarget);
if (pgobProcessor != NULL)
gsmm.SendMsg(kmidGalaxiteDelivery, m_gid, m_gidTarget);
// We'll sit in this state while the Processor extracts the
// Galaxite. When it's done it will send a kmidMineCommand
// with a negative target. OnMsg(kmidMineCommand) will
// recognize this as a signal to continue mining where we last
// were.
m_fAttemptingToDeliver = false;
SetState(kstGuard);
// Miner can't be under attack now. This state is used to
// determine if it's ok to announce "miner under attack!"
m_fMinerUnderAttack = false;
}
DefUpdate();
//-----------------------------------------------------------------------
// If not already full of Galaxite, find some to mine
State(kstMinerFindGalaxite)
OnUpdate
// Are we full?
if (m_nGalaxiteAmount == knMinerGalaxiteMax) {
// Yes, deliver our load to our favorite Processor
SendDeliverCommand(m_gidFavoriteProcessor);
} else {
// No, let's find some Galaxite
// Is there some right in front of us?
TCoord tx = TcFromWc(m_wx);
TCoord ty = TcFromWc(m_wy);
TCoord txTarget = tx + g_mpDirToDx[m_dir];
TCoord tyTarget = ty + g_mpDirToDy[m_dir];
m_wptTarget.wx = WcFromTc(txTarget);
m_wptTarget.wy = WcFromTc(tyTarget);
FogMap *pfogm = gsim.GetLevel()->GetFogMap();
if (pfogm->GetGalaxite(txTarget, tyTarget) != 0) {
// Yes, get busy with it
m_tptGalaxite.tx = txTarget;
m_tptGalaxite.ty = tyTarget;
//temp
if (!(m_ff & kfGobActive)) {
Assert();
}
SetState(kstMinerSuck);
} else {
// No, look around for some
// Miners controlled by computer players or in a network game can (must) ignore fog.
bool fFound = pfogm->FindNearestGalaxite(tx, ty, &m_tptGalaxite,
(m_pplr->GetFlags() & kfPlrComputer) != 0 || ggame.IsMultiplayer());
if (!fFound) {
// Can't find any! Deliver what we have & then we'll park it by our
// processor. If we've never found any then record that this is the closest
// we've come to finding any
if (m_tptGalaxite.tx == kwxInvalid){
gsim.GetLevel()->GetTriggerMgr()->SetConditionTrue(knMinerCantFindGalaxiteCondition, GetSideMask(GetSide()));
if (m_pplr == gpplrLocal)
ShowAlert(kidsMinerNeedsGalaxite);
SetState(kstGuard);
} else {
SendDeliverCommand(m_gidFavoriteProcessor);
}
} else {
// Are we on top of the Galaxite we want?
if (tx == m_tptGalaxite.tx && ty == m_tptGalaxite.ty) {
// Yes, pick an unoccupied adjacent tile to move to
for (int dir = 0; dir < 8; dir++) {
TCoord txT = tx + g_mpDirToDx[dir];
TCoord tyT = ty + g_mpDirToDy[dir];
if (!IsTileFree(txT, tyT))
continue;
m_wptTarget.wx = WcFromTc(txT);
m_wptTarget.wy = WcFromTc(tyT);
SetState(kstMinerStepAside);
break;
}
// NOTE: if can't move to a new spot then we'll try
// again next Update.
// NOTE: ideally we should just issue the move command and
// let the move waiting code handle this case.
m_unvl.MinSkip();
} else {
// No, move within range of the target tile, forcefully
m_wptTarget.wx = WcFromTc(m_tptGalaxite.tx);
m_wptTarget.wy = WcFromTc(m_tptGalaxite.ty);
SetState(kstMinerApproachGalaxite);
}
}
}
}
DefUpdate();
// Rotate to face the desired tile and advance to state kstMinerSuck
State(kstMinerFaceGalaxite)
OnEnter
m_cDelay = 0;
OnUpdate
// Introduce a little rotation delay
m_cDelay -= m_unvl.GetUpdateCount();
if (m_cDelay < 0) {
m_cDelay = 1;
// Make sure we're facing towards the Galaxite tile
Direction16 dirTo = CalcDir16(m_tptGalaxite.tx - TcFromWc(m_wx), m_tptGalaxite.ty - TcFromWc(m_wy));
if (m_dir != dirTo) {
m_dir = TurnToward16(dirTo, m_dir);
StartAnimation(&m_ani, m_pmuntc->anMovingStripIndices[m_dir], 0, kfAniLoop | kfAniIgnoreFirstAdvance);
} else {
//temp
if (!(m_ff & kfGobActive)) {
}
SetState(kstMinerSuck);
}
}
m_unvl.MinSkip(m_cDelay);
DefUpdate();
// Move off a Galaxite tile so we can mine from it.
// An appropriate target tile has already been selected.
State(kstMinerStepAside)
OnEnter
MoveEnter(true);
OnExit
MoveExit();
OnUpdate
switch (MoveUpdate()) {
case knMoveTargetReached:
// Turn around to face the tile we want to mine from
//temp
if (!(m_ff & kfGobActive)) {
Assert();
}
SetState(kstMinerFaceGalaxite);
break;
case knMoveStuck:
// UNDONE: what to do? Doing nothing means we repath every
// Update until a valid path can be determined.
SetState(kstGuard);
break;
}
// DefUpdate(); // called inside of MoveUpdate()
// Move within range of target and advance to state kstMinerFaceGalaxite
State(kstMinerApproachGalaxite)
OnEnter
MoveEnter(true);
OnExit
MoveExit();
OnUpdate
// Are we within 1 tile of the target?
if (!InTransition()) {
if (abs(WcTrunc(m_wx) - WcTrunc(m_wptTarget.wx)) <= kwcTile &&
abs(WcTrunc(m_wy) - WcTrunc(m_wptTarget.wy)) <= kwcTile) {
// Yes, this is where we want to be!
//temp
if (!(m_ff & kfGobActive)) {
Assert();
}
SetState(kstMinerFaceGalaxite);
return knHandled;
}
}
switch (MoveUpdate()) {
case knMoveTargetReached:
//temp
if (!(m_ff & kfGobActive)) {
Assert();
}
SetState(kstMinerFaceGalaxite);
break;
case knMoveStuck:
// UNDONE: what to do? Doing nothing means we repath every
// Update until a valid path can be determined.
SetState(kstGuard);
break;
}
// DefUpdate(); // called inside of MoveUpdate()
// Dig in, if there's any Galaxite left
State(kstMinerSuck)
OnEnter
//temp
if (!(m_ff & kfGobActive)) {
Assert();
}
// Begin countdown to Galaxite decrement
m_cDelay = kcMinerSuckDelay;
// Are we full?
if (m_nGalaxiteAmount == knMinerGalaxiteMax)
SendDeliverCommand(m_gidFavoriteProcessor);
OnUpdate
// Are we full?
if (m_nGalaxiteAmount == knMinerGalaxiteMax) {
// Yes, deliver our load to our favorite Processor
MarkRedraw();
SendDeliverCommand(m_gidFavoriteProcessor);
} else {
// If target tile is out of Galaxite try another
FogMap *pfogm = gsim.GetLevel()->GetFogMap();
if (pfogm->GetGalaxite(m_tptGalaxite.tx, m_tptGalaxite.ty) == 0) {
// Look for another
MarkRedraw();
SetState(kstMinerFindGalaxite);
} else {
AdvanceAnimation(&m_aniVacuum);
// Time to consume some Galaxite?
m_cDelay -= m_unvl.GetUpdateCount();
if (m_cDelay < 0) {
m_cDelay = kcMinerSuckDelay;
m_unvl.MinSkip(m_cDelay);
pfogm->DecGalaxite(m_tptGalaxite.tx, m_tptGalaxite.ty);
m_nGalaxiteAmount += 10;
MarkRedraw();
}
}
}
DefUpdate();
#if 0
EndStateMachineInherit(MobileUnitGob)
#else
return knHandled;
}
} else {
return (int)MobileUnitGob::ProcessStateMachineMessage(st, pmsg);
}
return (int)MobileUnitGob::ProcessStateMachineMessage(st, pmsg);
#endif
}
#ifdef MP_DEBUG_SHAREDMEM
void MinerGob::MPValidate()
{
// TODO: animation state
MPValidateGobMember(MinerGob, m_nGalaxiteAmount);
MPValidateGobMember(MinerGob, m_cDelay);
MPValidateGobMember(MinerGob, m_gidFavoriteProcessor);
MPValidateGobMember(MinerGob, m_tptGalaxite);
// gpplrLocal specific
// MPValidateGobMember(MinerGob, m_fMinerUnderAttack);
MPValidateGobMember(MinerGob, m_fAttemptingToDeliver);
MPValidateGobMember(MinerGob, m_fHidden);
// Visibility specific
// m_aniVacuum.MPValidate((Animation *)(((byte *)MPGetGobPtr(m_gid)) + OFFSETOF(MinerGob, m_aniVacuum)));
MobileUnitGob::MPValidate();
}
#endif
Gid MinerGob::FindClosestProcessor()
{
// Find the closest Processor owned by the Miner's owner
TCoord tcxyClosest = ktcMax;
TPoint tpt;
TCoord tc;
Gid gidClosest = kgidNull;
for (Gob *pgobT = ggobm.GetFirstGob(); pgobT != NULL; pgobT = ggobm.GetNextGob(pgobT)) {
if (pgobT->GetType() != kgtProcessor)
continue;
if (pgobT->GetOwner() != m_pplr)
continue;
if (pgobT->GetFlags() & kfGobBeingBuilt)
continue;
if (!(pgobT->GetFlags() & kfGobActive))
continue;
// candidate processor. Is it closer than our last candidate?
pgobT->GetTilePosition(&tpt);
tc = CalcRange(tpt.tx, tpt.ty, this);
if (tc < tcxyClosest) {
gidClosest = pgobT->GetId();
tcxyClosest = tc;
}
}
return gidClosest;
}
void MinerGob::SendDeliverCommand(Gid gidProcessor)
{
// Do it this way instead of calling SetTarget... SetTarget does
// some extra "user feedback" things we don't want here
Message msg;
memset(&msg, 0, sizeof(msg));
msg.mid = kmidDeliverCommand;
msg.MineCommand.gidTarget = gidProcessor;
msg.MineCommand.wptTarget.wx = 0;
msg.MineCommand.wptTarget.wy = 0;
msg.smidReceiver = m_gid;
gsmm.SendMsg(&msg);
}
} // namespace wi