Add dynamic item support

master
Talon 2024-03-22 18:23:46 +01:00
parent 2837263abd
commit ad6420e3a9
8 changed files with 134 additions and 79 deletions

View File

@ -11,8 +11,8 @@ export default function DropCommand(args, context) {
if (!item) { if (!item) {
context.print(`You're not carrying a ${args[1]}`); context.print(`You're not carrying a ${args[1]}`);
} else { } else {
context.player.removeItem(item.id); context.player.removeItem(item.getID());
room.addItem(item.id); room.addItem(item.getID());
context.print(`You set ${item.name} down on the floor.`); context.print(`You set ${item.name} down on the floor.`);
item.onDrop(); item.onDrop();
} }

View File

@ -1,15 +1,15 @@
export default function InventoryCommand(args, context) { export default function InventoryCommand(args, context) {
const items = context.player.getInventory(); const items = context.player.getInventory();
if (items.length < 1) return context.print(`You're not carrying anything.`); if (items.length < 1) return context.print(`You're not carrying anything.`);
let itemDescription = `You are carrying `; let itemDescription = `You are carrying `;
items.forEach((item, index) => { items.forEach((item, index) => {
if (index < items.length - 2) { if (index < items.length - 2) {
itemDescription += `${item.name}, `; itemDescription += `${item.name}, `;
} else if (index < items.length - 1) { } else if (index < items.length - 1) {
itemDescription += `${item.name} and `; itemDescription += `${item.name} and `;
} else { } else {
itemDescription += item.name itemDescription += item.name
} }
}); });
context.print(itemDescription + "."); context.print(itemDescription + ".");
} }

View File

@ -121,7 +121,7 @@ export default class Game {
} }
getItem(id) { getItem(id) {
return this.items.find((item) => item.id == id); return this.items.find((item) => item.getID() == id);
} }
wait(ms) { wait(ms) {

View File

@ -14,6 +14,8 @@ export default class Item {
this.dropCallback = null; this.dropCallback = null;
this.tickCallback = null; this.tickCallback = null;
this.context = null; this.context = null;
this.dynamic = false;
this.dynamicID = null;
} }
async onUse() { async onUse() {
@ -54,4 +56,32 @@ export default class Item {
getState(key) { getState(key) {
return this.state.get(key); return this.state.get(key);
} }
clone() {
const clonedItem = new Item();
clonedItem.id = this.id;
clonedItem.name = this.name;
clonedItem.description = this.description;
clonedItem.type = this.type;
clonedItem.state = new State();
clonedItem.usable = this.usable;
clonedItem.takeable = this.takeable;
if (this.useCallback) clonedItem.useCallback = this.useCallback.bind(clonedItem);
if (this.takeCallback) clonedItem.takeCallback = this.takeCallback.bind(clonedItem);
if (this.dropCallback) clonedItem.dropCallback = this.dropCallback.bind(clonedItem);
if (this.tickCallback) clonedItem.tickCallback = this.tickCallback.bind(clonedItem);
clonedItem.context = this.context;
clonedItem.dynamic = true;
clonedItem.dynamicID = generateUniqueID();
this.context.items.push(clonedItem);
return clonedItem;
}
getID() {
return this.dynamic ? this.dynamicID : this.id;
}
}
function generateUniqueID() {
return `dynamic_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
} }

View File

@ -1,19 +1,20 @@
export default class Player { export default class Player {
constructor() { constructor() {
this.inventory = []; this.inventory = [];
this.currentRoom = "start"; this.currentRoom = "start";
this.context = null; this.context = null;
} }
addItem(id) { addItem(id) {
this.inventory.push(id); console.log(`Adding item ${id} to player inv`);
} this.inventory.push(id);
}
removeItem(id) {
this.inventory = this.inventory.filter((item) => item != id); removeItem(id) {
} this.inventory = this.inventory.filter((item) => item != id);
}
getInventory() {
return this.inventory.map((item) => this.context.getItem(item)); getInventory() {
} return this.inventory.map((item) => this.context.getItem(item));
}
} }

View File

@ -6,6 +6,7 @@ export default class Serialization {
save() { save() {
const saveobj = { const saveobj = {
state: this.context.state.serialize(), state: this.context.state.serialize(),
dynamics: this.serializeDynamicItems(),
itemLocations: this.serializeItemLocations(), itemLocations: this.serializeItemLocations(),
itemStates: this.serializeItemStates(), itemStates: this.serializeItemStates(),
player: { player: {
@ -24,6 +25,7 @@ export default class Serialization {
load() { load() {
const loadobj = JSON.parse(localStorage.getItem("save")); const loadobj = JSON.parse(localStorage.getItem("save"));
this.context.state.deserialize(loadobj.state); this.context.state.deserialize(loadobj.state);
this.deserializeDynamicItems(loadobj.dynamics);
this.deserializeItemLocations(loadobj.itemLocations); this.deserializeItemLocations(loadobj.itemLocations);
this.deserializeItemStates(loadobj.itemStates); this.deserializeItemStates(loadobj.itemStates);
this.deserializePlayer(loadobj.player); this.deserializePlayer(loadobj.player);
@ -61,7 +63,20 @@ export default class Serialization {
serializeItemStates() { serializeItemStates() {
return this.context.items.map((item) => { return this.context.items.map((item) => {
return [item.id, item.state.serialize()] return [item.getID(), item.state.serialize()]
}); });
} }
serializeDynamicItems() {
return this.context.items.filter((item) => item.dynamic).map((item) => [item.id, item.dynamicID]);
}
deserializeDynamicItems(items) {
items.forEach((item) => {
const base = this.context.getItem(item[0]);
const cloned = base.clone();
cloned.dynamicID = item[1];
this.context.items.push(cloned);
})
}
} }

View File

@ -1,10 +1,18 @@
import ItemBuilder from "../../engine/builders/item"; import ItemBuilder from "../../engine/builders/item";
import Item from "../../engine/item"; import Item from "../../engine/item";
export default new ItemBuilder() export default new ItemBuilder()
.withID("cup") .withID("cup")
.withName("a cup") .withName("a cup")
.withDescription("A standard coffee cup") .withDescription("A standard coffee cup")
.isTakeable(true) .isTakeable(true)
.isUsable(false) .isUsable(true)
.withUseCallback((context) => {
const item = context.getItem("cup");
const cloned = item.clone();
cloned.name = 'A cloned cup';
console.log(cloned);
context.player.addItem(cloned.dynamicID);
context.print("You touch the cup and a new one somehow appears in your inventory.");
})
.create(); .create();

View File

@ -1,35 +1,36 @@
import RoomBuilder from '../../../engine/builders/room'; import RoomBuilder from '../../../engine/builders/room';
export default new RoomBuilder() export default new RoomBuilder()
.withID("start") .withID("start")
.withTitle("A small spherical alcove") .withTitle("A small spherical alcove")
.withFirstDescription( .withFirstDescription(
`You find yourself in a small, spherical alcove. It feels cold and dark, save from a dim glow which seems to be eluminating the area from the north. `You find yourself in a small, spherical alcove. It feels cold and dark, save from a dim glow which seems to be eluminating the area from the north.
The surface appears to be unnaturally smooth, as if melted away using acidic means. It's warm to the touch.` The surface appears to be unnaturally smooth, as if melted away using acidic means. It's warm to the touch.`
) )
.withDescription( .withDescription(
`A spherical alcove. The smooth surface appears to be melted away using acidic means. There's a dim glow shining in from the north.` `A spherical alcove. The smooth surface appears to be melted away using acidic means. There's a dim glow shining in from the north.`
) )
.withExit("north", "tunnel1") .withExit("north", "tunnel1")
.withEnterCallback(async function(context) { .withEnterCallback(async function(context) {
if (context.state.get("start.awoken")) return; if (context.state.get("start.awoken")) return;
const { output, wait } = context; const { output, wait } = context;
context.enableCommandInput(false); context.enableCommandInput(false);
await context.tell([ // await context.tell([
"You slowly wake up.", // "You slowly wake up.",
"you're not sure if you were ever conscious about waking up, but right now, you're clearly aware that you were previously asleep.", // "you're not sure if you were ever conscious about waking up, but right now, you're clearly aware that you were previously asleep.",
"In fact, a lot of your thoughts seem foreign to you.", // "In fact, a lot of your thoughts seem foreign to you.",
"You're not sure how to feel about this.", // "You're not sure how to feel about this.",
"God the headache...", // "God the headache...",
"OK, time to think about this.", // "OK, time to think about this.",
"Huh, something else you never did before.", // "Huh, something else you never did before.",
"Where are you?", // "Where are you?",
"You reach up and touch your head.", // "You reach up and touch your head.",
"OK, that seems to be in order. Your antennae are still there, your mouth parts seem in tact...", // "OK, that seems to be in order. Your antennae are still there, your mouth parts seem in tact...",
"Hmm. All this is strange.", // "Hmm. All this is strange.",
"No use sitting around. You get up and slowly examine your surroundings." // "No use sitting around. You get up and slowly examine your surroundings."
], 3000); // ], 3000);
context.enableCommandInput(true); context.enableCommandInput(true);
context.state.set("start.awoken", true); context.state.set("start.awoken", true);
}) })
.withItem("cup")
.create(); .create();