@auraindustry/aurajs 0.1.1 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/benchmarks/perf-thresholds.json +27 -0
- package/package.json +6 -1
- package/src/ai-guidance.mjs +302 -0
- package/src/asset-pack.mjs +2 -1
- package/src/authored-project.mjs +498 -2
- package/src/authored-runtime.mjs +14 -0
- package/src/bin-integrity.mjs +33 -26
- package/src/build-contract/capabilities.mjs +87 -1
- package/src/build-contract/constants.mjs +1 -0
- package/src/build-contract.mjs +2 -0
- package/src/bundler.mjs +143 -13
- package/src/cli.mjs +681 -13
- package/src/commands/packs.mjs +741 -0
- package/src/commands/project-authoring.mjs +128 -1
- package/src/conformance/cases/app-and-ui-runtime-cases.mjs +1 -2
- package/src/conformance/cases/core-runtime-cases.mjs +6 -2
- package/src/conformance/cases/scene3d-and-media-cases.mjs +238 -0
- package/src/conformance/cases/systems-and-gameplay-cases.mjs +1126 -10
- package/src/conformance-mobile.mjs +166 -0
- package/src/conformance.mjs +89 -30
- package/src/evidence-bundle.mjs +242 -0
- package/src/external-package-surface.mjs +1 -1
- package/src/headless-test/runtime-coordinator.mjs +186 -33
- package/src/headless-test.mjs +2 -0
- package/src/helpers/2d/index.mjs +183 -0
- package/src/helpers/index.mjs +26 -0
- package/src/helpers/starter-utils/adventure-objectives.js +102 -0
- package/src/helpers/starter-utils/adventure-world-2d.js +221 -0
- package/src/helpers/starter-utils/animation-2d.js +337 -0
- package/src/helpers/starter-utils/animation-packaging-2d.js +203 -0
- package/src/helpers/starter-utils/atlas-assets-2d.js +111 -0
- package/src/helpers/starter-utils/autoplay-debug-2d.js +215 -0
- package/src/helpers/starter-utils/avatar-3d.js +404 -0
- package/src/helpers/starter-utils/combat-feedback-2d.js +320 -0
- package/src/helpers/starter-utils/combat-runtime-2d.js +290 -0
- package/src/helpers/starter-utils/core.js +150 -0
- package/src/helpers/starter-utils/dialogue-2d.js +351 -0
- package/src/helpers/starter-utils/enemy-archetypes-2d.js +68 -0
- package/src/helpers/starter-utils/index.js +26 -0
- package/src/helpers/starter-utils/inventory-2d.js +268 -0
- package/src/helpers/starter-utils/journal-2d.js +267 -0
- package/src/helpers/starter-utils/platformer-3d.js +132 -0
- package/src/helpers/starter-utils/scene-audio-2d.js +236 -0
- package/src/helpers/starter-utils/streamed-world-2d.js +378 -0
- package/src/helpers/starter-utils/tilemap-nav-2d.js +499 -0
- package/src/helpers/starter-utils/tilemap-world-2d.js +205 -0
- package/src/helpers/starter-utils/triggers.js +662 -0
- package/src/helpers/starter-utils/tween-2d.js +615 -0
- package/src/helpers/starter-utils/wave-director.js +101 -0
- package/src/helpers/starter-utils/world-compositor-2d.js +253 -0
- package/src/helpers/starter-utils/world-persistence-2d.js +180 -0
- package/src/mobile/android/build.mjs +606 -0
- package/src/mobile/android/host-artifact.mjs +280 -0
- package/src/mobile/ios/build.mjs +1323 -0
- package/src/mobile/ios/host-artifact.mjs +819 -0
- package/src/mobile/shared/capabilities.mjs +174 -0
- package/src/package-integrity.mjs +18 -4
- package/src/packs/catalog.mjs +259 -0
- package/src/perf-benchmark-runner.mjs +17 -12
- package/src/perf-benchmark.mjs +408 -4
- package/src/publish-command.mjs +434 -17
- package/src/publish-validation.mjs +22 -11
- package/src/replay-runtime.mjs +257 -0
- package/src/scaffold/config.mjs +2 -0
- package/src/scaffold/fs.mjs +8 -1
- package/src/scaffold/project-docs.mjs +101 -41
- package/src/scaffold.mjs +4 -0
- package/src/session-runtime.mjs +4 -3
- package/src/web-conformance.mjs +0 -36
- package/templates/create/2d/src/runtime/app.js +4 -0
- package/templates/create/2d-adventure/config/gameplay/adventure.config.js +9 -6
- package/templates/create/2d-adventure/content/gameplay/dialogue.js +85 -0
- package/templates/create/2d-adventure/content/gameplay/world.js +32 -36
- package/templates/create/2d-adventure/content/gameplay/world.tilemap.json +273 -0
- package/templates/create/2d-adventure/docs/design/loop.md +4 -3
- package/templates/create/2d-adventure/prefabs/relic.prefab.js +10 -10
- package/templates/create/2d-adventure/prefabs/world.prefab.js +127 -74
- package/templates/create/2d-adventure/scenes/gameplay.scene.js +603 -112
- package/templates/create/2d-adventure/src/runtime/capabilities.js +16 -0
- package/templates/create/2d-adventure/ui/hud.screen.js +187 -4
- package/templates/create/2d-adventure/ui/journal.screen.js +183 -0
- package/templates/create/2d-survivor/src/runtime/app.js +4 -0
- package/templates/create/3d/scenes/gameplay.scene.js +30 -3
- package/templates/create/3d/src/runtime/app.js +4 -0
- package/templates/create/3d/src/runtime/capabilities.js +5 -0
- package/templates/create/3d/src/runtime/materials.js +10 -0
- package/templates/create/3d-adventure/scenes/gameplay.scene.js +30 -3
- package/templates/create/3d-adventure/src/runtime/capabilities.js +5 -0
- package/templates/create/3d-adventure/src/runtime/materials.js +11 -0
- package/templates/create/3d-collectathon/scenes/gameplay.scene.js +30 -3
- package/templates/create/3d-collectathon/src/runtime/app.js +4 -0
- package/templates/create/3d-collectathon/src/runtime/capabilities.js +5 -0
- package/templates/create/3d-collectathon/src/runtime/materials.js +10 -0
- package/templates/create/blank/assets/splash/aurajs-gg-wordmark.webp +0 -0
- package/templates/create/blank/assets/splash/bg.webp +0 -0
- package/templates/create/blank/assets/splash/boot-loop.wav +0 -0
- package/templates/create/blank/assets/splash/boot-sting.wav +0 -0
- package/templates/create/blank/assets/splash/logo-mascot-sheet.webp +0 -0
- package/templates/create/blank/assets/splash/logoholo.webp +0 -0
- package/templates/create/blank/src/main.js +5 -1
- package/templates/create/blank/src/runtime/splash.js +305 -0
- package/templates/create/local-multiplayer/scenes/gameplay.scene.js +186 -12
- package/templates/create/local-multiplayer/src/runtime/capabilities.js +8 -1
- package/templates/create/shared/assets/splash/aurajs-gg-wordmark.webp +0 -0
- package/templates/create/shared/assets/splash/bg.webp +0 -0
- package/templates/create/shared/assets/splash/boot-loop.wav +0 -0
- package/templates/create/shared/assets/splash/boot-sting.wav +0 -0
- package/templates/create/shared/assets/splash/logo-mascot-sheet.webp +0 -0
- package/templates/create/shared/assets/splash/logoholo.webp +0 -0
- package/templates/create/shared/src/runtime/splash.js +305 -0
- package/templates/create/shared/src/runtime/ui-forms.js +552 -0
- package/templates/create/shared/src/starter-utils/adventure-world-2d.js +221 -0
- package/templates/create/shared/src/starter-utils/animation-packaging-2d.js +203 -0
- package/templates/create/shared/src/starter-utils/atlas-assets-2d.js +111 -0
- package/templates/create/shared/src/starter-utils/autoplay-debug-2d.js +215 -0
- package/templates/create/shared/src/starter-utils/combat-runtime-2d.js +290 -0
- package/templates/create/shared/src/starter-utils/dialogue-2d.js +351 -0
- package/templates/create/shared/src/starter-utils/index.js +15 -1
- package/templates/create/shared/src/starter-utils/inventory-2d.js +268 -0
- package/templates/create/shared/src/starter-utils/journal-2d.js +267 -0
- package/templates/create/shared/src/starter-utils/scene-audio-2d.js +236 -0
- package/templates/create/shared/src/starter-utils/streamed-world-2d.js +378 -0
- package/templates/create/shared/src/starter-utils/tilemap-nav-2d.js +499 -0
- package/templates/create/shared/src/starter-utils/tilemap-world-2d.js +205 -0
- package/templates/create/shared/src/starter-utils/world-compositor-2d.js +253 -0
- package/templates/create/shared/src/starter-utils/world-persistence-2d.js +180 -0
- package/templates/create/video-cutscene/src/runtime/app.js +4 -0
- package/templates/create-bin/play.js +148 -7
- package/templates/skills/auramaxx/SKILL.md +46 -0
- package/templates/skills/auramaxx/project-requirements.md +68 -0
- package/templates/skills/auramaxx/starter-recipes.md +104 -0
- package/templates/skills/auramaxx/validation-checklist.md +49 -0
- package/templates/starter/assets/splash/aurajs-gg-wordmark.webp +0 -0
- package/templates/starter/assets/splash/bg.webp +0 -0
- package/templates/starter/assets/splash/boot-loop.wav +0 -0
- package/templates/starter/assets/splash/boot-sting.wav +0 -0
- package/templates/starter/assets/splash/logo-mascot-sheet.webp +0 -0
- package/templates/starter/assets/splash/logoholo.webp +0 -0
- package/templates/starter/src/main.js +4 -0
- package/templates/starter/src/runtime/splash.js +305 -0
- package/templates/skills/aurajs/SKILL.md +0 -96
- package/templates/skills/aurajs/api-contract-3d.md +0 -7
- package/templates/skills/aurajs/api-contract.md +0 -7
|
@@ -1,31 +1,75 @@
|
|
|
1
1
|
import {
|
|
2
2
|
axisFromKeys,
|
|
3
3
|
centeredRect,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
addInventoryItem2D,
|
|
5
|
+
advanceDialogueConversation2D,
|
|
6
|
+
chooseDialogueChoice2D,
|
|
7
|
+
createAdventureInteractablesFromTilemapObjects2D,
|
|
8
|
+
createAdventureInteractionState2D,
|
|
9
|
+
createDialogueState2D,
|
|
10
|
+
createInventory2D,
|
|
11
|
+
createJournal2D,
|
|
12
|
+
getDialogueView2D,
|
|
13
|
+
getInventoryView2D,
|
|
14
|
+
getJournalView2D,
|
|
15
|
+
hasInventoryItem2D,
|
|
16
|
+
listInventoryItems2D,
|
|
17
|
+
listJournalEntries2D,
|
|
18
|
+
selectInventoryCategory2D,
|
|
19
|
+
selectInventoryItem2D,
|
|
20
|
+
selectJournalCategory2D,
|
|
21
|
+
selectJournalEntry2D,
|
|
22
|
+
setJournalEntryStatus2D,
|
|
23
|
+
startDialogueConversation2D,
|
|
24
|
+
stepAdventureInteractables2D,
|
|
25
|
+
upsertJournalEntry2D,
|
|
14
26
|
} from '../src/starter-utils/index.js';
|
|
15
27
|
import { ensureSessionState, ensureUiState } from '../src/runtime/app-state.js';
|
|
16
28
|
import { ADVENTURE_CONFIG, ADVENTURE_TEXT } from '../config/gameplay/adventure.config.js';
|
|
17
29
|
import { drawAdventurePlayer, createPlayerState, resetPlayerPosition } from '../prefabs/player.prefab.js';
|
|
18
30
|
import { drawAdventureRelics } from '../prefabs/relic.prefab.js';
|
|
19
|
-
import {
|
|
20
|
-
|
|
31
|
+
import {
|
|
32
|
+
createAdventureWorldState,
|
|
33
|
+
drawAdventureWorld,
|
|
34
|
+
ensureAdventureWorldLoaded,
|
|
35
|
+
listAdventureWorldObjects,
|
|
36
|
+
moveActorThroughAdventureWorld,
|
|
37
|
+
resolveAdventurePlayerSpawn,
|
|
38
|
+
} from '../prefabs/world.prefab.js';
|
|
39
|
+
import {
|
|
40
|
+
INVENTORY_CATEGORIES,
|
|
41
|
+
STARTING_INVENTORY_ITEMS,
|
|
42
|
+
WORLD_OBJECT_LAYERS,
|
|
43
|
+
WORLD_TEXT,
|
|
44
|
+
} from '../content/gameplay/world.js';
|
|
45
|
+
import {
|
|
46
|
+
ARCHIVE_CONSOLE_DIALOGUE_ID,
|
|
47
|
+
ADVENTURE_DIALOGUES,
|
|
48
|
+
JOURNAL_CATEGORIES,
|
|
49
|
+
JOURNAL_ENTRY_IDS,
|
|
50
|
+
STARTING_JOURNAL_ENTRIES,
|
|
51
|
+
} from '../content/gameplay/dialogue.js';
|
|
21
52
|
|
|
22
53
|
const INTERACT_KEYS = ['e', 'enter'];
|
|
54
|
+
const DIALOGUE_ADVANCE_KEYS = ['space'];
|
|
55
|
+
const DIALOGUE_CHOICE_PREV_KEYS = ['w', 'arrowup'];
|
|
56
|
+
const DIALOGUE_CHOICE_NEXT_KEYS = ['s', 'arrowdown'];
|
|
57
|
+
const INVENTORY_TOGGLE_KEYS = ['i', 'tab'];
|
|
58
|
+
const INVENTORY_CATEGORY_PREV_KEYS = ['a', 'arrowleft'];
|
|
59
|
+
const INVENTORY_CATEGORY_NEXT_KEYS = ['d', 'arrowright'];
|
|
60
|
+
const INVENTORY_ITEM_PREV_KEYS = ['w', 'arrowup'];
|
|
61
|
+
const INVENTORY_ITEM_NEXT_KEYS = ['s', 'arrowdown'];
|
|
62
|
+
const JOURNAL_TOGGLE_KEYS = ['j'];
|
|
63
|
+
const JOURNAL_CATEGORY_PREV_KEYS = ['a', 'arrowleft'];
|
|
64
|
+
const JOURNAL_CATEGORY_NEXT_KEYS = ['d', 'arrowright'];
|
|
65
|
+
const JOURNAL_ENTRY_PREV_KEYS = ['w', 'arrowup'];
|
|
66
|
+
const JOURNAL_ENTRY_NEXT_KEYS = ['s', 'arrowdown'];
|
|
23
67
|
|
|
24
68
|
function createAdventureSessionSeed() {
|
|
25
69
|
return {
|
|
26
70
|
runsStarted: 0,
|
|
27
71
|
bestRelicCount: 0,
|
|
28
|
-
|
|
72
|
+
bestCheckpointCount: 0,
|
|
29
73
|
bestTimeSeconds: 0,
|
|
30
74
|
lastOutcome: 'idle',
|
|
31
75
|
lastSceneId: 'gameplay',
|
|
@@ -35,150 +79,537 @@ function createAdventureSessionSeed() {
|
|
|
35
79
|
function createAdventureUiStateSeed() {
|
|
36
80
|
return {
|
|
37
81
|
showControlsHint: true,
|
|
82
|
+
showInventory: false,
|
|
83
|
+
showJournal: false,
|
|
84
|
+
inventorySelectedCategoryId: null,
|
|
85
|
+
inventorySelectedItemId: null,
|
|
86
|
+
journalSelectedCategoryId: null,
|
|
87
|
+
journalSelectedEntryId: null,
|
|
88
|
+
dialogueSelectedChoiceId: null,
|
|
38
89
|
};
|
|
39
90
|
}
|
|
40
91
|
|
|
41
|
-
function
|
|
42
|
-
return
|
|
43
|
-
id: site.id,
|
|
44
|
-
label: site.label,
|
|
45
|
-
x: site.x,
|
|
46
|
-
y: site.y,
|
|
47
|
-
size: site.size,
|
|
48
|
-
radius: site.radius,
|
|
49
|
-
requiredRelics: site.requiredRelics,
|
|
50
|
-
lit: false,
|
|
51
|
-
}));
|
|
92
|
+
function pressedAny(keys = []) {
|
|
93
|
+
return keys.some((key) => aura.input.isKeyPressed(key));
|
|
52
94
|
}
|
|
53
95
|
|
|
54
96
|
function pressedInteract() {
|
|
55
|
-
return INTERACT_KEYS
|
|
97
|
+
return pressedAny(INTERACT_KEYS);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function objectProperty(object, name, fallback = null) {
|
|
101
|
+
if (!object || typeof object !== 'object') return fallback;
|
|
102
|
+
const properties = object.properties;
|
|
103
|
+
if (Array.isArray(properties)) {
|
|
104
|
+
const entry = properties.find((candidate) => candidate && candidate.name === name) || null;
|
|
105
|
+
return entry && Object.prototype.hasOwnProperty.call(entry, 'value') ? entry.value : fallback;
|
|
106
|
+
}
|
|
107
|
+
if (properties && typeof properties === 'object' && Object.prototype.hasOwnProperty.call(properties, name)) {
|
|
108
|
+
return properties[name];
|
|
109
|
+
}
|
|
110
|
+
return fallback;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function normalizeInteractables(world, layer) {
|
|
114
|
+
const objects = listAdventureWorldObjects(world, { layer, includeHidden: true });
|
|
115
|
+
const base = createAdventureInteractablesFromTilemapObjects2D(objects) || [];
|
|
116
|
+
const sourceById = new Map(objects.map((entry) => [String(entry.id), entry]));
|
|
117
|
+
|
|
118
|
+
return base.map((entry) => {
|
|
119
|
+
const source = sourceById.get(String(entry.id)) || null;
|
|
120
|
+
if (entry.kind === 'pickup') {
|
|
121
|
+
return {
|
|
122
|
+
...entry,
|
|
123
|
+
priority: 6,
|
|
124
|
+
grantItem: {
|
|
125
|
+
id: String(objectProperty(source, 'grantItemId', entry.id)),
|
|
126
|
+
label: String(entry.label || source?.name || entry.id),
|
|
127
|
+
categoryId: String(objectProperty(source, 'grantCategoryId', 'relics')),
|
|
128
|
+
categoryLabel: String(objectProperty(source, 'grantCategoryLabel', 'Relics')),
|
|
129
|
+
description: String(objectProperty(source, 'grantDescription', `${entry.label} recovered from the archive.`)),
|
|
130
|
+
detail: String(objectProperty(source, 'grantDetail', 'Recovered during the route.')),
|
|
131
|
+
badge: String(objectProperty(source, 'grantBadge', 'ITEM')),
|
|
132
|
+
quantity: 1,
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (entry.kind === 'lock') {
|
|
137
|
+
return {
|
|
138
|
+
...entry,
|
|
139
|
+
priority: 8,
|
|
140
|
+
openedPromptText: String(objectProperty(source, 'openedPromptText', `${entry.label} is open`)),
|
|
141
|
+
consumeRequiredItem: objectProperty(source, 'consumeRequiredItem', false) === true,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
if (entry.kind === 'checkpoint') {
|
|
145
|
+
return {
|
|
146
|
+
...entry,
|
|
147
|
+
priority: 7,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
...entry,
|
|
152
|
+
priority: 3,
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function createRunInventory() {
|
|
158
|
+
return createInventory2D({
|
|
159
|
+
categories: INVENTORY_CATEGORIES,
|
|
160
|
+
items: STARTING_INVENTORY_ITEMS,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function createRunJournal() {
|
|
165
|
+
return createJournal2D({
|
|
166
|
+
categories: JOURNAL_CATEGORIES,
|
|
167
|
+
entries: STARTING_JOURNAL_ENTRIES,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function createRunDialogue() {
|
|
172
|
+
return createDialogueState2D({
|
|
173
|
+
conversations: ADVENTURE_DIALOGUES,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function cycleValue(values, current, direction) {
|
|
178
|
+
if (!Array.isArray(values) || values.length <= 0) return current;
|
|
179
|
+
const index = values.indexOf(current);
|
|
180
|
+
const start = index >= 0 ? index : 0;
|
|
181
|
+
const nextIndex = (start + direction + values.length) % values.length;
|
|
182
|
+
return values[nextIndex];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function syncInventoryUiState(inventory, uiState) {
|
|
186
|
+
const view = getInventoryView2D(inventory);
|
|
187
|
+
uiState.inventorySelectedCategoryId = view.selectedCategoryId;
|
|
188
|
+
uiState.inventorySelectedItemId = view.selectedItemId;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function applyInventoryUiSelection(inventory, uiState) {
|
|
192
|
+
if (uiState.inventorySelectedCategoryId) {
|
|
193
|
+
selectInventoryCategory2D(inventory, uiState.inventorySelectedCategoryId);
|
|
194
|
+
}
|
|
195
|
+
const visibleItems = getInventoryView2D(inventory).items;
|
|
196
|
+
if (uiState.inventorySelectedItemId && visibleItems.some((entry) => entry.id === uiState.inventorySelectedItemId)) {
|
|
197
|
+
selectInventoryItem2D(inventory, uiState.inventorySelectedItemId);
|
|
198
|
+
}
|
|
199
|
+
syncInventoryUiState(inventory, uiState);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function handleInventoryNavigation(inventory, uiState) {
|
|
203
|
+
const categoryIds = getInventoryView2D(inventory).categories.map((entry) => entry.id);
|
|
204
|
+
if (pressedAny(INVENTORY_CATEGORY_PREV_KEYS)) {
|
|
205
|
+
selectInventoryCategory2D(
|
|
206
|
+
inventory,
|
|
207
|
+
cycleValue(categoryIds, getInventoryView2D(inventory).selectedCategoryId, -1),
|
|
208
|
+
);
|
|
209
|
+
} else if (pressedAny(INVENTORY_CATEGORY_NEXT_KEYS)) {
|
|
210
|
+
selectInventoryCategory2D(
|
|
211
|
+
inventory,
|
|
212
|
+
cycleValue(categoryIds, getInventoryView2D(inventory).selectedCategoryId, 1),
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const visibleItems = getInventoryView2D(inventory).items.map((entry) => entry.id);
|
|
217
|
+
if (pressedAny(INVENTORY_ITEM_PREV_KEYS)) {
|
|
218
|
+
selectInventoryItem2D(
|
|
219
|
+
inventory,
|
|
220
|
+
cycleValue(visibleItems, getInventoryView2D(inventory).selectedItemId, -1),
|
|
221
|
+
);
|
|
222
|
+
} else if (pressedAny(INVENTORY_ITEM_NEXT_KEYS)) {
|
|
223
|
+
selectInventoryItem2D(
|
|
224
|
+
inventory,
|
|
225
|
+
cycleValue(visibleItems, getInventoryView2D(inventory).selectedItemId, 1),
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
syncInventoryUiState(inventory, uiState);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function syncJournalUiState(journal, uiState) {
|
|
233
|
+
const view = getJournalView2D(journal);
|
|
234
|
+
uiState.journalSelectedCategoryId = view.selectedCategoryId;
|
|
235
|
+
uiState.journalSelectedEntryId = view.selectedEntryId;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function applyJournalUiSelection(journal, uiState) {
|
|
239
|
+
if (uiState.journalSelectedCategoryId) {
|
|
240
|
+
selectJournalCategory2D(journal, uiState.journalSelectedCategoryId);
|
|
241
|
+
}
|
|
242
|
+
const visibleEntries = getJournalView2D(journal).entries;
|
|
243
|
+
if (uiState.journalSelectedEntryId && visibleEntries.some((entry) => entry.id === uiState.journalSelectedEntryId)) {
|
|
244
|
+
selectJournalEntry2D(journal, uiState.journalSelectedEntryId);
|
|
245
|
+
}
|
|
246
|
+
syncJournalUiState(journal, uiState);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function handleJournalNavigation(journal, uiState) {
|
|
250
|
+
const categoryIds = getJournalView2D(journal).categories.map((entry) => entry.id);
|
|
251
|
+
if (pressedAny(JOURNAL_CATEGORY_PREV_KEYS)) {
|
|
252
|
+
selectJournalCategory2D(
|
|
253
|
+
journal,
|
|
254
|
+
cycleValue(categoryIds, getJournalView2D(journal).selectedCategoryId, -1),
|
|
255
|
+
);
|
|
256
|
+
} else if (pressedAny(JOURNAL_CATEGORY_NEXT_KEYS)) {
|
|
257
|
+
selectJournalCategory2D(
|
|
258
|
+
journal,
|
|
259
|
+
cycleValue(categoryIds, getJournalView2D(journal).selectedCategoryId, 1),
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const entryIds = getJournalView2D(journal).entries.map((entry) => entry.id);
|
|
264
|
+
if (pressedAny(JOURNAL_ENTRY_PREV_KEYS)) {
|
|
265
|
+
selectJournalEntry2D(
|
|
266
|
+
journal,
|
|
267
|
+
cycleValue(entryIds, getJournalView2D(journal).selectedEntryId, -1),
|
|
268
|
+
);
|
|
269
|
+
} else if (pressedAny(JOURNAL_ENTRY_NEXT_KEYS)) {
|
|
270
|
+
selectJournalEntry2D(
|
|
271
|
+
journal,
|
|
272
|
+
cycleValue(entryIds, getJournalView2D(journal).selectedEntryId, 1),
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
syncJournalUiState(journal, uiState);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function syncDialogueUiState(dialogue, uiState) {
|
|
280
|
+
const view = getDialogueView2D(dialogue);
|
|
281
|
+
if (!view.awaitingChoice) {
|
|
282
|
+
uiState.dialogueSelectedChoiceId = null;
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const choiceIds = view.choices
|
|
286
|
+
.filter((entry) => entry.disabled !== true)
|
|
287
|
+
.map((entry) => entry.id);
|
|
288
|
+
if (choiceIds.length <= 0) {
|
|
289
|
+
uiState.dialogueSelectedChoiceId = null;
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (!choiceIds.includes(uiState.dialogueSelectedChoiceId)) {
|
|
293
|
+
uiState.dialogueSelectedChoiceId = choiceIds[0];
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function applyInteractionResult(interactables, result) {
|
|
298
|
+
for (const entry of interactables) {
|
|
299
|
+
if (!entry) continue;
|
|
300
|
+
if (result.collectedIds.includes(entry.id)) entry.collected = true;
|
|
301
|
+
if (result.openedIds.includes(entry.id)) entry.opened = true;
|
|
302
|
+
if (result.activatedIds.includes(entry.id)) entry.activated = true;
|
|
303
|
+
}
|
|
56
304
|
}
|
|
57
305
|
|
|
58
306
|
export function createGameplayScene(context = {}) {
|
|
59
307
|
const appState = context.appState && typeof context.appState === 'object' ? context.appState : (context.appState = {});
|
|
60
308
|
const adventureSession = ensureSessionState(appState, 'adventure2d', createAdventureSessionSeed());
|
|
61
309
|
const adventureUiState = ensureUiState(appState, 'adventureHud', createAdventureUiStateSeed());
|
|
62
|
-
const
|
|
63
|
-
const triggerTracker = createTriggerTracker({ subjectId: 'player', dimension: '2d' });
|
|
310
|
+
const world = createAdventureWorldState();
|
|
64
311
|
const sceneState = {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
312
|
+
world,
|
|
313
|
+
player: createPlayerState(),
|
|
314
|
+
inventory: createRunInventory(),
|
|
315
|
+
journal: createRunJournal(),
|
|
316
|
+
dialogue: createRunDialogue(),
|
|
317
|
+
interaction: createAdventureInteractionState2D({
|
|
318
|
+
subjectId: 'player',
|
|
319
|
+
prompt: 'Press E to interact',
|
|
69
320
|
}),
|
|
70
|
-
|
|
321
|
+
interactables: [],
|
|
322
|
+
activeCheckpointId: null,
|
|
71
323
|
elapsed: 0,
|
|
72
324
|
runComplete: false,
|
|
325
|
+
lastDialogueCompletionRevision: 0,
|
|
73
326
|
};
|
|
74
327
|
|
|
75
328
|
function relicCount() {
|
|
76
|
-
return
|
|
329
|
+
return listInventoryItems2D(sceneState.inventory, 'relics')
|
|
330
|
+
.reduce((total, entry) => total + Number(entry.quantity || 0), 0);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function checkpointCount() {
|
|
334
|
+
return sceneState.interactables
|
|
335
|
+
.filter((entry) => entry.kind === 'checkpoint' && entry.activated === true)
|
|
336
|
+
.length;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function inventoryView() {
|
|
340
|
+
return getInventoryView2D(sceneState.inventory);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function journalView() {
|
|
344
|
+
return getJournalView2D(sceneState.journal);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function dialogueView() {
|
|
348
|
+
return getDialogueView2D(sceneState.dialogue);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function objectiveText() {
|
|
352
|
+
if (sceneState.runComplete) {
|
|
353
|
+
return 'Route secured. Restart when ready.';
|
|
354
|
+
}
|
|
355
|
+
if (!hasInventoryItem2D(sceneState.inventory, 'route-console-log')) {
|
|
356
|
+
return 'Inspect the archive console to recover the route note.';
|
|
357
|
+
}
|
|
358
|
+
if (!hasInventoryItem2D(sceneState.inventory, 'dawn-key')) {
|
|
359
|
+
return 'Recover the Dawn Key from the south gallery.';
|
|
360
|
+
}
|
|
361
|
+
return 'Use the Dawn Key on the Moon Gate to clear the route.';
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function activeCheckpointLabel() {
|
|
365
|
+
const checkpoint = sceneState.interactables.find((entry) => entry.kind === 'checkpoint' && entry.checkpointId === sceneState.activeCheckpointId) || null;
|
|
366
|
+
return checkpoint?.label || 'Route Entry';
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function rebuildInteractables() {
|
|
370
|
+
sceneState.interactables = [
|
|
371
|
+
...normalizeInteractables(sceneState.world, WORLD_OBJECT_LAYERS.pickups),
|
|
372
|
+
...normalizeInteractables(sceneState.world, WORLD_OBJECT_LAYERS.checkpoints),
|
|
373
|
+
...normalizeInteractables(sceneState.world, WORLD_OBJECT_LAYERS.props),
|
|
374
|
+
...normalizeInteractables(sceneState.world, WORLD_OBJECT_LAYERS.locks),
|
|
375
|
+
];
|
|
77
376
|
}
|
|
78
377
|
|
|
79
|
-
function
|
|
80
|
-
|
|
378
|
+
function focusJournalEntry(categoryId, entryId) {
|
|
379
|
+
if (categoryId) {
|
|
380
|
+
selectJournalCategory2D(sceneState.journal, categoryId);
|
|
381
|
+
}
|
|
382
|
+
if (entryId) {
|
|
383
|
+
selectJournalEntry2D(sceneState.journal, entryId);
|
|
384
|
+
}
|
|
385
|
+
syncJournalUiState(sceneState.journal, adventureUiState);
|
|
81
386
|
}
|
|
82
387
|
|
|
83
|
-
function
|
|
84
|
-
|
|
388
|
+
function registerConsoleRouteUnlock() {
|
|
389
|
+
if (!hasInventoryItem2D(sceneState.inventory, 'route-console-log')) {
|
|
390
|
+
addInventoryItem2D(sceneState.inventory, {
|
|
391
|
+
id: 'route-console-log',
|
|
392
|
+
label: WORLD_TEXT.consoleNoteTitle,
|
|
393
|
+
categoryId: 'field',
|
|
394
|
+
categoryLabel: 'Field Notes',
|
|
395
|
+
quantity: 1,
|
|
396
|
+
badge: 'NOTE',
|
|
397
|
+
description: 'Recovered from the archive console.',
|
|
398
|
+
detail: WORLD_TEXT.consoleNoteDetail,
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
setJournalEntryStatus2D(sceneState.journal, JOURNAL_ENTRY_IDS.routeBrief, 'completed', {
|
|
403
|
+
badge: 'Completed',
|
|
404
|
+
meta: 'Archive console route restored',
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
upsertJournalEntry2D(sceneState.journal, {
|
|
408
|
+
id: JOURNAL_ENTRY_IDS.consoleLog,
|
|
409
|
+
label: WORLD_TEXT.consoleNoteTitle,
|
|
410
|
+
categoryId: 'intel',
|
|
411
|
+
categoryLabel: 'Archive Intel',
|
|
412
|
+
description: 'Recovered from the archive console.',
|
|
413
|
+
detail: WORLD_TEXT.consoleNoteDetail,
|
|
414
|
+
status: 'completed',
|
|
415
|
+
badge: 'Recovered',
|
|
416
|
+
updatedAt: 'Recovered at the archive console',
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
upsertJournalEntry2D(sceneState.journal, {
|
|
420
|
+
id: JOURNAL_ENTRY_IDS.moonGate,
|
|
421
|
+
label: 'Moon Gate Route',
|
|
422
|
+
categoryId: 'route',
|
|
423
|
+
categoryLabel: 'Route',
|
|
424
|
+
description: 'Carry the Dawn Key to the Moon Gate and restore the exit route.',
|
|
425
|
+
detail: hasInventoryItem2D(sceneState.inventory, 'dawn-key')
|
|
426
|
+
? 'The Dawn Key is secured. Return to the lower gallery and open the gate.'
|
|
427
|
+
: 'Recover the Dawn Key from the south gallery, then return to the gate.',
|
|
428
|
+
status: 'active',
|
|
429
|
+
badge: hasInventoryItem2D(sceneState.inventory, 'dawn-key') ? 'Key Ready' : 'Active',
|
|
430
|
+
meta: 'Route goal updated',
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
adventureUiState.showJournal = true;
|
|
434
|
+
focusJournalEntry('route', JOURNAL_ENTRY_IDS.moonGate);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function handleDialogueCompletion() {
|
|
438
|
+
const completion = dialogueView().lastCompletion;
|
|
439
|
+
if (!completion || completion.revision === sceneState.lastDialogueCompletionRevision) {
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
sceneState.lastDialogueCompletionRevision = completion.revision;
|
|
443
|
+
if (completion.conversationId === ARCHIVE_CONSOLE_DIALOGUE_ID && completion.outcomeId === 'route-briefed') {
|
|
444
|
+
registerConsoleRouteUnlock();
|
|
445
|
+
}
|
|
85
446
|
}
|
|
86
447
|
|
|
87
448
|
function syncSessionState() {
|
|
88
449
|
adventureSession.lastSceneId = 'gameplay';
|
|
89
450
|
adventureSession.bestRelicCount = Math.max(Number(adventureSession.bestRelicCount || 0), relicCount());
|
|
90
|
-
adventureSession.
|
|
451
|
+
adventureSession.bestCheckpointCount = Math.max(Number(adventureSession.bestCheckpointCount || 0), checkpointCount());
|
|
91
452
|
adventureSession.bestTimeSeconds = Math.max(Number(adventureSession.bestTimeSeconds || 0), sceneState.elapsed);
|
|
92
453
|
adventureSession.lastElapsedSeconds = Number(sceneState.elapsed.toFixed(2));
|
|
93
|
-
adventureSession.lastOutcome = sceneState.runComplete
|
|
454
|
+
adventureSession.lastOutcome = sceneState.runComplete
|
|
455
|
+
? 'route-cleared'
|
|
456
|
+
: dialogueView().active === true
|
|
457
|
+
? 'dialogue-open'
|
|
458
|
+
: adventureUiState.showJournal === true
|
|
459
|
+
? 'journal-open'
|
|
460
|
+
: adventureUiState.showInventory === true
|
|
461
|
+
? 'inventory-open'
|
|
462
|
+
: 'surveying';
|
|
94
463
|
}
|
|
95
464
|
|
|
96
465
|
function syncHud() {
|
|
97
466
|
context.setHudScreen?.('hud', {
|
|
98
467
|
relicCount: relicCount(),
|
|
99
|
-
relicTarget:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
promptText:
|
|
468
|
+
relicTarget: 3,
|
|
469
|
+
checkpointCount: checkpointCount(),
|
|
470
|
+
checkpointLabel: activeCheckpointLabel(),
|
|
471
|
+
promptText: sceneState.interaction.prompt.prompt || '',
|
|
472
|
+
objectiveText: objectiveText(),
|
|
473
|
+
zoneLabel: WORLD_TEXT.zoneLabel,
|
|
103
474
|
runComplete: sceneState.runComplete,
|
|
104
475
|
showControlsHint: adventureUiState.showControlsHint !== false,
|
|
476
|
+
showInventory: adventureUiState.showInventory === true,
|
|
477
|
+
showJournal: adventureUiState.showJournal === true,
|
|
478
|
+
inventory: inventoryView(),
|
|
479
|
+
journal: journalView(),
|
|
480
|
+
inventoryHint: WORLD_TEXT.inventoryHint,
|
|
481
|
+
journalHint: WORLD_TEXT.journalHint,
|
|
482
|
+
dialogueActive: dialogueView().active === true,
|
|
105
483
|
fps: Number(aura.window.getFPS?.() || 0).toFixed(0),
|
|
106
484
|
});
|
|
107
485
|
}
|
|
108
486
|
|
|
487
|
+
function syncOverlay() {
|
|
488
|
+
const activeDialogue = dialogueView();
|
|
489
|
+
if (activeDialogue.active === true) {
|
|
490
|
+
syncDialogueUiState(sceneState.dialogue, adventureUiState);
|
|
491
|
+
context.showOverlayScreen?.('journal', {
|
|
492
|
+
mode: 'dialogue',
|
|
493
|
+
dialogue: {
|
|
494
|
+
...activeDialogue,
|
|
495
|
+
selectedChoiceId: adventureUiState.dialogueSelectedChoiceId,
|
|
496
|
+
},
|
|
497
|
+
journal: journalView(),
|
|
498
|
+
zoneLabel: WORLD_TEXT.zoneLabel,
|
|
499
|
+
title: 'Archive Console Link',
|
|
500
|
+
controlsText: ADVENTURE_TEXT.dialogueControls,
|
|
501
|
+
});
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
if (adventureUiState.showJournal === true) {
|
|
505
|
+
const activeJournal = journalView();
|
|
506
|
+
context.showOverlayScreen?.('journal', {
|
|
507
|
+
mode: 'journal',
|
|
508
|
+
journal: {
|
|
509
|
+
...activeJournal,
|
|
510
|
+
activeEntries: listJournalEntries2D(sceneState.journal, activeJournal.selectedCategoryId),
|
|
511
|
+
},
|
|
512
|
+
objectiveText: objectiveText(),
|
|
513
|
+
zoneLabel: WORLD_TEXT.zoneLabel,
|
|
514
|
+
controlsText: ADVENTURE_TEXT.journalControls,
|
|
515
|
+
});
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
context.clearOverlayScreen?.();
|
|
519
|
+
}
|
|
520
|
+
|
|
109
521
|
function resetRun() {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
sceneState.
|
|
522
|
+
ensureAdventureWorldLoaded(sceneState.world);
|
|
523
|
+
sceneState.inventory = createRunInventory();
|
|
524
|
+
sceneState.journal = createRunJournal();
|
|
525
|
+
sceneState.dialogue = createRunDialogue();
|
|
526
|
+
sceneState.lastDialogueCompletionRevision = 0;
|
|
527
|
+
rebuildInteractables();
|
|
528
|
+
sceneState.activeCheckpointId = null;
|
|
529
|
+
resetPlayerPosition(sceneState.player, resolveAdventurePlayerSpawn(sceneState.world));
|
|
530
|
+
sceneState.interaction = createAdventureInteractionState2D({
|
|
531
|
+
subjectId: 'player',
|
|
532
|
+
prompt: 'Press E to interact',
|
|
533
|
+
});
|
|
113
534
|
sceneState.elapsed = 0;
|
|
114
535
|
sceneState.runComplete = false;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
promptState.triggerId = null;
|
|
119
|
-
promptState.accepted = false;
|
|
120
|
-
promptState.acceptedTriggerId = null;
|
|
536
|
+
adventureUiState.showInventory = false;
|
|
537
|
+
adventureUiState.showJournal = false;
|
|
538
|
+
adventureUiState.dialogueSelectedChoiceId = null;
|
|
121
539
|
adventureSession.runsStarted += 1;
|
|
540
|
+
syncInventoryUiState(sceneState.inventory, adventureUiState);
|
|
541
|
+
syncJournalUiState(sceneState.journal, adventureUiState);
|
|
542
|
+
syncDialogueUiState(sceneState.dialogue, adventureUiState);
|
|
122
543
|
syncSessionState();
|
|
123
544
|
syncHud();
|
|
545
|
+
syncOverlay();
|
|
124
546
|
}
|
|
125
547
|
|
|
126
|
-
function
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
548
|
+
function handleInteractionSideEffects(result) {
|
|
549
|
+
if (result.checkpointId) {
|
|
550
|
+
sceneState.activeCheckpointId = result.checkpointId;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (result.activatedIds.includes('301') && !hasInventoryItem2D(sceneState.inventory, 'route-console-log')) {
|
|
554
|
+
startDialogueConversation2D(sceneState.dialogue, ARCHIVE_CONSOLE_DIALOGUE_ID);
|
|
555
|
+
adventureUiState.showInventory = false;
|
|
556
|
+
adventureUiState.showJournal = false;
|
|
557
|
+
syncDialogueUiState(sceneState.dialogue, adventureUiState);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (result.collectedIds.includes('104')) {
|
|
561
|
+
upsertJournalEntry2D(sceneState.journal, {
|
|
562
|
+
id: JOURNAL_ENTRY_IDS.moonGate,
|
|
563
|
+
label: 'Moon Gate Route',
|
|
564
|
+
categoryId: 'route',
|
|
565
|
+
categoryLabel: 'Route',
|
|
566
|
+
description: 'Carry the Dawn Key to the Moon Gate and restore the exit route.',
|
|
567
|
+
detail: 'The Dawn Key is secured. Return to the lower gallery and open the gate.',
|
|
568
|
+
status: 'active',
|
|
569
|
+
badge: 'Key Ready',
|
|
570
|
+
meta: 'Dawn Key secured',
|
|
571
|
+
});
|
|
148
572
|
}
|
|
149
573
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
role: 'goal',
|
|
158
|
-
priority: gateReady() ? 8 : 1,
|
|
159
|
-
promptText: gateReady()
|
|
160
|
-
? 'Press E to leave through the Moon Gate'
|
|
161
|
-
: 'Collect every relic and light both beacons to open the gate',
|
|
162
|
-
interactionKey: 'E',
|
|
163
|
-
},
|
|
164
|
-
));
|
|
165
|
-
|
|
166
|
-
return triggers;
|
|
574
|
+
if (result.openedIds.includes('401')) {
|
|
575
|
+
sceneState.runComplete = true;
|
|
576
|
+
setJournalEntryStatus2D(sceneState.journal, JOURNAL_ENTRY_IDS.moonGate, 'completed', {
|
|
577
|
+
badge: 'Completed',
|
|
578
|
+
meta: 'Moon Gate opened',
|
|
579
|
+
});
|
|
580
|
+
}
|
|
167
581
|
}
|
|
168
582
|
|
|
169
|
-
function
|
|
170
|
-
const
|
|
171
|
-
if (
|
|
583
|
+
function handleDialogueInput() {
|
|
584
|
+
const view = dialogueView();
|
|
585
|
+
if (view.active !== true) {
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
172
588
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
589
|
+
syncDialogueUiState(sceneState.dialogue, adventureUiState);
|
|
590
|
+
if (view.awaitingChoice === true) {
|
|
591
|
+
const choiceIds = view.choices
|
|
592
|
+
.filter((entry) => entry.disabled !== true)
|
|
593
|
+
.map((entry) => entry.id);
|
|
594
|
+
if (pressedAny(DIALOGUE_CHOICE_PREV_KEYS)) {
|
|
595
|
+
adventureUiState.dialogueSelectedChoiceId = cycleValue(choiceIds, adventureUiState.dialogueSelectedChoiceId, -1);
|
|
596
|
+
} else if (pressedAny(DIALOGUE_CHOICE_NEXT_KEYS)) {
|
|
597
|
+
adventureUiState.dialogueSelectedChoiceId = cycleValue(choiceIds, adventureUiState.dialogueSelectedChoiceId, 1);
|
|
178
598
|
}
|
|
179
|
-
|
|
180
|
-
|
|
599
|
+
if (pressedInteract() || pressedAny(DIALOGUE_ADVANCE_KEYS)) {
|
|
600
|
+
chooseDialogueChoice2D(
|
|
601
|
+
sceneState.dialogue,
|
|
602
|
+
adventureUiState.dialogueSelectedChoiceId || choiceIds[0] || null,
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
} else if (pressedInteract() || pressedAny(DIALOGUE_ADVANCE_KEYS)) {
|
|
606
|
+
advanceDialogueConversation2D(sceneState.dialogue);
|
|
181
607
|
}
|
|
608
|
+
|
|
609
|
+
syncDialogueUiState(sceneState.dialogue, adventureUiState);
|
|
610
|
+
adventureUiState.showControlsHint = false;
|
|
611
|
+
handleDialogueCompletion();
|
|
612
|
+
return true;
|
|
182
613
|
}
|
|
183
614
|
|
|
184
615
|
return {
|
|
@@ -188,19 +619,65 @@ export function createGameplayScene(context = {}) {
|
|
|
188
619
|
},
|
|
189
620
|
|
|
190
621
|
update(dt) {
|
|
622
|
+
applyInventoryUiSelection(sceneState.inventory, adventureUiState);
|
|
623
|
+
applyJournalUiSelection(sceneState.journal, adventureUiState);
|
|
624
|
+
syncDialogueUiState(sceneState.dialogue, adventureUiState);
|
|
191
625
|
sceneState.elapsed += dt;
|
|
192
626
|
|
|
193
627
|
if (sceneState.runComplete) {
|
|
628
|
+
if (pressedAny(JOURNAL_TOGGLE_KEYS)) {
|
|
629
|
+
adventureUiState.showJournal = adventureUiState.showJournal !== true;
|
|
630
|
+
}
|
|
194
631
|
if (aura.input.isKeyPressed('enter')) {
|
|
195
632
|
resetRun();
|
|
633
|
+
return;
|
|
196
634
|
}
|
|
635
|
+
syncSessionState();
|
|
197
636
|
syncHud();
|
|
637
|
+
syncOverlay();
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
if (handleDialogueInput()) {
|
|
642
|
+
syncSessionState();
|
|
643
|
+
syncHud();
|
|
644
|
+
syncOverlay();
|
|
198
645
|
return;
|
|
199
646
|
}
|
|
200
647
|
|
|
201
648
|
if (aura.input.isKeyPressed('h')) {
|
|
202
649
|
adventureUiState.showControlsHint = adventureUiState.showControlsHint !== true;
|
|
203
650
|
}
|
|
651
|
+
if (pressedAny(INVENTORY_TOGGLE_KEYS)) {
|
|
652
|
+
adventureUiState.showInventory = adventureUiState.showInventory !== true;
|
|
653
|
+
if (adventureUiState.showInventory === true) {
|
|
654
|
+
adventureUiState.showJournal = false;
|
|
655
|
+
}
|
|
656
|
+
adventureUiState.showControlsHint = false;
|
|
657
|
+
}
|
|
658
|
+
if (pressedAny(JOURNAL_TOGGLE_KEYS)) {
|
|
659
|
+
adventureUiState.showJournal = adventureUiState.showJournal !== true;
|
|
660
|
+
if (adventureUiState.showJournal === true) {
|
|
661
|
+
adventureUiState.showInventory = false;
|
|
662
|
+
}
|
|
663
|
+
adventureUiState.showControlsHint = false;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (adventureUiState.showInventory === true) {
|
|
667
|
+
handleInventoryNavigation(sceneState.inventory, adventureUiState);
|
|
668
|
+
syncSessionState();
|
|
669
|
+
syncHud();
|
|
670
|
+
syncOverlay();
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
if (adventureUiState.showJournal === true) {
|
|
675
|
+
handleJournalNavigation(sceneState.journal, adventureUiState);
|
|
676
|
+
syncSessionState();
|
|
677
|
+
syncHud();
|
|
678
|
+
syncOverlay();
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
204
681
|
|
|
205
682
|
const moveX = axisFromKeys(aura.input, ['arrowleft', 'a'], ['arrowright', 'd']);
|
|
206
683
|
const moveY = axisFromKeys(aura.input, ['arrowup', 'w'], ['arrowdown', 's']);
|
|
@@ -213,41 +690,55 @@ export function createGameplayScene(context = {}) {
|
|
|
213
690
|
}
|
|
214
691
|
|
|
215
692
|
moveActorThroughAdventureWorld(
|
|
693
|
+
sceneState.world,
|
|
216
694
|
sceneState.player,
|
|
217
695
|
moveX * ADVENTURE_CONFIG.playerSpeed * dt,
|
|
218
696
|
moveY * ADVENTURE_CONFIG.playerSpeed * dt,
|
|
219
697
|
ADVENTURE_CONFIG.playerSize,
|
|
220
698
|
);
|
|
221
699
|
|
|
222
|
-
collectAdventureObjectives2D(sceneState.player, sceneState.relics);
|
|
223
|
-
|
|
224
700
|
const playerRect = centeredRect(
|
|
225
701
|
sceneState.player.x,
|
|
226
702
|
sceneState.player.y,
|
|
227
703
|
ADVENTURE_CONFIG.playerSize * 0.84,
|
|
228
704
|
ADVENTURE_CONFIG.playerSize * 0.84,
|
|
229
705
|
);
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
706
|
+
const interactionResult = stepAdventureInteractables2D(
|
|
707
|
+
sceneState.interaction,
|
|
708
|
+
playerRect,
|
|
709
|
+
sceneState.interactables,
|
|
710
|
+
{
|
|
711
|
+
inventory: sceneState.inventory,
|
|
712
|
+
interactPressed: pressedInteract(),
|
|
713
|
+
},
|
|
714
|
+
);
|
|
715
|
+
applyInteractionResult(sceneState.interactables, interactionResult);
|
|
716
|
+
handleInteractionSideEffects(interactionResult);
|
|
717
|
+
if (interactionResult.acceptedId) {
|
|
718
|
+
syncInventoryUiState(sceneState.inventory, adventureUiState);
|
|
719
|
+
syncJournalUiState(sceneState.journal, adventureUiState);
|
|
720
|
+
}
|
|
721
|
+
|
|
235
722
|
syncSessionState();
|
|
236
723
|
syncHud();
|
|
724
|
+
syncOverlay();
|
|
237
725
|
},
|
|
238
726
|
|
|
239
727
|
onExit() {
|
|
240
728
|
context.clearHudScreen?.();
|
|
729
|
+
context.clearOverlayScreen?.();
|
|
241
730
|
},
|
|
242
731
|
|
|
243
732
|
draw() {
|
|
244
|
-
aura.draw2d.clear(aura.rgba(0.
|
|
733
|
+
aura.draw2d.clear(aura.rgba(0.02, 0.03, 0.05, 1.0));
|
|
245
734
|
drawAdventureWorld({
|
|
246
|
-
|
|
247
|
-
|
|
735
|
+
world: sceneState.world,
|
|
736
|
+
interactables: sceneState.interactables,
|
|
248
737
|
elapsed: sceneState.elapsed,
|
|
738
|
+
activeCheckpointId: sceneState.activeCheckpointId,
|
|
739
|
+
runComplete: sceneState.runComplete,
|
|
249
740
|
});
|
|
250
|
-
drawAdventureRelics(sceneState.
|
|
741
|
+
drawAdventureRelics(sceneState.interactables, sceneState.elapsed);
|
|
251
742
|
drawAdventurePlayer(sceneState.player, ADVENTURE_CONFIG, {
|
|
252
743
|
runComplete: sceneState.runComplete,
|
|
253
744
|
});
|