DragonWarriorJS
DragonWarriorJS copied to clipboard
A Dragon Warrior clone written in JavaScript.
DragonWarriorJS - A recreation of Dragon Warrior for the NES in TypeScript
Like it says on the tin. This reproduction will try to be as authentic as possible, warts and all.
What's (mostly) done:
- Map loading, motion, moving in and out of towns
- Collision detection
- Conversations with NPCs
- Sound (uses WebAudio, so Firefox and Chrome only for now)
What's currently being worked on (half-baked):
- Staying overnight at an inn
- Buying goods from a shop
- Battling an enemy
To test this out
npm install
npm run watch
# View http://localhost:8080
Editing the Map Data
In theory, once the engine is done, this game is mostly data-driven. Most of the data is in map files.
Tiled is used to create the maps for this game.
The actual data files live in src/tiled. There is one .tmx file per map
in the game, including the overworld. Please be sure to use the latest
version of Tiled when editing these files, as the XML schema of the .tmx
file format changes over time. The game is currently being built using 1.8.4.
All maps follow the same conventions and structure. Layers include:
tileLayer- The actual map graphics. Constitutes most of what you see.tileLayer2(optional) - A second layer of tiles. Used for the inside of buildings with roofs in towns. Where there are roofed buildings,tileLayerwill render the roof tile, andtileLayer2will render the inside of the building. This layer is omitted when it is not needed.collisionLayer- Dictates which tiles are solid and which aren't. This layer is currently used for bothtileLayerandtileLayer2. Solid tiles can be rendered with thecollisiontileset by entering a debug key combination in the game.warpLayer- A layer containing objects oftypewarp.warps are used to travel from map to map, and require the following custom properties:map- The map to warp torow- The row at which to place the herocol- The column at which to place the herodir(optional) - The direction the hero should face. Should be one ofnorth,east,south, orwest
npcLayer- A layer containing objects oftypenpc,talkAcrossanddoor.npcobjects should have the following custom properties:type- One of the values in NpcType.ts. Case is ignored. Thenameproperty of eachnpcis used as a lookup for the NPC's conversation (see below).wanders- Eithertrueorfalse, depending on whether you want the NPC to movedir(optional) - The direction the hero should initially face. Should be one ofnorth,east,south, orwest. Note you don't usually need to set this unlesswandersisfalse.
talkAcrossis an object type innpcLayerused to mark solid tiles the hero should be able to talk over, such as tables to chat with a merchant. Objects of typetalkAcrosscurrently have no custom properties.- The
doorobject type denotes a door that can be opened, e.g. with a key. They have the following custom properties:replacementTileIndex- The tile that should replace the door tile once the door has been opened.
enemyTerritoryLayer(optional) - If defined, this layer describes enemy groups. A non-empty tile type denotes an enemy group that the hero may randomly fight when stepping in it. If this layer does not exist, no random battles occur in the map (e.g. in towns).
The Tiled project lives in src/res/maps. All data is stored in .json files
instead of .tmx for simplicity.
Editing NPC Conversations
NPC's as defined in npcLayer above have their conversations defined in "map
logic" files that live in
src/app/dw/mapLogic.
There is one map logic file per map. They all follow the same pattern. Essentially, an object maps
each npc's name property to a generator function that returns the
NpcText
(i.e., the conversation that NPC will have with the hero) for that NPC. This function is passed the
game instance so that it can dynamically return different values depending on how far along the
player is.
The NpcText itself can be simple or complex, depending on how complex the NPC's conversation
with the hero should be. Essentially, it can be:
- A string, in which case the NPC says just that. This is the simple case
- An array of strings, in which case each string is rendered, but the user has to press a key to advance the conversation between each string
- An array containing a mixture of strings and
ConversationSegmentArgs, which allow for
logic in a conversation (question/answer, give/take money, etc.). This type
of conversation data is not well doc'd yet and is best observed by example
in the source. It's essentially a grab-bag of optional fields that are each
used in certain conditions.
- Note that
ConversationSegmentArgscan denote a "special" conversation type, as described by theconversationTypeproperty. If this property is defined, it must currently be set to eitherinnkeeperormerchant. In these cases, the logic for staying at an inn or purchasing items is automatically applied.
- Note that