1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483 |
- //
- // Copyright 2020 Electronic Arts Inc.
- //
- // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
- // software: you can redistribute it and/or modify it under the terms of
- // the GNU General Public License as published by the Free Software Foundation,
- // either version 3 of the License, or (at your option) any later version.
- // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
- // in the hope that it will be useful, but with permitted additional restrictions
- // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
- // distributed with this program. You should have received a copy of the
- // GNU General Public License along with permitted additional restrictions
- // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
- /* $Header: F:\projects\c&c\vcs\code\trigger.cpv 2.17 16 Oct 1995 16:51:20 JOE_BOSTIC $ */
- /***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : Command & Conquer *
- * *
- * File Name : TRIGGER.CPP *
- * *
- * Programmer : Joe L. Bostic *
- * *
- * Start Date : 11/12/94 *
- * *
- * Last Update : August 27, 1995 [JLB] *
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * Do_All_To_Hunt -- Forces all computer controlled units into hunt mode. *
- * TriggerClass::Action_From_Name -- retrieves ActionType for given name *
- * TriggerClass::Action_Need_Team -- Determines if this action event requires a team. *
- * TriggerClass::As_Pointer -- returns pointer for the given trigger name *
- * TriggerClass::As_Target -- Converts trigger to a target value *
- * TriggerClass::Event_From_Name -- retrieves EventType for given name *
- * TriggerClass::Event_Need_Data -- Determines if this event requires a data value. *
- * TriggerClass::Event_Need_House -- Determines if this event requires a house identifier. *
- * TriggerClass::Event_Need_Object -- Determines if the specified event requires an object. *
- * TriggerClass::Init -- clears triggers for new scenario *
- * TriggerClass::Name_From_Action -- retrieves name for ActionType *
- * TriggerClass::Name_From_Event -- retrieves name for EventType *
- * TriggerClass::Read_INI -- reads triggers from the INI file *
- * TriggerClass::Remove -- removes this trigger from the game *
- * TriggerClass::Spring -- Trigger processing routine for cell-based triggers *
- * TriggerClass::Spring -- Trigger processing routine for house-based triggers *
- * TriggerClass::Spring -- Trigger processing routine for object-based triggers *
- * TriggerClass::TriggerClass -- constructor *
- * TriggerClass::Validate -- validates trigger pointer *
- * TriggerClass::Write_INI -- writes triggers to the INI file *
- * TriggerClass::operator delete -- 'delete' operator *
- * TriggerClass::operator new -- 'new' operator *
- * TriggerClass::~TriggerClass -- Destructor for trigger objects. *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "function.h"
- static void Do_All_To_Hunt(void);
- #define FIXUP 0
- /*
- ********************************** Globals **********************************
- */
- static const char * EventText[EVENT_COUNT + 1] = {
- "None",
- "Player Enters",
- "Discovered",
- "Attacked",
- "Destroyed",
- "Any",
- "House Discov.",
- "Units Destr.",
- "Bldgs Destr.",
- "All Destr.",
- "Credits",
- "Time",
- "# Bldgs Dstr.",
- "# Units Dstr.",
- "No Factories",
- "Civ. Evac.",
- "Built It"
- };
- static const char * ActionText[TriggerClass::ACTION_COUNT + 1] = {
- "None",
- "Win",
- "Lose",
- "Production",
- "Create Team",
- "Dstry Teams",
- "All to Hunt",
- "Reinforce.",
- "DZ at 'Z'",
- "Airstrike",
- "Nuclear Missile",
- "Ion Cannon",
- "Dstry Trig 'XXXX'",
- "Dstry Trig 'YYYY'",
- "Dstry Trig 'ZZZZ'",
- "Autocreate",
- "Cap=Win/Des=Lose",
- "Allow Win"
- };
- /***********************************************************************************************
- * TriggerClass::Validate -- validates trigger pointer *
- * *
- * INPUT: *
- * none. *
- * *
- * OUTPUT: *
- * 1 = ok, 0 = error *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 08/09/1995 BRR : Created. *
- *=============================================================================================*/
- #ifdef CHEAT_KEYS
- int TriggerClass::Validate(void) const
- {
- int num;
- num = Triggers.ID(this);
- if (num < 0 || num >= TRIGGER_MAX) {
- Validate_Error("TRIGGER");
- return (0);
- }
- else
- return (1);
- }
- #else
- #define Validate()
- #endif
- /***********************************************************************************************
- * TriggerClass::Event_Need_Object -- Determines if the specified event requires an object. *
- * *
- * This routine determines if the specified event must be attached to an object. Such *
- * events can only exist in a parasitic fashion attached to object(s) in the game. *
- * *
- * INPUT: event -- The event type to examine. *
- * *
- * OUTPUT: Does the specified event require attachement to an object? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/27/1995 JLB : Created. *
- *=============================================================================================*/
- bool TriggerClass::Event_Need_Object(EventType event)
- {
- switch (event) {
- case EVENT_PLAYER_ENTERED:
- case EVENT_DISCOVERED:
- case EVENT_ATTACKED:
- case EVENT_DESTROYED:
- case EVENT_ANY:
- return(true);
- }
- return(false);
- }
- /***********************************************************************************************
- * TriggerClass::Event_Need_House -- Determines if this event requires a house identifier. *
- * *
- * This routine is used to determine if the specified event requires a house identifier. *
- * All trigger events that affect a house will require a house identifier. *
- * *
- * INPUT: event -- The event type to examine. *
- * *
- * OUTPUT: Does the specified event type require a house identifier? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/27/1995 JLB : Created. *
- *=============================================================================================*/
- bool TriggerClass::Event_Need_House(EventType event)
- {
- switch (event) {
- case EVENT_PLAYER_ENTERED:
- case EVENT_HOUSE_DISCOVERED:
- case EVENT_UNITS_DESTROYED:
- case EVENT_BUILDINGS_DESTROYED:
- case EVENT_ALL_DESTROYED:
- case EVENT_CREDITS:
- case EVENT_TIME:
- case EVENT_NBUILDINGS_DESTROYED:
- case EVENT_NUNITS_DESTROYED:
- case EVENT_NOFACTORIES:
- case EVENT_EVAC_CIVILIAN:
- case EVENT_BUILD:
- return(true);
- }
- return(false);
- }
- /***********************************************************************************************
- * TriggerClass::Event_Need_Data -- Determines if this event requires a data value. *
- * *
- * This routine will determine if the specified event requires a data number parameter. *
- * This is commonly needed for trigger events. *
- * *
- * INPUT: event -- The event to examine. *
- * *
- * OUTPUT: Does the specified event require a data number parameter? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/27/1995 JLB : Created. *
- *=============================================================================================*/
- bool TriggerClass::Event_Need_Data(EventType event)
- {
- switch (event) {
- case EVENT_CREDITS:
- case EVENT_TIME:
- case EVENT_NBUILDINGS_DESTROYED:
- case EVENT_NUNITS_DESTROYED:
- case EVENT_BUILD:
- return(true);
- }
- return(false);
- }
- /***********************************************************************************************
- * TriggerClass::Action_Need_Team -- Determines if this action event requires a team. *
- * *
- * This routine will determine if the specified action requires a team name parameter. *
- * Typically, this is needed for reinforcements or other trigger events that affect *
- * a particular team type. *
- * *
- * INPUT: action -- The action that is to be examined. *
- * *
- * OUTPUT: Does the specified action require a team type name? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/27/1995 JLB : Created. *
- *=============================================================================================*/
- bool TriggerClass::Action_Need_Team(TriggerClass::ActionType action)
- {
- switch (action) {
- case ACTION_CREATE_TEAM:
- case ACTION_DESTROY_TEAM:
- case ACTION_REINFORCEMENTS:
- return(true);
- }
- return(false);
- }
- /***********************************************************************************************
- * TriggerClass::TriggerClass -- constructor *
- * *
- * INPUT: *
- * none. *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 11/28/1994 BR : Created. *
- *=============================================================================================*/
- TriggerClass::TriggerClass(void)
- {
- IsPersistant = VOLATILE;
- AttachCount = 0;
- Event = EVENT_NONE;
- Action = ACTION_NONE;
- House = HOUSE_NONE;
- DataCopy = Data = 0L;
- Name[0] = '\0';
- Team = NULL;
- }
- /***********************************************************************************************
- * TriggerClass::~TriggerClass -- Destructor for trigger objects. *
- * *
- * This destructor will update the house blockage value if necessary. No other action need *
- * be performed on trigger destruction. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 07/29/1995 JLB : Created. *
- *=============================================================================================*/
- TriggerClass::~TriggerClass(void)
- {
- if (GameActive && House != HOUSE_NONE && Action == ACTION_ALLOWWIN) {
- if (Houses.Ptr(House)->Blockage) Houses.Ptr(House)->Blockage--;
- Houses.Ptr(House)->BorrowedTime = TICKS_PER_SECOND*4;
- }
- }
- /***********************************************************************************************
- * TriggerClass::Init -- clears triggers for new scenario *
- * *
- * INPUT: *
- * none. *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 11/29/1994 BR : Created. *
- *=============================================================================================*/
- void TriggerClass::Init(void)
- {
- Triggers.Free_All();
- }
- /***********************************************************************************************
- * TriggerClass::Spring -- Trigger processing routine *
- * *
- * Checks whether this trigger should "spring" for the given event & object; *
- * If it should, then some really cool undocumented stuff magically happens. *
- * *
- * INPUT: *
- * event EventType: What happened? *
- * object Ptr to object containing this trigger: What did it happen to? *
- * *
- * OUTPUT: *
- * 0 = nothing happened; 1 = the trigger was sprung *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 12/06/1994 BR : Created. *
- * 06/25/1995 JLB : Added more trigger events. *
- *=============================================================================================*/
- bool TriggerClass::Spring(EventType event, ObjectClass *obj)
- {
- Validate();
- /*
- ** If this is not the event for this trigger, just return.
- */
- if (event != Event && Event != EVENT_ANY) {
- return(false);
- }
- /*
- ** If time-based, decrement the minute counter; return if it's not time yet
- */
- if (Event == EVENT_TIME) {
- Data--;
- if (Data > 0) {
- return(false);
- }
- Data = DataCopy;
- }
- /*
- ** Semi-persistant trigger: first detach it from the calling object, then
- ** see if this is the last object we're attached to; if so, the trigger
- ** will spring.
- */
- if (IsPersistant == SEMIPERSISTANT) {
- /*
- ** Detach ourselves from the object
- */
- obj->Trigger = NULL;
- /*
- ** Decrement our attachment counter
- */
- AttachCount--;
- /*
- ** If we're attached to more objects, don't spring; otherwise, spring.
- ** And, mark ourselves as volatile so we'll completely remove ourselves
- ** from the game after we go off.
- */
- if (AttachCount > 0) {
- return(false);
- } else {
- IsPersistant = VOLATILE;
- }
- }
- /*
- ** Otherwise, take an appropriate action.
- */
- bool success = true;
- TriggerClass * trig = NULL;
- switch (Action) {
- case ACTION_NUKE:
- HouseClass::As_Pointer(HOUSE_BAD)->NukeStrike.Enable(true, false);
- HouseClass::As_Pointer(HOUSE_BAD)->NukeStrike.Forced_Charge(PlayerPtr->Class->House == HOUSE_BAD);
- break;
- case ACTION_ION:
- HouseClass::As_Pointer(HOUSE_GOOD)->IonCannon.Enable(true, false);
- HouseClass::As_Pointer(HOUSE_GOOD)->IonCannon.Forced_Charge(PlayerPtr->Class->House == HOUSE_GOOD);
- break;
- case ACTION_WINLOSE:
- switch (event) {
- case EVENT_DESTROYED:
- if (!PlayerPtr->IsToWin || PlayerPtr->Blockage > 0) PlayerPtr->Flag_To_Lose();
- success = true;
- break;
- case EVENT_PLAYER_ENTERED:
- if (!PlayerPtr->IsToLose) PlayerPtr->Flag_To_Win();
- success = true;
- break;
- default:
- success = false;
- break;
- }
- break;
- case ACTION_DESTROY_XXXX:
- trig = As_Pointer("XXXX");
- if (trig) {
- trig->Remove();
- }
- delete trig;
- break;
- case ACTION_DESTROY_YYYY:
- trig = As_Pointer("YYYY");
- if (trig) {
- trig->Remove();
- }
- delete trig;
- break;
- case ACTION_DESTROY_ZZZZ:
- trig = As_Pointer("ZZZZ");
- if (trig) {
- trig->Remove();
- }
- delete trig;
- break;
- case ACTION_AIRSTRIKE:
- PlayerPtr->IsAirstrikePending = true;
- // PlayerPtr->Make_Air_Strike_Available(true);
- break;
- case ACTION_DZ:
- new AnimClass(ANIM_LZ_SMOKE, Cell_Coord(Waypoint[25]));
- break;
- case ACTION_NONE:
- break;
- case ACTION_WIN:
- PlayerPtr->Flag_To_Win();
- break;
- case ACTION_LOSE:
- PlayerPtr->Flag_To_Lose();
- break;
- case ACTION_BEGIN_PRODUCTION:
- HouseClass::As_Pointer(House)->Begin_Production();
- break;
- case ACTION_AUTOCREATE:
- if (obj && obj->Is_Techno()) {
- ((TechnoClass *)obj)->House->IsAlerted = true;
- }
- break;
- case ACTION_CREATE_TEAM:
- if (Team) {
- ScenarioInit++;
- Team->Create_One_Of();
- ScenarioInit--;
- }
- break;
- case ACTION_DESTROY_TEAM:
- if (Team) {
- Team->Destroy_All_Of();
- }
- break;
- case ACTION_REINFORCEMENTS:
- if (Team) {
- success = Do_Reinforcements(Team);
- }
- break;
- case ACTION_ALL_HUNT:
- Do_All_To_Hunt();
- break;
- default:
- break;
- }
- if (!success && Event == EVENT_TIME) Data = 1;
- /*
- ** Remove trigger from the game.
- */
- if (success && IsPersistant == VOLATILE) {
- Remove();
- }
- return(true);
- }
- /***********************************************************************************************
- * TriggerClass::Spring -- Trigger processing routine *
- * *
- * This version of Spring is for cell-based triggers. *
- * *
- * INPUT: *
- * data elapsed time, or credits, depending on what 'Event' is. *
- * *
- * OUTPUT: *
- * 0 = nothing happened; 1 = the trigger was sprung *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 12/06/1994 BR : Created. *
- *=============================================================================================*/
- bool TriggerClass::Spring(EventType event, CELL cell)
- {
- Validate();
- /*
- ** If this is not the event for this trigger, just return.
- */
- if (event != Event) {
- return(false);
- }
- /*
- ** If time-based, decrement the minute counter; return if it's not time yet
- */
- if (Event == EVENT_TIME) {
- Data--;
- if (Data > 0) {
- return(false);
- }
- Data = DataCopy;
- }
- /*
- ** Semi-persistant trigger: first detach it from the calling cell, then
- ** see if this is the last cell we're attached to; if so, the trigger
- ** will spring.
- */
- if (IsPersistant == SEMIPERSISTANT) {
- /*
- ** Detach ourselves from the cell
- */
- Map[cell].IsTrigger = 0;
- /*
- ** Decrement our attachment counter
- */
- AttachCount--;
- /*
- ** If we're attached to more cells, don't spring; otherwise, spring.
- ** And, mark ourselves as volatile so we'll completely remove ourselves
- ** from the game after we go off.
- */
- if (AttachCount > 0) {
- return(false);
- } else {
- IsPersistant = VOLATILE;
- }
- }
- /*
- ** Otherwise, take an appropriate action.
- */
- bool success = true;
- TriggerClass * trig = NULL;
- int index;
- switch (Action) {
- case ACTION_NUKE:
- HouseClass::As_Pointer(HOUSE_BAD)->NukeStrike.Enable(true, false);
- HouseClass::As_Pointer(HOUSE_BAD)->NukeStrike.Forced_Charge(PlayerPtr->Class->House == HOUSE_BAD);
- break;
- case ACTION_ION:
- HouseClass::As_Pointer(HOUSE_GOOD)->IonCannon.Enable(true, false);
- HouseClass::As_Pointer(HOUSE_GOOD)->IonCannon.Forced_Charge(PlayerPtr->Class->House == HOUSE_GOOD);
- break;
- case ACTION_AUTOCREATE:
- for (index = 0; index < Houses.Count(); index++) {
- Houses.Ptr(index)->IsAlerted = true;
- }
- break;
- case ACTION_DESTROY_XXXX:
- trig = As_Pointer("XXXX");
- if (trig) {
- trig->Remove();
- }
- delete trig;
- break;
- case ACTION_DESTROY_YYYY:
- trig = As_Pointer("YYYY");
- if (trig) {
- trig->Remove();
- }
- delete trig;
- break;
- case ACTION_DESTROY_ZZZZ:
- trig = As_Pointer("ZZZZ");
- if (trig) {
- trig->Remove();
- }
- delete trig;
- break;
- case ACTION_AIRSTRIKE:
- HouseClass::As_Pointer(House)->AirStrike.Enable(false, true);
- if (House == PlayerPtr->Class->House) {
- PlayerPtr->AirStrike.Forced_Charge(true);
- Map.Add(RTTI_SPECIAL, SPC_AIR_STRIKE);
- Map.Column[1].Flag_To_Redraw();
- }
- // PlayerPtr->Make_Air_Strike_Available(true);
- break;
- case ACTION_DZ:
- new AnimClass(ANIM_LZ_SMOKE, Cell_Coord(Waypoint[25]));
- break;
- case ACTION_NONE:
- break;
- case ACTION_WIN:
- PlayerPtr->Flag_To_Win();
- break;
- case ACTION_LOSE:
- PlayerPtr->Flag_To_Lose();
- break;
- case ACTION_BEGIN_PRODUCTION:
- if (PlayerPtr->Class->House == HOUSE_GOOD) {
- HouseClass::As_Pointer(HOUSE_BAD)->Begin_Production();
- } else {
- HouseClass::As_Pointer(HOUSE_GOOD)->Begin_Production();
- }
- break;
- case ACTION_CREATE_TEAM:
- if (Team) {
- ScenarioInit++;
- Team->Create_One_Of();
- ScenarioInit--;
- }
- break;
- case ACTION_DESTROY_TEAM:
- if (Team) {
- Team->Destroy_All_Of();
- }
- break;
- case ACTION_REINFORCEMENTS:
- if (Team) {
- success = Do_Reinforcements(Team);
- }
- break;
- case ACTION_ALL_HUNT:
- Do_All_To_Hunt();
- break;
- default:
- break;
- }
- if (!success && Event == EVENT_TIME) Data = 1;
- /*
- ** Remove trigger from the game.
- */
- if (success && IsPersistant == VOLATILE) {
- Remove();
- }
- return(true);
- }
- /***********************************************************************************************
- * TriggerClass::Spring -- Trigger processing routine *
- * *
- * This version of Spring is for house-specific triggers. *
- * For a time-based trigger, 'data' will the the current TickCount. *
- * For a credit-based trigger, 'data' will be the credits for the HouseClass *
- * containing this trigger. *
- * *
- * INPUT: *
- * event the event that happened *
- * house house that this event relates to *
- * data elapsed time, or credits, depending on what 'Event' is. *
- * *
- * OUTPUT: *
- * 0 = nothing happened; 1 = the trigger was sprung *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 12/06/1994 BR : Created. *
- * 06/25/1995 JLB : Added more trigger events. *
- *=============================================================================================*/
- bool TriggerClass::Spring(EventType event, HousesType house, long data)
- {
- Validate();
- /*
- ** If this is not the event for this trigger, just return.
- */
- if (event != Event || house != House) {
- return(false);
- }
- /*
- ** If credits-based, check 'data'
- */
- if (Event == EVENT_CREDITS && data < Data) {
- return(false);
- }
- /*
- ** Building event check to ensure that the building number matches.
- */
- if (Event == EVENT_BUILD && data != Data) {
- return(false);
- }
- /*
- ** Number of objects destroyed checker. If the data supplied indicates that
- ** the correct number of objects have been destroyed, then this trigger
- ** will succeed.
- */
- if (Event == EVENT_NBUILDINGS_DESTROYED || Event == EVENT_NUNITS_DESTROYED) {
- if (data < Data) {
- return(false);
- }
- }
- /*
- ** If time-based, decrement the minute counter; return if it's not time yet
- */
- if (Event == EVENT_TIME) {
- Data--;
- if (Data > 0) {
- return(false);
- }
- Data = DataCopy;
- }
- /*
- ** The trigger has gone off; take appropriate action
- */
- bool success = true;
- TriggerClass * trig = NULL;
- switch (Action) {
- case ACTION_NUKE:
- HouseClass::As_Pointer(HOUSE_BAD)->NukeStrike.Enable(true, false);
- HouseClass::As_Pointer(HOUSE_BAD)->NukeStrike.Forced_Charge(PlayerPtr->Class->House == HOUSE_BAD);
- break;
- case ACTION_ION:
- HouseClass::As_Pointer(HOUSE_GOOD)->IonCannon.Enable(true, false);
- HouseClass::As_Pointer(HOUSE_GOOD)->IonCannon.Forced_Charge(PlayerPtr->Class->House == HOUSE_GOOD);
- break;
- /*
- ** This will remove a blockage to the win condition. No action need
- ** be performed here since the act of deleting the trigger will
- ** remove the blockage.
- */
- case ACTION_ALLOWWIN:
- break;
- case ACTION_AUTOCREATE:
- HouseClass::As_Pointer(House)->IsAlerted = true;
- break;
- case ACTION_DESTROY_XXXX:
- trig = As_Pointer("XXXX");
- if (trig) {
- trig->Remove();
- }
- delete trig;
- break;
- case ACTION_DESTROY_YYYY:
- trig = As_Pointer("YYYY");
- if (trig) {
- trig->Remove();
- }
- delete trig;
- break;
- case ACTION_DESTROY_ZZZZ:
- trig = As_Pointer("ZZZZ");
- if (trig) {
- trig->Remove();
- }
- delete trig;
- break;
- case ACTION_AIRSTRIKE:
- PlayerPtr->AirStrike.Enable(false, true);
- if (House == PlayerPtr->Class->House) {
- PlayerPtr->AirStrike.Forced_Charge(true);
- Map.Add(RTTI_SPECIAL, SPC_AIR_STRIKE);
- Map.Column[1].Flag_To_Redraw();
- }
- break;
- case ACTION_NONE:
- break;
- case ACTION_DZ:
- new AnimClass(ANIM_LZ_SMOKE, Cell_Coord(Waypoint[25]));
- break;
- case ACTION_WIN:
- PlayerPtr->Flag_To_Win();
- break;
- case ACTION_LOSE:
- PlayerPtr->Flag_To_Lose();
- break;
- case ACTION_BEGIN_PRODUCTION:
- HouseClass::As_Pointer(House)->Begin_Production();
- break;
- case ACTION_CREATE_TEAM:
- if (Team) {
- ScenarioInit++;
- Team->Create_One_Of();
- ScenarioInit--;
- }
- break;
- case ACTION_DESTROY_TEAM:
- if (Team) {
- Team->Destroy_All_Of();
- }
- break;
- case ACTION_REINFORCEMENTS:
- if (Team) {
- success = Do_Reinforcements(Team);
- }
- break;
- case ACTION_ALL_HUNT:
- Do_All_To_Hunt();
- break;
- default:
- break;
- }
- if (!success && Event == EVENT_TIME) Data = 1;
- /*
- ** Remove trigger from the game.
- */
- if (success && IsPersistant == VOLATILE) {
- Remove();
- }
- return(true);
- }
- /***********************************************************************************************
- * TriggerClass::Remove -- removes this trigger from the game *
- * *
- * INPUT: *
- * none. *
- * *
- * OUTPUT: *
- * 1 = trigger was removed, 0 = it wasn't *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 12/06/1994 BR : Created. *
- *=============================================================================================*/
- bool TriggerClass::Remove(void)
- {
- Validate();
- CELL cell;
- HousesType h;
- int index;
- /*
- ** Loop through all cells; remove any reference to this trigger
- */
- for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
- if (Map[cell].IsTrigger) {
- if (CellTriggers[cell] == this) {
- Map[cell].IsTrigger = 0;
- CellTriggers[cell] = NULL;
- }
- }
- }
- /*
- ** Loop through all objects, removing any reference to this trigger
- */
- for (index = 0; index < Infantry.Count(); index++) {
- if (Infantry.Ptr(index)->Trigger == this) {
- Infantry.Ptr(index)->Trigger = NULL;
- }
- }
- for (index = 0; index < Buildings.Count(); index++) {
- if (Buildings.Ptr(index)->Trigger == this) {
- Buildings.Ptr(index)->Trigger = NULL;
- }
- }
- for (index = 0; index < Units.Count(); index++) {
- if (Units.Ptr(index)->Trigger == this) {
- Units.Ptr(index)->Trigger = NULL;
- }
- }
- for (index = 0; index < Terrains.Count(); index++) {
- if (Terrains.Ptr(index)->Trigger == this) {
- Terrains.Ptr(index)->Trigger = NULL;
- }
- }
- /*
- ** Remove this trigger from any house list it's in. Invoking '-=' with a
- ** pointer not in the list has no effect; loop through all houses just to
- ** be on the safe side.
- */
- for (h = HOUSE_FIRST; h < HOUSE_COUNT; h++) {
- HouseTriggers[h].Delete(this);
- }
- delete this;
- return(true);
- }
- /***********************************************************************************************
- * TriggerClass::Read_INI -- reads triggers from the INI file *
- * *
- * INI entry format: *
- * Triggername = Eventname, Actionname, Data, Housename, TeamName, IsPersistant *
- * *
- * This routine reads in the triggers & creates them. Then, other classes can *
- * get pointers to the triggers they're linked to. *
- * *
- * The routine relies on the TeamTypeClasses already being loaded so it can resolve *
- * references to teams in this function. *
- * *
- * Cell Trigger pointers & IsTrigger flags are set in DisplayClass::Read_INI(), *
- * and cleared in the Map::Init() routine (which clears all cell objects to 0's). *
- * *
- * Object's pointers are set in: *
- * InfantryClass::Read_INI() *
- * BuildingClass::Read_INI() *
- * UnitClass::Read_INI() *
- * TerrainClass::Read_INI() *
- * The object trigger pointers are cleared in the ObjectClass constructor. *
- * *
- * The House's EMSListOf triggers is set in this routine, and cleared in the *
- * HouseClass::Init() routine. *
- * *
- * INPUT: *
- * buffer buffer to hold the INI data *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * This function must be called before any other class's Read_INI. *
- * *
- * HISTORY: *
- * 11/28/1994 BR : Created. *
- *=============================================================================================*/
- void TriggerClass::Read_INI(char *buffer)
- {
- TriggerClass *trigger; // Working trigger pointer.
- char *tbuffer; // Accumulation buffer of trigger IDs.
- int len; // Length of data in buffer.
- char buf[128];
- /*
- ** Set 'tbuffer' to point just past the INI buffer
- */
- len = strlen(buffer) + 2;
- tbuffer = buffer + len;
- /*
- ** Read all TRIGGER entry names into 'tbuffer'
- */
- WWGetPrivateProfileString(INI_Name(), NULL, NULL, tbuffer, ShapeBufferSize-len, buffer);
- /*
- ** Loop for all trigger entries.
- */
- while (*tbuffer != '\0') {
- /*
- ** Create a new trigger.
- */
- trigger = new TriggerClass();
- /*
- ** Set its name.
- */
- trigger->Set_Name (tbuffer);
- /*
- ** Get the trigger entry.
- */
- WWGetPrivateProfileString(INI_Name(), tbuffer, NULL, buf, sizeof(buf)-1, buffer);
- /*
- ** Fill in the trigger.
- */
- trigger->Fill_In(tbuffer,buf);
- /*
- ** Add 'trigger' to the House's list.
- */
- // if (trigger->House != HOUSE_NONE && trigger->Event != EVENT_PLAYER_ENTERED) {
- // if (Event_Need_House(trigger->Event) && !Event_Need_Object(trigger->Event)) {
- if (trigger->House != HOUSE_NONE) {
- if (trigger->Action == ACTION_ALLOWWIN) HouseClass::As_Pointer(trigger->House)->Blockage++;
- HouseTriggers[trigger->House].Add(trigger);
- trigger->AttachCount++;
- }
- /*
- ** Go to next entry.
- */
- tbuffer += strlen(tbuffer)+1;
- }
- }
- /***********************************************************************************************
- * TriggerClass::Fill_In -- fills in trigger from the given INI entry *
- * *
- * This routine fills in the given trigger with the given name, and values from *
- * the given INI entry. *
- * *
- * (This routine is used by the scenario editor, to import teams from the MASTER.INI file.) *
- * *
- * INI entry format: *
- * Triggername = Eventname, Actionname, Data, Housename, TeamName, IsPersistant *
- * *
- * INPUT: *
- * name mnemonic for the desired trigger *
- * entry INI entry to parse *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 11/28/1994 BR : Created. *
- *=============================================================================================*/
- void TriggerClass::Fill_In(char * name, char *entry)
- {
- Validate();
- char *p;
- /*
- ** Set its name.
- */
- Set_Name(name);
- /*
- ** 1st token: Event.
- */
- Event = Event_From_Name(strtok(entry, ","));
- /*
- ** 2nd token: Action.
- */
- Action = Action_From_Name(strtok(NULL, ","));
- /*
- ** 3rd token: Data.
- */
- DataCopy = Data = atol(strtok(NULL, ","));
- /*
- ** 4th token: House.
- */
- House = HouseTypeClass::From_Name(strtok(NULL, ","));
- if (House == HOUSE_NONE && Event == EVENT_PLAYER_ENTERED) {
- House = PlayerPtr->Class->House;
- }
- /*
- ** 5th token: Team.
- */
- Team = TeamTypeClass::As_Pointer(strtok(NULL, ","));
- /*
- ** 6th token: IsPersistant. This token was added later, so we must check
- ** for its existence.
- */
- p = strtok(NULL, ",");
- if (p) {
- IsPersistant = (PersistantType)atoi(p);
- } else {
- IsPersistant = VOLATILE;
- }
- }
- /***********************************************************************************************
- * TriggerClass::Write_INI -- writes triggers to the INI file *
- * *
- * INI entry format: *
- * Triggername = Eventname, Actionname, Data, Housename, TeamName, IsPersistant *
- * *
- * INPUT: *
- * buffer buffer to hold the INI data *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 11/28/1994 BR : Created. *
- *=============================================================================================*/
- void TriggerClass::Write_INI(char *buffer, bool refresh)
- {
- int index;
- char buf[128];
- TriggerClass *trigger;
- char const *hname;
- char const *tname;
- /*
- ** First, clear out all existing trigger data from the INI file.
- */
- if (refresh) {
- WWWritePrivateProfileString(INI_Name(), NULL, NULL, buffer);
- }
- /*
- ** Now write all the trigger data out
- */
- for (index = 0; index < Triggers.Count(); index++) {
- /*
- ** Get ptr to next active trigger.
- */
- trigger = Triggers.Ptr(index);
- /*
- ** Generate INI entry.
- */
- if (trigger->House==HOUSE_NONE) {
- hname = "None";
- } else {
- hname = HouseClass::As_Pointer(trigger->House)->Class->IniName;
- }
- if (trigger->Team==NULL) {
- tname = "None";
- } else {
- tname = trigger->Team->IniName;
- }
- sprintf(buf,"%s,%s,%ld,%s,%s,%d",
- TriggerClass::Name_From_Event(trigger->Event),
- TriggerClass::Name_From_Action(trigger->Action),
- trigger->Data,
- hname,
- tname,
- trigger->IsPersistant);
- WWWritePrivateProfileString(INI_Name(), trigger->Get_Name(), buf, buffer);
- }
- }
- /***********************************************************************************************
- * TriggerClass::As_Pointer -- returns pointer for the given trigger name *
- * *
- * This function is designed for use at initialization time, ie when the *
- * trigger mnemonics are read from the INI and the Read_INI functions need *
- * to get a pointer to that trigger. *
- * *
- * INPUT: *
- * name mnemonic for the desired trigger *
- * *
- * OUTPUT: *
- * near pointer to that trigger, NULL if not found *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 11/28/1994 BR : Created. *
- *=============================================================================================*/
- TriggerClass * TriggerClass::As_Pointer(char const * name)
- {
- if (name == NULL) {
- return(NULL);
- }
- for (int i = 0; i < Triggers.Count(); i++) {
- TriggerClass * trigger = Triggers.Ptr(i);
- if (!stricmp(name, trigger->Name)) {
- return(trigger);
- }
- }
- return(NULL);
- }
- /***********************************************************************************************
- * TriggerClass::operator new -- 'new' operator *
- * *
- * INPUT: *
- * none. *
- * *
- * OUTPUT: *
- * pointer to new trigger *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 11/28/1994 BR : Created. *
- *=============================================================================================*/
- void * TriggerClass::operator new(size_t )
- {
- void * ptr = Triggers.Allocate();
- if (ptr) {
- ((TriggerClass *)ptr)->IsActive = true;
- }
- return(ptr);
- }
- /***********************************************************************************************
- * TriggerClass::operator delete -- 'delete' operator *
- * *
- * INPUT: *
- * ptr pointer to delete *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 11/28/1994 BR : Created. *
- *=============================================================================================*/
- void TriggerClass::operator delete(void *ptr)
- {
- if (ptr) {
- ((TriggerClass *)ptr)->IsActive = false;
- }
- Triggers.Free((TriggerClass *)ptr);
- }
- /***********************************************************************************************
- * TriggerClass::Event_From_Name -- retrieves EventType for given name *
- * *
- * INPUT: *
- * name name to get event for *
- * *
- * OUTPUT: *
- * EventType for given name *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 11/29/1994 BR : Created. *
- *=============================================================================================*/
- EventType TriggerClass::Event_From_Name (char const *name)
- {
- int i;
- if (name == NULL) {
- return(EVENT_NONE);
- }
- for (i = EVENT_NONE; i < EVENT_COUNT; i++) {
- if (!stricmp(name,EventText[i + 1])) {
- return((EventType)i);
- }
- }
- return(EVENT_NONE);
- }
- /***********************************************************************************************
- * TriggerClass::Name_From_Event -- retrieves name for EventType *
- * *
- * INPUT: *
- * event EventType to get name for *
- * *
- * OUTPUT: *
- * name for EventType *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 11/29/1994 BR : Created. *
- *=============================================================================================*/
- char const *TriggerClass::Name_From_Event(EventType event)
- {
- return(EventText[event + 1]);
- }
- /***********************************************************************************************
- * TriggerClass::Action_From_Name -- retrieves ActionType for given name *
- * *
- * INPUT: *
- * name name to get ActionType for *
- * *
- * OUTPUT: *
- * ActionType for given name *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 11/29/1994 BR : Created. *
- *=============================================================================================*/
- TriggerClass::ActionType TriggerClass::Action_From_Name (char const *name)
- {
- int i;
- if (name == NULL) {
- return(ACTION_NONE);
- }
- for (i = ACTION_NONE; i < ACTION_COUNT; i++) {
- if (!stricmp(name,ActionText[i + 1])) {
- return((ActionType)i);
- }
- }
- return(ACTION_NONE);
- }
- /***********************************************************************************************
- * TriggerClass::Name_From_Action -- retrieves name for ActionType *
- * *
- * INPUT: *
- * action ActionType to get name for *
- * *
- * OUTPUT: *
- * name of ActionType *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 11/29/1994 BR : Created. *
- *=============================================================================================*/
- char const *TriggerClass::Name_From_Action(ActionType action)
- {
- return(ActionText[action + 1]);
- }
- /***********************************************************************************************
- * TriggerClass::As_Target -- Converts trigger to a target value *
- * *
- * INPUT: none *
- * *
- * OUTPUT: TARGET value *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 09/19/1994 JLB : Created. *
- *=============================================================================================*/
- TARGET TriggerClass::As_Target(void) const
- {
- Validate();
- return(Build_Target(KIND_TRIGGER, Triggers.ID(this)));
- }
- /***********************************************************************************************
- * Do_All_To_Hunt -- Forces all computer controlled units into hunt mode. *
- * *
- * This trigger action will cause the computer units and infantry to go into hunt mode. *
- * Use it to bring a scenario to a sudden conclusion. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 04/20/1995 JLB : Created. *
- * 08/14/1995 JLB : Removes the member from a team if necessary. *
- *=============================================================================================*/
- static void Do_All_To_Hunt(void)
- {
- int index;
- for (index = 0; index < Units.Count(); index++) {
- UnitClass * unit = Units.Ptr(index);
- if (!unit->House->IsHuman && unit->IsDown && !unit->IsInLimbo) {
- if (unit->Team) unit->Team->Remove(unit);
- unit->Assign_Mission(MISSION_HUNT);
- }
- }
- for (index = 0; index < Infantry.Count(); index++) {
- InfantryClass * infantry = Infantry.Ptr(index);
- if (!infantry->House->IsHuman && infantry->IsDown && !infantry->IsInLimbo) {
- if (infantry->Team) infantry->Team->Remove(infantry);
- infantry->Assign_Mission(MISSION_HUNT);
- }
- }
- }
|