feat: add gift zone city team and mashup mode
This commit is contained in:
@@ -105,6 +105,38 @@ function placePieces(piecePool, levelPreset, rng) {
|
||||
return placedPieces
|
||||
}
|
||||
|
||||
export function generateBoardFromDefinition({
|
||||
boardId,
|
||||
cityId,
|
||||
levelId,
|
||||
seed,
|
||||
elements,
|
||||
levelPreset,
|
||||
extraState = {},
|
||||
}) {
|
||||
const effectiveSeed = seed ?? levelPreset.seedBase
|
||||
const rng = createRng(effectiveSeed)
|
||||
const selectedElements = [...elements]
|
||||
const counts = normalizePiecesPerElement(levelPreset.piecesPerElement, levelPreset.elementCount)
|
||||
const piecePool = createPiecePool(selectedElements, counts)
|
||||
const pieces = placePieces(shuffleWithRng(piecePool, rng), levelPreset, rng)
|
||||
const overlapGraph = buildOverlapGraph(pieces)
|
||||
const boardState = {
|
||||
boardId: boardId ?? `${cityId}-${levelId}-${effectiveSeed}`,
|
||||
cityId,
|
||||
levelId,
|
||||
seed: effectiveSeed,
|
||||
pieces,
|
||||
overlapGraph,
|
||||
metrics: {},
|
||||
...extraState,
|
||||
}
|
||||
|
||||
boardState.metrics = evaluateBoard(boardState, levelPreset)
|
||||
|
||||
return boardState
|
||||
}
|
||||
|
||||
export function generateBoard({ cityId, levelId, seed, contentSystem }) {
|
||||
const city = contentSystem.getCity(cityId)
|
||||
const levelPreset = contentSystem.getLevelPreset(cityId, levelId)
|
||||
@@ -116,23 +148,14 @@ export function generateBoard({ cityId, levelId, seed, contentSystem }) {
|
||||
const effectiveSeed = seed ?? levelPreset.seedBase
|
||||
const rng = createRng(effectiveSeed)
|
||||
const selectedElements = pickElements(city, levelPreset, rng)
|
||||
const counts = normalizePiecesPerElement(levelPreset.piecesPerElement, levelPreset.elementCount)
|
||||
const piecePool = createPiecePool(selectedElements, counts)
|
||||
const pieces = placePieces(shuffleWithRng(piecePool, rng), levelPreset, rng)
|
||||
const overlapGraph = buildOverlapGraph(pieces)
|
||||
const boardState = {
|
||||
boardId: `${cityId}-${levelId}-${effectiveSeed}`,
|
||||
|
||||
return generateBoardFromDefinition({
|
||||
cityId,
|
||||
levelId,
|
||||
seed: effectiveSeed,
|
||||
pieces,
|
||||
overlapGraph,
|
||||
metrics: {},
|
||||
}
|
||||
|
||||
boardState.metrics = evaluateBoard(boardState, levelPreset)
|
||||
|
||||
return boardState
|
||||
elements: selectedElements,
|
||||
levelPreset,
|
||||
})
|
||||
}
|
||||
|
||||
export default generateBoard
|
||||
|
||||
99
js/gameplay/difficulty/generate-mashup-board.js
Normal file
99
js/gameplay/difficulty/generate-mashup-board.js
Normal file
@@ -0,0 +1,99 @@
|
||||
import { generateBoardFromDefinition } from './generate-board.js'
|
||||
import { createRng, shuffleWithRng } from './random.js'
|
||||
|
||||
function createMashupLevelPreset(elementCount) {
|
||||
return {
|
||||
id: 1,
|
||||
seedBase: 31001,
|
||||
elementCount,
|
||||
piecesPerElement: Array.from({ length: elementCount }, () => 3),
|
||||
layers: 4,
|
||||
density: 'medium_high',
|
||||
}
|
||||
}
|
||||
|
||||
function getSourceCities(cityIds, contentSystem) {
|
||||
return cityIds
|
||||
.map((cityId) => contentSystem.getCity(cityId))
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
function createCityElementPools(cities, rng) {
|
||||
return cities.map((city) => ({
|
||||
cityId: city.id,
|
||||
cursor: 0,
|
||||
elements: shuffleWithRng(
|
||||
city.elements.map((element) => ({
|
||||
...element,
|
||||
sourceCityId: city.id,
|
||||
sourceCityName: city.display.name,
|
||||
})),
|
||||
rng,
|
||||
),
|
||||
}))
|
||||
}
|
||||
|
||||
function pickMashupElements(cities, targetCount, rng) {
|
||||
const pools = createCityElementPools(cities, rng)
|
||||
const selected = []
|
||||
|
||||
while (selected.length < targetCount) {
|
||||
let didAdd = false
|
||||
|
||||
for (const pool of pools) {
|
||||
const element = pool.elements[pool.cursor]
|
||||
if (!element) {
|
||||
continue
|
||||
}
|
||||
|
||||
selected.push(element)
|
||||
pool.cursor += 1
|
||||
didAdd = true
|
||||
|
||||
if (selected.length === targetCount) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!didAdd) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return selected
|
||||
}
|
||||
|
||||
export function generateMashupBoard({ cityIds, seed, contentSystem }) {
|
||||
const cities = getSourceCities(cityIds, contentSystem)
|
||||
|
||||
if (cities.length === 0) {
|
||||
throw new Error('Mashup mode requires at least one source city')
|
||||
}
|
||||
|
||||
const effectiveSeed = seed ?? 31001
|
||||
const rng = createRng(effectiveSeed)
|
||||
const maxElementCount = cities.reduce((sum, city) => sum + city.elements.length, 0)
|
||||
const elementCount = Math.min(8, maxElementCount)
|
||||
const levelPreset = createMashupLevelPreset(elementCount)
|
||||
const selectedElements = pickMashupElements(cities, elementCount, rng)
|
||||
|
||||
return generateBoardFromDefinition({
|
||||
boardId: `mashup-${effectiveSeed}`,
|
||||
cityId: 'mashup',
|
||||
levelId: 1,
|
||||
seed: effectiveSeed,
|
||||
elements: selectedElements,
|
||||
levelPreset,
|
||||
extraState: {
|
||||
sourceCityIds: cities.map((city) => city.id),
|
||||
elementDefinitions: selectedElements.map((element) => ({
|
||||
elementId: element.id,
|
||||
name: element.name,
|
||||
sourceCityId: element.sourceCityId,
|
||||
sourceCityName: element.sourceCityName,
|
||||
})),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export default generateMashupBoard
|
||||
@@ -1,6 +1,7 @@
|
||||
export { classifyDeadlock } from './classify-deadlock.js'
|
||||
export { evaluateBoard } from './evaluate-board.js'
|
||||
export { generateBoard } from './generate-board.js'
|
||||
export { generateMashupBoard } from './generate-mashup-board.js'
|
||||
export {
|
||||
buildOverlapGraph,
|
||||
getClickablePieces,
|
||||
|
||||
Reference in New Issue
Block a user