- pots canviar el color del jugador desde la consola (persistent)
- cokmprova que el color no siga el mateix que el del fono (canvia a default) - eliminades animacions sobrants del jugador - canviada la logica del marcador pero a mostrar la animació de les vides del jugador - posibilitat d'utilitzar skins d'enemics en el jugador - canvi en calent de la skin en el marcador (abans soles en el constructir)
This commit is contained in:
@@ -108,21 +108,24 @@ categories:
|
||||
|
||||
- name: GAME
|
||||
commands:
|
||||
- keyword: PLAYER
|
||||
handler: cmd_player
|
||||
description: "Player skin and color"
|
||||
usage: "PLAYER SKIN <name> | PLAYER COLOR <0-15>|DEFAULT"
|
||||
completions:
|
||||
PLAYER: [SKIN, COLOR]
|
||||
PLAYER SKIN: [DEFAULT, ABAD, BATMAN, CHIP, CONGO, JEANNINE, MUMMY, UPV_STUDENT]
|
||||
PLAYER COLOR: [DEFAULT]
|
||||
|
||||
- keyword: SET
|
||||
handler: cmd_set
|
||||
description: "Change player skin"
|
||||
usage: "SET PLAYER SKIN <1|2>"
|
||||
description: "Set debug options"
|
||||
usage: "SET INITIAL [ROOM|POS|SCENE] | SET ITEMS <0-200>"
|
||||
debug_only: true
|
||||
completions:
|
||||
SET: [PLAYER]
|
||||
SET PLAYER: [SKIN]
|
||||
debug_extras:
|
||||
description: "Set player/debug options"
|
||||
usage: "SET PLAYER SKIN <1|2> | SET INITIAL [ROOM|POS|SCENE] | SET ITEMS <0-200>"
|
||||
completions:
|
||||
SET: [PLAYER, INITIAL, ITEMS]
|
||||
SET PLAYER: [SKIN]
|
||||
SET INITIAL: [ROOM, POS, SCENE]
|
||||
SET INITIAL SCENE: [LOGO, LOADING, TITLE, CREDITS, GAME, ENDING, ENDING2]
|
||||
SET: [INITIAL, ITEMS]
|
||||
SET INITIAL: [ROOM, POS, SCENE]
|
||||
SET INITIAL SCENE: [LOGO, LOADING, TITLE, CREDITS, GAME, ENDING, ENDING2]
|
||||
|
||||
- keyword: RESTART
|
||||
handler: cmd_restart
|
||||
|
||||
@@ -4,17 +4,7 @@ frameWidth: 8
|
||||
frameHeight: 16
|
||||
|
||||
animations:
|
||||
- name: stand
|
||||
speed: 0.1333
|
||||
loop: 0
|
||||
frames: [0]
|
||||
|
||||
- name: walk
|
||||
- name: default
|
||||
speed: 0.1333
|
||||
loop: 0
|
||||
frames: [0, 1, 2, 3]
|
||||
|
||||
- name: walk_menu
|
||||
speed: 0.0
|
||||
loop: 0
|
||||
frames: [0, 1, 2, 3]
|
||||
|
||||
@@ -4,17 +4,7 @@ frameWidth: 8
|
||||
frameHeight: 16
|
||||
|
||||
animations:
|
||||
- name: stand
|
||||
speed: 0.1333
|
||||
loop: 0
|
||||
frames: [0]
|
||||
|
||||
- name: walk
|
||||
- name: default
|
||||
speed: 0.1333
|
||||
loop: 0
|
||||
frames: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
|
||||
- name: walk_menu
|
||||
speed: 0.0
|
||||
loop: 0
|
||||
frames: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
|
||||
@@ -101,5 +101,6 @@ namespace Defaults::Game::Player {
|
||||
constexpr int SPAWN_X = 25 * Tile::SIZE; // Posición X inicial
|
||||
constexpr int SPAWN_Y = 13 * Tile::SIZE; // Posición Y inicial
|
||||
constexpr SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación inicial
|
||||
constexpr int SKIN = 1; // Skin del jugador por defecto (1=normal, 2=alternativa)
|
||||
constexpr const char* SKIN = "default"; // Skin del jugador por defecto
|
||||
constexpr int COLOR = -1; // Color del jugador (-1 = automático según cheats)
|
||||
} // namespace Defaults::Game::Player
|
||||
|
||||
@@ -620,20 +620,31 @@ auto Player::handleKillingTiles() -> bool {
|
||||
return false; // No se encontró ninguna colisión
|
||||
}
|
||||
|
||||
// Establece el color del jugador (0 = automático según cheats)
|
||||
// Establece el color del jugador (0 = automático según cheats/options)
|
||||
void Player::setColor(Uint8 color) {
|
||||
if (color != 0) {
|
||||
color_ = color;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Options::cheats.invincible == Options::Cheat::State::ENABLED) {
|
||||
// Color personalizado desde opciones (prioridad sobre cheats)
|
||||
if (Options::game.player_color >= 0) {
|
||||
color_ = static_cast<Uint8>(Options::game.player_color);
|
||||
} else if (Options::cheats.invincible == Options::Cheat::State::ENABLED) {
|
||||
// Color automático según cheats
|
||||
color_ = static_cast<Uint8>(PaletteColor::CYAN);
|
||||
} else if (Options::cheats.infinite_lives == Options::Cheat::State::ENABLED) {
|
||||
color_ = static_cast<Uint8>(PaletteColor::YELLOW);
|
||||
} else {
|
||||
color_ = static_cast<Uint8>(PaletteColor::WHITE);
|
||||
}
|
||||
|
||||
// Si el color coincide con el fondo de la habitación, usar fallback
|
||||
if (room_ != nullptr && color_ == room_->getBGColor()) {
|
||||
color_ = (room_->getBGColor() != static_cast<Uint8>(PaletteColor::WHITE))
|
||||
? static_cast<Uint8>(PaletteColor::WHITE)
|
||||
: static_cast<Uint8>(PaletteColor::BRIGHT_BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza los puntos de colisión
|
||||
@@ -765,11 +776,18 @@ void Player::applySpawnValues(const SpawnData& spawn) {
|
||||
sprite_->setFlip(spawn.flip);
|
||||
}
|
||||
|
||||
// Resuelve nombre de skin a fichero de animación
|
||||
auto Player::skinToAnimationPath(const std::string& skin_name) -> std::string {
|
||||
if (skin_name == "default") {
|
||||
return "player.yaml";
|
||||
}
|
||||
return skin_name + ".yaml";
|
||||
}
|
||||
|
||||
// Cambia la skin del jugador en caliente preservando la orientación actual
|
||||
void Player::setSkin(int skin_num) {
|
||||
void Player::setSkin(const std::string& skin_name) {
|
||||
const auto FLIP = sprite_->getFlip();
|
||||
const std::string PATH = (skin_num == 2) ? "player2.yaml" : "player.yaml";
|
||||
initSprite(PATH);
|
||||
initSprite(skinToAnimationPath(skin_name));
|
||||
sprite_->setFlip(FLIP);
|
||||
}
|
||||
|
||||
@@ -779,7 +797,7 @@ void Player::initSprite(const std::string& animations_path) { // NOLINT(readabi
|
||||
sprite_ = std::make_unique<AnimatedSprite>(animation_data);
|
||||
sprite_->setWidth(WIDTH);
|
||||
sprite_->setHeight(HEIGHT);
|
||||
sprite_->setCurrentAnimation("walk");
|
||||
sprite_->setCurrentAnimation("default");
|
||||
}
|
||||
|
||||
// Actualiza la posición del sprite y las colisiones
|
||||
|
||||
@@ -100,7 +100,8 @@ class Player {
|
||||
auto getCollider() -> SDL_FRect& { return collider_box_; } // Obtiene el rectangulo de colision del jugador
|
||||
auto getSpawnParams() -> SpawnData { return {.x = x_, .y = y_, .vx = vx_, .vy = vy_, .last_grounded_position = last_grounded_position_, .state = state_, .flip = sprite_->getFlip()}; } // Obtiene el estado de reaparición del jugador
|
||||
void setColor(Uint8 color = 0); // Establece el color del jugador (0 = automático según cheats)
|
||||
void setSkin(int skin_num); // Cambia la skin del jugador en caliente (1=normal, 2=alternativa)
|
||||
void setSkin(const std::string& skin_name); // Cambia la skin del jugador en caliente ("default" o nombre de enemigo)
|
||||
static auto skinToAnimationPath(const std::string& skin_name) -> std::string; // Resuelve nombre de skin a fichero de animación
|
||||
void setRoom(std::shared_ptr<Room> room) { room_ = std::move(room); } // Establece la habitación en la que se encuentra el jugador
|
||||
//[[nodiscard]] auto isAlive() const -> bool { return is_alive_ || (Options::cheats.invincible == Options::Cheat::State::ENABLED); } // Comprueba si el jugador esta vivo
|
||||
[[nodiscard]] auto isAlive() const -> bool { return is_alive_; } // Comprueba si el jugador esta vivo
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
namespace GameControl {
|
||||
// Disponible en todos los builds — refresca el color del jugador según cheats
|
||||
inline std::function<void()> refresh_player_color;
|
||||
// Disponible en todos los builds — cambia la skin del jugador (1=normal, 2=alternativa)
|
||||
inline std::function<void(int)> change_player_skin;
|
||||
// Disponible en todos los builds — cambia la skin del jugador ("default" o nombre de enemigo)
|
||||
inline std::function<void(const std::string&)> change_player_skin;
|
||||
// Disponible en todos los builds — cambia el color del jugador (-1 = automático, 0-15 = color fijo)
|
||||
inline std::function<void(int)> change_player_color;
|
||||
} // namespace GameControl
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "core/rendering/surface.hpp" // Para Surface
|
||||
#include "core/rendering/text.hpp" // Para Text
|
||||
#include "core/resources/resource_cache.hpp" // Para Resource
|
||||
#include "game/entities/player.hpp" // Para Player::skinToAnimationPath
|
||||
#include "game/options.hpp" // Para Options, options, Cheat, OptionsGame
|
||||
#include "utils/defines.hpp" // Para BLOCK
|
||||
#include "utils/utils.hpp" // Para stringToColor
|
||||
@@ -22,9 +23,10 @@ Scoreboard::Scoreboard(std::shared_ptr<Data> data)
|
||||
constexpr float SURFACE_HEIGHT = 6.0F * Tile::SIZE;
|
||||
|
||||
// Reserva memoria para los objetos
|
||||
const auto& player_animation_data = Resource::Cache::get()->getAnimationData((Options::game.player_skin == 2) ? "player2.yaml" : "player.yaml");
|
||||
const std::string player_anim_path = Player::skinToAnimationPath(Options::game.player_skin);
|
||||
const auto& player_animation_data = Resource::Cache::get()->getAnimationData(player_anim_path);
|
||||
player_sprite_ = std::make_shared<AnimatedSprite>(player_animation_data);
|
||||
player_sprite_->setCurrentAnimation("walk_menu");
|
||||
player_sprite_->setCurrentAnimation("default");
|
||||
|
||||
surface_ = std::make_shared<Surface>(SURFACE_WIDTH, SURFACE_HEIGHT);
|
||||
surface_dest_ = {.x = 0, .y = Options::game.height - SURFACE_HEIGHT, .w = SURFACE_WIDTH, .h = SURFACE_HEIGHT};
|
||||
@@ -49,9 +51,6 @@ void Scoreboard::update(float delta_time) {
|
||||
// Acumular tiempo para animaciones
|
||||
time_accumulator_ += delta_time;
|
||||
|
||||
// Actualizar sprite con delta time
|
||||
player_sprite_->update(delta_time);
|
||||
|
||||
// Actualiza el color de la cantidad de items recogidos
|
||||
updateItemsColor(delta_time);
|
||||
|
||||
@@ -77,6 +76,14 @@ auto Scoreboard::getTime() -> Scoreboard::ClockData { // NOLINT(readability-con
|
||||
return time;
|
||||
}
|
||||
|
||||
// Actualiza el sprite del jugador con la skin actual
|
||||
void Scoreboard::refreshPlayerSkin() {
|
||||
const std::string player_anim_path = Player::skinToAnimationPath(Options::game.player_skin);
|
||||
const auto& player_animation_data = Resource::Cache::get()->getAnimationData(player_anim_path);
|
||||
player_sprite_ = std::make_shared<AnimatedSprite>(player_animation_data);
|
||||
player_sprite_->setCurrentAnimation("default");
|
||||
}
|
||||
|
||||
// Pone el marcador en modo pausa
|
||||
void Scoreboard::setPaused(bool value) {
|
||||
if (is_paused_ == value) {
|
||||
@@ -136,8 +143,9 @@ void Scoreboard::fillTexture() {
|
||||
|
||||
// Dibuja las vidas
|
||||
// Calcular desplazamiento basado en tiempo
|
||||
const int DESP = static_cast<int>(time_accumulator_ / SPRITE_WALK_CYCLE_DURATION) % 8;
|
||||
const int FRAME = DESP % SPRITE_WALK_FRAMES;
|
||||
const int WALK_FRAMES = player_sprite_->getCurrentAnimationSize();
|
||||
const int DESP = static_cast<int>(time_accumulator_ / SPRITE_WALK_CYCLE_DURATION) % (WALK_FRAMES * 2);
|
||||
const int FRAME = DESP % WALK_FRAMES;
|
||||
player_sprite_->setCurrentAnimationFrame(FRAME);
|
||||
player_sprite_->setPosY(LINE2);
|
||||
for (int i = 0; i < data_->lives; ++i) {
|
||||
|
||||
@@ -28,6 +28,7 @@ class Scoreboard {
|
||||
void render(); // Pinta el objeto en pantalla
|
||||
void update(float delta_time); // Actualiza las variables del objeto
|
||||
void setPaused(bool value); // Pone el marcador en modo pausa
|
||||
void refreshPlayerSkin(); // Actualiza el sprite del jugador con la skin actual
|
||||
auto getMinutes() -> int; // Devuelve la cantidad de minutos de juego transcurridos
|
||||
|
||||
private:
|
||||
@@ -42,7 +43,6 @@ class Scoreboard {
|
||||
// Constantes de tiempo
|
||||
static constexpr float ITEMS_COLOR_BLINK_DURATION = 0.333F; // Duración de cada estado del parpadeo (era 10 frames @ 60fps)
|
||||
static constexpr float SPRITE_WALK_CYCLE_DURATION = 0.667F; // Duración del ciclo de caminar (era 40 frames @ 60fps)
|
||||
static constexpr int SPRITE_WALK_FRAMES = 4; // Número de frames de animación
|
||||
|
||||
// Métodos privados
|
||||
auto getTime() -> ClockData; // Obtiene el tiempo transcurrido de partida
|
||||
|
||||
@@ -510,12 +510,19 @@ namespace Options {
|
||||
const auto& player_node = yaml["player"];
|
||||
if (player_node.contains("skin")) {
|
||||
try {
|
||||
int skin = player_node["skin"].get_value<int>();
|
||||
game.player_skin = (skin == 2) ? 2 : Defaults::Game::Player::SKIN;
|
||||
game.player_skin = player_node["skin"].get_value<std::string>();
|
||||
} catch (...) {
|
||||
game.player_skin = Defaults::Game::Player::SKIN;
|
||||
}
|
||||
}
|
||||
if (player_node.contains("color")) {
|
||||
try {
|
||||
int color = player_node["color"].get_value<int>();
|
||||
game.player_color = (color >= 0 && color <= 15) ? color : Defaults::Game::Player::COLOR;
|
||||
} catch (...) {
|
||||
game.player_color = Defaults::Game::Player::COLOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -778,7 +785,8 @@ namespace Options {
|
||||
file << "\n";
|
||||
file << "# PLAYER\n";
|
||||
file << "player:\n";
|
||||
file << " skin: " << game.player_skin << "\n";
|
||||
file << " skin: \"" << game.player_skin << "\"\n";
|
||||
file << " color: " << game.player_color << "\n";
|
||||
file << "\n";
|
||||
|
||||
file << "# KIOSK MODE\n";
|
||||
|
||||
@@ -137,7 +137,8 @@ namespace Options {
|
||||
struct Game {
|
||||
float width{Defaults::Canvas::WIDTH}; // Ancho de la resolucion del juego
|
||||
float height{Defaults::Canvas::HEIGHT}; // Alto de la resolucion del juego
|
||||
int player_skin{Defaults::Game::Player::SKIN}; // Skin del jugador (1=normal, 2=alternativa)
|
||||
std::string player_skin{Defaults::Game::Player::SKIN}; // Skin del jugador ("default" o nombre de enemigo)
|
||||
int player_color{Defaults::Game::Player::COLOR}; // Color del jugador (-1 = automático, 0-15 = color fijo)
|
||||
};
|
||||
|
||||
// Estructura para un preset de PostFX
|
||||
|
||||
@@ -391,7 +391,7 @@ void Ending2::placeSprites() const {
|
||||
const float X = (Options::game.width - sprites_.back()->getWidth()) / 2;
|
||||
const float Y = sprites_.back()->getPosY() + (sprite_max_height_ * 2);
|
||||
sprites_.back()->setPos(X, Y);
|
||||
sprites_.back()->setCurrentAnimation("walk");
|
||||
sprites_.back()->setCurrentAnimation("default");
|
||||
}
|
||||
|
||||
// Crea los sprites con las texturas con los textos
|
||||
|
||||
@@ -67,9 +67,14 @@ Game::Game(Mode mode)
|
||||
GameControl::refresh_player_color = [this]() -> void { player_->setColor(); };
|
||||
Console::get()->on_toggle = [this](bool open) { player_->setIgnoreInput(open); };
|
||||
if (Console::get()->isActive()) { player_->setIgnoreInput(true); }
|
||||
GameControl::change_player_skin = [this](int skin_num) -> void {
|
||||
Options::game.player_skin = skin_num;
|
||||
player_->setSkin(skin_num);
|
||||
GameControl::change_player_skin = [this](const std::string& skin_name) -> void {
|
||||
Options::game.player_skin = skin_name;
|
||||
player_->setSkin(skin_name);
|
||||
scoreboard_->refreshPlayerSkin();
|
||||
};
|
||||
GameControl::change_player_color = [this](int color) -> void {
|
||||
Options::game.player_color = color;
|
||||
player_->setColor();
|
||||
};
|
||||
|
||||
#ifdef _DEBUG
|
||||
@@ -126,6 +131,7 @@ Game::~Game() {
|
||||
|
||||
GameControl::refresh_player_color = nullptr;
|
||||
GameControl::change_player_skin = nullptr;
|
||||
GameControl::change_player_color = nullptr;
|
||||
Console::get()->on_toggle = nullptr;
|
||||
|
||||
#ifdef _DEBUG
|
||||
@@ -655,6 +661,9 @@ auto Game::changeRoom(const std::string& room_path) -> bool {
|
||||
// Pasa la nueva habitación al jugador
|
||||
player_->setRoom(room_);
|
||||
|
||||
// Recalcula el color del jugador (evita coincidir con el fondo)
|
||||
player_->setColor();
|
||||
|
||||
// Cambia la habitación actual
|
||||
current_room_ = room_path;
|
||||
|
||||
@@ -901,7 +910,7 @@ void Game::checkEndGameCheevos() { // NOLINT(readability-convert-member-functio
|
||||
// Inicializa al jugador
|
||||
void Game::initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr<Room> room) { // NOLINT(readability-convert-member-functions-to-static)
|
||||
const bool IGNORE_INPUT = player_ != nullptr && player_->getIgnoreInput();
|
||||
std::string player_animations = (Options::game.player_skin == 2) ? "player2.yaml" : "player.yaml";
|
||||
std::string player_animations = Player::skinToAnimationPath(Options::game.player_skin);
|
||||
const Player::Data PLAYER{.spawn_data = spawn_point, .animations_path = player_animations, .room = std::move(room)};
|
||||
player_ = std::make_shared<Player>(PLAYER);
|
||||
if (IGNORE_INPUT) { player_->setIgnoreInput(true); }
|
||||
|
||||
@@ -623,19 +623,41 @@ static auto cmd_cheat(const std::vector<std::string>& args) -> std::string {
|
||||
return "usage: cheat [infinite lives|invincibility|open the jail|close the jail]";
|
||||
}
|
||||
|
||||
// SET PLAYER SKIN / SET INITIAL / SET ITEMS
|
||||
static auto cmd_set(const std::vector<std::string>& args) -> std::string {
|
||||
if (args.size() >= 3 && args[0] == "PLAYER" && args[1] == "SKIN") {
|
||||
if (SceneManager::current != SceneManager::Scene::GAME) { return "Only available in GAME scene"; }
|
||||
int num = 0;
|
||||
try {
|
||||
num = std::stoi(args[2]);
|
||||
} catch (...) {}
|
||||
if (num < 1 || num > 2) { return "usage: set player skin <1|2>"; }
|
||||
// PLAYER SKIN / PLAYER COLOR
|
||||
static auto cmd_player(const std::vector<std::string>& args) -> std::string {
|
||||
if (SceneManager::current != SceneManager::Scene::GAME) { return "Only available in GAME scene"; }
|
||||
|
||||
// PLAYER SKIN <name>
|
||||
if (args.size() >= 2 && args[0] == "SKIN") {
|
||||
if (!GameControl::change_player_skin) { return "Game not initialized"; }
|
||||
GameControl::change_player_skin(num);
|
||||
return "Player skin: " + std::to_string(num);
|
||||
std::string skin_name = args[1];
|
||||
std::ranges::transform(skin_name, skin_name.begin(), ::tolower);
|
||||
GameControl::change_player_skin(skin_name);
|
||||
return "Player skin: " + skin_name;
|
||||
}
|
||||
|
||||
// PLAYER COLOR DEFAULT
|
||||
if (args.size() >= 2 && args[0] == "COLOR" && args[1] == "DEFAULT") {
|
||||
if (!GameControl::change_player_color) { return "Game not initialized"; }
|
||||
GameControl::change_player_color(-1);
|
||||
return "Player color: default";
|
||||
}
|
||||
|
||||
// PLAYER COLOR <0-15>
|
||||
if (args.size() >= 2 && args[0] == "COLOR") {
|
||||
int color = -1;
|
||||
try { color = std::stoi(args[1]); } catch (...) {}
|
||||
if (color < 0 || color > 15) { return "usage: player color <0-15>|default"; }
|
||||
if (!GameControl::change_player_color) { return "Game not initialized"; }
|
||||
GameControl::change_player_color(color);
|
||||
return "Player color: " + std::to_string(color);
|
||||
}
|
||||
|
||||
return "usage: player skin <name> | player color <0-15>|default";
|
||||
}
|
||||
|
||||
// SET INITIAL / SET ITEMS
|
||||
static auto cmd_set(const std::vector<std::string>& args) -> std::string {
|
||||
#ifdef _DEBUG
|
||||
// SET INITIAL SCENE [<nombre>]
|
||||
if (args.size() >= 2 && args[0] == "INITIAL" && args[1] == "SCENE") {
|
||||
@@ -689,7 +711,7 @@ static auto cmd_set(const std::vector<std::string>& args) -> std::string {
|
||||
return "Items: " + std::to_string(count);
|
||||
}
|
||||
|
||||
if (args.empty() || args[0] != "INITIAL") { return "usage: set initial [room|pos|scene] | set items <0-200> | set player skin <1|2>"; }
|
||||
if (args.empty() || args[0] != "INITIAL") { return "usage: set initial [room|pos|scene] | set items <0-200>"; }
|
||||
|
||||
const bool DO_ROOM = args.size() == 1 || (args.size() >= 2 && args[1] == "ROOM");
|
||||
const bool DO_POS = args.size() == 1 || (args.size() >= 2 && args[1] == "POS");
|
||||
@@ -705,7 +727,7 @@ static auto cmd_set(const std::vector<std::string>& args) -> std::string {
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
return "usage: set player skin <1|2>";
|
||||
return "Debug only command";
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -771,6 +793,7 @@ void CommandRegistry::registerHandlers() {
|
||||
handlers_["cmd_show"] = cmd_show;
|
||||
handlers_["cmd_hide"] = cmd_hide;
|
||||
handlers_["cmd_cheat"] = cmd_cheat;
|
||||
handlers_["cmd_player"] = cmd_player;
|
||||
handlers_["cmd_set"] = cmd_set;
|
||||
handlers_["cmd_restart"] = cmd_restart;
|
||||
handlers_["cmd_kiosk"] = cmd_kiosk;
|
||||
|
||||
Reference in New Issue
Block a user