Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/KC3Kai/kancolle-replay in…
Browse files Browse the repository at this point in the history
…to gh-pages
  • Loading branch information
fourinone41 committed Feb 29, 2024
2 parents 829cb82 + 4bc088a commit c76ce63
Show file tree
Hide file tree
Showing 8 changed files with 7,385 additions and 3 deletions.
Binary file added assets/stats/item91.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7,243 changes: 7,243 additions & 0 deletions js/data/shell_range_weights.json

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion js/kcships.js
Original file line number Diff line number Diff line change
Expand Up @@ -1948,7 +1948,12 @@ function LHA(id,name,side,LVL,HP,FP,TP,AA,AR,EV,ASW,LOS,LUK,RNG,planeslots) {
};
LHA.prototype = Object.create(Ship.prototype);
LHA.prototype.planeasw = 1;
LHA.prototype.canASW = CAV.prototype.canASW;
LHA.prototype.canASW = function() {
if (this.mid == 945 || this.mid == 727) {
return !!this.equiptypes[DEPTHCHARGE];
}
return CAV.prototype.canASW.call(this);
}

function DE(id,name,side,LVL,HP,FP,TP,AA,AR,EV,ASW,LOS,LUK,RNG,planeslots) {
Ship.call(this,id,name,side,LVL,HP,FP,TP,AA,AR,EV,ASW,LOS,LUK,RNG,planeslots);
Expand Down
54 changes: 53 additions & 1 deletion js/kcsim.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ var SIMCONSTS = {
enableSkipTorpBonus: true,
enableAirstrikeSpecialBonus: true,
enableASFit: false,
enableRangeWeights: false,
echelonOld: {shellmod:.6,torpmod:.6,ASWmod:1,AAmod:1, shellacc:1.2,torpacc:.6,NBacc:.8, shellev:1.2,torpev:1.3,NBev:1.1,ASWev:1.3, id:4},
echelonNew: {shellmod:.75,torpmod:.6,ASWmod:1.1,AAmod:1, shellacc:1.2,torpacc:.75,NBacc:.9, shellev:1.4,torpev:1.3,NBev:1.3,ASWev:1.3, id:4},
nbattack7Old: { dmgMod: 1.3, accMod: 1.1, chanceMod: 1.3, name: 'DDCI (GTR)' },
Expand Down Expand Up @@ -3028,6 +3029,13 @@ function airstrikeLBAS(lbas,target,slot,contactMod,contactModLB,isjetphase) {
}

function orderByRange(ships,order,includeSubs,isOASW) {
if (SIMCONSTS.enableRangeWeights && ships.length && !ships.find(ship => ship.isSub)) {
let orderShips = SHELL_RANGE_WEIGHTS.getRollShips(ships,includeSubs,isOASW);
if (orderShips) {
order.push.apply(order,orderShips);
return;
}
}
var ranges = []; //fleet 1
for (var i=0; i<ships.length; i++) {
if (!includeSubs && ships[i].isSub) continue;
Expand Down Expand Up @@ -4654,4 +4662,48 @@ function getDetection(shipsF,shipsE) {
}
if (numReconSlots <= 0) return DetectionResult.NotFound;
return (shotdownVal <= 0)? DetectionResult.Failure : DetectionResult.FailureLost;
}
}

var SHELL_RANGE_WEIGHTS = {
_data: null,
_cache: { ranges: {}, weightTotals: {} },
_keysMiss: null,

init: async function() {
this._data = await fetch('js/data/shell_range_weights.json').then(resp => resp.ok ? resp.json() : null);
},

getRangeKey: function(ranges) {
let rangesOrder = [...new Set(ranges)].sort((a,b)=>b-a);
let key = ranges.join('');
return this._cache.ranges[key] || (this._cache.ranges[key] = ranges.map(r => String.fromCharCode(65+rangesOrder.indexOf(r))).join(''));
},
getRoll: function(rangeKey) {
if (!this._data[rangeKey]) return null;
let orderKeys = Object.keys(this._data[rangeKey]);
let weightTotal = this._cache.weightTotals[rangeKey] || (this._cache.weightTotals[rangeKey] = orderKeys.reduce((a,b) => a + this._data[rangeKey][b],0));
let roll = Math.floor(Math.random()*weightTotal);
for (let orderKey of orderKeys) {
if (roll < this._data[rangeKey][orderKey]) return orderKey;
roll -= this._data[rangeKey][orderKey];
}
return null;
},
getRollShips: function(ships,includeSubs,isOASW) {
let shipsCanShell = ships.filter(ship => !ship.retreated && (includeSubs || !ship.isSub) && ship.canShell(isOASW));
let rangeKey = this.getRangeKey(shipsCanShell.map(ship => ship.RNG));
let orderKey = this.getRoll(rangeKey);
if (!orderKey && shipsCanShell.length) {
this._keysMiss[shipsCanShell[0].side][rangeKey] = this._keysMiss[shipsCanShell[0].side][rangeKey] + 1 || 1;
}
return orderKey && orderKey.split('').map(num => shipsCanShell[+num]);
},

resetMissing: function() {
this._keysMiss = { 0: {}, 1: {} };
},
getMissing: function(side) {
return Object.keys(this._keysMiss[side]).filter(key => key.length >= 2 && key.length > (new Set(key)).size).sort((a,b) => this._keysMiss[side][b] - this._keysMiss[side][a]);
},
};
SHELL_RANGE_WEIGHTS.init();
1 change: 1 addition & 0 deletions js/simulator-ui/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,7 @@ window.CONVERT = {
lbas: [],
useBalloon: battleUI.useBalloon,
useSmoke: battleUI.useSmoke,
useAnchorageRepair: battleUI.useAnchorageRepair,
};
if (battleUI.doNBCond) nodeInput.doNBCond = battleUI.doNBCond;
for (let i=0; i<battleUI.lbasWaves.length; i++) {
Expand Down
68 changes: 67 additions & 1 deletion js/simulator-ui/sim-interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ var CONST = window.COMMON.getConst({
'warn_vanguard': { txt: 'Note: Destroyers have different vanguard evasion mods in event maps, see "Show Advanced" if simulating event maps', excludeImport: true },
'warn_enemy_unset_stats': { txt: 'Warning: Node <0> has enemies with unknown and unset evasion/luck stats (still set to 0/1).', excludeImport: true },
'warn_debuff_dmg': { txt: 'Warning: "Debuff Dmg" is a legacy setting and may be inaccurate to the mechanic, recommended to modify enemy\'s Armour stat instead.' },
'warn_range_weights_f': { txt: 'Warning: Player Fleets - Following range combination weights are unknown and not used: <0>' },
'warn_range_weights_e': { txt: 'Warning: Enemy Fleets - Following range combination weights are unknown and not used: <0>' },
},
});

Expand Down Expand Up @@ -88,6 +90,7 @@ var SIM = {
totalSteelR: 0,
totalBuckets: 0,
totalDamecon: 0,
totalAnchorageRepair: 0,
totalGaugeDamage: 0,
totalEmptiedPlanes: 0,
totalEmptiedLBAS: 0,
Expand Down Expand Up @@ -585,6 +588,19 @@ var SIM = {
}
}
}

if (dataInput.consts.enableRangeWeights) {
SHELL_RANGE_WEIGHTS.resetMissing();
}
},

_checkWarningsPostRun: function(dataInput) {
if (dataInput.consts.enableRangeWeights) {
let keysMissingF = SHELL_RANGE_WEIGHTS.getMissing(0);
if (keysMissingF.length) this._addWarning('warn_range_weights_f', [keysMissingF.join(', ')]);
let keysMissingE = SHELL_RANGE_WEIGHTS.getMissing(1);
if (keysMissingE.length) this._addWarning('warn_range_weights_e', [keysMissingE.join(', ')]);
}
},

_checkSettingsFCF: function(settingsFCF,fleetF,battleInd=-1) {
Expand Down Expand Up @@ -616,6 +632,47 @@ var SIM = {
return true;
},

_doAnchorageRepair: function(fleetF) {
let type = 0, hpRepairedTotal = 0;
let ships = fleetF.ships.slice(1);
if (fleetF.combinedWith) ships = ships.concat(fleetF.combinedWith.ships);
let shipR = null;
if (shipR = ships.find(ship => ship.mid == 187 && ship.HP/ship.maxHP > .5 && ship.equips.find(eq => eq.type == SRF))) type = 1;
else if (shipR = ships.find(ship => ship.mid == 958 && ship.HP/ship.maxHP > .5 && ship.equips.find(eq => eq.type == SRF))) type = 3;
else if (shipR = ships.find(ship => ship.mid == 450 && ship.HP/ship.maxHP > .5 && ship.equips.find(eq => eq.type == SRF))) type = 2;
if (!type) return 0;

let hpPercent = 0, shipsRepair = [];
if (type == 1) {
hpPercent = .3;
if (shipR.equips[0] && shipR.equips[0].type == SRF) shipsRepair.push.apply(shipsRepair,fleetF.ships.slice(0,3));
if (shipR.equips[1] && shipR.equips[1].type == SRF) shipsRepair.push.apply(shipsRepair,fleetF.ships.slice(3));
if (fleetF.combinedWith && shipR.equips[2] && shipR.equips[2].type == SRF) shipsRepair.push.apply(shipsRepair,fleetF.combinedWith.ships.slice(0,3));
if (fleetF.combinedWith && shipR.equips[3] && shipR.equips[3].type == SRF) shipsRepair.push.apply(shipsRepair,fleetF.combinedWith.ships.slice(3));
} else if (type == 2) {
hpPercent = .25;
if (fleetF.combinedWith && shipR.equips[0] && shipR.equips[0].type == SRF) shipsRepair.push.apply(shipsRepair,fleetF.combinedWith.ships.slice(0,3));
if (fleetF.combinedWith && shipR.equips[1] && shipR.equips[1].type == SRF) shipsRepair.push.apply(shipsRepair,fleetF.combinedWith.ships.slice(3));
} else if (type == 3) {
hpPercent = .28;
if (fleetF.combinedWith && shipR.equips[0] && shipR.equips[0].type == SRF) shipsRepair.push.apply(shipsRepair,fleetF.combinedWith.ships.slice(0,3));
if (fleetF.combinedWith && shipR.equips[1] && shipR.equips[1].type == SRF) shipsRepair.push.apply(shipsRepair,fleetF.combinedWith.ships.slice(3));
if (shipR.equips[2] && shipR.equips[2].type == SRF) shipsRepair.push.apply(shipsRepair,fleetF.ships.slice(3));
}

for (let ship of shipsRepair) {
if (!ship) continue;
if (ship.HP >= ship.maxHP) continue;
if (ship.HP/ship.maxHP <= .25) continue;
let hpRepaired = Math.min(ship.maxHP - ship.HP, Math.ceil(hpPercent*ship.maxHP));
ship.HP += hpRepaired;
hpRepairedTotal += hpRepaired;
ship.morale += 7;
if (ship.morale > 100) ship.morale = 100;
}
return hpRepairedTotal;
},

_doSimSortie: function(dataInput,dataReplay) {
for (let i=0; i<this._compListsEnemy.length; i++) {
if (!this._compListsEnemy[i]) continue;
Expand Down Expand Up @@ -685,6 +742,14 @@ var SIM = {
window.underwaySupply(fleetF);
}

if (node.useAnchorageRepair) {
let cost = this._doAnchorageRepair(fleetF);
if (cost && this._results) {
this._results.totalSteelR += 3*cost;
this._results.totalAnchorageRepair++;
}
}

fleetF.useBalloon = !!node.useBalloon;
fleetE.useBalloon = !!node.useBalloon;

Expand Down Expand Up @@ -820,7 +885,8 @@ var SIM = {
}
n += numStep;
if (n >= numSim || this.cancelRun) {
callback({ progress: n, progressTotal: numSim, result: this._results });
this._checkWarningsPostRun(dataInput);
callback({ progress: n, progressTotal: numSim, result: this._results, warnings: this._warnings.slice() });
let timeTotal = Date.now() - timeStart;
console.log('time: ' + (timeTotal/1000) + ' sec');
this.cancelRun = false;
Expand Down
2 changes: 2 additions & 0 deletions js/simulator-ui/ui-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ var UI_MAIN = Vue.createApp({
smokeModTorpAccE: SIMCONSTS.smokeModTorpAccE.slice(),
smokeModAirAccF: SIMCONSTS.smokeModAirAccF.slice(),
smokeModAirAccE: SIMCONSTS.smokeModAirAccE.slice(),
enableRangeWeights: SIMCONSTS.enableRangeWeights,
},
settingsFCF: {
los: null,
Expand Down Expand Up @@ -288,6 +289,7 @@ var UI_MAIN = Vue.createApp({
useNormalSupport: 0,
useBalloon: false,
useSmoke: false,
useAnchorageRepair: false,

enemyComps: [],
};
Expand Down
13 changes: 13 additions & 0 deletions simulator.html
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,17 @@ <h2>Settings</h2>
<div><a href="https://docs.google.com/spreadsheets/d/1I_HMplw81mR7g9_jUKRmI7ylhlhKkuvGKtrpj3DJ9zo/edit#gid=0" target="_blank">Activation Rate Suggestions</a></div>
<div><a href="https://docs.google.com/spreadsheets/d/1sznusxVurE6iCr2s-gLNpBQ_g1BD5mEMDlltluMB1CE/edit#gid=1397813463" target="_blank">Other Suggestions and Data</a></div>
</div>
<div v-show="settings.showAdvanced">
<div><span class="subheader">Shelling Range Tie Randomness Weights:</span></div>
<div><label><input type="checkbox" v-model="settings.enableRangeWeights" :class="getClassSetting('enableRangeWeights')"/>Enable heuristic weights</label></div>
<div style="color:red">Warning: This setting is experimental and subject to change.</div>
<div style="font-style:italic">This setting's weights are based on sampling the number of occurrences of each ordering in DB data: this is only an estimate, the actual formula is unknown. Note this also means that some orderings may be incorrectly impossible to roll in simulator with this setting, if they are extremely rare in the actual game and were never recorded in DB.<br>Only range combinations with sufficient data are included, other combinations default to "uniform weights" (same as without this setting).</div>
<div>
Explanation:&nbsp;
<a href="https://en.kancollewiki.net/Shooting_Order_and_Targeting#Range_Tie_Randomness">[1]</a>&nbsp;
<a href="https://docs.google.com/spreadsheets/d/1grAtIhlm2YMN9iyvniJA-j1YNCC-SCnA8q6WUi-Ctpg/edit#gid=0">[2]</a>&nbsp;
</div>
</div>
</div>
<div>
<input type="button" value="Restore Defaults" @click="onclickRestoreSettings"/>
Expand Down Expand Up @@ -421,6 +432,7 @@ <h3>Statistics</h3>
<div id="divOther">
<div id="divChangeLog">
<div><span class="header">Change Log:</span></div>
<div>2024-02-29 - Anchorage repair node setting, provisional "Shelling Range Tie Randomness Weights" setting (see Show Advanced)</div>
<div>2023-09-28 - Provisional Smokescreen settings, see Show Advanced</div>
<div>2023-09-04 - Barrage Balloon node setting</div>
<div>2023-08-07 - Auto-Set Historical Bonuses settings</div>
Expand Down Expand Up @@ -517,6 +529,7 @@ <h3>Statistics</h3>
</div>
<div class="space"><label><input type="checkbox" v-model="battle.useSmoke"/><img src="assets/items/54.png" title="Use Smokescreen"/></label></div>
<div><label><input type="checkbox" v-model="battle.useBalloon"/><img src="assets/items/55.png" title="Enable Barrage Balloon Effects"/></label></div>
<div class="space"><label><input type="checkbox" v-model="battle.useAnchorageRepair"/><img src="assets/stats/item91.png" title="Use Anchorage Repair BEFORE battle"/></label></div>
</div>
<div>
<div><span class="header">Override Historical Bonuses:</span></div>
Expand Down

0 comments on commit c76ce63

Please sign in to comment.