private static bool ImportArticyPins(ArticyFlowObject source, BaseQuestObject target, bool compileInputScripts, bool compileOutputScripts, Dictionary <ulong, QuestPin> pinIndex) { FlowObjectPin articyPin; QuestPin pin; bool badScripts = false; foreach (GraphPin graphPin in source.Inputs) { articyPin = (FlowObjectPin)graphPin; pin = new QuestPin(articyPin.Type, articyPin.Id); if (compileInputScripts && !string.IsNullOrWhiteSpace(articyPin.Script)) { if ((pin.Script = CompileScript(articyPin.Script, Quests.InputPinScriptEnvironment, "input pin", articyPin.Id)) == null) { badScripts = true; } } if (string.IsNullOrEmpty(target.Key)) { GameDebugger.Log(LogLevel.Debug, "Adding intput pin to '0x{0:X16}'", target.Id); } else { GameDebugger.Log(LogLevel.Debug, "Adding intput pin to '{0}'", target.Key); } pinIndex.Add(articyPin.Id, pin); target.AddInput(pin); } foreach (GraphPin graphPin in source.Outputs) { articyPin = (FlowObjectPin)graphPin; pin = new QuestPin(articyPin.Type, articyPin.Id); if (compileOutputScripts && !string.IsNullOrWhiteSpace(articyPin.Script)) { QuestSystemScriptEnvironment env; env = (target is QuestObjective) ? (QuestSystemScriptEnvironment)Quests.OutputPinScriptEnvironment : (QuestSystemScriptEnvironment)Quests.InstructionScriptEnvironment; if ((pin.Script = CompileScript(articyPin.Script, env, "output pin", articyPin.Id)) == null) { badScripts = true; } } if (string.IsNullOrEmpty(target.Key)) { GameDebugger.Log(LogLevel.Debug, "Adding output pin to '0x{0:X16}'", target.Id); } else { GameDebugger.Log(LogLevel.Debug, "Adding output pin to '{0}'", target.Key); } pinIndex.Add(articyPin.Id, pin); target.AddOutput(pin); } return(badScripts); }
protected void Lock(QuestPin pin, bool propagate) { QuestObjectState state = GetState(pin); if (state.Locked) { return; } state.Locked = true; GameDebugger.Log(LogLevel.Debug, "QS: {0} '0x{1:X16}' locked", pin.GetType().Name, pin.Id); if (pin.Type == GraphPin.PinType.Input) { if (m_ActivelyChecked.ContainsKey(pin.Id)) { GameDebugger.Log(LogLevel.Debug, "QS: Removing {0} '0x{1:X16}' from the list of actively checked objects", pin.GetType().Name, pin.Id); m_ActivelyChecked.Remove(pin.Id); } } foreach (QuestConnection connection in pin.Connections) { Lock(connection, (connection.Target == pin)); // propagate locking only on incoming connections } if (propagate && pin.Type == GraphPin.PinType.Output) { foreach (QuestPin otherPin in pin.Node.Outputs) { if (otherPin == pin) { continue; } Lock(otherPin, false); } Lock((BaseQuestObject)pin.Node); } }
public void Tick() { QuestObjectState state; bool result; var values = m_ActivelyChecked.Values; IQuestSystemObject[] objects = new IQuestSystemObject[values.Count]; values.CopyTo(objects, 0); GameDebugger.Log(LogLevel.Debug, "QS: TICK"); foreach (IQuestSystemObject obj in objects) { state = GetState(obj); if (state.Locked) { GameDebugger.Log(LogLevel.Warning, "QS: {0} '0x{1:X16}' is in the list of actively checked objects while being locked", obj.GetType().Name, obj.Id); m_ActivelyChecked.Remove(obj.Id); continue; } GameDebugger.Log(LogLevel.Debug, "QS: Checking {0} '0x{1:X16}'", obj.GetType().Name, obj.Id); if (obj is QuestPin) { QuestPin pin = (QuestPin)obj; result = CheckCondition(pin, true); if (result && state.Active == QuestObjectState.ActivationState.PartiallyActive) { state.Active = QuestObjectState.ActivationState.Active; GameDebugger.Log(LogLevel.Debug, "QS: Switched {0} '0x{1:X16}' from partially activated to activated", obj.GetType().Name, obj.Id); if (pin.Node is Quest) { Activate((BaseQuestObject)pin.Node); } else { CheckInputsOnActivation((BaseQuestObject)pin.Node); } foreach (QuestConnection connection in pin.Connections) { if (connection.Source == pin) { Activate(connection); } } } else if (!result && state.Active == QuestObjectState.ActivationState.Active) { state.Active = QuestObjectState.ActivationState.PartiallyActive; GameDebugger.Log(LogLevel.Debug, "QS: Switched {0} '0x{1:X16}' from activated to partially activated", obj.GetType().Name, obj.Id); Deactivate((BaseQuestObject)pin.Node); foreach (QuestConnection connection in pin.Connections) { if (connection.Source == pin) { Deactivate(connection); } } } } else if (obj is QuestCondition) { // every tick depending on it's script execution result it switches active either output[0] or output[1] active QuestCondition condition = (QuestCondition)obj; result = CheckCondition(condition, true); if (result) { if (state.CompletionOutput != 0 || state.Completion == QuestObjectState.CompletionState.Incomplete) { if (state.Completion != QuestObjectState.CompletionState.Incomplete) { Deactivate((QuestPin)condition.Outputs[1]); GameDebugger.Log(LogLevel.Debug, "QS: Switching {0} '0x{1:X16}' output from FALSE to TRUE", obj.GetType().Name, obj.Id); } else { GameDebugger.Log(LogLevel.Debug, "QS: Setting {0} '0x{1:X16}' output to TRUE", obj.GetType().Name, obj.Id); } Activate((QuestPin)condition.Outputs[0]); state.CompletionOutput = 0; } } else { if (state.CompletionOutput != 1 || state.Completion == QuestObjectState.CompletionState.Incomplete) { if (state.Completion != QuestObjectState.CompletionState.Incomplete) { Deactivate((QuestPin)condition.Outputs[0]); GameDebugger.Log(LogLevel.Debug, "QS: Switching {0} '0x{1:X16}' output from TRUE to FALSE", obj.GetType().Name, obj.Id); } else { GameDebugger.Log(LogLevel.Debug, "QS: Setting {0} '0x{1:X16}' output to FALSE", obj.GetType().Name, obj.Id); } Activate((QuestPin)condition.Outputs[1]); state.CompletionOutput = 1; } } state.Completion = QuestObjectState.CompletionState.Successful; } else if (obj is QuestObjective) { // every tick rechecks all conditions on output pins QuestObjective objective = (QuestObjective)obj; int pinIndex = 0; foreach (QuestPin pin in objective.Outputs) { if (pin.Script == null) { pinIndex++; continue; } result = CheckCondition(pin, false); if (result) { Activate(pin); // this will also deactivate previously active pin break; // Just in case when there is more than one output that passes the check. We don't want lots of unneeded events, right? } if (pinIndex == state.CompletionOutput && state.Completion != QuestObjectState.CompletionState.Incomplete) { state.Completion = QuestObjectState.CompletionState.Incomplete; GameDebugger.Log(LogLevel.Debug, "QS: event: OnQuestObjectiveIncomplete"); if (OnQuestObjectiveIncomplete != null) { OnQuestObjectiveIncomplete.Invoke(new QuestObjectiveIncompleteEventArgs(objective)); } } Deactivate(pin); pinIndex++; } } else { GameDebugger.Log(LogLevel.Warning, "QS: {0} '0x{1:X16}' is not supposed to be in the list of actively checked objects", obj.GetType().Name, obj.Id); } } }
protected void Lock(QuestPin pin) { Lock(pin, true); }
protected void Activate(QuestPin pin) { QuestObjectState state = GetState(pin); if (state.Locked || state.Active != QuestObjectState.ActivationState.Inactive) { return; } bool lockPin = false; if (pin.Type == GraphPin.PinType.Input) { if (pin.Script != null) { GameDebugger.Log(LogLevel.Debug, "QS: Partially activated pin '0x{0:X16}'", pin.Id); GameDebugger.Log(LogLevel.Debug, "QS: Adding pin '0x{0:X16}' to the list of actively checked objects", pin.Id); state.Active = QuestObjectState.ActivationState.PartiallyActive; m_ActivelyChecked.Add(pin.Id, pin); } else { state.Active = QuestObjectState.ActivationState.Active; GameDebugger.Log(LogLevel.Debug, "QS: Activated pin '0x{0:X16}'", pin.Id); if (pin.Node is Quest) { Activate((BaseQuestObject)pin.Node); } else { CheckInputsOnActivation((BaseQuestObject)pin.Node); } } } else { state.Active = QuestObjectState.ActivationState.Active; GameDebugger.Log(LogLevel.Debug, "QS: Activated pin '0x{0:X16}'", pin.Id); if (pin.Node is Quest || pin.Node is QuestObjective) { QuestObjectState nodeState = GetState((IQuestSystemObject)pin.Node); int pinIndex = 0; foreach (QuestPin testPin in pin.Node.Outputs) { if (testPin == pin) { GameDebugger.Log(LogLevel.Debug, "QS: Detected pin index: {0}", pinIndex); break; } pinIndex++; } if (nodeState.Completion == QuestObjectState.CompletionState.Incomplete || nodeState.CompletionOutput != pinIndex) { if (nodeState.Completion != QuestObjectState.CompletionState.Incomplete) { Deactivate((QuestPin)pin.Node.Outputs[nodeState.CompletionOutput]); GameDebugger.Log(LogLevel.Debug, "QS: Switching {0} '0x{1:X16}' completion state from {2} to {3}", pin.Node.GetType().Name, ((IQuestSystemObject)pin.Node).Id, nodeState.CompletionOutput, pinIndex); } else { GameDebugger.Log(LogLevel.Debug, "QS: Setting {0} '0x{1:X16}' completion state to {2}", pin.Node.GetType().Name, ((IQuestSystemObject)pin.Node).Id, pinIndex); } nodeState.CompletionOutput = (byte)pinIndex; nodeState.Completion = pin.IsFailureOutput ? QuestObjectState.CompletionState.Failed : QuestObjectState.CompletionState.Successful; if (pin.Node is Quest) { lockPin = true; GameDebugger.Log(LogLevel.Debug, "QS: event: OnQuestComplete"); if (OnQuestComplete != null) { OnQuestComplete.Invoke(new QuestCompleteEventArgs((Quest)pin.Node, pinIndex, pin.IsFailureOutput)); } } else { GameDebugger.Log(LogLevel.Debug, "QS: event: OnQuestObjectiveComplete"); if (OnQuestObjectiveComplete != null) { OnQuestObjectiveComplete.Invoke(new QuestObjectiveCompleteEventArgs((QuestObjective)pin.Node, pinIndex, pin.IsFailureOutput)); } } } } if (!(pin.Node is QuestObjective)) // quest objectives have conditions instead of instructions on outputs { ExecuteScript(pin); } } // activate all outgoing connections if (state.Active == QuestObjectState.ActivationState.Active) { foreach (QuestConnection connection in pin.Connections) { if (connection.Source == pin) { Activate(connection); } } } // locking the pin must be done in the end otherwise it will not activate connections (they will be already locked) if (lockPin) { Lock(pin); } }