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