Dialogue uses arrays

This commit is contained in:
2026-05-03 01:25:25 +03:00
parent 3fd167ebff
commit 11530dd7fc
8 changed files with 61 additions and 69 deletions

View File

@@ -17,10 +17,10 @@
* Only active in game mode (GamePlayState::Playing).
*
* Event payload (EventParams) parameters:
* "text" (string) - Narration text to display
* "choices" (string) - Comma-separated list of choice labels
* "speaker" (string) - Optional speaker name
* "auto_progress" (int) - If 1, clicking anywhere progresses (no choices)
* "text" (string) - Narration text to display
* "choices" (string_array) - Array of choice label strings (Lua table)
* "speaker" (string) - Optional speaker name
* "auto_progress" (int) - If 1, clicking anywhere progresses (no choices)
*
* Component state transitions:
* Idle -> Showing (on show() or event)

View File

@@ -10,8 +10,7 @@
-- Event payload parameters:
-- "text" (string) - Narration text to display
-- "speaker" (string) - Optional speaker name (shown above text)
-- "choices" (string) - Comma-separated choice labels (optional)
-- "auto_progress" (int) - If 1, click anywhere progresses (no choices)
-- "choices" (table) - Array of choice label strings (optional)
-- =============================================================================
-- ---------------------------------------------------------------------------
@@ -55,13 +54,13 @@ print("Sent basic narration dialogue")
-- ---------------------------------------------------------------------------
-- 3. Show dialogue with player choices
-- ---------------------------------------------------------------------------
-- When "choices" is provided (comma-separated), the dialogue box shows
-- When "choices" is provided as a table, the dialogue box shows
-- buttons instead of click-to-progress. The player must pick one.
ecs.send_event("dialogue_show", {
text = "Where would you like to go?",
speaker = "Guide",
choices = "The Forest,The Village,The Mountains"
choices = { "The Forest", "The Village", "The Mountains" }
})
print("Sent dialogue with choices")
@@ -92,10 +91,10 @@ print("Sent multi-line dialogue")
-- =============================================================================
-- To show dialogue from Lua:
-- 1. Ensure an entity with DialogueComponent exists (create one if needed)
-- 2. Call ecs.send_event("dialogue_show", { text = "...", speaker = "...", choices = "..." })
-- 2. Call ecs.send_event("dialogue_show", { text = "...", speaker = "...", choices = { ... } })
-- 3. Required: text = "The narration text"
-- 4. Optional: speaker = "Speaker Name"
-- 5. Optional: choices = "Choice1,Choice2,Choice3" (comma-separated)
-- 5. Optional: choices = { "Choice1", "Choice2", "Choice3" } (table of strings)
-- 6. EventParams uses flat key-value pairs (no nested stringValues/floatValues/etc.)
-- 7. Type metadata is available via params._types table
-- =============================================================================

View File

