Skip to content
Snippets Groups Projects
Commit c76ea8ab authored by Empress Sela's avatar Empress Sela
Browse files

Fixes; recalculate IBC on slave cheat edit

- Handle missing parents in kinship calculation
parent 6e3828bc
No related branches found
No related tags found
No related merge requests found
......@@ -71,6 +71,7 @@
You perform the dark rituals, pray to the dark gods, and sell your soul for the power to reshape your body and life at will. What a cheater!
<<set $PC = clone($tempSlave)>>
<<run ibc.recalculate_id(-1)>>
<<run PCDatatypeCleanup()>>
<<set $upgradeMultiplierArcology = upgradeMultiplier('engineering')>>
<<set $upgradeMultiplierMedicine = upgradeMultiplier('medicine')>>
......
......@@ -322,6 +322,7 @@ You perform the dark rituals, pray to the dark gods, and sell your soul for the
<br><br>This slave has been changed forever and you have lost a bit of your soul, YOU CHEATER!
<<set $activeSlave = clone($tempSlave)>>
<<run ibc.recalculate_coeff_id($activeSlave.ID)>>
<<unset $tempSlave>>
<<set _escn = $cribs.findIndex(function(s) { s.ID === $activeSlave.ID; })>>
<<if def _escn>>
......
......@@ -66,6 +66,7 @@ You perform the dark rituals, pray to the dark gods, and sell your soul for the
<br><br>This slave has been changed forever and you have lost a bit of your soul, YOU CHEATER!
<<set $activeSlave = clone($tempSlave)>>
<<run ibc.recalculate_coeff_id($activeSlave.ID)>>
<<unset $tempSlave>>
<<set _escdc = $slaveIndices[$activeSlave.ID]>>
<<if def _escdc>>
......
......@@ -225,6 +225,7 @@ You perform the dark rituals, pray to the dark gods, and sell your soul for the
<br><br>This slave has been changed forever and you have lost a bit of your soul, YOU CHEATER!
<<set $activeSlave = clone($tempSlave)>>
<<run ibc.recalculate_coeff_id($activeSlave.ID)>>
<<unset $tempSlave>>
<<set _escn = $slaveIndices[$activeSlave.ID]>>
<<if def _escn>>
......
......@@ -256,7 +256,7 @@ globalThis.ibc = (() => {
};
// Make nodes for an array of slaves
let nodes_slaves = slaves => {
let nodes_slaves = (slaves, ignore_coeffs=false) => {
let nodes = {};
// Recursively create the nodes we need, moving upwards from the given slave
......@@ -293,7 +293,7 @@ globalThis.ibc = (() => {
// Try to use a cached CoI for performance
let sg = find_gp(s.ID);
if (sg !== null && "inbreedingCoeff" in sg && sg.inbreedingCoeff !== -1) {
if (!ignore_coeffs && sg !== null && "inbreedingCoeff" in sg && sg.inbreedingCoeff !== -1) {
nodes[s.ID]._coeff = sg.inbreedingCoeff;
}
};
......@@ -309,12 +309,12 @@ globalThis.ibc = (() => {
// Determine the coefficients of inbreeding of an array of slaves. Returns a mapping of their
// ID to their coefficient of inbreeding
let coeff_slaves = slaves => {
let coeff_slaves = (slaves, ignore_coeffs=false) => {
let ret = {};
// First, pull as many existing CoI off the slaves
slaves.forEach(s => {
let sg = find_gp(s.ID);
if (sg !== null && "inbreedingCoeff" in sg && sg.inbreedingCoeff !== -1) {
if (!ignore_coeffs && sg !== null && "inbreedingCoeff" in sg && sg.inbreedingCoeff !== -1) {
ret[s.ID] = sg.inbreedingCoeff;
}
});
......@@ -322,7 +322,7 @@ globalThis.ibc = (() => {
// Now do any we haven't done already
slaves = slaves.filter(s => (!(s.ID in ret)));
if (slaves.length > 0) {
let nodes = nodes_slaves(slaves);
let nodes = nodes_slaves(slaves, ignore_coeffs);
// Compute coefficients
slaves.forEach(s => {
......@@ -334,19 +334,20 @@ globalThis.ibc = (() => {
};
// Determine the kinship between two slaves `a` and `b`
let kinship_slaves = (a, b) => {
let nodes = nodes_slaves([a, b]);
let kinship_slaves = (a, b, ignore_coeffs=false) => {
if (a === 0 || b === 0)
return 0;
return kinship(nodes[a.ID], nodes[b.ID]);
return kinship_one_many(a, [b], ignore_coeffs);
};
// Determine the coefficient of inbreeding of a single slave
let coeff_slave = slave => {
if ("inbreedingCoeff" in slave && slave.inbreedingCoeff !== -1)
let coeff_slave = (slave, ignore_coeffs=false) => {
if (!ignore_coeffs && "inbreedingCoeff" in slave && slave.inbreedingCoeff !== -1)
return slave.inbreedingCoeff;
let gp = find_gp(slave.ID);
if (gp !== null && "inbreedingCoeff" in gp && gp.inbreedingCoeff !== -1)
if (!ignore_coeffs && gp !== null && "inbreedingCoeff" in gp && gp.inbreedingCoeff !== -1)
return gp.inbreedingCoeff;
return coeff_slaves([slave])[slave.ID];
......@@ -354,21 +355,140 @@ globalThis.ibc = (() => {
// Determine the kinship between one and many slaves. Returns an mapping from the ID of each of
// the slaves in `others` to its kinship with slave `a`
let kinship_one_many = (a, others) => {
let nodes = nodes_slaves(others.concat([a]));
let kinship_one_many = (a, others, ignore_coeffs=false) => {
if (a === 0) {
let ks = {};
others.forEach(s => {
if (s === 0)
ks[s] = 0;
else
ks[s.ID] = 0;
});
return ks;
}
let nodes = nodes_slaves(others.concat([a]), ignore_coeffs);
let ks = {};
others.forEach(s => {
ks[s.ID] = kinship(nodes[a.ID], nodes[s.ID]);
if (s === -3) {
// Fake a slave object for the player's old master
s = {ID: -3, mother: 0, father: 0, inbreedingCoeff: 0};
}
if (s === 0)
ks[s] = 0;
else
ks[s.ID] = kinship(nodes[a.ID], nodes[s.ID]);
});
return ks;
};
// Recalculate the inbreeding coefficient for all slaves dependent on the passed IDs (e.g. the
// slaves themselves and all of their children). This will replace the inbreeding coefficients
// wherever they exist with the computed values, ignoring all cached values.
//
// This should be called if parents are changed.
let recalculate_coeff_ids = (ids) => {
// These are all the slave-like objects, i.e. they have ID, mother, and father. There will
// be multiple elements with the same ID: we want this, since we have to replace all
// occurrences of the COI for the affected slaves
let all_slave_like = V.slaves.concat(V.genePool).concat(V.cribs).concat(V.tanks).concat(Object.values(V.missingTable));
if (V.boomerangSlave !== 0)
all_slave_like.push(V.boomerangSlave);
if (V.traitor !== 0)
all_slave_like.push(V.traitor);
if (V.activeSlave !== 0)
all_slave_like.push(V.activeSlave);
all_slave_like.push(V.PC);
// Add a fake entry for the PC's old master
all_slave_like.push({ID: -3, mother: 0, father: 0, inbreedingCoeff: 0});
// Gather the genetics of all current fetuses
let all_fetuses = V.slaves.filter(s => s.preg > 0).map(s => s.womb.map(i => i.genetics)).reduce((res, cur) => res.concat(cur), []);
// Recursively find all of the given ID's children, born and unborn
let find_children_rec = (id, cur_slaves, cur_fetuses, cur_fetus_parents) => {
// Add fetuses
all_fetuses.filter(f => (f.father === id || f.mother === id)).forEach(f => {
// We may have to manually add the parents later
let actual_f = or_null(f.father);
let actual_m = or_null(f.mother);
if (actual_f !== null)
cur_fetus_parents.add(actual_f);
if (actual_m !== null)
cur_fetus_parents.add(actual_m);
cur_fetuses.add(f);
});
// Recursively add slaves
all_slave_like.filter(s => (s.father === id || s.mother === id)).forEach(s => {
if (!cur_slaves.has(s.ID)) {
cur_slaves.add(s.ID);
find_children_rec(s.ID, cur_slaves, cur_fetuses, cur_fetus_parents);
}
});
};
// We only need slave IDs, since we have to update all of their entries (including GP)
let needed_slave_ids = new Set();
// Since each fetus has a unique record, a set still suffices
let needed_fetuses = new Set();
let needed_parent_ids = new Set();
// Find all the children of the IDs we need to do
ids.forEach(id => {
needed_slave_ids.add(id);
find_children_rec(id, needed_slave_ids, needed_fetuses, needed_parent_ids);
});
// Now we assemble the tree from the slaves
let needed_slaves = [];
needed_slave_ids.forEach(id => {
if (typeof id !== "undefined")
needed_slaves.push(all_slave_like.find(s => s.ID === id));
});
needed_parent_ids.forEach(id => {
if (typeof id !== "undefined" && !needed_slave_ids.has(id))
needed_slaves.push(all_slave_like.find(s => s.ID == id));
});
let nodes = nodes_slaves(needed_slaves, true);
// Now calculate the inbreeding coefficients (they're cached in the tree once calculated)
all_slave_like.filter(s => needed_slave_ids.has(s.ID)).forEach(s => {
s.inbreedingCoeff = coeff(nodes[s.ID]);
});
// Finally, handle all of the kinship for the fetuses
let kinship_cache = new Map(); // Manually cache it
needed_fetuses.forEach(f => {
if (or_null(f.mother) === null || or_null(f.father) === null) {
f.inbreedingCoeff = 0;
return;
}
// Use a string of the form "parent;parent" to store the cache value; since kinship is
// commutative, the minumum parent ID will be first
let kinship_str = Math.min(f.mother, f.father) + ';' + Math.max(f.mother, f.father);
if (!kinship_cache.has(kinship_str))
kinship_cache.set(kinship_str, kinship(nodes[f.mother], nodes[f.father]));
f.inbreedingCoeff = kinship_cache.get(kinship_str);
});
};
let recalculate_coeff_id = (id) => {
return recalculate_coeff_ids([id]);
};
return {
coeff: coeff_slave,
coeff_slaves,
kinship: kinship_slaves,
kinship_one_many
kinship_one_many,
recalculate_coeff_ids,
recalculate_coeff_id
};
})();
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment