- Project page
- Tutorial[1]
- Repo[2]
Part 13 is about equipment.
I decided that equipment will be a location. It’s now:
{type: 'void'}
| {type: 'map', x: number, y: number}
| {type: 'held', by: number}
| {type: 'equipped', by: number, slot: 'weapon'|'armor'}
Equippable items have a component {slot: string, bonusAttack: number, bonusDefense: number}.
If entity 1 is holding a dagger, that dagger’s location will be {type: 'equipped', by: 1, slot: 'weapon'}.
Ideally the database index would prevent more than one dagger from being held by the same entity in the same slot. But we don’t want to make the location index unique, because that would prevent more than one item from being on a map tile or in inventory. It turns out databases support a partial index[3] which would solve this problem, but I decided not to implement it.
To equip an item means it goes from location {type: 'held', by: $id} to {type: 'equipped', by: $id, slot: entity.equippable.slot}. To unequip an item is the reverse — it goes into inventory. But you can also drop an equipped item, and its location becomes {type: 'map', x: player.location.x, y: player.location.y}.
I like the data model here but there were times I wanted to query for things that were in inventory or equipped, and my Table class doesn’t support that type of query.
I added an equipped spreadsheet formula column that returns all equipped items. This is a table query for {type: 'equipped', by: player.id, slot: ANY}, so I added support for “ANY” in the query system.
Here’s the game at the end of Part 13. You can try equipping/unequpping a weapon by editing the location to be held by 1 or equipped by 1 as weapon. This was a fun project. I think I kept the scope just barely within my limits. I learned a lot, and I’m glad I finished.