DEBUG.CPP 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. //
  2. // Copyright 2020 Electronic Arts Inc.
  3. //
  4. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
  5. // software: you can redistribute it and/or modify it under the terms of
  6. // the GNU General Public License as published by the Free Software Foundation,
  7. // either version 3 of the License, or (at your option) any later version.
  8. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. /* $Header: /CounterStrike/DEBUG.CPP 1 3/03/97 10:24a Joe_bostic $ */
  15. /***********************************************************************************************
  16. *** 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 ***
  17. ***********************************************************************************************
  18. * *
  19. * Project Name : Command & Conquer *
  20. * *
  21. * File Name : DEBUG.CPP *
  22. * *
  23. * Programmer : Joe L. Bostic *
  24. * *
  25. * Start Date : September 10, 1993 *
  26. * *
  27. * Last Update : July 18, 1996 [JLB] *
  28. * *
  29. *---------------------------------------------------------------------------------------------*
  30. * Functions: *
  31. * Self_Regulate -- Regulates the logic timer to result in smooth animation. *
  32. * Debug_Key -- Debug mode keyboard processing. *
  33. * Bench_Time -- Convert benchmark timer into descriptive string. *
  34. * Benchmarks -- Display the performance tracking benchmarks. *
  35. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  36. #include "function.h"
  37. #include "vortex.h"
  38. #include <stdarg.h>
  39. #ifdef CHEAT_KEYS
  40. static CDTimerClass<SystemTimerClass> DebugTimer;
  41. int VortexFrame = -1;
  42. /***********************************************************************************************
  43. * Debug_Key -- Debug mode keyboard processing. *
  44. * *
  45. * If debugging is enabled, then this routine will be called for every keystroke that the *
  46. * game doesn't recognize. These extra keys usually perform some debugging function. *
  47. * *
  48. * INPUT: input -- The key code that was pressed. *
  49. * *
  50. * OUTPUT: none *
  51. * *
  52. * WARNINGS: none *
  53. * *
  54. * HISTORY: *
  55. * 10/07/1992 JLB : Created. *
  56. *=============================================================================================*/
  57. void Debug_Key(unsigned input)
  58. {
  59. static int map_x = -1;
  60. static int map_y = -1;
  61. static int map_width = -1;
  62. static int map_height = -1;
  63. if (!input || input & KN_BUTTON) return;
  64. /*
  65. ** Processing of normal keystrokes.
  66. */
  67. if (Debug_Flag) {
  68. switch (input) {
  69. case KN_BACKSPACE:
  70. if (ChronalVortex.Is_Active()) {
  71. ChronalVortex.Disappear();
  72. } else {
  73. int xxxx = Get_Mouse_X() + Map.TacPixelX;
  74. int yyyy = Get_Mouse_Y() + Map.TacPixelY;
  75. CELL cell = Map.DisplayClass::Click_Cell_Calc(xxxx,yyyy);
  76. ChronalVortex.Appear ( Cell_Coord (cell) );
  77. }
  78. break;
  79. #ifdef WIN32
  80. case KN_J:
  81. Debug_MotionCapture = true;
  82. break;
  83. #ifdef OBSOLETE
  84. case KN_K:
  85. /*
  86. ** time to create a screen shot using the PCX code (if it works)
  87. */
  88. if (!Debug_MotionCapture) {
  89. GraphicBufferClass temp_page( SeenBuff.Get_Width(),
  90. SeenBuff.Get_Height(),
  91. NULL,
  92. SeenBuff.Get_Width() * SeenBuff.Get_Height());
  93. CDFileClass file;
  94. char filename[30];
  95. SeenBuff.Blit(temp_page);
  96. for (int lp = 0; lp < 99; lp ++) {
  97. sprintf(filename, "scrsht%02d.pcx", lp);
  98. file.Set_Name(filename);
  99. if (!file.Is_Available()) break;
  100. }
  101. file.Cache(200000);
  102. Write_PCX_File(file, temp_page, & GamePalette);
  103. Sound_Effect(VOC_BEEP);
  104. }
  105. break;
  106. #endif
  107. #endif
  108. case KN_P:
  109. {
  110. for (SpecialWeaponType spc = SPC_FIRST; spc < SPC_COUNT; spc++) {
  111. PlayerPtr->SuperWeapon[spc].Enable(true, true);
  112. PlayerPtr->SuperWeapon[spc].Forced_Charge(true);
  113. Map.Add(RTTI_SPECIAL, spc);
  114. Map.Column[1].Flag_To_Redraw();
  115. }
  116. }
  117. break;
  118. case KN_I:
  119. {
  120. Map.Flash_Power();
  121. Map.Flash_Money();
  122. }
  123. break;
  124. case KN_O:
  125. {
  126. AircraftClass * air = new AircraftClass(AIRCRAFT_HIND, PlayerPtr->Class->House);
  127. if (air) {
  128. air->Height = 0;
  129. air->Unlimbo(Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()), DIR_N);
  130. }
  131. }
  132. break;
  133. case KN_B:
  134. {
  135. AircraftClass * air = new AircraftClass(AIRCRAFT_LONGBOW, PlayerPtr->Class->House);
  136. if (air) {
  137. air->Height = 0;
  138. air->Unlimbo(Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()), DIR_N);
  139. }
  140. }
  141. break;
  142. case KN_GRAVE:
  143. {
  144. WarheadType warhead = Random_Pick(WARHEAD_HE, WARHEAD_FIRE);
  145. COORDINATE coord = Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y());
  146. int damage = 1000;
  147. new AnimClass(Combat_Anim(damage, warhead, Map[coord].Land_Type()), coord);
  148. Explosion_Damage(coord, damage, NULL, warhead);
  149. }
  150. break;
  151. case KN_C:
  152. Debug_Cheat = (Debug_Cheat == false);
  153. PlayerPtr->IsRecalcNeeded = true;
  154. /*
  155. ** This placement might affect any prerequisite requirements for construction
  156. ** lists. Update the buildable options accordingly.
  157. */
  158. if (!ScenarioInit) {
  159. Map.Recalc();
  160. for (int index = 0; index < Buildings.Count(); index++) {
  161. Buildings.Ptr(index)->Update_Buildables();
  162. }
  163. }
  164. break;
  165. case (int)KN_Z|(int)KN_ALT_BIT:
  166. if (map_x == -1) {
  167. map_x = Map.MapCellX;
  168. map_y = Map.MapCellY;
  169. map_width = Map.MapCellWidth;
  170. map_height = Map.MapCellHeight;
  171. Map.MapCellX = 1;
  172. Map.MapCellY = 1;
  173. Map.MapCellWidth = MAP_CELL_W-2;
  174. Map.MapCellHeight = MAP_CELL_H-2;
  175. } else {
  176. Map.MapCellX = map_x;
  177. Map.MapCellY = map_y;
  178. Map.MapCellWidth = map_width;
  179. Map.MapCellHeight = map_height;
  180. map_x = -1;
  181. map_y = -1;
  182. map_width = -1;
  183. map_height = -1;
  184. }
  185. break;
  186. case KN_M:
  187. if (Debug_Flag) {
  188. if (MonoClass::Is_Enabled()) {
  189. MonoClass::Disable();
  190. } else {
  191. MonoClass::Enable();
  192. }
  193. }
  194. break;
  195. case (int)KN_W|(int)KN_ALT_BIT:
  196. PlayerPtr->Flag_To_Win();
  197. break;
  198. case (int)KN_L|(int)KN_ALT_BIT:
  199. PlayerPtr->Flag_To_Lose();
  200. break;
  201. case KN_DELETE:
  202. if (CurrentObject.Count()) {
  203. Map.Recalc();
  204. //CurrentObject[0]->Detach_All();
  205. if (CurrentObject[0]->What_Am_I() == RTTI_BUILDING) {
  206. ((BuildingClass *)CurrentObject[0])->Sell_Back(1);
  207. } else {
  208. ObjectClass * object = CurrentObject[0];
  209. object->Unselect();
  210. object->Limbo();
  211. delete object;
  212. }
  213. }
  214. break;
  215. case (int)KN_DELETE|(int)KN_SHIFT_BIT:
  216. if (CurrentObject.Count()) {
  217. Map.Recalc();
  218. int damage = 50;
  219. CurrentObject[0]->Take_Damage(damage, 0, WARHEAD_SA);
  220. }
  221. break;
  222. case KN_INSERT:
  223. if (CurrentObject.Count()) {
  224. Map.PendingObject = &CurrentObject[0]->Class_Of();
  225. if (Map.PendingObject) {
  226. Map.PendingHouse = CurrentObject[0]->Owner();
  227. Map.PendingObjectPtr = Map.PendingObject->Create_One_Of(HouseClass::As_Pointer(Map.PendingHouse));
  228. if (Map.PendingObjectPtr) {
  229. Map.Set_Cursor_Pos();
  230. Map.Set_Cursor_Shape(Map.PendingObject->Occupy_List());
  231. }
  232. }
  233. }
  234. break;
  235. case KN_LBRACKET:
  236. case KN_F11:
  237. if (MonoPage == DMONO_FIRST) {
  238. MonoPage = DMonoType(DMONO_COUNT-1);
  239. } else {
  240. MonoPage = DMonoType(MonoPage - 1);
  241. }
  242. DebugTimer = 0;
  243. break;
  244. case KN_RBRACKET:
  245. case KN_F12:
  246. MonoPage = DMonoType(MonoPage + 1);
  247. if (MonoPage == DMONO_COUNT) {
  248. MonoPage = DMONO_FIRST;
  249. }
  250. DebugTimer = 0;
  251. break;
  252. case KN_V:
  253. case KN_F3:
  254. Debug_Icon = (Debug_Icon == false);
  255. Map.Flag_To_Redraw(true);
  256. break;
  257. /*
  258. ** Reveal entire map to player.
  259. */
  260. // case KN_F4:
  261. // if (Session.Type == GAME_NORMAL) {
  262. // Debug_Unshroud = (Debug_Unshroud == false);
  263. // Map.Flag_To_Redraw(true);
  264. // }
  265. // break;
  266. /*
  267. ** Shows sight and fire range in the form of circles emanating from the currently
  268. ** selected unit. The white circle is for sight range, the red circle is for
  269. ** fire range.
  270. */
  271. case KN_F7:
  272. if (CurrentObject.Count() && CurrentObject[0]->Is_Techno()) {
  273. TechnoTypeClass const & ttype = (TechnoTypeClass const &)CurrentObject[0]->Class_Of();
  274. int sight = ((int)ttype.SightRange)<<8;
  275. int weapon = 0;
  276. if (ttype.PrimaryWeapon != NULL) weapon = ttype.PrimaryWeapon->Range;
  277. Set_Logic_Page(SeenBuff);
  278. COORDINATE center = CurrentObject[0]->Center_Coord();
  279. COORDINATE center2 = CurrentObject[0]->Fire_Coord(0);
  280. for (int r = 0; r < 255; r += 10) {
  281. int x,y,x1,y1;
  282. DirType r1 = (DirType)r;
  283. DirType r2 = (DirType)((r+10) & 0xFF);
  284. if (Map.Coord_To_Pixel(Coord_Move(center, r1, sight), x, y)) {
  285. Map.Coord_To_Pixel(Coord_Move(center, r2, sight), x1, y1);
  286. LogicPage->Draw_Line(x, y+8, x1, y1+8, WHITE);
  287. }
  288. if (Map.Coord_To_Pixel(Coord_Move(center2, r1, weapon), x, y)) {
  289. Map.Coord_To_Pixel(Coord_Move(center2, r2, weapon), x1, y1);
  290. LogicPage->Draw_Line(x, y+8, x1, y1+8, RED);
  291. }
  292. }
  293. }
  294. break;
  295. case ((int)KN_F4 | (int)KN_CTRL_BIT):
  296. Debug_Unshroud = (Debug_Unshroud == false);
  297. Map.Flag_To_Redraw(true);
  298. break;
  299. default:
  300. break;
  301. }
  302. }
  303. }
  304. /***********************************************************************************************
  305. * Bench_Time -- Convert benchmark timer into descriptive string. *
  306. * *
  307. * This routine will take the values of the benchmark timer specified and build a string *
  308. * that displays the average time each event consumed as well as the ranking of how much *
  309. * time that event took (total) during the tracking duration (one second?). *
  310. * *
  311. * INPUT: btype -- The benchmark to convert to a descriptive string. *
  312. * *
  313. * OUTPUT: Returns with a pointer to the descriptive string of the benchmark specified. *
  314. * *
  315. * WARNINGS: The value returned is a pointer to a static buffer. As such, it is only valid *
  316. * until the next time that this routine is called. *
  317. * *
  318. * HISTORY: *
  319. * 07/18/1996 JLB : Created. *
  320. *=============================================================================================*/
  321. static char const * Bench_Time(BenchType btype)
  322. {
  323. static char buffer[32];
  324. int rootcount = Benches[BENCH_GAME_FRAME].Count();
  325. if (rootcount == 0) rootcount = 1;
  326. int roottime = Benches[BENCH_GAME_FRAME].Value();
  327. int count = Benches[btype].Count();
  328. int time = Benches[btype].Value();
  329. if (count > 0 && count * time > roottime * rootcount) time = roottime / count;
  330. int percent = 0;
  331. if (roottime != 0 && rootcount != 0) {
  332. percent = ((count * time) * 99) / (roottime * rootcount);
  333. }
  334. if (percent > 99) percent = 99;
  335. sprintf(buffer, "%-2d%% %7d", percent, time);
  336. return(buffer);
  337. }
  338. /***********************************************************************************************
  339. * Benchmarks -- Display the performance tracking benchmarks. *
  340. * *
  341. * This will display the benchmarks for the various processes that are being tracked. The *
  342. * display will indicate the fraction that each process is consuming out of the entire *
  343. * process time as well as the time consumed by each individual event. The total fraction *
  344. * is useful for determing what should be optimized. The individual time is useful for *
  345. * guaging the effectiveness of optimization changes. *
  346. * *
  347. * INPUT: mono -- Pointer to the monochrome screen that the display will use. *
  348. * *
  349. * OUTPUT: none *
  350. * *
  351. * WARNINGS: none *
  352. * *
  353. * HISTORY: *
  354. * 07/18/1996 JLB : Created. *
  355. *=============================================================================================*/
  356. static void Benchmarks(MonoClass * mono)
  357. {
  358. static bool _first = true;
  359. if (_first) {
  360. _first = false;
  361. mono->Clear();
  362. mono->Set_Cursor(0, 0);
  363. mono->Print(Text_String(TXT_DEBUG_PERFORMANCE));
  364. if (Benches == NULL) {
  365. mono->Set_Cursor(20, 15);
  366. mono->Printf(TXT_NO_PENTIUM);
  367. }
  368. }
  369. if (Benches != NULL) {
  370. mono->Set_Cursor(1, 2);mono->Printf("%s", Bench_Time(BENCH_FINDPATH));
  371. mono->Set_Cursor(1, 4);mono->Printf("%s", Bench_Time(BENCH_GREATEST_THREAT));
  372. mono->Set_Cursor(1, 6);mono->Printf("%s", Bench_Time(BENCH_AI));
  373. mono->Set_Cursor(1, 8);mono->Printf("%s", Bench_Time(BENCH_PCP));
  374. mono->Set_Cursor(1, 10);mono->Printf("%s", Bench_Time(BENCH_EVAL_OBJECT));
  375. mono->Set_Cursor(1, 12);mono->Printf("%s", Bench_Time(BENCH_EVAL_CELL));
  376. mono->Set_Cursor(1, 14);mono->Printf("%s", Bench_Time(BENCH_EVAL_WALL));
  377. mono->Set_Cursor(1, 16);mono->Printf("%s", Bench_Time(BENCH_MISSION));
  378. mono->Set_Cursor(14, 2);mono->Printf("%s", Bench_Time(BENCH_CELL));
  379. mono->Set_Cursor(14, 4);mono->Printf("%s", Bench_Time(BENCH_OBJECTS));
  380. mono->Set_Cursor(14, 6);mono->Printf("%s", Bench_Time(BENCH_ANIMS));
  381. mono->Set_Cursor(27, 2);mono->Printf("%s", Bench_Time(BENCH_PALETTE));
  382. mono->Set_Cursor(40, 2);mono->Printf("%s", Bench_Time(BENCH_GSCREEN_RENDER));
  383. mono->Set_Cursor(40, 4);mono->Printf("%s", Bench_Time(BENCH_SIDEBAR));
  384. mono->Set_Cursor(40, 6);mono->Printf("%s", Bench_Time(BENCH_RADAR));
  385. mono->Set_Cursor(40, 8);mono->Printf("%s", Bench_Time(BENCH_TACTICAL));
  386. mono->Set_Cursor(40, 10);mono->Printf("%s", Bench_Time(BENCH_POWER));
  387. mono->Set_Cursor(40, 12);mono->Printf("%s", Bench_Time(BENCH_SHROUD));
  388. mono->Set_Cursor(40, 14);mono->Printf("%s", Bench_Time(BENCH_TABS));
  389. mono->Set_Cursor(40, 16);mono->Printf("%s", Bench_Time(BENCH_BLIT_DISPLAY));
  390. mono->Set_Cursor(66, 2);mono->Printf("%7d", Benches[BENCH_RULES].Value());
  391. mono->Set_Cursor(66, 4);mono->Printf("%7d", Benches[BENCH_SCENARIO].Value());
  392. for (BenchType index = BENCH_FIRST; index < BENCH_COUNT; index++) {
  393. if (index != BENCH_RULES && index != BENCH_SCENARIO) Benches[index].Reset();
  394. }
  395. }
  396. }
  397. /***********************************************************************************************
  398. * Self_Regulate -- Regulates the logic timer to result in smooth animation *
  399. * *
  400. * The self regulation process checks the number of frames displayed *
  401. * per second and from this determines the amount of time to devote *
  402. * to internal logic processing. By adjusting the time allotted to *
  403. * internal processing, smooth animation can be maintained. *
  404. * *
  405. * INPUT: none *
  406. * *
  407. * OUTPUT: none *
  408. * *
  409. * WARNINGS: In order for this routine to work properly it MUST be *
  410. * called every display loop. *
  411. * *
  412. * HISTORY: *
  413. * 07/31/1991 JLB : Created. *
  414. * 07/05/1994 JLB : Handles new monochrome system. *
  415. *=============================================================================================*/
  416. #define UPDATE_INTERVAL TIMER_SECOND
  417. void Self_Regulate(void)
  418. {
  419. static ObjectClass * _lastobject = 0;
  420. static bool _first=true;
  421. if (DebugTimer == 0) {
  422. DebugTimer = UPDATE_INTERVAL;
  423. if (MonoClass::Is_Enabled()) {
  424. if (_first) {
  425. _first = false;
  426. for (DMonoType index = DMONO_FIRST; index < DMONO_COUNT; index++) {
  427. MonoArray[index].Clear();
  428. }
  429. }
  430. /*
  431. ** Always update the stress tracking mono display even if it
  432. ** currently isn't visible.
  433. */
  434. Logic.Debug_Dump(&MonoArray[DMONO_STRESS]);
  435. MonoClass * mono = &MonoArray[MonoPage];
  436. mono->Set_Default_Attribute(MonoClass::NORMAL);
  437. mono->View();
  438. switch (MonoPage) {
  439. case DMONO_EVENTS:
  440. Benchmarks(mono);
  441. break;
  442. case DMONO_OBJECT:
  443. mono->Clear();
  444. /*
  445. ** Display the status of the currently selected object.
  446. */
  447. if (CurrentObject.Count()) {
  448. _lastobject = CurrentObject[0];
  449. }
  450. if (_lastobject && !_lastobject->IsActive) {
  451. _lastobject = 0;
  452. }
  453. if (_lastobject) {
  454. _lastobject->Debug_Dump(mono);
  455. }
  456. break;
  457. case DMONO_STRESS:
  458. #ifdef OBSOLETE
  459. mono->Set_Cursor(0, 20);
  460. mono->Printf(
  461. "Heap size:%10ld \r"
  462. "Largest: %10ld \r"
  463. "Ttl Free: %10ld \r"
  464. "Frag: %10ld \r",
  465. Heap_Size(MEM_NORMAL),
  466. Ram_Free(MEM_NORMAL),
  467. Total_Ram_Free(MEM_NORMAL),
  468. Total_Ram_Free(MEM_NORMAL)-Ram_Free(MEM_NORMAL)
  469. );
  470. #endif
  471. break;
  472. case DMONO_HOUSE:
  473. mono->Clear();
  474. if (CurrentObject.Count()) {
  475. _lastobject = CurrentObject[0];
  476. }
  477. if (_lastobject && !_lastobject->IsActive) {
  478. _lastobject = 0;
  479. }
  480. if (_lastobject && _lastobject->Is_Techno()) {
  481. ((TechnoClass *)_lastobject)->House->Debug_Dump(mono);
  482. }
  483. break;
  484. default:
  485. break;
  486. }
  487. mono->Set_Cursor(0, 0);
  488. }
  489. }
  490. }
  491. #endif