Add item states

master
Kevin Weispfennig 2022-10-26 16:05:20 +02:00
parent f8f4c555b8
commit 8d74237a6d
6 changed files with 377 additions and 348 deletions

2
package-lock.json generated
View File

@ -5,6 +5,7 @@
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "assassin-bug",
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@ -568,7 +569,6 @@
"dependencies": { "dependencies": {
"anymatch": "~3.1.2", "anymatch": "~3.1.2",
"braces": "~3.0.2", "braces": "~3.0.2",
"fsevents": "~2.3.2",
"glob-parent": "~5.1.2", "glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0", "is-binary-path": "~2.1.0",
"is-glob": "~4.0.1", "is-glob": "~4.0.1",

View File

@ -1,56 +1,61 @@
import Item from '../item'; import Item from '../item';
export default class ItemBuilder { export default class ItemBuilder {
constructor() { constructor() {
this.item = new Item(); this.item = new Item();
} }
withID(ID) { withID(ID) {
this.item.id = ID; this.item.id = ID;
return this; return this;
} }
withName(name) { withName(name) {
this.item.name = name; this.item.name = name;
return this; return this;
} }
withDescription(description) { withDescription(description) {
this.item.description = description; this.item.description = description;
return this; return this;
} }
isUsable(value) { withState(key, value) {
this.item.usable = value; this.item.setState(key, value);
return this; return this;
} }
isTakeable(value) { isUsable(value) {
this.item.takeable = value; this.item.usable = value;
return this; return this;
} }
withUseCallback(callback) { isTakeable(value) {
this.item.addUseCallback(callback); this.item.takeable = value;
return this; return this;
} }
withTakeCallback(callback) { withUseCallback(callback) {
this.item.addTakeCallback(callback); this.item.addUseCallback(callback);
return this; return this;
} }
withDropCallback(callback) { withTakeCallback(callback) {
this.item.addDropCallback(callback); this.item.addTakeCallback(callback);
return this; return this;
} }
withTickCallback(callback) { withDropCallback(callback) {
this.item.addTickCallback(callback); this.item.addDropCallback(callback);
return this; return this;
} }
create() { withTickCallback(callback) {
return this.item; this.item.addTickCallback(callback);
} return this;
}
create() {
return this.item;
}
} }

View File

@ -1,160 +1,160 @@
import State from './state'; import State from './state';
import Room from './room'; import Room from './room';
import Player from './player'; import Player from './player';
import Output from './output'; import Output from './output';
import Input from './input'; import Input from './input';
import Commands from './commands'; import Commands from './commands';
import Serialization from './serialization'; import Serialization from './serialization';
export default class Game { export default class Game {
constructor(newGame = true) { constructor(newGame = true) {
this.newGame = newGame; this.newGame = newGame;
this.player = new Player(); this.player = new Player();
this.state = State; this.state = new State();
this.rooms = []; this.rooms = [];
this.items = []; this.items = [];
this.output = new Output(); this.output = new Output();
this.commandHandler = new Commands(this); this.commandHandler = new Commands(this);
this.input = new Input(this.commandHandler, this.output); this.input = new Input(this.commandHandler, this.output);
this.visitedRooms = new Map(); this.visitedRooms = new Map();
this.interval = null; this.interval = null;
this.Serialization = new Serialization(this); this.Serialization = new Serialization(this);
} }
print(string) { print(string) {
this.output.say(string); this.output.say(string);
} }
async tell(lines, time) { async tell(lines, time) {
for (let line of lines) { for (let line of lines) {
this.print(line); this.print(line);
await this.wait(time); await this.wait(time);
} }
} }
init(data) { init(data) {
this.rooms = data.rooms.map((room) => { this.rooms = data.rooms.map((room) => {
room.context = this; room.context = this;
return room; return room;
}); });
this.items = data.items.map((item) => { this.items = data.items.map((item) => {
item.context = this; item.context = this;
return item; return item;
}); });
this.state = data.state || State; this.state = data.state || new State();
this.commandHandler.addCommands(data.commands); this.commandHandler.addCommands(data.commands);
this.player = new Player(); this.player = new Player();
this.player.context = this; this.player.context = this;
if (this.newGame) { if (this.newGame) {
this.move(this.player.currentRoom); this.move(this.player.currentRoom);
} else { } else {
this.Serialization.load(); this.Serialization.load();
} }
this.start(); this.start();
} }
advanceTick() { advanceTick() {
this.items.forEach((item) => item.onTick()); this.items.forEach((item) => item.onTick());
this.rooms.forEach((room) => room.onTick()); this.rooms.forEach((room) => room.onTick());
} }
start() { start() {
this.interval = setInterval(() => this.advanceTick(), 1000); this.interval = setInterval(() => this.advanceTick(), 1000);
} }
stop() { stop() {
clearInterval(this.interval); clearInterval(this.interval);
this.interval = null; this.interval = null;
} }
examineRoom() { examineRoom() {
const room = this.getRoom(this.player.currentRoom); const room = this.getRoom(this.player.currentRoom);
this.output.say(room.title); this.output.say(room.title);
if (!this.visitedRooms.get(this.player.currentRoom) && room.firstDescription != "") { if (!this.visitedRooms.get(this.player.currentRoom) && room.firstDescription != "") {
this.output.say(room.firstDescription); this.output.say(room.firstDescription);
} else { } else {
this.output.say(room.description); this.output.say(room.description);
} }
this.examineItems(); this.examineItems();
this.examineExits(); this.examineExits();
} }
examineItems() { examineItems() {
const room = this.getRoom(this.player.currentRoom); const room = this.getRoom(this.player.currentRoom);
const items = room.getItems(); const items = room.getItems();
if (items.length < 1) return; if (items.length < 1) return;
let itemDescription = `You see `; let itemDescription = `You see `;
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
} }
}); });
this.output.say(itemDescription + "."); this.output.say(itemDescription + ".");
} }
examineExits() { examineExits() {
const room = this.getRoom(this.player.currentRoom); const room = this.getRoom(this.player.currentRoom);
let exits = []; let exits = [];
let exitDescription = "You can go "; let exitDescription = "You can go ";
const exitKeys = room.exits.keys(); const exitKeys = room.exits.keys();
for (let exit of exitKeys) { for (let exit of exitKeys) {
exits.push(exit); exits.push(exit);
} }
exits.forEach((item, index) => { exits.forEach((item, index) => {
if (index < exits.length - 2) { if (index < exits.length - 2) {
exitDescription += `${item}, `; exitDescription += `${item}, `;
} else if (index < exits.length - 1) { } else if (index < exits.length - 1) {
exitDescription += `${item} and `; exitDescription += `${item} and `;
} else { } else {
exitDescription += item exitDescription += item
} }
}); });
this.output.say(exitDescription + "."); this.output.say(exitDescription + ".");
} }
getRoom(id) { getRoom(id) {
return this.rooms.find((room) => room.id == id); return this.rooms.find((room) => room.id == id);
} }
getItem(id) { getItem(id) {
return this.items.find((item) => item.id == id); return this.items.find((item) => item.id == id);
} }
wait(ms) { wait(ms) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
setTimeout(resolve, ms); setTimeout(resolve, ms);
}); });
} }
async move(roomID) { async move(roomID) {
const currentRoom = this.getRoom(this.player.currentRoom); const currentRoom = this.getRoom(this.player.currentRoom);
const newRoom = this.getRoom(roomID); const newRoom = this.getRoom(roomID);
if (currentRoom.canExit() && newRoom.canEnter()) { if (currentRoom.canExit() && newRoom.canEnter()) {
await currentRoom.onExit(); await currentRoom.onExit();
await newRoom.onEnter(); await newRoom.onEnter();
this.player.currentRoom = roomID; this.player.currentRoom = roomID;
this.examineRoom(); this.examineRoom();
this.visitedRooms.set(roomID, true); this.visitedRooms.set(roomID, true);
} }
} }
enableCommandInput(value) { enableCommandInput(value) {
this.commandHandler.enabled = value; this.commandHandler.enabled = value;
} }
setInputEcho(value) { setInputEcho(value) {
this.input.setEcho(value); this.input.setEcho(value);
} }
save() { save() {
this.Serialization.save(); this.Serialization.save();
} }
load() { load() {
this.Serialization.load(); this.Serialization.load();
} }
} }

