diff --git a/src/component/chat.cpp b/src/component/chat.cpp new file mode 100644 index 00000000..22fd2056 --- /dev/null +++ b/src/component/chat.cpp @@ -0,0 +1,88 @@ +#include +#include "chat.hpp" +#include "scheduler.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include +#include + +#define chat_font game::R_RegisterFont("fonts/fira_mono_regular.ttf", 25) +#define material_white game::Material_RegisterHandle("white") + +namespace chat +{ + namespace + { + struct message + { + std::string text; + std::chrono::steady_clock::time_point time; + }; + + std::deque history; + + float color_white[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + + float screen_max[2]; + + void check_resize() + { + screen_max[0] = game::ScrPlace_GetViewPlacement()->realViewportSize[0]; + screen_max[1] = game::ScrPlace_GetViewPlacement()->realViewportSize[1]; + } + + float relative(float value) + { + const auto ratio = screen_max[0] / 2560.f; + + return value * ratio; + } + + void draw_chat() + { + check_resize(); + + const auto now = std::chrono::high_resolution_clock::now(); + + for (auto i = 0; i < std::min(15, (int)history.size()); i++) + { + if (now - history[i].time > 11s) + { + return; + } + + const auto diff = now - history[i].time; + + float color[4] = { color_white[0], color_white[1], color_white[2], 1.f }; + + if (diff > 10.5s) + { + const auto milliseconds = (float)(11000 - std::chrono::duration_cast(diff).count()); + + color[3] = (float)(milliseconds / 500.f); + } + + game::R_AddCmdDrawText(history[i].text.data(), 0x7FFFFFFF, chat_font, relative(15.f), relative(600.f + i * 25), 1.f, 1.f, 0.f, color, 0); + } + } + } + + void print(const std::string& msg) + { + message m; + m.text = msg; + m.time = std::chrono::high_resolution_clock::now(); + + history.push_front(m); + } + + void init() + { + scheduler::loop([]() + { + draw_chat(); + }, scheduler::pipeline::renderer); + } +} \ No newline at end of file diff --git a/src/component/chat.hpp b/src/component/chat.hpp new file mode 100644 index 00000000..9b406e7b --- /dev/null +++ b/src/component/chat.hpp @@ -0,0 +1,8 @@ +#pragma once + +namespace chat +{ + void print(const std::string& msg); + + void init(); +} \ No newline at end of file diff --git a/src/component/command.cpp b/src/component/command.cpp index c7d78279..7aca8225 100644 --- a/src/component/command.cpp +++ b/src/component/command.cpp @@ -146,6 +146,11 @@ namespace command { utils::hook::jump(game::base_address + 0x5A74F0, dvar_command_stub, true); + add("say", [](const params& params) + { + chat::print(params.join(1)); + }); + add("listassetpool", [](const params& params) { if (params.size() < 2) diff --git a/src/component/game_console.cpp b/src/component/game_console.cpp index e697af1a..73f991c2 100644 --- a/src/component/game_console.cpp +++ b/src/component/game_console.cpp @@ -6,6 +6,10 @@ #include "game/game.hpp" #include "game/dvars.hpp" +#include "game/scripting/event.hpp" +#include "game/scripting/execution.hpp" +#include "game/scripting/lua/engine.hpp" + #include #include #include @@ -215,9 +219,9 @@ namespace game_console con.globals.left_x = con.globals.x; con.globals.auto_complete_choice[0] = 0; - game::R_AddCmdDrawText(con.buffer, 0x7FFFFFFF, console_font, con.globals.x, - con.globals.y + con.globals.font_height, 1.0f, 1.0f, 0.0f, color_white, 0/*, - con.cursor, '|'*/); + game::R_AddCmdDrawTextWithCursor(con.buffer, 0x7FFFFFFF, console_font, 18, con.globals.x, + con.globals.y + con.globals.font_height, 1.0f, 1.0f, 0, color_white, 0, + con.cursor, '|'); // check if using a prefixed '/' or not const auto input = con.buffer[1] && (con.buffer[0] == '/' || con.buffer[0] == '\\') @@ -470,6 +474,18 @@ namespace game_console return true; } + void execute(const char* cmd) + { + scripting::event e; + e.name = "console_command"; + e.arguments.push_back(cmd); + e.entity = *game::levelEntityId; + + scripting::lua::engine::notify(e); + + game::Cbuf_AddText(0, utils::string::va("%s \n", cmd)); + } + bool console_key_event(const int localClientNum, const int key, const int down) { if (key == game::keyNum_t::K_F10) @@ -573,7 +589,7 @@ namespace game_console if (key == game::keyNum_t::K_ENTER) { - game::Cbuf_AddText(0, utils::string::va("%s \n", fixed_input.data())); + execute(fixed_input.data()); if (history_index != -1) { diff --git a/src/component/game_console.hpp b/src/component/game_console.hpp index 873f4e79..23fc157c 100644 --- a/src/component/game_console.hpp +++ b/src/component/game_console.hpp @@ -14,5 +14,7 @@ namespace game_console bool console_char_event(int local_client_num, int key); bool console_key_event(int local_client_num, int key, int down); + void execute(const char* cmd); + void init(); } \ No newline at end of file diff --git a/src/dllmain.cpp b/src/dllmain.cpp index a2aae362..a78a8297 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -17,7 +17,7 @@ DWORD WINAPI dwConsole(LPVOID) std::cout << "\n"; std::getline(std::cin, cmd); - game::Cbuf_AddText(0, cmd.data()); + game_console::execute(cmd.data()); } return 0; @@ -36,6 +36,7 @@ void init() scheduler::init(); game_console::init(); scripting::init(); + chat::init(); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) diff --git a/src/game/scripting/lua/context.cpp b/src/game/scripting/lua/context.cpp index 551f3f60..1079d92e 100644 --- a/src/game/scripting/lua/context.cpp +++ b/src/game/scripting/lua/context.cpp @@ -168,6 +168,11 @@ namespace scripting::lua { command::execute(command, false); }; + + game_type["say"] = [](const game&, const std::string& msg) + { + chat::print(msg); + }; } } diff --git a/src/game/symbols.hpp b/src/game/symbols.hpp index 3bcdd373..b43cbbdd 100644 --- a/src/game/symbols.hpp +++ b/src/game/symbols.hpp @@ -44,8 +44,8 @@ namespace game float* color, Material* material)> R_AddCmdDrawStretchPic{0x3C9710}; WEAK symbol R_AddCmdDrawText{0x76C660}; - WEAK symbol - R_AddCmdDrawTextWithCursor{0x769D90}; + WEAK symbol R_AddCmdDrawTextWithCursor{0x76CAF0}; WEAK symbol R_RegisterFont{0x746FE0}; WEAK symbol R_TextWidth{0x7472A0}; diff --git a/src/stdinc.hpp b/src/stdinc.hpp index c9f56c2c..fb60fedf 100644 --- a/src/stdinc.hpp +++ b/src/stdinc.hpp @@ -21,6 +21,15 @@ #include #include #include +#include + +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif #include #include @@ -42,3 +51,4 @@ using namespace std::literals; #include "component/scheduler.hpp" #include "component/input.hpp" #include "component/game_console.hpp" +#include "component/chat.hpp"