NPC dialog is stored in a file called ENCONTER.SET.
This is an array of records which defines which NPCs exist, how they move, and what they say. It does not say which map they are a part of. Each record is 147 bytes long
type NPCData = record icon : byte; ai : byte; stackSize : byte; x : byte; y : byte; dialog1 : string; dialog2 : string; end;
The icon corresponds to an index in the sprite sheet for a given level (e.g. if a town then it's TOWNMAN.CON, and a value of 1 corresponds to a merchant, 2 is the guard, etc.
The stack size says how many NPCs will be part of the battle. For example, this is typically 8 (the max) for guards.
The ai byte says how the NPC interacts with the world:
- 0x01 - Hostile (will chase the player)
- 0x04 - Stay still
- 0x05 - Wander
x and y are self explanatory although the top-left corner of the map is (1,1). (The is called out because the intuitive way is to have the top-left as 0,0)
dialog1 and dialog2 always has space for 70 characters, even if the length is smaller. This means the rest of the buffer typically has garbage. It's interesting to note that some of the garbage looks a lot like Pascal (combine that with the fact that the binary appears to has BGI statically linked in suggests that this was coded in Borland Turbo Pascal circa 1989 or before).
Shops utilize the dialog not as text but as specially formatted strings:
- Armor shops look like: ARM XX YY ZZ ... where XX, YY, ZZ .. are 2 character IDs of the armor being sold (see the list of IDs below)
- Weapon shops look like: WPN XX YY ZZ ... where XX, YY, ZZ .. are 2 character IDs of the weapons being sold (see the list of IDs below)
- Pubs look like: PUB X Y Z
- Inns look like: INN X Y Z
- Trainers look like: TRN X Y Z
- Travel agencies look like TNP ID COST
- For special events: SPL X
- X=0x03: judgement by the gods
- X=0x04: blue rose merchant
- x=0x01: ?
- x=0x0A: ?
Text related to the SPL X dialog is compiled into VAMPYR.EXE. This includes:
- King dialog on completing a mission
- Blue Rose merchant
- Rust Armor teacher
How Loading is Done
When the player enters a map, the game has hard-coded contiguous block of entries that it will load for that map.
For example, when Myron is invaded, the game will load records 280-297
I've created a Turbo Pascal 5.5 program to translate the binary into CSV: https://drive.google.com/open?id=16X2H1uXZl5im9DSFrv3elP7gpzKE_ifj