mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 22:56:30 -10:00
* use std::move() for local variables that are copied but not reused Addresses ~140 Coverity "Variable copied when it could be moved" defects across 74 files. Every std::move() targets a local variable whose value is consumed by push_back, emplace, assignment, lambda capture, or a function call and is never read again afterward. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * clang: use std::make_shared * clang: use std::make_unique * address feedback --------- Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
186 lines
5.6 KiB
C++
186 lines
5.6 KiB
C++
#include "cheats_table.h"
|
|
#include "parse/parselo.h"
|
|
|
|
void cheat_table_init() {
|
|
customCheats.clear();
|
|
|
|
if (cf_exists_full("cheats.tbl", CF_TYPE_TABLES)) {
|
|
parse_cheat_table("cheats.tbl");
|
|
}
|
|
parse_modular_table("*-cht.tbm", parse_cheat_table);
|
|
}
|
|
|
|
bool CustomCheat::canUseCheat() {
|
|
return !requireCheatsEnabled || Cheats_enabled;
|
|
}
|
|
|
|
void CustomCheat::runCheat() {
|
|
if (!canUseCheat()) return;
|
|
|
|
//Only try to send the message if we actually have one to send and are in a mission
|
|
if (!cheatMsg.empty() && (Game_mode & GM_IN_MISSION))
|
|
HUD_printf("%s", cheatMsg.c_str());
|
|
|
|
scripting::hooks::OnCheat->run(scripting::hook_param_list(scripting::hook_param("Cheat", 's', cheatCode)));
|
|
CheatUsed = cheatCode;
|
|
}
|
|
|
|
void SpawnShipCheat::runCheat() {
|
|
CustomCheat::runCheat();
|
|
|
|
if (canUseCheat() && (Game_mode & GM_IN_MISSION) && Player_obj != nullptr) {
|
|
extern void prevent_spawning_collision(object *new_obj);
|
|
ship_subsys *ptr;
|
|
char name[NAME_LENGTH];
|
|
int ship_idx, ship_class;
|
|
|
|
// if not found, then don't create it :(
|
|
ship_class = ship_info_lookup(shipClassName.c_str());
|
|
if (ship_class < 0)
|
|
return;
|
|
|
|
vec3d pos = Player_obj->pos;
|
|
matrix orient = Player_obj->orient;
|
|
pos.xyz.x += frand_range(-700.0f, 700.0f);
|
|
pos.xyz.y += frand_range(-700.0f, 700.0f);
|
|
pos.xyz.z += frand_range(-700.0f, 700.0f);
|
|
|
|
int objnum = ship_create(&orient, &pos, ship_class);
|
|
if (objnum < 0)
|
|
return;
|
|
|
|
ship *shipp = &Ships[Objects[objnum].instance];
|
|
shipp->ship_name[0] = '\0';
|
|
shipp->display_name.clear();
|
|
for (size_t j = 0; j < Player_orders.size(); j++)
|
|
shipp->orders_accepted.insert(j);
|
|
|
|
// Goober5000 - stolen from support ship creation
|
|
// create a name for the ship with a number. look for collisions until one isn't found anymore
|
|
ship_idx = 1;
|
|
do {
|
|
sprintf(name, "%s %d", shipName.c_str(), ship_idx);
|
|
if ( (ship_name_lookup(name) == -1) && (ship_find_exited_ship_by_name(name) == -1) )
|
|
{
|
|
strcpy_s(shipp->ship_name, name);
|
|
break;
|
|
}
|
|
|
|
ship_idx++;
|
|
} while(1);
|
|
|
|
shipp->flags.set(Ship::Ship_Flags::Escort);
|
|
shipp->escort_priority = 1000 - ship_idx;
|
|
|
|
// now make sure we're not colliding with anyone
|
|
prevent_spawning_collision(&Objects[objnum]);
|
|
|
|
// Goober5000 - beam free
|
|
for (ptr = GET_FIRST(&shipp->subsys_list); ptr != END_OF_LIST(&shipp->subsys_list); ptr = GET_NEXT(ptr))
|
|
{
|
|
// mark all turrets as beam free
|
|
if (ptr->system_info->type == SUBSYSTEM_TURRET)
|
|
{
|
|
ptr->weapons.flags.set(Ship::Weapon_Flags::Beam_Free);
|
|
ptr->turret_next_fire_stamp = timestamp(Random::next(50, 4000));
|
|
}
|
|
}
|
|
|
|
// Cyborg17 to prevent a nullptr...
|
|
ship_set_warp_effects(&Objects[objnum]);
|
|
// warpin
|
|
shipfx_warpin_start(&Objects[objnum]);
|
|
}
|
|
}
|
|
|
|
void parse_cheat_table(const char* filename) {
|
|
try {
|
|
read_file_text(filename, CF_TYPE_TABLES);
|
|
reset_parse();
|
|
optional_string("#CUSTOM CHEATS");
|
|
|
|
while (optional_string("$Cheat:")) {
|
|
SCP_string code, msg, shipClass, shipName;
|
|
bool requireCheats = false;
|
|
bool shipSpawn = false;
|
|
required_string("+Code:");
|
|
stuff_string(code, F_RAW);
|
|
|
|
//We are limited to the buffer size used for the traditional cheats. We can still use short cheats, though.
|
|
if (code.length() > CHEAT_BUFFER_LEN) {
|
|
Warning(LOCATION, "Cheat code %s is too long. It will be cut off to maximum length (%i characters).", code.c_str(), CHEAT_BUFFER_LEN);
|
|
code = code.substr(0, CHEAT_BUFFER_LEN);
|
|
}
|
|
|
|
if (optional_string("+Message:")) {
|
|
stuff_string(msg, F_MESSAGE);
|
|
}
|
|
|
|
if (optional_string("+RequireCheats:")) {
|
|
stuff_boolean(&requireCheats);
|
|
}
|
|
|
|
if (optional_string("+SpawnShip:")) {
|
|
shipSpawn = true;
|
|
required_string("+Name:");
|
|
stuff_string(shipName, F_NAME);
|
|
required_string("+Class:");
|
|
stuff_string(shipClass, F_NAME);
|
|
|
|
int shipClassInfo = ship_info_lookup(shipClass.c_str());
|
|
if (shipClassInfo < 0) {
|
|
shipSpawn = false;
|
|
Warning(LOCATION, "There is no ship class named '%s'. The '%s' cheat won't summon a ship.", shipClass.c_str(), code.c_str());
|
|
}
|
|
}
|
|
|
|
if (shipSpawn) {
|
|
std::unique_ptr<CustomCheat> shipCheat(new SpawnShipCheat(code, std::move(msg), requireCheats, std::move(shipClass), std::move(shipName)));
|
|
|
|
if(customCheats.count(code) == 1) {
|
|
Warning(LOCATION, "A cheat for code '%s' already exists. It will be replaced.", code.c_str());
|
|
customCheats[code] = std::move(shipCheat);
|
|
} else {
|
|
customCheats.emplace(code, std::move(shipCheat));
|
|
}
|
|
} else {
|
|
std::unique_ptr<CustomCheat> cheat(new CustomCheat(code, std::move(msg), requireCheats));
|
|
|
|
if(customCheats.count(code) == 1) {
|
|
Warning(LOCATION, "A cheat for code '%s' already exists. It will be replaced.", code.c_str());
|
|
customCheats[code] = std::move(cheat);
|
|
} else {
|
|
customCheats.emplace(code, std::move(cheat));
|
|
}
|
|
}
|
|
}
|
|
required_string("#END");
|
|
}
|
|
catch (const parse::ParseException& e) {
|
|
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool checkForCustomCheats(const char* buffer, int buffer_length) {
|
|
const char* check_buffer = buffer;
|
|
for (int i = 0; i < buffer_length; i++) {
|
|
if (*check_buffer == '\0') {
|
|
check_buffer++;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Loop through our map of custom cheats and check if the code is within the buffer.
|
|
// We don't just check for equality, as the player may have typed other characters before the cheat.
|
|
for (auto &ccheat : customCheats) {
|
|
auto found = std::strstr(check_buffer, ccheat.first.c_str());
|
|
if (found != nullptr) {
|
|
ccheat.second->runCheat();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
} |