Skip to content

Commit 164af93

Browse files
committed
4.2.5
1 parent 755ce09 commit 164af93

21 files changed

Lines changed: 371 additions & 74 deletions

KTL/.cursorrules

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ You are assisting with a vanilla JavaScript idle game. Follow these strict archi
55
4. UI EVENTS: Click handlers and user interactions belong in `events.js`.
66
5. HELPERS: Use `helper.js` for formatting and generic functions instead of writing new ones.
77
6. HTML GENERATION: Menu UI generation happens dynamically in `menu.js`, `upgradeData.js` and `store.js`.
8-
7. SAVING: Any new global variable that tracks progress MUST be integrated into `saving.js`.
8+
7. SAVING: Any new global variable that tracks progress MUST be integrated into `saving.js`.
9+
10+
The game is deployed both as a playable web version on github, as well as an electron.js build for steam.

KTL/MECHANICS.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,19 @@ The game runs at 20 frames per second. **CRITICAL RULE: Game tick logic is stric
3333
* **NEVER** use `getElementById()` or modify the DOM directly inside game logic or tick calculations.
3434
* **Creation:** New HTML elements must use `queueCache("<newId>")`. The UI builder processes the cache and stores elements globally.
3535
* **Continuous Updates (Per Frame/Second):** Use `views.updateVal(id, newVal, type="textContent", sigFigs)`. This function references the cached element and validates if `newVal` is different from the current state before touching the DOM.
36-
* **Event-Triggered Updates (During Ticks):** If game logic needs to update the UI instantly, use `views.ScheduleUpdate(id, newVal, type="textContent", sigFigs)`. This queues the update to be popped and rendered safely on the next UI frame.
36+
* **Event-Triggered Updates (During Ticks):** If game logic needs to update the UI instantly, use `views.ScheduleUpdate(id, newVal, type="textContent", sigFigs)`. This queues the update to be popped and rendered safely on the next UI frame.
37+
38+
## 5. Debug Playbook (Next Time)
39+
Use runtime evidence first, then fix only what logs prove.
40+
* Start with 3-5 concrete hypotheses (listeners, loops, scheduler bursts, DOM growth, heap growth).
41+
* Add minimal instrumentation (entry counts, loop duration, burst size, memory/DOM samples), then reproduce.
42+
* Read logs and mark each hypothesis: confirmed, rejected, or inconclusive.
43+
* Remove speculative/rejected changes; keep only proven fixes.
44+
* For slowdown under high `bonusSpeed`, inspect `helpers/interval2.js` first:
45+
* Watch `totalTicksToRun` and loop duration.
46+
* If burst size grows and loop time spikes, cap simulation work per loop.
47+
* Scale bonus-time consumption to actual processed work (`processedRatio`) so capped loops stay consistent.
48+
49+
## 6. Electron / Steam Packaging
50+
This game is built with Electron.js for Steam distribution.
51+
* `main.js`, `preload.js`, and `package.json` are located one folder up from this `KTL` project folder.

