Extract helpers for chain finish flow

This commit is contained in:
Daddy32
2025-12-15 21:15:23 +01:00
parent ec6ea8aa1d
commit 6410a98f5d

View File

@@ -435,93 +435,93 @@
updateHud(); updateHud();
}; };
const finishChain = (releasePoint) => { const updateLongestChain = (chainLength) => {
if (!chain.active || gameOver || isPaused) return; if (chainLength <= longestChainRecord) return;
if (chain.bodies.length >= config.minChain) { longestChainRecord = chainLength;
const chainLength = chain.bodies.length; saveLongestChain(currentScene.id, longestChainRecord);
if (chainLength > longestChainRecord) { console.log(
longestChainRecord = chainLength; "New longest chain record",
saveLongestChain(currentScene.id, longestChainRecord); chainLength,
console.log( "scene",
"New longest chain record", currentScene?.id,
chainLength, );
"scene", ui.showFloatingMessage(`New chain record: ${chainLength}`, {
currentScene?.id, durationMs: 3600,
); position: config.messages.position,
ui.showFloatingMessage(`New chain record: ${chainLength}`, { });
durationMs: 3600, };
position: config.messages.position,
}); const getChainScoreState = () => {
const baseGain = 10 * Math.pow(chain.bodies.length, 2);
const negativeColors = (
currentScene?.config?.negativeScoreColors || []
).map(normalizeColor);
const negativeProgressColors = (
currentScene?.config?.negativeProgressColors || []
).map(normalizeColor);
const normalizedColor = chain.color
? normalizeColor(chain.color || "")
: null;
const isNegative =
normalizedColor && negativeColors.includes(normalizedColor);
const isNegativeProgress =
normalizedColor && negativeProgressColors.includes(normalizedColor);
const gain = isNegative ? -baseGain : baseGain;
return { gain, isNegativeProgress };
};
const removeChainConstraints = () => {
chain.constraints.forEach((c) => World.remove(world, c));
};
const removeChainBodies = () => {
const blobIds = new Set();
chain.bodies.forEach((body) => {
if (body.plugin?.blobId) {
blobIds.add(body.plugin.blobId);
} else {
if (body.plugin?.color) {
const key = normalizeColor(body.plugin.color);
clearedByColor[key] = (clearedByColor[key] || 0) + 1;
}
spawnSystem.cleanupBall(body);
World.remove(world, body);
} }
const baseGain = 10 * Math.pow(chain.bodies.length, 2); });
const negativeColors = ( blobIds.forEach((id) => {
currentScene?.config?.negativeScoreColors || [] balls
).map(normalizeColor); .filter((b) => b.plugin?.blobId === id)
const negativeProgressColors = ( .forEach((b) => {
currentScene?.config?.negativeProgressColors || [] if (b.plugin?.color) {
).map(normalizeColor); const key = normalizeColor(b.plugin.color);
const isNegative =
chain.color &&
negativeColors.includes(normalizeColor(chain.color || ""));
const isNegativeProgress =
chain.color &&
negativeProgressColors.includes(normalizeColor(chain.color || ""));
const gain = isNegative ? -baseGain : baseGain;
score += gain;
clearedCount += chain.bodies.length;
if (score > highScore) {
highScore = score;
saveHighScore(currentScene.id, highScore);
}
ui.spawnScorePopup(releasePoint || chain.pointer, gain, chain.color);
chain.constraints.forEach((c) => World.remove(world, c));
const blobIds = new Set();
chain.bodies.forEach((body) => {
if (body.plugin?.blobId) {
blobIds.add(body.plugin.blobId);
} else {
if (body.plugin?.color) {
const key = normalizeColor(body.plugin.color);
clearedByColor[key] = (clearedByColor[key] || 0) + 1; clearedByColor[key] = (clearedByColor[key] || 0) + 1;
} }
spawnSystem.cleanupBall(body); });
World.remove(world, body); spawnSystem.removeBlob(id);
} });
}); for (let i = balls.length - 1; i >= 0; i -= 1) {
blobIds.forEach((id) => { if (
balls chain.bodies.includes(balls[i]) ||
.filter((b) => b.plugin?.blobId === id) (balls[i].plugin?.blobId && blobIds.has(balls[i].plugin?.blobId))
.forEach((b) => { ) {
if (b.plugin?.color) { balls.splice(i, 1);
const key = normalizeColor(b.plugin.color);
clearedByColor[key] = (clearedByColor[key] || 0) + 1;
}
});
spawnSystem.removeBlob(id);
});
// Remove cleared balls from tracking list.
for (let i = balls.length - 1; i >= 0; i -= 1) {
if (
chain.bodies.includes(balls[i]) ||
(balls[i].plugin?.blobId && blobIds.has(balls[i].plugin?.blobId))
) {
balls.splice(i, 1);
}
} }
if (isNegativeProgress) {
const winCond = currentScene?.config?.winCondition;
if (winCond?.type === "colorClear" && Array.isArray(winCond.targets)) {
winCond.targets.forEach((target) => {
const key = normalizeColor(target.color);
const current = clearedByColor[key] || 0;
clearedByColor[key] = Math.max(0, current - chain.bodies.length);
});
}
}
} else {
chain.constraints.forEach((c) => World.remove(world, c));
chain.bodies.forEach((b) => setHighlight(b, false));
} }
};
const applyNegativeProgressPenalty = (chainLength) => {
const winCond = currentScene?.config?.winCondition;
if (winCond?.type !== "colorClear" || !Array.isArray(winCond.targets)) {
return;
}
winCond.targets.forEach((target) => {
const key = normalizeColor(target.color);
const current = clearedByColor[key] || 0;
clearedByColor[key] = Math.max(0, current - chainLength);
});
};
const resetChainState = () => {
chain.active = false; chain.active = false;
chain.color = null; chain.color = null;
chain.bodies = []; chain.bodies = [];
@@ -531,6 +531,31 @@
checkWinCondition(); checkWinCondition();
}; };
const finishChain = (releasePoint) => {
if (!chain.active || gameOver || isPaused) return;
const chainLength = chain.bodies.length;
if (chainLength >= config.minChain) {
updateLongestChain(chainLength);
const { gain, isNegativeProgress } = getChainScoreState();
score += gain;
clearedCount += chainLength;
if (score > highScore) {
highScore = score;
saveHighScore(currentScene.id, highScore);
}
ui.spawnScorePopup(releasePoint || chain.pointer, gain, chain.color);
removeChainConstraints();
removeChainBodies();
if (isNegativeProgress) {
applyNegativeProgressPenalty(chainLength);
}
} else {
removeChainConstraints();
chain.bodies.forEach((b) => setHighlight(b, false));
}
resetChainState();
};
const updateHud = () => { const updateHud = () => {
ui.updateHud({ ui.updateHud({
spawnIntervalMs: config.spawnIntervalMs, spawnIntervalMs: config.spawnIntervalMs,