protected bool BuildChoices(BaseDialogueObject fromObject, List <DialogueFragment> fragments) { IList <GraphPin> pins; if (fromObject is Dialogue) { pins = fromObject.Inputs; } else if (fromObject is DialogueCondition) { DialogueCondition condition = (DialogueCondition)fromObject; if (condition.Script == null) { GameDebugger.Log(LogLevel.Warning, "Condition '0x{0:X16}' has no script", condition.Id); return(true); } dynamic result = condition.Script.Run(this); if (!(result is Boolean)) { GameDebugger.Log(LogLevel.Warning, "Condition '0x{0:X16}' script exits with a non boolean result ({1})", condition.Id, result.GetType().Name); return(true); // end the dialogue due to error } pins = new List <GraphPin>(); pins.Add(condition.Outputs[result ? 0 : 1]); } else { if (fromObject is DialogueFragment) { DialogueFragment fragment = (DialogueFragment)fromObject; if (!string.IsNullOrWhiteSpace(fragment.MenuText)) { fragments.Add(fragment); return(false); } if (OnActorTalk != null) { OnActorTalk.Invoke(new ActorTalkEventArgs(fragment)); } } pins = fromObject.Outputs; } if (fromObject is DialogueInstruction) { DialogueInstruction instruction = (DialogueInstruction)fromObject; if (instruction.Script != null) { instruction.Script.Run(this); } } if (fromObject is DialogueJump) { DialogueJump jump = (DialogueJump)fromObject; if (jump.TargetPin != null) { if (BuildChoices(jump.TargetPin, fragments)) { return(true); } } else if (jump.Target != null) { if (BuildChoices(jump.Target, fragments)) { return(true); } } } foreach (GraphPin gpin in pins) { if (BuildChoices(gpin, fragments)) { return(true); } } return(false); }
public static bool ImportArticyDialogues(Project project, string dialogueContainerExternalId) { ArticyFlowObject dialogueContainer; try { dialogueContainer = project.GetFlowObject(dialogueContainerExternalId); } catch { throw new UserFriendlyException( String.Format("Could not find dialogue container '{0}' in the project.", dialogueContainerExternalId), "One of data files does not contain required information." ); } IList <GraphNode> dialogues = dialogueContainer.Children; GameDebugger.Log(LogLevel.Debug, "{0} dialogues found:", dialogues.Count); ArticyDialogue articyDialogue; Dialogue dialogue; Dictionary <ulong, DialoguePin> pinIndex = new Dictionary <ulong, DialoguePin>(); List <Jump> articyJumps = new List <Jump>(); DialogueJump jump; bool badScripts = false; // copy dialogues foreach (GraphNode node in dialogueContainer.Children) { if (!(node is ArticyDialogue)) { continue; } articyDialogue = (ArticyDialogue)node; dialogue = new Dialogue(articyDialogue.Id, articyDialogue.ExternalId); GameDebugger.Log(LogLevel.Debug, "Importing dialogue '{0}'", dialogue.Key); GameDebugger.Log(LogLevel.Debug, "Dialogue has {0} inputs and {1} outputs", articyDialogue.Inputs.Count, articyDialogue.Outputs.Count); badScripts |= ImportArticyPins(articyDialogue, dialogue, false, false, pinIndex); Add(dialogue); // copy dialogue fragments foreach (GraphNode childNode in node.Children) { if (childNode is ArticyFlowFragment) { throw new UserFriendlyException( String.Format("FlowFragment '0x{0:X16}' is not supposed to be a part of a dialogue", ((ArticyFlowFragment)childNode).Id), "One of data files is either corupt or has a version that is not supported by the game engine." ); } if (childNode is ArticyDialogueFragment) { ArticyDialogueFragment articyFragment = (ArticyDialogueFragment)childNode; DialogueFragment fragment = new DialogueFragment(articyFragment.Id, articyFragment.ExternalId); fragment.ActorId = (articyFragment.Speaker == null) ? 0UL : articyFragment.Speaker.Id; fragment.MenuText = articyFragment.MenuText; fragment.Text = articyFragment.Text; fragment.Extra = articyFragment.StageDirections; badScripts |= ImportArticyPins(articyFragment, fragment, true, true, pinIndex); GameDebugger.Log(LogLevel.Debug, "Adding fragment '0x{0:X16}' to the dialogue", fragment.Id); dialogue.AddChild(fragment); Add(fragment); } if (childNode is ArticyCondition) { ArticyCondition articyCondition = (ArticyCondition)childNode; DialogueCondition condition = new DialogueCondition(articyCondition.Id, articyCondition.ExternalId); if (string.IsNullOrWhiteSpace(articyCondition.Script)) { badScripts = true; GameDebugger.Log(LogLevel.Error, "Condition '0x{0:X16}' has no script", condition.Id); } else { if ((condition.Script = CompileScript(articyCondition.Script, Dialogues.ConditionScriptEnvironment, "condition", condition.Id)) == null) { badScripts = true; } } badScripts |= ImportArticyPins(articyCondition, condition, true, true, pinIndex); GameDebugger.Log(LogLevel.Debug, "Adding condition '0x{0:X16}' to the dialogue", condition.Id); dialogue.AddChild(condition); Add(condition); } if (childNode is ArticyInstruction) { ArticyInstruction articyInstruction = (ArticyInstruction)childNode; DialogueInstruction instruction = new DialogueInstruction(articyInstruction.Id, articyInstruction.ExternalId); if (string.IsNullOrWhiteSpace(articyInstruction.Script)) { GameDebugger.Log(LogLevel.Notice, "Instruction '0x{0:X16}' has no script", instruction.Id); } else { if ((instruction.Script = CompileScript(articyInstruction.Script, Dialogues.ConditionScriptEnvironment, "instruction", instruction.Id)) == null) { badScripts = true; } } badScripts |= ImportArticyPins(articyInstruction, instruction, true, true, pinIndex); GameDebugger.Log(LogLevel.Debug, "Adding instruction '0x{0:X16}' to the dialogue", instruction.Id); dialogue.AddChild(instruction); Add(instruction); } if (childNode is ArticyHub) { ArticyHub articyHub = (ArticyHub)childNode; DialogueHub hub = new DialogueHub(articyHub.Id, articyHub.ExternalId); badScripts |= ImportArticyPins(articyHub, hub, true, true, pinIndex); GameDebugger.Log(LogLevel.Debug, "Adding hub '0x{0:X16}' to the dialogue", hub.Id); dialogue.AddChild(hub); Add(hub); } if (childNode is Jump) { Jump articyJump = (Jump)childNode; jump = new DialogueJump(articyJump.Id, articyJump.ExternalId); badScripts |= ImportArticyPins(articyJump, jump, true, true, pinIndex); GameDebugger.Log(LogLevel.Debug, "Adding jump '0x{0:X16}' to the dialogue", jump.Id); m_Objects.Add(jump.Id, jump); dialogue.AddChild(jump); Add(jump); articyJumps.Add(articyJump); } } } // jumps need postprocessing, because we must make sure all dialogue system nodes are already added BaseDialogueObject obj; DialoguePin pin; foreach (Jump articyJump in articyJumps) { jump = (DialogueJump)m_Objects[articyJump.Id]; GameDebugger.Log(LogLevel.Debug, "Linking jump '0x{0:X16}'", jump.Id); if (articyJump.Target != null) { if (!m_Objects.TryGetValue(articyJump.Target.Id, out obj)) { throw new UserFriendlyException( String.Format("Jump '0x{0:X16}' references an object outside the dialogue container", jump.Id), "One of data files is either corupt or has a version that is not supported by the game engine." ); } jump.Target = obj; GameDebugger.Log(LogLevel.Debug, "Linked target to {0} '0x{1:X16}'", obj.GetType().Name, obj.Id); } if (articyJump.TargetPin != null) { if (articyJump.TargetPin.Node == dialogueContainer) { throw new UserFriendlyException( String.Format("Jump '0x{0:X16}' references a pin of the dialogue container itself", jump.Id), "One of data files is either corupt or has a version that is not supported by the game engine." ); } if (!pinIndex.TryGetValue(articyJump.TargetPin.Id, out pin)) { throw new UserFriendlyException( String.Format("Jump '0x{0:X16}' references a pin outside the dialogue container", jump.Id), "One of data files is either corupt or has a version that is not supported by the game engine." ); } jump.TargetPin = pin; GameDebugger.Log(LogLevel.Debug, "Linked target pin to '0x{0:X16}'", articyJump.TargetPin.Id); } } // recreate connections DialoguePin srcPin, dstPin; foreach (ArticyFlowConnection articyConnection in project.FlowConnections) { if (articyConnection.Source.Node is ArticyFlowFragment || articyConnection.Target.Node is ArticyFlowFragment || (articyConnection.Source.Node is ArticyDialogue && articyConnection.Target.Node is ArticyDialogue) || !pinIndex.TryGetValue(((FlowObjectPin)articyConnection.Source).Id, out srcPin) || !pinIndex.TryGetValue(((FlowObjectPin)articyConnection.Target).Id, out dstPin) ) { continue; } GraphConnection newConnection = new GraphConnection(); newConnection.Source = srcPin; newConnection.Target = dstPin; GameDebugger.Log(LogLevel.Debug, "Connected '0x{0:X16}' to '0x{1:X16}'", ((BaseDialogueObject)newConnection.Source.Node).Id, ((BaseDialogueObject)newConnection.Target.Node).Id); } return(badScripts); }