@@ -180,7 +180,6 @@ update_npc_dialogue(guard, "At ease, friend. The town is safe with you around.")
function show_dialogue_with_dynamic_choices(npc_entity, base_text, choice_list)
-- choice_list is a table of strings
local choices_str = table.concat(choice_list, ",")
-- Update the component
ecs.set_field(npc_entity, "Dialogue", "text", base_text)
@@ -189,7 +188,7 @@ function show_dialogue_with_dynamic_choices(npc_entity, base_text, choice_list)
ecs.send_event("dialogue_show", {
text = base_text,
speaker = ecs.get_field(npc_entity, "Dialogue", "speaker"),
choices = choices_str
choices = choice_list
})
end
@@ -210,7 +209,7 @@ show_dialogue_with_dynamic_choices(merchant, "What would you like to buy?", shop
--
-- EventBus (ecs.send_event "dialogue_show"):
-- - Triggers proper state transitions
-- - Parses choices from comma-separated string
-- - Parses choices from table of strings
-- - Best for showing dialogue to the player
--
-- Best practice: Use the EventBus to SHOW dialogue, and the component API

View File

@@ -87,7 +87,7 @@ function on_player_near_npc(npc_name, distance)
ecs.send_event("dialogue_show", {
text = "Hello there! I have a quest for a brave adventurer.",
speaker = npc_name,
choices = "I'll help!,What's the reward?,Not interested"
choices = { "I'll help!", "What's the reward?", "Not interested" }
})
end
end
@@ -119,14 +119,14 @@ local choice_sub = ecs.subscribe_event("dialogue_choice", function(event, params
ecs.send_event("dialogue_show", {
text = "Excellent! The ancient artifact was stolen from the temple.\nBring it back and you'll be richly rewarded!",
speaker = "QuestGiver",
choices = "Where is the temple?,I'm on it!,Tell me more"
choices = { "Where is the temple?", "I'm on it!", "Tell me more" }
})
elseif choice_text == "What's the reward?" then
ecs.send_event("dialogue_show", {
text = "100 gold pieces and a magical amulet! What do you say?",
speaker = "QuestGiver",
choices = "I'll help!,Sounds good,Maybe later"
choices = { "I'll help!", "Sounds good", "Maybe later" }
})
elseif choice_text == "Not interested" then

View File

@@ -74,12 +74,12 @@ print("Subscribed to dialogue_dismiss events (ID: " .. dismiss_sub .. ")")
local show_sub = ecs.subscribe_event("dialogue_show", function(event, params)
local text = params.text or ""
local speaker = params.speaker or "Unknown"
local choices = params.choices or ""
local choices = params.choices or {}
print("[Dialogue Log] " .. speaker .. ": \"" .. text .. "\"")
if choices ~= "" then
print("[Dialogue Log] Choices: " .. choices)
if #choices > 0 then
print("[Dialogue Log] Choices: " .. table.concat(choices, ", "))
end
end)
@@ -95,7 +95,7 @@ function show_branching_dialogue()
ecs.send_event("dialogue_show", {
text = "You see a dark cave entrance. What do you do?",
speaker = "Narrator",
choices = "Enter the cave,Look around first,Leave"
choices = { "Enter the cave", "Look around first", "Leave" }
})
-- Step 2: The choice will be handled by our subscriber above.
@@ -114,7 +114,7 @@ function npc_greeting(npc_name, greeting_text)
ecs.send_event("dialogue_show", {
text = greeting_text,
speaker = npc_name,
choices = "Who are you?,Tell me about this place,Goodbye"
choices = { "Who are you?", "Tell me about this place", "Goodbye" }
})
-- The choice subscriber will handle the response.

View File

@@ -56,14 +56,14 @@ end)
--- Show a line of dialogue and wait for the player to respond.
--- @param text string The narration text
--- @param speaker string|nil Optional speaker name
--- @param choices string|nil Comma-separated choices (nil = click to dismiss)
--- @param choices table|nil Array of choice label strings (nil = click to dismiss)
--- @return number choice_index (0 if dismissed, 1+ for choices)
function show_and_wait(text, speaker, choices)
-- Send the dialogue event
ecs.send_event("dialogue_show", {
text = text,
speaker = speaker or "",
choices = choices or ""
choices = choices or {}
})
-- Wait for player response
@@ -106,7 +106,7 @@ function simple_conversation()
ecs.send_event("dialogue_show", {
text = "I've been expecting you. The darkness grows stronger each day.",
speaker = "Old Man",
choices = "Tell me more,How can I help?,I must go"
choices = { "Tell me more", "How can I help?", "I must go" }
})
print(" (Player would now see choices and pick one)")
@@ -212,23 +212,21 @@ function run_conversation(tree, start_node)
break
end
-- Build choices string from the node's choices table
local choices_str = ""
-- Build choices table from the node's choices
local choices = {}
local choice_map = {}
if node.choices then
local parts = {}
for i, choice in ipairs(node.choices) do
table.insert(parts, choice.text)
table.insert(choices, choice.text)
choice_map[i] = choice
end
choices_str = table.concat(parts, ",")
end
-- Show the dialogue
ecs.send_event("dialogue_show", {
text = node.text,
speaker = node.speaker or "",
choices = choices_str
choices = choices
})
-- In a real game, you'd wait for the player's choice here.
@@ -272,7 +270,7 @@ function talk_to_elder_marcus()
ecs.send_event("dialogue_show", {
text = "Ah, a new face! I am Elder Marcus, keeper of this village.\nIt's been so long since we had visitors.",
speaker = "Elder Marcus",
choices = "Pleasure to meet you,I've heard stories about you,Hello"
choices = { "Pleasure to meet you", "I've heard stories about you", "Hello" }
})
elseif npc_state.quest_active and npc_state.quest_completed then
-- Quest completed
@@ -281,21 +279,21 @@ function talk_to_elder_marcus()
ecs.send_event("dialogue_show", {
text = "You did it! The village is safe thanks to you.\nPlease, take this reward.",
speaker = "Elder Marcus",
choices = "Thank you, elder,I was happy to help"
choices = { "Thank you, elder", "I was happy to help" }
})
elseif npc_state.quest_active then
-- Quest in progress
ecs.send_event("dialogue_show", {
text = "Have you dealt with those bandits yet?\nThe villagers are growing anxious.",
speaker = "Elder Marcus",
choices = "I'm working on it,I need more information,Not yet"
choices = { "I'm working on it", "I need more information", "Not yet" }
})
else
-- Regular greeting
ecs.send_event("dialogue_show", {
text = "Welcome back, friend. The village is peaceful today.",
speaker = "Elder Marcus",
choices = "Any news?,I need supplies,Goodbye"
choices = { "Any news?", "I need supplies", "Goodbye" }
})
end
end

View File

@@ -1251,7 +1251,8 @@ static void registerAllComponents()
lua_pushstring(L, c.text.c_str());
lua_setfield(L, -2, "text");
lua_pushstring(L, c.speaker.c_str());
lua_setfield(L, -2, "speaker");
lua_setfield(L, -2, "speaker"); pushStringVector(L, c.choices);
lua_setfield(L, -2, "choices");
lua_pushstring(L, c.fontName.c_str());
lua_setfield(L, -2, "fontName"); lua_pushnumber(L, c.fontSize);
lua_setfield(L, -2, "fontSize");
@@ -1269,6 +1270,9 @@ static void registerAllComponents()
if (lua_getfield(L, idx, "speaker"), lua_isstring(L, -1))
c.speaker = lua_tostring(L, -1);
lua_pop(L, 1);
if (lua_getfield(L, idx, "choices"), lua_istable(L, -1))
c.choices = readStringVector(L, lua_gettop(L));
lua_pop(L, 1);
if (lua_getfield(L, idx, "fontName"), lua_isstring(L, -1))
c.fontName = lua_tostring(L, -1);
lua_pop(L, 1);

View File

@@ -21,45 +21,37 @@ DialogueSystem::DialogueSystem(flecs::world &world,
"dialogue_show", [this](const Ogre::String &,
const editScene::EventParams &params) {
// Find the first entity with DialogueComponent
m_world.query<DialogueComponent>().each([&](flecs::entity
e,
DialogueComponent
&dc) {
if (!dc.enabled)
return;
m_world.query<DialogueComponent>().each(
[&](flecs::entity e, DialogueComponent &dc) {
if (!dc.enabled)
return;
Ogre::String text = params.getString("text");
if (text.empty())
return;
Ogre::String text =
params.getString("text");
if (text.empty())
return;
// Parse choices from comma-separated
// string
std::vector<Ogre::String> choices;
Ogre::String choicesStr =
params.getString("choices");
if (!choicesStr.empty()) {
Ogre::String::size_type start = 0;
Ogre::String::size_type end;
while ((end = choicesStr.find(",",
start)) !=
Ogre::String::npos) {
choices.push_back(
choicesStr.substr(
start,
end - start));
start = end + 1;
// Parse choices from string array
std::vector<Ogre::String> choices;
const editScene::EventValue *choicesVal =
params.get("choices");
if (choicesVal &&
choicesVal->getType() ==
editScene::EventValue::
STRING_ARRAY) {
const auto &arr =
choicesVal
->getStringArray();
choices.reserve(arr.size());
for (const auto &s : arr)
choices.push_back(s);
}
if (start < choicesStr.length())
choices.push_back(
choicesStr.substr(
start));
}
Ogre::String speaker =
params.getString("speaker");
Ogre::String speaker =
params.getString("speaker");
dc.show(text, choices, speaker);
});
dc.show(text, choices, speaker);
});
});
}