View File

@ -1,45 +1,56 @@
export default class Item { import State from "./state";
constructor() {
this.id = "item"; export default class Item {
this.name = "An item"; constructor() {
this.description = "You see nothing special about this item"; this.id = "item";
this.usable = true; this.name = "An item";
this.takeable = true; this.description = "You see nothing special about this item";
this.useCallback = null; this.state = new State();
this.takeCallback = null; this.usable = true;
this.dropCallback = null; this.takeable = true;
this.tickCallback = null; this.useCallback = null;
this.context = null; this.takeCallback = null;
} this.dropCallback = null;
this.tickCallback = null;
async onUse() { this.context = null;
if (this.useCallback) return this.useCallback(this.context); }
}
async onUse() {
async onTake() { if (this.useCallback) return this.useCallback(this.context);
if (this.takeCallback) return this.takeCallback(this.context); }
}
async onTake() {
async onDrop() { if (this.takeCallback) return this.takeCallback(this.context);
if (this.dropCallback) return this.dropCallback(this.context); }
}
async onTick() { async onDrop() {
if (this.tickCallback) return this.tickCallback(this.context); if (this.dropCallback) return this.dropCallback(this.context);
} }
async onTick() {
addUseCallback(callback) { if (this.tickCallback) return this.tickCallback(this.context);
this.useCallback = callback.bind(this); }
}
addUseCallback(callback) {
addTakeCallback(callback) { this.useCallback = callback.bind(this);
this.takeCallback = callback.bind(this); }
}
addTakeCallback(callback) {
addDropCallback(callback) { this.takeCallback = callback.bind(this);
this.dropCallback = callback.bind(this); }
}
addDropCallback(callback) {
addTickCallback(callback) { this.dropCallback = callback.bind(this);
this.tickCallback = callback.bind(this); }
}
addTickCallback(callback) {
this.tickCallback = callback.bind(this);
}
setState(key, value) {
return this.state.set(key, value);
}
getState(key) {
return this.state.get(key);
}
} }

