// Extending from loop has weird, but useful implications for this node. // Also, be careful with parameters. It essentially boils down to copying values around. class LK_SequenceFunction extends LK_SeqFlow_Loop; var() Name FunctionName; struct SequenceFunctionParameter { var() const class ParameterType; var() const bool bIsOutput; var() const string ParameterName; }; var LK_SeqAct_CallFunction Caller; var() Array FunctionParams; event Activated() { // Function completed if(InputLinks[InternalLoopInputIdx].bHasImpulse || InputLinks[BreakInputIdx].bHasImpulse) { Caller.OnFunctionCompleted(self); return; } } public function Execute(LK_SeqAct_CallFunction _Caller) { if(!bHasProcessedChain) { ProcessLoopBody(); bHasProcessedChain = true; } Caller = _Caller; AcceptVars(Caller); ForceActivateOutput(0); } private function AcceptVars(LK_SeqAct_CallFunction Src) { local int i; for(i = 0; i < VariableLinks.Length; i++) { CopySeqVar(Src.VariableLinks[i].LinkedVariables[0], VariableLinks[i].LinkedVariables[0]); } PopulateLinkedVariableValues(); } // shouldn't happen public function NotifiedByUpper(LK_SeqFlow_Loop Op) { return; } public event CheckForErrors(out Array ErrorMessages) { ObjName = "Function Definition: "$String(FunctionName); ObjComment = String(GetReferenceCount())$" reference(s)"; UpdateVariableLinksFor(self, FunctionParams, true); } private function int GetReferenceCount() { local int i, count; local Array objs; ParentSequence.FindSeqObjectsByClass(class'LK_SeqAct_CallFunction', true, objs); for(i = 0; i < objs.Length; i++) { if(LK_SeqAct_CallFunction(objs[i]).TargetFunctionName == FunctionName) count++; } return count; } // A bit of a stupid solution public static function bool CopySeqVar(const SequenceVariable A, SequenceVariable B) { if(A == None || B == None) return false; if(A.Class != B.Class) return false; switch(A.Class) { case class'SeqVar_Int': SeqVar_Int(B).IntValue = SeqVar_Int(A).IntValue; break; case class'SeqVar_Float': SeqVar_Float(B).FloatValue = SeqVar_Float(A).FloatValue; break; case class'SeqVar_Bool': SeqVar_Bool(B).bValue = SeqVar_Bool(A).bValue; break; case class'SeqVar_Object': case class'SeqVar_Player': SeqVar_Object(B).SetObjectValue(SeqVar_Object(B).GetObjectValue()); break; case class'SeqVar_Vector': SeqVar_Vector(B).VectValue = SeqVar_Vector(A).VectValue; break; case class'SeqVar_ObjectList': SeqVar_ObjectList(B).ObjList = SeqVar_ObjectList(A).ObjList; break; case class'SeqVar_String': SeqVar_String(B).StrValue = SeqVar_String(A).StrValue; break; default: break; } return true; } public static function UpdateVariableLinksFor(SequenceOp Op, const Array _FunctionParams, const bool bInvertIsOutput) { local int i; local SeqVarLink l; for(i = 0; i < _FunctionParams.Length; i++) { if(i < Op.VariableLinks.Length) { Op.VariableLinks[i].LinkDesc = _FunctionParams[i].ParameterName; Op.VariableLinks[i].bWriteable = bInvertIsOutput ? !_FunctionParams[i].bIsOutput : _FunctionParams[i].bIsOutput; Op.VariableLinks[i].ExpectedType = _FunctionParams[i].ParameterType; } else { l.LinkDesc = _FunctionParams[i].ParameterName; l.bWriteable = bInvertIsOutput ? !_FunctionParams[i].bIsOutput : _FunctionParams[i].bIsOutput; l.ExpectedType = _FunctionParams[i].ParameterType; l.MaxVars = 1; l.MinVars = 1; Op.VariableLinks.AddItem(l); } } // trim to remove any excess Op.VariableLinks.Length = _FunctionParams.Length; Op.bPendingVarConnectorRecalc = true; Op.bPendingInputConnectorRecalc = true; Op.bPendingOutputConnectorRecalc = true; } defaultproperties { ObjName = "Function Definition" ObjCategory = "Functions" ObjColor = (R=138, G=29, B=29, A=255) InputLinks.Empty; InputLinks(0) = (LinkDesc = "INPUT | DO NOT USE", bHidden=true); InputLinks(1) = (LinkDesc = "RETURN | DO NOT USE", bHidden=true); InternalLoopInputIdx = 0; BreakInputIdx = 1; // RETURN MainInputIdx = -1; // has none LoopBodyIdx = 0; CompletedOutputIdx = -1; // has none OutputLinks.Empty; OutputLinks(0) = (LinkDesc="Function Body") VariableLinks.Empty ObjComment = "Use the Break node to end the function early." FunctionName = "My Function" }