This is a skeleton project for making a MUD with tactical turn based combat. It
uses the tiny
Ranvier project as a base which means it has a basic command parser
a demo area and a handful of example commands.
This project adds the attack
command which is used to initiate combat with an NPC.
The example combat setup is extremely simple:
- A 10x10 blank map is generated
- NPCs are randomly placed in the top half of the map, players are randomly placed in the bottom half
- The
turn-combat
bundle adds the following attributes:attacks
- number of attacks a player/NPC can make per turn. Resets at end of turnmovement
- number of cells a player/NPC can move per turn. Resets at end of turnagility
andinitiative
are used to determine turn order- NPCs can be assigned an AI, if not assigned an AI it will be given the
Idiot
AI which is super dumb
The combat architecture is made up of 3 main parts: The controller, the menu, and the map.
bundles/turn-combat/lib/CombatController.js
This is the thing in charge of everything related to combat. It handles the creation of the map, assignment of characters to teams, turn order, display of the menu, and a central point for handling damage/healing. If you want to start changing things this is the place.
bundles/turn-combat/lib/CombatMenu.js
This handles player input, and display of the map/actions on a player's turn.
The commands
input event
(bundles/tiny-input-events/input-events/commands.js
) is modified to reroute
input to CombatMenu#parseInput
(proxied by CombatController
). That determines
which actions can be used.
bundles/turn-combat/lib/CombatMenu.js
CombatMap
is an extension of AreaFloor
which is just a grid of cells. In
this case instances of CombatCell
. The current setup only creates a map
of free cells. CombatCell
however has support for other types of cells
(walls, water, etc.) Right now doesn't build a walkability layer but will in
the future.
The map will distribute the combat participants along the map. When the map is rendered for a player the characters on the map are represented by a single character (sigil). Enemies are represented by A-Z, friendlies are represented by 0-9, the current player is represented by @. This sigil can be used by the player for targeting.
Represents a single cell in the map. Has the following properties:
?occupant
-Character
currently in the cellsigil
- Symbol used for the map (.
for free,~
for water, etc.) Not to be confused with a participant sigil which will be displayed in place of the cell's sigil when it has an occupant.coordinates
-[x, y]
of that cell
getCellFromSigil(sigil, player): CombatCell
- Given a sigil as described above and a player who is looking at the map determine which cell the sigil representsgetOccupantSigil(player, occupant): string
- Given a player and a participant on the map, determine which participant sigil they should getgetFirstAdjacentEnemy(character): ?Character
- Find the first character of a different team in an adjacent cellfindPath(CombatCell, CombatCell)
- Get the pathfinding path between two cells. The path will include the target cell as the last entry in the path but will not include the starting cell so you may need to remove that cell if you actually want to path between two charactersfindNearestEnemy(Character): ?Character
- Find the nearest other participant on a different team than the given characterfindPathToNearestEnemy(Character): ?{ enemy: Character, path: Array<[x, y]> }
- For a given character pathfind to the nearest enemy. Basically a helper combiningfindNearestEnemy
andfindPath
. The returned path will not include the enemy's cell since the character and the enemy can't occupy the same cell.getDistance(CombatCell, CombatCell): number
- get manhattan distance from cell A to cell B