From 82a59a5cbe97ab4b4772f8ec386ab4a482e80765 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Mon, 6 Jun 2022 17:39:19 -0700 Subject: [PATCH 01/65] Added trait ranks --- index.html | 648 ++++++++++++++++++++++++++++++++++++++------------ js/hellsim.js | 75 +++--- js/worker.js | 104 +++++--- 3 files changed, 612 insertions(+), 215 deletions(-) diff --git a/index.html b/index.html index d5558ca..a5889ac 100644 --- a/index.html +++ b/index.html @@ -31,153 +31,509 @@
Traits -
@@ -151,11 +163,13 @@
Traits @@ -166,11 +180,13 @@
Traits @@ -181,11 +197,13 @@
Traits @@ -196,11 +214,13 @@
Traits @@ -211,11 +231,13 @@
Traits @@ -226,11 +248,13 @@
Traits @@ -241,11 +265,13 @@
Traits @@ -256,11 +282,13 @@
Traits @@ -271,11 +299,13 @@
Traits @@ -286,11 +316,13 @@
Traits @@ -301,11 +333,13 @@
Traits @@ -316,11 +350,13 @@
Traits @@ -331,11 +367,13 @@
Traits @@ -346,11 +384,13 @@
Traits @@ -361,11 +401,13 @@
Traits @@ -376,11 +418,13 @@
Traits @@ -391,11 +435,13 @@
Traits @@ -406,11 +452,13 @@
Traits @@ -421,11 +469,13 @@
Traits @@ -436,11 +486,13 @@
Traits @@ -451,11 +503,13 @@
Traits @@ -466,11 +520,13 @@
Traits @@ -481,11 +537,13 @@
Traits @@ -496,11 +554,13 @@
Traits @@ -511,11 +571,13 @@
Traits @@ -526,11 +588,13 @@
Traits @@ -541,11 +605,13 @@
Traits @@ -556,11 +622,13 @@
Traits @@ -571,11 +639,13 @@
Traits diff --git a/js/worker.js b/js/worker.js index db3c575..ab0d4b5 100644 --- a/js/worker.js +++ b/js/worker.js @@ -49,10 +49,10 @@ onmessage = function(e) { function SimStart(id, simId, params, stats) { var tickLength = 250; if (params.hyper) { - tickLength *= TraitSelect(params.hyper, 0.98, 0.97, 0.95, 0.94, 0.93); + tickLength *= TraitSelect(params.hyper, 0.99, 0.98, 0.97, 0.95, 0.94, 0.93, 0.92); } if (params.slow) { - tickLength *= TraitSelect(params.slow, 1.13, 1.12, 1.1, 1.08, 1.06); + tickLength *= TraitSelect(params.slow, 1.14, 1.13, 1.12, 1.1, 1.08, 1.06, 1.05); } var sim = { id: id, @@ -348,7 +348,7 @@ function BloodWar(params, sim, stats) { } gemOdds = Math.round(gemOdds * (0.948 ** params.beacons)); if (params.ghostly) { - gemOdds = Math.round(gemOdds * TraitSelect(params.ghostly, 0.95, 0.9, 0.85, 0.8, 0.78)); + gemOdds = Math.round(gemOdds * TraitSelect(params.ghostly, 0.98, 0.95, 0.9, 0.85, 0.8, 0.78, 0.77)); } /* Patrols */ @@ -406,7 +406,7 @@ function BloodWar(params, sim, stats) { let maxDemons = Math.floor(sim.threat / 10); let demons = Rand(minDemons, maxDemons); - let ambushOdds = 30 + Math.max(params.elusive ? TraitSelect(params.elusive, 10, 15, 20, 25, 30) : 0, params.chameleon ? TraitSelect(params.chameleon, 10, 15, 20, 25, 30) : 0); + let ambushOdds = 30 + Math.max(params.elusive ? TraitSelect(params.elusive, 5, 10, 15, 20, 25, 30, 35) : 0, params.chameleon ? TraitSelect(params.chameleon, 5, 10, 15, 20, 25, 30, 35) : 0); if (Rand(0, ambushOdds) == 0) { /* Ambush @@ -465,7 +465,7 @@ function BloodWar(params, sim, stats) { } if (params.revive) { - let reviveDivisor = TraitSelect(params.revive, 4, 4, 3, 2, 2); + let reviveDivisor = TraitSelect(params.revive, 4, 4, 4, 3, 2, 2, 2); let reviveMax = soldiersKilled / reviveDivisor + 0.25; let revived = Math.round(Math.random() * reviveMax); sim.soldiers += revived; @@ -574,10 +574,10 @@ function BloodWar(params, sim, stats) { divisor *= 1.10; } if (params.blurry) { - divisor *= TraitSelect(params.blurry, 1.10, 1.15, 1.25, 1.35, 1.4); + divisor *= TraitSelect(params.blurry, 1.05, 1.10, 1.15, 1.25, 1.35, 1.4, 1.45); } if (params.instincts) { - divisor *= TraitSelect(params.instincts, 1.03, 1.05, 1.10, 1.15, 1.2); + divisor *= TraitSelect(params.instincts, 1.02, 1.03, 1.05, 1.10, 1.15, 1.2, 1.25); } if (params.shieldGen) { divisor += 250; @@ -854,10 +854,10 @@ function MercPrice(params, sim, stats) { price *= 1.1 ** sim.mercCounter; } if (params.brute){ - price *= TraitSelect(params.brute, 0.8, 0.75, 0.5, 0.4, 0.35); + price *= TraitSelect(params.brute, 0.85, 0.8, 0.75, 0.5, 0.4, 0.35, 0.3); } if (params.highPop){ - price *= TraitSelect(params.highPop, 0.5, 0.34, 0.26, 0.212, 0.18); + price *= TraitSelect(params.highPop, 0.5, 0.5, 0.34, 0.26, 0.212, 0.18, 0.158); } /* Convert to millions */ @@ -874,7 +874,7 @@ function HealSoldiers(params, sim, stats) { var healed = 1; if (params.regenerative) { - healed = TraitSelect(params.regenerative, 2, 3, 4, 5, 6); + healed = TraitSelect(params.regenerative, 1, 2, 3, 4, 5, 6, 7); } var healCredits = params.hospitals; @@ -887,9 +887,9 @@ function HealSoldiers(params, sim, stats) { healCredits += params.fibroblast * 2; if (params.cannibal) { if (healCredits >= 20) { - healCredits *= TraitSelect(params.cannibal, 1.08, 1.1, 1.15, 1.2, 1.22); + healCredits *= TraitSelect(params.cannibal, 1.06, 1.08, 1.1, 1.15, 1.2, 1.22, 1.24); } else { - healCredits += Math.floor(TraitSelect(params.cannibal, 1.6, 2, 3, 4, 4.4)); + healCredits += Math.floor(TraitSelect(params.cannibal, 1.2, 1.6, 2, 3, 4, 4.4, 4.8)); } healCredits += 3; } @@ -900,7 +900,7 @@ function HealSoldiers(params, sim, stats) { var healCost = 20; if (params.slowRegen) { - healCost *= TraitSelect(params.slowRegen, 1.4, 1.35, 1.25, 1.2, 1.15); + healCost *= TraitSelect(params.slowRegen, 1.45, 1.4, 1.35, 1.25, 1.2, 1.15, 1.12); } healed += Math.floor(healCredits / healCost); healCredits = healCredits % healCost; @@ -943,10 +943,10 @@ function PatrolCasualties(params, sim, stats, demons, ambush) { armor = 0; } if (params.armored) { - armor += TraitSelect(params.armored, 1, 1, 2, 2, 2); + armor += TraitSelect(params.armored, 0, 1, 1, 2, 2, 2, 2); } if (params.scales) { - armor += TraitSelect(params.scales, 1, 1, 1, 1, 2); + armor += TraitSelect(params.scales, 0, 1, 1, 1, 1, 2, 2); } } @@ -961,7 +961,7 @@ function PatrolCasualties(params, sim, stats, demons, ambush) { dead = Rand(0, (casualties + 1)); let wounded = casualties - dead; if (params.instincts) { - let proportion = TraitSelect(params.instincts, 0.15, 0.25, 0.5, 0.6, 0.65) + let proportion = TraitSelect(params.instincts, 0.1, 0.15, 0.25, 0.5, 0.6, 0.65, 0.7); let reduction = Math.floor(dead * proportion); dead -= reduction; wounded += reduction; @@ -991,17 +991,17 @@ function TrainingTime(params) { /* rate is percentage points per tick */ rate = 2.5; if (params.highPop) { - rate *= TraitSelect(params.highPop, 1.5, 2.5, 3.5, 4.5, 5.5); + rate *= TraitSelect(params.highPop, 1.2, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5); } if (params.diverse) { - rate /= TraitSelect(params.diverse, 1.35, 1.3, 1.25, 1.2, 1.15); + rate /= TraitSelect(params.diverse, 1.4, 1.35, 1.3, 1.25, 1.2, 1.15, 1.12); } rate *= 1 + params.bootCamps * bootCampBonus; if (params.beast) { - rate *= TraitSelect(params.beast, 1.04, 1.05, 1.1, 1.15, 1.2); + rate *= TraitSelect(params.beast, 1.03, 1.04, 1.05, 1.1, 1.15, 1.2, 1.25); } if (params.brute) { - rate += TraitSelect(params.brute, 1.25, 1.5, 2.5, 3, 3.5); + rate += TraitSelect(params.brute, 1, 1.25, 1.5, 2.5, 3, 3.5, 3.75); } rate *= 0.25; @@ -1023,7 +1023,7 @@ function ArmyRating(params, sim, size, wound) { } if (params.rhinoRage) { - rating += wounded * TraitSelect(params.rhinoRage, 0.2, 0.3, 0.5, 0.6, 0.65); + rating += wounded * TraitSelect(params.rhinoRage, 0.1, 0.2, 0.3, 0.5, 0.6, 0.65, 0.7); } else { rating -= wounded / 2; } @@ -1032,7 +1032,7 @@ function ArmyRating(params, sim, size, wound) { let weaponTech = params.weaponTech; if (weaponTech > 1 && params.sniper) { - let sniperBonus = TraitSelect(params.sniper, 0.04, 0.06, 0.08, 0.09, 0.1) + let sniperBonus = TraitSelect(params.sniper, 0.03, 0.04, 0.06, 0.08, 0.09, 0.1, 0.11); /* Sniper bonus doesn't apply to the base value of 1 or the Cyborg Soldiers upgrade */ weaponTech -= params.weaponTech >= 10 ? 2 : 1; weaponTech *= 1 + (sniperBonus * weaponTech); @@ -1042,45 +1042,45 @@ function ArmyRating(params, sim, size, wound) { rating *= weaponTech; if (sim && params.rhinoRage) { - let rageBonus = TraitSelect(params.rhinoRage, 0.0025, 0.005, 0.01, 0.0125, 0.014); + let rageBonus = TraitSelect(params.rhinoRage, 0.002, 0.0025, 0.005, 0.01, 0.0125, 0.014, 0.015); rating *= 1 + (rageBonus * sim.wounded); } if (params.puny) { - rating *= TraitSelect(params.puny, 0.82, 0.85, 0.9, 0.94, 0.96); + rating *= TraitSelect(params.puny, 0.8, 0.82, 0.85, 0.9, 0.94, 0.96, 0.97); } if (params.claws) { - rating *= TraitSelect(params.claws, 1.08, 1.12, 1.25, 1.32, 1.35); + rating *= TraitSelect(params.claws, 1.05, 1.08, 1.12, 1.25, 1.32, 1.35, 1.38); } if (params.chameleon) { - rating *= TraitSelect(params.chameleon, 1.05, 1.1, 1.2, 1.25, 1.3); + rating *= TraitSelect(params.chameleon, 1.03, 1.05, 1.1, 1.2, 1.25, 1.3, 1.35); } if (params.cautious) { if (sim) { /* Not doing a full weather sim here, but it rains about 21.6% of the time in most biomes */ if (Rand(0, 1000) < 216) { - rating *= TraitSelect(params.cautious, 0.86, 0.88, 0.9, 0.92, 0.94); + rating *= TraitSelect(params.cautious, 0.84, 0.86, 0.88, 0.9, 0.92, 0.94, 0.96); } } else { /* Average multiplier */ - rating *= (1 - 0.216) * 1 + 0.216 * TraitSelect(params.cautious, 0.86, 0.88, 0.9, 0.92, 0.94); + rating *= (1 - 0.216) * 1 + 0.216 * TraitSelect(params.cautious, 0.84, 0.86, 0.88, 0.9, 0.92, 0.94, 0.96); } } if (params.apexPredator) { - rating *= TraitSelect(params.apexPredator, 1.15, 1.2, 1.3, 1.4, 1.45); + rating *= TraitSelect(params.apexPredator, 1.1, 1.15, 1.2, 1.3, 1.4, 1.45, 1.5); } if (params.fiery) { - rating *= TraitSelect(params.fiery, 1.3, 1.4, 1.65, 1.7, 1.72); + rating *= TraitSelect(params.fiery, 1.2, 1.3, 1.4, 1.65, 1.7, 1.72, 1.74); } if (params.sticky) { - rating *= TraitSelect(params.sticky, 1.05, 1.08, 1.15, 1.18, 1.2); + rating *= TraitSelect(params.sticky, 1.03, 1.05, 1.08, 1.15, 1.18, 1.2, 1.22); } if (params.pathetic) { - rating *= TraitSelect(params.pathetic, 0.65, 0.7, 0.75, 0.8, 0.85); + rating *= TraitSelect(params.pathetic, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.88); } if (params.holy) { - rating *= TraitSelect(params.holy, 1.25, 1.3, 1.5, 1.6, 1.65); + rating *= TraitSelect(params.holy, 1.2, 1.25, 1.3, 1.5, 1.6, 1.65, 1.7); } if (params.rage) { rating *= 1.05; @@ -1122,7 +1122,7 @@ function ArmyRating(params, sim, size, wound) { rating = Math.floor(rating); if (params.hivemind) { - let breakpoint = TraitSelect(params.hivemind, 12, 11, 10, 8, 7); + let breakpoint = TraitSelect(params.hivemind, 13, 12, 11, 10, 8, 7, 6); if (size <= 10) { rating *= (size * 0.05) + (1 - breakpoint * 0.05); } else { @@ -1131,11 +1131,11 @@ function ArmyRating(params, sim, size, wound) { } if (params.cannibal) { - rating *= TraitSelect(params.cannibal, 1.08, 1.1, 1.15, 1.2, 1.22); + rating *= TraitSelect(params.cannibal, 1.06, 1.08, 1.1, 1.15, 1.2, 1.22, 1.24); } if (params.ooze) { - rating *= TraitSelect(params.ooze, 0.8, 0.85, 0.88, 0.9, 0.92); + rating *= TraitSelect(params.ooze, 0.75, 0.8, 0.85, 0.88, 0.9, 0.92, 0.94); } if (params.government == "democracy") { @@ -1143,7 +1143,7 @@ function ArmyRating(params, sim, size, wound) { } if (params.highPop) { - rating *= TraitSelect(params.highPop, 0.5, 0.34, 0.26, 0.212, 0.18); + rating *= TraitSelect(params.highPop, 0.5, 0.5, 0.34, 0.26, 0.212, 0.18, 0.158); } return Math.round(rating); @@ -1152,7 +1152,7 @@ function ArmyRating(params, sim, size, wound) { function DroidSize(params) { var size = params.enhDroids ? 2 : 1; if (params.highPop) { - size *= TraitSelect(params.highPop, 2, 3, 4, 5, 6); + size *= TraitSelect(params.highPop, 2, 2, 3, 4, 5, 6, 7); } return size; } @@ -1216,8 +1216,10 @@ function ForgeSoldiers(params) { return soldiers; } -function TraitSelect(trait_rank, rank_quarter, rank_half, rank_1, rank_2, rank_3) { +function TraitSelect(trait_rank, rank_tenth, rank_quarter, rank_half, rank_1, rank_2, rank_3, rank_4) { switch (trait_rank || 1) { + case 0.1: + return rank_tenth; case 0.25: return rank_quarter; case 0.5: @@ -1229,6 +1231,8 @@ function TraitSelect(trait_rank, rank_quarter, rank_half, rank_1, rank_2, rank_3 return rank_2; case 3: return rank_3; + case 4: + return rank_4; } } From 7539501f75264d64773a6c6da60f1a58c66ba000 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Tue, 13 May 2025 16:29:54 -0700 Subject: [PATCH 22/65] Make pages happy, maybe --- .github/workflows/static.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index 5feb91a..f732747 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -34,7 +34,7 @@ jobs: - name: Setup Pages uses: actions/configure-pages@v3 - name: Upload artifact - uses: actions/upload-pages-artifact@v1 + uses: actions/upload-pages-artifact@v3 with: # Upload entire repository path: '.' From e785246d2c33d0dc14cd3e2d7e912dd26ca625ac Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Tue, 13 May 2025 17:26:31 -0700 Subject: [PATCH 23/65] More pages ver updates --- .github/workflows/static.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index f732747..0ba8230 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -30,9 +30,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Pages - uses: actions/configure-pages@v3 + uses: actions/configure-pages@v5 - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: @@ -40,4 +40,4 @@ jobs: path: '.' - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@v4 From b9aa5bdd3671d53f7e891482137e300e0c5a77c2 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Thu, 15 May 2025 12:21:24 -0700 Subject: [PATCH 24/65] Unfathomable (thralls) --- index.html | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++ js/hellsim.js | 68 ++++++++++++++++++---- js/worker.js | 133 ++++++++++++++++++++++++++++-------------- 3 files changed, 305 insertions(+), 54 deletions(-) diff --git a/index.html b/index.html index 9124213..19b3bb7 100644 --- a/index.html +++ b/index.html @@ -649,8 +649,166 @@
Traits +
+
+
+ Unfathomable (Eldritch) +
+ +
+
+ + + +
Thralls -
+
+
+
+
+
+ Ancient Nightmare 🏆 +
+ +
+
+
+
+
+ Torturers +
+ +
+
+
+
+
+
+
+
+
+
+ Antid Thralls +
+ +
+
+
+
+
+ Balorg Thralls +
+ +
+
+
+
+
+ Centaur Thralls +
+ +
+
+
+
+
+ Mantis Thralls +
+ +
+
+
+
+
+ Orc Thralls +
+ +
+
+
+
+
+ Penguicula Thralls +
+ +
+
+
+
+
+ Rhinotaur Thralls +
+ +
+
+
+
+
+ Scorpid Thralls +
+ +
+
+
+
+
+ Sharkin Thralls +
+ +
+
+
+
+
+ Tortosian Thralls +
+ +
+
+
+
+
+ Unicorn Thralls +
+ +
+
+
+
+
+ Wendigo Thralls +
+ +
+
+
+
+
+ Yeti Thralls +
+ +
+
+ +
+
Upgrades -
diff --git a/js/hellsim.js b/js/hellsim.js index a4a2f6c..2ddc602 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -581,17 +581,30 @@ function OnChange() { ShowMercOptions(); + /* Show thralls only when needed */ + if (gParams.unfathomable > 0) { + $('#hThralls').parent()[0].hidden = false; + $('#cThralls')[0].hidden = false; + } else { + $('#hThralls').parent()[0].hidden = true; + $('#cThralls')[0].hidden = true; + } + /* Round dark energy to 3 places */ $('#darkEnergy')[0].value = gParams.darkEnergy = +gParams.darkEnergy.toFixed(3); /* Manage collapsers */ $('.collapser-icon').each(function(index, element) { var el = $(element); - let content = $(el.parent().data("target")); - if (el.text() == "+") { - content.hide(100); + if (gParams.unfathomable == 0 && el[0].id == 'hThrallsStatus') { + /* Skip */ } else { - content.show(100); + let content = $(el.parent().data("target")); + if (el.text() == "+") { + content.hide(100); + } else { + content.show(100); + } } }); @@ -746,6 +759,16 @@ function ImportSave() { $('#saveString').val("") } +function ParseFathom(save, race) { + if (save.city.surfaceDwellers) { + let idx = save.city.surfaceDwellers.indexOf(race); + if (idx >= 0) { + return global.city.captive_housing['race' + idx]; + } + } + return 0; +} + function ConvertSave(save) { console.log(save); @@ -790,7 +813,22 @@ function ConvertSave(save) { $('#smoldering')[0].value = save.race['smoldering'] || 0; $('#sniper')[0].value = save.race['sniper'] || 0; $('#sticky')[0].value = save.race['sticky'] || 0; - + $('#unfathomable')[0].value = save.race['unfathomable'] || 0; + + $('#antid_thralls') = ParseFathom(save, 'antid'); + $('#balorg_thralls') = ParseFathom(save, 'balorg'); + $('#centaur_thralls') = ParseFathom(save, 'centaur'); + $('#mantis_thralls') = ParseFathom(save, 'mantis'); + $('#orc_thralls') = ParseFathom(save, 'orc'); + $('#penguicula_thralls') = ParseFathom(save, 'penguicula'); + $('#rhinotaur_thralls') = ParseFathom(save, 'rhinotaur'); + $('#scorpid_thralls') = ParseFathom(save, 'scorpid'); + $('#sharkin_thralls') = ParseFathom(save, 'sharkin'); + $('#tortosian_thralls') = ParseFathom(save, 'tortosian'); + $('#unicorn_thralls') = ParseFathom(save, 'unicorn'); + $('#wendigo_thralls') = ParseFathom(save, 'wendigo'); + $('#yeti_thralls') = ParseFathom(save, 'yeti'); + $('#zealotry')[0].checked = save.tech['fanaticism'] && save.tech['fanaticism'] >= 4 ? true : false; $('#vrTraining')[0].checked = save.tech['boot_camp'] && save.tech['boot_camp'] >= 2 ? true : false; $('#bacTanks')[0].checked = save.tech['medic'] && save.tech['medic'] >= 2 ? true : false; @@ -889,21 +927,27 @@ function ConvertSave(save) { } -$(document).ready( function() { - var traits = $('#traitsRow').children(); - var newRow; - var i; - for (i = 5; i < traits.length; i++) { +function GroupRow(containerQuery, rowQuery) { + let row = $(rowQuery); + let cols = row.children(); + let newRow = row; + let i = Math.min(5, cols.length); + for (; i < cols.length; i++) { if (i % 5 == 0) { newRow = $('
').prop({className: 'form-row'}); - $('#cTraits').append(newRow); + $(containerQuery).append(newRow); } - newRow.append(traits[i]); + newRow.append(cols[i]); } while (i % 5 != 0) { newRow.append('
'); i++; } +} + +$(document).ready( function() { + GroupRow("#cTraits", "#traitsRow"); + GroupRow("#cThralls", "#thrallsRow"); $('#cTraits')[0].hidden = false; $('#paramsForm').submit(function(event) { diff --git a/js/worker.js b/js/worker.js index ab0d4b5..7a7ca3b 100644 --- a/js/worker.js +++ b/js/worker.js @@ -350,6 +350,9 @@ function BloodWar(params, sim, stats) { if (params.ghostly) { gemOdds = Math.round(gemOdds * TraitSelect(params.ghostly, 0.98, 0.95, 0.9, 0.85, 0.8, 0.78, 0.77)); } + if (params.wendigo_thralls) { + gemOdds = Math.round(gemOdds * (0.01 * (100 - 10 * Fathom(params, params.wendigo_thralls)))); + } /* Patrols */ let soldiersKilled = 0; @@ -576,6 +579,9 @@ function BloodWar(params, sim, stats) { if (params.blurry) { divisor *= TraitSelect(params.blurry, 1.05, 1.10, 1.15, 1.25, 1.35, 1.4, 1.45); } + if (params.yeti_thralls) { + divisor *= 1 + 0.25 * Fathom(params, params.yeti_thralls); + } if (params.instincts) { divisor *= TraitSelect(params.instincts, 1.02, 1.03, 1.05, 1.10, 1.15, 1.2, 1.25); } @@ -945,6 +951,9 @@ function PatrolCasualties(params, sim, stats, demons, ambush) { if (params.armored) { armor += TraitSelect(params.armored, 0, 1, 1, 2, 2, 2, 2); } + if (params.tortosian_thralls) { + armor += Math.floor(2 * Fathom(params, params.tortosian_thralls)); + } if (params.scales) { armor += TraitSelect(params.scales, 0, 1, 1, 1, 1, 2, 2); } @@ -1003,6 +1012,9 @@ function TrainingTime(params) { if (params.brute) { rate += TraitSelect(params.brute, 1, 1.25, 1.5, 2.5, 3, 3.5, 3.75); } + if (params.orc_thralls) { + rate += 2.5 * Fathom(params, params.orc_thralls); + } rate *= 0.25; /* Convert to ticks per soldier */ @@ -1022,8 +1034,13 @@ function ArmyRating(params, sim, size, wound) { } } - if (params.rhinoRage) { - rating += wounded * TraitSelect(params.rhinoRage, 0.1, 0.2, 0.3, 0.5, 0.6, 0.65, 0.7); + if (params.rhinoRage || (params.unfathomable && params.rhinotaur_thralls)) { + if (params.rhinoRage) { + rating += wounded * TraitSelect(params.rhinoRage, 0.1, 0.2, 0.3, 0.5, 0.6, 0.65, 0.7); + } + if (params.rhinotaur_thralls) { + rating += wounded * (0.5 * Fathom(params, params.rhinotaur_thralls)); + } } else { rating -= wounded / 2; } @@ -1031,26 +1048,40 @@ function ArmyRating(params, sim, size, wound) { /* Game code subtracts 1 for tech >= 5 to skip bunk beds. Here that gets skipped in the HTML selection values themselves */ let weaponTech = params.weaponTech; - if (weaponTech > 1 && params.sniper) { - let sniperBonus = TraitSelect(params.sniper, 0.03, 0.04, 0.06, 0.08, 0.09, 0.1, 0.11); + if (weaponTech > 1) { /* Sniper bonus doesn't apply to the base value of 1 or the Cyborg Soldiers upgrade */ weaponTech -= params.weaponTech >= 10 ? 2 : 1; - weaponTech *= 1 + (sniperBonus * weaponTech); + if (params.sniper) { + weaponTech *= 1 + weaponTech * TraitSelect(params.sniper, 0.03, 0.04, 0.06, 0.08, 0.09, 0.1, 0.11); + } + if (params.centaur_thralls) { + weaponTech *= 1 + weaponTech * 0.08 * Fathom(params, params.centaur_thralls); + } weaponTech += params.weaponTech >= 10 ? 2 : 1; } - + rating *= weaponTech; - + + rating *= 1 + (params.tactical * 0.05); + if (params.zealotry) { + rating *= 1 + (params.temples * 0.01); + } if (sim && params.rhinoRage) { let rageBonus = TraitSelect(params.rhinoRage, 0.002, 0.0025, 0.005, 0.01, 0.0125, 0.014, 0.015); rating *= 1 + (rageBonus * sim.wounded); } + if (sim && params.rhinotaur_thralls) { + rating *= 1 + 0.01 * Fathom(params, params.rhinotaur_thralls) * sim.wounded; + } if (params.puny) { rating *= TraitSelect(params.puny, 0.8, 0.82, 0.85, 0.9, 0.94, 0.96, 0.97); } if (params.claws) { rating *= TraitSelect(params.claws, 1.05, 1.08, 1.12, 1.25, 1.32, 1.35, 1.38); } + if (params.scorpid_thralls) { + rating *= 1 + 0.25 * Fathom(params, params.scorpid_thralls); + } if (params.chameleon) { rating *= TraitSelect(params.chameleon, 1.03, 1.05, 1.1, 1.2, 1.25, 1.3, 1.35); } @@ -1070,23 +1101,29 @@ function ArmyRating(params, sim, size, wound) { if (params.apexPredator) { rating *= TraitSelect(params.apexPredator, 1.1, 1.15, 1.2, 1.3, 1.4, 1.45, 1.5); } + if (params.sharkin_thralls) { + rating *= 1 + 0.3 * Fathom(params, params.sharkin_thralls); + } if (params.fiery) { rating *= TraitSelect(params.fiery, 1.2, 1.3, 1.4, 1.65, 1.7, 1.72, 1.74); } + if (params.balorg_thralls) { + rating *= 1 + 0.65 * Fathom(params, params.balorg_thralls); + } if (params.sticky) { rating *= TraitSelect(params.sticky, 1.03, 1.05, 1.08, 1.15, 1.18, 1.2, 1.22); } + if (params.pinguicula_thralls) { + rating *= 1 + 0.15 * Fathom(params, params.pinguicula_thralls); + } if (params.pathetic) { rating *= TraitSelect(params.pathetic, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.88); } if (params.holy) { rating *= TraitSelect(params.holy, 1.2, 1.25, 1.3, 1.5, 1.6, 1.65, 1.7); } - if (params.rage) { - rating *= 1.05; - } - if (params.magic) { - rating *= 0.75; + if (params.unicorn_thralls) { + rating *= 1 + 0.5 * Fathom(params, params.unicorn_thralls); } if (params.banana) { rating *= 0.8; @@ -1094,23 +1131,9 @@ function ArmyRating(params, sim, size, wound) { if (params.governor == "soldier") { rating *= 1.05; } - - rating *= 1 + (params.tactical * 0.05); - - if (params.zealotry) { - rating *= 1 + (params.temples * 0.01); - } - - rating *= 1 + (params.warRitual / (params.warRitual + 75)); - - if (params.parasite) { - if (size == 1) { - rating += 2; - } else if (size > 1) { - rating += 4; - } + if (params.rage) { + rating *= 1.05; } - if (params.government == "autocracy") { if (params.governor == "bureaucrat") { rating *= 1.40; @@ -1118,35 +1141,53 @@ function ArmyRating(params, sim, size, wound) { rating *= 1.35; } } - + rating = Math.floor(rating); - + + let racialModifier = 1; if (params.hivemind) { let breakpoint = TraitSelect(params.hivemind, 13, 12, 11, 10, 8, 7, 6); if (size <= 10) { - rating *= (size * 0.05) + (1 - breakpoint * 0.05); + racialModifier *= (size * 0.05) + (1 - breakpoint * 0.05); } else { - rating *= 1 + (1 - (0.99 ** (size - breakpoint))); + racialModifier *= 1 + (1 - (0.99 ** (size - breakpoint))); } } - + if (params.antid_thralls) { + racialModifier *= 1 + (1 - (0.99 ** (size * Fathom(params, params.antid_thralls) / 4))) / 2; + } if (params.cannibal) { - rating *= TraitSelect(params.cannibal, 1.06, 1.08, 1.1, 1.15, 1.2, 1.22, 1.24); + racialModifier *= TraitSelect(params.cannibal, 1.06, 1.08, 1.1, 1.15, 1.2, 1.22, 1.24); + } + if (params.mantis_thralls) { + racialModifier *= 1 + 0.15 * Fathom(params, params.mantis_thralls); } - if (params.ooze) { - rating *= TraitSelect(params.ooze, 0.75, 0.8, 0.85, 0.88, 0.9, 0.92, 0.94); + racialModifier *= TraitSelect(params.ooze, 0.75, 0.8, 0.85, 0.88, 0.9, 0.92, 0.94); } - if (params.government == "democracy") { - rating *= 0.95; + racialModifier *= 0.95; + } + if (params.magic) { + racialModifier *= 0.75; + if (params.warRitual) { + racialModifier *= 1 + (params.warRitual / (params.warRitual + 75)); + } } - if (params.highPop) { - rating *= TraitSelect(params.highPop, 0.5, 0.5, 0.34, 0.26, 0.212, 0.18, 0.158); + racialModifier *= TraitSelect(params.highPop, 0.5, 0.5, 0.34, 0.26, 0.212, 0.18, 0.158); } - - return Math.round(rating); + rating *= racialModifier; + + if (params.parasite) { + if (size == 1) { + rating += 2; + } else if (size > 1) { + rating += 4; + } + } + + return rating; } function DroidSize(params) { @@ -1236,6 +1277,14 @@ function TraitSelect(trait_rank, rank_tenth, rank_quarter, rank_half, rank_1, ra } } +function Fathom(params, thralls) { + let active = Math.min(100, thralls); + if (params.torturers && active > params.torturers) { + active -= Math.ceil((active - params.torturers) / 3); + } + return (active / 100) * (params.nightmare / 5); +} + function Rand(min, max) { return Math.floor(Math.random() * (max - min)) + min; } From 248daa3917915efe27e39670053a4b68da715c2c Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Fri, 16 May 2025 13:40:07 -0700 Subject: [PATCH 25/65] Psychic assault (channelled only) --- index.html | 30 +++++++++++++++++++++++++++--- js/hellsim.js | 46 +++++++++++++++++++++++++--------------------- js/worker.js | 7 +++++++ 3 files changed, 59 insertions(+), 24 deletions(-) diff --git a/index.html b/index.html index 19b3bb7..9567c05 100644 --- a/index.html +++ b/index.html @@ -462,6 +462,23 @@
Traits
+
+
+
+ Psychic (Eldritch) +
+ +
+
@@ -669,8 +686,8 @@
Traits
-
Thralls -
-
+
Eldritch Powers -
+
@@ -695,7 +712,14 @@
Thralls
-
+
+
+
+ Channelled Psy Attack Energy +
+ +
+
diff --git a/js/hellsim.js b/js/hellsim.js index 2ddc602..668459d 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -581,13 +581,14 @@ function OnChange() { ShowMercOptions(); - /* Show thralls only when needed */ - if (gParams.unfathomable > 0) { - $('#hThralls').parent()[0].hidden = false; - $('#cThralls')[0].hidden = false; + /* Show eldritch things only when needed */ + let eldritch = gParams.unfathomable > 0 || gParams.psychic > 0; + if (eldritch) { + $('#hEldritch').parent()[0].hidden = false; + $('#cEldritch')[0].hidden = false; } else { - $('#hThralls').parent()[0].hidden = true; - $('#cThralls')[0].hidden = true; + $('#hEldritch').parent()[0].hidden = true; + $('#cEldritch')[0].hidden = true; } /* Round dark energy to 3 places */ @@ -596,7 +597,7 @@ function OnChange() { /* Manage collapsers */ $('.collapser-icon').each(function(index, element) { var el = $(element); - if (gParams.unfathomable == 0 && el[0].id == 'hThrallsStatus') { + if (!eldritch && el[0].id == 'hEldritchStatus') { /* Skip */ } else { let content = $(el.parent().data("target")); @@ -802,6 +803,7 @@ function ConvertSave(save) { $('#ooze')[0].value = save.race['ooze'] || 0; $('#parasite')[0].value = save.race['parasite'] || 0; $('#pathetic')[0].value = save.race['pathetic'] || 0; + $('#psychic')[0].value = save.race['psychic'] || 0; $('#puny')[0].value = save.race['puny'] || 0; $('#rhinoRage')[0].value = save.race['rage'] || 0; $('#regenerative')[0].value = save.race['regenerative'] || 0; @@ -815,19 +817,21 @@ function ConvertSave(save) { $('#sticky')[0].value = save.race['sticky'] || 0; $('#unfathomable')[0].value = save.race['unfathomable'] || 0; - $('#antid_thralls') = ParseFathom(save, 'antid'); - $('#balorg_thralls') = ParseFathom(save, 'balorg'); - $('#centaur_thralls') = ParseFathom(save, 'centaur'); - $('#mantis_thralls') = ParseFathom(save, 'mantis'); - $('#orc_thralls') = ParseFathom(save, 'orc'); - $('#penguicula_thralls') = ParseFathom(save, 'penguicula'); - $('#rhinotaur_thralls') = ParseFathom(save, 'rhinotaur'); - $('#scorpid_thralls') = ParseFathom(save, 'scorpid'); - $('#sharkin_thralls') = ParseFathom(save, 'sharkin'); - $('#tortosian_thralls') = ParseFathom(save, 'tortosian'); - $('#unicorn_thralls') = ParseFathom(save, 'unicorn'); - $('#wendigo_thralls') = ParseFathom(save, 'wendigo'); - $('#yeti_thralls') = ParseFathom(save, 'yeti'); + $('#channel_assault')[0].value = save.race['psychicPowers'] && save.race.psychicPowers['channel'] && save.race.psychicPowers.channel['assault'] || 0; + + $('#antid_thralls')[0].value = ParseFathom(save, 'antid'); + $('#balorg_thralls')[0].value = ParseFathom(save, 'balorg'); + $('#centaur_thralls')[0].value = ParseFathom(save, 'centaur'); + $('#mantis_thralls')[0].value = ParseFathom(save, 'mantis'); + $('#orc_thralls')[0].value = ParseFathom(save, 'orc'); + $('#penguicula_thralls')[0].value = ParseFathom(save, 'penguicula'); + $('#rhinotaur_thralls')[0].value = ParseFathom(save, 'rhinotaur'); + $('#scorpid_thralls')[0].value = ParseFathom(save, 'scorpid'); + $('#sharkin_thralls')[0].value = ParseFathom(save, 'sharkin'); + $('#tortosian_thralls')[0].value = ParseFathom(save, 'tortosian'); + $('#unicorn_thralls')[0].value = ParseFathom(save, 'unicorn'); + $('#wendigo_thralls')[0].value = ParseFathom(save, 'wendigo'); + $('#yeti_thralls')[0].value = ParseFathom(save, 'yeti'); $('#zealotry')[0].checked = save.tech['fanaticism'] && save.tech['fanaticism'] >= 4 ? true : false; $('#vrTraining')[0].checked = save.tech['boot_camp'] && save.tech['boot_camp'] >= 2 ? true : false; @@ -947,7 +951,7 @@ function GroupRow(containerQuery, rowQuery) { $(document).ready( function() { GroupRow("#cTraits", "#traitsRow"); - GroupRow("#cThralls", "#thrallsRow"); + GroupRow("#cEldritch", "#thrallsRow"); $('#cTraits')[0].hidden = false; $('#paramsForm').submit(function(event) { diff --git a/js/worker.js b/js/worker.js index 7a7ca3b..c332bdc 100644 --- a/js/worker.js +++ b/js/worker.js @@ -1134,6 +1134,13 @@ function ArmyRating(params, sim, size, wound) { if (params.rage) { rating *= 1.05; } + if (params.psychic) { + let boost = 0; + if (params.channel_assault) { + boost += +(TraitSelect(params.psychic, 15, 20, 30, 40, 50, 60, 65) / 50000 * params.nightmare * params.channel_assault).toFixed(3); + } + rating *= 1 + boost; + } if (params.government == "autocracy") { if (params.governor == "bureaucrat") { rating *= 1.40; From 248b6f64589afceb14384564d87a4480c9da997f Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Fri, 16 May 2025 14:04:27 -0700 Subject: [PATCH 26/65] Thrall fixes --- index.html | 10 +++++++++- js/hellsim.js | 7 +++++-- js/worker.js | 19 ++++++++++++++++--- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 9567c05..5525705 100644 --- a/index.html +++ b/index.html @@ -707,7 +707,7 @@
Eldritch Pow
- Torturers + Tormentors
@@ -804,6 +804,14 @@
Eldritch Pow
+
+
+
+ Troll Thralls +
+ +
+
diff --git a/js/hellsim.js b/js/hellsim.js index 668459d..671df50 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -761,10 +761,10 @@ function ImportSave() { } function ParseFathom(save, race) { - if (save.city.surfaceDwellers) { + if (save.city['surfaceDwellers']) { let idx = save.city.surfaceDwellers.indexOf(race); if (idx >= 0) { - return global.city.captive_housing['race' + idx]; + return save.city.captive_housing['race' + idx]; } } return 0; @@ -817,6 +817,8 @@ function ConvertSave(save) { $('#sticky')[0].value = save.race['sticky'] || 0; $('#unfathomable')[0].value = save.race['unfathomable'] || 0; + $('#nightmare')[0].value = save.stats.achieve['nightmare'] && save.stats.achieve.nightmare['mg'] || 0; + $('#torturers')[0].value = save.civic['torturer'] && save.civic['torturer'].assigned || 0; $('#channel_assault')[0].value = save.race['psychicPowers'] && save.race.psychicPowers['channel'] && save.race.psychicPowers.channel['assault'] || 0; $('#antid_thralls')[0].value = ParseFathom(save, 'antid'); @@ -829,6 +831,7 @@ function ConvertSave(save) { $('#scorpid_thralls')[0].value = ParseFathom(save, 'scorpid'); $('#sharkin_thralls')[0].value = ParseFathom(save, 'sharkin'); $('#tortosian_thralls')[0].value = ParseFathom(save, 'tortosian'); + $('#troll_thralls')[0].value = ParseFathom(save, 'troll'); $('#unicorn_thralls')[0].value = ParseFathom(save, 'unicorn'); $('#wendigo_thralls')[0].value = ParseFathom(save, 'wendigo'); $('#yeti_thralls')[0].value = ParseFathom(save, 'yeti'); diff --git a/js/worker.js b/js/worker.js index c332bdc..96b35c0 100644 --- a/js/worker.js +++ b/js/worker.js @@ -856,13 +856,16 @@ function MercPrice(params, sim, stats) { if (price > 25000){ price = 25000; } - if (sim.mercCounter > 0){ + if (sim.mercCounter > 0) { price *= 1.1 ** sim.mercCounter; } - if (params.brute){ + if (params.brute) { price *= TraitSelect(params.brute, 0.85, 0.8, 0.75, 0.5, 0.4, 0.35, 0.3); } - if (params.highPop){ + if (params.orc_thralls) { + price *= 0.5 * Fathom(params, params.orc_thralls); + } + if (params.highPop) { price *= TraitSelect(params.highPop, 0.5, 0.5, 0.34, 0.26, 0.212, 0.18, 0.158); } @@ -899,9 +902,19 @@ function HealSoldiers(params, sim, stats) { } healCredits += 3; } + if (params.mantis_thralls) { + if (healCredits >= 20) { + healCredits *= 1 + 0.15 * Fathom(params, params.mantis_thralls); + } else { + healCredits += Math.floor(3 * Fathom(params, params.mantis_thralls)); + } + } if (params.governor == "sports") { healCredits *= 1.5; } + if (params.troll_thralls) { + healCredits += Math.round(20 * 4 * Fathom(params, params.troll_thralls)); + } healCredits = Math.round(healCredits); var healCost = 20; From f867a50c7e5fc3b8d1d28e589ba5335d52390379 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Fri, 16 May 2025 14:14:44 -0700 Subject: [PATCH 27/65] Chicken trait --- index.html | 17 +++++++++++++++++ js/hellsim.js | 1 + js/worker.js | 6 ++++++ 3 files changed, 24 insertions(+) diff --git a/index.html b/index.html index 5525705..36543fd 100644 --- a/index.html +++ b/index.html @@ -207,6 +207,23 @@
Traits
+
+
+
+ Chicken (Wyvern) +
+ +
+
diff --git a/js/hellsim.js b/js/hellsim.js index 671df50..54741c8 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -788,6 +788,7 @@ function ConvertSave(save) { $('#cannibal')[0].value = save.race['cannibalize'] || 0; $('#cautious')[0].value = save.race['cautious'] || 0; $('#chameleon')[0].value = save.race['chameleon'] || 0; + $('#chicken')[0].value = save.race['chicken'] || 0; $('#claws')[0].value = save.race['claws'] || 0; $('#diverse')[0].value = save.race['diverse'] || 0; $('#elusive')[0].value = save.race['elusive'] || 0; diff --git a/js/worker.js b/js/worker.js index 96b35c0..ced4e4f 100644 --- a/js/worker.js +++ b/js/worker.js @@ -410,6 +410,9 @@ function BloodWar(params, sim, stats) { let demons = Rand(minDemons, maxDemons); let ambushOdds = 30 + Math.max(params.elusive ? TraitSelect(params.elusive, 5, 10, 15, 20, 25, 30, 35) : 0, params.chameleon ? TraitSelect(params.chameleon, 5, 10, 15, 20, 25, 30, 35) : 0); + if (params.chicken) { + ambushOdds -= TraitSelect(params.chicken, 22, 20, 15, 10, 8, 6, 4); + } if (Rand(0, ambushOdds) == 0) { /* Ambush @@ -565,6 +568,9 @@ function BloodWar(params, sim, stats) { if (sim.threat < 10000) { let influx = ((10000 - sim.threat) / 2500) + 1; influx *= 1 + (params.beacons * 0.22); + if (params.chicken) { + influx *= TraitSelect(params.chicken, 2.1, 2, 1.75, 1.5, 1.4, 1.3, 1.2); + } influx = Math.round(influx); sim.threat += Rand(influx * 10, influx * 50); } From 75e37daba1a4f318cc8354a0b6716de19326094f Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Fri, 16 May 2025 14:19:56 -0700 Subject: [PATCH 28/65] Elemental trait --- index.html | 17 +++++++++++++++++ js/hellsim.js | 1 + js/worker.js | 3 +++ 3 files changed, 21 insertions(+) diff --git a/index.html b/index.html index 36543fd..bf74e78 100644 --- a/index.html +++ b/index.html @@ -258,6 +258,23 @@
Traits
+
+
+
+ Elemental (Wyvern) +
+ +
+
diff --git a/js/hellsim.js b/js/hellsim.js index 54741c8..d04ac13 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -791,6 +791,7 @@ function ConvertSave(save) { $('#chicken')[0].value = save.race['chicken'] || 0; $('#claws')[0].value = save.race['claws'] || 0; $('#diverse')[0].value = save.race['diverse'] || 0; + $('#elemental')[0].value = save.race['elemental'] || 0; $('#elusive')[0].value = save.race['elusive'] || 0; $('#evil')[0].value = save.race['evil'] || 0; $('#fiery')[0].value = save.race['fiery'] || 0; diff --git a/js/worker.js b/js/worker.js index ced4e4f..5c5ae45 100644 --- a/js/worker.js +++ b/js/worker.js @@ -1153,6 +1153,9 @@ function ArmyRating(params, sim, size, wound) { if (params.rage) { rating *= 1.05; } + if (params.elemental) { + rating *= TraitSelect(params.elemental, 1.01, 1.02, 1.04, 1.06, 1.08, 1.1, 1.2); + } if (params.psychic) { let boost = 0; if (params.channel_assault) { From 4b7507c0ad4addb2162aaf678ffa6a1df3fd65f2 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Fri, 16 May 2025 14:38:57 -0700 Subject: [PATCH 29/65] Ocular power trait --- index.html | 27 +++++++++++++++++++++++++++ js/hellsim.js | 6 +++++- js/worker.js | 6 ++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index bf74e78..4320e06 100644 --- a/index.html +++ b/index.html @@ -445,6 +445,23 @@
Traits
+
+
+
+ Ocular Power (Eye-Spector) +
+ +
+
@@ -722,6 +739,16 @@
Traits Eldritch Powers -
+
+
+ + +
+
+ + +
+
diff --git a/js/hellsim.js b/js/hellsim.js index d04ac13..f695805 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -582,7 +582,7 @@ function OnChange() { ShowMercOptions(); /* Show eldritch things only when needed */ - let eldritch = gParams.unfathomable > 0 || gParams.psychic > 0; + let eldritch = gParams.unfathomable > 0 || gParams.psychic > 0 || gParams.ocularPower > 0; if (eldritch) { $('#hEldritch').parent()[0].hidden = false; $('#cEldritch')[0].hidden = false; @@ -802,6 +802,7 @@ function ConvertSave(save) { $('#hyper')[0].value = save.race['hyper'] || 0; $('#instincts')[0].value = save.race['instinct'] || 0; $('#kindling')[0].value = save.race['kindling_kindred'] || 0; + $('#ocularPower')[0].value = save.race['ocular_power'] || 0; $('#ooze')[0].value = save.race['ooze'] || 0; $('#parasite')[0].value = save.race['parasite'] || 0; $('#pathetic')[0].value = save.race['pathetic'] || 0; @@ -823,6 +824,9 @@ function ConvertSave(save) { $('#torturers')[0].value = save.civic['torturer'] && save.civic['torturer'].assigned || 0; $('#channel_assault')[0].value = save.race['psychicPowers'] && save.race.psychicPowers['channel'] && save.race.psychicPowers.channel['assault'] || 0; + $('#ocular_disintegration')[0].checked = save.race['ocularPowerConfig'] && save.race.ocularPowerConfig['d'] ? true : false; + $('#ocular_fear')[0].checked = save.race['ocularPowerConfig'] && save.race.ocularPowerConfig['f'] ? true : false; + $('#antid_thralls')[0].value = ParseFathom(save, 'antid'); $('#balorg_thralls')[0].value = ParseFathom(save, 'balorg'); $('#centaur_thralls')[0].value = ParseFathom(save, 'centaur'); diff --git a/js/worker.js b/js/worker.js index 5c5ae45..1df7508 100644 --- a/js/worker.js +++ b/js/worker.js @@ -413,6 +413,9 @@ function BloodWar(params, sim, stats) { if (params.chicken) { ambushOdds -= TraitSelect(params.chicken, 22, 20, 15, 10, 8, 6, 4); } + if (params.ocularPower && params.ocular_fear) { + ambushOdds += TraitSelect(params.ocularPower, 0, 1, 2, 2, 3, 4, 5); + } if (Rand(0, ambushOdds) == 0) { /* Ambush @@ -1156,6 +1159,9 @@ function ArmyRating(params, sim, size, wound) { if (params.elemental) { rating *= TraitSelect(params.elemental, 1.01, 1.02, 1.04, 1.06, 1.08, 1.1, 1.2); } + if (params.ocularPower && params.ocular_disintegration) { + rating *= TraitSelect(params.ocularPower, 1.05, 1.125, 1.25, 1.375, 1.5, 1.625, 1.75); + } if (params.psychic) { let boost = 0; if (params.channel_assault) { From a5bca52e9aa38232e4866749da738a2058e88390 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Fri, 16 May 2025 14:59:12 -0700 Subject: [PATCH 30/65] Swift and Grenadier traits --- index.html | 34 ++++++++++++++++++++++++++++++++++ js/hellsim.js | 2 ++ js/worker.js | 6 ++++++ 3 files changed, 42 insertions(+) diff --git a/index.html b/index.html index 4320e06..581f344 100644 --- a/index.html +++ b/index.html @@ -343,6 +343,23 @@
Traits
+
+
+
+ Grenadier (Bombardier) +
+ +
+
@@ -717,6 +734,23 @@
Traits
+
+
+
+ Swift (Ghast) +
+ +
+
diff --git a/js/hellsim.js b/js/hellsim.js index f695805..7498567 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -796,6 +796,7 @@ function ConvertSave(save) { $('#evil')[0].value = save.race['evil'] || 0; $('#fiery')[0].value = save.race['fiery'] || 0; $('#ghostly')[0].value = save.race['ghostly'] || 0; + $('#grenadier')[0].value = save.race['grenadier'] || 0; $('#highPop')[0].value = save.race['high_pop'] || 0; $('#hivemind')[0].value = save.race['hivemind'] || 0; $('#holy')[0].value = save.race['holy'] || 0; @@ -818,6 +819,7 @@ function ConvertSave(save) { $('#smoldering')[0].value = save.race['smoldering'] || 0; $('#sniper')[0].value = save.race['sniper'] || 0; $('#sticky')[0].value = save.race['sticky'] || 0; + $('#swift')[0].value = save.race['swift'] || 0; $('#unfathomable')[0].value = save.race['unfathomable'] || 0; $('#nightmare')[0].value = save.stats.achieve['nightmare'] && save.stats.achieve.nightmare['mg'] || 0; diff --git a/js/worker.js b/js/worker.js index 1df7508..b19de5b 100644 --- a/js/worker.js +++ b/js/worker.js @@ -1126,6 +1126,9 @@ function ArmyRating(params, sim, size, wound) { if (params.sharkin_thralls) { rating *= 1 + 0.3 * Fathom(params, params.sharkin_thralls); } + if (params.swift) { + rating *= TraitSelect(params.swift, 1.2, 1.35, 1.55, 1.75, 1.85, 1.9, 1.92); + } if (params.fiery) { rating *= TraitSelect(params.fiery, 1.2, 1.3, 1.4, 1.65, 1.7, 1.72, 1.74); } @@ -1169,6 +1172,9 @@ function ArmyRating(params, sim, size, wound) { } rating *= 1 + boost; } + if (params.grenadier) { + rating *= TraitSelect(params.grenadier, 2, 2.1, 2.25, 2.5, 2.75, 3, 3.25); + } if (params.government == "autocracy") { if (params.governor == "bureaucrat") { rating *= 1.40; From e754d0df01f3b62c000a1ab9dc162f0c87984338 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Fri, 16 May 2025 17:32:21 -0700 Subject: [PATCH 31/65] Max gem chance --- js/worker.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/worker.js b/js/worker.js index b19de5b..81d6777 100644 --- a/js/worker.js +++ b/js/worker.js @@ -353,6 +353,9 @@ function BloodWar(params, sim, stats) { if (params.wendigo_thralls) { gemOdds = Math.round(gemOdds * (0.01 * (100 - 10 * Fathom(params, params.wendigo_thralls)))); } + if (gemOdds < 12) { + gemOdds = 12; + } /* Patrols */ let soldiersKilled = 0; From 787d567a632b7808ea37bdddd57db6c06c471e77 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Fri, 16 May 2025 19:39:35 -0700 Subject: [PATCH 32/65] Evil changes / basic authority model (constant) --- index.html | 73 ++++++++++++++++++++++++++++++++++++++++++--------- js/hellsim.js | 16 +++++------ js/worker.js | 29 +++++++++++++++----- 3 files changed, 92 insertions(+), 26 deletions(-) diff --git a/index.html b/index.html index 581f344..511ddf2 100644 --- a/index.html +++ b/index.html @@ -29,21 +29,13 @@
-
Traits -
-
Traits -
diff --git a/js/hellsim.js b/js/hellsim.js index 86aa7f4..14f4f74 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -775,6 +775,7 @@ function ConvertSave(save) { $('#dark_energy')[0].value = save.prestige && save.prestige.Dark.count || 0; $('#harmony')[0].value = save.prestige && save.prestige.Harmony.count || 0; $('#evil_lemon')[0].value = save.stats.achieve['extinct_sludge'] && save.stats.achieve.extinct_sludge['e'] || 0; + $('#what_is_best')[0].value = save.stats.achieve['what_is_best'] && save.stats.achieve.what_is_best['e'] || 0; $('#banana')[0].checked = save.race['banana'] ? true : false; $('#rage')[0].checked = save.city.ptrait.includes('rage') ? true : false; diff --git a/js/worker.js b/js/worker.js index 6112c22..870ed26 100644 --- a/js/worker.js +++ b/js/worker.js @@ -690,7 +690,11 @@ function BloodWar(params, sim, stats) { let cap = params.soulAbsorption ? 750000 : 1000000; if (params.soulLink) { - cap = Math.round(cap * 0.97 ** params.soulAttractors); + let base = 0.97; + if (params.what_is_best >= 3) { + base = 0.96; + } + cap = Math.round(cap * base ** params.soulAttractors); } if (sim.forgeSouls > cap) { stats.forgeGems++; From 776caae0660b238e6ebf2ae57007c04af86312bf Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Fri, 16 May 2025 20:15:29 -0700 Subject: [PATCH 34/65] Allow fractions in new Evil fields --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 7fbba35..22a76c0 100644 --- a/index.html +++ b/index.html @@ -66,7 +66,7 @@
General Dark Energy
- +
@@ -74,7 +74,7 @@
General Harmony Crystals
- +
@@ -1177,7 +1177,7 @@
Upgrades Authority
- +
From d2c96701b54842292474772a5dcf1930ecb16f3b Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Fri, 16 May 2025 20:50:17 -0700 Subject: [PATCH 35/65] Updated soul forge can multi-craft and saves overflow --- js/worker.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/js/worker.js b/js/worker.js index 870ed26..21105be 100644 --- a/js/worker.js +++ b/js/worker.js @@ -696,9 +696,10 @@ function BloodWar(params, sim, stats) { } cap = Math.round(cap * base ** params.soulAttractors); } - if (sim.forgeSouls > cap) { - stats.forgeGems++; - sim.forgeSouls = 0; + if (sim.forgeSouls >= cap) { + let gems = Math.floor(sim.forgeSouls / cap); + sim.forgeSouls -= cap * gems; + stats.forgeGems += gems; } } } From a4121f76d1a0cb5ff88323dbc27fc25f563e940c Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Fri, 16 May 2025 21:43:55 -0700 Subject: [PATCH 36/65] Astrology --- index.html | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ js/hellsim.js | 21 +++++++++++++++++++++ js/worker.js | 25 +++++++++++++++++++++++++ 3 files changed, 98 insertions(+) diff --git a/index.html b/index.html index 22a76c0..2612d97 100644 --- a/index.html +++ b/index.html @@ -107,6 +107,20 @@
General
+
+
+
+ Astrology +
+ +
+
Traits -
@@ -135,6 +149,23 @@
Traits +
+
+
+ Astrologer (Slitheryn) +
+ +
+
@@ -832,6 +863,23 @@
Traits
+
+
+
+ Unfavored (Kamel) +
+ +
+
@@ -1040,6 +1088,10 @@
Upgrades +
+ + +
diff --git a/js/hellsim.js b/js/hellsim.js index 14f4f74..d7dd5d1 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -36,6 +36,11 @@ function Simulate() { Shallow copy should be fine */ gSim.params = Object.assign({}, gParams); + /* Recalculate current astrological sign */ + if (gSim.params.astrology == 'current') { + gSim.params.astrology = GetStarSign(); + } + gSim.stats = InitStats(gSim.params); gSim.startTime = Date.now(); gSim.progress = 0; @@ -783,6 +788,7 @@ function ConvertSave(save) { $('#aquatic')[0].checked = (save.race.species == "sharkin" || save.race.species == "octigoran"); $('#apexPredator')[0].value = save.race['apex_predator'] || 0; + $('#astrologer')[0].value = save.race['astrologer'] || 0; $('#armored')[0].value = save.race['armored'] || 0; $('#artifical')[0].value = save.race['artifical'] || 0; $('#beast')[0].value = save.race['beast'] || 0; @@ -824,6 +830,7 @@ function ConvertSave(save) { $('#sticky')[0].value = save.race['sticky'] || 0; $('#swift')[0].value = save.race['swift'] || 0; $('#unfathomable')[0].value = save.race['unfathomable'] || 0; + $('#unfavored')[0].value = save.race['unfavored'] || 0; $('#nightmare')[0].value = save.stats.achieve['nightmare'] && save.stats.achieve.nightmare['mg'] || 0; $('#torturers')[0].value = save.civic['torturer'] && save.civic['torturer'].assigned || 0; @@ -856,6 +863,7 @@ function ConvertSave(save) { $('#soulAbsorption')[0].checked = save.tech['hell_pit'] && save.tech['hell_pit'] >= 6 ? true : false; $('#soulLink')[0].checked = save.tech['hell_pit'] && save.tech['hell_pit'] >= 7 ? true : false; $('#advGuns')[0].checked = save.tech['hell_gun'] && save.tech['hell_gun'] >= 2 ? true : false; + $('#astroWish')[0].checked = save.race['wishStats'] && save.race.wishStats['astro'] ? true : false; $('#weaponTech')[0].value = save.tech['military'] ? (save.tech['military'] >= 5 ? save.tech['military'] - 1 : save.tech['military']) : 0; $('#armorTech')[0].value = save.tech['armor'] || 0; @@ -961,6 +969,19 @@ function GroupRow(containerQuery, rowQuery) { } } +function GetStarSign() { + let date = new Date(); + if (date.getMonth() === 1 && date.getDate() >= 19 || date.getMonth() == 2 && date.getDate() <= 20) { + return 'pisces'; + } else if (date.getMonth() == 2 && date.getDate() >= 21 || date.getMonth() == 3 && date.getDate() <= 19) { + return 'aries'; + } else if (date.getMonth() == 5 && date.getDate() >= 22 || date.getMonth() == 6 && date.getDate() <= 22) { + return 'cancer'; + } else { + return 'other'; + } +} + $(document).ready( function() { GroupRow("#cTraits", "#traitsRow"); GroupRow("#cEldritch", "#thrallsRow"); diff --git a/js/worker.js b/js/worker.js index 21105be..1392223 100644 --- a/js/worker.js +++ b/js/worker.js @@ -762,6 +762,9 @@ function Events(params, sim, stats) { /* Reset event odds */ sim.eventOdds = 999; + if (params.astrology == "pisces") { + sim.eventOdds -= Math.round((params.astroWish ? 79 : 49) * AstroMod(params)); + } } else { /* No event, increase the odds */ sim.eventOdds--; @@ -908,6 +911,9 @@ function HealSoldiers(params, sim, stats) { if (params.artifical) { healCredits = params.bootCamps; } + if (params.astrology == "cancer") { + healCredits = Math.max(0, healCredits + Math.round((params.astroWish ? 8 : 5) * AstroMod(params))); + } if (params.bacTanks) { healCredits *= 2; } @@ -1162,6 +1168,9 @@ function ArmyRating(params, sim, size, wound) { if (params.banana) { rating *= 0.8; } + if (params.astrology == "aries") { + rating *= 1 + Math.round((params.astroWish ? 12 : 10) * AstroMod(params)) / 100; + } if (params.governor == "soldier") { rating *= 1.05; } @@ -1343,6 +1352,22 @@ function TraitSelect(trait_rank, rank_tenth, rank_quarter, rank_half, rank_1, ra } } +function AstroMod(params) { + let mod = 1; + if (params.astrologer) { + let bonus = TraitSelect(params.astrologer, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7); + if (params.unfavored) { + mod -= bonus; + } else { + mod += bonus; + } + } + if (params.unfavored) { + mod *= TraitSelect(params.unfavored, -1.75, -1.5, -1.25, -1, -0.75, -0.5, -0.25); + } + return mod; +} + function Fathom(params, thralls) { let active = Math.min(100, thralls); if (params.torturers && active > params.torturers) { From 919ad6cacd1183b5f6207342fabf8060190f234c Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 17 May 2025 00:15:50 -0700 Subject: [PATCH 37/65] Weather sim (for Cautious and forthcoming Tusked) --- index.html | 33 +++++++++++ js/hellsim.js | 10 +++- js/worker.js | 149 ++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 187 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index 2612d97..f79a563 100644 --- a/index.html +++ b/index.html @@ -40,6 +40,10 @@
General
+
+ + +
@@ -121,6 +125,35 @@
General
+
+
+
+ Biome +
+ +
+
+
+
+
+ Orbital Period +
+ +
+
Traits -
diff --git a/js/hellsim.js b/js/hellsim.js index d7dd5d1..d0a001c 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -117,6 +117,8 @@ function InitStats(params) { mercsHired: 0, maxMercPrice: 0, minMoney: params.moneyCap, + rainy: 0, + wet: 0, }; } @@ -260,6 +262,9 @@ function SimResults() { LogResult(stats, "Soul Forge on-time: " + ((stats.forgeOn / stats.bloodWars) * 100).toFixed(1) + "%" + ", souls per hour: " + (stats.forgeSouls / hours).toFixed(0) + "\n"); + if (params.cautious) { + LogResult(stats, "Rainy time: " + ((stats.rainy / stats.bloodWars) * 100).toFixed(1) + "%\n"); + } LogResult(stats, "Total sim time: " + ((Date.now() - gSim.startTime) / 1000).toFixed(1) + " seconds. " + "Sim ticks per second: " + ((stats.ticks / ((Date.now() - gSim.startTime) / 1000)) / 1000).toFixed(1) + "k" + "\n"); @@ -781,9 +786,12 @@ function ConvertSave(save) { $('#harmony')[0].value = save.prestige && save.prestige.Harmony.count || 0; $('#evil_lemon')[0].value = save.stats.achieve['extinct_sludge'] && save.stats.achieve.extinct_sludge['e'] || 0; $('#what_is_best')[0].value = save.stats.achieve['what_is_best'] && save.stats.achieve.what_is_best['e'] || 0; + $('#biome')[0].value = save.city.biome; + $('#orbit')[0].value = save.city.calendar.orbit; $('#banana')[0].checked = save.race['banana'] ? true : false; - $('#rage')[0].checked = save.city.ptrait.includes('rage') ? true : false; + $('#rage')[0].checked = save.city['ptrait'] && save.city.ptrait.includes('rage') ? true : false; + $('#elliptical')[0].checked = save.city['ptrait'] && save.city.ptrait.includes('elliptical') ? true : false; $('#technophobe')[0].checked = save.stats.achieve['technophobe'] && save.stats.achieve.technophobe.l >= 5 ? true : false; $('#aquatic')[0].checked = (save.race.species == "sharkin" || save.race.species == "octigoran"); diff --git a/js/worker.js b/js/worker.js index 1392223..bb88f8b 100644 --- a/js/worker.js +++ b/js/worker.js @@ -82,6 +82,9 @@ function SimStart(id, simId, params, stats) { money: params.moneyCap, mercCounter: 0, clickerCounter: 0, + day: Rand(0, params.orbit), + temp: 1, + weather: 0, lastEvent: -1, progress: 0, done: false @@ -148,6 +151,10 @@ function SimRun(sim, params, stats) { while (sim.tick < sim.ticks) { if (sim.tick % ticks_per_bloodwar == 0) { + if (params.cautious) { + UpdateWeather(sim, params, stats); + } + /* Fight demons */ BloodWar(params, sim, stats); @@ -1122,16 +1129,14 @@ function ArmyRating(params, sim, size, wound) { if (params.chameleon) { rating *= TraitSelect(params.chameleon, 1.03, 1.05, 1.1, 1.2, 1.25, 1.3, 1.35); } - if (params.cautious) { + if (params.cautious && sim && sim.weather == 0) { + /* Note: old simplified weather was Rand(0, 1000) < 216 */ if (sim) { /* Not doing a full weather sim here, but it rains about 21.6% of the time in most biomes */ if (Rand(0, 1000) < 216) { rating *= TraitSelect(params.cautious, 0.84, 0.86, 0.88, 0.9, 0.92, 0.94, 0.96); } - } else { - /* Average multiplier */ - rating *= (1 - 0.216) * 1 + 0.216 * TraitSelect(params.cautious, 0.84, 0.86, 0.88, 0.9, 0.92, 0.94, 0.96); } } @@ -1376,6 +1381,142 @@ function Fathom(params, thralls) { return (active / 100) * (params.nightmare / 5); } +function UpdateWeather(sim, params, stats) { + sim.day++; + if (sim.day >= params.orbit) { + sim.day = 0; + } + + /* TODO: cata / decay */ + + if (Rand(0, 5) == 0) { + + let season = 0; + if (params.elliptical) { + season = Math.floor(sim.day / Math.round(params.orbit / 6)); + season = Math.min(3, Math.round(season * 4/6)); + } else { + /* Yes, season 4 is a thing in the real game too... */ + season = Math.floor(sim.day / Math.round(params.orbit / 4)); + } + + let temp = Rand(0, 3); + let sky = Rand(0, 5); + /* Wind doesn't need to be simmed at the moment */ + /* let wind = Rand(0, 3); */ + + switch (params.biome) { + case 'oceanic': + case 'swamp': + if (sky > 0 && Rand(0, 3) == 0) { + sky--; + } + break; + case 'tundra': + case 'taiga': + if (season == 3) { + temp = 0; + } else if (temp > 0 && Rand(0, 2) == 0) { + temp--; + } + break; + case 'desert': + if (sky < 4 && Rand(0, 2) == 0) { + sky++; + } + break; + case 'ashland': + if (Rand(0, 2) == 0) { + if (sky < 1) { + sky++; + } else if (sky > 2) { + sky--; + } + } + /* Falls through */ + case 'volcanic': + if (season == 1) { + temp = 2; + } else if (temp < 2 && Rand(0, 2) == 0) { + /* Permafrost check -- ashland / volcanic can't be permafrost? */ + temp++; + } + break; + default: + break; + } + + switch (season) { + case 0: + if (sky > 0 && Rand(0, 3) == 0) { + sky--; + } + break; + case 1: + if (temp < 2 && Rand(0, 3) == 0) { + temp++; + } + break; + case 2: + /* Skip wind + if (wind > 0 && Rand(0, 3) == 0) { + wind--; + } + */ + break; + case 3: + if (temp > 0 && Rand(0, 3) == 0) { + temp--; + } + break; + default: + break; + } + + /* Skip wind + if (params.stormy && wind > 0 && Rand(0, 2) == 0) { + // rejuvenated also affects wind here + wind--; + } + */ + + if (sky == 0) { + sim.weather = 0; + } else if (sky >= 1 && sky <= 2) { + sim.weather = 1; + } else { + sim.weather = 2; + /* Don't sim darkness, as weather 2 and weather 1 are the same for our purposes... + + if (params.darkness) { + if (Rand(0, 7 - TraitSelect( params.darkness, 0, 1, 2, 3, 4, 5, 6 )) == 0) { + sim.weather = 1; + } + } + */ + } + + if (temp == 0) { + let min_temp = 0; + if (season == 1 || params.biome == 'hellscape' || (params.biome == 'eden' && season != 3)) { + /* Permafrost check -- hellscape can't be permafrost? */ + min_temp = 1; + } + sim.temp = Math.max(min_temp, sim.temp - 1); + } else if (temp == 2) { + let max_temp = 2; + if (season == 3 || (params.biome == 'eden' && season != 1)) { + max_temp = 1; + } + sim.temp = Math.min(max_temp, sim.temp + 1); + } + } + + if (sim.weather == 0) { + stats.rainy++; + } +} + function Rand(min, max) { return Math.floor(Math.random() * (max - min)) + min; } From cb39463a9663441aa6ce1625a246fd7c9d74cbdb Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 17 May 2025 00:30:36 -0700 Subject: [PATCH 38/65] Tusked trait --- index.html | 17 +++++++++++++++++ js/hellsim.js | 6 +++++- js/worker.js | 34 +++++++++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index f79a563..58bfcb4 100644 --- a/index.html +++ b/index.html @@ -879,6 +879,23 @@
Traits +
+
+
+ Tusked (Narwhalus) +
+ +
+
diff --git a/js/hellsim.js b/js/hellsim.js index d0a001c..e63b655 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -263,7 +263,10 @@ function SimResults() { ", souls per hour: " + (stats.forgeSouls / hours).toFixed(0) + "\n"); if (params.cautious) { - LogResult(stats, "Rainy time: " + ((stats.rainy / stats.bloodWars) * 100).toFixed(1) + "%\n"); + LogResult(stats, "Cautious weather penalty time: " + ((stats.rainy / stats.bloodWars) * 100).toFixed(1) + "%\n"); + } + if (params.tusk) { + LogResult(stats, "Tusked weather bonus time: " + ((stats.wet / stats.bloodWars) * 100).toFixed(1) + "%\n"); } LogResult(stats, "Total sim time: " + ((Date.now() - gSim.startTime) / 1000).toFixed(1) + " seconds. " + "Sim ticks per second: " + ((stats.ticks / ((Date.now() - gSim.startTime) / 1000)) / 1000).toFixed(1) + "k" + @@ -837,6 +840,7 @@ function ConvertSave(save) { $('#sniper')[0].value = save.race['sniper'] || 0; $('#sticky')[0].value = save.race['sticky'] || 0; $('#swift')[0].value = save.race['swift'] || 0; + $('#tusk')[0].value = save.race['tusk'] || 0; $('#unfathomable')[0].value = save.race['unfathomable'] || 0; $('#unfavored')[0].value = save.race['unfavored'] || 0; diff --git a/js/worker.js b/js/worker.js index bb88f8b..7043f80 100644 --- a/js/worker.js +++ b/js/worker.js @@ -151,7 +151,7 @@ function SimRun(sim, params, stats) { while (sim.tick < sim.ticks) { if (sim.tick % ticks_per_bloodwar == 0) { - if (params.cautious) { + if (params.cautious || params.tusk) { UpdateWeather(sim, params, stats); } @@ -364,8 +364,8 @@ function BloodWar(params, sim, stats) { /* Patrols */ let soldiersKilled = 0; let needPity = true; - /* Update patrol rating if cautious, for random weather */ - if (params.cautious) { + /* Update patrol rating if cautious/tusked, for random weather */ + if (params.cautious || params.tusk) { sim.patrolRating = ArmyRating(params, sim, params.patrolSize); sim.patrolRatingDroids = ArmyRating(params, sim, params.patrolSize + DroidSize(params)); } @@ -1195,6 +1195,31 @@ function ArmyRating(params, sim, size, wound) { } rating *= 1 + boost; } + if (params.tusk) { + let moisture = 0; + switch (params.biome) { + case 'oceanic': + case 'swamp': + moisture = 30; + break; + case 'eden': + case 'forest': + case 'grassland': + case 'savanna': + moisture = 20; + break; + case 'tundra': + case 'taiga': + moisture = 10; + break; + default: + break; + } + if (sim.weather == 0 && sim.temp > 0) { + moisture += 10; + } + rating *= 1 + Math.round(moisture * TraitSelect(params.tusk, 0.4, 0.5, 0.75, 1, 1.2, 1.4, 1.6)) / 100 / 2; + } if (params.grenadier) { rating *= TraitSelect(params.grenadier, 2, 2.1, 2.25, 2.5, 2.75, 3, 3.25); } @@ -1514,6 +1539,9 @@ function UpdateWeather(sim, params, stats) { if (sim.weather == 0) { stats.rainy++; + if (sim.temp > 0) { + stats.wet++; + } } } From 3b51f658e0fd28842b6150df335b10efe6d15350 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 17 May 2025 00:31:54 -0700 Subject: [PATCH 39/65] Weather trait fixes --- js/worker.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/js/worker.js b/js/worker.js index 7043f80..19086a9 100644 --- a/js/worker.js +++ b/js/worker.js @@ -1131,13 +1131,7 @@ function ArmyRating(params, sim, size, wound) { } if (params.cautious && sim && sim.weather == 0) { /* Note: old simplified weather was Rand(0, 1000) < 216 */ - if (sim) { - /* Not doing a full weather sim here, but it rains about 21.6% of the time - in most biomes */ - if (Rand(0, 1000) < 216) { - rating *= TraitSelect(params.cautious, 0.84, 0.86, 0.88, 0.9, 0.92, 0.94, 0.96); - } - } + rating *= TraitSelect(params.cautious, 0.84, 0.86, 0.88, 0.9, 0.92, 0.94, 0.96); } if (params.apexPredator) { @@ -1215,7 +1209,7 @@ function ArmyRating(params, sim, size, wound) { default: break; } - if (sim.weather == 0 && sim.temp > 0) { + if (sim && sim.weather == 0 && sim.temp > 0) { moisture += 10; } rating *= 1 + Math.round(moisture * TraitSelect(params.tusk, 0.4, 0.5, 0.75, 1, 1.2, 1.4, 1.6)) / 100 / 2; From e48d93935daa01bbe86b43b3cedbd4c32316f67f Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 17 May 2025 00:36:29 -0700 Subject: [PATCH 40/65] Add dictatorship to government selection box --- index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/index.html b/index.html index 58bfcb4..b23850c 100644 --- a/index.html +++ b/index.html @@ -1206,6 +1206,7 @@
Upgrades Technocracy +
From b3c52d4e55ecc3f0affe464610dee811ace7f08b Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 17 May 2025 00:52:51 -0700 Subject: [PATCH 41/65] Government updates --- index.html | 4 ++++ js/hellsim.js | 1 + js/worker.js | 11 ++++++----- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index b23850c..dc3e97e 100644 --- a/index.html +++ b/index.html @@ -48,6 +48,10 @@
General
+
+ + +
diff --git a/js/hellsim.js b/js/hellsim.js index e63b655..d9c3ae6 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -796,6 +796,7 @@ function ConvertSave(save) { $('#rage')[0].checked = save.city['ptrait'] && save.city.ptrait.includes('rage') ? true : false; $('#elliptical')[0].checked = save.city['ptrait'] && save.city.ptrait.includes('elliptical') ? true : false; $('#technophobe')[0].checked = save.stats.achieve['technophobe'] && save.stats.achieve.technophobe.l >= 5 ? true : false; + $('#bureaucratic_efficiency')[0].checked = save['genes'] && save.genes['governor'] && save.genes.governor >= 3 ? true : false; $('#aquatic')[0].checked = (save.race.species == "sharkin" || save.race.species == "octigoran"); $('#apexPredator')[0].value = save.race['apex_predator'] || 0; diff --git a/js/worker.js b/js/worker.js index 19086a9..df551bc 100644 --- a/js/worker.js +++ b/js/worker.js @@ -1218,11 +1218,11 @@ function ArmyRating(params, sim, size, wound) { rating *= TraitSelect(params.grenadier, 2, 2.1, 2.25, 2.5, 2.75, 3, 3.25); } if (params.government == "autocracy") { - if (params.governor == "bureaucrat") { - rating *= 1.40; - } else { - rating *= 1.35; + let bonus = (params.governor == "bureaucrat") ? 40 : 35; + if (params.bureaucratic_efficiency) { + bonus += (params.governor == "bureaucrat") ? 10 : 5; } + rating *= 1 + bonus / 100; } if (params.universe == "evil") { if (params.authority > 100) { @@ -1265,7 +1265,8 @@ function ArmyRating(params, sim, size, wound) { racialModifier *= TraitSelect(params.ooze, 0.75, 0.8, 0.85, 0.88, 0.9, 0.92, 0.94); } if (params.government == "democracy") { - racialModifier *= 0.95; + let malus = (params.governor == "bureaucrat") ? 1 : 5; + racialModifier *= 1 - malus / 100; } if (params.universe == "magic") { racialModifier *= 0.75; From df5a3c82b5a4683c32e3ef0685f4f1d291df755d Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 17 May 2025 01:02:59 -0700 Subject: [PATCH 42/65] Governor updates --- js/worker.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/worker.js b/js/worker.js index df551bc..c4f46ca 100644 --- a/js/worker.js +++ b/js/worker.js @@ -593,7 +593,7 @@ function BloodWar(params, sim, stats) { if (sim.surveyors > 0) { let divisor = 1000; if (params.governor == "sports") { - divisor *= 1.10; + divisor *= params.bureaucratic_efficiency ? 1.20 : 1.10; } if (params.blurry) { divisor *= TraitSelect(params.blurry, 1.05, 1.10, 1.15, 1.25, 1.35, 1.4, 1.45); @@ -1038,7 +1038,7 @@ function TrainingTime(params) { bootCampBonus = params.vrTraining == true ? 0.08 : 0.05; bootCampBonus += params.bloodLust * 0.002; if (params.governor == "soldier") { - bootCampBonus *= 1.25; + bootCampBonus *= params.bureaucratic_efficiency ? 1.3 : 1.25; } /* rate is percentage points per tick */ @@ -1171,7 +1171,7 @@ function ArmyRating(params, sim, size, wound) { rating *= 1 + Math.round((params.astroWish ? 12 : 10) * AstroMod(params)) / 100; } if (params.governor == "soldier") { - rating *= 1.05; + rating *= params.bureaucratic_efficiency ? 1.3 : 1.25; } if (params.rage) { rating *= 1.05; From 302f96a81ae9fde63c135c9e271e700860601080 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 17 May 2025 01:09:09 -0700 Subject: [PATCH 43/65] Fractional healing update --- js/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/worker.js b/js/worker.js index c4f46ca..edb4ffe 100644 --- a/js/worker.js +++ b/js/worker.js @@ -954,7 +954,7 @@ function HealSoldiers(params, sim, stats) { } healed += Math.floor(healCredits / healCost); healCredits = healCredits % healCost; - if (Rand(0, healCredits) > Rand(0, healCost)) { + if (Rand(0, healCost) < healCredits) { healed++; } From 19fb48dde351911fa666b2ca015f5ca9eb95d5be Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 17 May 2025 01:36:35 -0700 Subject: [PATCH 44/65] Rejuvenated (post-Terraform) bonuses --- index.html | 19 +++++++++++++++++++ js/hellsim.js | 2 ++ js/worker.js | 6 ++++++ 3 files changed, 27 insertions(+) diff --git a/index.html b/index.html index dc3e97e..7f9daed 100644 --- a/index.html +++ b/index.html @@ -44,6 +44,10 @@
General
+
+ + +
@@ -115,6 +119,21 @@
General
+
+
+
+ Lamentis 🏆 +
+ +
+
diff --git a/js/hellsim.js b/js/hellsim.js index d9c3ae6..fb16e1c 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -789,12 +789,14 @@ function ConvertSave(save) { $('#harmony')[0].value = save.prestige && save.prestige.Harmony.count || 0; $('#evil_lemon')[0].value = save.stats.achieve['extinct_sludge'] && save.stats.achieve.extinct_sludge['e'] || 0; $('#what_is_best')[0].value = save.stats.achieve['what_is_best'] && save.stats.achieve.what_is_best['e'] || 0; + $('#lamentis')[0].value = save.stats.achieve['lamentis'] && save.stats.achieve.lamentis['l'] || 0; $('#biome')[0].value = save.city.biome; $('#orbit')[0].value = save.city.calendar.orbit; $('#banana')[0].checked = save.race['banana'] ? true : false; $('#rage')[0].checked = save.city['ptrait'] && save.city.ptrait.includes('rage') ? true : false; $('#elliptical')[0].checked = save.city['ptrait'] && save.city.ptrait.includes('elliptical') ? true : false; + $('#rejuvenated')[0].checked = save.race['rejuvenated'] ? true : false; $('#technophobe')[0].checked = save.stats.achieve['technophobe'] && save.stats.achieve.technophobe.l >= 5 ? true : false; $('#bureaucratic_efficiency')[0].checked = save['genes'] && save.genes['governor'] && save.genes.governor >= 3 ? true : false; diff --git a/js/worker.js b/js/worker.js index edb4ffe..1ce189c 100644 --- a/js/worker.js +++ b/js/worker.js @@ -918,6 +918,9 @@ function HealSoldiers(params, sim, stats) { if (params.artifical) { healCredits = params.bootCamps; } + if (params.rejuvenated && params.lamentis) { + hc += params.lamentis; + } if (params.astrology == "cancer") { healCredits = Math.max(0, healCredits + Math.round((params.astroWish ? 8 : 5) * AstroMod(params))); } @@ -1217,6 +1220,9 @@ function ArmyRating(params, sim, size, wound) { if (params.grenadier) { rating *= TraitSelect(params.grenadier, 2, 2.1, 2.25, 2.5, 2.75, 3, 3.25); } + if (params.rejuvenated) { + rating *= 1.05; + } if (params.government == "autocracy") { let bonus = (params.governor == "bureaucrat") ? 40 : 35; if (params.bureaucratic_efficiency) { From 644843382b1e7821f0266caac0d13f122b5388a6 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 17 May 2025 01:42:23 -0700 Subject: [PATCH 45/65] Hivemind fix --- js/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/worker.js b/js/worker.js index 1ce189c..53d3b7e 100644 --- a/js/worker.js +++ b/js/worker.js @@ -1252,7 +1252,7 @@ function ArmyRating(params, sim, size, wound) { let racialModifier = 1; if (params.hivemind) { let breakpoint = TraitSelect(params.hivemind, 13, 12, 11, 10, 8, 7, 6); - if (size <= 10) { + if (size <= breakpoint) { racialModifier *= (size * 0.05) + (1 - breakpoint * 0.05); } else { racialModifier *= 1 + (1 - (0.99 ** (size - breakpoint))); From b524f71540c7e193c97abb8ba24f4639bb6c07d8 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 17 May 2025 01:44:53 -0700 Subject: [PATCH 46/65] Add the new minimum army rating safeguard --- js/worker.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/worker.js b/js/worker.js index 53d3b7e..c0f5b2a 100644 --- a/js/worker.js +++ b/js/worker.js @@ -1293,6 +1293,10 @@ function ArmyRating(params, sim, size, wound) { } } + if (rating <= 0 && size > 0) { + rating = 0.01; + } + return rating; } From c30e828494e734f885468ee3036070a1560d43b2 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 17 May 2025 02:21:37 -0700 Subject: [PATCH 47/65] Update how forge staffing works with high pop and hivemind --- js/worker.js | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/js/worker.js b/js/worker.js index c0f5b2a..f94258b 100644 --- a/js/worker.js +++ b/js/worker.js @@ -1301,11 +1301,7 @@ function ArmyRating(params, sim, size, wound) { } function DroidSize(params) { - var size = params.enhDroids ? 2 : 1; - if (params.highPop) { - size *= TraitSelect(params.highPop, 2, 2, 3, 4, 5, 6, 7); - } - return size; + return PopFactor(params) * (params.enhDroids ? 2 : 1); } function FortressRating(params, sim) { @@ -1359,10 +1355,20 @@ function FortressRating(params, sim) { } function ForgeSoldiers(params) { - let soldiers = Math.round(650 / ArmyRating(params, false, 1)); - let gunValue = params.advGuns ? 2 : 1; + let popfactor = PopFactor(params); + let rating = Math.max(ArmyRating(params, false, 1), popfactor); + let soldiers = Math.ceil(650 / rating); + + let gunSavings = params.guns * popfactor * (params.advGuns ? 2 : 1); + soldiers = Math.max(0, soldiers - gunSavings); - soldiers = Math.max(0, soldiers - params.guns * gunValue); + if (params.hivemind && soldiers > 0) { + soldiers = 1; + while ((soldiers + gunSavings) * rating < 650) { + soldiers++; + rating = Math.max(ArmyRating(params, false, soldiers), popfactor) / soldiers; + } + } return soldiers; } @@ -1411,6 +1417,14 @@ function Fathom(params, thralls) { return (active / 100) * (params.nightmare / 5); } +function PopFactor(params) { + if (params.highPop) { + return TraitSelect(params.highPop, 2, 2, 3, 4, 5, 6, 7); + } else { + return 1; + } +} + function UpdateWeather(sim, params, stats) { sim.day++; if (sim.day >= params.orbit) { From c157e1d49bdb12dec87a90a5953d9fef58556ba8 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sun, 18 May 2025 15:42:51 -0700 Subject: [PATCH 48/65] Edenic Realm --- index.html | 116 ++++++++++++++++++++++++++++++++++++++++++++++++-- js/hellsim.js | 51 +++++++++++++++++++++- js/worker.js | 82 +++++++++++++++++++++++++++++------ 3 files changed, 231 insertions(+), 18 deletions(-) diff --git a/index.html b/index.html index 7f9daed..772c0f5 100644 --- a/index.html +++ b/index.html @@ -32,6 +32,10 @@
General -
+
+ + +
@@ -48,10 +52,6 @@
General
-
- - -
@@ -89,6 +89,29 @@
General
+
+
+
+ Technophobe 🏆 +
+ +
+
@@ -1183,6 +1206,7 @@
Upgrades Disruptor Rifles +
@@ -1558,6 +1582,90 @@
+
Eden Setup -
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+
+ Ghost Trappers +
+ +
+
+
+
+
+ Mech Response Effect % +
+ +
+
+
+
+
+ Thermal Collectors +
+ +
+
+
+
+
+ Bunkers +
+ +
+
+
+
+
+ Spirit Vacuums +
+ +
+
+
+
+
+ Spirit Batteries +
+ +
+
+
+
+
Sim Options -
diff --git a/js/hellsim.js b/js/hellsim.js index fb16e1c..976beaf 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -41,6 +41,16 @@ function Simulate() { gSim.params.astrology = GetStarSign(); } + /* Parse technophobe info */ + let technophobe_input = gSim.params.technophobe; + if (technophobe_input >= 100) { + gSim.params.technophobe = technophobe_input % 100; + gSim.params.additional_technophobe_universes = Math.floor(technophobe_input / 100); + } else { + gSim.params.technophobe = Math.min(technophobe_input, 5); + gSim.params.additional_technophobe_universes = Math.max(technophobe_input - 5, 0); + } + gSim.stats = InitStats(gSim.params); gSim.startTime = Date.now(); gSim.progress = 0; @@ -74,6 +84,7 @@ function InitStats(params) { forgeGems: 0, gunGems: 0, gateGems: 0, + compactorGems: 0, patrolKills: 0, droneKills: 0, totalPreFightThreat: 0, @@ -182,7 +193,8 @@ function SimResults() { ", Guns: " + (stats.gunGems / hours).toFixed(2) + ", Forge: " + (stats.forgeGems / hours).toFixed(2) + ", Gate Turrets: " + (stats.gateGems / hours).toFixed(2) + - ", Total: " + ((stats.patrolGems + stats.surveyorGems + stats.gunGems + stats.forgeGems + stats.gateGems) / hours).toFixed(2) + + (params.soul_compactor ? ", Compactor: " + (stats.compactorGems / hours).toFixed(2) : "") + + ", Total: " + ((stats.patrolGems + stats.surveyorGems + stats.gunGems + stats.forgeGems + stats.gateGems + stats.compactorGems) / hours).toFixed(2) + "\n"); LogResult(stats, "Encounters: " + stats.patrolEncounters + ", per hour: " + (stats.patrolEncounters / hours).toFixed(1) + @@ -734,6 +746,13 @@ function GetParams() { } +/* Old saved params may not match current format */ +function UpdateParams() { + if (gParams['technophobe'] && "boolean" == typeof gParams.technophobe) { + gParams.technophobe = gParams.technophobe ? 5 : 0; + } +} + /* Fill parameter values back to the form */ function SetParams() { console.log(gParams); @@ -793,11 +812,20 @@ function ConvertSave(save) { $('#biome')[0].value = save.city.biome; $('#orbit')[0].value = save.city.calendar.orbit; + $('#emfield')[0].checked = save.race['emfield'] ? true : false; $('#banana')[0].checked = save.race['banana'] ? true : false; $('#rage')[0].checked = save.city['ptrait'] && save.city.ptrait.includes('rage') ? true : false; $('#elliptical')[0].checked = save.city['ptrait'] && save.city.ptrait.includes('elliptical') ? true : false; $('#rejuvenated')[0].checked = save.race['rejuvenated'] ? true : false; - $('#technophobe')[0].checked = save.stats.achieve['technophobe'] && save.stats.achieve.technophobe.l >= 5 ? true : false; + let technophobe_l = save.stats.achieve['technophobe'] && save.stats.achieve.technophobe.l; + let technophobe_additional = 0; + let universes = ['e', 'a', 'h', 'm', 'mg']; + for (let idx in universes) { + if (save.stats.achieve['technophobe'] && save.stats.achieve.technophobe[universes[idx]] >= 5) { + technophobe_additional++; + } + } + $('#technophobe')[0].value = technophobe_l >= 5 ? 5 + technophobe_additional : technophobe_l + 100 * technophobe_additional; $('#bureaucratic_efficiency')[0].checked = save['genes'] && save.genes['governor'] && save.genes.governor >= 3 ? true : false; $('#aquatic')[0].checked = (save.race.species == "sharkin" || save.race.species == "octigoran"); @@ -962,6 +990,24 @@ function ConvertSave(save) { $('#soulForge')[0].value = 0; } + $('#soul_bait')[0].checked = save.tech['hell_pit'] && save.tech.hell_pit >= 6 ? true : false; + /* "Soul Power" enables the tech 5 event which is random, just assume it will happen */ + $('#asphodel_hostility')[0].checked = save.tech['asphodel'] && save.tech.asphodel >= 4 ? true : false; + $('#asphodel_mech_security')[0].checked = save.tech['asphodel'] && save.tech.asphodel >= 6 ? true : false; + $('#dimensional_tap')[0].checked = save.tech['science'] && save.tech.science >= 24 && + save['interstellar'] && save.interstellar['ascension_trigger'] && save.interstellar.ascension_trigger.on >= 1 ? + true : false; + $('#spectral_training')[0].checked = save.tech['celestial_warfare'] && save.tech.celestial_warfare >= 5 ? true : false; + $('#soul_compactor')[0].checked = save['eden'] && save.eden['soul_compactor'] && save.eden.soul_compactor.count >= 1 ? true : false; + $('#suction_force')[0].checked = save.tech['isle'] && save.tech.isle >= 6 ? true : false; + + $('#ghost_trappers')[0].value = save.civic['ghost_trapper'] && save.civic['ghost_trapper'].assigned || 0; + $('#mech_station_effect')[0].value = save['eden'] && save.eden['mech_station'] && save.eden.mech_station.count >= 10 && save.eden.mech_station.effect || 0; + $('#thermal_collectors')[0].value = save['interstellar'] && save.interstellar['thermal_collector'] && save.interstellar.thermal_collector.count || 0; + $('#bunkers')[0].value = save['eden'] && save.eden['bunker'] && save.eden.bunker.on || 0; + $('#vacuums')[0].value = save['eden'] && save.eden['spirit_vacuum'] && save.eden.spirit_vacuum.on || 0; + $('#batteries')[0].value = save['eden'] && save.eden['spirit_battery'] && save.eden.spirit_battery.on || 0; + OnChange(); } @@ -1034,6 +1080,7 @@ $(document).ready( function() { paramStr = window.localStorage.getItem('hellSimParams') || false; if (paramStr) { gParams = JSON.parse(paramStr); + UpdateParams(); SetParams(); } diff --git a/js/worker.js b/js/worker.js index f94258b..8294d8b 100644 --- a/js/worker.js +++ b/js/worker.js @@ -79,6 +79,7 @@ function SimStart(id, simId, params, stats) { pity: 0, eventOdds: 999, forgeSouls: 0, + compactor_energy: 0, money: params.moneyCap, mercCounter: 0, clickerCounter: 0, @@ -220,6 +221,9 @@ function SimRun(sim, params, stats) { } } + /* Spirit Vacuum */ + Vacuum(params, sim, stats); + sim.tick++; stats.ticks++; @@ -348,7 +352,7 @@ function BloodWar(params, sim, stats) { } /* Gem Chance */ - let gemOdds = params.technophobe ? 9000 : 10000; + let gemOdds = params.technophobe >= 5 ? 9000 : 10000; gemOdds -= sim.pity; gemOdds = Math.round(gemOdds * (0.948 ** params.beacons)); if (params.ghostly) { @@ -639,13 +643,40 @@ function BloodWar(params, sim, stats) { } /* Soul Attractors */ - if (forgeOperating) { - forgeSouls += params.soulAttractors * ((params.soulTrap * 5) + Rand(40, 120)); + if (forgeOperating && params.soulAttractors) { + let bonus = params.soulTrap * 5; + if (params.soul_bait) { + bonus *= 2; + } + forgeSouls += params.soulAttractors * (bonus + Rand(40, 120)); + } + + /* Ghost Trappers */ + if (forgeOperating && params.ghost_trappers) { + let souls = params.ghost_trappers * (params.soulTrap * 5 + Rand(150, 250)); + if (params.dimensional_tap) { + let heatsink = 100; + if (params.technophobe >= 2) { + heatsink += params.technophobe >= 4 ? 25 : 10; + heatsink += 5 * params.additional_technophobe_universes; + } + heatsink = Math.max(0, heatsink * params.thermal_collectors - (params.emfield ? 15000 : 10000)); + souls *= 1 + heatsink / 12500; + } + let resist = 1; + if (params.asphodel_hostility) { + if (params.asphodel_mech_security) { + resist = 0.34 + params.mech_station_effect * 0.0066; + } else { + resist = 0.67; + } + } + forgeSouls += Math.floor(souls * resist); } /* Gun Emplacements */ - if (forgeOperating) { - let gemOdds = params.technophobe ? 6750 : 7500; + if (forgeOperating && params.guns) { + let gemOdds = params.technophobe >= 5 ? 6750 : 7500; if (params.soulLink) { gemOdds = Math.round(gemOdds * 0.94 ** params.soulAttractors); } @@ -665,8 +696,8 @@ function BloodWar(params, sim, stats) { } /* Gate Turrets */ - if (forgeOperating) { - let gemOdds = params.technophobe ? 2700 : 3000; + if (forgeOperating && params.gateTurrets) { + let gemOdds = params.technophobe >= 5 ? 2700 : 3000; let gateKills = 0; if (params.advGuns) { gateKills = params.gateTurrets * Rand(65, 100); @@ -684,7 +715,7 @@ function BloodWar(params, sim, stats) { /* Soul Forge */ if (forgeOperating) { - let gemOdds = params.technophobe ? 4500 : 5000; + let gemOdds = params.technophobe >= 5 ? 4500 : 5000; let forgeKills = Rand(25, 150); forgeSouls += forgeKills; stats.kills += forgeKills; @@ -984,6 +1015,20 @@ function RepairSurveyors(params, sim, stats) { } } +function Vacuum(params, sim, stats) { + if (params.soul_compactor && params.vacuums > 0) { + let drain = 1653439 * params.vacuums; + if (params.suction_force && params.batteries > 0) { + drain *= 1 + params.batteries * 0.08; + } + sim.compactor_energy += Math.round(drain / 2); + if (sim.compactor_energy >= 1000000000) { + sim.compactor_energy -= 1000000000; + stats.compactorGems++; + } + } +} + function PatrolCasualties(params, sim, stats, demons, ambush) { var armor; if (ambush) { @@ -1035,7 +1080,6 @@ function PatrolCasualties(params, sim, stats, demons, ambush) { /* Returns soldier training time in ticks, not rounded */ function TrainingTime(params) { - var rate; var bootCampBonus; bootCampBonus = params.vrTraining == true ? 0.08 : 0.05; @@ -1044,15 +1088,20 @@ function TrainingTime(params) { bootCampBonus *= params.bureaucratic_efficiency ? 1.3 : 1.25; } - /* rate is percentage points per tick */ - rate = 2.5; + /* Rate is calculated in percentage points per second */ + let rate = 2.5; if (params.highPop) { rate *= TraitSelect(params.highPop, 1.2, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5); } if (params.diverse) { rate /= TraitSelect(params.diverse, 1.4, 1.35, 1.3, 1.25, 1.2, 1.15, 1.12); } - rate *= 1 + params.bootCamps * bootCampBonus; + if (params.bootCamps) { + rate *= 1 + params.bootCamps * TrainingBonus(params.vrTraining ? 0.08 : 0.05, params); + } + if (params.bunkers && params.spectral_training) { + rate *= 1 + params.bunkers * TrainingBonus(0.1, params); + } if (params.beast) { rate *= TraitSelect(params.beast, 1.03, 1.04, 1.05, 1.1, 1.15, 1.2, 1.25); } @@ -1062,6 +1111,7 @@ function TrainingTime(params) { if (params.orc_thralls) { rate += 2.5 * Fathom(params, params.orc_thralls); } + /* Convert to progress per tick (as does the game) */ rate *= 0.25; /* Convert to ticks per soldier */ @@ -1069,6 +1119,14 @@ function TrainingTime(params) { return 1.0/rate; } +function TrainingBonus(value, params) { + value += params.bloodLust * 0.002; + if (params.governor == "soldier") { + value *= params.bureaucratic_efficiency ? 1.3 : 1.25; + } + return value; +} + function ArmyRating(params, sim, size, wound) { var rating = size; var wounded = 0; From 48b2455c14bccd6f79efb5d6af2916fdcaf528df Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sun, 18 May 2025 15:46:04 -0700 Subject: [PATCH 49/65] Reformat general params --- index.html | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/index.html b/index.html index 772c0f5..ac1d0a4 100644 --- a/index.html +++ b/index.html @@ -89,6 +89,12 @@
General
+
+
+
+
+
+
@@ -157,6 +163,10 @@
General
+
+
+
+
@@ -200,6 +210,10 @@
General
+
+
+
+
Traits -
From 8321fe016065e4ddaf46d597e87f5487eee4ad59 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sun, 18 May 2025 15:48:18 -0700 Subject: [PATCH 50/65] Eden collapsed by default --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index ac1d0a4..eb5774d 100644 --- a/index.html +++ b/index.html @@ -1596,7 +1596,7 @@
-
Eden Setup -
+
Eden Setup +
From 0eb38c6896302a8a3631e24f12f03132ac37d99a Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sun, 18 May 2025 17:15:42 -0700 Subject: [PATCH 51/65] Star names, icon locations --- index.html | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/index.html b/index.html index eb5774d..7eb29c1 100644 --- a/index.html +++ b/index.html @@ -102,7 +102,7 @@
General - + @@ -140,7 +142,7 @@
General - + @@ -174,9 +176,9 @@
General
@@ -1013,7 +1015,7 @@
Eldritch Pow
+ +
diff --git a/js/hellsim.js b/js/hellsim.js index 976beaf..6ae1a58 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -813,6 +813,7 @@ function ConvertSave(save) { $('#orbit')[0].value = save.city.calendar.orbit; $('#emfield')[0].checked = save.race['emfield'] ? true : false; + $('#witch_hunter')[0].checked = save.race['witch_hunter'] ? true : false; $('#banana')[0].checked = save.race['banana'] ? true : false; $('#rage')[0].checked = save.city['ptrait'] && save.city.ptrait.includes('rage') ? true : false; $('#elliptical')[0].checked = save.city['ptrait'] && save.city.ptrait.includes('elliptical') ? true : false; diff --git a/js/worker.js b/js/worker.js index 8294d8b..08768da 100644 --- a/js/worker.js +++ b/js/worker.js @@ -1334,8 +1334,15 @@ function ArmyRating(params, sim, size, wound) { } if (params.universe == "magic") { racialModifier *= 0.75; + if (params.witch_hunter) { + racialModifier *= 0.75; + } if (params.warRitual) { - racialModifier *= 1 + (params.warRitual / (params.warRitual + 75)); + let boost = params.warRitual / (params.warRitual + 75); + if (params.witch_hunter) { + boost *= 2.5; + } + racialModifier *= 1 + boost; } } if (params.highPop) { From 8c15265ae99eedc5a5d241d8c861976ae2cfb976 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Mon, 19 May 2025 01:35:45 -0700 Subject: [PATCH 53/65] Modeling more events --- index.html | 67 ++++++++++++++++++++++++++++++++++++++++++++++++--- js/hellsim.js | 9 ++++++- js/worker.js | 37 ++++++++++++++++++++++++++-- 3 files changed, 106 insertions(+), 7 deletions(-) diff --git a/index.html b/index.html index dc41a76..acac6f4 100644 --- a/index.html +++ b/index.html @@ -52,6 +52,14 @@
General
+
+ + +
+
+ + +
@@ -234,9 +242,9 @@
Traits
- Apex Predator (Sharkin) + Aggressive (Bombardier)
- @@ -251,9 +259,9 @@
Traits
- Astrologer (Slitheryn) + Apex Predator (Sharkin)
- @@ -299,6 +307,23 @@
Traits
+
+
+
+ Astrologer (Slitheryn) +
+ +
+
@@ -435,6 +460,23 @@
Traits
+
+
+
+ Curious (Cath) +
+ +
+
@@ -809,6 +851,23 @@
Traits
+
+
+
+ Rogue (Racconar) +
+ +
+
diff --git a/js/hellsim.js b/js/hellsim.js index 6ae1a58..7fde10f 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -85,6 +85,7 @@ function InitStats(params) { gunGems: 0, gateGems: 0, compactorGems: 0, + curiousGems: 0, patrolKills: 0, droneKills: 0, totalPreFightThreat: 0, @@ -194,7 +195,8 @@ function SimResults() { ", Forge: " + (stats.forgeGems / hours).toFixed(2) + ", Gate Turrets: " + (stats.gateGems / hours).toFixed(2) + (params.soul_compactor ? ", Compactor: " + (stats.compactorGems / hours).toFixed(2) : "") + - ", Total: " + ((stats.patrolGems + stats.surveyorGems + stats.gunGems + stats.forgeGems + stats.gateGems + stats.compactorGems) / hours).toFixed(2) + + (params.curious ? ", Curious: " + (stats.curiousGems / hours).toFixed(2) : "") + + ", Total: " + ((stats.patrolGems + stats.surveyorGems + stats.gunGems + stats.forgeGems + stats.gateGems + stats.compactorGems + stats.curiousGems) / hours).toFixed(2) + "\n"); LogResult(stats, "Encounters: " + stats.patrolEncounters + ", per hour: " + (stats.patrolEncounters / hours).toFixed(1) + @@ -817,6 +819,8 @@ function ConvertSave(save) { $('#banana')[0].checked = save.race['banana'] ? true : false; $('#rage')[0].checked = save.city['ptrait'] && save.city.ptrait.includes('rage') ? true : false; $('#elliptical')[0].checked = save.city['ptrait'] && save.city.ptrait.includes('elliptical') ? true : false; + $('#flare')[0].checked = save.city['ptrait'] && save.city.ptrait.includes('flare') ? true : false; + $('#ancient_ruins')[0].checked = save.race['ancient_ruins'] ? true : false; $('#rejuvenated')[0].checked = save.race['rejuvenated'] ? true : false; let technophobe_l = save.stats.achieve['technophobe'] && save.stats.achieve.technophobe.l; let technophobe_additional = 0; @@ -830,6 +834,7 @@ function ConvertSave(save) { $('#bureaucratic_efficiency')[0].checked = save['genes'] && save.genes['governor'] && save.genes.governor >= 3 ? true : false; $('#aquatic')[0].checked = (save.race.species == "sharkin" || save.race.species == "octigoran"); + $('#aggressive')[0].value = save.race['aggressive'] || 0; $('#apexPredator')[0].value = save.race['apex_predator'] || 0; $('#astrologer')[0].value = save.race['astrologer'] || 0; $('#armored')[0].value = save.race['armored'] || 0; @@ -842,6 +847,7 @@ function ConvertSave(save) { $('#chameleon')[0].value = save.race['chameleon'] || 0; $('#chicken')[0].value = save.race['chicken'] || 0; $('#claws')[0].value = save.race['claws'] || 0; + $('#curious')[0].value = save.race['curious'] || 0; $('#diverse')[0].value = save.race['diverse'] || 0; $('#elemental')[0].value = save.race['elemental'] || 0; $('#elusive')[0].value = save.race['elusive'] || 0; @@ -864,6 +870,7 @@ function ConvertSave(save) { $('#rhinoRage')[0].value = save.race['rage'] || 0; $('#regenerative')[0].value = save.race['regenerative'] || 0; $('#revive')[0].value = save.race['revive'] || 0; + $('#rogue')[0].value = save.race['rogue'] || 0; $('#scales')[0].value = save.race['scales'] || 0; $('#slaver')[0].value = save.race['slaver'] || 0; $('#slow')[0].value = save.race['slow'] || 0; diff --git a/js/worker.js b/js/worker.js index 08768da..5eef1d6 100644 --- a/js/worker.js +++ b/js/worker.js @@ -748,16 +748,45 @@ function Events(params, sim, stats) { "inspiration", "motivation", "surge", - "terrorist", - "ruins" + "terrorist" ]; if (!(params.kindling || params.smoldering || params.evil || params.aquatic)) { events.push("fire"); } + if (params.flare) { + events.push("flare"); + } + /* TODO: Witch crusade? */ + if (params.ancient_ruins) { + events.push("ruins"); + } if (params.slaver) { events.push("slave1", "slave2", "slave3"); } + if (params.government == "republic") { + events.push("protest"); + } + if (params.governor == "media") { + events.push("scandal"); + } + /* TODO: maybe? + if (params.miners) { + events.push("mine_collapse"); + } + */ + if (params.rogue) { + events.push("klepto"); + } + if (params.chicken) { + events.push("chicken_feast"); + } + if (params.aggressive) { + events.push("brawl"); + } + if (params.curious) { + events.push("m_curious"); + } /* Remove the last event that occurred from the list so that the same event can't happen twice in a row */ let lastIdx = events.indexOf(sim.lastEvent); @@ -794,6 +823,10 @@ function Events(params, sim, stats) { LogResult(stats, TimeStr(sim) + " - Terrorist attack: " + wounded + " wounded, " + killed + " killed.\n"); } } + } else if (event == "m_curious") { + if (Rand(0, 25) == 0) { + stats.curiousGems++; + } } /* else, irrelevant event */ sim.lastEvent = event; From c21215a2e5c8273a21cb261d1594522a60c4e148 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 31 May 2025 14:42:38 -0700 Subject: [PATCH 54/65] Implementing current sort-of-broken revive trait behavior --- js/worker.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/js/worker.js b/js/worker.js index 5eef1d6..a7afd80 100644 --- a/js/worker.js +++ b/js/worker.js @@ -487,7 +487,10 @@ function BloodWar(params, sim, stats) { if (params.revive) { let reviveDivisor = TraitSelect(params.revive, 4, 4, 4, 3, 2, 2, 2); let reviveMax = soldiersKilled / reviveDivisor + 0.25; - let revived = Math.round(Math.random() * reviveMax); + /* Yes, the argument is not an integer. This is wacky in-game due to refactoring. + It's a pretty devastating nerf in practice. See: + https://github.com/pmotschmann/Evolve/issues/1479 */ + let revived = Rand(0, reviveMax); sim.soldiers += revived; stats.soldiersRevived += revived; } From e264ee2ae23c73980f8b0c721891600a3054172c Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 31 May 2025 14:57:51 -0700 Subject: [PATCH 55/65] Terror attack wasn't wounding the right number --- js/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/worker.js b/js/worker.js index a7afd80..e7fbfa9 100644 --- a/js/worker.js +++ b/js/worker.js @@ -813,7 +813,7 @@ function Events(params, sim, stats) { /* Terrorist attack or enemy raid. Equivalent for our purposes here */ if (params.terrorists) { let killed = Rand(0, sim.wounded); - let wounded = Rand(sim.wounded, sim.soldiers); + let wounded = Rand(0, sim.soldiers - sim.wounded); sim.soldiers -= killed; stats.soldiersKilled += killed; From b7ca7578c9a28ac447cc46a9b12fa6e4165d161a Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 31 May 2025 15:00:33 -0700 Subject: [PATCH 56/65] Instincts help against terror attack --- js/worker.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/js/worker.js b/js/worker.js index e7fbfa9..3d3ba8a 100644 --- a/js/worker.js +++ b/js/worker.js @@ -815,6 +815,11 @@ function Events(params, sim, stats) { let killed = Rand(0, sim.wounded); let wounded = Rand(0, sim.soldiers - sim.wounded); + if (params.instincts) { + killed = Math.round(killed / 2); + wounded = Math.round(wounded / 2); + } + sim.soldiers -= killed; stats.soldiersKilled += killed; sim.wounded += wounded; From efa0cc18a2ae8726157b77d78f5bb9d76f667269 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Sat, 31 May 2025 15:53:03 -0700 Subject: [PATCH 57/65] Training update -- allow multiple per tick, save fraction, UI respects hyper/slow rank --- js/hellsim.js | 26 +++++++++--------------- js/worker.js | 56 ++++++++++++++++++++++++++++----------------------- 2 files changed, 40 insertions(+), 42 deletions(-) diff --git a/js/hellsim.js b/js/hellsim.js index 7fde10f..044c940 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -486,7 +486,7 @@ function HandleSimStopped(stats) { } */ function UpdateUIStrings(e) { - ratingStr = ""; + let ratingStr = ""; if (gParams.cautious) { ratingStr += "~ "; } @@ -509,17 +509,13 @@ function UpdateUIStrings(e) { } $('#fortressRating').html(ratingStr); - /* Get the training time, then round up to next tick and convert to seconds */ - trainingTime = e.data.trainingTime; - trainingTime = Math.ceil(trainingTime) / 4; - if (gParams.hyper) { - trainingTime *= 0.95; - } - if (gParams.slow) { - trainingTime *= 1.1; - } - let trainingRate = 3600 / trainingTime; - let trainingStr = trainingTime.toFixed(2) + "sec   " + trainingRate.toFixed(1); + /* Get the training rate in progress (%) per tick, convert to soldiers per hour */ + let trainingRate = e.data.trainingRate; + let tickLength = e.data.tickLength; /* milliseconds */ + + let soldierPerHour = (trainingRate / 100) * (1000 / tickLength) * 3600; + let trainingTime = (tickLength / 1000) * (100 / trainingRate); + let trainingStr = trainingTime.toFixed(2) + "sec   " + soldierPerHour.toFixed(1); var mercRate; switch (gParams.hireMercs) { case 'script': @@ -576,11 +572,7 @@ function UpdateUIStrings(e) { } function OnChange() { - var patrolRating; - var patrolRatingDroids; - var fortressRating; - var trainingTime; - + GetParams(); /* If cpuThreads is invalid, set it to default based on user hardware. diff --git a/js/worker.js b/js/worker.js index 3d3ba8a..f7847cc 100644 --- a/js/worker.js +++ b/js/worker.js @@ -18,7 +18,8 @@ var gStop = false; fortressRating - Fortress combat rating patrolRating - Normal patrol combat rating patrolRatingDroids - Droid-augmented patrol combat rating - trainingTime - Soldier training time in ticks per soldier + tickLength - Length of a tick in milliseconds + trainingRate - Training progress (%) per tick forgeSoldiers - Number of soldiers required to run the Soul Forge 'progress' - Update for progress bar increment - Progress increment as a percentage of the sim @@ -47,13 +48,7 @@ onmessage = function(e) { } function SimStart(id, simId, params, stats) { - var tickLength = 250; - if (params.hyper) { - tickLength *= TraitSelect(params.hyper, 0.99, 0.98, 0.97, 0.95, 0.94, 0.93, 0.92); - } - if (params.slow) { - tickLength *= TraitSelect(params.slow, 1.14, 1.13, 1.12, 1.1, 1.08, 1.06, 1.05); - } + let tickLength = TickLength(params); var sim = { id: id, simId: simId, @@ -70,7 +65,7 @@ function SimStart(id, simId, params, stats) { patrolRatingDroids: 0, wounded: 0, trainingProgress: 0, - trainingTime: 0, + trainingRate: 0, surveyors: params.surveyors, carRepair: 0, siegeOdds: 999, @@ -100,7 +95,7 @@ function SimStart(id, simId, params, stats) { /* Calculate patrol rating and training rate ahead of time for efficiency */ sim.patrolRating = ArmyRating(params, false, params.patrolSize); sim.patrolRatingDroids = ArmyRating(params, false, params.patrolSize + DroidSize(params)); - sim.trainingTime = TrainingTime(params); + sim.trainingRate = TrainingRate(params); LogResult(stats, " -- Sim " + sim.simId.toString().padStart(Math.floor(Math.log10(params.sims)) + 1, 0) + " --\n"); @@ -123,13 +118,15 @@ function ProvideInfo (params) { var fortressRating; var patrolRating; var patrolRatingDroids; - var trainingTime; + var tickLength; + var trainingRate; var forgeSoldiers; fortressRating = FortressRating(params, false); patrolRating = ArmyRating(params, false, params.patrolSize); patrolRatingDroids = ArmyRating(params, false, params.patrolSize + DroidSize(params)); - trainingTime = TrainingTime(params); + tickLength = TickLength(params); + trainingRate = TrainingRate(params); forgeSoldiers = ForgeSoldiers(params); self.postMessage({ @@ -137,7 +134,8 @@ function ProvideInfo (params) { fortressRating: fortressRating, patrolRating: patrolRating, patrolRatingDroids: patrolRatingDroids, - trainingTime: trainingTime, + tickLength: tickLength, + trainingRate: trainingRate, forgeSoldiers: forgeSoldiers }); } @@ -855,15 +853,14 @@ function TrainSoldiers(params, sim, stats) { return; } - sim.trainingProgress += 100 / sim.trainingTime; + sim.trainingProgress += sim.trainingRate; if (sim.trainingProgress >= 100) { - sim.soldiers++; - stats.soldiersTrained++; - sim.trainingProgress = 0; - if (sim.hellSoldiers < sim.maxHellSoldiers) { - sim.hellSoldiers++; - } + let trained = Math.floor(sim.trainingProgress / 100); + sim.soldiers += trained; + stats.soldiersTrained += trained; + sim.trainingProgress -= trained * 100; + sim.hellSoldiers = Math.min(sim.hellSoldiers + trained, sim.maxHellSoldiers); } } @@ -1119,8 +1116,19 @@ function PatrolCasualties(params, sim, stats, demons, ambush) { return dead; } -/* Returns soldier training time in ticks, not rounded */ -function TrainingTime(params) { +function TickLength(params) { + let tickLength = 250; + if (params.hyper) { + tickLength *= TraitSelect(params.hyper, 0.99, 0.98, 0.97, 0.95, 0.94, 0.93, 0.92); + } + if (params.slow) { + tickLength *= TraitSelect(params.slow, 1.14, 1.13, 1.12, 1.1, 1.08, 1.06, 1.05); + } + return tickLength; +} + +/* Returns soldier training rate in progress points (%) per tick */ +function TrainingRate(params) { var bootCampBonus; bootCampBonus = params.vrTraining == true ? 0.08 : 0.05; @@ -1155,9 +1163,7 @@ function TrainingTime(params) { /* Convert to progress per tick (as does the game) */ rate *= 0.25; - /* Convert to ticks per soldier */ - rate /= 100.0; - return 1.0/rate; + return rate; } function TrainingBonus(value, params) { From f272e2cc715ebe774c67edfe4a3a38c349e9e38d Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Wed, 4 Jun 2025 15:51:24 -0700 Subject: [PATCH 58/65] High pop updates --- js/hellsim.js | 26 +++++++++++++++++++++++++- js/worker.js | 25 ++++++++++++++++++------- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/js/hellsim.js b/js/hellsim.js index 044c940..084dae1 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -959,11 +959,35 @@ function ConvertSave(save) { defenders = 0; garrison = save.civic.garrison.max; } + let popFactor = 1; + if (save.race['high_pop']) { + switch(save.race.high_pop) { + case 0.1: + case 0.25: + popFactor = 2; + break; + case 0.5: + popFactor = 3; + break; + case 1: + popFactor = 4; + break; + case 2: + popFactor = 5; + break; + case 3: + popFactor = 6; + break; + case 4: + popFactor = 7; + break; + } + } $('#patrols')[0].value = patrols; $('#patrolSize')[0].value = patrolSize; $('#defenders')[0].value = defenders; $('#garrison')[0].value = garrison; - $('#surveyors')[0].value = save.portal.carport ? save.portal.carport.count : 0; + $('#surveyors')[0].value = save.portal.carport ? popFactor * save.portal.carport.count : 0; $('#repairDroids')[0].value = save.portal.repair_droid ? save.portal.repair_droid.count : 0; $('#turrets')[0].value = save.portal.turret ? save.portal.turret.on : 0; $('#beacons')[0].value = save.portal.attractor ? save.portal.attractor.on : 0; diff --git a/js/worker.js b/js/worker.js index f7847cc..70e56fc 100644 --- a/js/worker.js +++ b/js/worker.js @@ -179,10 +179,13 @@ function SimRun(sim, params, stats) { /* Random events, which could mean a demon surge influx */ Events(params, sim, stats); - /* 1/4 chance to reduce merc counter */ + /* 1/3 chance to reduce merc counter -- we assume Signing Bonus was researched. */ if (sim.mercCounter > 0) { - if (Rand(0,3) == 0) { - sim.mercCounter--; + let rolls = PopFactor(params); + for (let i = 0; i < rolls && sim.mercCounter > 0; i++) { + if (Rand(0,3) == 0) { + sim.mercCounter--; + } } } } @@ -612,9 +615,11 @@ function BloodWar(params, sim, stats) { if (params.shieldGen) { divisor += 250; } - let danger = sim.threat / divisor; - let exposure = Math.min(10, sim.surveyors); - let risk = 10 - Rand(0, exposure+1); + let popfactor = PopFactor(params); + let danger = popfactor * (sim.threat / divisor); + let max_risk = popfactor * 10; + let exposure = Math.min(max_risk, sim.surveyors); + let risk = max_risk - Rand(0, exposure+1); if (danger > risk) { let cap = Math.round(danger); @@ -1012,6 +1017,9 @@ function HealSoldiers(params, sim, stats) { healCredits += Math.floor(3 * Fathom(params, params.mantis_thralls)); } } + if (params.highPop) { + healCredits *= TraitSelect(params.HighPop, 1.2, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5); + } if (params.governor == "sports") { healCredits *= 1.5; } @@ -1043,8 +1051,11 @@ function RepairSurveyors(params, sim, stats) { let repair = 180; if (params.repairDroids > 0) { repair *= 0.95 ** params.repairDroids; - repair = Math.round(repair); } + if (params.highPop) { + repair /= TraitSelect(params.HighPop, 1.2, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5); + } + repair = Math.round(repair); sim.carRepair++; if (sim.carRepair >= repair) { From b96ea963ef21b0fc499c68775aab0d6797342731 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Wed, 4 Jun 2025 15:53:04 -0700 Subject: [PATCH 59/65] Fix Lamentis healing bonus --- js/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/worker.js b/js/worker.js index 70e56fc..d4555d6 100644 --- a/js/worker.js +++ b/js/worker.js @@ -993,7 +993,7 @@ function HealSoldiers(params, sim, stats) { healCredits = params.bootCamps; } if (params.rejuvenated && params.lamentis) { - hc += params.lamentis; + healCredits += params.lamentis; } if (params.astrology == "cancer") { healCredits = Math.max(0, healCredits + Math.round((params.astroWish ? 8 : 5) * AstroMod(params))); From ebb40b0b11748e51e8718099ebe3cabe05b57e16 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Wed, 4 Jun 2025 15:55:15 -0700 Subject: [PATCH 60/65] Fix repair droid bonus to surveyors --- js/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/worker.js b/js/worker.js index d4555d6..ea15e3c 100644 --- a/js/worker.js +++ b/js/worker.js @@ -1050,7 +1050,7 @@ function RepairSurveyors(params, sim, stats) { } let repair = 180; if (params.repairDroids > 0) { - repair *= 0.95 ** params.repairDroids; + repair *= 0.92 ** params.repairDroids; } if (params.highPop) { repair /= TraitSelect(params.HighPop, 1.2, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5); From 49dce9761935323ada589f51b9980b1c0ade41e5 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:28:21 -0700 Subject: [PATCH 61/65] New death stats --- js/hellsim.js | 4 ++++ js/worker.js | 20 +++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/js/hellsim.js b/js/hellsim.js index 084dae1..0e65bc4 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -104,6 +104,8 @@ function InitStats(params) { totalWounded: 0, maxWounded: 0, ambushDeaths: 0, + woundedDeaths: 0, + noDroidDeaths: 0, minReserves: params.garrison + params.defenders, surges: 0, sieges: 0, @@ -221,6 +223,8 @@ function SimResults() { LogResult(stats, ", per bloodwar: " + (stats.soldiersKilled / stats.bloodWars).toFixed(3) + ", in ambushes: " + (stats.ambushDeaths / stats.soldiersKilled * 100).toFixed(1) + "%" + + ", in wounded patrols: " + (stats.woundedDeaths / stats.soldiersKilled * 100).toFixed(1) + "%" + + ", with no droid: " + (stats.noDroidDeaths / stats.soldiersKilled * 100).toFixed(1) + "%" + "\n"); if (params.hireMercs != "off") { LogResult(stats, diff --git a/js/worker.js b/js/worker.js index ea15e3c..09568f6 100644 --- a/js/worker.js +++ b/js/worker.js @@ -399,20 +399,24 @@ function BloodWar(params, sim, stats) { /* Encounter */ stats.patrolEncounters++; + let droid = false; + if (droids > 0) { + droid = true; + droids--; + } + var patrolRating; /* If no wounded, use alread-calculated patrol rating to save time */ if (wounded == 0) { - if (droids > 0) { + if (droid) { patrolRating = sim.patrolRatingDroids; - droids--; } else { patrolRating = sim.patrolRating; } } else { let patrolSize = params.patrolSize; - if (droids > 0) { + if (droid) { patrolSize += DroidSize(params); - droids--; } patrolRating = ArmyRating(params, sim, patrolSize, wounded); } @@ -455,7 +459,13 @@ function BloodWar(params, sim, stats) { let kills = patrolRating; if (kills < demons) { /* Suffer casualties if the patrol didn't kill all of the demons */ - soldiersKilled += PatrolCasualties(params, sim, stats, (demons - kills), false); + let dead = PatrolCasualties(params, sim, stats, (demons - kills), false); + soldiersKilled += dead; + if (wounded > 0) { + stats.woundedDeaths += dead; + } else if (!droid) { + stats.noDroidDeaths += dead; + } } else { kills = demons; } From 17e962e450c9f3e1761947ba8a4558b84e423d73 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:49:24 -0700 Subject: [PATCH 62/65] Marginal encounter rate --- js/hellsim.js | 2 ++ js/worker.js | 3 +++ 2 files changed, 5 insertions(+) diff --git a/js/hellsim.js b/js/hellsim.js index 0e65bc4..9bb7803 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -97,6 +97,7 @@ function InitStats(params) { bloodWars: 0, patrolEncounters: 0, skippedEncounters: 0, + marginalEncounters: 0, ambushes: 0, soldiersTrained: 0, soldiersKilled: 0, @@ -203,6 +204,7 @@ function SimResults() { LogResult(stats, "Encounters: " + stats.patrolEncounters + ", per hour: " + (stats.patrolEncounters / hours).toFixed(1) + ", per bloodwar: " + (stats.patrolEncounters / stats.bloodWars).toFixed(3) + + ", marginal: " + (stats.marginalEncounters / stats.bloodWars * 100).toFixed(2) + "%" + ", skipped: " + (stats.skippedEncounters / (stats.skippedEncounters + stats.patrolEncounters) * 100).toFixed(2) + "%" + "\n"); LogResult(stats, "Patrol kills per gem: " + (stats.patrolKills / stats.patrolGems).toFixed(2) + diff --git a/js/worker.js b/js/worker.js index 09568f6..8132fcf 100644 --- a/js/worker.js +++ b/js/worker.js @@ -398,6 +398,9 @@ function BloodWar(params, sim, stats) { if (Rand(0, sim.threat) >= Rand(0, 999)) { /* Encounter */ stats.patrolEncounters++; + if (i + 1 == sim.patrols) { + stats.marginalEncounters++; + } let droid = false; if (droids > 0) { From 5a2f323bb42269ae91082371f0a5883b751c0a9e Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Wed, 4 Jun 2025 17:40:18 -0700 Subject: [PATCH 63/65] Re-add army rating rounding where appropriate (not forge) --- js/worker.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/js/worker.js b/js/worker.js index 8132fcf..f9fa054 100644 --- a/js/worker.js +++ b/js/worker.js @@ -93,8 +93,8 @@ function SimStart(id, simId, params, stats) { sim.maxHellSoldiers += forgeSoldiers; } /* Calculate patrol rating and training rate ahead of time for efficiency */ - sim.patrolRating = ArmyRating(params, false, params.patrolSize); - sim.patrolRatingDroids = ArmyRating(params, false, params.patrolSize + DroidSize(params)); + sim.patrolRating = Math.round(ArmyRating(params, false, params.patrolSize)); + sim.patrolRatingDroids = Math.round(ArmyRating(params, false, params.patrolSize + DroidSize(params))); sim.trainingRate = TrainingRate(params); LogResult(stats, " -- Sim " + sim.simId.toString().padStart(Math.floor(Math.log10(params.sims)) + 1, 0) + " --\n"); @@ -123,8 +123,8 @@ function ProvideInfo (params) { var forgeSoldiers; fortressRating = FortressRating(params, false); - patrolRating = ArmyRating(params, false, params.patrolSize); - patrolRatingDroids = ArmyRating(params, false, params.patrolSize + DroidSize(params)); + patrolRating = Math.round(ArmyRating(params, false, params.patrolSize)); + patrolRatingDroids = Math.round(ArmyRating(params, false, params.patrolSize + DroidSize(params))); tickLength = TickLength(params); trainingRate = TrainingRate(params); forgeSoldiers = ForgeSoldiers(params); @@ -371,8 +371,8 @@ function BloodWar(params, sim, stats) { let needPity = true; /* Update patrol rating if cautious/tusked, for random weather */ if (params.cautious || params.tusk) { - sim.patrolRating = ArmyRating(params, sim, params.patrolSize); - sim.patrolRatingDroids = ArmyRating(params, sim, params.patrolSize + DroidSize(params)); + sim.patrolRating = Math.round(ArmyRating(params, sim, params.patrolSize)); + sim.patrolRatingDroids = Math.round(ArmyRating(params, sim, params.patrolSize + DroidSize(params))); } let patrolWounds = 0; let extraWounds = 0; @@ -421,7 +421,7 @@ function BloodWar(params, sim, stats) { if (droid) { patrolSize += DroidSize(params); } - patrolRating = ArmyRating(params, sim, patrolSize, wounded); + patrolRating = Math.round(ArmyRating(params, sim, patrolSize, wounded)); } let minDemons = Math.floor(sim.threat / 50); @@ -1487,7 +1487,7 @@ function FortressRating(params, sim) { break; } - return ArmyRating(params, sim, defenders, wounded) + params.turrets * turretRating; + return Math.round(ArmyRating(params, sim, defenders, wounded)) + params.turrets * turretRating; } function ForgeSoldiers(params) { From cb6bd6dffd543922649246c8e03f40c3e7ade363 Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Wed, 4 Jun 2025 17:49:14 -0700 Subject: [PATCH 64/65] Update version text --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index acac6f4..86538e9 100644 --- a/index.html +++ b/index.html @@ -20,7 +20,7 @@

Evolve Hell Simulator

-
By jotun (aka Zarakon) and Beorseder
Based on Evolve by Demagorddon v1.3.5b
+
By jotun (aka Zarakon), Mary, and Beorseder
Based on Evolve by Demagorddon v1.4.8
From f32f3749a46207f7b3a2a7534033f05cd567884f Mon Sep 17 00:00:00 2001 From: maryrivlet <107000523+maryrivlet@users.noreply.github.com> Date: Wed, 4 Jun 2025 17:51:18 -0700 Subject: [PATCH 65/65] Fix Soul Bait save parsing --- js/hellsim.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/hellsim.js b/js/hellsim.js index 9bb7803..84d55ff 100644 --- a/js/hellsim.js +++ b/js/hellsim.js @@ -1020,7 +1020,7 @@ function ConvertSave(save) { $('#soulForge')[0].value = 0; } - $('#soul_bait')[0].checked = save.tech['hell_pit'] && save.tech.hell_pit >= 6 ? true : false; + $('#soul_bait')[0].checked = save.tech['hell_pit'] && save.tech.hell_pit >= 8 ? true : false; /* "Soul Power" enables the tech 5 event which is random, just assume it will happen */ $('#asphodel_hostility')[0].checked = save.tech['asphodel'] && save.tech.asphodel >= 4 ? true : false; $('#asphodel_mech_security')[0].checked = save.tech['asphodel'] && save.tech.asphodel >= 6 ? true : false;