Spaces:
Running
Running
Update index.html
Browse files- index.html +44 -39
index.html
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
-
<title>Persistent Procedural World (Fixed)</title>
|
7 |
<style>
|
8 |
body { font-family: 'Courier New', monospace; background-color: #111; color: #eee; margin: 0; padding: 0; overflow: hidden; display: flex; flex-direction: column; height: 100vh; }
|
9 |
#game-container { display: flex; flex-grow: 1; overflow: hidden; }
|
@@ -37,7 +37,6 @@
|
|
37 |
.message-info { color: #aaa; border-left-color: #666; }
|
38 |
.message-item { color: #8bf; border-left-color: #46a; }
|
39 |
#action-info { position: absolute; bottom: 10px; left: 10px; background-color: rgba(0,0,0,0.7); color: #ffcc66; padding: 5px 10px; border-radius: 3px; font-size: 0.9em; display: none; z-index: 10;}
|
40 |
-
|
41 |
</style>
|
42 |
</head>
|
43 |
<body>
|
@@ -83,7 +82,7 @@
|
|
83 |
let locationGroups = {};
|
84 |
let currentMessage = "";
|
85 |
let currentPlacingItem = null;
|
86 |
-
let currentLights = [];
|
87 |
|
88 |
const MAT = {
|
89 |
stone: new THREE.MeshStandardMaterial({ color: 0x777788, roughness: 0.85, metalness: 0.1 }),
|
@@ -101,6 +100,42 @@
|
|
101 |
placementPreview: new THREE.MeshBasicMaterial({ color: 0x00ff00, transparent: true, opacity: 0.5, wireframe: true }),
|
102 |
};
|
103 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
function initThreeJS() {
|
105 |
scene = new THREE.Scene();
|
106 |
scene.background = new THREE.Color(0x1a1a1a);
|
@@ -290,41 +325,11 @@
|
|
290 |
return { group, lighting: 'cave', entryText: "It's dark and damp in here.", cameraPos: {x:0, y:4, z:8}, targetPos: {x:0, y:1, z:0} };
|
291 |
}
|
292 |
|
293 |
-
const locationData = {
|
294 |
-
'start': { creator: createDefaultZone },
|
295 |
-
'forest': { creator: createForestZone },
|
296 |
-
'cave': { creator: createCaveZone }
|
297 |
-
};
|
298 |
-
|
299 |
-
const pageGraph = {
|
300 |
-
'start': {
|
301 |
-
title: "The Crossroads",
|
302 |
-
options: [ { text: "Enter Forest", transitionTo: 'forest' }, { text: "Enter Cave", transitionTo: 'cave'} ]
|
303 |
-
},
|
304 |
-
'forest': {
|
305 |
-
title: "Dark Forest",
|
306 |
-
options: [ { text: "Return to Crossroads", transitionTo: 'start' } ]
|
307 |
-
},
|
308 |
-
'cave': {
|
309 |
-
title: "Dim Cave",
|
310 |
-
options: [ { text: "Leave Cave", transitionTo: 'start' } ]
|
311 |
-
}
|
312 |
-
};
|
313 |
-
|
314 |
-
let gameState = {
|
315 |
-
currentLocationId: null,
|
316 |
-
character: {
|
317 |
-
name: "Player",
|
318 |
-
stats: { hp: 20, maxHp: 20, xp: 0 },
|
319 |
-
inventory: []
|
320 |
-
}
|
321 |
-
};
|
322 |
-
|
323 |
function startGame() {
|
324 |
const defaultChar = {
|
325 |
name: "Player",
|
326 |
stats: { hp: 20, maxHp: 20, xp: 0 },
|
327 |
-
inventory: ["Rusty Sword"]
|
328 |
};
|
329 |
gameState = {
|
330 |
currentLocationId: null,
|
@@ -450,7 +455,7 @@
|
|
450 |
|
451 |
inventoryElement.querySelectorAll('.item-tag').forEach(tag => {
|
452 |
tag.onclick = (event) => {
|
453 |
-
event.stopPropagation();
|
454 |
togglePlacementMode(tag.dataset.itemname);
|
455 |
};
|
456 |
});
|
@@ -467,14 +472,14 @@
|
|
467 |
}
|
468 |
|
469 |
function pickupItem() {
|
470 |
-
if (currentPlacingItem) return;
|
471 |
|
472 |
raycaster.setFromCamera(mouse, camera);
|
473 |
const currentGroup = locationGroups[gameState.currentLocationId];
|
474 |
if (!currentGroup) return;
|
475 |
|
476 |
const pickupables = [];
|
477 |
-
currentGroup.traverseVisible(child => {
|
478 |
if (child.userData.isPickupable) {
|
479 |
pickupables.push(child);
|
480 |
}
|
@@ -542,8 +547,8 @@
|
|
542 |
else if(itemDef.type === 'consumable') itemMat.color.setHex(0xaa7744);
|
543 |
else itemMat.color.setHex(0x8888aa);
|
544 |
|
545 |
-
const placedMesh = createMesh(itemGeo, itemMat, {x: point.x, y: 0.25, z: point.z});
|
546 |
-
placedMesh.userData = { isPlacedItem: true, itemName: itemName, isPickupable: true, description: `Placed ${itemName}` };
|
547 |
currentGroup.add(placedMesh);
|
548 |
|
549 |
gameState.character.inventory = gameState.character.inventory.filter(i => i !== itemName);
|
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Persistent Procedural World (Fixed Again)</title>
|
7 |
<style>
|
8 |
body { font-family: 'Courier New', monospace; background-color: #111; color: #eee; margin: 0; padding: 0; overflow: hidden; display: flex; flex-direction: column; height: 100vh; }
|
9 |
#game-container { display: flex; flex-grow: 1; overflow: hidden; }
|
|
|
37 |
.message-info { color: #aaa; border-left-color: #666; }
|
38 |
.message-item { color: #8bf; border-left-color: #46a; }
|
39 |
#action-info { position: absolute; bottom: 10px; left: 10px; background-color: rgba(0,0,0,0.7); color: #ffcc66; padding: 5px 10px; border-radius: 3px; font-size: 0.9em; display: none; z-index: 10;}
|
|
|
40 |
</style>
|
41 |
</head>
|
42 |
<body>
|
|
|
82 |
let locationGroups = {};
|
83 |
let currentMessage = "";
|
84 |
let currentPlacingItem = null;
|
85 |
+
let currentLights = [];
|
86 |
|
87 |
const MAT = {
|
88 |
stone: new THREE.MeshStandardMaterial({ color: 0x777788, roughness: 0.85, metalness: 0.1 }),
|
|
|
100 |
placementPreview: new THREE.MeshBasicMaterial({ color: 0x00ff00, transparent: true, opacity: 0.5, wireframe: true }),
|
101 |
};
|
102 |
|
103 |
+
// ---> Item Data Definition (Ensure this exists globally) <---
|
104 |
+
const itemsData = {
|
105 |
+
"Rusty Sword": {type:"weapon", description:"Old but sharp."},
|
106 |
+
"Torch": {type:"consumable", description:"Provides light.", use: "light"},
|
107 |
+
"Key": {type:"quest", description:"A simple iron key."},
|
108 |
+
"Mysterious Cube": {type:"unknown", description:"A plain stone cube."} // Added item from default zone
|
109 |
+
};
|
110 |
+
|
111 |
+
// ---> Location/Zone Definitions <---
|
112 |
+
const locationData = {
|
113 |
+
'start': { creator: createDefaultZone },
|
114 |
+
'forest': { creator: createForestZone },
|
115 |
+
'cave': { creator: createCaveZone }
|
116 |
+
};
|
117 |
+
|
118 |
+
// ---> Navigation/Story Graph <---
|
119 |
+
const pageGraph = {
|
120 |
+
'start': {
|
121 |
+
title: "The Crossroads",
|
122 |
+
options: [ { text: "Enter Forest", transitionTo: 'forest' }, { text: "Enter Cave", transitionTo: 'cave'} ]
|
123 |
+
},
|
124 |
+
'forest': {
|
125 |
+
title: "Dark Forest",
|
126 |
+
options: [ { text: "Return to Crossroads", transitionTo: 'start' } ]
|
127 |
+
},
|
128 |
+
'cave': {
|
129 |
+
title: "Dim Cave",
|
130 |
+
options: [ { text: "Leave Cave", transitionTo: 'start' } ]
|
131 |
+
}
|
132 |
+
};
|
133 |
+
|
134 |
+
// ---> Game State Variable <---
|
135 |
+
let gameState = {}; // Initialized in startGame
|
136 |
+
|
137 |
+
// --- Core Functions ---
|
138 |
+
|
139 |
function initThreeJS() {
|
140 |
scene = new THREE.Scene();
|
141 |
scene.background = new THREE.Color(0x1a1a1a);
|
|
|
325 |
return { group, lighting: 'cave', entryText: "It's dark and damp in here.", cameraPos: {x:0, y:4, z:8}, targetPos: {x:0, y:1, z:0} };
|
326 |
}
|
327 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
328 |
function startGame() {
|
329 |
const defaultChar = {
|
330 |
name: "Player",
|
331 |
stats: { hp: 20, maxHp: 20, xp: 0 },
|
332 |
+
inventory: ["Rusty Sword"]
|
333 |
};
|
334 |
gameState = {
|
335 |
currentLocationId: null,
|
|
|
455 |
|
456 |
inventoryElement.querySelectorAll('.item-tag').forEach(tag => {
|
457 |
tag.onclick = (event) => {
|
458 |
+
event.stopPropagation();
|
459 |
togglePlacementMode(tag.dataset.itemname);
|
460 |
};
|
461 |
});
|
|
|
472 |
}
|
473 |
|
474 |
function pickupItem() {
|
475 |
+
if (currentPlacingItem) return;
|
476 |
|
477 |
raycaster.setFromCamera(mouse, camera);
|
478 |
const currentGroup = locationGroups[gameState.currentLocationId];
|
479 |
if (!currentGroup) return;
|
480 |
|
481 |
const pickupables = [];
|
482 |
+
currentGroup.traverseVisible(child => {
|
483 |
if (child.userData.isPickupable) {
|
484 |
pickupables.push(child);
|
485 |
}
|
|
|
547 |
else if(itemDef.type === 'consumable') itemMat.color.setHex(0xaa7744);
|
548 |
else itemMat.color.setHex(0x8888aa);
|
549 |
|
550 |
+
const placedMesh = createMesh(itemGeo, itemMat, {x: point.x, y: 0.25, z: point.z});
|
551 |
+
placedMesh.userData = { isPlacedItem: true, itemName: itemName, isPickupable: true, description: `Placed ${itemName}` };
|
552 |
currentGroup.add(placedMesh);
|
553 |
|
554 |
gameState.character.inventory = gameState.character.inventory.filter(i => i !== itemName);
|