diff --git a/CMakeLists.txt b/CMakeLists.txt index 7731227..f60cddc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,9 @@ add_library(sacredK SHARED src/mods/mainmenu.cpp src/mods/mapreveal.cpp src/mods/questbook.cpp + src/mods/followers.cpp src/mods/questfail.cpp + src/mods/questgiver.cpp src/mods/questnpc.cpp src/mods/anticheat.cpp src/mods/loadingscreen.cpp diff --git a/docs/quests.md b/docs/quests.md index 84938e3..4ebbbc7 100644 --- a/docs/quests.md +++ b/docs/quests.md @@ -36,11 +36,38 @@ A failed quest is not final: talking to the quest giver again offers it again. `mods/questfail.cpp`: after `Quest_End` with success 0 (its failure -script has run) the quest's flags 1/2/4/8 are cleared and its book entries -removed, as if never triggered; quests failed before the mod are reset once +script has run) the quest's flags 2/4/8 are cleared and flag 1 is kept +(book entry: see below); quests failed before the mod are reset once after loading. Confirmed in the log (the four quests above reset, 2026-10-25); the giver offering them again is still to be tested in the game. +2026-10-26: the restart first cleared flag 1 as well. Measured: a quest's +script labels, its giver's dialog too, run only while flag 1 is set +(Script_RunLabel `0x46bf11`; "Dialog faild" in the game log otherwise), and +accepting it (opcode 0x14, `0x48f320`) needs it too; the game sets it when the +hero enters the quest's region (`Quest_Trigger`). A restarted quest is now +"available": flags 1. + +Marker back to the giver (request 2026-10-25: "quests that failed, should +have the blue marker point back to the quest giver"): + +- Measured: the maps draw a marker for every book entry at its compass cell + +0x18/+0x1c, colour from `0x4975d0` (thiscall (entry, kind), ret 8): open + side quest `ff006cff` (blue), main `ffffff80`, solved green, failed red. + The compass target +0x10/+0x14 is set by the scripts' QuestkompassPos + (`0x49a7a0`: a cell, radius +0x20 "rad:") and QuestkompassOBJ + (`0x49af70`: 0xffffffff + object id, or 0xeeeeeeee + script NPC id); + `0x4a6740` resolves it into +0x18/+0x1c. The game keeps no giver per quest. +- A quest is accepted in a dialog answer (`cDialogManager::Answer` 0x49a090 -> + quest script -> `QuestManager_AddBookEntry` 0x46c450). The mod keeps the map + cell of the NPC nearest to the hero then (within 400) as the giver, saved + with the hero data (`questGivers`: quest id -> cell, merged from save game + and hero file; quest ids and givers are the same in every world). +- On failure the book entry stays (state 101) with its compass on the giver + and is drawn blue; without a known giver it is removed as before (all + quests that failed before this change). Accepting the quest again removes + the failed entry. + ## Quest book (measured 2026-10-25) - Book entries (quest manager +0x424, 0x174 bytes): kind +0 (3 main quest, @@ -151,3 +178,61 @@ exists, is done (flag 0x2) and not in progress (0x4): Dialogs without a quest (healers, closed shops: `geschlossen101`, `heilen_global`) stay as the game has them. + +## Quest scripts (measured 2026-10-26) + +- Code: `binNetScriptFunkCode.bin` (`binAddonNetScript` differs only past + 0x9a653), open as the quest manager's FILE* +4 (`0xaaaf04`). Instructions + {u16 opcode, u16 size with the header, args}; args tagged: 0x01 string, + 0x0b int32, 0x09 dialog, 0x05 label (e.g. a death label), ... Jump table of + the executor `0x475970` at `0x4787b0` (opcode * 4). +- Labels: the script label table (`0xaa9688`, 0x54 bytes; from + `Vectoren.bin`): name, +0x40 code offset, +0x44 code size, +0x48 quest. + `Script_RunLabel` `0x46bd80` (cdecl (label, object, flag)) reads the code + and runs it with `0x475970` (quest manager thiscall (code, &offset, quest, + object, flag, 0), ret 0x18; any memory buffer with offset 0 works). +- Opcodes seen: 1 spawn ("Res: