Skip to content

NPCs talk from their data: talk fields, steps and the NPC rules tools (PR 3c, MN5) - #175

Merged
Mosch0512 merged 3 commits into
mainfrom
feat/npc-rules
Nov 13, 2026
Merged

Mosch0512 merged 3 commits into
mainfrom
feat/npc-rules

Conversation

@Mosch0512

@Mosch0512 Mosch0512 commented Nov 11, 2026 •

Copy link
Copy Markdown
Owner

PR 3c of the data-driven monsters (MN5, D66, Q-MN46 to Q-MN48): what the client does when the hero talks to an NPC now comes from the NPC's entry in Data/Monsters/Monsters.json, not from the number and model checks in MOVEMENT_TALK. The map rules that stay code (the Crywolf altar contract, Kanturu 2nd's entrance, the Illusion Temple's NPCs) are called from the data.

Before the move, the talk code went through GameLogic::Npcs::Talk and a TalkWorld whose side effects are std::functions (D50). A recorder test (tests/monsters/test_npc_talk.cpp) records what each NPC does (talk requests, dialogs and their OK result, messages, repair buttons, quest window, pet info) and stayed the same through the move, except for the decided changes below.

The talk fields

"talkLevel": {"level": 10, "message": {"en": "Only level above %d can do the Chaos Combination."}},
"onTalk": [
  {"dialog": {"title": {"en": "Werewolf Guardsman"}, "lines": [{"en": "..."}],
              "ok": {"request": "enterRefuge", "if": {"quest": "thirdChangeUp2", "is": ["ongoing", "done"]},
                     "zen": 3000000, "failure": {"en": "You are short of Zen."}}}},
  {"send": "talk"}
]
  • talks: false for the Wolf Status 204, the only NPC that does not talk.
  • talkLevel: the level the hero needs (the Chaos Goblin 238) and the message below it, with %d for the level. Below it the hero keeps the NPC as the target, as before.
  • repairShop: the shop shows the repair buttons (243, 246, 251, 416, 578).
  • onTalk: the steps, in order. send (talk, petInfo), dialog (title, lines, an OK that sends enterRefuge or enterBarracks when a quest is in one of the given states and the hero has the zen, else its failure text), message (the red and blue Little Santas), questWindow (noQuestTitleFor: Marlon 229 for the Dark Lord, Magic Gladiator and Rage Fighter) and crywolfAltarContract (the altars 205-209; it names its texts in the shared talkTexts, see below). Without onTalk the NPC sends the talk request.
  • crywolfContract: the 0x07 rule for a Crywolf hero contract that is already shown now reads this field on 13 entries (the altars, 226, 230, 240, 248, 250, 251, 256, 478) instead of a list of models.

All texts are translatable like the names, copied from the game's texts in the 11 languages that have them (the game's own zh-CN texts have none of them yet, so Data Checks warns about each). bCheckNPC became a list of class indexes.

Shared talk texts and Crywolf's elf time

  • Texts several NPCs share are defined once, by name, in a new talkTexts section of Monsters.json. The five altars' step is {"crywolfAltarContract": "crywolfAltar"}; a name the list does not have, or a set missing a text, is fatal.
  • While only elves may make the altar contracts, the new state crywolfElfTime is on. The altar step makes its contract then, and the Werewolf Guardsman 407 has a state variant that only talks; the talk code has no special rule for that time.
  • Data Checks also warns about an OK whose quest has no state in is and about an altar step on a model that is no Crywolf altar (it only talks), and reports a step naming a set that is not there. Monster Setup keeps a set a step names (its x is disabled).

Changes in behaviour (one commit each, or decided)

  • P23: a Little Santa's message is formatted whole; on Windows the red and blue Santas' messages wrote past a 32-character buffer in de, en, es, pl and tl.
  • The six Little Santas without a message no longer log an empty system line.
  • The Gatekeeper dialog belongs to the Gatekeeper 408; before, every NPC on the Balgass barracks map showed it (D66).
  • The Delgado, Lugard, Julia and David list that skipped the map rules is gone (D66).

