231 lines
6.9 KiB
C++
231 lines
6.9 KiB
C++
#include "vehicle_tuning.hpp"
|
|
|
|
#include "assets/cmdfile.hpp"
|
|
|
|
#include <iomanip>
|
|
|
|
static float game::VehicleTuningContext::* GetCtxVariablePointer(const std::string& name)
|
|
{
|
|
if (name == "mass")
|
|
return &game::VehicleTuningContext::mass;
|
|
if (name == "engine_force")
|
|
return &game::VehicleTuningContext::engine_force;
|
|
if (name == "braking_force")
|
|
return &game::VehicleTuningContext::braking_force;
|
|
|
|
throw std::runtime_error("tuning list: invalid variable " + name);
|
|
}
|
|
|
|
static float game::VehicleWheelTuningContext::* GetWheelVariablePointer(const std::string& name)
|
|
{
|
|
if (name == "radius")
|
|
return &game::VehicleWheelTuningContext::radius;
|
|
if (name == "z_offset")
|
|
return &game::VehicleWheelTuningContext::z_offset;
|
|
if (name == "friction")
|
|
return &game::VehicleWheelTuningContext::friction;
|
|
if (name == "suspension_stiffness")
|
|
return &game::VehicleWheelTuningContext::suspension_stiffness;
|
|
if (name == "suspension_max_force")
|
|
return &game::VehicleWheelTuningContext::suspension_max_force;
|
|
if (name == "suspension_rest_length")
|
|
return &game::VehicleWheelTuningContext::suspension_rest_length;
|
|
if (name == "suspension_travel")
|
|
return &game::VehicleWheelTuningContext::suspension_travel;
|
|
if (name == "roll_influence")
|
|
return &game::VehicleWheelTuningContext::roll_influence;
|
|
if (name == "steering_factor")
|
|
return &game::VehicleWheelTuningContext::steering_factor;
|
|
if (name == "braking_factor")
|
|
return &game::VehicleWheelTuningContext::braking_factor;
|
|
if (name == "engine_factor")
|
|
return &game::VehicleWheelTuningContext::engine_factor;
|
|
|
|
throw std::runtime_error("tuning list: invalid wheel variable " + name);
|
|
}
|
|
|
|
static void ApplyOp(float& var, const std::string& op, float value)
|
|
{
|
|
if (op == "+=")
|
|
var += value;
|
|
else if (op == "-=")
|
|
var -= value;
|
|
else if (op == "*=")
|
|
var *= value;
|
|
else if (op == "/=")
|
|
var /= value;
|
|
else
|
|
var = value;
|
|
}
|
|
|
|
static bool CheckWheelCond(const game::VehicleWheelTuningContext& wheel_ctx, const std::string& cond)
|
|
{
|
|
if (cond == "front" && !wheel_ctx.front)
|
|
return false;
|
|
|
|
if (cond == "rear" && wheel_ctx.front)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static uint32_t ParseColor(uint32_t c)
|
|
{
|
|
auto r = (c >> 16) & 0xFF;
|
|
auto g = (c >> 8) & 0xFF;
|
|
auto b = c & 0xFF;
|
|
return 0xFF000000 | (b << 16) | (g << 8) | r;
|
|
}
|
|
|
|
static game::VehicleTuningFunction ParseTuningFunction(std::istringstream& iss)
|
|
{
|
|
std::string func_name;
|
|
iss >> func_name;
|
|
|
|
if (func_name == "set")
|
|
{
|
|
std::string var_name, op;
|
|
float value;
|
|
iss >> var_name >> op >> value;
|
|
|
|
auto var_ptr = GetCtxVariablePointer(var_name);
|
|
|
|
return [var_ptr, op, value](game::VehicleTuningContext& ctx) {
|
|
ApplyOp(ctx.*var_ptr, op, value);
|
|
};
|
|
}
|
|
else if (func_name == "setcolor")
|
|
{
|
|
size_t color_idx;
|
|
uint32_t color;
|
|
iss >> color_idx >> std::hex >> color >> std::dec;
|
|
|
|
if (color_idx >= 4)
|
|
throw std::runtime_error("tuning list: invalid color index");
|
|
|
|
color = ParseColor(color);
|
|
|
|
return [color_idx, color](game::VehicleTuningContext& ctx) {
|
|
ctx.colors[color_idx] = color;
|
|
};
|
|
}
|
|
else if (func_name == "setwheel")
|
|
{
|
|
std::string wheel_cond, var_name, op;
|
|
float value;
|
|
|
|
iss >> wheel_cond >> var_name >> op >> value;
|
|
|
|
auto var_ptr = GetWheelVariablePointer(var_name);
|
|
|
|
return [wheel_cond, var_ptr, op, value](game::VehicleTuningContext& ctx) {
|
|
for (auto& wheel : ctx.wheels)
|
|
{
|
|
if (CheckWheelCond(wheel, wheel_cond))
|
|
ApplyOp(wheel.*var_ptr, op, value);
|
|
}
|
|
};
|
|
}
|
|
else if (func_name == "setwheelmodel")
|
|
{
|
|
std::string wheel_cond, modelname;
|
|
iss >> wheel_cond >> modelname;
|
|
|
|
return [wheel_cond, modelname](game::VehicleTuningContext& ctx) {
|
|
for (auto& wheel : ctx.wheels)
|
|
{
|
|
if (CheckWheelCond(wheel, wheel_cond))
|
|
wheel.modelname = modelname;
|
|
}
|
|
};
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error("tuning list: unknown function " + func_name);
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<const game::VehicleTuningList> game::VehicleTuningList::LoadFromFile(const std::string& filename)
|
|
{
|
|
auto tuninglist = std::make_unique<VehicleTuningList>();
|
|
|
|
if (!fs::FileExists(filename))
|
|
return tuninglist; // empty
|
|
|
|
VehicleTuningGroup* current_group = nullptr;
|
|
VehicleTuningPart* current_part = nullptr;
|
|
|
|
auto process_command = [&](const std::string& command, std::istringstream& iss) {
|
|
if (command == "group")
|
|
{
|
|
VehicleTuningGroup group{};
|
|
iss >> group.id;
|
|
group.displayname = assets::ParseString(iss);
|
|
|
|
tuninglist->groups.emplace_back(std::move(group));
|
|
current_group = &tuninglist->groups.back();
|
|
|
|
return true;
|
|
}
|
|
else if (command == "part")
|
|
{
|
|
if (!current_group)
|
|
throw std::runtime_error("tuning list: part without active group");
|
|
|
|
VehicleTuningPart part{};
|
|
iss >> part.id >> part.price;
|
|
part.displayname = assets::ParseString(iss);
|
|
|
|
current_part = &(current_group->parts[part.id] = std::move(part));
|
|
|
|
return true;
|
|
}
|
|
else if (command == "stock")
|
|
{
|
|
if (!current_group)
|
|
throw std::runtime_error("tuning list: stock without active group");
|
|
|
|
std::string part_id;
|
|
iss >> part_id;
|
|
auto part_it = current_group->parts.find(part_id);
|
|
if (part_it == current_group->parts.end())
|
|
throw std::runtime_error("tuning list: stock references unknown part " + part_id);
|
|
|
|
part_it->second.stock = true;
|
|
}
|
|
else if (command == "default")
|
|
{
|
|
tuninglist->default_funcs.emplace_back(ParseTuningFunction(iss));
|
|
return true;
|
|
}
|
|
else if (command == "mod")
|
|
{
|
|
if (!current_part)
|
|
throw std::runtime_error("tuning list: mod without active part");
|
|
|
|
current_part->funcs.emplace_back(ParseTuningFunction(iss));
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
assets::LoadCMDFile(filename, [&](const std::string& command, std::istringstream& iss) {
|
|
|
|
if (process_command(command, iss))
|
|
return;
|
|
|
|
if (command == "include")
|
|
{
|
|
std::string include_name;
|
|
iss >> include_name;
|
|
|
|
assets::LoadCMDFile("data/" + include_name + ".tun", [&](const std::string& command, std::istringstream& iss) {
|
|
process_command(command, iss);
|
|
});
|
|
|
|
}
|
|
});
|
|
|
|
return tuninglist;
|
|
} |