Skip to content
This repository has been archived by the owner on Oct 4, 2024. It is now read-only.

Add /set and /heal console commands #30

Merged
merged 5 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
9 changes: 9 additions & 0 deletions include/libtrx/config/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

#include "config_option.h"

bool Config_Read(void);
bool Config_Write(void);
void Config_Sanitize(void);
void Config_ApplyChanges(void);
const CONFIG_OPTION *Config_GetOptionMap(void);
11 changes: 11 additions & 0 deletions include/libtrx/game/console/commands/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include "../../../config/config_option.h"
#include "../common.h"

extern CONSOLE_COMMAND g_Console_Cmd_Config;

const CONFIG_OPTION *Console_Cmd_Config_GetOptionFromKey(const char *key);
const CONFIG_OPTION *Console_Cmd_Config_GetOptionFromTarget(const void *target);
COMMAND_RESULT Console_Cmd_Config_Helper(
const CONFIG_OPTION *option, const char *new_value);
5 changes: 5 additions & 0 deletions include/libtrx/game/console/commands/heal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

#include "../common.h"

extern CONSOLE_COMMAND g_Console_Cmd_Heal;
7 changes: 7 additions & 0 deletions include/libtrx/game/game_string.def
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
GS_DEFINE(OSD_POS_GET, "Room: %d\nPosition: %.3f, %.3f, %.3f\nRotation: %.3f,%.3f,%.3f")
GS_DEFINE(OSD_CURRENT_HEALTH_GET, "Current Lara's health: %d")
GS_DEFINE(OSD_CURRENT_HEALTH_SET, "Lara's health set to %d")
GS_DEFINE(OSD_CONFIG_OPTION_GET, "%s is currently set to %s")
GS_DEFINE(OSD_CONFIG_OPTION_SET, "%s changed to %s")
GS_DEFINE(OSD_CONFIG_OPTION_UNKNOWN_OPTION, "Unknown option: %s")
GS_DEFINE(MISC_ON, "On")
GS_DEFINE(MISC_OFF, "Off")
GS_DEFINE(OSD_HEAL_ALREADY_FULL_HP, "Lara's already at full health")
GS_DEFINE(OSD_HEAL_SUCCESS, "Healed Lara back to full health")
3 changes: 3 additions & 0 deletions include/libtrx/game/lara/misc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

