diff --git a/icons.css b/icons.css index 4a350cc8..2ccbb190 100644 --- a/icons.css +++ b/icons.css @@ -288,6 +288,10 @@ .icon-button-surprise:before {content:'⚡'; padding-right: .4em;} .icon-button-shock:before {content:'💫'; padding-right: .4em;} + +.icon-button-flee:before {content:'⛵'; padding-right: .4em;} +.icon-button-waiting:before {content:'⌛'; padding-right: .4em;} + .icon-button-maneuvering:before {content:'💢'; padding-right: .4em;} .icon-button-dogfight:before {content:'🐕'; padding-right: .4em;} diff --git a/index.html b/index.html index 824e00af..d8a46d18 100644 --- a/index.html +++ b/index.html @@ -2481,7 +2481,7 @@ @@ -2512,17 +2512,18 @@ diff --git a/modules/ui/battle-screen.js b/modules/ui/battle-screen.js index b53789ef..e2ad006f 100644 --- a/modules/ui/battle-screen.js +++ b/modules/ui/battle-screen.js @@ -37,11 +37,11 @@ class Battle { // add listeners document.getElementById("battleType").addEventListener("click", ev => this.toggleChange(ev)); document.getElementById("battleType").nextElementSibling.addEventListener("click", ev => Battle.prototype.context.changeType(ev)); - document.getElementById("battleNameShow").addEventListener("click", () => this.showNameSection()); - document.getElementById("battleNamePlace").addEventListener("change", ev => this.place = ev.target.value); - document.getElementById("battleNameFull").addEventListener("change", ev => this.changeName(ev)); - document.getElementById("battleNameCulture").addEventListener("click", () => this.generateName(Names.getCulture(pack.cells.culture[this.cell], null, null, ""))); - document.getElementById("battleNameRandom").addEventListener("click", () => this.generateName(Names.getBase(rand(nameBases.length-1)))); + document.getElementById("battleNameShow").addEventListener("click", () => Battle.prototype.context.showNameSection()); + document.getElementById("battleNamePlace").addEventListener("change", ev => Battle.prototype.context.place = ev.target.value); + document.getElementById("battleNameFull").addEventListener("change", ev => Battle.prototype.context.changeName(ev)); + document.getElementById("battleNameCulture").addEventListener("click", () => Battle.prototype.context.generateName("culture")); + document.getElementById("battleNameRandom").addEventListener("click", () => Battle.prototype.context.generateName("random")); document.getElementById("battleNameHide").addEventListener("click", this.hideNameSection); document.getElementById("battleAddRegiment").addEventListener("click", this.addSide); document.getElementById("battleRoll").addEventListener("click", () => Battle.prototype.context.randomize()); @@ -136,8 +136,8 @@ class Battle { ${regiment.icon}`; const body = ``; - let initial = `${icon}${regiment.name.slice(0, 24)}`; - let casualties = `${state.fullName.slice(0, 26)}`; + let initial = `${icon}${regiment.name.slice(0, 24)}`; + let casualties = `${state.fullName.slice(0, 26)}`; let survivors = `Distance to base: ${distance} ${distanceUnitInput.value}`; for (const u of options.military) { @@ -239,7 +239,10 @@ class Battle { $("#battleScreen").dialog({"title":this.name}); } - generateName(place) { + generateName(type) { + const place = type === "culture" + ? Names.getCulture(pack.cells.culture[this.cell], null, null, "") + : Names.getBase(rand(nameBases.length-1)); document.getElementById("battleNamePlace").value = this.place = place; document.getElementById("battleNameFull").value = this.name = this.defineName(); $("#battleScreen").dialog({"title":this.name}); @@ -280,8 +283,13 @@ class Battle { "surrendering": {"melee":.1, "ranged":.1, "mounted":.05, "machinery":.01, "naval":.01, "armored":.02, "aviation":.01, "magical":.03}, // reduced // ambush phases - "surprise": {"melee":2.2, "ranged":3, "mounted":1.5, "machinery":1.3, "naval":1, "armored":1.3, "aviation":1, "magical":2}, // increased - "shock": {"melee":.8, "ranged":.8, "mounted":.6, "machinery":.5, "naval":.5, "armored":.1, "aviation":.5, "magical":.7} // reduced + "surprise": {"melee":2, "ranged":2.4, "mounted":1, "machinery":1, "naval":1, "armored":1, "aviation":.8, "magical":1.2}, // increased + "shock": {"melee":.5, "ranged":.5, "mounted":.5, "machinery":.4, "naval":.3, "armored":.1, "aviation":.4, "magical":.5}, // reduced + + // langing phases + "landing": {"melee":.8, "ranged":.6, "mounted":.6, "machinery":.5, "naval":.5, "armored":.5, "aviation":.5, "magical":.6}, // reduced + "flee": {"melee":.1, "ranged":.01, "mounted":.5, "machinery":.01, "naval":.5, "armored":.1, "aviation":.2, "magical":.05}, // reduced + "waiting": {"melee":.05, "ranged":.5, "mounted":.05, "machinery":.5, "naval":2, "armored":.05, "aviation":.5, "magical":.5} // reduced }; const forces = this.getJoinedForces(this[side].regiments); @@ -406,12 +414,27 @@ class Battle { } const getLandingPhase = () => { - // ⚓ landing / 💫 shock OR 🛡️ defense, ⚔️ melee, 🏳️ retreat / 🐎 pursue + const prev = [this.attackers.phase || "landing", this.defenders.phase || "defense"]; // previous phase + if (prev[1] === "waiting") return ["flee", "waiting"]; + if (prev[1] === "pursue") return ["flee", P(.3) ? "pursue" : "waiting"]; + if (prev[1] === "retreat") return ["pursue", "retreat"]; + + if (prev[0] === "landing") { + const attackers = P(i/2) ? "melee" : "landing"; + const defenders = i ? prev[1] : P(.5) ? "defense" : "shock"; + return [attackers, defenders]; + } + + if (P(1 - morale[0] / 40)) return ["flee", "pursue"]; // chance if moral < 40 + if (P(1 - morale[1] / 25)) return ["pursue", "retreat"]; // chance if moral < 25 + + return ["melee", "melee"]; // default option } const getAirBattlePhase = () => { // 🎯 maneuvering, 🐕 dogfight, 🏳️ retreat / 🐎 pursue + } @@ -429,10 +452,14 @@ class Battle { this.attackers.phase = phase[0]; this.defenders.phase = phase[1]; - document.getElementById("battlePhase_attackers").className = "icon-button-" + this.attackers.phase; - document.getElementById("battlePhase_defenders").className = "icon-button-" + this.defenders.phase; - document.getElementById("battlePhase_attackers").dataset.tip = battleBody.querySelector(".battlePhases > [data-phase='"+phase[0]+"']").dataset.tip; - document.getElementById("battlePhase_defenders").dataset.tip = battleBody.querySelector(".battlePhases > [data-phase='"+phase[1]+"']").dataset.tip; + + const buttonA = document.getElementById("battlePhase_attackers"); + buttonA.className = "icon-button-" + this.attackers.phase; + buttonA.dataset.tip = buttonA.nextElementSibling.querySelector("[data-phase='"+phase[0]+"']").dataset.tip; + + const buttonD = document.getElementById("battlePhase_defenders"); + buttonD.className = "icon-button-" + this.defenders.phase; + buttonD.dataset.tip = buttonD.nextElementSibling.querySelector("[data-phase='"+phase[1]+"']").dataset.tip; } run() { @@ -442,19 +469,20 @@ class Battle { // calculate casualties const attack = this.attackers.power * (this.attackers.die / 10 + .4); - const defence = this.defenders.power * (this.defenders.die / 10 + .4); + const defense = this.defenders.power * (this.defenders.die / 10 + .4); // casualties modifier for phase const phase = { "skirmish":.1, "melee":.2, "pursue":.3, "retreat":.3, "boarding":.2, "shelling":.1, "chase":.03, "withdrawal": .03, "blockade":0, "sheltering":0, "sortie":.1, "bombardment":.05, "storming":.2, "defense":.2, "looting":.5, "surrendering":.5, - "surprise":.3, "shock":.3 + "surprise":.3, "shock":.3, + "landing":.3, "flee":0, "waiting":0 }; const casualties = Math.random() * (Math.max(phase[this.attackers.phase], phase[this.defenders.phase])); // total casualties, ~10% per iteration - const casualtiesA = casualties * defence / (attack + defence); // attackers casualties, ~5% per iteration - const casualtiesD = casualties * attack / (attack + defence); // defenders casualties, ~5% per iteration + const casualtiesA = casualties * defense / (attack + defense); // attackers casualties, ~5% per iteration + const casualtiesD = casualties * attack / (attack + defense); // defenders casualties, ~5% per iteration this.calculateCasualties("attackers", casualtiesA); this.calculateCasualties("defenders", casualtiesD);