From 4ffbbc99ea4e144bc575e7e435bc4553437428ea Mon Sep 17 00:00:00 2001 From: krypek Date: Sat, 24 Aug 2024 15:16:00 +0200 Subject: [PATCH] Add door destination replacing for puzzle rooms --- pnpm-lock.yaml | 8 +-- src/dungeon/builder.ts | 9 ++- src/map-arrange/map-arrange.ts | 2 + src/map-construct/map-construct.ts | 4 ++ src/maps/dng-puzzle-tunnel.ts | 104 ++++++++++++++++++++++++++--- src/maps/puzzle-data.ts | 3 +- src/maps/simple.ts | 3 +- src/util/vec2.ts | 2 - 8 files changed, 114 insertions(+), 21 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 575e82c..db0c37d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -55,7 +55,7 @@ importers: version: 5.5.4 ultimate-crosscode-typedefs: specifier: github:krypciak/ultimate-crosscode-typedefs - version: https://codeload.github.com/krypciak/ultimate-crosscode-typedefs/tar.gz/845803b1ce6e9369dec2a2a58dff031a1fcb6843 + version: https://codeload.github.com/krypciak/ultimate-crosscode-typedefs/tar.gz/19a95a62bda5b310c911772e4d2c0010646a21ef packages: @@ -884,8 +884,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - ultimate-crosscode-typedefs@https://codeload.github.com/krypciak/ultimate-crosscode-typedefs/tar.gz/845803b1ce6e9369dec2a2a58dff031a1fcb6843: - resolution: {tarball: https://codeload.github.com/krypciak/ultimate-crosscode-typedefs/tar.gz/845803b1ce6e9369dec2a2a58dff031a1fcb6843} + ultimate-crosscode-typedefs@https://codeload.github.com/krypciak/ultimate-crosscode-typedefs/tar.gz/19a95a62bda5b310c911772e4d2c0010646a21ef: + resolution: {tarball: https://codeload.github.com/krypciak/ultimate-crosscode-typedefs/tar.gz/19a95a62bda5b310c911772e4d2c0010646a21ef} version: 0.0.1 engines: {node: '>=10.0.0'} @@ -1696,7 +1696,7 @@ snapshots: typescript@5.5.4: {} - ultimate-crosscode-typedefs@https://codeload.github.com/krypciak/ultimate-crosscode-typedefs/tar.gz/845803b1ce6e9369dec2a2a58dff031a1fcb6843: + ultimate-crosscode-typedefs@https://codeload.github.com/krypciak/ultimate-crosscode-typedefs/tar.gz/19a95a62bda5b310c911772e4d2c0010646a21ef: dependencies: '@types/jquery': 1.10.45 '@types/node': 11.15.54 diff --git a/src/dungeon/builder.ts b/src/dungeon/builder.ts index 400333c..50bb391 100644 --- a/src/dungeon/builder.ts +++ b/src/dungeon/builder.ts @@ -5,6 +5,7 @@ import { MapArrange, MapArrangeData } from '../map-arrange/map-arrange' import { MapPicker, mapPickerConfigurable } from '../map-arrange/map-picker/configurable' import { AreaInfo, constructMapsFromMapsArrange } from '../map-construct/map-construct' import { initAllPuzzles } from '../maps/puzzle-data' +import { Dir } from '../util/geometry' import { Item } from '../util/items' import { setRandomSeed } from '../util/util' import { DungeonPaths } from './paths' @@ -57,13 +58,20 @@ export class DungeonBuilder { } const mapPicker: MapPicker = mapPickerConfigurable({ + startDir: Dir.WEST, root: { type: 'DngPuzzleTunnel', tunnelSize: tunnelSizeReg, // size: roomSizeReg, count: 5, randomizeDirTryOrder, + // forcePuzzleMap: 'rhombus-dng/room-1', + followedBy: { + type: 'Simple', + size: roomSizeReg, + count: 1, + }, // followedBy: branch( // 1, // () => 1, @@ -108,6 +116,5 @@ export class DungeonBuilder { mapsConstruct[0].constructed.name, ig.TeleportPosition.createFromJson({ marker: 'entrance_0', level: 0, baseZPos: 0, size: { x: 0, y: 0 } }) ) - console.dir(mapsConstruct, { depth: null }) } } diff --git a/src/map-arrange/map-arrange.ts b/src/map-arrange/map-arrange.ts index 959a415..2882bf6 100644 --- a/src/map-arrange/map-arrange.ts +++ b/src/map-arrange/map-arrange.ts @@ -5,10 +5,12 @@ import { Vec2 } from '../util/vec2' import { MapPicker } from './map-picker/configurable' export interface TprArrange3d extends Vec2 { + level?: number dir: Dir3d destId: Id destIndex?: number noDrawConnection?: boolean + dontPlace?: boolean } export interface TprArrange extends TprArrange3d { dir: Dir diff --git a/src/map-construct/map-construct.ts b/src/map-construct/map-construct.ts index dc3f971..eb34f22 100644 --- a/src/map-construct/map-construct.ts +++ b/src/map-construct/map-construct.ts @@ -11,6 +11,10 @@ import { MapTheme } from './theme' export type TprDoorLikeType = 'Door' | 'TeleportGround' export type TprType = TprDoorLikeType | 'TeleportField' +export function isEntityATpr(e: sc.MapModel.MapEntity): e is sc.MapModel.MapEntity { + return e.type == 'Door' || e.type == 'TeleportGround' || e.type == 'TeleportField' +} + export interface MapConstruct extends MapArrange { arrangeCopy: MapArrange constructed: sc.MapModel.Map diff --git a/src/maps/dng-puzzle-tunnel.ts b/src/maps/dng-puzzle-tunnel.ts index d143e03..fce01a0 100644 --- a/src/maps/dng-puzzle-tunnel.ts +++ b/src/maps/dng-puzzle-tunnel.ts @@ -9,11 +9,18 @@ import { RoomPlaceOrder, } from '../map-arrange/map-arrange' import { MapPicker, registerMapPickerNodeConfig } from '../map-arrange/map-picker/configurable' -import { AreaInfo, MapConstruct, registerMapConstructor } from '../map-construct/map-construct' +import { + AreaInfo, + getTprName, + isEntityATpr, + MapConstruct, + registerMapConstructor, + TprType, +} from '../map-construct/map-construct' import { Dir, DirU, Rect } from '../util/geometry' import { assert, shuffleArray } from '../util/util' import { Vec2 } from '../util/vec2' -import { getPuzzleList } from './puzzle-data' +import { getPuzzleList, PuzzleData } from './puzzle-data' import { simpleMapConstructor } from './simple' declare global { @@ -26,6 +33,7 @@ declare global { tunnelSize: Vec2 randomizeDirTryOrder?: boolean followedBy?: MapPicker.ConfigNode + forcePuzzleMap?: string } } } @@ -42,6 +50,7 @@ export function das({ branchDone, nodeId, nodeProgress, + forcePuzzleMap, }: { mapPicker: MapPicker exitTpr: TprArrange @@ -52,6 +61,7 @@ export function das({ branchDone?: boolean nodeId?: number nodeProgress?: number + forcePuzzleMap?: string }): NextQueueEntryGenerator { return (id, _, accesor) => { const tpr: TprArrange = { @@ -82,7 +92,9 @@ export function das({ } if (!doesMapArrangeFit(accesor, map, id)) return null - const puzzles = shuffleArray(getPuzzleList(tpr.dir)) + let puzzles = shuffleArray(getPuzzleList(tpr.dir)) + if (forcePuzzleMap) puzzles = puzzles.filter(p => p.map == forcePuzzleMap) + // printMapArrangeQueue(accesor, 16, true, [], false, true) return { data: map, @@ -131,7 +143,7 @@ export function das({ const room: RoomArrange = { ...rect, walls: [true, true, true, true], - dontPlace: true + dontPlace: true, } map.rects.push(room) @@ -173,12 +185,28 @@ registerMapConstructor( mapsArranged: MapArrange[], mapsConstructed: MapConstruct[] ) => { - const res = simpleMapConstructor(map, areaInfo, pathResolver, mapsArranged, mapsConstructed, [8, 1, 1, 1]) - const puzzle = res.placeData!.puzzle! - + const puzzle = map.placeData!.puzzle! const puzzleMapRaw: string = blitzkrieg.mapUtil.cachedMaps[puzzle.map] assert(puzzleMapRaw) const puzzleMap: sc.MapModel.Map = JSON.parse(blitzkrieg.mapUtil.cachedMaps[puzzle.map]) + + const exitTpr = removeUnwantedTprsFromMap(puzzleMap, puzzle.exitTpr) + removeCutscenesFromMap(puzzleMap) + + if (exitTpr) { + const destId = map.id + 1 + const prevExitTprIndex = map.restTprs.findIndex(tpr => tpr.destId == destId) + assert(prevExitTprIndex != -1) + const prevExitTpr = map.restTprs[prevExitTprIndex] + prevExitTpr.dontPlace = true + + exitTpr.settings.name = getTprName(false, prevExitTprIndex) + exitTpr.settings.map = pathResolver(destId) + exitTpr.settings.marker = getTprName(true, prevExitTpr.destIndex ?? 0) + } + + const res = simpleMapConstructor(map, areaInfo, pathResolver, mapsArranged, mapsConstructed, [8, 1, 1, 1]) + const pastePos = Vec2.add(Vec2.divC(Vec2.copy(res.rects[0]), 16), { x: puzzle.pasteOffset, y: puzzle.pasteOffset, @@ -192,13 +220,67 @@ registerMapConstructor( { disableEntities: false, mergeLayers: false, - removeCutscenes: true, - // makePuzzlesUnique: true, - // uniqueId: puzzle.usel.id, - // uniqueSel: puzzle.usel.sel, } ) + res.constructed = out return res } ) + +function removeUnwantedTprsFromMap( + map: sc.MapModel.Map, + keep: PuzzleData.Tpr | undefined +): sc.MapModel.MapEntity | undefined { + let foundToKeep: sc.MapModel.MapEntity | undefined + map.entities = map.entities.filter(e => { + if (!isEntityATpr(e)) return true + if (!keep) return false + if (!(e.x == keep.x && e.y == keep.y && e.level == keep.level && e.type == keep.type)) return false + assert(!foundToKeep) + foundToKeep = e + return true + }) + if (keep) assert(foundToKeep) + return foundToKeep +} + +const cutsceneEventTypes = new Set([ + 'ADD_MSG_PERSON', + 'CLEAR_MSG', + 'SHOW_MSG', + 'SHOW_SIDE_MSG', + 'SET_MSG_EXPRESSION', + 'SET_TASK', + 'SET_ENTITY_ON_TOP_OTHER', + 'SET_CAMERA_TARGET', + 'SET_CAMERA_POS', + 'WAIT_UNTIL_ACTION_DONE', + 'CLEAR_TASK', +]) +const cutsceneActionTypes = new Set(['ENTER_DOOR', 'MOVE_TO_POINT', 'NAVIGATE_TO_POINT', 'SET_FACE_TO_ENTITY']) +function removeCutscenesFromMap(map: sc.MapModel.Map) { + for (let enI = map.entities.length - 1; enI >= 0; enI--) { + const entity = map.entities[enI] + + if (entity.type == 'NPC') { + map.entities.splice(enI, 1) + } else if (entity.type == 'EventTrigger') { + const events = entity.settings.event ?? [] + for (let evI = events.length - 1; evI >= 0; evI--) { + const event = events[evI] + + if (cutsceneEventTypes.has(event.type)) { + events.splice(evI) + } else if (event.type == 'DO_ACTION') { + for (let acI = event.action.length - 1; acI >= 0; acI--) { + const action = event.action[acI] + if (cutsceneActionTypes.has(action.type)) { + event.action.splice(acI, 1) + } + } + } + } + } + } +} diff --git a/src/maps/puzzle-data.ts b/src/maps/puzzle-data.ts index e06e2e2..d67d5ef 100644 --- a/src/maps/puzzle-data.ts +++ b/src/maps/puzzle-data.ts @@ -65,11 +65,10 @@ function createPuzzleData(map: string, sel: PuzzleSelection, mapData: sc.MapMode }, { dist: 100e3, entity: undefined } as { dist: number; entity: sc.MapModel.MapEntity | undefined } ) - if (dist < 200) break exitTprIf + if (dist > 200) break exitTprIf assert(entity) exitTpr = { ...entity } - Vec2.sub(exitTpr, selPos) } else assert(false) let completionCondition: { path: string; value: any } | undefined diff --git a/src/maps/simple.ts b/src/maps/simple.ts index 1b1c803..cb67c61 100644 --- a/src/maps/simple.ts +++ b/src/maps/simple.ts @@ -149,6 +149,7 @@ export const simpleMapConstructor = (( const mic = baseMapConstruct(map, pathResolver(map.id), areaInfo.id, theme, extension) function pushTprEntity(tpr: TprArrange3d, isEntrance: boolean, index: number) { + if (tpr.dontPlace) return const name = getTprName(isEntrance, index) const dir = DirU.flip(tpr.dir as Dir) if (tpr.destId == -1) { @@ -171,7 +172,7 @@ export const simpleMapConstructor = (( type: 'Door', x, y, - level: 0, + level: tpr.level ?? 0, settings: { name, map: pathResolver(tpr.destId), diff --git a/src/util/vec2.ts b/src/util/vec2.ts index 7269c8d..424b718 100644 --- a/src/util/vec2.ts +++ b/src/util/vec2.ts @@ -250,8 +250,6 @@ export namespace Vec2 { Vec2.copy(gridCorner), Vec2.mulC(Vec2.floor(Vec2.divC(Vec2.copy(gridCorner), interval)), interval) ) - assert(offset.x < interval) - assert(offset.y < interval) const div = Vec2.divC(Vec2.sub(Vec2.copy(toSnap), offset), interval)