sots-engine/src/shim/hooks/movement_inputs.cpp

152 lines
5.4 KiB
C++

#include "shim/hooks/movement_inputs.h"
#include <cmath>
#include <cstring>
#include <utility>
#include "game/sim/numeric.h"
namespace shim::hooks {
using sots::sim::JumpResult;
using sots::sim::MoveStepResult;
using sots::sim::Vec3;
using trace::Tv;
namespace tv = trace::tv;
namespace {
Vec3 vec_of(const double v[3]) { return Vec3{v[0], v[1], v[2]}; }
void store(double out[3], const Vec3& v) {
out[0] = v.x;
out[1] = v.y;
out[2] = v.z;
}
} // namespace
std::vector<double> ShipRanges(const FleetStepSnapshot& s) {
std::vector<double> r;
const int n = s.shipCount < kMaxTracedShips ? s.shipCount : kMaxTracedShips;
for (int i = 0; i < n; ++i) r.push_back(s.ships[i].range);
return r;
}
FleetStepResult StepFleet(const FleetStepSnapshot& s, double step, sots::sim::IRandom& rng) {
FleetStepResult r;
const Vec3 pos = vec_of(s.pos);
const Vec3 dest = vec_of(s.dest);
store(r.pos, pos);
r.shipRanges = ShipRanges(s);
if (s.heldFlag != 0 || s.waypointType < 0) return r; // held, or no waypoints: no move
switch (s.waypointType) {
case static_cast<int>(sots::sim::WaypointKind::ProbabilisticJump): {
const JumpResult j = sots::sim::RollProbabilisticJump(s.castEfficiency,
s.castThreshold, rng);
r.rngDraws = j.draws;
r.fraction = 1.0; // a type-5 waypoint never recurses
if (j.arrived) {
store(r.pos, dest);
r.arrived = true;
} else {
// The miss scatters the fleet around the destination in a random direction.
// The direction is a second draw whose mapping this milestone does not model,
// so the position is left where it was and the scatter distance is reported.
r.moved = j.scatter;
}
return r; // no fuel is charged and no clamp applies
}
case static_cast<int>(sots::sim::WaypointKind::GateTeleport):
store(r.pos, dest);
r.arrived = true;
r.fraction = 1.0;
return r; // no fuel, no clamp
default:
break;
}
r.distance = sots::sim::Distance(pos, dest);
const double minRange = sots::sim::FleetMinShipRange(r.shipRanges, 0.0);
const MoveStepResult m = sots::sim::ResolveMoveStep(step, minRange, r.distance);
r.moved = m.moved;
r.range = m.range;
r.arrived = m.arrived;
r.stranded = m.stranded;
store(r.pos, m.arrived ? dest : sots::sim::AdvanceAlongDirection(pos, dest, m.moved));
for (int i = 0; i < static_cast<int>(r.shipRanges.size()); ++i) {
r.shipRanges[static_cast<std::size_t>(i)] =
sots::sim::ConsumeShipRange(r.shipRanges[static_cast<std::size_t>(i)], m.moved,
s.ships[i].exempt != 0);
}
r.fraction = sots::sim::PassFraction(s.waypointType, r.distance, step);
return r;
}
std::vector<int> GateTraffic(const std::vector<FleetSummary>& fleets, int playerCount) {
std::vector<sots::sim::GateTrafficEntry> e;
e.reserve(fleets.size());
for (const FleetSummary& f : fleets) {
sots::sim::GateTrafficEntry g;
g.ownerIndex = f.ownerIndex;
g.waypointType = f.waypointType;
g.traffic = f.gateTraffic;
e.push_back(g);
}
return sots::sim::GateTrafficTotals(e, playerCount);
}
std::vector<sots::sim::MovementPass> PassSchedule(const std::vector<FleetSummary>& fleets) {
std::vector<sots::sim::FleetMovementEntry> e;
e.reserve(fleets.size());
for (const FleetSummary& f : fleets) {
sots::sim::FleetMovementEntry x;
x.fleetId = f.fleetId;
x.targetFleetId = f.targetFleetId;
x.relation = f.relation;
e.push_back(x);
}
return sots::sim::PlanFleetMovement(e);
}
Tv DescribeFleetStep(const void* data, std::size_t size, unsigned) {
Tv s = tv::struct_();
if (size < sizeof(FleetStepSnapshot)) return s;
FleetStepSnapshot f;
std::memcpy(&f, data, sizeof f);
s.add("fleet", tv::i32(f.fleetId));
s.add("owner", tv::i32(f.ownerIndex));
s.add("wpt_type", tv::i32(f.waypointType));
s.add("wpt_count", tv::i32(f.waypointCount));
s.add("dest_kind", tv::i32(f.destKind));
s.add("dt", tv::f32(f.dt));
s.add("speed", tv::f32(f.speed));
std::vector<Tv> p, d;
for (int i = 0; i < 3; ++i) p.push_back(tv::f32(static_cast<float>(f.pos[i])));
for (int i = 0; i < 3; ++i) d.push_back(tv::f32(static_cast<float>(f.dest[i])));
s.add("pos", tv::list(std::move(p)));
s.add("dest", tv::list(std::move(d)));
s.add("cst_e", tv::f32(f.castEfficiency));
s.add("cst_t", tv::f32(f.castThreshold));
s.add("ships", tv::i32(f.shipCount));
s.add("held", tv::i32(f.heldFlag));
s.add("rng_left_in", tv::i32(f.rngLeftIn));
s.add("fpu_cw", tv::u32(f.fpuControlWord));
const int n = f.shipCount < kMaxTracedShips ? f.shipCount : kMaxTracedShips;
std::vector<Tv> ranges;
for (int i = 0; i < n; ++i) {
Tv one = tv::struct_();
one.add("range", tv::f32(f.ships[i].range));
one.add("exempt", tv::boolean(f.ships[i].exempt != 0));
ranges.push_back(std::move(one));
}
s.add("ship_range", tv::list(std::move(ranges)));
return s;
}
Tv DescribeGateTraffic(const std::vector<int>& totals) {
std::vector<Tv> items;
for (int v : totals) items.push_back(tv::i32(v));
return tv::list(std::move(items));
}
} // namespace shim::hooks