View File

@ -1,52 +1,67 @@
export default class Serialization { export default class Serialization {
constructor(context) { constructor(context) {
this.context = context; this.context = context;
} }
save() { save() {
const saveobj = { const saveobj = {
state: this.context.state.serialize(), state: this.context.state.serialize(),
itemLocations: this.serializeItemLocations(), itemLocations: this.serializeItemLocations(),
player: { itemStates: this.serializeItemStates(),
currentRoom: this.context.player.currentRoom, player: {
inventory: this.context.player.inventory currentRoom: this.context.player.currentRoom,
}, inventory: this.context.player.inventory
volumes: { },
music: this.context.output.sound.musicVolume, volumes: {
sfx: this.context.output.sound.sfxVolume, music: this.context.output.sound.musicVolume,
ambience: this.context.output.sound.ambienceVolume sfx: this.context.output.sound.sfxVolume,
} ambience: this.context.output.sound.ambienceVolume
}; }
localStorage.setItem("save", JSON.stringify(saveobj)); };
} localStorage.setItem("save", JSON.stringify(saveobj));
}
load() {
const loadobj = JSON.parse(localStorage.getItem("save")); load() {
this.context.state.deserialize(loadobj.state); const loadobj = JSON.parse(localStorage.getItem("save"));
this.deserializeItemLocations(loadobj.itemLocations); this.context.state.deserialize(loadobj.state);
this.deserializePlayer(loadobj.player); this.deserializeItemLocations(loadobj.itemLocations);
this.context.output.sound.setSFXVolume(loadobj.volumes.sfx); this.deserializeItemStates(loadobj.itemStates);
this.context.output.sound.setMusicVolume(loadobj.volumes.music); this.deserializePlayer(loadobj.player);
this.context.output.sound.setAmbienceVolume(loadobj.volumes.ambience); this.context.output.sound.setSFXVolume(loadobj.volumes.sfx);
} this.context.output.sound.setMusicVolume(loadobj.volumes.music);
this.context.output.sound.setAmbienceVolume(loadobj.volumes.ambience);
serializeItemLocations() { }
return this.context.rooms.map((item) => {
return [item.id, serializeItemLocations() {
item.objects return this.context.rooms.map((item) => {
] return [item.id,
}); item.objects
} ]
});
deserializeItemLocations(items) { }
items.forEach((item) => {
const room = this.context.getRoom(item[0]); deserializeItemLocations(items) {
room.objects = item[1]; items.forEach((item) => {
}) const room = this.context.getRoom(item[0]);
} room.objects = item[1];
})
deserializePlayer(player) { }
this.context.move(player.currentRoom);
this.context.player.inventory = player.inventory; deserializeItemStates(items) {
} items.forEach((item) => {
const obj = this.context.getItem(item[0]);
obj.state.deserialize(item[1]);
})
}
deserializePlayer(player) {
this.context.move(player.currentRoom);
this.context.player.inventory = player.inventory;
}
serializeItemStates() {
return this.context.items.map((item) => {
return [item.id, item.state.serialize()]
});
}
} }

View File

@ -1,38 +1,36 @@
class State { export default class State {
constructor() { constructor() {
this.states = new Map(); this.states = new Map();
} }
get(key, defaultValue = null) { get(key, defaultValue = null) {
if (!this.states.has(key)) { if (!this.states.has(key)) {
this.states.set(key, defaultValue); this.states.set(key, defaultValue);
return defaultValue; return defaultValue;
} }
return this.states.get(key); return this.states.get(key);
} }
set(key, value) { set(key, value) {
return this.states.set(key, value); return this.states.set(key, value);
} }
change(key, amount = 1) { change(key, amount = 1) {
let val = this.get(key, 0); let val = this.get(key, 0);
val += amount; val += amount;
this.set(key, val); this.set(key, val);
} }
serialize() { serialize() {
const entries = this.states.entries(); const entries = this.states.entries();
const entrymap = []; const entrymap = [];
for (let state of entries) { for (let state of entries) {
entrymap.push(state); entrymap.push(state);
} }
return entrymap; return entrymap;
} }
deserialize(data) { deserialize(data) {
this.states = new Map(data); this.states = new Map(data);
} }
} }
export default new State();