From eeac9155bf42b7c3a6374b5b462235abe89ef288 Mon Sep 17 00:00:00 2001 From: Heron Date: Sat, 16 May 2026 12:03:54 -0400 Subject: [PATCH] Scaffold for conversation manager --- .../conversation_action.java | 11 + .../conversation_actions.java | 162 +++++++++++++ .../conversation_conditions.java | 106 +++++++++ .../conversation_context.java | 21 ++ .../conversation_definition.java | 18 ++ .../conversation_engine.java | 216 ++++++++++++++++++ .../conversation_loader.java | 175 ++++++++++++++ .../conversation_node.java | 14 ++ .../conversation_response.java | 15 ++ .../table_conversation.java | 67 ++++++ 10 files changed, 805 insertions(+) create mode 100644 sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_action.java create mode 100644 sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_actions.java create mode 100644 sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_conditions.java create mode 100644 sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_context.java create mode 100644 sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_definition.java create mode 100644 sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_engine.java create mode 100644 sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_loader.java create mode 100644 sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_node.java create mode 100644 sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_response.java create mode 100644 sku.0/sys.server/compiled/game/script/systems/conversation_manager/table_conversation.java diff --git a/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_action.java b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_action.java new file mode 100644 index 000000000..cd63cfbf1 --- /dev/null +++ b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_action.java @@ -0,0 +1,11 @@ +package script.systems.conversation_manager; + +public class conversation_action +{ + public String actionSet; + public int order; + public String actionType; + public String arg1; + public String arg2; + public String arg3; +} diff --git a/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_actions.java b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_actions.java new file mode 100644 index 000000000..ec2b56b35 --- /dev/null +++ b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_actions.java @@ -0,0 +1,162 @@ +package script.systems.conversation_manager; + +import script.dictionary; +import script.library.armor; +import script.library.factions; +import script.library.groundquests; +import script.library.money; +import script.library.utils; +import script.obj_id; +import script.string_id; + +public class conversation_actions extends script.base_script +{ + public conversation_actions() + { + } + + public void executeActionSet(conversation_context ctx, conversation_definition definition, String actionSet) throws InterruptedException + { + if (actionSet == null || actionSet.equals("")) + { + return; + } + for (int order = 0; order < 1000; ++order) + { + for (conversation_action action : definition.actions) + { + if (action.actionSet != null && action.actionSet.equals(actionSet) && action.order == order) + { + debug(ctx, "execute actionSet=" + actionSet + " order=" + action.order + " type=" + action.actionType + " arg1=" + action.arg1); + execute(ctx, action); + } + } + } + } + + public void execute(conversation_context ctx, conversation_action action) throws InterruptedException + { + if (action == null || action.actionType == null || action.actionType.equals("")) + { + return; + } + if (action.actionType.equals("grantQuest")) + { + groundquests.grantQuest(ctx.player, action.arg1); + return; + } + if (action.actionType.equals("requestGrantQuest")) + { + groundquests.requestGrantQuest(ctx.player, action.arg1); + return; + } + if (action.actionType.equals("clearQuest")) + { + groundquests.clearQuest(ctx.player, action.arg1); + return; + } + if (action.actionType.equals("sendQuestSignal")) + { + groundquests.sendSignal(ctx.player, action.arg1); + return; + } + if (action.actionType.equals("giveItem")) + { + createObjectInInventoryAllowOverload(action.arg1, ctx.player); + return; + } + if (action.actionType.equals("giveArmorItem")) + { + obj_id armorItem = createObjectInInventoryAllowOverload(action.arg1, ctx.player); + if (isIdValid(armorItem) && action.arg2 != null && !action.arg2.equals("")) + { + float min = utils.stringToFloat(action.arg2); + float max = min; + if (action.arg3 != null && !action.arg3.equals("")) + { + max = utils.stringToFloat(action.arg3); + } + if (!isGameObjectTypeOf(armorItem, GOT_armor_foot) && !isGameObjectTypeOf(armorItem, GOT_armor_hand)) + { + armor.setArmorDataPercent(armorItem, 2, 1, min, max); + } + } + return; + } + if (action.actionType.equals("grantSchematic")) + { + grantSchematic(ctx.player, action.arg1); + return; + } + if (action.actionType.equals("rewardFaction")) + { + factions.awardFactionStanding(ctx.player, action.arg1, utils.stringToInt(action.arg2)); + return; + } + if (action.actionType.equals("giveCredits")) + { + money.bankTo(money.ACCT_JABBA, ctx.player, utils.stringToInt(action.arg1)); + return; + } + if (action.actionType.equals("setObjvar")) + { + setObjVar(ctx.player, action.arg1, action.arg2); + return; + } + if (action.actionType.equals("removeObjvar")) + { + removeObjVar(ctx.player, action.arg1); + return; + } + if (action.actionType.equals("playNpcAnimation")) + { + doAnimationAction(ctx.npc, action.arg1); + return; + } + if (action.actionType.equals("playPlayerAnimation")) + { + doAnimationAction(ctx.player, action.arg1); + return; + } + if (action.actionType.equals("facePlayer")) + { + faceTo(ctx.npc, ctx.player); + return; + } + if (action.actionType.equals("sendMessageNpc")) + { + dictionary params = new dictionary(); + params.put("player", ctx.player); + params.put("npc", ctx.npc); + params.put("arg1", action.arg1); + params.put("arg2", action.arg2); + params.put("arg3", action.arg3); + messageTo(ctx.npc, action.arg1, params, 0, false); + return; + } + if (action.actionType.equals("sendSystemMessage")) + { + sendSystemMessage(ctx.player, new string_id(ctx.stringFile, action.arg1)); + return; + } + LOG("conversation_manager", "Unknown action type '" + action.actionType + "' for conversation '" + ctx.conversationId + "'"); + debug(ctx, "unknown action type=" + action.actionType); + } + + public void debug(conversation_context ctx, String message) throws InterruptedException + { + if (ctx == null || !isIdValid(ctx.npc) || !isIdValid(ctx.player)) + { + return; + } + if (!hasObjVar(ctx.npc, "conversation_manager.debug")) + { + return; + } + if (!getBooleanObjVar(ctx.npc, "conversation_manager.debug")) + { + return; + } + sendSystemMessage(ctx.player, "[conversation_manager] " + message, null); + } +} diff --git a/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_conditions.java b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_conditions.java new file mode 100644 index 000000000..eb7bf5ca1 --- /dev/null +++ b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_conditions.java @@ -0,0 +1,106 @@ +package script.systems.conversation_manager; + +import script.library.features; +import script.library.factions; +import script.library.groundquests; +import script.obj_id; + +public class conversation_conditions extends script.base_script +{ + public conversation_conditions() + { + } + + public boolean passes(conversation_context ctx, String conditionType, String arg1, String arg2) throws InterruptedException + { + if (conditionType == null || conditionType.equals("") || conditionType.equals("always")) + { + return true; + } + if (conditionType.equals("questActive")) + { + return debugResult(ctx, conditionType, arg1, arg2, groundquests.isQuestActive(ctx.player, arg1)); + } + if (conditionType.equals("questComplete")) + { + return debugResult(ctx, conditionType, arg1, arg2, groundquests.hasCompletedQuest(ctx.player, arg1)); + } + if (conditionType.equals("questActiveOrComplete")) + { + return debugResult(ctx, conditionType, arg1, arg2, groundquests.isQuestActiveOrComplete(ctx.player, arg1)); + } + if (conditionType.equals("taskActive")) + { + return debugResult(ctx, conditionType, arg1, arg2, groundquests.isTaskActive(ctx.player, arg1, arg2)); + } + if (conditionType.equals("taskComplete")) + { + return debugResult(ctx, conditionType, arg1, arg2, groundquests.hasCompletedTask(ctx.player, arg1, arg2)); + } + if (conditionType.equals("hasObjvar")) + { + return debugResult(ctx, conditionType, arg1, arg2, hasObjVar(ctx.player, arg1)); + } + if (conditionType.equals("notHasObjvar")) + { + return debugResult(ctx, conditionType, arg1, arg2, !hasObjVar(ctx.player, arg1)); + } + if (conditionType.equals("objvarEquals")) + { + return debugResult(ctx, conditionType, arg1, arg2, hasObjVar(ctx.player, arg1) && getStringObjVar(ctx.player, arg1).equals(arg2)); + } + if (conditionType.equals("faction")) + { + String playerFaction = factions.getFaction(ctx.player); + return debugResult(ctx, conditionType, arg1, arg2, playerFaction != null && playerFaction.equals(arg1)); + } + if (conditionType.equals("hasSkill")) + { + return debugResult(ctx, conditionType, arg1, arg2, hasSkill(ctx.player, arg1)); + } + if (conditionType.equals("hasEp3")) + { + return debugResult(ctx, conditionType, arg1, arg2, features.hasEpisode3Expansion(ctx.player)); + } + if (conditionType.equals("isGm")) + { + return debugResult(ctx, conditionType, arg1, arg2, hasObjVar(ctx.player, "gm")); + } + LOG("conversation_manager", "Unknown condition type '" + conditionType + "' for conversation '" + ctx.conversationId + "'"); + debug(ctx, "unknown condition type=" + conditionType + " arg1=" + arg1 + " arg2=" + arg2); + return false; + } + + public boolean passesNode(conversation_context ctx, conversation_node node) throws InterruptedException + { + return passes(ctx, node.conditionType, node.conditionArg1, node.conditionArg2); + } + + public boolean passesResponse(conversation_context ctx, conversation_response response) throws InterruptedException + { + return passes(ctx, response.conditionType, response.conditionArg1, response.conditionArg2); + } + + public boolean debugResult(conversation_context ctx, String conditionType, String arg1, String arg2, boolean result) throws InterruptedException + { + debug(ctx, "condition type=" + conditionType + " arg1=" + arg1 + " arg2=" + arg2 + " result=" + result); + return result; + } + + public void debug(conversation_context ctx, String message) throws InterruptedException + { + if (ctx == null || !isIdValid(ctx.npc) || !isIdValid(ctx.player)) + { + return; + } + if (!hasObjVar(ctx.npc, "conversation_manager.debug")) + { + return; + } + if (!getBooleanObjVar(ctx.npc, "conversation_manager.debug")) + { + return; + } + sendSystemMessage(ctx.player, "[conversation_manager] " + message, null); + } +} diff --git a/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_context.java b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_context.java new file mode 100644 index 000000000..a034f38ff --- /dev/null +++ b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_context.java @@ -0,0 +1,21 @@ +package script.systems.conversation_manager; + +import script.obj_id; + +public class conversation_context +{ + public obj_id npc; + public obj_id player; + public String conversationId; + public String table; + public String stringFile; + + public conversation_context(obj_id npc, obj_id player, conversation_definition definition) + { + this.npc = npc; + this.player = player; + this.conversationId = definition.conversationId; + this.table = definition.table; + this.stringFile = definition.stringFile; + } +} diff --git a/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_definition.java b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_definition.java new file mode 100644 index 000000000..7d4f5d24a --- /dev/null +++ b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_definition.java @@ -0,0 +1,18 @@ +package script.systems.conversation_manager; + +public class conversation_definition +{ + public String conversationId; + public String table; + public String stringFile; + public conversation_node[] nodes; + public conversation_response[] responses; + public conversation_action[] actions; + + public conversation_definition() + { + nodes = new conversation_node[0]; + responses = new conversation_response[0]; + actions = new conversation_action[0]; + } +} diff --git a/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_engine.java b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_engine.java new file mode 100644 index 000000000..ee99a91f4 --- /dev/null +++ b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_engine.java @@ -0,0 +1,216 @@ +package script.systems.conversation_manager; + +import script.library.ai_lib; +import script.library.utils; +import script.obj_id; +import script.string_id; + +public class conversation_engine extends script.base_script +{ + public conversation_engine() + { + } + + public static final String CONVERSATION_NAME = "conversationManager"; + public static final String SCRIPT_VAR_PREFIX = "conversation_manager."; + + protected conversation_conditions conditions = new conversation_conditions(); + protected conversation_actions actions = new conversation_actions(); + + public int startConversation(obj_id npc, obj_id player, conversation_definition definition) throws InterruptedException + { + if (ai_lib.isInCombat(npc) || ai_lib.isInCombat(player)) + { + return SCRIPT_OVERRIDE; + } + conversation_context ctx = new conversation_context(npc, player, definition); + debug(ctx, "start conversation table=" + definition.table); + conversation_node startNode = findStartNode(ctx, definition); + if (startNode == null) + { + LOG("conversation_manager", "No valid start node for conversation '" + definition.conversationId + "'"); + debug(ctx, "no valid start node"); + return SCRIPT_OVERRIDE; + } + debug(ctx, "start node=" + startNode.nodeId); + return enterNode(ctx, definition, startNode); + } + + public int continueConversation(obj_id npc, obj_id player, string_id responseId, conversation_definition definition) throws InterruptedException + { + conversation_context ctx = new conversation_context(npc, player, definition); + String currentNodeId = getCurrentNode(player, definition); + debug(ctx, "continue conversation currentNode=" + currentNodeId + " response=" + responseId.getAsciiId()); + if (currentNodeId == null || currentNodeId.equals("")) + { + LOG("conversation_manager", "No current node for conversation '" + definition.conversationId + "'"); + endConversation(ctx, null); + return SCRIPT_CONTINUE; + } + conversation_response response = findResponse(ctx, definition, currentNodeId, responseId); + if (response == null) + { + LOG("conversation_manager", "No matching response '" + responseId + "' for node '" + currentNodeId + "'"); + debug(ctx, "no matching response for current node"); + endConversation(ctx, null); + return SCRIPT_CONTINUE; + } + debug(ctx, "selected response=" + response.responseId + " actionSet=" + response.actionSet); + actions.executeActionSet(ctx, definition, response.actionSet); + if (response.endConversation) + { + debug(ctx, "response ends conversation"); + endConversation(ctx, response.endTextKey); + return SCRIPT_CONTINUE; + } + conversation_node nextNode = findNode(definition, response.nextNodeId); + if (nextNode == null) + { + debug(ctx, "no next node, ending conversation"); + endConversation(ctx, response.endTextKey); + return SCRIPT_CONTINUE; + } + debug(ctx, "next node=" + nextNode.nodeId); + return enterNode(ctx, definition, nextNode); + } + + public int enterNode(conversation_context ctx, conversation_definition definition, conversation_node node) throws InterruptedException + { + debug(ctx, "enter node=" + node.nodeId + " enterActionSet=" + node.enterActionSet); + actions.executeActionSet(ctx, definition, node.enterActionSet); + conversation_response[] responses = getValidResponses(ctx, definition, node.nodeId); + string_id message = new string_id(ctx.stringFile, node.textKey); + if (node.endNode || responses.length == 0) + { + debug(ctx, "node ends conversation responseCount=" + responses.length); + endConversation(ctx, node.textKey); + return SCRIPT_CONTINUE; + } + string_id[] responseIds = new string_id[responses.length]; + for (int i = 0; i < responses.length; ++i) + { + responseIds[i] = new string_id(ctx.stringFile, responses[i].textKey); + } + setCurrentNode(ctx.player, definition, node.nodeId); + debug(ctx, "show node=" + node.nodeId + " responseCount=" + responses.length); + npcStartConversation(ctx.player, ctx.npc, CONVERSATION_NAME, message, responseIds); + return SCRIPT_CONTINUE; + } + + public void endConversation(conversation_context ctx, String textKey) throws InterruptedException + { + debug(ctx, "end conversation textKey=" + textKey); + clearCurrentNode(ctx.player, ctx.conversationId); + if (textKey != null && !textKey.equals("")) + { + npcEndConversationWithMessage(ctx.player, new string_id(ctx.stringFile, textKey)); + } + else + { + npcEndConversation(ctx.player); + } + } + + public conversation_node findStartNode(conversation_context ctx, conversation_definition definition) throws InterruptedException + { + conversation_node best = null; + for (conversation_node node : definition.nodes) + { + if (node.startNode && conditions.passesNode(ctx, node)) + { + if (best == null || node.priority < best.priority) + { + best = node; + } + } + } + return best; + } + + public conversation_node findNode(conversation_definition definition, String nodeId) throws InterruptedException + { + if (nodeId == null || nodeId.equals("")) + { + return null; + } + for (conversation_node node : definition.nodes) + { + if (node.nodeId != null && node.nodeId.equals(nodeId)) + { + return node; + } + } + return null; + } + + public conversation_response findResponse(conversation_context ctx, conversation_definition definition, String nodeId, string_id selectedResponse) throws InterruptedException + { + for (conversation_response response : definition.responses) + { + if (response.nodeId != null && response.nodeId.equals(nodeId) && response.textKey != null && response.textKey.equals(selectedResponse.getAsciiId()) && conditions.passesResponse(ctx, response)) + { + return response; + } + } + return null; + } + + public conversation_response[] getValidResponses(conversation_context ctx, conversation_definition definition, String nodeId) throws InterruptedException + { + int count = 0; + for (conversation_response response : definition.responses) + { + if (response.nodeId != null && response.nodeId.equals(nodeId) && conditions.passesResponse(ctx, response)) + { + ++count; + } + } + conversation_response[] valid = new conversation_response[count]; + int index = 0; + for (conversation_response response : definition.responses) + { + if (response.nodeId != null && response.nodeId.equals(nodeId) && conditions.passesResponse(ctx, response)) + { + valid[index++] = response; + } + } + return valid; + } + + public String getCurrentNode(obj_id player, conversation_definition definition) throws InterruptedException + { + return utils.getStringScriptVar(player, getCurrentNodeScriptVar(definition.conversationId)); + } + + public void setCurrentNode(obj_id player, conversation_definition definition, String nodeId) throws InterruptedException + { + utils.setScriptVar(player, getCurrentNodeScriptVar(definition.conversationId), nodeId); + } + + public void clearCurrentNode(obj_id player, String conversationId) throws InterruptedException + { + utils.removeScriptVar(player, getCurrentNodeScriptVar(conversationId)); + } + + public String getCurrentNodeScriptVar(String conversationId) throws InterruptedException + { + return SCRIPT_VAR_PREFIX + conversationId + ".currentNode"; + } + + public void debug(conversation_context ctx, String message) throws InterruptedException + { + if (ctx == null || !isIdValid(ctx.npc) || !isIdValid(ctx.player)) + { + return; + } + if (!hasObjVar(ctx.npc, "conversation_manager.debug")) + { + return; + } + if (!getBooleanObjVar(ctx.npc, "conversation_manager.debug")) + { + return; + } + sendSystemMessage(ctx.player, "[conversation_manager] " + message, null); + } +} diff --git a/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_loader.java b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_loader.java new file mode 100644 index 000000000..c20955a9d --- /dev/null +++ b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_loader.java @@ -0,0 +1,175 @@ +package script.systems.conversation_manager; + +import script.dictionary; +import script.obj_id; + +public class conversation_loader extends script.base_script +{ + public conversation_loader() + { + } + + public static final String TABLE_OBJVAR = "conversation_manager.table"; + public static final String TABLE_ROOT = "datatables/conversation_manager/"; + + public conversation_definition load(obj_id npc) throws InterruptedException + { + String tableName = getStringObjVar(npc, TABLE_OBJVAR); + conversation_definition definition = new conversation_definition(); + definition.table = tableName; + definition.conversationId = tableName; + if (tableName == null || tableName.equals("")) + { + LOG("conversation_manager", "Missing objvar '" + TABLE_OBJVAR + "' on npc " + npc); + return definition; + } + String table = TABLE_ROOT + tableName + ".iff"; + definition.stringFile = getStringCell(table, 0, "stringFile"); + if (definition.stringFile == null || definition.stringFile.equals("")) + { + definition.stringFile = "conversation/" + tableName; + } + definition.nodes = loadNodes(table); + definition.responses = loadResponses(table); + definition.actions = loadActions(table); + return definition; + } + + public conversation_node[] loadNodes(String table) throws InterruptedException + { + String[] nodeIds = dataTableGetStringColumn(table, "nodeId"); + if (nodeIds == null) + { + return new conversation_node[0]; + } + int count = 0; + for (String nodeId : nodeIds) + { + if (nodeId != null && !nodeId.equals("")) + { + ++count; + } + } + conversation_node[] nodes = new conversation_node[count]; + int index = 0; + for (int i = 0; i < nodeIds.length; ++i) + { + if (nodeIds[i] == null || nodeIds[i].equals("")) + { + continue; + } + dictionary row = dataTableGetRow(table, i); + conversation_node node = new conversation_node(); + node.nodeId = getString(row, "nodeId"); + node.textKey = getString(row, "nodeText"); + node.conditionType = getString(row, "nodeCondition"); + node.conditionArg1 = getString(row, "conditionArg1"); + node.conditionArg2 = getString(row, "conditionArg2"); + node.priority = getInt(row, "priority"); + node.startNode = getBoolean(row, "startNode"); + node.endNode = getBoolean(row, "endNode"); + node.enterActionSet = getString(row, "enterActionSet"); + nodes[index++] = node; + } + return nodes; + } + + public conversation_response[] loadResponses(String table) throws InterruptedException + { + String[] responseIds = dataTableGetStringColumn(table, "responseId"); + if (responseIds == null) + { + return new conversation_response[0]; + } + int count = 0; + for (String responseId : responseIds) + { + if (responseId != null && !responseId.equals("")) + { + ++count; + } + } + conversation_response[] responses = new conversation_response[count]; + int index = 0; + for (int i = 0; i < responseIds.length; ++i) + { + if (responseIds[i] == null || responseIds[i].equals("")) + { + continue; + } + dictionary row = dataTableGetRow(table, i); + conversation_response response = new conversation_response(); + response.responseId = getString(row, "responseId"); + response.nodeId = getString(row, "responseNode"); + response.textKey = getString(row, "responseText"); + response.conditionType = getString(row, "responseCondition"); + response.conditionArg1 = getString(row, "responseConditionArg1"); + response.conditionArg2 = getString(row, "responseConditionArg2"); + response.actionSet = getString(row, "actionSet"); + response.nextNodeId = getString(row, "nextNode"); + response.endConversation = getBoolean(row, "endConversation"); + response.endTextKey = getString(row, "endText"); + responses[index++] = response; + } + return responses; + } + + public conversation_action[] loadActions(String table) throws InterruptedException + { + String[] actionSets = dataTableGetStringColumn(table, "actionSetName"); + if (actionSets == null) + { + return new conversation_action[0]; + } + int count = 0; + for (String actionSet : actionSets) + { + if (actionSet != null && !actionSet.equals("")) + { + ++count; + } + } + conversation_action[] actions = new conversation_action[count]; + int index = 0; + for (int i = 0; i < actionSets.length; ++i) + { + if (actionSets[i] == null || actionSets[i].equals("")) + { + continue; + } + dictionary row = dataTableGetRow(table, i); + conversation_action action = new conversation_action(); + action.actionSet = getString(row, "actionSetName"); + action.order = getInt(row, "actionOrder"); + action.actionType = getString(row, "actionType"); + action.arg1 = getString(row, "actionArg1"); + action.arg2 = getString(row, "actionArg2"); + action.arg3 = getString(row, "actionArg3"); + actions[index++] = action; + } + return actions; + } + + public String getStringCell(String table, int row, String column) throws InterruptedException + { + String value = dataTableGetString(table, row, column); + return value == null ? "" : value; + } + + public String getString(dictionary row, String key) throws InterruptedException + { + String value = row.getString(key); + return value == null ? "" : value; + } + + public int getInt(dictionary row, String key) throws InterruptedException + { + return row.getInt(key); + } + + public boolean getBoolean(dictionary row, String key) throws InterruptedException + { + String value = getString(row, key); + return value.equals("1") || value.equals("true") || value.equals("yes"); + } +} diff --git a/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_node.java b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_node.java new file mode 100644 index 000000000..2f57ca05c --- /dev/null +++ b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_node.java @@ -0,0 +1,14 @@ +package script.systems.conversation_manager; + +public class conversation_node +{ + public String nodeId; + public String textKey; + public String conditionType; + public String conditionArg1; + public String conditionArg2; + public int priority; + public boolean startNode; + public boolean endNode; + public String enterActionSet; +} diff --git a/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_response.java b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_response.java new file mode 100644 index 000000000..12c1a476a --- /dev/null +++ b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/conversation_response.java @@ -0,0 +1,15 @@ +package script.systems.conversation_manager; + +public class conversation_response +{ + public String responseId; + public String nodeId; + public String textKey; + public String conditionType; + public String conditionArg1; + public String conditionArg2; + public String actionSet; + public String nextNodeId; + public boolean endConversation; + public String endTextKey; +} diff --git a/sku.0/sys.server/compiled/game/script/systems/conversation_manager/table_conversation.java b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/table_conversation.java new file mode 100644 index 000000000..5e819c2a9 --- /dev/null +++ b/sku.0/sys.server/compiled/game/script/systems/conversation_manager/table_conversation.java @@ -0,0 +1,67 @@ +package script.systems.conversation_manager; + +import script.menu_info; +import script.menu_info_data; +import script.menu_info_types; +import script.obj_id; +import script.string_id; + +public class table_conversation extends script.base_script +{ + public table_conversation() + { + } + + protected conversation_loader loader = new conversation_loader(); + protected conversation_engine engine = new conversation_engine(); + + public int OnInitialize(obj_id self) throws InterruptedException + { + if ((!isTangible(self)) || (isPlayer(self))) + { + detachScript(self, "systems.conversation_manager.table_conversation"); + return SCRIPT_CONTINUE; + } + setCondition(self, CONDITION_CONVERSABLE); + return SCRIPT_CONTINUE; + } + + public int OnAttach(obj_id self) throws InterruptedException + { + setCondition(self, CONDITION_CONVERSABLE); + return SCRIPT_CONTINUE; + } + + public int OnObjectMenuRequest(obj_id self, obj_id player, menu_info menuInfo) throws InterruptedException + { + int menu = menuInfo.addRootMenu(menu_info_types.CONVERSE_START, null); + menu_info_data menuInfoData = menuInfo.getMenuItemById(menu); + menuInfoData.setServerNotify(false); + setCondition(self, CONDITION_CONVERSABLE); + faceTo(self, player); + return SCRIPT_CONTINUE; + } + + public int OnIncapacitated(obj_id self, obj_id killer) throws InterruptedException + { + clearCondition(self, CONDITION_CONVERSABLE); + detachScript(self, "systems.conversation_manager.table_conversation"); + return SCRIPT_CONTINUE; + } + + public int OnStartNpcConversation(obj_id self, obj_id player) throws InterruptedException + { + conversation_definition definition = loader.load(self); + return engine.startConversation(self, player, definition); + } + + public int OnNpcConversationResponse(obj_id self, String conversationId, obj_id player, string_id response) throws InterruptedException + { + if (!conversationId.equals(conversation_engine.CONVERSATION_NAME)) + { + return SCRIPT_CONTINUE; + } + conversation_definition definition = loader.load(self); + return engine.continueConversation(self, player, response, definition); + } +}