void Lara_Extinguish(void);
2 changes: 2 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ sources = [
'src/engine/image.c',
'src/enum_str.c',
'src/filesystem.c',
'src/game/console/commands/config.c',
'src/game/console/commands/heal.c',
'src/game/console/commands/pos.c',
'src/game/console/commands/set_health.c',
'src/game/items.c',
Expand Down
252 changes: 252 additions & 0 deletions src/game/console/commands/config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
#include "game/console/commands/config.h"

#include "config/config.h"
#include "config/config_map.h"
#include "game/game_string.h"
#include "memory.h"
#include "strings.h"

#include <assert.h>
#include <stdio.h>
#include <string.h>

static const char *Console_Cmd_Config_Resolve(const char *option_name);
static bool Console_Cmd_Config_SameKey(const char *key1, const char *key2);
static char *Console_Cmd_Config_NormalizeKey(const char *key);

static bool Console_Cmd_Config_GetCurrentValue(
const CONFIG_OPTION *option, char *target, size_t target_size);
static bool Console_Cmd_Config_SetCurrentValue(
const CONFIG_OPTION *option, const char *new_value);

static COMMAND_RESULT Console_Cmd_Set(const char *args);

static const char *Console_Cmd_Config_Resolve(const char *const option_name)
{
const char *dot = strrchr(option_name, '.');
if (dot) {
return dot + 1;
}
return option_name;
}

static bool Console_Cmd_Config_SameKey(const char *key1, const char *key2)
{
key1 = Console_Cmd_Config_Resolve(key1);
key2 = Console_Cmd_Config_Resolve(key2);
const size_t len1 = strlen(key1);
const size_t len2 = strlen(key2);
if (len1 != len2) {
return false;
}
for (uint32_t i = 0; i < len1; i++) {
char c1 = key1[i];
char c2 = key2[i];
if (c1 == '_') {
c1 = '-';
}
if (c2 == '_') {
c2 = '-';
}
if (c1 != c2) {
return false;
}
}
return true;
}

static char *Console_Cmd_Config_NormalizeKey(const char *key)
{
// TODO: Once we support arbitrary glyphs, this conversion should
// no longer be necessary.
char *result = Memory_DupStr(key);
for (uint32_t i = 0; i < strlen(result); i++) {
if (result[i] == '_') {
result[i] = '-';
}
}
return result;
}

static bool Console_Cmd_Config_GetCurrentValue(
const CONFIG_OPTION *const option, char *target, const size_t target_size)
{
if (option == NULL) {
return false;
}

assert(option->target != NULL);
switch (option->type) {
case COT_BOOL:
snprintf(
target, target_size, "%s",
*(bool *)option->target ? GS(MISC_ON) : GS(MISC_OFF));
break;
case COT_INT32:
snprintf(target, target_size, "%d", *(int32_t *)option->target);
break;
case COT_FLOAT:
snprintf(target, target_size, "%.2f", *(float *)option->target);
break;
case COT_DOUBLE:
snprintf(target, target_size, "%.2f", *(double *)option->target);
break;
case COT_ENUM:
for (const ENUM_STRING_MAP *enum_map = option->param;
enum_map->text != NULL; enum_map++) {
if (enum_map->value == *(int32_t *)option->target) {
strncpy(target, enum_map->text, target_size);
}
}
break;
}
return true;
}

static bool Console_Cmd_Config_SetCurrentValue(
const CONFIG_OPTION *const option, const char *const new_value)
{
if (option == NULL) {
return CR_BAD_INVOCATION;
}

assert(option->target != NULL);
switch (option->type) {
case COT_BOOL:
if (String_Match(new_value, "on|true|1")) {
*(bool *)option->target = true;
return true;
} else if (String_Match(new_value, "off|false|0")) {
*(bool *)option->target = false;
return true;
}
break;

case COT_INT32: {
int32_t new_value_typed;
if (sscanf(new_value, "%d", &new_value_typed) == 1) {
*(int32_t *)option->target = new_value_typed;
return true;
}
break;
}

case COT_FLOAT: {
float new_value_typed;
if (sscanf(new_value, "%f", &new_value_typed) == 1) {
*(float *)option->target = new_value_typed;
return true;
}
break;
}

case COT_DOUBLE: {
double new_value_typed;
if (sscanf(new_value, "%lf", &new_value_typed) == 1) {
*(double *)option->target = new_value_typed;
return true;
}
break;
}

case COT_ENUM:
for (const ENUM_STRING_MAP *enum_map = option->param;
enum_map->text != NULL; enum_map++) {
if (String_Equivalent(enum_map->text, new_value)) {
*(int32_t *)option->target = enum_map->value;
return true;
}
}
break;
}

return false;
}

const CONFIG_OPTION *Console_Cmd_Config_GetOptionFromKey(const char *const key)
{
for (const CONFIG_OPTION *option = Config_GetOptionMap();
option->name != NULL; option++) {
if (Console_Cmd_Config_SameKey(option->name, key)) {
return option;
}
}

return NULL;
}

const CONFIG_OPTION *Console_Cmd_Config_GetOptionFromTarget(
const void *const target)
{
for (const CONFIG_OPTION *option = Config_GetOptionMap();
option->name != NULL; option++) {
if (option->target == target) {
return option;
}
}

return NULL;
}

COMMAND_RESULT Console_Cmd_Config_Helper(
const CONFIG_OPTION *const option, const char *const new_value)
{
assert(option != NULL);

char *normalized_name = Console_Cmd_Config_NormalizeKey(option->name);

COMMAND_RESULT result = CR_BAD_INVOCATION;
if (new_value == NULL || String_IsEmpty(new_value)) {
char cur_value[128];
if (Console_Cmd_Config_GetCurrentValue(option, cur_value, 128)) {
Console_Log(GS(OSD_CONFIG_OPTION_GET), normalized_name, cur_value);
result = CR_SUCCESS;
}
}

if (Console_Cmd_Config_SetCurrentValue(option, new_value)) {
Config_Sanitize();
Config_Write();
Config_ApplyChanges();

char final_value[128];
assert(Console_Cmd_Config_GetCurrentValue(option, final_value, 128));
Console_Log(GS(OSD_CONFIG_OPTION_SET), normalized_name, final_value);
result = CR_SUCCESS;
}

cleanup:
Memory_FreePointer(&normalized_name);
return result;
}

static COMMAND_RESULT Console_Cmd_Config(const char *const args)
{
COMMAND_RESULT result = CR_BAD_INVOCATION;

char *key = Memory_DupStr(args);
char *const space = strchr(key, ' ');
const char *new_value = NULL;
if (space != NULL) {
new_value = space + 1;
space[0] = '\0'; // NULL-terminate the key
}

const CONFIG_OPTION *const option =
Console_Cmd_Config_GetOptionFromKey(key);
if (option == NULL) {
Console_Log(GS(OSD_CONFIG_OPTION_UNKNOWN_OPTION), key);
result = CR_FAILURE;
} else {
result = Console_Cmd_Config_Helper(option, new_value);
}

cleanup:
Memory_FreePointer(&key);
return result;
}

CONSOLE_COMMAND g_Console_Cmd_Config = {
.prefix = "set",
.proc = Console_Cmd_Config,
};
29 changes: 29 additions & 0 deletions src/game/console/commands/heal.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include "game/console/commands/heal.h"

#include "game/game.h"
#include "game/game_string.h"
#include "game/lara/common.h"
#include "game/lara/misc.h"

static COMMAND_RESULT Console_Cmd_Heal(const char *const args)
{
if (!Game_IsPlayable()) {
return CR_UNAVAILABLE;
}

ITEM_INFO *const lara_item = Lara_GetItem();
if (lara_item->hit_points == LARA_MAX_HITPOINTS) {
Console_Log(GS(OSD_HEAL_ALREADY_FULL_HP));
return CR_SUCCESS;
}

lara_item->hit_points = LARA_MAX_HITPOINTS;
Lara_Extinguish();
Console_Log(GS(OSD_HEAL_SUCCESS));
return CR_SUCCESS;
}

CONSOLE_COMMAND g_Console_Cmd_Heal = {
.prefix = "heal",
.proc = Console_Cmd_Heal,
};
3 changes: 2 additions & 1 deletion tools/additional_lint
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
from libtrx.cli.additional_lint import run_script
from libtrx.paths import LIBTRX_REPO_DIR

run_script(ignored_patterns=["*.patch", "*.bin", "gl_core_3_3.h"])
run_script(root_dir=LIBTRX_REPO_DIR, ignored_patterns=["*.patch", "*.bin", "gl_core_3_3.h"])
22 changes: 16 additions & 6 deletions tools/libtrx/cli/additional_lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from pathlib import Path

from libtrx.files import find_versioned_files, is_binary_file
from libtrx.linting import lint_file
from libtrx.linting import LintContext, lint_bulk_files, lint_file


def parse_args() -> argparse.Namespace:
Expand Down Expand Up @@ -37,22 +37,32 @@ def filter_files(


def run_script(
root_dir: Path | None = None, ignored_patterns: list[str] | None = None
root_dir: Path, ignored_patterns: list[str] | None = None
) -> None:
args = parse_args()

context = LintContext(
root_dir=root_dir,
versioned_files=find_versioned_files(root_dir=root_dir),
)
if args.path:
files = args.path
else:
files = find_versioned_files(root_dir=root_dir)

files = filter_files(files, ignored_patterns, debug=args.debug)
files = context.versioned_files
files = list(filter_files(files, ignored_patterns, debug=args.debug))

exit_code = 0
for file in files:
if args.debug:
print(f"Checking {file}...", file=sys.stderr)
for lint_warning in lint_file(file):
for lint_warning in lint_file(context, file):
print(str(lint_warning), file=sys.stderr)
exit_code = 1

if args.debug:
print(f"Checking files in bulk {file}...", file=sys.stderr)
for lint_warning in lint_bulk_files(context, files):
print(str(lint_warning), file=sys.stderr)
exit_code = 1

exit(exit_code)
Loading