| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 |
- /*
- ** Command & Conquer Red Alert(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /* $Header: /CounterStrike/DEBUG.CPP 1 3/03/97 10:24a Joe_bostic $ */
- /***********************************************************************************************
- *** 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 ***
- ***********************************************************************************************
- * *
- * Project Name : Command & Conquer *
- * *
- * File Name : DEBUG.CPP *
- * *
- * Programmer : Joe L. Bostic *
- * *
- * Start Date : September 10, 1993 *
- * *
- * Last Update : July 18, 1996 [JLB] *
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * Self_Regulate -- Regulates the logic timer to result in smooth animation. *
- * Debug_Key -- Debug mode keyboard processing. *
- * Bench_Time -- Convert benchmark timer into descriptive string. *
- * Benchmarks -- Display the performance tracking benchmarks. *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "function.h"
- #include "vortex.h"
- #include <stdarg.h>
- #ifdef CHEAT_KEYS
- static CDTimerClass<SystemTimerClass> DebugTimer;
- int VortexFrame = -1;
- /***********************************************************************************************
- * Debug_Key -- Debug mode keyboard processing. *
- * *
- * If debugging is enabled, then this routine will be called for every keystroke that the *
- * game doesn't recognize. These extra keys usually perform some debugging function. *
- * *
- * INPUT: input -- The key code that was pressed. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 10/07/1992 JLB : Created. *
- *=============================================================================================*/
- void Debug_Key(unsigned input)
- {
- static int map_x = -1;
- static int map_y = -1;
- static int map_width = -1;
- static int map_height = -1;
- if (!input || input & KN_BUTTON) return;
- /*
- ** Processing of normal keystrokes.
- */
- if (Debug_Flag) {
- switch (input) {
- case KN_BACKSPACE:
- if (ChronalVortex.Is_Active()) {
- ChronalVortex.Disappear();
- } else {
- int xxxx = Get_Mouse_X() + Map.TacPixelX;
- int yyyy = Get_Mouse_Y() + Map.TacPixelY;
- CELL cell = Map.DisplayClass::Click_Cell_Calc(xxxx,yyyy);
- ChronalVortex.Appear ( Cell_Coord (cell) );
- }
- break;
- #ifdef WIN32
- case KN_J:
- Debug_MotionCapture = true;
- break;
- #ifdef OBSOLETE
- case KN_K:
- /*
- ** time to create a screen shot using the PCX code (if it works)
- */
- if (!Debug_MotionCapture) {
- GraphicBufferClass temp_page( SeenBuff.Get_Width(),
- SeenBuff.Get_Height(),
- NULL,
- SeenBuff.Get_Width() * SeenBuff.Get_Height());
- CDFileClass file;
- char filename[30];
- SeenBuff.Blit(temp_page);
- for (int lp = 0; lp < 99; lp ++) {
- sprintf(filename, "scrsht%02d.pcx", lp);
- file.Set_Name(filename);
- if (!file.Is_Available()) break;
- }
- file.Cache(200000);
- Write_PCX_File(file, temp_page, & GamePalette);
- Sound_Effect(VOC_BEEP);
- }
- break;
- #endif
- #endif
- case KN_P:
- {
- for (SpecialWeaponType spc = SPC_FIRST; spc < SPC_COUNT; spc++) {
- PlayerPtr->SuperWeapon[spc].Enable(true, true);
- PlayerPtr->SuperWeapon[spc].Forced_Charge(true);
- Map.Add(RTTI_SPECIAL, spc);
- Map.Column[1].Flag_To_Redraw();
- }
- }
- break;
- case KN_I:
- {
- Map.Flash_Power();
- Map.Flash_Money();
- }
- break;
- case KN_O:
- {
- AircraftClass * air = new AircraftClass(AIRCRAFT_HIND, PlayerPtr->Class->House);
- if (air) {
- air->Height = 0;
- air->Unlimbo(Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()), DIR_N);
- }
- }
- break;
- case KN_B:
- {
- AircraftClass * air = new AircraftClass(AIRCRAFT_LONGBOW, PlayerPtr->Class->House);
- if (air) {
- air->Height = 0;
- air->Unlimbo(Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()), DIR_N);
- }
- }
- break;
- case KN_GRAVE:
- {
- WarheadType warhead = Random_Pick(WARHEAD_HE, WARHEAD_FIRE);
- COORDINATE coord = Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y());
- int damage = 1000;
- new AnimClass(Combat_Anim(damage, warhead, Map[coord].Land_Type()), coord);
- Explosion_Damage(coord, damage, NULL, warhead);
- }
- break;
- case KN_C:
- Debug_Cheat = (Debug_Cheat == false);
- PlayerPtr->IsRecalcNeeded = true;
- /*
- ** This placement might affect any prerequisite requirements for construction
- ** lists. Update the buildable options accordingly.
- */
- if (!ScenarioInit) {
- Map.Recalc();
- for (int index = 0; index < Buildings.Count(); index++) {
- Buildings.Ptr(index)->Update_Buildables();
- }
- }
- break;
- case (int)KN_Z|(int)KN_ALT_BIT:
- if (map_x == -1) {
- map_x = Map.MapCellX;
- map_y = Map.MapCellY;
- map_width = Map.MapCellWidth;
- map_height = Map.MapCellHeight;
- Map.MapCellX = 1;
- Map.MapCellY = 1;
- Map.MapCellWidth = MAP_CELL_W-2;
- Map.MapCellHeight = MAP_CELL_H-2;
- } else {
- Map.MapCellX = map_x;
- Map.MapCellY = map_y;
- Map.MapCellWidth = map_width;
- Map.MapCellHeight = map_height;
- map_x = -1;
- map_y = -1;
- map_width = -1;
- map_height = -1;
- }
- break;
- case KN_M:
- if (Debug_Flag) {
- if (MonoClass::Is_Enabled()) {
- MonoClass::Disable();
- } else {
- MonoClass::Enable();
- }
- }
- break;
- case (int)KN_W|(int)KN_ALT_BIT:
- PlayerPtr->Flag_To_Win();
- break;
- case (int)KN_L|(int)KN_ALT_BIT:
- PlayerPtr->Flag_To_Lose();
- break;
- case KN_DELETE:
- if (CurrentObject.Count()) {
- Map.Recalc();
- //CurrentObject[0]->Detach_All();
- if (CurrentObject[0]->What_Am_I() == RTTI_BUILDING) {
- ((BuildingClass *)CurrentObject[0])->Sell_Back(1);
- } else {
- ObjectClass * object = CurrentObject[0];
- object->Unselect();
- object->Limbo();
- delete object;
- }
- }
- break;
- case (int)KN_DELETE|(int)KN_SHIFT_BIT:
- if (CurrentObject.Count()) {
- Map.Recalc();
- int damage = 50;
- CurrentObject[0]->Take_Damage(damage, 0, WARHEAD_SA);
- }
- break;
- case KN_INSERT:
- if (CurrentObject.Count()) {
- Map.PendingObject = &CurrentObject[0]->Class_Of();
- if (Map.PendingObject) {
- Map.PendingHouse = CurrentObject[0]->Owner();
- Map.PendingObjectPtr = Map.PendingObject->Create_One_Of(HouseClass::As_Pointer(Map.PendingHouse));
- if (Map.PendingObjectPtr) {
- Map.Set_Cursor_Pos();
- Map.Set_Cursor_Shape(Map.PendingObject->Occupy_List());
- }
- }
- }
- break;
- case KN_LBRACKET:
- case KN_F11:
- if (MonoPage == DMONO_FIRST) {
- MonoPage = DMonoType(DMONO_COUNT-1);
- } else {
- MonoPage = DMonoType(MonoPage - 1);
- }
- DebugTimer = 0;
- break;
- case KN_RBRACKET:
- case KN_F12:
- MonoPage = DMonoType(MonoPage + 1);
- if (MonoPage == DMONO_COUNT) {
- MonoPage = DMONO_FIRST;
- }
- DebugTimer = 0;
- break;
- case KN_V:
- case KN_F3:
- Debug_Icon = (Debug_Icon == false);
- Map.Flag_To_Redraw(true);
- break;
- /*
- ** Reveal entire map to player.
- */
- // case KN_F4:
- // if (Session.Type == GAME_NORMAL) {
- // Debug_Unshroud = (Debug_Unshroud == false);
- // Map.Flag_To_Redraw(true);
- // }
- // break;
- /*
- ** Shows sight and fire range in the form of circles emanating from the currently
- ** selected unit. The white circle is for sight range, the red circle is for
- ** fire range.
- */
- case KN_F7:
- if (CurrentObject.Count() && CurrentObject[0]->Is_Techno()) {
- TechnoTypeClass const & ttype = (TechnoTypeClass const &)CurrentObject[0]->Class_Of();
- int sight = ((int)ttype.SightRange)<<8;
- int weapon = 0;
- if (ttype.PrimaryWeapon != NULL) weapon = ttype.PrimaryWeapon->Range;
- Set_Logic_Page(SeenBuff);
- COORDINATE center = CurrentObject[0]->Center_Coord();
- COORDINATE center2 = CurrentObject[0]->Fire_Coord(0);
- for (int r = 0; r < 255; r += 10) {
- int x,y,x1,y1;
- DirType r1 = (DirType)r;
- DirType r2 = (DirType)((r+10) & 0xFF);
- if (Map.Coord_To_Pixel(Coord_Move(center, r1, sight), x, y)) {
- Map.Coord_To_Pixel(Coord_Move(center, r2, sight), x1, y1);
- LogicPage->Draw_Line(x, y+8, x1, y1+8, WHITE);
- }
- if (Map.Coord_To_Pixel(Coord_Move(center2, r1, weapon), x, y)) {
- Map.Coord_To_Pixel(Coord_Move(center2, r2, weapon), x1, y1);
- LogicPage->Draw_Line(x, y+8, x1, y1+8, RED);
- }
- }
- }
- break;
- case ((int)KN_F4 | (int)KN_CTRL_BIT):
- Debug_Unshroud = (Debug_Unshroud == false);
- Map.Flag_To_Redraw(true);
- break;
- default:
- break;
- }
- }
- }
- /***********************************************************************************************
- * Bench_Time -- Convert benchmark timer into descriptive string. *
- * *
- * This routine will take the values of the benchmark timer specified and build a string *
- * that displays the average time each event consumed as well as the ranking of how much *
- * time that event took (total) during the tracking duration (one second?). *
- * *
- * INPUT: btype -- The benchmark to convert to a descriptive string. *
- * *
- * OUTPUT: Returns with a pointer to the descriptive string of the benchmark specified. *
- * *
- * WARNINGS: The value returned is a pointer to a static buffer. As such, it is only valid *
- * until the next time that this routine is called. *
- * *
- * HISTORY: *
- * 07/18/1996 JLB : Created. *
- *=============================================================================================*/
- static char const * Bench_Time(BenchType btype)
- {
- static char buffer[32];
- int rootcount = Benches[BENCH_GAME_FRAME].Count();
- if (rootcount == 0) rootcount = 1;
- int roottime = Benches[BENCH_GAME_FRAME].Value();
- int count = Benches[btype].Count();
- int time = Benches[btype].Value();
- if (count > 0 && count * time > roottime * rootcount) time = roottime / count;
- int percent = 0;
- if (roottime != 0 && rootcount != 0) {
- percent = ((count * time) * 99) / (roottime * rootcount);
- }
- if (percent > 99) percent = 99;
- sprintf(buffer, "%-2d%% %7d", percent, time);
- return(buffer);
- }
- /***********************************************************************************************
- * Benchmarks -- Display the performance tracking benchmarks. *
- * *
- * This will display the benchmarks for the various processes that are being tracked. The *
- * display will indicate the fraction that each process is consuming out of the entire *
- * process time as well as the time consumed by each individual event. The total fraction *
- * is useful for determing what should be optimized. The individual time is useful for *
- * guaging the effectiveness of optimization changes. *
- * *
- * INPUT: mono -- Pointer to the monochrome screen that the display will use. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 07/18/1996 JLB : Created. *
- *=============================================================================================*/
- static void Benchmarks(MonoClass * mono)
- {
- static bool _first = true;
- if (_first) {
- _first = false;
- mono->Clear();
- mono->Set_Cursor(0, 0);
- mono->Print(Text_String(TXT_DEBUG_PERFORMANCE));
- if (Benches == NULL) {
- mono->Set_Cursor(20, 15);
- mono->Printf(TXT_NO_PENTIUM);
- }
- }
- if (Benches != NULL) {
- mono->Set_Cursor(1, 2);mono->Printf("%s", Bench_Time(BENCH_FINDPATH));
- mono->Set_Cursor(1, 4);mono->Printf("%s", Bench_Time(BENCH_GREATEST_THREAT));
- mono->Set_Cursor(1, 6);mono->Printf("%s", Bench_Time(BENCH_AI));
- mono->Set_Cursor(1, 8);mono->Printf("%s", Bench_Time(BENCH_PCP));
- mono->Set_Cursor(1, 10);mono->Printf("%s", Bench_Time(BENCH_EVAL_OBJECT));
- mono->Set_Cursor(1, 12);mono->Printf("%s", Bench_Time(BENCH_EVAL_CELL));
- mono->Set_Cursor(1, 14);mono->Printf("%s", Bench_Time(BENCH_EVAL_WALL));
- mono->Set_Cursor(1, 16);mono->Printf("%s", Bench_Time(BENCH_MISSION));
- mono->Set_Cursor(14, 2);mono->Printf("%s", Bench_Time(BENCH_CELL));
- mono->Set_Cursor(14, 4);mono->Printf("%s", Bench_Time(BENCH_OBJECTS));
- mono->Set_Cursor(14, 6);mono->Printf("%s", Bench_Time(BENCH_ANIMS));
- mono->Set_Cursor(27, 2);mono->Printf("%s", Bench_Time(BENCH_PALETTE));
- mono->Set_Cursor(40, 2);mono->Printf("%s", Bench_Time(BENCH_GSCREEN_RENDER));
- mono->Set_Cursor(40, 4);mono->Printf("%s", Bench_Time(BENCH_SIDEBAR));
- mono->Set_Cursor(40, 6);mono->Printf("%s", Bench_Time(BENCH_RADAR));
- mono->Set_Cursor(40, 8);mono->Printf("%s", Bench_Time(BENCH_TACTICAL));
- mono->Set_Cursor(40, 10);mono->Printf("%s", Bench_Time(BENCH_POWER));
- mono->Set_Cursor(40, 12);mono->Printf("%s", Bench_Time(BENCH_SHROUD));
- mono->Set_Cursor(40, 14);mono->Printf("%s", Bench_Time(BENCH_TABS));
- mono->Set_Cursor(40, 16);mono->Printf("%s", Bench_Time(BENCH_BLIT_DISPLAY));
- mono->Set_Cursor(66, 2);mono->Printf("%7d", Benches[BENCH_RULES].Value());
- mono->Set_Cursor(66, 4);mono->Printf("%7d", Benches[BENCH_SCENARIO].Value());
- for (BenchType index = BENCH_FIRST; index < BENCH_COUNT; index++) {
- if (index != BENCH_RULES && index != BENCH_SCENARIO) Benches[index].Reset();
- }
- }
- }
- /***********************************************************************************************
- * Self_Regulate -- Regulates the logic timer to result in smooth animation *
- * *
- * The self regulation process checks the number of frames displayed *
- * per second and from this determines the amount of time to devote *
- * to internal logic processing. By adjusting the time allotted to *
- * internal processing, smooth animation can be maintained. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: In order for this routine to work properly it MUST be *
- * called every display loop. *
- * *
- * HISTORY: *
- * 07/31/1991 JLB : Created. *
- * 07/05/1994 JLB : Handles new monochrome system. *
- *=============================================================================================*/
- #define UPDATE_INTERVAL TIMER_SECOND
- void Self_Regulate(void)
- {
- static ObjectClass * _lastobject = 0;
- static bool _first=true;
- if (DebugTimer == 0) {
- DebugTimer = UPDATE_INTERVAL;
- if (MonoClass::Is_Enabled()) {
- if (_first) {
- _first = false;
- for (DMonoType index = DMONO_FIRST; index < DMONO_COUNT; index++) {
- MonoArray[index].Clear();
- }
- }
- /*
- ** Always update the stress tracking mono display even if it
- ** currently isn't visible.
- */
- Logic.Debug_Dump(&MonoArray[DMONO_STRESS]);
- MonoClass * mono = &MonoArray[MonoPage];
- mono->Set_Default_Attribute(MonoClass::NORMAL);
- mono->View();
- switch (MonoPage) {
- case DMONO_EVENTS:
- Benchmarks(mono);
- break;
- case DMONO_OBJECT:
- mono->Clear();
- /*
- ** Display the status of the currently selected object.
- */
- if (CurrentObject.Count()) {
- _lastobject = CurrentObject[0];
- }
- if (_lastobject && !_lastobject->IsActive) {
- _lastobject = 0;
- }
- if (_lastobject) {
- _lastobject->Debug_Dump(mono);
- }
- break;
- case DMONO_STRESS:
- #ifdef OBSOLETE
- mono->Set_Cursor(0, 20);
- mono->Printf(
- "Heap size:%10ld \r"
- "Largest: %10ld \r"
- "Ttl Free: %10ld \r"
- "Frag: %10ld \r",
- Heap_Size(MEM_NORMAL),
- Ram_Free(MEM_NORMAL),
- Total_Ram_Free(MEM_NORMAL),
- Total_Ram_Free(MEM_NORMAL)-Ram_Free(MEM_NORMAL)
- );
- #endif
- break;
- case DMONO_HOUSE:
- mono->Clear();
- if (CurrentObject.Count()) {
- _lastobject = CurrentObject[0];
- }
- if (_lastobject && !_lastobject->IsActive) {
- _lastobject = 0;
- }
- if (_lastobject && _lastobject->Is_Techno()) {
- ((TechnoClass *)_lastobject)->House->Debug_Dump(mono);
- }
- break;
- default:
- break;
- }
- mono->Set_Cursor(0, 0);
- }
- }
- }
- #endif
|