LOGIC.CPP 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /*
  2. ** Command & Conquer Red Alert(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: /CounterStrike/LOGIC.CPP 1 3/03/97 10:25a Joe_bostic $ */
  19. /***********************************************************************************************
  20. *** 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 ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Command & Conquer *
  24. * *
  25. * File Name : LOGIC.CPP *
  26. * *
  27. * Programmer : Joe L. Bostic *
  28. * *
  29. * Start Date : September 27, 1993 *
  30. * *
  31. * Last Update : July 30, 1996 [JLB] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * LogicClass::AI -- Handles AI logic processing for game objects. *
  36. * LogicClass::Debug_Dump -- Displays logic class status to the mono screen. *
  37. * LogicClass::Detach -- Detatch the specified target from the logic system. *
  38. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  39. #include "function.h"
  40. #include "logic.h"
  41. #include "vortex.h"
  42. static unsigned FramesPerSecond=0;
  43. #ifdef CHEAT_KEYS
  44. /***********************************************************************************************
  45. * LogicClass::Debug_Dump -- Displays logic class status to the mono screen. *
  46. * *
  47. * This is a debugging support routine. It displays the current state of the logic class *
  48. * to the monochrome monitor. It assumes that it is being called once per second. *
  49. * *
  50. * INPUT: none *
  51. * *
  52. * OUTPUT: none *
  53. * *
  54. * WARNINGS: Call this routine only once per second. *
  55. * *
  56. * HISTORY: *
  57. * 05/31/1994 JLB : Created. *
  58. * 01/26/1996 JLB : Prints game time value. *
  59. *=============================================================================================*/
  60. void LogicClass::Debug_Dump(MonoClass * mono) const
  61. {
  62. #define RECORDCOUNT 40
  63. #define RECORDHEIGHT 21
  64. static int _framecounter = 0;
  65. static bool first = true;
  66. if (first) {
  67. first = false;
  68. mono->Set_Cursor(0, 0);
  69. mono->Print(Text_String(TXT_DEBUG_STRESS));
  70. }
  71. //mono->Set_Cursor(0,0);mono->Printf("%d", AllowVoice);
  72. _framecounter++;
  73. mono->Set_Cursor(1, 1);mono->Printf("%ld", (long)Scen.Timer);
  74. mono->Set_Cursor(10, 1);mono->Printf("%3d", FramesPerSecond);
  75. 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);
  76. mono->Set_Cursor(1, 11);mono->Printf("%3d", Units.Count());
  77. mono->Set_Cursor(1, 12);mono->Printf("%3d", Infantry.Count());
  78. mono->Set_Cursor(1, 13);mono->Printf("%3d", Aircraft.Count());
  79. mono->Set_Cursor(1, 14);mono->Printf("%3d", Vessels.Count());
  80. mono->Set_Cursor(1, 15);mono->Printf("%3d", Buildings.Count());
  81. mono->Set_Cursor(1, 16);mono->Printf("%3d", Terrains.Count());
  82. mono->Set_Cursor(1, 17);mono->Printf("%3d", Bullets.Count());
  83. mono->Set_Cursor(1, 18);mono->Printf("%3d", Anims.Count());
  84. mono->Set_Cursor(1, 19);mono->Printf("%3d", Teams.Count());
  85. mono->Set_Cursor(1, 20);mono->Printf("%3d", Triggers.Count());
  86. mono->Set_Cursor(1, 21);mono->Printf("%3d", TriggerTypes.Count());
  87. mono->Set_Cursor(1, 22);mono->Printf("%3d", Factories.Count());
  88. SpareTicks = min((long)SpareTicks, (long)TIMER_SECOND);
  89. /*
  90. ** CPU utilization record.
  91. */
  92. mono->Sub_Window(15, 1, 6, 11);
  93. mono->Scroll();
  94. mono->Set_Cursor(0, 10);
  95. mono->Printf("%3d%%", ((TIMER_SECOND-SpareTicks)*100) / TIMER_SECOND);
  96. /*
  97. ** Update the frame rate log.
  98. */
  99. mono->Sub_Window(22, 1, 6, 11);
  100. mono->Scroll();
  101. mono->Set_Cursor(0, 10);
  102. mono->Printf("%4d", FramesPerSecond);
  103. /*
  104. ** Update the findpath calc record.
  105. */
  106. mono->Sub_Window(50, 1, 6, 11);
  107. mono->Scroll();
  108. mono->Set_Cursor(0, 10);
  109. mono->Printf("%4d", PathCount);
  110. PathCount = 0;
  111. /*
  112. ** Update the cell redraw record.
  113. */
  114. mono->Sub_Window(29, 1, 6, 11);
  115. mono->Scroll();
  116. mono->Set_Cursor(0, 10);
  117. mono->Printf("%5d", CellCount);
  118. CellCount = 0;
  119. /*
  120. ** Update the target scan record.
  121. */
  122. mono->Sub_Window(36, 1, 6, 11);
  123. mono->Scroll();
  124. mono->Set_Cursor(0, 10);
  125. mono->Printf("%5d", TargetScan);
  126. TargetScan = 0;
  127. /*
  128. ** Sidebar redraw record.
  129. */
  130. mono->Sub_Window(43, 1, 6, 11);
  131. mono->Scroll();
  132. mono->Set_Cursor(0, 10);
  133. mono->Printf("%5d", SidebarRedraws);
  134. SidebarRedraws = 0;
  135. /*
  136. ** Update the CPU utilization chart.
  137. */
  138. mono->Sub_Window(15, 13, 63, 10);
  139. mono->Pan(1);
  140. mono->Sub_Window(15, 13, 64, 10);
  141. int graph = RECORDHEIGHT * fixed(TIMER_SECOND-SpareTicks, TIMER_SECOND);
  142. for (int row = 1; row < RECORDHEIGHT; row += 2) {
  143. static char _barchar[4] = {' ', 220, 0, 219};
  144. char str[2];
  145. int index = 0;
  146. index |= (graph >= row) ? 0x01 : 0x00;
  147. index |= (graph >= row+1) ? 0x02: 0x00;
  148. str[1] = '\0';
  149. str[0] = _barchar[index];
  150. mono->Text_Print(str, 62, 9-(row/2));
  151. }
  152. mono->Sub_Window();
  153. SpareTicks = 0;
  154. FramesPerSecond = 0;
  155. }
  156. #endif
  157. /***********************************************************************************************
  158. * LogicClass::AI -- Handles AI logic processing for game objects. *
  159. * *
  160. * This routine is used to perform the AI processing for all game objects. This includes *
  161. * all houses, factories, objects, and teams. *
  162. * *
  163. * INPUT: none *
  164. * *
  165. * OUTPUT: none *
  166. * *
  167. * WARNINGS: none *
  168. * *
  169. * HISTORY: *
  170. * 05/29/1994 JLB : Created. *
  171. * 12/17/1994 JLB : Must perform one complete pass rather than bailing early. *
  172. * 12/23/1994 JLB : Ensures that no object gets skipped if it was deleted. *
  173. *=============================================================================================*/
  174. void LogicClass::AI(void)
  175. {
  176. int index;
  177. FramesPerSecond++;
  178. /*
  179. ** Fading to B&W or color due to the chronosphere is handled here.
  180. */
  181. Scen.Do_Fade_AI();
  182. /*
  183. ** Handle any general timer trigger events.
  184. */
  185. for (LogicTriggerID = 0; LogicTriggerID < LogicTriggers.Count(); LogicTriggerID++) {
  186. TriggerClass * trig = LogicTriggers[LogicTriggerID];
  187. /*
  188. ** Global changed trigger event might be triggered.
  189. */
  190. if (Scen.IsGlobalChanged) {
  191. if (trig->Spring(TEVENT_GLOBAL_SET)) continue;
  192. if (trig->Spring(TEVENT_GLOBAL_CLEAR)) continue;
  193. }
  194. /*
  195. ** Bridge change event.
  196. */
  197. if (Scen.IsBridgeChanged) {
  198. if (trig->Spring(TEVENT_ALL_BRIDGES_DESTROYED)) continue;
  199. }
  200. /*
  201. ** General time expire trigger events can be sprung without warning.
  202. */
  203. if (trig->Spring(TEVENT_TIME)) continue;
  204. /*
  205. ** The mission timer expiration trigger event might spring if the timer is active
  206. ** but at a value of zero.
  207. */
  208. if (Scen.MissionTimer.Is_Active() && Scen.MissionTimer == 0) {
  209. if (trig->Spring(TEVENT_MISSION_TIMER_EXPIRED)) continue;
  210. }
  211. }
  212. /*
  213. ** Clean up any status values that were maintained only for logic trigger
  214. ** purposes.
  215. */
  216. if (Scen.MissionTimer.Is_Active() && Scen.MissionTimer == 0) {
  217. Scen.MissionTimer.Stop();
  218. Map.Flag_To_Redraw(true); // Used only to cause tabs to redraw in new state.
  219. }
  220. Scen.IsGlobalChanged = false;
  221. Scen.IsBridgeChanged = false;
  222. /*
  223. ** Shadow creeping back over time is handled here.
  224. */
  225. if (Special.IsShadowGrow && Rule.ShroudRate != 0 && Scen.ShroudTimer == 0) {
  226. Scen.ShroudTimer = TICKS_PER_MINUTE * Rule.ShroudRate;
  227. Map.Encroach_Shadow();
  228. }
  229. /*
  230. ** Team AI is processed.
  231. */
  232. for (index = 0; index < Teams.Count(); index++) {
  233. Teams.Ptr(index)->AI();
  234. }
  235. /*
  236. ** If there's a time quake, handle it here.
  237. */
  238. if (TimeQuake) {
  239. Sound_Effect(VOC_KABOOM15);
  240. Shake_The_Screen(8);
  241. }
  242. ChronalVortex.AI();
  243. /*
  244. ** AI for all sentient objects is processed.
  245. */
  246. for (index = 0; index < Count(); index++) {
  247. ObjectClass * obj = (*this)[index];
  248. BStart(BENCH_AI);
  249. obj->AI();
  250. BEnd(BENCH_AI);
  251. if (TimeQuake && obj != NULL && obj->IsActive && !obj->IsInLimbo && obj->Strength) {
  252. int damage = obj->Class_Of().MaxStrength * Rule.QuakeDamagePercent;
  253. #ifdef FIXIT_CSII // checked - ajw 9/28/98
  254. if (TimeQuakeCenter) {
  255. if(::Distance(obj->As_Target(),TimeQuakeCenter)/256 < MTankDistance) {
  256. switch(obj->What_Am_I()) {
  257. case RTTI_INFANTRY:
  258. damage = QuakeInfantryDamage;
  259. break;
  260. case RTTI_BUILDING:
  261. damage = QuakeBuildingDamage * obj->Class_Of().MaxStrength;
  262. break;
  263. default:
  264. damage = QuakeUnitDamage * obj->Class_Of().MaxStrength;
  265. break;
  266. }
  267. if (damage) {
  268. obj->Clicked_As_Target();
  269. new AnimClass(ANIM_MINE_EXP1, obj->Center_Coord());
  270. }
  271. obj->Take_Damage(damage, 0, WARHEAD_AP, 0, true);
  272. }
  273. } else {
  274. obj->Take_Damage(damage, 0, WARHEAD_AP, 0, true);
  275. }
  276. #else
  277. obj->Take_Damage(damage, 0, WARHEAD_AP, 0, true);
  278. #endif
  279. }
  280. /*
  281. ** If the object was destroyed in the process of performing its AI, then
  282. ** adjust the index so that no object gets skipped.
  283. */
  284. if (obj != (*this)[index]) {
  285. index--;
  286. }
  287. }
  288. HouseClass::Recalc_Attributes();
  289. /*
  290. ** Map related logic is performed.
  291. */
  292. Map.Logic();
  293. /*
  294. ** Factory processing is performed.
  295. */
  296. for (index = 0; index < Factories.Count(); index++) {
  297. Factories.Ptr(index)->AI();
  298. }
  299. /*
  300. ** House processing is performed.
  301. */
  302. #ifdef FIXIT_VERSION_3
  303. if( Session.Type != GAME_NORMAL )
  304. {
  305. for (HousesType house = HOUSE_MULTI1; house < HOUSE_COUNT; house++) {
  306. HouseClass * hptr = HouseClass::As_Pointer(house);
  307. if (hptr && hptr->IsActive) {
  308. hptr->AI();
  309. }
  310. }
  311. }
  312. else
  313. {
  314. for (HousesType house = HOUSE_FIRST; house < HOUSE_COUNT; house++) {
  315. HouseClass * hptr = HouseClass::As_Pointer(house);
  316. if (hptr && hptr->IsActive) {
  317. hptr->AI();
  318. }
  319. }
  320. }
  321. #else // AI() is called redundantly 12 times in multiplayer games here. ajw
  322. for (HousesType house = HOUSE_FIRST; house < HOUSE_COUNT; house++) {
  323. HouseClass * hptr = HouseClass::As_Pointer(house);
  324. if (hptr && hptr->IsActive) {
  325. hptr->AI();
  326. }
  327. }
  328. #endif
  329. #ifdef FIXIT_VERSION_3 // For endgame auto-sonar pulse.
  330. if( Session.Type != GAME_NORMAL && Scen.AutoSonarTimer == 0 )
  331. {
  332. if( bAutoSonarPulse )
  333. {
  334. Map.Activate_Pulse();
  335. Sound_Effect(VOC_SONAR);
  336. bAutoSonarPulse = false;
  337. }
  338. #define AUTOSONAR_PERIOD TICKS_PER_SECOND * 40;
  339. Scen.AutoSonarTimer = AUTOSONAR_PERIOD;
  340. }
  341. #endif
  342. }
  343. /***********************************************************************************************
  344. * LogicClass::Detach -- Detatch the specified target from the logic system. *
  345. * *
  346. * This routine is called when the specified target object is about to be removed from the *
  347. * game system and all references to it must be severed. The only thing that the logic *
  348. * system looks for in this case is to see if the target refers to a trigger and if so, *
  349. * it scans through the trigger list and removes all references to it. *
  350. * *
  351. * INPUT: target -- The target to remove from the sytem. *
  352. * *
  353. * OUTPUT: none *
  354. * *
  355. * WARNINGS: none *
  356. * *
  357. * HISTORY: *
  358. * 07/30/1996 JLB : Created. *
  359. *=============================================================================================*/
  360. void LogicClass::Detach(TARGET target, bool )
  361. {
  362. /*
  363. ** Remove any triggers from the logic trigger list.
  364. */
  365. if (Is_Target_Trigger(target)) {
  366. for (int index = 0; index < LogicTriggers.Count(); index++) {
  367. if (As_Trigger(target) == LogicTriggers[index]) {
  368. LogicTriggers.Delete(index);
  369. index--;
  370. }
  371. }
  372. }
  373. }