Editor

  • Monster Setup: a new section NPC rules with talks, the minimum level and its message, repairShop, crywolfContract and On talk, in order: a row per step with its kind and values (a dialog's title and lines, OK sends a request with its request, quest, states, zen and failure text; a message; a quest window's classes; the altar contract's texts), with Move up, Move down, x and Add a step.
  • Monster Setup: a Shared talk texts section edits the sets (English, Add a set, x); the altar step picks its set. A dialog OK with a quest and no state ticked shows a red hint.
  • Monster Translations: the names table and a new Talk texts tab, a row per text (the shared sets first, then "408 onTalk[1].dialog.lines[0]", map and state variants included) with a column per language and the missing-language filter.
  • Data Checks: warns about a talk text missing one of the game's languages.

Texts in English and German; docs/monster-data.md has a new section "Talking to NPCs". The MN5 row of the design doc is updated.

Tests

  • New: test_npc_talk.cpp (the recorder, each quest's own state), talk fields and talkTexts in the setup JSON tests, the step editor, the Talk texts rows (variants and shared sets), the warnings, and a check that the shipped crywolfContract entries are exactly the old code's models.
  • Release x64 editor build, ctest -C Release: 3175 of 3180 pass. The five failures are not from this PR: ci_build_plan (this machine blocks PowerShell scripts), ensure_submodule_leaves_history_out (a file:// path problem with this machine's git) and the three test_connection_library_load entries: that test, from fix(network): load the network library at startup, not during static initialisation sven-n/MuMain#1097, does not link in the editor build here (g_hWnd, g_iNoMouseTime and others unresolved).
  • clang-format 21.1.8 on the changed lines.
  • Not tried in game yet, and not run on Linux for this PR.

… rules tools (MN5)

What the client does when the hero talks to an NPC now comes from the NPC's entry in Data/Monsters/Monsters.json instead of the number and model checks in MOVEMENT_TALK (D66, Q-MN46 to Q-MN48). Talk goes through GameLogic::Npcs::Talk and a TalkWorld, recorded by tests/monsters/test_npc_talk.cpp (D50).

- Talk fields: talks, talkLevel (with "%d"), repairShop, crywolfContract (the 0x07 Crywolf hero contract rule, on the 13 entries the old model list named) and onTalk, the steps in order: send talk or petInfo, dialog (title, lines, an OK sending enterRefuge or enterBarracks by quest state and zen), message, questWindow (noQuestTitleFor) and crywolfAltarContract.
- Shared talk texts: a talkTexts section; the five Crywolf altars' step names the set crywolfAltar. Crywolf's elf time is the state crywolfElfTime; the Werewolf Guardsman 407 only talks then by his state variant.
- Texts translatable like the names, copied from the game's texts in its 11 languages that have them.
- Fixes: P23 (a Little Santa's message overflowed its buffer), the six Little Santas without a message no longer log an empty line. The Gatekeeper dialog is 408's own, and the Delgado/Lugard/Julia/David list is gone (D66).
- Editor: Monster Setup's NPC rules section and step editor, a Shared talk texts section, Monster Translations' Talk texts tab, and Data Checks warnings (missing languages, an OK quest without a state, an altar step on another model or naming no set).
- Docs: docs/monster-data.md "Talking to NPCs" and "Shared talk texts".
…f calling Set

MonsterDatabase::Set is editor-only, so the Linux and macOS editor-OFF builds failed on test_npc_talk.cpp. The test now builds the database from a changed copy of the shipped list and builds the shipped one back however it ends.
…iterator

OnTalk bound [kind, content] to *row.items().begin(); nlohmann's iterator returns a reference to itself, so the names referred into a temporary that ended with the line. libstdc++ happened to survive it, but on macOS (libc++) every test reading the shipped monster list crashed. The step's key and value are now read from row.begin() into a string and a reference into the row.
@Mosch0512
Mosch0512 merged commit 1893e8e into main Nov 13, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant