From bcdd6cc532bb9ca0d36fd4adec1c3570df93ca25 Mon Sep 17 00:00:00 2001 From: Gerkinfeltser Date: Fri, 29 May 2026 08:08:53 -0500 Subject: [PATCH] feat: add quest journal prompt template and decorator test section --- .../character_bio/0610_party_quests.prompt | 40 ++++++ .../0600_quest_gamesystem_decorators.prompt | 114 ++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 SKSE/Plugins/SkyrimNet/prompts/submodules/character_bio/0610_party_quests.prompt diff --git a/SKSE/Plugins/SkyrimNet/prompts/submodules/character_bio/0610_party_quests.prompt b/SKSE/Plugins/SkyrimNet/prompts/submodules/character_bio/0610_party_quests.prompt new file mode 100644 index 0000000000..ed2be6ef21 --- /dev/null +++ b/SKSE/Plugins/SkyrimNet/prompts/submodules/character_bio/0610_party_quests.prompt @@ -0,0 +1,40 @@ +{% if render_mode == "full" or render_mode == "thoughts" or render_mode == "transform" %} +{% if is_follower(actorUUID) or actorUUID == player.UUID %} +{% set tracked_quests = get_selected_quests() %} +{% set journal = get_quest_journal() %} +{% set show_misc_tasks = show_misc_tasks | default(true) %} +{% set show_inactive_quests = show_inactive_quests | default(false) %} +{% if length(tracked_quests) > 0 %} +{% if is_follower(actorUUID) %}## {{ player.name }}'s Party's Active Quests{% else %}## Active Quests{% endif %} +(Quests remain available indefinitely unless explicitly stated otherwise. Do NOT create urgency, invent deadlines, or repeatedly remind about objectives.) +{% for quest in tracked_quests %} +{% for jq in journal %}{% if jq.editorID == quest.editorID %} +{% if jq.journalText and not jq.isMisc %} +**{{ jq.questName }}** +{{ jq.journalText }} +{% for obj in jq.objectives %}{% if obj.displayed %}{% if obj.completed %} +- {{ obj.text }} [DONE]{% elif not obj.failed %} +- {{ obj.text }}{% endif %}{% endif %}{% endfor %} + +{% endif %} +{% endif %}{% endfor %} +{% endfor %} +{% if show_inactive_quests %} +{% for jq in journal %}{% if jq.inQuestLog %}{% if jq.journalText %} +**{{ jq.questName }}** (inactive) +{{ jq.journalText }} +{% endif %}{% endif %}{% endfor %} +{% endif %} +{% if show_misc_tasks %} +### Misc. Tasks +{% for quest in tracked_quests %} +{% for jq in journal %}{% if jq.editorID == quest.editorID %}{% if jq.isMisc %}{% for obj in jq.objectives %}{% if obj.displayed and not obj.completed and not obj.failed %} +- {{ obj.text }}{% endif %}{% endfor %}{% endif %}{% endif %}{% endfor %} +{% endfor %} +{% endif %} +{% else %} +## {{ player.name }}'s Party's Active Quests +No active quests currently tracked. +{% endif %} +{% endif %} +{% endif %} \ No newline at end of file diff --git a/SKSE/Plugins/SkyrimNet/prompts/submodules/test_decorators/0600_quest_gamesystem_decorators.prompt b/SKSE/Plugins/SkyrimNet/prompts/submodules/test_decorators/0600_quest_gamesystem_decorators.prompt index 2abbc5e0a0..0743adf648 100644 --- a/SKSE/Plugins/SkyrimNet/prompts/submodules/test_decorators/0600_quest_gamesystem_decorators.prompt +++ b/SKSE/Plugins/SkyrimNet/prompts/submodules/test_decorators/0600_quest_gamesystem_decorators.prompt @@ -498,3 +498,117 @@ First 10 Plugins: {{ join(allPlugins, ", ") }} --- +### Test 16: get_quest_journal() - Resolved Journal Data +{# Returns JSON array of active quests with resolved objective text and journal entries #} +{# Each entry: questName, editorID, stage, questType, isMisc, inQuestLog, objectives[{text,completed,failed,displayed}], journalText #} + +{% set journal = get_quest_journal() %} +**Total Journal Entries:** {{ length(journal) }} + +{% if journal and length(journal) > 0 %} +{% set firstEntry = first(journal) %} + +**First Entry Inspection:** +- questName: "{{ firstEntry.questName }}" +- editorID: {{ firstEntry.editorID }} +- stage: {{ firstEntry.stage }} +- questType: {{ firstEntry.questType }} +- isMisc: {{ firstEntry.isMisc }} +- inQuestLog: {{ firstEntry.inQuestLog }} +- journalText: {% if firstEntry.journalText %}"{{ firstEntry.journalText }}" ✓{% else %}(none){% endif %} +- objectives: {% if firstEntry.objectives and length(firstEntry.objectives) >0 %}{{ length(firstEntry.objectives) }} entries{% else %}(none){% endif %} + +**Type Validation:** +- is_array(journal): {% if journal and is_array(journal) %}✓ YES{% else %}✗ NO{% endif %} +- questName is string: {% if firstEntry.questName %}✓{% else %}✗{% endif %} +- isMisc is bool: {% if firstEntry.isMisc == true or firstEntry.isMisc == false %}✓{% else %}✗{% endif %} +- inQuestLog is bool: {% if firstEntry.inQuestLog == true or firstEntry.inQuestLog == false %}✓{% else %}✗{% endif %} +- stage is number: {% if firstEntry.stage >= 0 %}✓{% else %}✗{% endif %} +- questType is number: {% if firstEntry.questType >= 0 %}✓{% else %}✗{% endif %} + +**Objective Structure (first quest with objectives):** +{% for jq in journal %} +{% if loop.index == 1 and jq.objectives and length(jq.objectives) > 0 %} +{% set firstObj = first(jq.objectives) %} +- Quest: {{ jq.editorID }} + - text: "{{ firstObj.text }}" + - displayed: {{ firstObj.displayed }} + - completed: {{ firstObj.completed }} + - failed: {{ firstObj.failed }} +{% endif %} +{% endfor %} + +**Objective Listing (first quest with objectives):** +{% for jq in journal %} +{% if loop.index == 1 and jq.objectives and length(jq.objectives) > 0 %} +{% for obj in jq.objectives %} +{% if loop.index <= 3 %} + - [{{ loop.index }}] "{{ obj.text }}" (disp:{{ obj.displayed }}, done:{{ obj.completed }}, fail:{{ obj.failed }}) +{% endif %} +{% endfor %} +{% endif %} +{% endfor %} + +**Cross-Reference with get_selected_quests():** +{% set selectedQuests = get_selected_quests() %} +- {{ length(selectedQuests) }} selected quests, {{ length(journal) }} journal entries +{% if selectedQuests and length(selectedQuests) > 0 %} +{% for sq in selectedQuests %} +{% if loop.index <= 5 %} +{% set matched = false %} +{% for jq in journal %} +{% if not matched and jq.editorID == sq.editorID %}{% set matched = true %}{% endif %} +{% endfor %} +- {{ sq.editorID }} ({{ sq.name }}): {% if matched %}✓ in journal{% else %}✗ not in journal{% endif %} +{% endif %} +{% endfor %} +{% else %} +- No selected quests to cross-reference. +{% endif %} + +**Content Summary:** +{% set totalDisplayed = 0 %}{% set totalCompleted = 0 %}{% set totalFailed = 0 %} +{% set miscCount = 0 %}{% set withJournalText = 0 %} +{% for jq in journal %} +{% if jq.isMisc %}{% set miscCount = miscCount + 1 %}{% endif %} +{% if jq.journalText %}{% set withJournalText = withJournalText + 1 %}{% endif %} +{% if jq.objectives and length(jq.objectives) > 0 %} +{% for obj in jq.objectives %} +{% if obj.displayed %}{% set totalDisplayed = totalDisplayed + 1 %}{% endif %} +{% if obj.completed %}{% set totalCompleted = totalCompleted + 1 %}{% endif %} +{% if obj.failed %}{% set totalFailed = totalFailed + 1 %}{% endif %} +{% endfor %} +{% endif %} +{% endfor %} +- Misc quests: {{ miscCount }} +- Quests with journal text: {{ withJournalText }}/{{ length(journal) }} +- Displayed objectives: {{ totalDisplayed }} +- Completed objectives: {{ totalCompleted }} +- Failed objectives: {{ totalFailed }} + +**Specific Quest Lookups:** +{% set hasMQ101 = false %}{% set hasMainQuest = false %} +{% for jq in journal %} +{% if jq.editorID == "MQ101" %}{% set hasMQ101 = true %}{% endif %} +{% if jq.editorID == "MQ102" or jq.editorID == "MQ103" or jq.editorID == "MQ104" %}{% set hasMainQuest = true %}{% endif %} +{% endfor %} +- MQ101 in journal: {% if hasMQ101 %}✓ YES{% else %}✗ NO (not started or filtered){% endif %} +- Main quest (MQ102/MQ103/MQ104) in journal: {% if hasMainQuest %}✓ YES{% else %}✗ NO{% endif %} + +**Default Call Idempotency:** +{% set journalDefault = get_quest_journal() %} +- Same result count: {% if length(journalDefault) == length(journal) %}✓ YES{% else %}✗ different{% endif %} + +{% for jq in journal %} +{% if loop.index <= 3 %} +**Quest {{ loop.index }} in list:** {{ jq.questName }} ({{ jq.editorID }}) + - Stage {{ jq.stage }}, Misc={{ jq.isMisc }}, Log={{ jq.inQuestLog }} +{% endif %} +{% endfor %} + +{% else %} +No journal entries found. +{% endif %} + +--- +