#include "ht.h" namespace wi { bool Trigger::LoadCondition(IniReader *pini, FindProp *pfind) { char sz[128]; sz[0] = 0; int nCondition; int cArgs = pini->GetPropertyValue(pfind, "%d,%s", &nCondition, sz); if (cArgs == 0) return false; Condition *pcdn = NULL; switch (nCondition) { case knMissionLoadedCondition: pcdn = new MissionLoadedCondition(); break; case knCreditsCondition: pcdn = new CreditsCondition(); break; case knOwnsUnitsCondition: pcdn = new OwnsUnitsCondition(); break; case knAreaContainsUnitsCondition: pcdn = new AreaContainsUnitsCondition(); break; case knPlaceStructureModeCondition: pcdn = new PlaceStructureModeCondition(); break; case knMinerCantFindGalaxiteCondition: pcdn = new MinerCantFindGalaxiteCondition(); break; case knGalaxiteCapacityReachedCondition: pcdn = new GalaxiteCapacityReachedCondition(); break; case knElapsedTimeCondition: pcdn = new ElapsedTimeCondition(); break; case knSwitchCondition: pcdn = new SwitchCondition(); break; case knPeriodicTimerCondition: pcdn = new PeriodicTimerCondition(); break; case knDiscoversSideCondition: pcdn = new DiscoversSideCondition(); break; case knCountdownTimerCondition: pcdn = new CountdownTimerCondition(); break; case knTestPvarCondition: pcdn = new TestPvarCondition(); break; case knHasUpgradesCondition: pcdn = new HasUpgradesCondition(); break; #ifdef UNDONE case knUnitDestroyedCondition: pcdn = new UnitDestroyedCondition(); break; case knDeathsCondition: pcdn = new DeathsCondition(); break; case knMobileHQDeployableCondition: pcdn = new MobileHQDeployableCondition(); break; case knMobileHQDeployedCondition: pcdn = new MobileHQDeployedCondition(); break; case knUnitSeesUnitCondition: pcdn = new UnitSeesUnitCondition(); break; case knUnitDestroyedCondition: pcdn = new UnitDestroyedCondition(); break; #endif default: Assert(false); break; } // Init it, error if that failed Assert(pcdn != NULL, "out of memory!"); if (!pcdn->Init(sz)) { delete pcdn; return false; } // Link it in last Condition **ppcdn = &m_pcdn; while ((*ppcdn) != NULL) ppcdn = &((*ppcdn)->m_pcdnNext); *ppcdn = pcdn; return true; } // Condition base class implementation Condition::Condition() { m_pcdnNext = NULL; } bool Condition::Init(char *psz) { return true; } #ifdef DEBUG_HELPERS bool Condition::SafeIsTrue(Side side) { return IsTrue(side); } #endif // MissionLoadedCondition // REMOVE_SOMEDAY: this is here to keep m68k-gcc from generating a default // constructor in the .text section MissionLoadedCondition::MissionLoadedCondition() { } bool MissionLoadedCondition::IsTrue(Side side) { return true; } // CreditsCondition // REMOVE_SOMEDAY: this is here to keep m68k-gcc from generating a default // constructor in the .text section CreditsCondition::CreditsCondition() { } bool CreditsCondition::Init(char *psz) { int nCaSideMask; if (!ParseNumber(&psz, &nCaSideMask)) return false; m_wfCaSideMask = nCaSideMask; return m_qnum.Parse(&psz); } bool CreditsCondition::IsTrue(Side side) { Player *applr[kcSides]; int cplrs = GetPlayersListFromCaSideMask(side, m_wfCaSideMask, applr); // Add up a total credits for all the sides in question long cCredits = 0; for (int n = 0; n < cplrs; n++) cCredits += applr[n]->GetCredits(); // Does the total credit count meet our threshold? return m_qnum.Compare(cCredits); } // OwnsUnitsCondition // REMOVE_SOMEDAY: this is here to keep m68k-gcc from generating a default // constructor in the .text section OwnsUnitsCondition::OwnsUnitsCondition() { } bool OwnsUnitsCondition::Init(char *psz) { int nCaSideMask; if (!ParseNumber(&psz, &nCaSideMask)) return false; m_wfCaSideMask = nCaSideMask; if (!m_qnum.Parse(&psz)) return false; return ParseUnitMask(&psz, &m_um); } bool OwnsUnitsCondition::IsTrue(Side side) { Player *applr[kcSides]; int cplrs = GetPlayersListFromCaSideMask(side, m_wfCaSideMask, applr); // Add up the number of Units owned by these players int cunt = 0; for (int n = 0; n < cplrs; n++) cunt += applr[n]->GetUnitActiveCountFromMask(m_um); // Does the total Unit count meet our threshold? return m_qnum.Compare(cunt); } // AreaContainsUnitsCondition // REMOVE_SOMEDAY: this is here to keep m68k-gcc from generating a default // constructor in the .text section AreaContainsUnitsCondition::AreaContainsUnitsCondition() { m_nVersionLevel = gsim.GetLevel()->GetVersion(); } bool AreaContainsUnitsCondition::Init(char *psz) { if (!ParseNumber(&psz, &m_nArea)) return false; if (!m_qnum.Parse(&psz)) return false; if (!ParseUnitMask(&psz, &m_um)) return false; int nCaSideMask; if (!ParseNumber(&psz, &nCaSideMask)) return false; m_wfCaSideMask = nCaSideMask; return true; } bool AreaContainsUnitsCondition::IsTrue(Side side) { // Find the Gobs in the Area. SideMask sidm = GetSideMaskFromCaSideMask(side, m_wfCaSideMask); // This logic has an error. It is here for backwards compatibility. // CheckUnitsInArea returns true if a desired unit type and a desired // side are in an area, but not if desired unit type is of desired side. if (m_nVersionLevel == 0) { switch (m_qnum.m_nNumber) { case 0: if (m_qnum.m_nQualifier == knQualifierExactly) return !ggobm.CheckUnitsInArea(m_nArea, sidm, m_um); break; case 1: if (m_qnum.m_nQualifier == knQualifierAtLeast) return ggobm.CheckUnitsInArea(m_nArea, sidm, m_um); break; } } // Count gobs in area Enum enm; int cgobsMatch = 0; while (ggobm.EnumGobsInArea(&enm, m_nArea, sidm, m_um) != NULL) cgobsMatch++; // Does the total Unit count meet our threshold? return m_qnum.Compare(cgobsMatch); } #ifdef DEBUG_HELPERS char *AreaContainsUnitsCondition::ToString() { sprintf(s_szDebugHelpers, "area \"%s\" contains %s %s owned by %s", ggobm.GetAreaName(m_nArea), m_qnum.ToString(), PszFromUnitMask(m_um), PszFromCaSideMask(m_wfCaSideMask)); return s_szDebugHelpers; } #endif // PlaceStructureModeCondition // REMOVE_SOMEDAY: this is here to keep m68k-gcc from generating a default // constructor in the .text section PlaceStructureModeCondition::PlaceStructureModeCondition() { } bool PlaceStructureModeCondition::IsTrue(Side side) { return gpfrmPlace->GetOwner() != NULL; } // MinerCantFindGalaxiteCondition // REMOVE_SOMEDAY: this is here to keep m68k-gcc from generating a default // constructor in the .text section MinerCantFindGalaxiteCondition::MinerCantFindGalaxiteCondition() { } bool MinerCantFindGalaxiteCondition::Init(char *psz) { int nCaSideMask; if (!ParseNumber(&psz, &nCaSideMask)) return false; m_wfCaSideMask = nCaSideMask; return true; } bool MinerCantFindGalaxiteCondition::IsTrue(Side side) { // Determine the Sides we will be testing against SideMask sidmTest = GetSideMaskFromCaSideMask(side, m_wfCaSideMask); return gsim.GetLevel()->GetTriggerMgr()->IsConditionTrue(knMinerCantFindGalaxiteCondition, sidmTest); } // GalaxiteCapacityReachedCondition // REMOVE_SOMEDAY: this is here to keep m68k-gcc from generating a default // constructor in the .text section GalaxiteCapacityReachedCondition::GalaxiteCapacityReachedCondition() { } bool GalaxiteCapacityReachedCondition::Init(char *psz) { int nCaSideMask; if (!ParseNumber(&psz, &nCaSideMask)) return false; m_wfCaSideMask = nCaSideMask; return true; } bool GalaxiteCapacityReachedCondition::IsTrue(Side side) { // Determine the Sides we will be testing against SideMask sidmTest = GetSideMaskFromCaSideMask(side, m_wfCaSideMask); return gsim.GetLevel()->GetTriggerMgr()->IsConditionTrue(knGalaxiteCapacityReachedCondition, sidmTest); } // ElapsedTimeCondition // REMOVE_SOMEDAY: this is here to keep m68k-gcc from generating a default // constructor in the .text section ElapsedTimeCondition::ElapsedTimeCondition() { } bool ElapsedTimeCondition::Init(char *psz) { return m_qnum.Parse(&psz); } bool ElapsedTimeCondition::IsTrue(Side side) { return m_qnum.Compare(gsim.GetTickCount() / 100); } #ifdef DEBUG_HELPERS char *ElapsedTimeCondition::ToString() { sprintf(s_szDebugHelpers, "elapsed time [%d] is %s", gsim.GetTickCount() / 100, m_qnum.ToString()); return s_szDebugHelpers; } #endif // SwitchCondition // REMOVE_SOMEDAY: this is here to keep m68k-gcc from generating a default // constructor in the .text section SwitchCondition::SwitchCondition() { } bool SwitchCondition::Init(char *psz) { if (!ParseNumber(&psz, &m_iSwitch)) return false; Assert(m_iSwitch < kcSwitchMax); int nOnOff; if (!ParseNumber(&psz, &nOnOff)) return false; m_fOn = nOnOff == 1; return true; } bool SwitchCondition::IsTrue(Side side) { return gsim.GetLevel()->GetTriggerMgr()->GetSwitch(m_iSwitch) == m_fOn; } #ifdef DEBUG_HELPERS char *SwitchCondition::ToString() { sprintf(s_szDebugHelpers, "switch \"%s\" is %s", gsim.GetLevel()->GetTriggerMgr()->GetSwitchName(m_iSwitch), m_fOn ? "on" : "off"); return s_szDebugHelpers; } #endif // PeriodicTimerCondition // REMOVE_SOMEDAY: this is here to keep m68k-gcc from generating a default // constructor in the .text section PeriodicTimerCondition::PeriodicTimerCondition() { } bool PeriodicTimerCondition::Init(char *psz) { int csec; if (!ParseNumber(&psz, &csec)) return false; m_iTimer = gsim.GetLevel()->GetTriggerMgr()->AddPeriodicTimer(csec * 100); return true; } // Periodic timers only start counting the first time they are tested. // This way they can sit 'below' other conditions and have deterministic // firing times. bool PeriodicTimerCondition::IsTrue(Side side) { TriggerMgr *ptgrm = gsim.GetLevel()->GetTriggerMgr(); ptgrm->StartPeriodicTimer(m_iTimer); return ptgrm->IsPeriodicTimerTriggered(m_iTimer); } #ifdef DEBUG_HELPERS bool PeriodicTimerCondition::SafeIsTrue(Side side) { return gsim.GetLevel()->GetTriggerMgr()->IsPeriodicTimerTriggered(m_iTimer); } char *PeriodicTimerCondition::ToString() { TriggerMgr *ptgrm = gsim.GetLevel()->GetTriggerMgr(); long ctPeriod = ptgrm->GetTimerPeriod(m_iTimer); long ctCountdown = ptgrm->GetTimerCountdown(m_iTimer); if (ctCountdown == kctTimerNotStarted) ctCountdown = ctPeriod + 100; sprintf(s_szDebugHelpers, "every %d [%d] seconds", ctPeriod / 100, (ctPeriod - ctCountdown) / 100); return s_szDebugHelpers; } #endif // CountdownTimerCondition bool CountdownTimerCondition::Init(char *psz) { return m_qnum.Parse(&psz); } bool CountdownTimerCondition::IsTrue(Side side) { int csecs; bool fStarted; fStarted = gsim.GetLevel()->GetTriggerMgr()->GetCountdownTimer()->GetTimer(&csecs); if (fStarted) return m_qnum.Compare(csecs); return false; } #if 0 // UnitDestroyedCondition bool UnitDestroyedCondition::Init(char *psz) { if (!ParseNumber(&psz, &m_iUnitDestroyed)) return false; Assert(m_iUnitDestroyed < kcUnitDestroyedMax); int nOnOff; if (!ParseNumber(&psz, &nOnOff)) return false; m_fOn = nOnOff == 1; return true; } bool UnitDestroyedCondition::IsTrue(Side side) { return gsim.GetLevel()->GetTriggerMgr()->GetUnitDestroyed(m_iUnitDestroyed) == m_fOn; } #endif // DiscoversSideCondition // REMOVE_SOMEDAY: this is here to keep m68k-gcc from generating a default // constructor in the .text section DiscoversSideCondition::DiscoversSideCondition() { } bool DiscoversSideCondition::Init(char *psz) { int nCaSideMask; if (!ParseNumber(&psz, &nCaSideMask)) return false; m_wfCaSideMaskA = nCaSideMask; if (!ParseNumber(&psz, &nCaSideMask)) return false; m_wfCaSideMaskB = nCaSideMask; return true; } bool DiscoversSideCondition::IsTrue(Side side) { SideMask sidmTotalDiscovered = 0; Player *applr[kcSides]; int cplrs = GetPlayersListFromCaSideMask(side, m_wfCaSideMaskA, applr); for (int n = 0; n < cplrs; n++) sidmTotalDiscovered |= applr[n]->GetDiscoveredSides(); return (sidmTotalDiscovered & GetSideMaskFromCaSideMask(side, m_wfCaSideMaskB)) != 0; } // TestPvarCondition // REMOVE_SOMEDAY: this is here to keep m68k-gcc from generating a default // constructor in the .text section TestPvarCondition::TestPvarCondition() { } bool TestPvarCondition::Init(char *psz) { if (!ParseString(&psz, m_szName)) return false; Assert(strlen(m_szName) < kcbPvarNameMax); return m_qnum.Parse(&psz); } bool TestPvarCondition::IsTrue(Side side) { int nValue = 0; char szT[kcbPvarValueMax]; if (ggame.GetVar(m_szName, szT, sizeof(szT))) nValue = atoi(szT); return m_qnum.Compare(nValue); } // HasUpgradesCondition // REMOVE_SOMEDAY: this is here to keep m68k-gcc from generating a default // constructor in the .text section HasUpgradesCondition::HasUpgradesCondition() { } bool HasUpgradesCondition::Init(char *psz) { int nCaSideMask; if (!ParseNumber(&psz, &nCaSideMask)) return false; m_wfCaSideMask = nCaSideMask; if (!ParseUpgradeMask(&psz, &m_upgm)) return false; return true; } bool HasUpgradesCondition::IsTrue(Side side) { UpgradeMask upgm = 0; Player *applr[kcSides]; int cplrs = GetPlayersListFromCaSideMask(side, m_wfCaSideMask, applr); for (int n = 0; n < cplrs; n++) upgm |= applr[n]->GetUpgradeMask(); return (upgm & m_upgm) != 0; } } // namespace wi