public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5PlayerReference player = TES5ReferenceFactory.CreateReferenceToPlayer(globalScope); TES5ObjectCallArguments arguments = objectCallArgumentsFactory.CreateArgumentList(function.Arguments, codeScope, globalScope, multipleScriptsScope); return(objectCallFactory.CreateObjectCall(player, "SetDisplayName", arguments)); }
/* * Create a generic-purpose reference. */ private ITES5Referencer CreateReference(string referenceName, TES5BasicType?typeForNewProperty, string?tes4ReferenceNameForType, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope, TES5LocalScope localScope) { if (TES5PlayerReference.EqualsPlayer(referenceName)) { return(CreateReferenceToPlayer(globalScope)); } Match match = ReferenceAndPropertyNameRegex.Match(referenceName); if (match.Success) { TES5ObjectProperty propertyReference = this.objectPropertyFactory.CreateObjectProperty(match.Groups[1].Value, match.Groups[2].Value, this, localScope, globalScope, multipleScriptsScope); return(propertyReference); } ITES5VariableOrProperty?property = localScope.TryGetVariable(referenceName); if (property == null) { property = globalScope.TryGetPropertyByOriginalName(referenceName); //todo rethink how to unify the prefix searching if (property == null) { Nullable <int> tes4FormID = null; ITES5Type propertyType = typeForNewProperty != null ? typeForNewProperty : GetPropertyTypeAndFormID(referenceName, tes4ReferenceNameForType, globalScope, multipleScriptsScope, out tes4FormID); TES5Property propertyToAddToGlobalScope = TES5PropertyFactory.ConstructWithTES4FormID(referenceName, propertyType, referenceName, tes4FormID); globalScope.AddProperty(propertyToAddToGlobalScope); property = propertyToAddToGlobalScope; } } return(CreateReferenceToVariableOrProperty(property)); }
/* * Create a generic-purpose reference. */ public ITES5Referencer CreateReference(string referenceName, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope, TES5LocalScope localScope) { if (TES5PlayerReference.EqualsPlayer(referenceName)) { return(CreateReferenceToPlayer()); } referenceName = PapyrusCompiler.FixReferenceName(referenceName); Match match = PropertyNameRegex.Match(referenceName); if (match.Success) { ITES5Referencer mainReference = this.CreateReference(match.Groups[1].Value, globalScope, multipleScriptsScope, localScope); TES5ObjectProperty propertyReference = this.objectPropertyFactory.CreateObjectProperty(multipleScriptsScope, mainReference, match.Groups[2].Value); //Todo rethink the prefix adding return(propertyReference); } ITES5VariableOrProperty property = localScope.GetVariable(referenceName); if (property == null) { property = globalScope.GetPropertyByName(referenceName); //todo rethink how to unify the prefix searching if (property == null) { TES5Property propertyToAddToGlobalScope = null; ITES5Type specialConversion; if (specialConversions.TryGetValue(referenceName, out specialConversion)) { propertyToAddToGlobalScope = new TES5Property(referenceName, specialConversion, referenceName); } if (propertyToAddToGlobalScope == null) { if (!multipleScriptsScope.ContainsGlobalVariable(referenceName)) { propertyToAddToGlobalScope = new TES5Property(referenceName, TES5BasicType.T_FORM, referenceName); } else { propertyToAddToGlobalScope = new TES5Property(referenceName, TES5BasicType.T_GLOBALVARIABLE, referenceName); } } globalScope.AddProperty(propertyToAddToGlobalScope); property = propertyToAddToGlobalScope; } } return(new TES5Reference(property)); }
public override ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5LocalScope localScope = codeScope.LocalScope; TES4FunctionArguments functionArguments = function.Arguments; TES5ObjectCallArguments convertedArguments = new TES5ObjectCallArguments(); Dictionary <string, string> actorValueMap = ActorValueMap.Map; ITES4StringValue firstArg = functionArguments[0]; string firstArgString = firstArg.StringValue; string firstArgStringLower = firstArgString.ToLower(); switch (firstArgStringLower) { case "strength": case "intelligence": case "willpower": case "agility": case "endurance": case "personality": case "luck": { if (!TES5PlayerReference.EqualsPlayer(calledOn.Name)) { //We can"t convert those.. and shouldn"t be any, too. throw new ConversionException("[" + TES4FunctionName + "] Cannot set attributes on non-player"); } const string functionName = "SetValue"; calledOn = this.referenceFactory.CreateReference(TES5ReferenceFactory.TES4Attr + PHPFunction.UCWords(firstArgStringLower), globalScope, multipleScriptsScope, localScope); ITES4StringValue secondArg = functionArguments[1]; convertedArguments.Add(this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope)); return(CreateObjectCall(calledOn, functionName, multipleScriptsScope, convertedArguments)); } case "speed": { const string functionName = "ForceMovementSpeed"; ITES4StringValue secondArg = functionArguments[1]; convertedArguments.Add(this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope)); return(CreateObjectCall(calledOn, functionName, multipleScriptsScope, convertedArguments)); } case "fatigue": case "armorer": case "security": case "acrobatics": case "mercantile": case "mysticism": //It doesn"t exist in Skyrim - defaulting to Illusion.. case "blade": case "blunt": case "encumbrance": case "spellabsorbchance": case "resistfire": case "resistfrost": case "resistdisease": case "resistmagic": case "resistpoison": case "resistshock": { convertedArguments.Add(new TES5String(actorValueMap[firstArgStringLower])); ITES4StringValue secondArg = functionArguments[1]; convertedArguments.Add(this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope)); return(CreateObjectCall(calledOn, TES5FunctionName, multipleScriptsScope, convertedArguments)); } case "aggression": { ITES4StringValue secondArg = functionArguments[1]; object secondArgObject = secondArg.Data; Nullable <int> secondArgNullableInt = secondArgObject as Nullable <int>; AST.Value.ITES5Value convertedArgument2; if (secondArgNullableInt != null) { //WTM: Change: This apparently went unnoticed in the PHP version. The second argument is not always an integer. Sometimes its a variable reference. //But the value of the variable will not be properly scaled to the values below, so the converted script may operate incorrectly. int secondArgInt = secondArgNullableInt.Value; float newValue; if (secondArgInt == 0) { newValue = 0; } else if (secondArgInt > 0 && secondArgInt < 50) { newValue = 1; } else if (secondArgInt >= 50 && secondArgInt < 80) { newValue = 2; } else { newValue = 3; } convertedArgument2 = new TES5Float(newValue); } else { convertedArgument2 = this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope); } convertedArguments.Add(new TES5String(firstArgString)); convertedArguments.Add(convertedArgument2); return(CreateObjectCall(calledOn, TES5FunctionName, multipleScriptsScope, convertedArguments)); } case "confidence": { ITES4StringValue secondArg = functionArguments[1]; int secondArgData = (int)secondArg.Data; float newValue; if (secondArgData == 0) { newValue = 0; } else if (secondArgData > 0 && secondArgData < 30) { newValue = 1; } else if (secondArgData >= 30 && secondArgData < 70) { newValue = 2; } else if (secondArgData >= 70 && secondArgData < 99) { newValue = 3; } else { newValue = 4; } convertedArguments.Add(new TES5String(firstArgString)); convertedArguments.Add(new TES5Float(newValue)); return(CreateObjectCall(calledOn, TES5FunctionName, multipleScriptsScope, convertedArguments)); } default: { convertedArguments.Add(new TES5String(firstArgString)); ITES4StringValue secondArg = functionArguments[1]; convertedArguments.Add(this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope)); return(CreateObjectCall(calledOn, TES5FunctionName, multipleScriptsScope, convertedArguments)); } } }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES4FunctionArguments functionArguments = function.Arguments; TES5LocalScope localScope = codeScope.LocalScope; if (function.FunctionCall.FunctionName.Equals("modpcskill", StringComparison.OrdinalIgnoreCase)) { /* * MODPCSkill means we will need to call upon the player object */ calledOn = TES5ReferenceFactory.CreateReferenceToPlayer(); } TES5ObjectCallArguments convertedArguments = new TES5ObjectCallArguments(); var actorValueMap = ActorValueMap.Map; string firstArgString = functionArguments[0].StringValue; string firstArgStringLower = firstArgString.ToLower(); switch (firstArgStringLower) { case "strength": case "intelligence": case "willpower": case "agility": case "speed": case "endurance": case "personality": case "luck": { if (!TES5PlayerReference.EqualsPlayer(calledOn.Name)) { //We can"t convert those.. and shouldn"t be any, too. throw new ConversionException(nameof(ModActorValueFactory) + ": Cannot set attributes on non-player. Name: " + calledOn.Name + ", Argument: " + firstArgString); } const string functionName = "SetValue"; string tes4AttrFirstArg = TES5ReferenceFactory.TES4Attr + PHPFunction.UCWords(firstArgStringLower); /* * Switch out callee with the reference to attr */ ITES5Referencer newCalledOn = this.referenceFactory.CreateReference(tes4AttrFirstArg, globalScope, multipleScriptsScope, localScope); ITES4StringValue secondArg = functionArguments[1]; ITES5Value addedValue = this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope); convertedArguments.Add(TES5ExpressionFactory.CreateArithmeticExpression(addedValue, TES5ArithmeticExpressionOperator.OPERATOR_ADD, this.referenceFactory.CreateReadReference(tes4AttrFirstArg, globalScope, multipleScriptsScope, localScope))); return(this.objectCallFactory.CreateObjectCall(newCalledOn, functionName, multipleScriptsScope, convertedArguments)); } case "fatigue": case "armorer": case "security": case "acrobatics": case "mercantile": case "mysticism": //It doesn"t exist in Skyrim - defaulting to Illusion.. case "blade": case "blunt": case "encumbrance": case "spellabsorbchance": case "resistfire": case "resistfrost": case "resistdisease": case "resistmagic": case "resistpoison": case "resistshock": { const string functionName = "ModActorValue"; convertedArguments.Add(new TES5String(actorValueMap[firstArgStringLower])); ITES4StringValue secondArg = functionArguments[1]; convertedArguments.Add(this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope)); return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, multipleScriptsScope, convertedArguments)); } case "aggression": { const string functionName = "ModActorValue"; ITES4StringValue secondArg = functionArguments[1]; int secondArgData = (int)secondArg.Data; int newValue; if (secondArgData < -80) { newValue = -3; } else if (secondArgData >= -80 && secondArgData < -50) { newValue = -2; } else if (secondArgData >= -50 && secondArgData < 0) { newValue = -1; } else if (secondArgData == 0) { newValue = 0; } else if (secondArgData > 0 && secondArgData < 50) { newValue = 1; } else if (secondArgData >= 50 && secondArgData < 80) { newValue = 2; } else { newValue = 3; } convertedArguments.Add(new TES5String(firstArgString)); convertedArguments.Add(new TES5Float(newValue)); return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, multipleScriptsScope, convertedArguments)); } case "confidence": { const string functionName = "ModActorValue"; ITES4StringValue secondArg = functionArguments[1]; int secondArgData = (int)secondArg.Data; int newValue; if (secondArgData == -100) { newValue = -4; } else if (secondArgData <= -70 && secondArgData > -100) { newValue = -3; } else if (secondArgData <= -30 && secondArgData > -70) { newValue = -2; } else if (secondArgData < 0 && secondArgData > -30) { newValue = -1; } else if (secondArgData == 0) { newValue = 0; } else if (secondArgData > 0 && secondArgData < 30) { newValue = 1; } else if (secondArgData >= 30 && secondArgData < 70) { newValue = 2; } else if (secondArgData >= 70 && secondArgData < 99) { newValue = 3; } else { newValue = 4; } convertedArguments.Add(new TES5String(firstArgString)); convertedArguments.Add(new TES5Float(newValue)); return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, multipleScriptsScope, convertedArguments)); } default: { const string functionName = "ModActorValue"; convertedArguments.Add(new TES5String(firstArgString)); ITES4StringValue secondArg = functionArguments[1]; convertedArguments.Add(this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope)); return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, multipleScriptsScope, convertedArguments)); } } }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5LocalScope localScope = codeScope.LocalScope; const string functionName = "GetActorValue"; TES4FunctionArguments functionArguments = function.Arguments; //@TODO - This should be fixed on expression-parsing level, with agression and confidence checks adjusted accordingly. There are no retail uses, so im not doing this for now ;) ITES4StringValue firstArg = functionArguments[0]; string firstArgString = firstArg.StringValue; string firstArgStringLower = firstArgString.ToLower(); switch (firstArgStringLower) { case "strength": case "intelligence": case "willpower": case "agility": case "speed": case "endurance": case "personality": case "luck": { if (!TES5PlayerReference.EqualsPlayer(calledOn.Name)) { if (calledOn.TES5Type.NativeType == TES5BasicType.T_ACTOR) //WTM: Change: I added this if branch. { TES5ObjectCallArguments convertedArguments = new TES5ObjectCallArguments() { new TES5String(firstArgString) }; return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, convertedArguments)); } //We can"t convert those.. and shouldn"t be any, too. throw new ConversionException(nameof(GetActorValueFactory) + ": Cannot get attributes on non-player. Name: " + calledOn.Name + ", Argument: " + firstArgString); } /* * Switch out callee with the reference to attr */ string tes4AttrFirstArg = TES5ReferenceFactory.GetTES4AttrPlusName(firstArgStringLower); return(this.referenceFactory.CreateReadReference(tes4AttrFirstArg, globalScope, multipleScriptsScope, localScope)); } case "fatigue": case "armorer": case "security": case "acrobatics": case "mercantile": case "mysticism": //It doesn"t exist in Skyrim - defaulting to Illusion.. case "blade": case "blunt": case "encumbrance": case "spellabsorbchance": case "resistfire": case "resistfrost": case "resistdisease": case "resistmagic": case "resistpoison": case "resistshock": { TES5ObjectCallArguments convertedArguments = new TES5ObjectCallArguments() { new TES5String(ActorValueMap.Map[firstArgStringLower]) }; return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, convertedArguments)); } default: { TES5ObjectCallArguments convertedArguments = new TES5ObjectCallArguments() { new TES5String(firstArgString) }; return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, convertedArguments)); } } }