|
|
|
|
@ -851,6 +851,41 @@ struct DesignSection { // Game::ShipDesignDef::Section, one DSec of a Des frame
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// Game::GunBankSelection -- the `wgb` frame of a weapon group. The recovery
|
|
|
|
|
// resolves ONE NULL-named int here, which is a loop body: the only record in the
|
|
|
|
|
// corpus (human-turn15-spyprogram, the first save with Dwgv set) carries three.
|
|
|
|
|
// Neither a count word nor a fixed arity is on the wire, so this is read as an
|
|
|
|
|
// uncounted run of "." ints rather than as a fixed three -- a design with a
|
|
|
|
|
// different bank arity cannot desynchronise the frame. What settles the arity is
|
|
|
|
|
// a save whose design has a non-three gun-bank layout.
|
|
|
|
|
struct GunBankSelection {
|
|
|
|
|
static constexpr const char* kStreamName = "";
|
|
|
|
|
std::vector<int32_t> banks;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.repeat(".", banks, [](Ar& a, int32_t& e) { a.i32(R("bank"), e); });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct WeaponGroup { // one wgng element: the group id and its bank selection
|
|
|
|
|
static constexpr const char* kStreamName = "";
|
|
|
|
|
int32_t wgid = 0;
|
|
|
|
|
GunBankSelection wgb;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.i32(A("wgid"), wgid);
|
|
|
|
|
ar.obj(A("wgb"), wgb);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct WeaponGroups { // Game::WeaponGroups, the Dwg frame
|
|
|
|
|
static constexpr const char* kStreamName = "Dwg";
|
|
|
|
|
std::vector<WeaponGroup> groups;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.narr(A("wgng"), groups, [](Ar& a, WeaponGroup& e) { e.io(a); });
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// A design is written by TWO serializers, a base and a derived one. The base
|
|
|
|
|
// emits FAIDes / DHide / DWep / DName and then EXACTLY THREE section frames;
|
|
|
|
|
// the derived one appends Dtc, the Dwgv flag and -- only when that flag is set
|
|
|
|
|
@ -875,7 +910,10 @@ struct Design { // on-disk tags are case variants of the reference names (FAIDe
|
|
|
|
|
std::vector<DesignSection> sections;
|
|
|
|
|
int32_t dtc = 0;
|
|
|
|
|
bool dwgv = false;
|
|
|
|
|
Node weaponGroups; // Dwg; present only when dwgv, which is false in every save available
|
|
|
|
|
// Dwg; present only when dwgv, which is set on exactly one design in the
|
|
|
|
|
// corpus (human-turn15-spyprogram). Typed from that record plus the
|
|
|
|
|
// recovered Game::WeaponGroups serializer.
|
|
|
|
|
WeaponGroups weaponGroups;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
@ -886,7 +924,7 @@ struct Design { // on-disk tags are case variants of the reference names (FAIDe
|
|
|
|
|
ar.repeat("DSec", sections, [](Ar& a, DesignSection& e) { a.obj(A("DSec"), e); });
|
|
|
|
|
ar.i32(A("Dtc"), dtc);
|
|
|
|
|
ar.b(A("Dwgv"), dwgv);
|
|
|
|
|
ar.when(dwgv, [&](Ar& a) { a.any(A("Dwg"), weaponGroups); });
|
|
|
|
|
ar.when(dwgv, [&](Ar& a) { a.obj(A("Dwg"), weaponGroups); });
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
@ -1186,11 +1224,24 @@ struct SpyReport { // Game::SpyReport: four counted lists, one per report kind
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct FreighterWarning { // Game::ServerTradeSector::FreighterWarning, one fwarn element
|
|
|
|
|
static constexpr const char* kStreamName = "";
|
|
|
|
|
int32_t pid = 0, ntrns = 0;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.i32(A("pid"), pid);
|
|
|
|
|
ar.i32(A("ntrns"), ntrns);
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct TradeSector { // Game::ServerTradeSector
|
|
|
|
|
static constexpr const char* kStreamName = "Trade";
|
|
|
|
|
Vec3 pos, ctr;
|
|
|
|
|
int32_t gridID = 0, tssec = 0, tsct = 0, tscr = 0, ptssec = 0, ptsct = 0, ptscr = 0;
|
|
|
|
|
std::vector<Node> fwarn; // ServerTradeSector::FreighterWarning; empty in every save available
|
|
|
|
|
// ServerTradeSector::FreighterWarning. The count was 0 in every save until
|
|
|
|
|
// human-turn11-spytechs, which raided a route and produced one.
|
|
|
|
|
std::vector<FreighterWarning> fwarn;
|
|
|
|
|
std::vector<int32_t> systems, fleets;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
@ -1210,6 +1261,23 @@ struct TradeSector { // Game::ServerTradeSector
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct TradeRoute { // Game::TradeRoute, one `rt` frame of the trade manager
|
|
|
|
|
static constexpr const char* kStreamName = "rt";
|
|
|
|
|
int32_t tro = 0, trfow = 0, trfr = 0, trfrs = 0, trtow = 0, trto = 0, trtos = 0, trtc = 0;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.i32(A("tro"), tro);
|
|
|
|
|
ar.i32(A("trfow"), trfow);
|
|
|
|
|
ar.i32(A("trfr"), trfr);
|
|
|
|
|
ar.i32(A("trfrs"), trfrs);
|
|
|
|
|
ar.i32(A("trtow"), trtow);
|
|
|
|
|
ar.i32(A("trto"), trto);
|
|
|
|
|
ar.i32(A("trtos"), trtos);
|
|
|
|
|
ar.i32(A("trtc"), trtc);
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct TradeManager { // Game::ServerTradeManagerImpl
|
|
|
|
|
// The `trdmgr` member is declared as Game::ServerTradeManager, whose Read and
|
|
|
|
|
// Write really are the inherited no-op -- the campaign recorded that as an open
|
|
|
|
|
@ -1228,23 +1296,58 @@ struct TradeManager { // Game::ServerTradeManagerImpl
|
|
|
|
|
};
|
|
|
|
|
std::vector<Entry> sectors;
|
|
|
|
|
float sctSize = 0;
|
|
|
|
|
// `rt` is a container write with NO count word: the recovery marks it a loop
|
|
|
|
|
// body (member == false) and the wire has the frames back to back after
|
|
|
|
|
// SctSize, so it is read as an uncounted run keyed on the tag. Every save
|
|
|
|
|
// that has any route at all (human-turn11, human-turn15) carries exactly one
|
|
|
|
|
// here, so "uncounted" is the framing the evidence supports, not "one".
|
|
|
|
|
std::vector<TradeRoute> routes;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.narr(A("NumTradeSectors"), sectors, [](Ar& a, Entry& e) { e.io(a); });
|
|
|
|
|
ar.f32(A("SctSize"), sctSize);
|
|
|
|
|
ar.repeat("rt", routes, [](Ar& a, TradeRoute& e) { a.obj(A("rt"), e); });
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct SpyCraft { // Game::SpyCraft, one `spy` frame
|
|
|
|
|
static constexpr const char* kStreamName = "spy";
|
|
|
|
|
int32_t sid = 0, sown = 0, atto = 0, deat = 0, tdep = 0;
|
|
|
|
|
float cbh = 0, sdo = 0;
|
|
|
|
|
int32_t sdet = 0, spyon = 0, spyat = 0, cm = 0;
|
|
|
|
|
float cmo = 0;
|
|
|
|
|
std::vector<int32_t> cpl; // ncp: compromised players; 0 in the one record we hold
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.i32(A("sid"), sid);
|
|
|
|
|
ar.i32(A("sown"), sown);
|
|
|
|
|
ar.i32(A("atto"), atto);
|
|
|
|
|
ar.i32(A("deat"), deat);
|
|
|
|
|
ar.i32(A("tdep"), tdep);
|
|
|
|
|
ar.f32(A("cbh"), cbh);
|
|
|
|
|
ar.f32(A("sdo"), sdo);
|
|
|
|
|
ar.i32(A("sdet"), sdet);
|
|
|
|
|
ar.i32(A("spyon"), spyon);
|
|
|
|
|
ar.i32(A("spyat"), spyat);
|
|
|
|
|
ar.i32(A("cm"), cm);
|
|
|
|
|
ar.f32(A("cmo"), cmo);
|
|
|
|
|
ar.narr(A("ncp"), cpl, [](Ar& a, int32_t& e) { a.i32(A("cpl"), e); });
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct SpyManager { // Game::ServerSpyManager
|
|
|
|
|
static constexpr const char* kStreamName = "spymgr";
|
|
|
|
|
int32_t xsid = 0;
|
|
|
|
|
std::vector<Node> spies; // Game::SpyCraft frames; nspy is 0 in every save available
|
|
|
|
|
// nspy was 0 in every save until human-turn15-spyprogram, which ran a spy
|
|
|
|
|
// program and produced one craft.
|
|
|
|
|
std::vector<SpyCraft> spies;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.i32(A("xsid"), xsid);
|
|
|
|
|
ar.narr(A("nspy"), spies, [](Ar& a, Node& e) { a.any(A("spy"), e); });
|
|
|
|
|
ar.narr(A("nspy"), spies, [](Ar& a, SpyCraft& e) { a.obj(A("spy"), e); });
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
@ -1589,6 +1692,40 @@ struct ShipEntry {
|
|
|
|
|
ar.obj(A("Ship"), ship);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct FieldTemplate { // Game::FieldTemplate, the NULL-named first frame of a Lay
|
|
|
|
|
static constexpr const char* kStreamName = "";
|
|
|
|
|
// FTPnts is the ONE item in this round's work that the recovery itself marks
|
|
|
|
|
// unresolved: it names the element class from the decorated helper name
|
|
|
|
|
// (Game::FieldTemplate::Point, whose own serializer is fully recovered --
|
|
|
|
|
// FTPShID/FTPDesID/FTPPosX/FTPPosY/FTPSqd) but could not type the item, and
|
|
|
|
|
// the count is 0 in every Lay in the corpus. That is exactly the pair of
|
|
|
|
|
// conditions under which SysMem, mts and nalat were all typed wrong: the
|
|
|
|
|
// element FRAMING is a property of the helper, not of the element class, and
|
|
|
|
|
// no save has ever shown one. So the elements stay carried. What settles it
|
|
|
|
|
// is a save whose fleet has a stored tactical formation -- set a fleet's
|
|
|
|
|
// combat layout in the tactical setup screen, then save.
|
|
|
|
|
std::vector<Node> points;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.carr(A("FTPnts"), points);
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// Game::FleetLayout, the `Lay` frame gated by HLay. Every item in it is
|
|
|
|
|
// NULL-named: a FieldTemplate frame, then a count, then that many ship ids.
|
|
|
|
|
struct FleetLayout {
|
|
|
|
|
static constexpr const char* kStreamName = "Lay";
|
|
|
|
|
FieldTemplate tmpl;
|
|
|
|
|
std::vector<int32_t> shipIDs;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.obj(R("tmpl"), tmpl);
|
|
|
|
|
ar.narr(R("nships"), shipIDs, [](Ar& a, int32_t& e) { a.i32(R("shipID"), e); });
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct Fleet {
|
|
|
|
|
static constexpr const char* kStreamName = "Flt";
|
|
|
|
|
Vec3 pos;
|
|
|
|
|
@ -1606,7 +1743,7 @@ struct Fleet {
|
|
|
|
|
bool perm = false;
|
|
|
|
|
Vec3 prvPos;
|
|
|
|
|
bool hLay = false;
|
|
|
|
|
Node lay;
|
|
|
|
|
FleetLayout lay;
|
|
|
|
|
std::vector<ShipEntry> ships;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
@ -1633,44 +1770,94 @@ struct Fleet {
|
|
|
|
|
ar.b(A("Perm"), perm);
|
|
|
|
|
ar.vec3(A("PrvPos"), prvPos);
|
|
|
|
|
ar.b(A("HLay"), hLay);
|
|
|
|
|
ar.when(hLay, [&](Ar& a) { a.any(A("Lay"), lay); });
|
|
|
|
|
ar.when(hLay, [&](Ar& a) { a.obj(A("Lay"), lay); });
|
|
|
|
|
ar.narr(A("NShips"), ships, [](Ar& a, ShipEntry& e) { e.io(a); });
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ---- combat reports, node grid ---------------------------------------------------
|
|
|
|
|
struct Dams {
|
|
|
|
|
static constexpr const char* kStreamName = "dams";
|
|
|
|
|
int32_t dams = 0, damp = 0, dami = 0, damt = 0;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.i32(R("dams", "dams"), dams);
|
|
|
|
|
ar.i32(R("damp", "damp"), damp);
|
|
|
|
|
ar.i32(R("dami", "dami"), dami);
|
|
|
|
|
ar.i32(R("damt", "damt"), damt);
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct Wrep {
|
|
|
|
|
//
|
|
|
|
|
// The damage quartet is written by TWO classes, Game::CombatWeaponReport and
|
|
|
|
|
// Game::CombatShipReport, and both recoveries agree: dams and damp are ints, dami
|
|
|
|
|
// and damt are FLOATS. An earlier `Dams` sub-struct read all four as ints and was
|
|
|
|
|
// reached through obj_flex, i.e. it modelled a nested `dams` frame that the
|
|
|
|
|
// binary does not write and that no save in the corpus contains. Both are
|
|
|
|
|
// corrected here: the quartet is flat, and the last two are f32. The int reading
|
|
|
|
|
// round-tripped because the bytes are the bytes; the values it produced
|
|
|
|
|
// (dami = 1033392620 for what is 0.0787) were nonsense.
|
|
|
|
|
struct Wrep { // Game::CombatWeaponReport
|
|
|
|
|
static constexpr const char* kStreamName = "";
|
|
|
|
|
std::string wep;
|
|
|
|
|
Dams dams;
|
|
|
|
|
bool damsFramed = true;
|
|
|
|
|
int32_t dams = 0, damp = 0;
|
|
|
|
|
float dami = 0, damt = 0;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.str(R("wep", "wep"), wep);
|
|
|
|
|
ar.obj_flex(R("dams", "dams"), dams, damsFramed);
|
|
|
|
|
ar.i32(R("dams", "dams"), dams);
|
|
|
|
|
ar.i32(R("damp", "damp"), damp);
|
|
|
|
|
ar.f32(R("dami", "dami"), dami);
|
|
|
|
|
ar.f32(R("damt", "damt"), damt);
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct CrepPrep {
|
|
|
|
|
struct Srep { // Game::CombatShipReport, one srep element
|
|
|
|
|
static constexpr const char* kStreamName = "";
|
|
|
|
|
std::string name;
|
|
|
|
|
int32_t did = 0, cls = 0;
|
|
|
|
|
int64_t caps2 = 0;
|
|
|
|
|
int32_t nshp = 0, nfld = 0, nlst = 0, dtak = 0, dams = 0, damp = 0;
|
|
|
|
|
float dami = 0, damt = 0;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.str(A("name"), name);
|
|
|
|
|
ar.i32(A("did"), did);
|
|
|
|
|
ar.i32(A("cls"), cls);
|
|
|
|
|
ar.i64(A("caps2"), caps2);
|
|
|
|
|
ar.i32(A("nshp"), nshp);
|
|
|
|
|
ar.i32(A("nfld"), nfld);
|
|
|
|
|
ar.i32(A("nlst"), nlst);
|
|
|
|
|
ar.i32(A("dtak"), dtak);
|
|
|
|
|
ar.i32(A("dams"), dams);
|
|
|
|
|
ar.i32(A("damp"), damp);
|
|
|
|
|
ar.f32(A("dami"), dami);
|
|
|
|
|
ar.f32(A("damt"), damt);
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct CrepClass { // one ncls loop body of a CombatPlayerReport (per ship class)
|
|
|
|
|
static constexpr const char* kStreamName = "";
|
|
|
|
|
int32_t cls = 0, nshp = 0, nsat = 0, nshfld = 0, nshlst = 0, nsatl = 0;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.i32(A("cls"), cls);
|
|
|
|
|
ar.i32(A("nshp"), nshp);
|
|
|
|
|
ar.i32(A("nsat"), nsat);
|
|
|
|
|
ar.i32(A("nshfld"), nshfld);
|
|
|
|
|
ar.i32(A("nshlst"), nshlst);
|
|
|
|
|
ar.i32(A("nsatl"), nsatl);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct CrepSector { // one nsec loop body of a CombatPlayerReport (per ship section)
|
|
|
|
|
static constexpr const char* kStreamName = "";
|
|
|
|
|
int32_t ssec = 0, nshp = 0;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.i32(A("ssec"), ssec);
|
|
|
|
|
ar.i32(A("nshp"), nshp);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct CrepPrep { // Game::CombatPlayerReport
|
|
|
|
|
static constexpr const char* kStreamName = "";
|
|
|
|
|
int32_t plr = 0;
|
|
|
|
|
bool ai = false;
|
|
|
|
|
int32_t ally = 0, status = 0, mxeng = 0, mxcls = 0, mxmsl = 0;
|
|
|
|
|
std::vector<CrepClass> classes;
|
|
|
|
|
std::vector<CrepSector> sectors;
|
|
|
|
|
int32_t ndam = 0;
|
|
|
|
|
std::vector<Srep> srep;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
@ -1681,14 +1868,28 @@ struct CrepPrep {
|
|
|
|
|
ar.i32(R("mxeng", "mxeng"), mxeng);
|
|
|
|
|
ar.i32(R("mxcls", "mxcls"), mxcls);
|
|
|
|
|
ar.i32(R("mxmsl", "mxmsl"), mxmsl);
|
|
|
|
|
ar.narr(A("ncls"), classes, [](Ar& a, CrepClass& e) { e.io(a); });
|
|
|
|
|
ar.narr(A("nsec"), sectors, [](Ar& a, CrepSector& e) { e.io(a); });
|
|
|
|
|
ar.i32(A("ndam"), ndam);
|
|
|
|
|
ar.carr(A("srep"), srep);
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// Game::CombatReport. auto and cdst are BOOLs and dur, cdt and cdi are FLOATS --
|
|
|
|
|
// all five were read as ints here. Four of them are 0 or 1 in every save, so the
|
|
|
|
|
// bytes never moved; cdt is not (0x3FCC... = 1.598 turns of combat), and reading
|
|
|
|
|
// it as an int gave 1070805848.
|
|
|
|
|
struct Crep {
|
|
|
|
|
static constexpr const char* kStreamName = "crep";
|
|
|
|
|
int32_t cid = 0, trn = 0;
|
|
|
|
|
Vec3 pos;
|
|
|
|
|
int32_t sid = 0, autoF = 0, dur = 0, cow = 0, cdst = 0, cpk = 0, cpt = 0, cdt = 0, cdi = 0;
|
|
|
|
|
int32_t sid = 0;
|
|
|
|
|
bool autoF = false;
|
|
|
|
|
float dur = 0;
|
|
|
|
|
int32_t cow = 0;
|
|
|
|
|
bool cdst = false;
|
|
|
|
|
int32_t cpk = 0, cpt = 0;
|
|
|
|
|
float cdt = 0, cdi = 0;
|
|
|
|
|
std::vector<CrepPrep> prep;
|
|
|
|
|
bool prepFramed = true;
|
|
|
|
|
std::vector<Wrep> wrep;
|
|
|
|
|
@ -1700,14 +1901,14 @@ struct Crep {
|
|
|
|
|
ar.i32(R("trn", "trn"), trn);
|
|
|
|
|
ar.vec3(R("pos", "pos"), pos);
|
|
|
|
|
ar.i32(R("sid", "sid"), sid);
|
|
|
|
|
ar.i32(R("auto", "auto"), autoF);
|
|
|
|
|
ar.i32(R("dur", "dur"), dur);
|
|
|
|
|
ar.b(R("auto", "auto"), autoF);
|
|
|
|
|
ar.f32(R("dur", "dur"), dur);
|
|
|
|
|
ar.i32(R("cow", "cow"), cow);
|
|
|
|
|
ar.i32(R("cdst", "cdst"), cdst);
|
|
|
|
|
ar.b(R("cdst", "cdst"), cdst);
|
|
|
|
|
ar.i32(R("cpk", "cpk"), cpk);
|
|
|
|
|
ar.i32(R("cpt", "cpt"), cpt);
|
|
|
|
|
ar.i32(R("cdt", "cdt"), cdt);
|
|
|
|
|
ar.i32(R("cdi", "cdi"), cdi);
|
|
|
|
|
ar.f32(R("cdt", "cdt"), cdt);
|
|
|
|
|
ar.f32(R("cdi", "cdi"), cdi);
|
|
|
|
|
ar.carr_flex(R("prep", "prep"), prep, prepFramed);
|
|
|
|
|
ar.carr_flex(R("wrep", "wrep"), wrep, wrepFramed);
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
@ -2415,14 +2616,77 @@ struct AIAutoPeaceRun { // Game::AIAutoPeaceRun
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct TacReportEvents { // Game::TacReportEvents, the TRby / TRto frames
|
|
|
|
|
static constexpr const char* kStreamName = "";
|
|
|
|
|
int32_t hd = 0, hi = 0;
|
|
|
|
|
float d = 0, dp = 0, di = 0, dt = 0;
|
|
|
|
|
bool b = false;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.i32(A("TREhd"), hd);
|
|
|
|
|
ar.i32(A("TREhi"), hi);
|
|
|
|
|
ar.f32(A("TREd"), d);
|
|
|
|
|
ar.f32(A("TREdp"), dp);
|
|
|
|
|
ar.f32(A("TREdi"), di);
|
|
|
|
|
ar.f32(A("TREdt"), dt);
|
|
|
|
|
ar.b(A("TREb"), b);
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct TacClass { // one TRnc loop body: the per-ship-class tail of a TacReport
|
|
|
|
|
static constexpr const char* kStreamName = "";
|
|
|
|
|
int32_t ships = 0, sats = 0, shipsL = 0;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.i32(A("TRships"), ships);
|
|
|
|
|
ar.i32(A("TRsats"), sats);
|
|
|
|
|
ar.i32(A("TRshipsL"), shipsL);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// Game::TacReport. Two lanes left this carried: the recovery ends with a computed
|
|
|
|
|
// count (TRnc) and three trailing scalar items, and with TRnc == 0 in every save
|
|
|
|
|
// held at the time there was no way to tell three trailing scalars from a loop
|
|
|
|
|
// body of three. The trade/spy saves settle it -- TRnc == 3 and the wire carries
|
|
|
|
|
// TRships, TRsats, TRshipsL three times, INTERLEAVED, so the recovery's three
|
|
|
|
|
// items are one loop body, not three runs.
|
|
|
|
|
struct TacReport {
|
|
|
|
|
static constexpr const char* kStreamName = "";
|
|
|
|
|
TacReportEvents by, to;
|
|
|
|
|
// `mine` not `min`: windows.h defines min as a macro and this header is
|
|
|
|
|
// compiled by the MinGW cross-build too.
|
|
|
|
|
int32_t id = 0, al = 0, bal = 0, las = 0, mis = 0, mine = 0, nrg = 0, bio = 0, brd = 0;
|
|
|
|
|
bool sld = false, sldd = false, sldc = false, sldi = false, sldr = false;
|
|
|
|
|
std::vector<TacClass> classes;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
ar.obj(A("TRby"), by);
|
|
|
|
|
ar.obj(A("TRto"), to);
|
|
|
|
|
ar.i32(A("TRid"), id);
|
|
|
|
|
ar.i32(A("TRal"), al);
|
|
|
|
|
ar.i32(A("TRbal"), bal);
|
|
|
|
|
ar.i32(A("TRlas"), las);
|
|
|
|
|
ar.i32(A("TRmis"), mis);
|
|
|
|
|
ar.i32(A("TRmin"), mine);
|
|
|
|
|
ar.i32(A("TRnrg"), nrg);
|
|
|
|
|
ar.i32(A("TRbio"), bio);
|
|
|
|
|
ar.i32(A("TRbrd"), brd);
|
|
|
|
|
ar.b(A("TRsld"), sld);
|
|
|
|
|
ar.b(A("TRsldd"), sldd);
|
|
|
|
|
ar.b(A("TRsldc"), sldc);
|
|
|
|
|
ar.b(A("TRsldi"), sldi);
|
|
|
|
|
ar.b(A("TRsldr"), sldr);
|
|
|
|
|
ar.narr(A("TRnc"), classes, [](Ar& a, TacClass& e) { e.io(a); });
|
|
|
|
|
ar.rest(extra);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct CombatPlayerStats { // Game::CombatPlayerStats
|
|
|
|
|
static constexpr const char* kStreamName = "CRPlSv2";
|
|
|
|
|
float rpBon = 0;
|
|
|
|
|
int32_t rpBonT = 0, savBonus = 0;
|
|
|
|
|
bool maintHF = false;
|
|
|
|
|
// Game::TacReport has a computed count and three trailing scalar runs that no
|
|
|
|
|
// save we hold exercises; its body stays carried rather than typed on a guess.
|
|
|
|
|
std::vector<Node> tacReports;
|
|
|
|
|
std::vector<TacReport> tacReports;
|
|
|
|
|
std::vector<Node> extra;
|
|
|
|
|
template <class Ar>
|
|
|
|
|
void io(Ar& ar) {
|
|
|
|
|
|