diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 40cb79e..7f69bfe 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -112,6 +112,7 @@ set(src_redalert ./RedAlert/AIRCRAFT.CPP ./RedAlert/AIRCRAFT.H ./RedAlert/ANIM.CPP + ./RedAlert/CONSOLE.CPP ./RedAlert/ANIM.H ./RedAlert/AUDIO.CPP ./RedAlert/AUDIO.H diff --git a/code/REDALERT/CONSOLE.CPP b/code/REDALERT/CONSOLE.CPP new file mode 100644 index 0000000..6d96959 --- /dev/null +++ b/code/REDALERT/CONSOLE.CPP @@ -0,0 +1,305 @@ +// CONSOLE.CPP +// + +#include "imgui.h" +#include "FUNCTION.H" + +char console_text[16384]; +int console_text_len = 0; +char command_text[512]; + +#define MAX_ARGS 80 + +static int cmd_argc; +static char* cmd_argv[MAX_ARGS]; +static char* cmd_null_string = ""; +static char* cmd_args = NULL; + +char com_token[1024]; +int com_argc; +char** com_argv; + +typedef struct cmd_function_s +{ + struct cmd_function_s* next; + char* name; + xcommand_t function; +} cmd_function_t; + +static bool executeConsoleCommand = false; + +static cmd_function_t* cmd_functions; // possible commands to execute + +/* +============ +Cmd_AddCommand +============ +*/ +void Cmd_AddCommand(char* cmd_name, xcommand_t function) +{ + cmd_function_t* cmd; + + // fail if the command already exists + for (cmd = cmd_functions; cmd; cmd = cmd->next) + { + if (!strcmp(cmd_name, cmd->name)) + { + Console_Printf("Cmd_AddCommand: %s already defined\n", cmd_name); + return; + } + } + + cmd = (cmd_function_t *)malloc(sizeof(cmd_function_t)); + cmd->name = cmd_name; + cmd->function = function; + cmd->next = cmd_functions; + cmd_functions = cmd; +} + + +/* +============== +Cmd_Argc +============== +*/ +int Cmd_Argc() { + return cmd_argc; +} + +/* +============== +Cmd_Argv +============== +*/ +char* Cmd_Argv(int index) { + return cmd_argv[index]; +} + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char* COM_Parse(char* data) +{ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if (!data) + return NULL; + + // skip whitespace +skipwhite: + while ((c = *data) <= ' ') + { + if (c == 0) + return NULL; // end of file; + data++; + } + + // skip // comments + if (c == '/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + + // handle quoted strings specially + if (c == '\"') + { + data++; + while (1) + { + c = *data++; + if (c == '\"' || !c) + { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } + } + + // parse single characters + if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':') + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data + 1; + } + + // parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':') + break; + } while (c > 32); + + com_token[len] = 0; + return data; +} + + +/* +============ +Cmd_TokenizeString + +Parses the given string into command line tokens. +============ +*/ +void Cmd_TokenizeString(char* text) +{ + int i; + + // clear the args from the last string + for (i = 0; i < cmd_argc; i++) + free(cmd_argv[i]); + + cmd_argc = 0; + cmd_args = NULL; + + while (1) + { + // skip whitespace up to a /n + while (*text && *text <= ' ' && *text != '\n') + { + text++; + } + + if (*text == '\n') + { // a newline seperates commands in the buffer + text++; + break; + } + + if (!*text) + return; + + if (cmd_argc == 1) + cmd_args = text; + + text = COM_Parse(text); + if (!text) + return; + + if (cmd_argc < MAX_ARGS) + { + cmd_argv[cmd_argc] = (char *)malloc(strlen(com_token) + 1); + strcpy(cmd_argv[cmd_argc], com_token); + cmd_argc++; + } + } + +} + +/* +==================== +Console_Init +==================== +*/ +void Console_Init(void) { + memset(command_text, 0, sizeof(command_text)); + memset(console_text, 0, sizeof(console_text)); + console_text_len = 0; +} + +/* +==================== +Console_Render +==================== +*/ +void Console_Printf(const char* fmt, ...) { + va_list argptr; + char msg[4096]; + + va_start(argptr, fmt); + vsprintf(msg, fmt, argptr); + va_end(argptr); + + int len = strlen(msg); + strcpy(&console_text[console_text_len], msg); + + OutputDebugStringA(msg); + console_text_len += len; +} + +/* +==================== +ExecuteConsoleCommand +==================== +*/ +void ExecuteConsoleCommand(void) { + cmd_function_t* cmd; + + if (strlen(command_text) <= 0) + return; + + Console_Printf("%s\n", command_text); + Cmd_TokenizeString(command_text); + + memset(command_text, 0, sizeof(command_text)); + + for (cmd = cmd_functions; cmd; cmd = cmd->next) + { + if (!strcmp(Cmd_Argv(0), cmd->name)) + { + cmd->function(); + return; + } + } + + Console_Printf("Unknown command %s\n", Cmd_Argv(0)); +} + +/* +==================== +Console_Render +==================== +*/ +void Console_Render(void) { + bool ScreenActive; + + ImGuiStyle& style = ImGui::GetStyle(); + style.FramePadding = ImVec2(0, 0); + ImGui::SetNextWindowSize(ImVec2(420, 270)); + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::Begin("Developer Console", &ScreenActive, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar); + ImVec2 textres(420, 180); + ImGui::PushID("ConsoleTxt"); + ImGui::InputTextMultiline("", &console_text[0], sizeof(console_text), textres, ImGuiInputTextFlags_ReadOnly); + ImGui::PopID(); + ImGui::Text("Commands"); + ImGui::PushID("CmdTxt"); + ImGui::InputText("", &command_text[0], sizeof(command_text)); + ImGui::PopID(); + ImGui::SameLine(); + if (ImGui::Button("Execute")) { + executeConsoleCommand = true; + } + ImGui::End(); +} + +/* +================= +Console_Tick +================= +*/ +void Console_Tick(void) { + if (executeConsoleCommand) { + ExecuteConsoleCommand(); + executeConsoleCommand = false; + } +} \ No newline at end of file diff --git a/code/REDALERT/FUNCTION.H b/code/REDALERT/FUNCTION.H index a8dcef5..a52e3a9 100644 --- a/code/REDALERT/FUNCTION.H +++ b/code/REDALERT/FUNCTION.H @@ -1085,6 +1085,17 @@ void GlyphX_Debug_Print(const char *debug_text); void Disable_Uncompressed_Shapes (void); void Enable_Uncompressed_Shapes (void); +int Cmd_Argc(); +char* Cmd_Argv(int index); + +void Console_Init(void); +void Console_Render(void); +void Console_Printf(const char* fmt, ...); +void Console_Tick(void); + +typedef void (*xcommand_t) (void); +void Cmd_AddCommand(char* cmd_name, xcommand_t function); + /* ** Achievement event. ST - 11/11/2019 11:39AM */ diff --git a/code/REDALERT/SCENARIO.CPP b/code/REDALERT/SCENARIO.CPP index 2737a1c..7314ecc 100644 --- a/code/REDALERT/SCENARIO.CPP +++ b/code/REDALERT/SCENARIO.CPP @@ -114,6 +114,8 @@ bool Is_Mission_Aftermath (char *file_name); MapScript* mapScript = nullptr; bool mapScriptPlayStart = false; +void Cmd_Map(void); + /*********************************************************************************************** * ScenarioClass::ScenarioClass -- Constructor for the scenario control object. * * * @@ -183,6 +185,9 @@ ScenarioClass::ScenarioClass(void) : strcpy(BriefingText, ""); memset(GlobalFlags, '\0', sizeof(GlobalFlags)); memset(Views, '\0', sizeof(Views)); +// jmarshall + Cmd_AddCommand("map", Cmd_Map); +// jmarshall end } @@ -316,9 +321,12 @@ bool ScenarioClass::Set_Global_To(int global, bool value) bool Start_Scenario(char * name, bool briefing) { //BG Theme.Queue_Song(THEME_QUIET); + Console_Printf("Start_Scenario: %s\n", name); + Theme.Stop(); IsTanyaDead = SaveTanya; if (!Read_Scenario(name)) { + Console_Printf("Failed to load scenario!\n"); return(false); } @@ -3739,4 +3747,18 @@ void Disect_Scenario_Name(char const * name, int & scenario, ScenarioPlayerType */ var = SCEN_VAR_A; var = ScenarioVarType((name[6] - 'A') + SCEN_VAR_A); +} + +/* +============= +Cmd_Map +============= +*/ +void Cmd_Map(void) { + if (Cmd_Argc() != 2) { + Console_Printf("usage: map \n"); + return; + } + + Start_Scenario(Cmd_Argv(1)); } \ No newline at end of file diff --git a/code/REDALERT/STARTUP.CPP b/code/REDALERT/STARTUP.CPP index bd30cb4..d9135e0 100644 --- a/code/REDALERT/STARTUP.CPP +++ b/code/REDALERT/STARTUP.CPP @@ -195,6 +195,10 @@ int PASCAL WinMain ( HINSTANCE instance , HINSTANCE , char * command_line , int ** and if so, switch to the existing instance and terminate ourselves. */ SpawnedFromWChat = false; + + Console_Init(); + Console_Printf("Red Alert Build %s %s\n", __DATE__, __TIME__); + #if (0)//PG if (RA95AlreadyRunning) { //Set in the DDEServer constructor //MessageBox (NULL, "Error - attempt to restart Red Alert 95 when already running.", "Red Alert", MB_ICONEXCLAMATION|MB_OK); @@ -560,7 +564,7 @@ int PASCAL WinMain ( HINSTANCE instance , HINSTANCE , char * command_line , int ImGui_ImplSDL2_InitForD3D(game_window); ImGui_ImplOpenGL3_Init(); - io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 16.0f); + io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 16.0f); // jmarshall end if (!video_success) { diff --git a/code/REDALERT/VQAMOVIE.CPP b/code/REDALERT/VQAMOVIE.CPP index 64d143a..66234ce 100644 --- a/code/REDALERT/VQAMOVIE.CPP +++ b/code/REDALERT/VQAMOVIE.CPP @@ -101,8 +101,6 @@ long VQA_Play(_VQAHandle* vqaHandle) { int currentFrame = 0; bool shouldSampleAudio = true; - return 0; - smk_first(vqaHandle->smacker_video); while (currentFrame < vqaHandle->frame_count) { @@ -138,6 +136,7 @@ long VQA_Play(_VQAHandle* vqaHandle) { //} raw_image_buffer = smk_get_palette(vqaHandle->smacker_video); + Set_DD_Palette(raw_image_buffer, false); vqaHandle->video_graphics_buffer->Lock(); VQA_Dropsample(smk_get_video(vqaHandle->smacker_video), vqaHandle->width, vqaHandle->height, ScreenWidth, ScreenHeight); diff --git a/code/REDALERT/WIN32LIB/MISC.H b/code/REDALERT/WIN32LIB/MISC.H index 8d4aafd..a9a23aa 100644 --- a/code/REDALERT/WIN32LIB/MISC.H +++ b/code/REDALERT/WIN32LIB/MISC.H @@ -56,7 +56,7 @@ void Wait_Blit(void); unsigned Get_Video_Hardware_Capabilities(void); void Wait_Vert_Blank(void); -void Set_DD_Palette (void *palette); +void Set_DD_Palette (void *palette, bool raShift = true); /* ** Pointer to function to call if we detect a focus loss diff --git a/code/REDALERT/WIN32LIB/MOUSEWW.CPP b/code/REDALERT/WIN32LIB/MOUSEWW.CPP index 0e170f4..d186904 100644 --- a/code/REDALERT/WIN32LIB/MOUSEWW.CPP +++ b/code/REDALERT/WIN32LIB/MOUSEWW.CPP @@ -319,7 +319,8 @@ void WWMouseClass::Hide_Mouse() void WWMouseClass::Low_Show_Mouse(int x, int y) { extern bool Debug_Map; - if (Debug_Map) + extern bool renderConsole; + if (Debug_Map || renderConsole) return; // diff --git a/code/REDALERT/WINSTUB.CPP b/code/REDALERT/WINSTUB.CPP index 9881dcc..432066d 100644 --- a/code/REDALERT/WINSTUB.CPP +++ b/code/REDALERT/WINSTUB.CPP @@ -69,6 +69,8 @@ SDL_Window* game_window; SDL_GLContext game_context; int OverlappedVideoBlits = 0; +bool renderConsole = false; + void (*Misc_Focus_Loss_Function)(void) = nullptr; void (*Misc_Focus_Restore_Function)(void) = nullptr; @@ -91,11 +93,16 @@ void Reset_Video_Mode(void) { } -void Set_DD_Palette(void* palette) +void Set_DD_Palette(void* palette, bool raShift) { char* palette_get = (char*)palette; //CCPalette.Get_Data(); for (int j = 0; j < 768; j++) { - backbuffer_palette[j] = palette_get[j] << 2; + if (raShift) { + backbuffer_palette[j] = palette_get[j] << 2; + } + else { + backbuffer_palette[j] = palette_get[j]; + } } } @@ -137,10 +144,17 @@ void Device_Present(void) { Imgui_Dialog_Function(); } + if (renderConsole) { + Console_Render(); + } + ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); SDL_GL_SwapWindow(game_window); + + // Last thing we do is execute any console commands + Console_Tick(); } @@ -450,34 +464,7 @@ HANDLE DebugFile = INVALID_HANDLE_VALUE; *=============================================================================================*/ void WWDebugString (char *string) { -#if (0) - char outstr[256]; - - sprintf (outstr, "%s", string); - - DWORD actual; - if (DebugFile == INVALID_HANDLE_VALUE){ - DebugFile = CreateFile("debug.txt", GENERIC_WRITE, 0, - NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - }else{ - DebugFile = CreateFile("debug.txt", GENERIC_WRITE, 0, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - } - - if (DebugFile != INVALID_HANDLE_VALUE){ - SetFilePointer (DebugFile, 0, NULL, FILE_END); - WriteFile(DebugFile, outstr, strlen(outstr)+1, &actual, NULL); - CloseHandle (DebugFile); - } - - OutputDebugString (string); -#else //(0) - - string = string; -// debugprint( string ); - -#endif //(0) - + Console_Printf(string); } @@ -810,6 +797,20 @@ void WWSDL_ProcessEvents(KeyNumType& key, int& flags) { break; case SDL_KEYDOWN: + if (event.key.keysym.scancode == SDL_SCANCODE_GRAVE) { + renderConsole = !renderConsole; + + if (renderConsole) { + ShowCursor(TRUE); + Hide_Mouse(); + } + else { + ShowCursor(FALSE); + Show_Mouse(); + } + break; + } + const Uint8* state = SDL_GetKeyboardState(NULL); if (state[SDL_SCANCODE_RALT] || state[SDL_SCANCODE_LALT]) @@ -824,7 +825,7 @@ void WWSDL_ProcessEvents(KeyNumType& key, int& flags) { break; } - if (Debug_Map) + if (Debug_Map || renderConsole) { ImGui_ImplSDL2_ProcessEvent(&event); }