CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

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