KTL/actionData.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,14 +1160,7 @@ let actionData = {
11601160
visible: false, unlocked: false, purchased: true, hasUpstream: false, keepParentAutomation:true,
11611161
ignoreConsume:true,
11621162
onLevelCustom: function () {
1163-
if(data.actions.hearAboutTheLich.level <= 1) {
1164-
data.ancientCoinMultKTL = 1
1165-
} else {
1166-
data.ancientCoinMultKTL = Math.pow(1.5, (data.actions.hearAboutTheLich.level - 1));
1167-
}
1168-
data.ancientCoinMultKTL *= Math.pow(1.05, data.upgrades.extraAncientCoins.upgradePower);
1169-
data.ancientCoinMultKTL *= Math.pow(1.5, data.shopUpgrades.extraAncientCoins.upgradePower);
1170-
data.ancientCoinMultKTL *= (data.shopUpgrades.currencyGainPotion.upgradePower > 0 ? 2 : 1)
1163+
recalculateKTLCurrencyMultipliers();
11711164
},
11721165
updateMults: function () {
11731166
let actionObj = data.actions.hearAboutTheLich;

KTL/actionDataFunctions.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,27 @@ function giveResourceTo(actionObj, downstreamObj, amount) {
547547
if(actionObj.resource < 0) { //NaN protection
548548
actionObj.resource = 0;
549549
}
550+
if(Number.isNaN(actionObj.progress)) {
551+
actionObj.progress = 0;
552+
}
553+
if(Number.isNaN(actionObj.progressGain)) {
554+
actionObj.progressGain = 0;
555+
}
556+
if(Number.isNaN(actionObj.resource)) {
557+
actionObj.resource = 0;
558+
}
559+
if(Number.isNaN(actionObj.resourceDecrease)) {
560+
actionObj.resourceDecrease = 0;
561+
}
562+
if(Number.isNaN(actionObj.resourceDelta)) {
563+
actionObj.resourceDelta = 0;
564+
}
565+
if(Number.isNaN(actionObj.resourceIncrease)) {
566+
actionObj.resourceIncrease = 0;
567+
}
568+
if(Number.isNaN(actionObj.totalSend)) {
569+
actionObj.totalSend = 0;
570+
}
550571
}
551572

552573
function addResourceTo(downstreamObj, amount) {

KTL/collectData.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ function hoverLog() {
220220
openLogButton.innerHTML = `Open Log`
221221
}
222222

223+
//run on prestige
223224
function clearLog() {
224225
const logMessages = document.getElementById('logMessages');
225226
logMessages.replaceChildren();
@@ -228,8 +229,9 @@ function clearLog() {
228229
openLogButton.innerHTML = `Open Log`
229230
}
230231

232+
//run once, on load
231233
function rebuildLog() {
232-
clearLog();
234+
// clearLog();
233235
const logContainer = document.getElementById('logContainer');
234236
const logMessages = document.getElementById('logMessages');
235237
for (let message of data.currentLog) {

KTL/data/globalsAndInitial.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ let mySecret = "test"
6565
data.gameSettings = {
6666
gameSpeed: 1,
6767
bonusSpeed: 1,
68+
webZoomFactor: 1,
6869
stop: false,
6970
stopAll: false,
7071
fps: 20,

KTL/driver.js

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
2-
function startGame() {
2+
async function startGame() {
33
// load calls recalcInterval, which will start the callbacks
4-
load();
4+
await load();
55
setScreenSize();
66
setTimeout(initTimingSystem, 200);
77
}
@@ -19,6 +19,7 @@ function checkOfflineProgress() {
1919
console.log(`Welcome back! Gained ${(offlineMilliseconds / 1000).toFixed(1)}s of bonus time.`);
2020
data.currentGameState.instantTimerCooldown -= offlineMilliseconds / 1000;
2121
data.currentGameState.dailyTimer -= offlineMilliseconds;
22+
checkDailyTimer();
2223
}
2324
}
2425
}
@@ -212,23 +213,25 @@ function calcDeltas() {
212213
let actionObj = data.actions[actionVar];
213214
let dataObj = actionData[actionVar];
214215

215-
let totalDecrease = actionObj.totalSend || 0;
216+
let sendDecrease = actionObj.totalSend || 0;
217+
let consumeDecrease = 0;
216218

217219
if (!dataObj.isGenerator) {
218-
totalDecrease += actionObj.progressGain;
219-
} else {
220-
if (["makeMoney", "socialize"].includes(actionVar)) {
221-
totalDecrease += (actionObj.resource * calcTierMult(dataObj.tier)) * actionObj.progressGain / actionObj.progressMax;
222-
}
220+
consumeDecrease = actionObj.progressGain;
221+
} else if (["makeMoney", "socialize"].includes(actionVar)) {
222+
consumeDecrease = (actionObj.resource * calcTierMult(dataObj.tier)) * actionObj.progressGain / actionObj.progressMax;
223223
}
224-
if(dataObj.ignoreConsume) {
225-
totalDecrease = 0;
224+
225+
if (dataObj.ignoreConsume) {
226+
consumeDecrease = 0;
226227
}
227-
if(actionVar === "tidalBurden") {
228-
actionObj.resourceDecrease = totalDecrease
228+
229+
if (actionVar === "tidalBurden") {
230+
actionObj.resourceDecrease = sendDecrease + consumeDecrease;
229231
} else {
230232
let consumptionReduction = Math.max(0, 1 - (data.shopUpgrades.focusBarsImproveEfficiency.upgradePower * .25 * actionObj.connectedLines));
231-
actionObj.resourceDecrease = totalDecrease * (1-data.upgrades.reduceResourcesConsumed.upgradePower*.05) * consumptionReduction;
233+
let consumeMult = (1 - data.upgrades.reduceResourcesConsumed.upgradePower * .05) * consumptionReduction;
234+
actionObj.resourceDecrease = sendDecrease + (consumeDecrease * consumeMult);
232235
}
233236

234237
// Calculate the final net change per second for display.

KTL/events.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ function toggleAllHundred(actionVar) {
108108
});
109109
}
110110
window.addEventListener('resize', () => {
111+
updateZoomViewportVariables();
111112
resizeStatMenu();
112113
resizeCanvas();
113114
drawChart();
@@ -121,7 +122,7 @@ function resizeStatMenu() {
121122
}
122123

123124
if(view.cached[`attDisplay`]) {
124-
view.cached[`attDisplay`].style.maxHeight = window.innerHeight - reduction + "px";
125+
view.cached[`attDisplay`].style.maxHeight = getViewportHeight() - reduction + "px";
125126
}
126127
}
127128

KTL/helpers/interval2.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,11 @@ function loop() {
3737
const effectiveSpeed = data.gameSettings.gameSpeed * data.gameSettings.bonusSpeed;
3838
const upgradeMultiplier = 1 + (data.shopUpgrades.extraGameSpeed.upgradePower * 0.1);
3939
const exactTicks = (ticksProcessed * effectiveSpeed * upgradeMultiplier) + (tickResidue || 0);
40-
const totalTicksToRun = Math.floor(exactTicks);
41-
tickResidue = exactTicks - totalTicksToRun;
40+
const requestedTicksToRun = Math.floor(exactTicks);
41+
tickResidue = exactTicks - requestedTicksToRun;
42+
const maxSimTicksPerLoop = data.gameSettings.bonusSpeed >= 10 ? 40 : 120;
43+
const totalTicksToRun = Math.min(requestedTicksToRun, maxSimTicksPerLoop);
44+
const processedRatio = requestedTicksToRun > 0 ? (totalTicksToRun / requestedTicksToRun) : 1;
4245

4346
if (!data.gameSettings.stop) {
4447
for (let i = 0; i < totalTicksToRun; i++) {
@@ -51,7 +54,7 @@ function loop() {
5154
}
5255
if (data.gameSettings.bonusSpeed > 1) {
5356
const processedElapsed = ticksProcessed * tickInterval;
54-
const bonusTimeConsumed = processedElapsed * data.gameSettings.gameSpeed * (data.gameSettings.bonusSpeed - 1);
57+
const bonusTimeConsumed = processedElapsed * data.gameSettings.gameSpeed * (data.gameSettings.bonusSpeed - 1) * processedRatio;
5558
data.currentGameState.bonusTime -= bonusTimeConsumed;
5659
if (data.currentGameState.bonusTime <= 0) {
5760
data.currentGameState.bonusTime = 0;

KTL/index.html

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
<meta http-equiv="expires" content="0" />
99
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
1010
<meta http-equiv="pragma" content="no-cache" />
11-
<meta http-equiv="Content-Security-Policy" content="
12-
default-src 'self';
13-
script-src 'self' https://stopsign.github.io https://cdn.jsdelivr.net https://www.googletagmanager.com 'unsafe-inline';
14-
style-src 'self' 'unsafe-inline';
15-
connect-src 'self' https://steam-sc-proxy.jimkap09.workers.dev/ https://www.google-analytics.com https://cdn.jsdelivr.net;
16-
img-src 'self' data: https://www.google-analytics.com;
17-
">
11+
<!-- <meta http-equiv="Content-Security-Policy" content="-->
12+
<!-- default-src 'self';-->
13+
<!-- script-src 'self' https://stopsign.github.io https://cdn.jsdelivr.net https://www.googletagmanager.com 'unsafe-inline';-->
14+
<!-- style-src 'self' 'unsafe-inline';-->
15+
<!-- connect-src 'self' https://steam-sc-proxy.jimkap09.workers.dev/ https://www.google-analytics.com https://cdn.jsdelivr.net;-->
16+
<!-- img-src 'self' data: https://www.google-analytics.com;-->
17+
<!--">-->
1818
<meta name="viewport" content="width=device-width, initial-scale=.8">
1919

2020
<title>KTL</title>
@@ -120,7 +120,7 @@
120120
View Amulet Upgrades
121121
</span>
122122

123-
<span id="currentVersion" style="position:fixed;top:1px;right:5px;color:var(--text-muted)">v3.2.4</span>
123+
<span id="currentVersion" style="position:fixed;top:1px;right:5px;color:var(--text-muted)">v3.2.5</span>
124124

125125

126126
<div id="bonusDisplayShowButton" class="button" onclick="bonusMenuHideButton()"
@@ -322,7 +322,7 @@
322322

323323
<div class="menuSeparator"></div>
324324

325-
<div style="display:flex;height:calc(80vh - 100px);min-height:200px;position:relative;overflow:hidden;font-size:0;">
325+
<div style="display:flex;height:calc(var(--app-vh, 1vh) * 80 - 100px);min-height:200px;position:relative;overflow:hidden;font-size:0;">
326326
<div class="menuOptionContainer">
327327
<div id="uniqueUpgradeTab" onclick="clickUpgradeTab('unique')" class="menuTab">
328328
Unique Upgrades (AC)
@@ -493,11 +493,18 @@
493493
<!--<script src="steamStuff.js"></script>-->
494494
<!--<script src="steamSecrets.js"></script>-->
495495
<!--<script src="soulCoinsSecrets.js"></script>-->
496-
<script async src="https://www.googletagmanager.com/gtag/js?id=G-E10C6H16MH"></script><script>
497-
window.dataLayer = window.dataLayer || [];
498-
function gtag(){dataLayer.push(arguments);}
499-
gtag('js', new Date());
500-
gtag('config', 'G-E10C6H16MH');
496+
<script>
497+
if (!isSteam) {
498+
const gaScript = document.createElement('script');
499+
gaScript.async = true;
500+
gaScript.src = 'https://www.googletagmanager.com/gtag/js?id=G-E10C6H16MH';
501+
document.head.appendChild(gaScript);
502+
503+
window.dataLayer = window.dataLayer || [];
504+
function gtag(){dataLayer.push(arguments);}
505+
gtag('js', new Date());
506+
gtag('config', 'G-E10C6H16MH');
507+
}
501508
</script>
502509
<script>
503510
startGame();

0 commit comments

Comments
 (0)