Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alias spectate command to camera2 in SP, add help strings for cheat commands #287

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ Version 1.9.0 (not released yet)
- Add level filename to "Level Initializing" console message
- Properly handle WM_PAINT in dedicated server, may improve performance (DF bug)
- Fix crash when `verify_level` command is run without a level being loaded
- Add missing help strings for builtin cheat commands
- Make `spectate` command set camera to free look when issued in single player

Version 1.8.0 (released 2022-09-17)
-----------------------------------
Expand Down
10 changes: 9 additions & 1 deletion game_patch/hud/multi_spectate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "multi_scoreboard.h"
#include "../os/console.h"
#include "../rf/entity.h"
#include "../rf/level.h"
#include "../rf/player/player.h"
#include "../rf/multi.h"
#include "../rf/gameseq.h"
Expand Down Expand Up @@ -229,8 +230,15 @@ FunHook<void(rf::Player*)> render_reticle_hook{
ConsoleCommand2 spectate_cmd{
"spectate",
[](std::optional<std::string> player_name) {
if (!(rf::level.flags & rf::LEVEL_LOADED)) {
rf::console::output("No level loaded!", nullptr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rf::console::output("No level loaded!", nullptr);
rf::console::print("No level loaded!");

return;
}

if (!rf::is_multi) {
rf::console::output("Spectate mode is only supported in multiplayer game!", nullptr);
// in single player, just enter free look mode
rf::console::output("Camera mode set to free look. Use `camera1` to return to first person.", nullptr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rf::console::output("Camera mode set to free look. Use `camera1` to return to first person.", nullptr);
rf::console::print("Camera mode set to free look. Use `camera1` to return to first person.");

rf::camera_enter_freelook(rf::local_player->cam);
return;
}

Expand Down
65 changes: 65 additions & 0 deletions game_patch/os/commands.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#include <common/config/BuildConfig.h>
#include "console.h"
#include "../main/main.h"
#include "../rf/player/camera.h"
#include "../rf/multi.h"
#include "../rf/player/player.h"
#include "../rf/level.h"
#include "../rf/entity.h"
#include "../rf/hud.h"
#include "../misc/misc.h"
#include "../misc/vpackfile.h"
#include <common/utils/list-utils.h>
Expand Down Expand Up @@ -104,6 +107,62 @@ FunHook<void()> verify_level_cmd_hook{
}
};

bool check_can_use_cheat_cmd()
{
return (rf::level.flags & rf::LEVEL_LOADED) && !rf::is_multi;
}

void handle_camera_command(FunHook<void()>& hook)
{
if (!check_can_use_cheat_cmd()) {
if (!(rf::level.flags & rf::LEVEL_LOADED)) {
rf::console::print("No level loaded!");
}
else if (rf::is_multi) {
rf::console::print("That command can't be used in multiplayer.");
}
return;
}
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
hook.call_target();

rf::CameraMode current_mode = rf::camera_get_mode(rf::local_player->cam);
GooberRF marked this conversation as resolved.
Show resolved Hide resolved

std::string mode_text = (current_mode == rf::CAMERA_FIRST_PERSON) ? "first person"
: (current_mode == rf::CAMERA_THIRD_PERSON) ? "third person"
: (current_mode == rf::CAMERA_FREELOOK) ? "free look"
: "unknown";

std::string helper_text =
(current_mode == rf::CAMERA_FIRST_PERSON) ? "" : " Use `camera1` to return to first person.";

rf::console::print("Camera mode set to {}.{}", mode_text, helper_text);
}

FunHook<void()> camera1_cmd_hook{0x00431270, []() { handle_camera_command(camera1_cmd_hook); }};
FunHook<void()> camera2_cmd_hook{0x004312D0, []() { handle_camera_command(camera2_cmd_hook); }};
FunHook<void()> camera3_cmd_hook{0x00431330, []() { handle_camera_command(camera3_cmd_hook); }};

FunHook<void()> heehoo_cmd_hook{
0x00431210,
[]() {
if (!check_can_use_cheat_cmd()) {
if (!(rf::level.flags & rf::LEVEL_LOADED)) {
rf::console::print("No level loaded!");
}
else if (rf::is_multi) {
rf::console::print("That command can't be used in multiplayer.");
}
return;
}
if (rf::entity_is_flying(rf::local_player_entity)) {
rf::hud_msg("You feel heavy", 0, 0, 0);
} else {
rf::hud_msg("You feel lighter", 0, 0, 0);
}
heehoo_cmd_hook.call_target();
}
};

static void register_builtin_command(const char* name, const char* description, uintptr_t addr)
{
static std::vector<std::unique_ptr<rf::console::Command>> builtin_commands;
Expand Down Expand Up @@ -205,5 +264,11 @@ void console_commands_init()
map_cmd.register_cmd();
level_info_cmd.register_cmd();
map_info_cmd.register_cmd();

// Hooks for builtin commands
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
verify_level_cmd_hook.install();
camera1_cmd_hook.install();
camera2_cmd_hook.install();
camera3_cmd_hook.install();
heehoo_cmd_hook.install();
}
1 change: 1 addition & 0 deletions game_patch/rf/entity.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ namespace rf
static auto& entity_fire_init_bones = addr_as_ref<bool(EntityFireInfo *efi, Object *objp)>(0x0042EB20);
static auto& entity_is_swimming = addr_as_ref<bool(Entity* ep)>(0x0042A0A0);
static auto& entity_is_falling = addr_as_ref<bool(Entity* ep)>(0x0042A020);
static auto& entity_is_flying = addr_as_ref<bool(Entity* ep)>(0x0042A060);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static auto& entity_is_flying = addr_as_ref<bool(Entity* ep)>(0x0042A060);
static auto& entity_is_flying = addr_as_ref<bool(const Entity* ep)>(0x0042A060);

static auto& entity_can_swim = addr_as_ref<bool(Entity* ep)>(0x00427FF0);
static auto& entity_update_liquid_status = addr_as_ref<void(Entity* ep)>(0x00429100);
static auto& entity_is_playing_action_animation = addr_as_ref<bool(Entity* entity, int action)>(0x00428D10);
Expand Down
1 change: 1 addition & 0 deletions game_patch/rf/hud.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,5 @@ namespace rf
static auto& hud_weapon_cycle_current_idx = addr_as_ref<int>(0x007C71A8);

static auto& hud_do_frame = addr_as_ref<void(Player*)>(0x00437B80);
static auto& hud_msg = addr_as_ref<void(const char* text, int, int duration, Color*)>(0x004383C0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static auto& hud_msg = addr_as_ref<void(const char* text, int, int duration, Color*)>(0x004383C0);
static auto& hud_msg = addr_as_ref<void(const char* text, int, int duration, const Color*)>(0x004383C0);

}
2 changes: 2 additions & 0 deletions game_patch/rf/player/camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ namespace rf
AddrCaller{0x0040D780}.c_call(&result, camera);
return result;
}

static auto& camera_get_mode = addr_as_ref<CameraMode(rf::Camera*)>(0x0040D740);
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
}