breakout71/src/newGameState.ts
2025-03-23 17:52:25 +01:00

118 lines
3.1 KiB
TypeScript

import { GameState, RunParams } from "./types";
import { getTotalScore } from "./settings";
import { allLevels, upgrades } from "./loadGameData";
import {
defaultSounds,
getPossibleUpgrades,
makeEmptyPerksMap,
sumOfKeys,
} from "./game_utils";
import { dontOfferTooSoon, resetBalls } from "./gameStateMutators";
import { isOptionOn } from "./options";
export function newGameState(params: RunParams): GameState {
const totalScoreAtRunStart = getTotalScore();
const firstLevel = params?.level
? allLevels.filter((l) => l.name === params?.level)
: [];
const restInRandomOrder = allLevels
.filter((l) => totalScoreAtRunStart >= l.threshold)
.filter((l) => l.name !== params?.level)
.filter((l) => l.name !== params?.levelToAvoid)
.sort(() => Math.random() - 0.5);
const runLevels = firstLevel.concat(
restInRandomOrder.slice(0, 7 + 3).sort((a, b) => a.sortKey - b.sortKey),
);
const perks = { ...makeEmptyPerksMap(upgrades), ...(params?.perks || {}) };
const gameState: GameState = {
runLevels,
currentLevel: 0,
upgradesOfferedFor: -1,
perks,
puckWidth: 200,
baseSpeed: 12,
combo: 1,
gridSize: 12,
running: false,
isGameOver: false,
ballStickToPuck: true,
puckPosition: 400,
pauseTimeout: null,
canvasWidth: 0,
canvasHeight: 0,
offsetX: 0,
offsetXRoundedDown: 0,
gameZoneWidth: 0,
gameZoneWidthRoundedUp: 0,
gameZoneHeight: 0,
brickWidth: 0,
score: 0,
lastScoreIncrease: -1000,
lastExplosion: -1000,
highScore: parseFloat(localStorage.getItem("breakout-3-hs") || "0"),
balls: [],
ballsColor: "white",
bricks: [],
brickHP: [],
lights: { indexMin: 0, total: 0, list: [] },
particles: { indexMin: 0, total: 0, list: [] },
texts: { indexMin: 0, total: 0, list: [] },
coins: { indexMin: 0, total: 0, list: [] },
levelStartScore: 0,
levelMisses: 0,
levelSpawnedCoins: 0,
lastPlayedCoinGrab: 0,
puckColor: "#FFF",
ballSize: 20,
coinSize: 14,
puckHeight: 20,
totalScoreAtRunStart,
isCreativeModeRun: sumOfKeys(perks) > 1,
pauseUsesDuringRun: 0,
keyboardPuckSpeed: 0,
lastTick: performance.now(),
lastTickDown: 0,
runStatistics: {
started: Date.now(),
levelsPlayed: 0,
runTime: 0,
coins_spawned: 0,
score: 0,
bricks_broken: 0,
misses: 0,
balls_lost: 0,
puck_bounces: 0,
wall_bounces: 0,
upgrades_picked: 1,
max_combo: 1,
max_level: 0,
},
lastOffered: {},
levelTime: 0,
winAt: 0,
levelWallBounces: 0,
needsRender: true,
autoCleanUses: 0,
...defaultSounds(),
};
resetBalls(gameState);
if (!sumOfKeys(gameState.perks)) {
const giftable = getPossibleUpgrades(gameState).filter((u) => u.giftable);
const randomGift =
(isOptionOn("easy") && "slow_down") ||
giftable[Math.floor(Math.random() * giftable.length)].id;
perks[randomGift] = 1;
dontOfferTooSoon(gameState, randomGift);
}
for (let perk of upgrades) {
if (gameState.perks[perk.id]) {
dontOfferTooSoon(gameState, perk.id);
}
}
return gameState;
}