maestrale
Version:
Maestrale Kit for Azurlane
1,129 lines (1,115 loc) • 29.5 kB
JavaScript
import { ShareCfg } from "@maestrale/data";
import { computed, isRef, ref, shallowReactive, shallowRef, toRaw, toValue, watch } from "@vue/reactivity";
export * from "@maestrale/data"
//#region src/core/attributes.ts
function createAttributes(options = {}) {
return {
durability: 0,
cannon: 0,
torpedo: 0,
antiaircraft: 0,
air: 0,
reload: 0,
hit: 0,
dodge: 0,
speed: 0,
luck: 0,
antisub: 0,
...options
};
}
//#endregion
//#region src/utils.ts
const ShipFleetKey = Symbol();
function nonNullable(obj) {
return obj !== null && obj !== void 0;
}
function* entries(obj) {
for (const key in obj) yield [key, obj[key]];
}
//#endregion
//#region src/core/commander.ts
var Commander = class {
data_template;
level;
name;
constructor(id) {
this.id = id;
this.data_template = ShareCfg.commander_data_template[id];
this.level = ref(this.maxLevel);
this.name = ref(this.originalName);
}
get originalName() {
return this.data_template.name;
}
get nationality() {
return this.data_template.nationality;
}
get rarity() {
return this.data_template.rarity;
}
get painting() {
return this.data_template.painting;
}
get maxLevel() {
return this.data_template.max_level;
}
getAbility(baseVal) {
return Math.floor(baseVal * (1 + 3 / 38 * (this.level.value - 1)));
}
support = computed(() => {
return this.getAbility(this.data_template.support_value);
});
command = computed(() => {
return this.getAbility(this.data_template.command_value);
});
tactic = computed(() => {
return this.getAbility(this.data_template.tactic_value);
});
attrRates = computed(() => {
const attrs = createAttributes();
for (const [key] of entries(attrs)) {
const coefficient = getCoefficient(key);
const efficiency = this.support.value * coefficient[0] + this.command.value * coefficient[1] + this.tactic.value * coefficient[2];
const percent = 6 * efficiency / (250 + efficiency) / 100;
attrs[key] = Math.round(percent * 1e3) / 1e3;
}
return attrs;
});
abilities = shallowReactive([]);
};
function createCommander(id) {
if (!(id in ShareCfg.commander_data_template)) return null;
return new Commander(id);
}
function getCoefficient(attr) {
switch (attr) {
case "durability": return [
.9,
0,
0
];
case "cannon": return [
.3,
.6,
0
];
case "torpedo": return [
0,
.3,
.6
];
case "antiaircraft": return [
0,
0,
.9
];
case "air": return [
.6,
0,
.3
];
case "antisub": return [
0,
.9,
0
];
default: return [
0,
0,
0
];
}
}
var CommanderAbility = class {
data_template;
effects;
constructor(id) {
this.id = id;
this.data_template = ShareCfg.commander_ability_template[id];
this.effects = this.data_template.add.map(([type, nationalities, shipTypes, key, value]) => ({
type,
nationalities,
shipTypes,
key,
value
}));
}
get name() {
return this.data_template.name;
}
get desc() {
return this.data_template.desc;
}
get icon() {
return this.data_template.icon;
}
get worth() {
return this.data_template.worth;
}
};
function createCommanderAbility(id) {
if (!(id in ShareCfg.commander_ability_template)) return null;
return new CommanderAbility(id);
}
//#endregion
//#region src/core/equip.ts
var Equip = class {
data_statistics;
data_template;
level;
constructor(id) {
this.id = id;
this.data_statistics = [];
this.data_template = [];
for (let i = id; i !== 0;) {
const stat = ShareCfg.equip_data_statistics[i];
const temp = ShareCfg.equip_data_template[i];
this.data_statistics.push(stat);
this.data_template.push(temp);
i = temp.next;
}
this.level = ref(this.maxLevel);
}
curStat = computed(() => {
return {
...this.data_statistics[0],
...this.data_statistics[this.level.value]
};
});
get name() {
return this.data_statistics[0].name;
}
get icon() {
return this.data_statistics[0].icon;
}
get nationality() {
return this.data_statistics[0].nationality;
}
get rarity() {
return this.data_statistics[0].rarity;
}
get type() {
return this.data_statistics[0].type;
}
get maxLevel() {
return this.data_statistics.length - 1;
}
attrs = computed(() => {
const res = {};
for (const i of [
1,
2,
3
]) {
const attrKey = `attribute_${i}`;
const valueKey = `value_${i}`;
if (attrKey in this.curStat.value) {
const attr = this.curStat.value[attrKey];
const value = Number(this.curStat.value[valueKey]);
res[attr] = value;
}
}
return res;
});
};
function createEquip(id) {
if (id % 10 !== 0 || !(id in ShareCfg.equip_data_template)) return null;
return new Equip(id);
}
//#endregion
//#region src/core/fleet.ts
var Fleet = class {
name;
constructor(name) {
this.name = ref(name);
}
commander1 = shallowRef(null);
commander2 = shallowRef(null);
commanders = computed(() => [this.commander1.value, this.commander2.value]);
};
var SurfaceFleet = class extends Fleet {
constructor(name) {
super(name);
track(this);
}
ships = computed(() => [
this.main1.value,
this.main2.value,
this.main3.value,
this.vanguard1.value,
this.vanguard2.value,
this.vanguard3.value
]);
main1 = shallowRef(null);
main2 = shallowRef(null);
main3 = shallowRef(null);
vanguard1 = shallowRef(null);
vanguard2 = shallowRef(null);
vanguard3 = shallowRef(null);
};
var SubmarineFleet = class extends Fleet {
constructor(name) {
super(name);
track(this);
}
ships = computed(() => [
this.submarine1.value,
this.submarine2.value,
this.submarine3.value
]);
submarine1 = shallowRef(null);
submarine2 = shallowRef(null);
submarine3 = shallowRef(null);
};
function createFleet(type, name = "新编队") {
switch (type) {
case "surface": return new SurfaceFleet(name);
case "submarine": return new SubmarineFleet(name);
}
}
function track(fleet) {
watch(fleet.ships, (newVal, oldVal) => {
for (let i = 0; i < newVal.length; i++) {
const oldShip = oldVal[i];
const newShip = newVal[i];
if (oldShip === newShip) continue;
if (oldShip && !fleet.ships.value.includes(oldShip)) oldShip[ShipFleetKey].value = null;
if (newShip) newShip[ShipFleetKey].value = fleet;
}
});
}
//#endregion
//#region src/types.ts
let StrengthenType = /* @__PURE__ */ function(StrengthenType$1) {
StrengthenType$1[StrengthenType$1["General"] = 0] = "General";
StrengthenType$1[StrengthenType$1["Meta"] = 1] = "Meta";
StrengthenType$1[StrengthenType$1["Blueprint"] = 2] = "Blueprint";
return StrengthenType$1;
}({});
let Favor = /* @__PURE__ */ function(Favor$1) {
Favor$1[Favor$1["Disappointed"] = 0] = "Disappointed";
Favor$1[Favor$1["Stranger"] = 1] = "Stranger";
Favor$1[Favor$1["Friendly"] = 2] = "Friendly";
Favor$1[Favor$1["Like"] = 3] = "Like";
Favor$1[Favor$1["Love"] = 4] = "Love";
Favor$1[Favor$1["Pledge"] = 5] = "Pledge";
Favor$1[Favor$1["PledgePlus"] = 6] = "PledgePlus";
return Favor$1;
}({});
//#endregion
//#region src/core/power.ts
function usePower(ship) {
const attrsPower = computed(() => {
const attrs = createAttributes();
for (const [key] of entries(attrs)) {
const baseAttr = Math.floor(ship[key].value);
const equipAttr = ship.equipAttrs.value[key];
const techAttr = ship.techAttrs.value[key];
attrs[key] = baseAttr + equipAttr + techAttr;
}
return attrs.durability * .2 + attrs.cannon + attrs.torpedo + attrs.antiaircraft + attrs.air + attrs.reload + attrs.hit * 2 + attrs.dodge * 2 + attrs.speed + attrs.antisub;
});
const equipPower = computed(() => {
return ship.equips.value.reduce((res, equip) => {
if (equip) {
const [base, strengthen] = getEquipPower(equip.rarity);
res += base + strengthen * (1 + equip.level.value);
}
return res;
}, 0);
});
const transPower = computed(() => {
let res = 0;
if (ship.transform) {
for (let i = 0; i < 6; i++) for (const templates of ship.transform.matrix[i]) for (const { enable } of templates) if (enable.value) res += getTransPower(i);
}
return res;
});
const power = computed(() => {
return Math.floor(attrsPower.value + equipPower.value + transPower.value);
});
return power;
}
function getEquipPower(rarity) {
switch (rarity) {
case 1: return [30, 5];
case 2: return [50, 8];
case 3: return [80, 10];
case 4: return [120, 12];
case 5: return [180, 15];
case 6: return [300, 20];
}
}
function getTransPower(index) {
switch (index) {
case 0: return 10;
case 1: return 15;
case 2: return 20;
case 3: return 25;
case 4: return 30;
case 5: return 50;
}
}
//#endregion
//#region src/core/spweapon.ts
var SPWeapon = class {
data_statistics;
level;
constructor(id) {
this.id = id;
this.data_statistics = [];
for (let i = id; i !== 0;) {
const stat = ShareCfg.spweapon_data_statistics[i];
this.data_statistics.push(stat);
if (stat.next - i > 1) break;
i = stat.next;
}
this.level = ref(this.maxLevel);
}
curStat = computed(() => {
return {
...this.data_statistics[0],
...this.data_statistics[this.level.value]
};
});
get name() {
return this.data_statistics[0].name;
}
get icon() {
return this.data_statistics[0].icon;
}
get rarity() {
return this.data_statistics[0].rarity;
}
get maxLevel() {
return this.data_statistics.length - 1;
}
attrs = computed(() => {
const res = {};
for (const i of [1, 2]) {
const attrKey = `attribute_${i}`;
const valueKey = `value_${i}`;
const randomValueKey = `value_${i}_random`;
if (attrKey in this.curStat.value) {
const attr = this.curStat.value[attrKey];
const value = this.curStat.value[valueKey];
const randomValue = this.curStat.value[randomValueKey];
res[attr] = value + randomValue;
}
}
return res;
});
};
function createSPWeapon(id) {
if (id % 10 !== 0 || !(id in ShareCfg.spweapon_data_statistics)) return null;
return new SPWeapon(id);
}
//#endregion
//#region src/core/ship.ts
var Ship = class {
breakout;
maxBreakout;
strengthen;
transform;
constructor(id, technology) {
this.id = id;
this.technology = technology;
this.maxBreakout = 0;
const baseId = id * 10 + 1;
const data_breakout = baseId in ShareCfg.ship_meta_breakout ? ShareCfg.ship_meta_breakout : ShareCfg.ship_data_breakout;
for (let i = baseId; i !== 0;) {
this.maxBreakout++;
i = data_breakout[i].breakout_id;
}
if (id in ShareCfg.ship_data_blueprint) {
const { breakout,...strengthen } = useStrengthenBlueprint(this);
this.breakout = breakout;
this.strengthen = {
type: StrengthenType.Blueprint,
...strengthen
};
} else if (id in ShareCfg.ship_strengthen_meta) {
this.breakout = ref(this.maxBreakout);
this.strengthen = {
type: StrengthenType.Meta,
...useStrengthenMeta(this)
};
} else {
this.breakout = ref(this.maxBreakout);
this.strengthen = {
type: StrengthenType.General,
...useStrengthenGeneral(this)
};
}
if (id in ShareCfg.ship_data_trans) this.transform = useTransform(this);
}
get curStat() {
return ShareCfg.ship_data_statistics[this.curId.value];
}
get curTemp() {
return ShareCfg.ship_data_template[this.curId.value];
}
get curSkin() {
return ShareCfg.ship_skin_template[this.id * 10 + (this.transform?.isModernized.value ? 9 : 0)];
}
curId = computed(() => {
return this.transform?.isModernized.value && this.transform?.modernizedId.value || this.id * 10 + this.breakout.value;
});
level = ref(125);
favor = ref(Favor.Love);
name = computed(() => {
const name = this.curStat.name;
if (this.transform?.isModernized.value) {
const suffixes = [".改", "·改"];
return (name.endsWith(suffixes[0]) || name.endsWith(suffixes[1]) ? name.slice(0, -2) : name) + suffixes[0];
} else return name;
});
armor = computed(() => {
return this.curStat.armor_type;
});
nationality = computed(() => {
return this.curStat.nationality;
});
rarity = computed(() => {
return this.curStat.rarity + (this.transform?.isModernized.value ? 1 : 0);
});
type = computed(() => {
return this.curStat.type;
});
painting = computed(() => {
return this.curSkin.painting;
});
star = computed(() => {
return this.maxStar.value - this.maxBreakout + this.breakout.value;
});
maxStar = computed(() => {
return Math.max(4, this.rarity.value);
});
getAttr(index, attrName) {
const favorRate = 1 + (["speed", "luck"].includes(attrName) ? 0 : getFavorRate(this.favor.value));
return (this.curStat.attrs[index] + this.curStat.attrs_growth[index] * (this.level.value - 1) / 1e3 + this.strengthen.attrs.value[attrName]) * favorRate + this.transAttrs.value[attrName];
}
transAttrs = computed(() => {
const attrs = createAttributes();
const templates = this.transform?.matrix.flat(2) ?? [];
for (const template of templates) if (template.enable.value) for (const effect of template.effect) for (const [attr, val] of entries(effect)) attrs[attr] += val;
return attrs;
});
equipAttrs = computed(() => {
const attrs = createAttributes();
for (const equip of [...this.equips.value, this.spweapon.value]) {
if (!equip) continue;
for (const [attr, val] of entries(equip.attrs.value)) attrs[attr] += val;
}
return attrs;
});
techAttrs = computed(() => {
const attrs = createAttributes();
if (this.breakout.value === this.maxBreakout) for (const [key] of entries(attrs)) attrs[key] += this.technology.get(this.type.value, key);
return attrs;
});
commanderAttrs = computed(() => {
const attrs = createAttributes();
const commanders = this.fleet.value?.commanders.value.filter(nonNullable) ?? [];
const effects = commanders.flatMap((commander) => commander.abilities).filter(nonNullable).flatMap((ability) => ability.effects).filter((effect) => effect.type === 1 && (!effect.nationalities.length || effect.nationalities.includes(this.nationality.value)) && (!effect.shipTypes.length || effect.shipTypes.includes(this.type.value)));
for (const effect of effects) {
const key = ShareCfg.attribute_info_by_type[effect.key].name;
attrs[key] += effect.value;
}
return attrs;
});
durability = computed(() => {
return this.getAttr(0, "durability");
});
cannon = computed(() => {
return this.getAttr(1, "cannon");
});
torpedo = computed(() => {
return this.getAttr(2, "torpedo");
});
antiaircraft = computed(() => {
return this.getAttr(3, "antiaircraft");
});
air = computed(() => {
return this.getAttr(4, "air");
});
reload = computed(() => {
return this.getAttr(5, "reload");
});
hit = computed(() => {
return this.getAttr(7, "hit");
});
dodge = computed(() => {
return this.getAttr(8, "dodge");
});
speed = computed(() => {
return this.getAttr(9, "speed");
});
luck = computed(() => {
return this.getAttr(10, "luck");
});
antisub = computed(() => {
return this.getAttr(11, "antisub");
});
oxy_max = computed(() => {
return this.curStat.oxy_max;
});
ammo = computed(() => {
return this.curStat.ammo;
});
oil = computed(() => {
const levelRate = .5 + .005 * Math.min(99, this.level.value);
return Math.floor(([
8,
17,
22
].includes(this.type.value) ? 0 : 1) + this.curTemp.oil_at_end * levelRate);
});
power = usePower(this);
equipSlotTypes = computed(() => {
return [
this.curTemp.equip_1,
this.curTemp.equip_2,
this.curTemp.equip_3,
this.curTemp.equip_4,
this.curTemp.equip_5
];
});
equip1 = shallowRef(null);
equip2 = shallowRef(null);
equip3 = shallowRef(null);
equip4 = shallowRef(null);
equip5 = shallowRef(null);
equips = computed(() => [
this.equip1.value,
this.equip2.value,
this.equip3.value,
this.equip4.value,
this.equip5.value
]);
spweapon = shallowRef(null);
[ShipFleetKey] = shallowRef(null);
fleet = computed(() => this[ShipFleetKey].value);
};
function createShip(id, options) {
if (!(id + "1" in ShareCfg.ship_data_statistics)) return null;
const { equips = [], spweapon = null, technology } = options;
const ship = new Ship(id, technology);
equips.push(...Array.from({ length: 5 - equips.length }, () => null));
ship.equip1.value = normalizeEquip(equips[0]);
ship.equip2.value = normalizeEquip(equips[1]);
ship.equip3.value = normalizeEquip(equips[2]);
ship.equip4.value = normalizeEquip(equips[3]);
ship.equip5.value = normalizeEquip(equips[4]);
ship.spweapon.value = normalizeSPWeapon(spweapon);
return ship;
}
function normalizeEquip(equip) {
return typeof equip === "number" ? createEquip(equip) : equip;
}
function normalizeSPWeapon(spweapon) {
return typeof spweapon === "number" ? createSPWeapon(spweapon) : spweapon;
}
function useStrengthenBlueprint(ship) {
const data_blueprint = ShareCfg.ship_data_blueprint[ship.id];
const data_strengthen = [...data_blueprint.strengthen_effect, ...data_blueprint.fate_strengthen].map((i) => ShareCfg.ship_strengthen_blueprint[i]);
const blueprintMax1 = data_strengthen.slice(0, 30).reduce((res, item) => {
return res + item.need_exp;
}, 0) / 10;
const blueprintMax2 = data_strengthen.slice(30).reduce((res, item) => {
return res + item.need_exp;
}, 0) / 10;
const blueprint = ref(blueprintMax1 + blueprintMax2);
const blueprint1 = computed({
get: () => {
return Math.min(blueprint.value, blueprintMax1);
},
set: (value) => {
blueprint.value = value;
}
});
const blueprint2 = computed({
get: () => {
return Math.max(0, blueprint.value - blueprintMax1);
},
set: (value) => {
blueprint.value = value + blueprintMax1;
}
});
const blueprintLevel = computed({
get: () => {
let level = 0;
let exp = 0;
for (const item of data_strengthen) {
exp += item.need_exp;
if (blueprint.value >= exp / 10) level++;
else break;
}
return level;
},
set: (level) => {
let exp = 0;
for (let i = 0; i < level; i++) exp += data_strengthen[i].need_exp;
blueprint.value = exp / 10;
}
});
const attrs = computed(() => {
const res = createAttributes();
for (let i = 0; i < blueprintLevel.value; i++) {
const item = data_strengthen[i];
for (const attr of item.effect_attr) res[attr[0]] += attr[1];
res.cannon += item.effect[0] / 100;
res.torpedo += item.effect[1] / 100;
res.air += item.effect[3] / 100;
res.reload += item.effect[4] / 100;
}
return res;
});
const breakout = computed({
get: () => {
const lv = blueprintLevel.value;
if (lv < 10) return 1;
else if (lv < 20) return 2;
else if (lv < 30) return 3;
else return 4;
},
set: (value) => {
blueprintLevel.value = {
1: 0,
2: 10,
3: 20,
4: 30
}[value] ?? 0;
}
});
return {
blueprintMax1,
blueprintMax2,
blueprint,
blueprint1,
blueprint2,
blueprintLevel,
attrs,
breakout
};
}
function useStrengthenMeta(ship) {
const data_strengthen = ShareCfg.ship_strengthen_meta[ship.id];
const repair_effect = data_strengthen.repair_effect.map(([per, key]) => {
return {
per,
...ShareCfg.ship_meta_repair_effect[key]
};
});
const maxAttrs = createAttributes();
for (const attr of [
"cannon",
"torpedo",
"air",
"reload"
]) {
const repairList = data_strengthen[`repair_${attr}`];
for (const key of repairList) {
const [attr$1, value] = ShareCfg.ship_meta_repair[key].effect_attr;
maxAttrs[attr$1] += value;
}
}
const adjustAttrs = ref({ ...maxAttrs });
const attrs = computed(() => {
const res = createAttributes(adjustAttrs.value);
let acc = 0;
let total = 0;
for (const [attr] of entries(res)) {
acc += res[attr];
total += maxAttrs[attr];
}
const rate = acc / total * 100;
for (const effect of repair_effect) if (rate >= effect.per) for (const [attr, value] of effect.effect_attr) res[attr] += value;
else break;
return res;
});
return {
maxAttrs,
adjustAttrs,
attrs
};
}
function useStrengthenGeneral(ship) {
const data_strengthen = ShareCfg.ship_data_strengthen[ship.id];
const maxAttrs = createAttributes({
cannon: data_strengthen.durability[0],
torpedo: data_strengthen.durability[1],
air: data_strengthen.durability[3],
reload: data_strengthen.durability[4]
});
const adjustAttrs = ref({ ...maxAttrs });
const attrs = computed(() => adjustAttrs.value);
return {
maxAttrs,
adjustAttrs,
attrs
};
}
function useTransform(ship) {
const templates = {};
const matrix = ShareCfg.ship_data_trans[ship.id].transform_list.map((item) => {
const column = [
[],
[],
[]
];
for (const [index, id] of item) {
const template = {
...ShareCfg.transform_data_template[id],
enable: ref(true),
next_id: []
};
templates[id] = template;
column[index - 2].push(template);
}
return column;
});
for (const [key, template] of entries(templates)) {
const stack = [[Number(key), template]];
while (stack.length) {
const [id, { condition_id }] = stack.pop();
for (const prevId of condition_id) {
const prev = templates[prevId];
if (prev.edit_trans.includes(id)) stack.push([id, prev]);
else prev.next_id.push(id);
}
}
}
const isModernized = ref(false);
const modernizedId = ref(null);
for (const [, template] of entries(templates)) watch(template.enable, (value) => {
if (value) {
updateTemplates(template.condition_id, true);
updateTemplates(template.edit_trans, false);
} else if (!template.edit_trans.length) updateTemplates(template.next_id, false);
else if (template.condition_id.every((id) => templates[id].enable.value)) updateTemplates(template.edit_trans, true);
if (template.name === "近代化改造") isModernized.value = value;
if (template.ship_id.length) {
const [from, to] = template.ship_id[0];
modernizedId.value = value ? to : from;
}
}, { immediate: true });
function updateTemplates(ids, value) {
for (const id of ids) templates[id].enable.value = value;
}
return {
matrix,
isModernized,
modernizedId
};
}
function getFavorRate(favor) {
switch (favor) {
case 2: return .01;
case 3: return .03;
case 4: return .06;
case 5: return .09;
case 6: return .12;
default: return 0;
}
}
//#endregion
//#region src/core/serialize/clone.ts
function createClone(options) {
const handlers = new Map(options.handlers);
return clone;
function clone(obj) {
if (obj === null || obj === void 0) return obj;
if (handlers.has(obj.constructor)) {
const handler = handlers.get(obj.constructor);
return handler(obj);
}
if (typeof obj !== "object") return obj;
if (Array.isArray(obj)) return cloneArray(obj);
return cloneObject(obj);
}
function cloneArray(arr) {
const res = [];
for (let i = 0; i < arr.length; i++) {
const cur = arr[i];
res[i] = clone(cur);
}
return res;
}
function cloneObject(obj) {
const res = {};
for (const key in obj) {
const cur = Reflect.get(obj, key);
res[key] = clone(cur);
}
return res;
}
}
//#endregion
//#region src/core/serialize/index.ts
const registry = [];
register("surface-fleet", SurfaceFleet, {
paths: [
"name",
"commander1",
"commander2",
"main1",
"main2",
"main3",
"vanguard1",
"vanguard2",
"vanguard3"
],
initialize(_, raw) {
return createFleet("surface", raw.name);
}
});
register("submarine-fleet", SubmarineFleet, {
paths: [
"name",
"commander1",
"commander2",
"submarine1",
"submarine2",
"submarine3"
],
initialize(_, raw) {
return createFleet("submarine", raw.name);
}
});
register("ship", Ship, {
paths: [
"id",
"level",
"favor",
"breakout",
"strengthen.adjustAttrs",
"strengthen.blueprint",
"transform.matrix[][][].enable",
"equip1",
"equip2",
"equip3",
"equip4",
"equip5",
"spweapon"
],
initialize(options, raw) {
return createShip(raw.id, { technology: options.technology });
}
});
register("equip", Equip, {
paths: ["id", "level"],
initialize(_, raw) {
return createEquip(raw.id);
}
});
register("spweapon", SPWeapon, {
paths: ["id", "level"],
initialize(_, raw) {
return createSPWeapon(raw.id);
}
});
register("commander", Commander, {
paths: [
"id",
"level",
"name",
"abilities[]"
],
initialize(_, raw) {
return createCommander(raw.id);
}
});
register("commander-ability", CommanderAbility, {
paths: ["id"],
initialize(_, raw) {
return createCommanderAbility(raw.id);
}
});
function register(name, structure, options) {
const { paths, initialize } = options;
const parsedPaths = paths.map((path) => path.split(/\.|(?=\[\])/));
function serialize(ctx, source) {
const normalizedPaths = parsedPaths.flatMap((path) => [...normalizePath(source, path)]);
const raw = {};
const key = ctx.track(name, source, raw);
for (const path of normalizedPaths) {
let srcObj = source;
let rawObj = raw;
for (let i = 0; i < path.length; i++) {
const key$1 = path[i];
const nextKey = path[i + 1];
srcObj = srcObj[key$1];
if (nextKey !== void 0) rawObj = rawObj[key$1] ??= {};
else if (srcObj === void 0) break;
else {
const val = toRaw(toValue(srcObj));
rawObj[key$1] = ctx.resolve(val);
}
}
}
return key;
}
function deserialize(options$1, ctx, raw, id) {
const source = initialize(options$1, raw);
const normalizedPaths = parsedPaths.flatMap((path) => [...normalizePath(raw, path)]);
ctx.track(id, name, source);
for (const path of normalizedPaths) {
let srcObj = source;
let rawObj = raw;
for (let i = 0; i < path.length; i++) {
const key = path[i];
const nextKey = path[i + 1];
rawObj = rawObj[key];
if (nextKey === void 0) {
const val = ctx.resolve(rawObj);
if (isRef(srcObj[key])) srcObj[key].value = val;
else srcObj[key] = val;
}
srcObj = srcObj[key];
}
}
return source;
}
registry.push({
name,
structure,
serialize,
deserialize
});
return {
serialize,
deserialize
};
}
function createSerializer(options) {
const internalKeys = new WeakMap();
const mapping = options.mapping ?? {};
let sources = {};
let curId = 0;
function serialize(source) {
const serialized = new WeakSet();
const ctx = {
resolve(source$1) {
if (source$1 && serialized.has(source$1)) return internalKeys.get(source$1);
for (const reg of registry) if (source$1 instanceof reg.structure) return reg.serialize(ctx, source$1);
return source$1;
},
track(name, source$1, raw) {
serialized.add(source$1);
let id;
let key;
if (!internalKeys.has(source$1)) {
id = curId++;
key = resolveInternalKey(id, name);
internalKeys.set(source$1, key);
} else {
key = internalKeys.get(source$1);
id = parseInternalKey(key).id;
}
mapping[id] = raw;
return key;
}
};
const clone = createClone({ handlers: registry.map((reg) => [reg.structure, (obj) => reg.serialize(ctx, obj)]) });
curId = Number(Object.keys(mapping).at(-1) ?? -1) + 1;
return clone(source);
}
function deserialize(raw) {
const ctx = {
resolve(raw$1) {
if (typeof raw$1 !== "string") return raw$1;
try {
const { name, id } = parseInternalKey(raw$1);
if (id in sources) return sources[id];
const obj = mapping[id];
const { deserialize: deserialize$1 } = registry.find((r) => r.name === name);
return deserialize$1(options, ctx, obj, id);
} catch {
return raw$1;
}
},
track(id, name, source) {
const key = resolveInternalKey(id, name);
internalKeys.set(source, key);
sources[id] = source;
return source;
}
};
const clone = createClone({ handlers: [[String, (raw$1) => ctx.resolve(raw$1)]] });
return clone(raw);
}
function cleanup(raw) {
sources = {};
const ids = new Set(Object.keys(mapping).map(Number));
for (const id of traverse(raw)) ids.delete(id);
for (const id of ids) delete mapping[id];
function* traverse(raw$1) {
if (typeof raw$1 === "string") try {
const { id } = parseInternalKey(raw$1);
yield id;
yield* traverse(mapping[id]);
} catch {}
else if (Array.isArray(raw$1)) for (const item of raw$1) yield* traverse(item);
else if (typeof raw$1 === "object" && raw$1 !== null) for (const value of Object.values(raw$1)) yield* traverse(value);
}
}
return {
mapping,
serialize,
deserialize,
cleanup
};
}
function* normalizePath(obj, path) {
const key = path[0];
if (obj === void 0 || !path.length) {
if (key !== "[]") yield [];
} else if (key === "[]") for (const [key$1, value] of Object.entries(obj)) for (const res of normalizePath(value, path.slice(1))) yield [key$1, ...res];
else for (const res of normalizePath(obj[key], path.slice(1))) yield [key, ...res];
}
function resolveInternalKey(id, name) {
return `id(${name}):${id}`;
}
function parseInternalKey(key) {
const match = key.match(/^id\((?<name>[-\w]+)\):(?<id>\d+)$/);
if (!match) throw 0;
const { name, id } = match.groups;
return {
name,
id: Number(id)
};
}
//#endregion
//#region src/core/technology.ts
function useTechnology() {
const attrs = ref(createTechnologyAttributes());
function get(type, attr) {
if (attr === "speed" || attr === "luck") return 0;
return attrs.value[type]?.[attr] ?? 0;
}
return {
attrs,
get
};
}
function createTechnologyAttributes() {
return {
...structuredClone(ShareCfg.fleet_tech_attributes),
get 20() {
return this[1];
},
get 21() {
return this[1];
},
get 23() {
return this[22];
},
get 24() {
return this[22];
}
};
}
//#endregion
export { Commander, CommanderAbility, Equip, Favor, Fleet, SPWeapon, Ship, StrengthenType, SubmarineFleet, SurfaceFleet, createAttributes, createCommander, createCommanderAbility, createEquip, createFleet, createSPWeapon, createSerializer, createShip, createTechnologyAttributes, useTechnology };