| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497 |
- /*
- ** Command & Conquer Red Alert(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program 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.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /* $Header: /CounterStrike/TRIGGER.CPP 1 3/03/97 10:26a 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 13, 1996 [JLB] *
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * Find_Or_Make -- Find or create a trigger of the type specified. *
- * TriggerClass::As_Target -- Converts trigger to a target value *
- * TriggerClass::Attaches_To -- Determines what trigger can attach to. *
- * TriggerClass::Description -- Fetch a one line ASCII description of the trigger. *
- * TriggerClass::Detach -- Detach specified target from this trigger. *
- * TriggerClass::Draw_It -- Draws this trigger as if it were part of a list box. *
- * TriggerClass::Init -- clears triggers for new scenario *
- * TriggerClass::Spring -- Spring the trigger (possibly). *
- * TriggerClass::TriggerClass -- constructor *
- * TriggerClass::operator delete -- Returns a trigger to the special memory pool. *
- * TriggerClass::operator new -- 'new' operator *
- * TriggerClass::~TriggerClass -- Destructor for trigger objects. *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "function.h"
- #if defined(CHEAT_KEYS) || defined(SCENARIO_EDITOR)
- /***********************************************************************************************
- * TriggerClass::Description -- Fetch a one line ASCII description of the trigger. *
- * *
- * In the rare (possibly never?) case of requiring a description for this trigger, then *
- * just have the model class generate a description and return that. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with an ASCII description of this trigger. *
- * *
- * WARNINGS: see TriggerTypeClass::Description() *
- * *
- * HISTORY: *
- * 07/09/1996 JLB : Created. *
- *=============================================================================================*/
- char const * TriggerClass::Description(void) const
- {
- return(Class->Description());
- }
- /***********************************************************************************************
- * TriggerClass::Draw_It -- Draws this trigger as if it were part of a list box. *
- * *
- * This routine is called when the trigger has been assigned to a list box. It will *
- * display a description of the trigger. *
- * *
- * INPUT: see below... *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 07/09/1996 JLB : Created. *
- *=============================================================================================*/
- void TriggerClass::Draw_It(int , int x, int y, int width, int height, bool selected, TextPrintType flags) const
- {
- RemapControlType * scheme = GadgetClass::Get_Color_Scheme();
- static int _tabs[] = {13,40};
- if ((flags & 0x0F) == TPF_6PT_GRAD || (flags & 0x0F) == TPF_EFNT) {
- if (selected) {
- flags = flags | TPF_BRIGHT_COLOR;
- LogicPage->Fill_Rect(x, y, x + width - 1, y + height - 1, scheme->Shadow);
- } else {
- if (!(flags & TPF_USE_GRAD_PAL)) {
- flags = flags | TPF_MEDIUM_COLOR;
- }
- }
- Conquer_Clip_Text_Print(Description(), x, y, scheme, TBLACK, flags, width, _tabs);
- } else {
- Conquer_Clip_Text_Print(Description(), x, y, (selected ? &ColorRemaps[PCOLOR_DIALOG_BLUE] : &ColorRemaps[PCOLOR_GREY]), TBLACK, flags, width, _tabs);
- }
- }
- #endif
- /***********************************************************************************************
- * TriggerClass::TriggerClass -- constructor *
- * *
- * INPUT: *
- * none. *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 11/28/1994 BR : Created. *
- *=============================================================================================*/
- TriggerClass::TriggerClass(TriggerTypeClass * trigtype) :
- RTTI(RTTI_TRIGGER),
- ID(Triggers.ID(this)),
- Class(trigtype),
- AttachCount(0),
- Cell(0)
- {
- Class->Event1.Reset(Event1);
- Class->Event2.Reset(Event2);
- }
- /***********************************************************************************************
- * 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 && Class.Is_Valid() && (Class->Attaches_To() & ATTACH_GENERAL) != 0) {
- if (LogicTriggerID >= LogicTriggers.ID(this)) {
- LogicTriggerID--;
- if (LogicTriggerID < 0 && LogicTriggers.Count() == 0) {
- LogicTriggerID = 0;
- }
- }
- }
- if (GameActive && Class.Is_Valid() && (Class->Attaches_To() & ATTACH_MAP) != 0) {
- if (MapTriggerID >= MapTriggers.ID(this)) {
- MapTriggerID--;
- if (MapTriggerID < 0 && MapTriggers.Count() == 0) {
- MapTriggerID = 0;
- }
- }
- }
- if (GameActive && Class->House != HOUSE_NONE && Class->Action1.Action == TACTION_ALLOWWIN) {
- if (Houses.Ptr(Class->House)->Blockage) Houses.Ptr(Class->House)->Blockage--;
- Houses.Ptr(Class->House)->BorrowedTime = TICKS_PER_SECOND*4;
- }
- ID = -1;
- }
- /***********************************************************************************************
- * 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 -- Spring the trigger (possibly). *
- * *
- * This routine is called when a potential trigger even has occurred. The event is matched *
- * with the trigger event needed by this trigger. If the condition warrants, the trigger *
- * action is performed. *
- * *
- * INPUT: event -- The event that is occurring. *
- * *
- * obj -- If the trigger is attached to an object, this points to the object. *
- * *
- * cell -- If the trigger is attached to a cell, this is the cell number. *
- * *
- * forced -- Should the trigger be forced to execute regardless of the event? *
- * *
- * OUTPUT: bool; Was the trigger sprung? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/31/1996 JLB : Created. *
- * 08/13/1996 JLB : Linked triggers supported. *
- *=============================================================================================*/
- bool TriggerClass::Spring(TEventType event, ObjectClass * obj, CELL cell, bool forced)
- {
- assert(Triggers.ID(this) == ID);
- bool e1 = Class->Event1(Event1, event, Class->House, obj, forced);
- bool e2 = false;
- bool execute = false;
- /*
- ** Forced triggers must presume that the cell parameter is invalid. It then
- ** uses the embedded cell value in the trigger as the official location where
- ** the trigger will detonate at.
- */
- if (forced) {
- cell = Cell;
- } else {
- /*
- ** Determine if the trigger event is considered to have been sprung according to the
- ** event control value. This might require that both events be triggered, one event
- ** triggered, or either event triggered to activate the trigger action.
- */
- switch (Class->EventControl) {
- case MULTI_ONLY:
- execute = e1;
- break;
- case MULTI_AND:
- e2 = Class->Event2(Event2, event, Class->House, obj, forced);
- execute = (e1 && e2);
- break;
- case MULTI_LINKED:
- case MULTI_OR:
- e2 = Class->Event2(Event2, event, Class->House, obj, forced);
- execute = (e1 || e2);
- break;
- }
- }
- /*
- ** See if the trigger is sprung with a qualifying event.
- */
- if (execute || forced) {
- /*
- ** Verify that the trigger event should really be sprung. Exceptions
- ** would include semi-persistent triggers that don't actually
- ** spring until all triggers have sprung.
- */
- if (Class->IsPersistant == TriggerTypeClass::SEMIPERSISTANT) {
- /*
- ** Detach ourselves from the object and record that there
- ** is one less attachment to keep track of.
- */
- if (obj) {
- obj->Trigger = NULL;
- }
- if (cell) {
- Map[cell].Trigger = NULL;
- }
- /*
- ** 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.
- */
- AttachCount--;
- if (AttachCount > 0) {
- return(false);
- }
- }
- /*
- ** For linked trigger events, perform the action associated with the matching
- ** trigger event. Otherwise perform the action for both events.
- */
- bool ok = false;
- HousesType hh = Class->House;
- if (Class->EventControl == MULTI_LINKED) {
- if (e1 || forced) ok |= Class->Action1(hh, obj, ID, cell);
- if (e2 && !forced) ok |= Class->Action2(hh, obj, ID, cell);
- } else {
- switch (Class->ActionControl) {
- case MULTI_ONLY:
- ok |= Class->Action1(hh, obj, ID, cell);
- break;
- default:
- case MULTI_AND:
- ok |= Class->Action1(hh, obj, ID, cell);
- ok |= Class->Action2(hh, obj, ID, cell);
- break;
- }
- }
- if (!IsActive) return(true);
- /*
- ** If at least one action was performed, then consider this
- ** trigger to have completed and thus will be deleted if
- ** necessary.
- */
- if (ok) {
- #ifdef CHEAT_KEYS
- MonoArray[DMONO_STRESS].Sub_Window(61, 1, 17, 11);
- MonoArray[DMONO_STRESS].Scroll();
- MonoArray[DMONO_STRESS].Sub_Window(61, 1, 18, 11);
- MonoArray[DMONO_STRESS].Set_Cursor(0, 10);
- MonoArray[DMONO_STRESS].Printf("%02d:%02d:%02d-%s", Scen.Timer / TICKS_PER_HOUR, (Scen.Timer % TICKS_PER_HOUR)/TICKS_PER_MINUTE, (Scen.Timer % TICKS_PER_MINUTE)/TICKS_PER_SECOND, Class->IniName);
- MonoArray[DMONO_STRESS].Sub_Window();
- #endif
- if (Class->IsPersistant == TriggerTypeClass::VOLATILE || (Class->IsPersistant == TriggerTypeClass::SEMIPERSISTANT && AttachCount <= 1)) {
- Detach_This_From_All(As_Target(), true);
- delete this;
- return(true);
- } else {
- /*
- ** Reset event data so that the event will
- ** repeat as necessary.
- */
- Class->Event1.Reset(Event1);
- Class->Event2.Reset(Event2);
- }
- }
- }
- return(false);
- }
- /***********************************************************************************************
- * 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 -- Returns a trigger to the special memory pool. *
- * *
- * This routine will return a previously allocated trigger object back to the memory *
- * pool from which it came. *
- * *
- * INPUT: pointer -- Pointer to the trigger to return to the memory pool. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 07/09/1996 JLB : Created. *
- *=============================================================================================*/
- void TriggerClass::operator delete(void * pointer)
- {
- if (pointer) {
- ((TriggerClass *)pointer)->IsActive = false;
- }
- Triggers.Free((TriggerClass *)pointer);
- }
- /***********************************************************************************************
- * TriggerClass::As_Target -- Converts trigger to a target value *
- * *
- * Converts the trigger object into a target identifier. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: TARGET value *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 09/19/1994 JLB : Created. *
- *=============================================================================================*/
- TARGET TriggerClass::As_Target(void) const
- {
- assert(Triggers.ID(this) == ID);
- return(Build_Target(RTTI_TRIGGER, ID));
- }
- /***********************************************************************************************
- * Find_Or_Make -- Find or create a trigger of the type specified. *
- * *
- * This routine is used when, given a trigger type, an actual trigger object is needed. *
- * In this case, an existing trigger of the correct type must be located, or a trigger *
- * object must be created. In either case, this routine will return a trigger object that *
- * corresponds to the trigger type class specified. *
- * *
- * INPUT: trigtype -- Pointer to the trigger type to find (or create) a matching trigger *
- * object. *
- * *
- * OUTPUT: Returns a pointer to a matching trigger object. If no more triggers could be *
- * allocated and no matching trigger could be found, then this routine will return *
- * NULL (a very rare case). *
- * *
- * WARNINGS: This routine could return NULL. *
- * *
- * HISTORY: *
- * 07/09/1996 JLB : Created. *
- *=============================================================================================*/
- TriggerClass * Find_Or_Make(TriggerTypeClass * trigtype)
- {
- if (!trigtype) return(NULL);
- for (int index = 0; index < Triggers.Count(); index++) {
- if (trigtype == Triggers.Ptr(index)->Class) {
- return(Triggers.Ptr(index));
- }
- }
- /*
- ** No trigger was found, so make one.
- */
- TriggerClass * trig = new TriggerClass(trigtype);
- return(trig);
- }
- /***********************************************************************************************
- * TriggerClass::Detach -- Detach specified target from this trigger. *
- * *
- * This routine is called when the specified trigger MUST be detached from all references *
- * to it. The only reference maintained by a trigger is the reference to the trigger *
- * type class it is modeled after. *
- * *
- * INPUT: target -- The target identifier to remove all attachments to. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: You must never detach the trigger type class from a trigger. Such a process *
- * will leave the trigger orphan and in a 'crash the game immediately if used' *
- * state. As such, this routine will throw an assertion if this is tried. *
- * *
- * HISTORY: *
- * 07/09/1996 JLB : Created. *
- *=============================================================================================*/
- void TriggerClass::Detach(TARGET target, bool )
- {
- if (Is_Target_TriggerType(target)) {
- assert((TriggerTypeClass*)Class != As_TriggerType(target));
- // if (Class == As_TriggerType(target)) {
- // Class = NULL;
- // }
- }
- }
|