| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- //
- // 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: /CounterStrike/LOGIC.CPP 1 3/03/97 10:25a 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 : LOGIC.CPP *
- * *
- * Programmer : Joe L. Bostic *
- * *
- * Start Date : September 27, 1993 *
- * *
- * Last Update : July 30, 1996 [JLB] *
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * LogicClass::AI -- Handles AI logic processing for game objects. *
- * LogicClass::Debug_Dump -- Displays logic class status to the mono screen. *
- * LogicClass::Detach -- Detatch the specified target from the logic system. *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "function.h"
- #include "logic.h"
- #include "vortex.h"
- static unsigned FramesPerSecond=0;
- #ifdef CHEAT_KEYS
- /***********************************************************************************************
- * LogicClass::Debug_Dump -- Displays logic class status to the mono screen. *
- * *
- * This is a debugging support routine. It displays the current state of the logic class *
- * to the monochrome monitor. It assumes that it is being called once per second. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: Call this routine only once per second. *
- * *
- * HISTORY: *
- * 05/31/1994 JLB : Created. *
- * 01/26/1996 JLB : Prints game time value. *
- *=============================================================================================*/
- void LogicClass::Debug_Dump(MonoClass * mono) const
- {
- #define RECORDCOUNT 40
- #define RECORDHEIGHT 21
- static int _framecounter = 0;
- static bool first = true;
- if (first) {
- first = false;
- mono->Set_Cursor(0, 0);
- mono->Print(Text_String(TXT_DEBUG_STRESS));
- }
- //mono->Set_Cursor(0,0);mono->Printf("%d", AllowVoice);
- _framecounter++;
- mono->Set_Cursor(1, 1);mono->Printf("%ld", (long)Scen.Timer);
- mono->Set_Cursor(10, 1);mono->Printf("%3d", FramesPerSecond);
- mono->Set_Cursor(1, 3);mono->Printf("%02d:%02d:%02d", Scen.Timer / TICKS_PER_HOUR, (Scen.Timer % TICKS_PER_HOUR)/TICKS_PER_MINUTE, (Scen.Timer % TICKS_PER_MINUTE)/TICKS_PER_SECOND);
- mono->Set_Cursor(1, 11);mono->Printf("%3d", Units.Count());
- mono->Set_Cursor(1, 12);mono->Printf("%3d", Infantry.Count());
- mono->Set_Cursor(1, 13);mono->Printf("%3d", Aircraft.Count());
- mono->Set_Cursor(1, 14);mono->Printf("%3d", Vessels.Count());
- mono->Set_Cursor(1, 15);mono->Printf("%3d", Buildings.Count());
- mono->Set_Cursor(1, 16);mono->Printf("%3d", Terrains.Count());
- mono->Set_Cursor(1, 17);mono->Printf("%3d", Bullets.Count());
- mono->Set_Cursor(1, 18);mono->Printf("%3d", Anims.Count());
- mono->Set_Cursor(1, 19);mono->Printf("%3d", Teams.Count());
- mono->Set_Cursor(1, 20);mono->Printf("%3d", Triggers.Count());
- mono->Set_Cursor(1, 21);mono->Printf("%3d", TriggerTypes.Count());
- mono->Set_Cursor(1, 22);mono->Printf("%3d", Factories.Count());
- SpareTicks = min((long)SpareTicks, (long)TIMER_SECOND);
- /*
- ** CPU utilization record.
- */
- mono->Sub_Window(15, 1, 6, 11);
- mono->Scroll();
- mono->Set_Cursor(0, 10);
- mono->Printf("%3d%%", ((TIMER_SECOND-SpareTicks)*100) / TIMER_SECOND);
- /*
- ** Update the frame rate log.
- */
- mono->Sub_Window(22, 1, 6, 11);
- mono->Scroll();
- mono->Set_Cursor(0, 10);
- mono->Printf("%4d", FramesPerSecond);
- /*
- ** Update the findpath calc record.
- */
- mono->Sub_Window(50, 1, 6, 11);
- mono->Scroll();
- mono->Set_Cursor(0, 10);
- mono->Printf("%4d", PathCount);
- PathCount = 0;
- /*
- ** Update the cell redraw record.
- */
- mono->Sub_Window(29, 1, 6, 11);
- mono->Scroll();
- mono->Set_Cursor(0, 10);
- mono->Printf("%5d", CellCount);
- CellCount = 0;
- /*
- ** Update the target scan record.
- */
- mono->Sub_Window(36, 1, 6, 11);
- mono->Scroll();
- mono->Set_Cursor(0, 10);
- mono->Printf("%5d", TargetScan);
- TargetScan = 0;
- /*
- ** Sidebar redraw record.
- */
- mono->Sub_Window(43, 1, 6, 11);
- mono->Scroll();
- mono->Set_Cursor(0, 10);
- mono->Printf("%5d", SidebarRedraws);
- SidebarRedraws = 0;
- /*
- ** Update the CPU utilization chart.
- */
- mono->Sub_Window(15, 13, 63, 10);
- mono->Pan(1);
- mono->Sub_Window(15, 13, 64, 10);
- int graph = RECORDHEIGHT * fixed(TIMER_SECOND-SpareTicks, TIMER_SECOND);
- for (int row = 1; row < RECORDHEIGHT; row += 2) {
- static char _barchar[4] = {' ', 220, 0, 219};
- char str[2];
- int index = 0;
- index |= (graph >= row) ? 0x01 : 0x00;
- index |= (graph >= row+1) ? 0x02: 0x00;
- str[1] = '\0';
- str[0] = _barchar[index];
- mono->Text_Print(str, 62, 9-(row/2));
- }
- mono->Sub_Window();
- SpareTicks = 0;
- FramesPerSecond = 0;
- }
- #endif
- /***********************************************************************************************
- * LogicClass::AI -- Handles AI logic processing for game objects. *
- * *
- * This routine is used to perform the AI processing for all game objects. This includes *
- * all houses, factories, objects, and teams. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/29/1994 JLB : Created. *
- * 12/17/1994 JLB : Must perform one complete pass rather than bailing early. *
- * 12/23/1994 JLB : Ensures that no object gets skipped if it was deleted. *
- *=============================================================================================*/
- void LogicClass::AI(void)
- {
- int index;
- FramesPerSecond++;
- /*
- ** Fading to B&W or color due to the chronosphere is handled here.
- */
- Scen.Do_Fade_AI();
- /*
- ** Handle any general timer trigger events.
- */
- for (LogicTriggerID = 0; LogicTriggerID < LogicTriggers.Count(); LogicTriggerID++) {
- TriggerClass * trig = LogicTriggers[LogicTriggerID];
- /*
- ** Global changed trigger event might be triggered.
- */
- if (Scen.IsGlobalChanged) {
- if (trig->Spring(TEVENT_GLOBAL_SET)) continue;
- if (trig->Spring(TEVENT_GLOBAL_CLEAR)) continue;
- }
- /*
- ** Bridge change event.
- */
- if (Scen.IsBridgeChanged) {
- if (trig->Spring(TEVENT_ALL_BRIDGES_DESTROYED)) continue;
- }
- /*
- ** General time expire trigger events can be sprung without warning.
- */
- if (trig->Spring(TEVENT_TIME)) continue;
- /*
- ** The mission timer expiration trigger event might spring if the timer is active
- ** but at a value of zero.
- */
- if (Scen.MissionTimer.Is_Active() && Scen.MissionTimer == 0) {
- if (trig->Spring(TEVENT_MISSION_TIMER_EXPIRED)) continue;
- }
- }
- if (Scen.MissionTimer.Is_Active()) {
- long secs = Scen.MissionTimer / TICKS_PER_SECOND;
- long mins = secs / 60;
- long hours = mins / 60;
- secs %= 60;
- mins %= 60;
- /*
- ** Speak mission timer reminders.
- */
- VoxType vox = VOX_NONE;
- if (Scen.MissionTimer == (1 * TICKS_PER_MINUTE)) vox = VOX_TIME_1;
- if (Scen.MissionTimer == (2 * TICKS_PER_MINUTE)) vox = VOX_TIME_2;
- if (Scen.MissionTimer == (3 * TICKS_PER_MINUTE)) vox = VOX_TIME_3;
- if (Scen.MissionTimer == (4 * TICKS_PER_MINUTE)) vox = VOX_TIME_4;
- if (Scen.MissionTimer == (5 * TICKS_PER_MINUTE)) vox = VOX_TIME_5;
- if (Scen.MissionTimer == (10 * TICKS_PER_MINUTE)) vox = VOX_TIME_10;
- if (Scen.MissionTimer == (20 * TICKS_PER_MINUTE)) vox = VOX_TIME_20;
- if (Scen.MissionTimer == (30 * TICKS_PER_MINUTE)) vox = VOX_TIME_30;
- if (Scen.MissionTimer == (40 * TICKS_PER_MINUTE)) vox = VOX_TIME_40;
- if (vox != VOX_NONE) {
- Speak(vox);
- Map.FlasherTimer = 7;
- }
- }
- /*
- ** Clean up any status values that were maintained only for logic trigger
- ** purposes.
- */
- if (Scen.MissionTimer.Is_Active() && Scen.MissionTimer == 0) {
- Scen.MissionTimer.Stop();
- Map.Flag_To_Redraw(true); // Used only to cause tabs to redraw in new state.
- }
- Scen.IsGlobalChanged = false;
- Scen.IsBridgeChanged = false;
- /*
- ** Shadow creeping back over time is handled here.
- */
- if (Special.IsShadowGrow && Rule.ShroudRate != 0 && Scen.ShroudTimer == 0) {
- Scen.ShroudTimer = TICKS_PER_MINUTE * Rule.ShroudRate;
-
- /*
- ** Do this for all players in Client/Server multiplayer. ST - 8/9/2019 10:23AM
- */
- if (Session.Type != GAME_GLYPHX_MULTIPLAYER) {
- Map.Encroach_Shadow(PlayerPtr);
- } else {
- for (int i=0 ; i<Session.Players.Count() ; i++) {
- HouseClass *player_ptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
- if (player_ptr && player_ptr->IsHuman) {
- Map.Encroach_Shadow(player_ptr);
- }
- }
- }
- }
- /*
- ** Team AI is processed.
- */
- for (index = 0; index < Teams.Count(); index++) {
- Teams.Ptr(index)->AI();
- }
- /*
- ** If there's a time quake, handle it here.
- */
- if (TimeQuake) {
- Sound_Effect(VOC_KABOOM15);
- Shake_The_Screen(8);
- }
- ChronalVortex.AI();
- /*
- ** AI for all sentient objects is processed.
- */
- for (index = 0; index < Count(); index++) {
- ObjectClass * obj = (*this)[index];
- int count = Count();
- BStart(BENCH_AI);
- obj->AI();
- BEnd(BENCH_AI);
- if (TimeQuake && obj != NULL && obj->IsActive && !obj->IsInLimbo && obj->Strength) {
- int damage = (int)obj->Class_Of().MaxStrength * Rule.QuakeDamagePercent;
- #ifdef FIXIT_CSII // checked - ajw 9/28/98
- if (TimeQuakeCenter) {
- if(::Distance(obj->As_Target(),TimeQuakeCenter)/256 < MTankDistance) {
- switch(obj->What_Am_I()) {
- case RTTI_INFANTRY:
- damage = QuakeInfantryDamage;
- break;
- case RTTI_BUILDING:
- damage = QuakeBuildingDamage * (int)obj->Class_Of().MaxStrength;
- break;
- default:
- damage = QuakeUnitDamage * (int)obj->Class_Of().MaxStrength;
- break;
- }
- if (damage) {
- obj->Clicked_As_Target(HOUSE_COUNT); // 2019/09/20 JAS - Added record of who clicked on the object, HOUSE_COUNT is used to mark for all houses
- new AnimClass(ANIM_MINE_EXP1, obj->Center_Coord());
- }
- obj->Take_Damage(damage, 0, WARHEAD_AP, 0, true);
- }
- } else {
- obj->Take_Damage(damage, 0, WARHEAD_AP, 0, true);
- }
- #else
- obj->Take_Damage(damage, 0, WARHEAD_AP, 0, true);
- #endif
- }
- /*
- ** If the object was destroyed in the process of performing its AI, then
- ** adjust the index so that no object gets skipped.
- */
- int count_diff = Count() - count;
- if (count_diff < 0) {
- index += count_diff;
- }
- }
- HouseClass::Recalc_Attributes();
- /*
- ** Map related logic is performed.
- */
- Map.Logic();
- /*
- ** Factory processing is performed.
- */
- for (index = 0; index < Factories.Count(); index++) {
- Factories.Ptr(index)->AI();
- }
- /*
- ** House processing is performed.
- */
- #ifdef FIXIT_VERSION_3
- if( Session.Type != GAME_NORMAL )
- {
- for (HousesType house = HOUSE_MULTI1; house < HOUSE_COUNT; house++) {
- HouseClass * hptr = HouseClass::As_Pointer(house);
- if (hptr && hptr->IsActive) {
- hptr->AI();
- }
- }
- }
- else
- {
- for (HousesType house = HOUSE_FIRST; house < HOUSE_COUNT; house++) {
- HouseClass * hptr = HouseClass::As_Pointer(house);
- if (hptr && hptr->IsActive) {
- hptr->AI();
- }
- }
- }
- #else // AI() is called redundantly 12 times in multiplayer games here. ajw
- for (HousesType house = HOUSE_FIRST; house < HOUSE_COUNT; house++) {
- HouseClass * hptr = HouseClass::As_Pointer(house);
- if (hptr && hptr->IsActive) {
- hptr->AI();
- }
- }
- #endif
- #ifdef FIXIT_VERSION_3 // For endgame auto-sonar pulse.
- if( Session.Type != GAME_NORMAL && Scen.AutoSonarTimer == 0 )
- {
- if( bAutoSonarPulse )
- {
- Map.Activate_Pulse();
- Sound_Effect(VOC_SONAR);
- bAutoSonarPulse = false;
- }
- #define AUTOSONAR_PERIOD TICKS_PER_SECOND * 40;
- Scen.AutoSonarTimer = AUTOSONAR_PERIOD;
- }
- #endif
- }
- /***********************************************************************************************
- * LogicClass::Detach -- Detatch the specified target from the logic system. *
- * *
- * This routine is called when the specified target object is about to be removed from the *
- * game system and all references to it must be severed. The only thing that the logic *
- * system looks for in this case is to see if the target refers to a trigger and if so, *
- * it scans through the trigger list and removes all references to it. *
- * *
- * INPUT: target -- The target to remove from the sytem. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 07/30/1996 JLB : Created. *
- *=============================================================================================*/
- void LogicClass::Detach(TARGET target, bool )
- {
- /*
- ** Remove any triggers from the logic trigger list.
- */
- if (Is_Target_Trigger(target)) {
- for (int index = 0; index < LogicTriggers.Count(); index++) {
- if (As_Trigger(target) == LogicTriggers[index]) {
- LogicTriggers.Delete(index);
- index--;
- }
- }
- }
- }
- /***********************************************************************************************
- * LogicClass::Clear_Recently_Created_Bits -- Clear out the indicators that objects were *
- * recently created *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 8/19/2019 5:47PM ST : Created. *
- *=============================================================================================*/
- void LogicClass::Clear_Recently_Created_Bits(void)
- {
- for (int index = 0; index < Count(); index++) {
- ObjectClass * obj = (*this)[index];
- obj->IsRecentlyCreated = false;
- }
- }
|