CnC_Remastered_Collection

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

DEBUG.CPP (20828B)


      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:   F:\projects\c&c\vcs\code\debug.cpv   2.17   16 Oct 1995 16:49:18   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 5, 1994   [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  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     36 
     37 #include "function.h"
     38 #include	<stdarg.h>
     39 #include <filepcx.h>
     40 #include <io.h>
     41 #ifdef CHEAT_KEYS
     42 
     43 extern bool ScreenRecording;
     44 
     45 /***********************************************************************************************
     46  * Debug_Key -- Debug mode keyboard processing.                                                *
     47  *                                                                                             *
     48  *    If debugging is enabled, then this routine will be called for every keystroke that the   *
     49  *    game doesn't recognize. These extra keys usually perform some debugging function.        *
     50  *                                                                                             *
     51  * INPUT:   input -- The key code that was pressed.                                            *
     52  *                                                                                             *
     53  * OUTPUT:  none                                                                               *
     54  *                                                                                             *
     55  * WARNINGS:   none                                                                            *
     56  *                                                                                             *
     57  * HISTORY:                                                                                    *
     58  *   10/07/1992 JLB : Created.                                                                 *
     59  *=============================================================================================*/
     60 void Debug_Key(unsigned input)
     61 {
     62 	static int map_x = -1;
     63 	static int map_y = -1;
     64 	static int map_width = -1;
     65 	static int map_height = -1;
     66 
     67 	if (!input || input & KN_BUTTON) return;
     68 
     69 	/*
     70 	**	Processing of normal keystrokes.
     71 	*/
     72 	if (Debug_Flag) {
     73 
     74 		switch (input) {
     75 
     76 			case KN_L:
     77 				extern int NetMonoMode,NewMonoMode;
     78 				if (NetMonoMode)
     79 					NetMonoMode = 0;
     80 				else
     81 					NetMonoMode = 1;
     82 				NewMonoMode = 1;
     83 				break;
     84 
     85 			/*
     86 			** Start saving off screens
     87 			*/
     88 			case (int)KN_K|(int)KN_CTRL_BIT:
     89 				ScreenRecording = true;
     90 				break;
     91 
     92 			case KN_K:
     93 //PG_TO_FIX
     94 #if (0)
     95 				/*
     96 				** time to create a screen shot using the PCX code (if it works)
     97 				*/
     98 				{
     99 					GraphicBufferClass temp_page(	SeenBuff.Get_Width(),
    100 															SeenBuff.Get_Height(),
    101 															NULL,
    102 															SeenBuff.Get_Width() * SeenBuff.Get_Height());
    103 					char filename[30];
    104 
    105 					SeenBuff.Blit(temp_page);
    106 					for (int lp = 0; lp < 99; lp ++) {
    107 						if (lp < 10) {
    108 							sprintf(filename, "scrsht0%d.pcx", lp);
    109 						} else {
    110 							sprintf(filename, "scrsht%d.pcx", lp);
    111 						}
    112 						if (access(filename, F_OK) == -1)
    113 							break;
    114 					}
    115 
    116 					Write_PCX_File(filename, temp_page, (unsigned char *)CurrentPalette);
    117 					//Map.Place_Random_Crate();
    118 				}
    119 #endif
    120 				break;
    121 
    122 			case KN_P:
    123 				Keyboard::Clear();
    124 				while (!Keyboard::Check()) {
    125 					Self_Regulate();
    126 					Sound_Callback();
    127 				}
    128 				Keyboard::Clear();
    129 				break;
    130 
    131 			case KN_O:
    132 				{
    133 					AircraftClass * air = new AircraftClass(AIRCRAFT_ORCA, PlayerPtr->Class->House);
    134 					if (air) {
    135 						air->Altitude = 0;
    136 						air->Unlimbo(Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()), DIR_N);
    137 					}
    138 				}
    139 				break;
    140 
    141 			case (int)KN_B|(int)KN_ALT_BIT:
    142 				{
    143 					Debug_Instant_Build ^= 1;
    144 				}
    145 				break;
    146 			case KN_B:
    147 				{
    148 					AircraftClass * air = new AircraftClass(AIRCRAFT_HELICOPTER, PlayerPtr->Class->House);
    149 					if (air) {
    150 						air->Altitude = 0;
    151 						air->Unlimbo(Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()), DIR_N);
    152 					}
    153 				}
    154 				break;
    155 
    156 			case KN_T:
    157 				{
    158 					AircraftClass * air = new AircraftClass(AIRCRAFT_TRANSPORT, PlayerPtr->Class->House);
    159 					if (air) {
    160 						air->Altitude = 0;
    161 						air->Unlimbo(Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()), DIR_N);
    162 					}
    163 				}
    164 				break;
    165 
    166 			case KN_GRAVE:
    167 				new AnimClass(ANIM_ART_EXP1, Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()));
    168 				Explosion_Damage(Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()), 250, NULL, WARHEAD_HE);
    169 				break;
    170 
    171 			case KN_Z:
    172 //				new AnimClass(ANIM_LZ_SMOKE, Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()));
    173 				GDI_Ending();
    174 				break;
    175 
    176 			case KN_C:
    177 				Debug_Cheat = (Debug_Cheat == false);
    178 				PlayerPtr->IsRecalcNeeded = true;
    179 				PlayerPtr->Add_Nuke_Piece();
    180 				PlayerPtr->Add_Nuke_Piece();
    181 				PlayerPtr->Add_Nuke_Piece();
    182 
    183 				/*
    184 				**	This placement might affect any prerequisite requirements for construction
    185 				**	lists. Update the buildable options accordingly.
    186 				*/
    187 				if (!ScenarioInit) {
    188 					Map.Recalc();
    189 					for (int index = 0; index < Buildings.Count(); index++) {
    190 						Buildings.Ptr(index)->Update_Buildables();
    191 					}
    192 				}
    193 				break;
    194 
    195 			case (int)KN_Z|(int)KN_ALT_BIT:
    196 				if (map_x == -1) {
    197 					map_x = Map.MapCellX;
    198 					map_y = Map.MapCellY;
    199 					map_width = Map.MapCellWidth;
    200 					map_height = Map.MapCellHeight;
    201 					Map.MapCellX = 1;
    202 					Map.MapCellY = 1;
    203 					Map.MapCellWidth = 62;
    204 					Map.MapCellHeight = 62;
    205 				} else {
    206 					Map.MapCellX = map_x;
    207 					Map.MapCellY = map_y;
    208 					Map.MapCellWidth = map_width;
    209 					Map.MapCellHeight = map_height;
    210 					map_x = -1;
    211 					map_y = -1;
    212 					map_width = -1;
    213 					map_height = -1;
    214 				}
    215 				break;
    216 
    217 #ifdef NEVER
    218 			case KN_G:
    219 				HouseClass::As_Pointer(HOUSE_GOOD)->Flag_Attach(Map.Click_Cell_Calc(Get_Mouse_X(), Get_Mouse_Y()));
    220 				break;
    221 
    222 			case KN_N:
    223 				HouseClass::As_Pointer(HOUSE_BAD)->Flag_Attach(Map.Click_Cell_Calc(Get_Mouse_X(), Get_Mouse_Y()));
    224 				break;
    225 #endif
    226 
    227 			case KN_R:
    228 				if (CurrentObject.Count()) {
    229 					((TechnoClass *)CurrentObject[0])->IsCloakable = true;
    230 				}
    231 				break;
    232 
    233 			case KN_M:
    234 				if (Debug_Flag) {
    235 					if (MonoClass::Is_Enabled()) {
    236 						MonoClass::Disable();
    237 					} else {
    238 						MonoClass::Enable();
    239 					}
    240 				}
    241 				break;
    242 
    243 			case (int)KN_W|(int)KN_ALT_BIT:
    244 				PlayerPtr->Flag_To_Win();
    245 				break;
    246 
    247 			case (int)KN_L|(int)KN_ALT_BIT:
    248 				PlayerPtr->Flag_To_Lose();
    249 				break;
    250 
    251 			case KN_F:
    252 				Debug_Find_Path ^= 1;
    253 				break;
    254 
    255 			case KN_DELETE:
    256 				if (CurrentObject.Count()) {
    257 					Map.Recalc();
    258 					//CurrentObject[0]->Detach_All();
    259 					delete CurrentObject[0];
    260 				}
    261 				break;
    262 
    263 			case KN_D:
    264 				if (Teams.Ptr(0)) {
    265 					delete Teams.Ptr(0);
    266 				}
    267 				break;
    268 
    269 			case (int)KN_DELETE|(int)KN_SHIFT_BIT:
    270 				if (CurrentObject.Count()) {
    271 					Map.Recalc();
    272 					int damage = 50;
    273 					CurrentObject[0]->Take_Damage(damage, 0, WARHEAD_SA);
    274 				}
    275 				break;
    276 
    277 			case KN_INSERT:
    278 				if (CurrentObject.Count()) {
    279 					Map.PendingObject = &CurrentObject[0]->Class_Of();
    280 					if (Map.PendingObject) {
    281 						Map.PendingHouse = CurrentObject[0]->Owner();
    282 						Map.PendingObjectPtr = Map.PendingObject->Create_One_Of(HouseClass::As_Pointer(Map.PendingHouse));
    283 						if (Map.PendingObjectPtr) {
    284 							Map.Set_Cursor_Pos();
    285 							Map.Set_Cursor_Shape(Map.PendingObject->Occupy_List());
    286 						}
    287 					}
    288 				}
    289 				break;
    290 
    291 #ifdef NEVER
    292 			case KN_1:
    293 			case KN_2:
    294 			case KN_3:
    295 			case KN_4:
    296 			case KN_5:
    297 			case KN_6:
    298 			case KN_7:
    299 			case KN_8:
    300 			case KN_9:
    301 			case KN_0:
    302 				MonoPage = (input & 0xFF) - KN_1;
    303 				MonoPage %= sizeof(MonoArray)/sizeof(MonoArray[0]);
    304 				MonoArray[MonoPage].View();
    305 				input = 0;
    306 				break;
    307 #endif
    308 
    309 #ifdef NEVER
    310 			case ((int)KN_F1 | (int)KN_SHIFT_BIT):
    311 				Special.IsBarOn = (Special.IsBarOn == false);
    312 				Map.Flag_To_Redraw(true);
    313 				break;
    314 
    315 			case ((int)KN_F1 | (int)KN_SHIFT_BIT):	// quick load/save for debugging
    316 				if (!Save_Game(0,"Command & Conquer Save Game File")) {
    317 					CCMessageBox().Process("Error saving game!");
    318 					Prog_End();
    319 					exit(EXIT_SUCCESS);
    320 				}
    321 				break;
    322 
    323 			case ((int)KN_F2 | (int)KN_SHIFT_BIT):	// quick load/save for debugging
    324 				if (!Load_Game(0)) {
    325 					CCMessageBox().Process("Error loading game!");
    326 					Prog_End();
    327 					exit(EXIT_SUCCESS);
    328 				}
    329 				break;
    330 
    331 //#ifdef SCENARIO_EDITOR
    332 			case KN_F2:		// enable/disable the map editor
    333 				Go_Editor(!Debug_Map);
    334 				break;
    335 //#endif
    336 #endif
    337 
    338 #ifdef NEVER
    339 			case KN_F2: {
    340 				Debug_Map++;
    341 				Scenario_Editor();
    342 				Debug_Map--;
    343 #ifdef NEVER
    344 				COORDINATE		coord;
    345 				int		index;
    346 				static COORDINATE	_coords[] = {
    347 					0x00010001L,
    348 					0x00800080L,
    349 					0x00810081L,
    350 					0x00010081L,
    351 					0x00810001L,
    352 					0x00800081L,
    353 					0x00800001L,
    354 					0x00010080L,
    355 					0x00810080L,
    356 					0L
    357 				};
    358 				index = 0;
    359 				while (_coords[index]) {
    360 					coord = _coords[index++];
    361 					Mono_Printf("Spillage for %08lX = %d.\r", coord, Coord_Spillage_Number(coord));
    362 				}
    363 				Keyboard::Clear();
    364 				Keyboard::Get();
    365 
    366 #endif
    367 
    368 #ifdef NEVER
    369 #define MAX_RADIUS	10
    370 					COORDINATE	coord;
    371 					int	x,y;
    372 					COORDINATE	const *ptr;
    373 					int	input;
    374 					int	f1,f2;
    375 					TurnTrackType	const *track;
    376 
    377 					#define	XCENTER	160
    378 					#define	YCENTER	100
    379 					for (;;) {
    380 						VisiblePage.Clear();
    381 
    382 						// Draw grid.
    383 						{
    384 							static int _gridx[] = {0,64,128,192,0,64,128,192,0,64,128,192};
    385 							static int _gridy[] = {0,0,0,0,64,64,64,64,128,128,128,128};
    386 							int	index;
    387 
    388 							for (index = 0; index < 12; index++) {
    389 								LogicPage->Put_Pixel((_gridx[index]+XCENTER)-(32+64),(_gridy[index]+YCENTER)-(32+64), DKGRAY);
    390 							}
    391 						}
    392 
    393 						// Get facing #1.
    394 						LogicPage->Print("Facing #1 (0-7)?", 0, 0, WHITE, BLACK);
    395 						input = Keyboard::Get();
    396 						if (input == KA_ESC) break;
    397 						input -= KA_0;
    398 						input = Bound(input, 0, 7);
    399 //						input = MAX(input, 0);
    400 //						input = MIN(input, 7);
    401 						f1 = input;
    402 						Int_Print(f1, 100, 0, WHITE, BLACK);
    403 
    404 						// Get facing #2.
    405 						LogicPage->Print("Facing #2 (0-7)?", 0, 10, WHITE, BLACK);
    406 						input = Keyboard::Get();
    407 						if (input == KA_ESC) break;
    408 						input -= KA_0;
    409 						input = Bound(input, 0, 7);
    410 //						input = MAX(input, 0);
    411 //						input = MIN(input, 7);
    412 						f2 = input;
    413 						Int_Print(f2, 100, 10, WHITE, BLACK);
    414 
    415 						track = &TrackControl[f1][f2];
    416 						if (track->Track == 0) {
    417 							LogicPage->Print("Undefined track.", 0, 30, WHITE, BLACK);
    418 						} else {
    419 							int	index;	// Track index counter.
    420 
    421 							ptr = TrackPointers[track->Track-1];
    422 							index = 0;
    423 							while (ptr[index]) {
    424 								coord = Smooth_Turn(NULL, ptr[index], track->Flag);
    425 
    426 								x = (int)(coord & 0xFFFF);
    427 								y = (int)((coord >> 16) & 0xFFFF);
    428 								LogicPage->Put_Pixel(XCENTER + (x>>2), YCENTER + (y>>2), WHITE);
    429 								Delay(1);
    430 								index++;
    431 							}
    432 
    433 						}
    434 						input = Keyboard::Get();
    435 						if (input == KA_ESC) break;
    436 					}
    437 
    438 					Map.Flag_To_Redraw(true);
    439 #endif
    440 #ifdef NEVER
    441 					FILE	*fh;
    442 					int	index;
    443 					COORDINATE	coord;
    444 
    445 					fh = fopen("diagonal.txt", "wt");
    446 					if (fh) {
    447 
    448 						fprintf(fh, "track 2\n");
    449 						coord = 0x0100FF00L;
    450 						for (index = 0; index <= 48; index++) {
    451 							fprintf(fh, "0x%08lXL\n", coord);
    452 							coord = Coord_Move(coord, 32, 11);
    453 						}
    454 						fprintf(fh, "\n\n");
    455 
    456 						fprintf(fh, "track 1\n");
    457 						coord = 0x01000000L;
    458 						for (index = 0; index <= 40; index++) {
    459 							fprintf(fh, "0x%08lXL\n", coord);
    460 							coord = Coord_Move(coord, 0, 11);
    461 						}
    462 						fprintf(fh, "\n\n");
    463 
    464 						fclose(fh);
    465 					}
    466 #endif
    467 #ifdef NEVER
    468 					FILE	*fh;
    469 					int	x,y,radius;
    470 					int	radsize[MAX_RADIUS+2];
    471 					int	count;
    472 
    473 					memset(radsize, 0, sizeof(radsize));
    474 					fh = fopen("Range.txt", "wt");
    475 					if (fh) {
    476 						fprintf(fh, "int const RadiusOffset[] = {\n");
    477 
    478 						for (radius = 0; radius <= MAX_RADIUS; radius++) {
    479 
    480 							fprintf(fh, "\t/* %-2d */\t", radius);
    481 							for (y = -MAX_RADIUS; y <= MAX_RADIUS; y++) {
    482 								for (x = -MAX_RADIUS; x <= MAX_RADIUS; x++) {
    483 									int	xd,yd,dist;
    484 
    485 									xd = ABS(x);
    486 									yd = ABS(y);
    487 									if (xd > yd) {
    488 										dist = yd/2 + xd;
    489 									} else {
    490 										dist = xd/2 + yd;
    491 									}
    492 									if (dist == radius) {
    493 										dist = y*MAP_CELL_W + x;
    494 
    495 										if (y) {
    496 											if (y < 0) {
    497 												fprintf(fh, "(-MCW*%d)", ABS(y));
    498 											} else {
    499 												fprintf(fh, "(MCW*%d)", ABS(y));
    500 											}
    501 											fprintf(fh, "%c%d,", (x<0) ? '-' : '+', ABS(x));
    502 										} else {
    503 											fprintf(fh, "%d,", x);
    504 										}
    505 										radsize[radius]++;
    506 									}
    507 								}
    508 							}
    509 							fprintf(fh, "\n");
    510 						}
    511 						fprintf(fh, "};\n\n");
    512 
    513 						count = 0;
    514 						fprintf(fh, "int const RadiusCount[%d] = {", MAX_RADIUS+1);
    515 						for (radius = 0; radius <= MAX_RADIUS; radius++) {
    516 							count += radsize[radius];
    517 							fprintf(fh, "%d", count);
    518 							if (radius != MAX_RADIUS) {
    519 								fprintf(fh, ",");
    520 							}
    521 						}
    522 						fprintf(fh, "};\n");
    523 						fclose(fh);
    524 					}
    525 #endif
    526 				}
    527 				break;
    528 #endif
    529 
    530 #ifdef NEVER
    531 			case ((int)KN_F3 | (int)KN_ALT_BIT):	// quick load/save for debugging
    532 				Debug_Threat = (Debug_Threat == false);
    533 				Map.Flag_To_Redraw(true);
    534 				break;
    535 
    536 #endif
    537 
    538 			case KN_F3:
    539 				Debug_Icon = (Debug_Icon == false);
    540 				Map.Flag_To_Redraw(true);
    541 				break;
    542 
    543 
    544 			/*
    545 			**	Reveal entire map to player.
    546 			*/
    547 			case KN_F4:
    548 				if (GameToPlay == GAME_NORMAL) {
    549 					Debug_Unshroud = (Debug_Unshroud == false);
    550 					Map.Flag_To_Redraw(true);
    551 				}
    552 				break;
    553 
    554 			/*
    555 			**	Shows sight and fire range in the form of circles emanating from the currently
    556 			**	selected unit. The white circle is for sight range, the red circle is for
    557 			**	fire range.
    558 			*/
    559 			case KN_F7:
    560 				if (CurrentObject.Count() && CurrentObject[0]->Is_Techno()) {
    561 					TechnoTypeClass const & ttype = (TechnoTypeClass const &)CurrentObject[0]->Class_Of();
    562 					int sight = ((int)ttype.SightRange)<<8;
    563 					int weapon = 0;
    564 					if (ttype.Primary != WEAPON_NONE) weapon = Weapons[ttype.Primary].Range;
    565 					Set_Logic_Page(SeenBuff);
    566 					COORDINATE center = CurrentObject[0]->Center_Coord();
    567 					COORDINATE center2 = CurrentObject[0]->Fire_Coord(0);
    568 
    569 					for (int r = 0; r < 255; r += 10) {
    570 						int	x,y,x1,y1;
    571 						DirType r1 = (DirType)r;
    572 						DirType r2 = (DirType)((r+10) & 0xFF);
    573 
    574 						if (Map.Coord_To_Pixel(Coord_Move(center, r1, sight), x, y)) {
    575 							Map.Coord_To_Pixel(Coord_Move(center, r2, sight), x1, y1);
    576 							LogicPage->Draw_Line(x, y+8, x1, y1+8, WHITE);
    577 						}
    578 						if (Map.Coord_To_Pixel(Coord_Move(center2, r1, weapon), x, y)) {
    579 							Map.Coord_To_Pixel(Coord_Move(center2, r2, weapon), x1, y1);
    580 							LogicPage->Draw_Line(x, y+8, x1, y1+8, RED);
    581 						}
    582 					}
    583 				}
    584 				break;
    585 
    586 			case ((int)KN_F4 | (int)KN_CTRL_BIT):
    587 				Debug_Unshroud = (Debug_Unshroud == false);
    588 				Map.Flag_To_Redraw(true);
    589 				break;
    590 
    591 #ifdef NEVER
    592 			case KN_F5:
    593 				Special.IsShowPath = (Special.IsShowPath == false);
    594 				//PlayerPtr->Credits += 1000;
    595 				break;
    596 
    597 			case KN_F6:
    598 				if (Map.In_Radar(XY_Cell(Map.MapCellX+5, Map.MapCellY - 1))) {
    599 					Mono_Printf("Arrrggggghhhhh!");
    600 				} else {
    601 					Mono_Printf("No Arrrggggghhhhh!");
    602 				}
    603 				break;
    604 
    605 			case ((int)KN_F9 | (int)KN_CTRL_BIT):
    606 				if (HouseClass::As_Pointer(HOUSE_GOOD))
    607 					(HouseClass::As_Pointer(HOUSE_GOOD))->Blowup_All();
    608 				break;
    609 
    610 			case ((int)KN_F10 | (int)KN_CTRL_BIT):
    611 				if (HouseClass::As_Pointer(HOUSE_BAD))
    612 					(HouseClass::As_Pointer(HOUSE_BAD))->Blowup_All();
    613 				break;
    614 #endif
    615 		}
    616 
    617 	}
    618 }
    619 
    620 
    621 /***********************************************************************************************
    622  * Self_Regulate -- Regulates the logic timer to result in smooth animation                    *
    623  *                                                                                             *
    624  *    The self regulation process checks the number of frames displayed                        *
    625  *    per second and from this determines the amount of time to devote                         *
    626  *    to internal logic processing. By adjusting the time allotted to                          *
    627  *    internal processing, smooth animation can be maintained.                                 *
    628  *                                                                                             *
    629  * INPUT:   none                                                                               *
    630  *                                                                                             *
    631  * OUTPUT:  none                                                                               *
    632  *                                                                                             *
    633  * WARNINGS:   In order for this routine to work properly it MUST be                           *
    634  *             called every display loop.                                                      *
    635  *                                                                                             *
    636  * HISTORY:                                                                                    *
    637  *   07/31/1991 JLB : Created.                                                                 *
    638  *   07/05/1994 JLB : Handles new monochrome system.                                           *
    639  *=============================================================================================*/
    640 #define	UPDATE_INTERVAL	TIMER_SECOND
    641 void Self_Regulate(void)
    642 {
    643 	static CountDownTimerClass DebugTimer(BT_SYSTEM);
    644 	static ObjectClass * _lastobject = 0;
    645 
    646 	if (!DebugTimer.Time()) {
    647 		DebugTimer.Set(UPDATE_INTERVAL);
    648 
    649 		if (MonoClass::Is_Enabled()) {
    650 			MonoClass *mono = MonoClass::Get_Current();
    651 			mono->Set_Default_Attribute(2);
    652 
    653 			switch (MonoPage) {
    654 				case 0:
    655 					mono = &MonoArray[0];
    656 					mono->Clear();
    657 
    658 					/*
    659 					**	Display the status of the currently selected object.
    660 					*/
    661 					if (CurrentObject.Count()) {
    662 						_lastobject = CurrentObject[0];
    663 					}
    664 					if (_lastobject && !_lastobject->IsActive) {
    665 						_lastobject = 0;
    666 					}
    667 					if (_lastobject) {
    668 						_lastobject->Debug_Dump(mono);
    669 					}
    670 					Logic.Debug_Dump(mono);
    671 					mono->Set_Cursor(0, 20);
    672 					mono->Printf(
    673 						"Heap size:%10ld \r"
    674 						"Largest:  %10ld \r"
    675 						"Ttl Free: %10ld \r"
    676 						"Frag:     %10ld \r",
    677 						Heap_Size(MEM_NORMAL),
    678 						Ram_Free(MEM_NORMAL),
    679 						Total_Ram_Free(MEM_NORMAL),
    680 						Total_Ram_Free(MEM_NORMAL)-Ram_Free(MEM_NORMAL)
    681 					);
    682 					*MonoClass::Get_Current() = *mono;
    683 					break;
    684 			}
    685 
    686 			MonoArray[MonoPage] = *mono;
    687 		}
    688 	}
    689 }
    690 #endif