Ejemplo n.º 1
0
        public float EvalTag(TagKeyScript key)
        {
            float result;

            if (!ScriptFormulaEvaluator.Evaluate(this.PowerSNO, key,
                                                 User.Attributes, Rand, out result))
            {
                return(0);
            }

            return(result);
        }
Ejemplo n.º 2
0
        private static ScriptFormula FindScriptFormula(int powerSNO, TagKeyScript scriptTag)
        {
            TagMap tagmap = PowerTagHelper.FindTagMapWithKey(powerSNO, scriptTag);

            if (tagmap != null)
            {
                return(tagmap[scriptTag]);
            }
            else
            {
                return(null);
            }
        }
Ejemplo n.º 3
0
        private static bool LoadIdentifier(int powerSNO, TagKeyScript scriptTag, GameAttributeMap attributes, Random rand,
                                           int numb1, int numb2, int numb3, int numb4,
                                           out float result)
        {
            switch (numb1)
            {
            case 0:
                return(LoadAttribute(powerSNO, attributes, numb2, out result));

            case 1:     // slevel
                result = attributes[GameAttribute.Skill, powerSNO];
                return(true);

            case 22:     // absolute power formula ref
                return(Evaluate(numb2, new TagKeyScript(numb3), attributes, rand, out result));

            default:
                if (numb1 >= 23 && numb1 <= 62)     // SF_N, relative power formula ref
                {
                    int          SF_N        = numb1 - 23;
                    TagKeyScript relativeTag = PowerTagHelper.GenerateTagForScriptFormula(SF_N);
                    return(Evaluate(powerSNO, relativeTag, attributes, rand, out result));
                }
                else if (numb1 >= 63 && numb1 <= 72)     // known gamebalance power table id range
                {
                    result = BinaryIntToFloat(numb1);    // simply store id, used later by Table()
                    return(true);
                }
                else
                {
                    Logger.Error("unknown identifier");
                    result = 0;
                    return(false);
                }
            }
        }
Ejemplo n.º 4
0
        public static bool Evaluate(int powerSNO, TagKeyScript scriptTag, GameAttributeMap attributes, Random rand, out float result)
        {
            result = 0;

            ScriptFormula scriptFormula = FindScriptFormula(powerSNO, scriptTag);

            if (scriptFormula == null)
            {
                //Logger.Error("could not find script tag {0} in power {1}", scriptTag.ID, powerSNO);
                return(false);
            }

            byte[]        script = scriptFormula.OpCodeArray;
            Stack <float> stack = new Stack <float>(4);  // analysis of all stack formulas found the biggest stack is currently 11
            int           pos = 0;
            float         numb1, numb2, numb3;
            float         temp;

            while (pos < script.Length)
            {
                switch (script[pos])
                {
                case 0:     // return
                    if (StackUnderflow(stack, 1))
                    {
                        return(false);
                    }
                    result = stack.Pop();
                    return(true);

                case 1:     // function
                    pos += 4;
                    switch (script[pos])
                    {
                    case 0:         // Min()
                        if (StackUnderflow(stack, 2))
                        {
                            return(false);
                        }
                        numb2 = stack.Pop();
                        numb1 = stack.Pop();
                        stack.Push(Math.Min(numb1, numb2));
                        break;

                    case 1:         // Max()
                        if (StackUnderflow(stack, 2))
                        {
                            return(false);
                        }
                        numb2 = stack.Pop();
                        numb1 = stack.Pop();
                        stack.Push(Math.Max(numb1, numb2));
                        break;

                    case 2:         // Pin()
                        if (StackUnderflow(stack, 3))
                        {
                            return(false);
                        }
                        numb3 = stack.Pop();
                        numb2 = stack.Pop();
                        numb1 = stack.Pop();
                        if (numb2 > numb1)
                        {
                            stack.Push(numb2);
                        }
                        else if (numb1 > numb3)
                        {
                            stack.Push(numb3);
                        }
                        else
                        {
                            stack.Push(numb1);
                        }

                        break;

                    case 3:         // RandomIntMinRange()
                        if (StackUnderflow(stack, 2))
                        {
                            return(false);
                        }
                        numb2 = stack.Pop();
                        numb1 = stack.Pop();
                        stack.Push(rand.Next((int)numb1, (int)numb1 + (int)numb2));
                        break;

                    case 4:         // RandomIntMinMax()
                        if (StackUnderflow(stack, 2))
                        {
                            return(false);
                        }
                        numb2 = stack.Pop();
                        numb1 = stack.Pop();
                        stack.Push(rand.Next((int)numb1, (int)numb2));
                        break;

                    case 5:         // Floor()
                        if (StackUnderflow(stack, 1))
                        {
                            return(false);
                        }
                        numb1 = stack.Pop();
                        stack.Push((float)Math.Floor(numb1));
                        break;

                    case 9:         // RandomFloatMinRange()
                        if (StackUnderflow(stack, 2))
                        {
                            return(false);
                        }
                        numb2 = stack.Pop();
                        numb1 = stack.Pop();
                        stack.Push(numb1 + (float)rand.NextDouble() * numb2);
                        break;

                    case 10:         // RandomFloatMinMax()
                        if (StackUnderflow(stack, 2))
                        {
                            return(false);
                        }
                        numb2 = stack.Pop();
                        numb1 = stack.Pop();
                        stack.Push(numb1 + (float)rand.NextDouble() * (numb2 - numb1));
                        break;

                    case 11:         // Table()
                        if (StackUnderflow(stack, 2))
                        {
                            return(false);
                        }
                        float index   = stack.Pop();
                        float tableID = stack.Pop();
                        if (!LookupBalanceTable(tableID, index, out temp))
                        {
                            return(false);
                        }
                        stack.Push(temp);
                        break;

                    default:
                        Logger.Error("Unimplemented function");
                        return(false);
                    }
                    break;

                case 5:     // external identifier
                    if (!LoadIdentifier(powerSNO, scriptTag, attributes, rand,
                                        BitConverter.ToInt32(script, pos + 4 * 1),
                                        BitConverter.ToInt32(script, pos + 4 * 2),
                                        BitConverter.ToInt32(script, pos + 4 * 3),
                                        BitConverter.ToInt32(script, pos + 4 * 4),
                                        out temp))
                    {
                        return(false);
                    }

                    stack.Push(temp);
                    pos += 4 * 4;
                    break;

                case 6:     // push float
                    pos += 4;
                    stack.Push(BitConverter.ToSingle(script, pos));
                    break;

                case 8:     // operator >
                    if (StackUnderflow(stack, 2))
                    {
                        return(false);
                    }
                    numb2 = stack.Pop();
                    numb1 = stack.Pop();
                    stack.Push(numb1 > numb2 ? 1 : 0);
                    break;

                case 11:     // operator +
                    if (StackUnderflow(stack, 2))
                    {
                        return(false);
                    }
                    numb2 = stack.Pop();
                    numb1 = stack.Pop();
                    stack.Push(numb1 + numb2);
                    break;

                case 12:     // operator -
                    if (StackUnderflow(stack, 2))
                    {
                        return(false);
                    }
                    numb2 = stack.Pop();
                    numb1 = stack.Pop();
                    stack.Push(numb1 - numb2);
                    break;

                case 13:     // operator *
                    if (StackUnderflow(stack, 2))
                    {
                        return(false);
                    }
                    numb2 = stack.Pop();
                    numb1 = stack.Pop();
                    stack.Push(numb1 * numb2);
                    break;

                case 14:     // operator /
                    if (StackUnderflow(stack, 2))
                    {
                        return(false);
                    }
                    numb2 = stack.Pop();
                    numb1 = stack.Pop();
                    if (numb2 == 0f)
                    {
                        Logger.Error("Division by zero, 0 pushed to stack instead of divide result");
                        stack.Push(0f);
                    }
                    else
                    {
                        stack.Push(numb1 / numb2);
                    }
                    break;

                case 16:     // operator -(unary)
                    if (StackUnderflow(stack, 1))
                    {
                        return(false);
                    }
                    numb1 = stack.Pop();
                    stack.Push(-numb1);
                    break;

                case 17:     // operator ?:
                    if (StackUnderflow(stack, 3))
                    {
                        return(false);
                    }
                    numb3 = stack.Pop();
                    numb2 = stack.Pop();
                    numb1 = stack.Pop();
                    stack.Push(numb1 != 0 ? numb2 : numb3);
                    break;

                default:
                    Logger.Error("Unimplemented OpCode({0})", script[pos]);
                    return(false);
                }
                pos += 4;
            }

            // HACK: ignore bad formula
            if (powerSNO == Skills.Skills.Barbarian.FurySpenders.Whirlwind &&
                scriptTag.ID == 266560) // ScriptFormula(4)
            {
                return(true);
            }

            Logger.Error("script finished without return opcode");
            return(false);
        }
Ejemplo n.º 5
0
        public static bool Evaluate(int powerSNO, TagKeyScript scriptTag, GameAttributeMap attributes, Random rand, out float result)
        {
            result = 0;

            ScriptFormula scriptFormula = FindScriptFormula(powerSNO, scriptTag);
            if (scriptFormula == null)
            {
                //Logger.Error("could not find script tag {0} in power {1}", scriptTag.ID, powerSNO);
                return false;
            }

            byte[] script = scriptFormula.OpCodeArray;
            Stack<float> stack = new Stack<float>(4);  // analysis of all stack formulas found the biggest stack is currently 11
            int pos = 0;
            float numb1, numb2, numb3;
            float temp;
            while (pos < script.Length)
            {
                switch (script[pos])
                {
                    case 0: // return
                        if (StackUnderflow(stack, 1))
                            return false;
                        result = stack.Pop();
                        return true;

                    case 1: // function
                        pos += 4;
                        switch (script[pos])
                        {
                            case 0: // Min()
                                if (StackUnderflow(stack, 2))
                                    return false;
                                numb2 = stack.Pop();
                                numb1 = stack.Pop();
                                stack.Push(Math.Min(numb1, numb2));
                                break;

                            case 1: // Max()
                                if (StackUnderflow(stack, 2))
                                    return false;
                                numb2 = stack.Pop();
                                numb1 = stack.Pop();
                                stack.Push(Math.Max(numb1, numb2));
                                break;

                            case 2: // Pin()
                                if (StackUnderflow(stack, 3))
                                    return false;
                                numb3 = stack.Pop();
                                numb2 = stack.Pop();
                                numb1 = stack.Pop();
                                if (numb2 > numb1)
                                    stack.Push(numb2);
                                else if (numb1 > numb3)
                                    stack.Push(numb3);
                                else
                                    stack.Push(numb1);

                                break;

                            case 3: // RandomIntMinRange()
                                if (StackUnderflow(stack, 2))
                                    return false;
                                numb2 = stack.Pop();
                                numb1 = stack.Pop();
                                stack.Push(rand.Next((int)numb1, (int)numb1 + (int)numb2));
                                break;

                            case 4: // RandomIntMinMax()
                                if (StackUnderflow(stack, 2))
                                    return false;
                                numb2 = stack.Pop();
                                numb1 = stack.Pop();
                                stack.Push(rand.Next((int)numb1, (int)numb2));
                                break;

                            case 5: // Floor()
                                if (StackUnderflow(stack, 1))
                                    return false;
                                numb1 = stack.Pop();
                                stack.Push((float)Math.Floor(numb1));
                                break;

                            case 9: // RandomFloatMinRange()
                                if (StackUnderflow(stack, 2))
                                    return false;
                                numb2 = stack.Pop();
                                numb1 = stack.Pop();
                                stack.Push(numb1 + (float)rand.NextDouble() * numb2);
                                break;

                            case 10: // RandomFloatMinMax()
                                if (StackUnderflow(stack, 2))
                                    return false;
                                numb2 = stack.Pop();
                                numb1 = stack.Pop();
                                stack.Push(numb1 + (float)rand.NextDouble() * (numb2 - numb1));
                                break;

                            case 11: // Table()
                                if (StackUnderflow(stack, 2))
                                    return false;
                                float index = stack.Pop();
                                float tableID = stack.Pop();
                                if (!LookupBalanceTable(tableID, index, out temp))
                                    return false;
                                stack.Push(temp);
                                break;

                            default:
                                Logger.Error("Unimplemented function");
                                return false;
                        }
                        break;
                    case 5: // external identifier
                        if (!LoadIdentifier(powerSNO, scriptTag, attributes, rand,
                                            BitConverter.ToInt32(script, pos + 4 * 1),
                                            BitConverter.ToInt32(script, pos + 4 * 2),
                                            BitConverter.ToInt32(script, pos + 4 * 3),
                                            BitConverter.ToInt32(script, pos + 4 * 4),
                                            out temp))
                            return false;

                        stack.Push(temp);
                        pos += 4 * 4;
                        break;

                    case 6: // push float
                        pos += 4;
                        stack.Push(BitConverter.ToSingle(script, pos));
                        break;

                    case 8: // operator >
                        if (StackUnderflow(stack, 2))
                            return false;
                        numb2 = stack.Pop();
                        numb1 = stack.Pop();
                        stack.Push(numb1 > numb2 ? 1 : 0);
                        break;

                    case 11: // operator +
                        if (StackUnderflow(stack, 2))
                            return false;
                        numb2 = stack.Pop();
                        numb1 = stack.Pop();
                        stack.Push(numb1 + numb2);
                        break;

                    case 12: // operator -
                        if (StackUnderflow(stack, 2))
                            return false;
                        numb2 = stack.Pop();
                        numb1 = stack.Pop();
                        stack.Push(numb1 - numb2);
                        break;

                    case 13: // operator *
                        if (StackUnderflow(stack, 2))
                            return false;
                        numb2 = stack.Pop();
                        numb1 = stack.Pop();
                        stack.Push(numb1 * numb2);
                        break;

                    case 14: // operator /
                        if (StackUnderflow(stack, 2))
                            return false;
                        numb2 = stack.Pop();
                        numb1 = stack.Pop();
                        if (numb2 == 0f)
                        {
                            Logger.Error("Division by zero, 0 pushed to stack instead of divide result");
                            stack.Push(0f);
                        }
                        else
                        {
                            stack.Push(numb1 / numb2);
                        }
                        break;

                    case 16: // operator -(unary)
                        if (StackUnderflow(stack, 1))
                            return false;
                        numb1 = stack.Pop();
                        stack.Push(-numb1);
                        break;

                    case 17: // operator ?:
                        if (StackUnderflow(stack, 3))
                            return false;
                        numb3 = stack.Pop();
                        numb2 = stack.Pop();
                        numb1 = stack.Pop();
                        stack.Push(numb1 != 0 ? numb2 : numb3);
                        break;

                    default:
                        Logger.Error("Unimplemented OpCode({0})", script[pos]);
                        return false;
                }
                pos += 4;
            }

            // HACK: ignore bad formula
            if (powerSNO == Skills.Skills.Barbarian.FurySpenders.Whirlwind &&
                scriptTag.ID == 266560) // ScriptFormula(4)
            {
                return true;
            }

            Logger.Error("script finished without return opcode");
            return false;
        }
Ejemplo n.º 6
0
 private static ScriptFormula FindScriptFormula(int powerSNO, TagKeyScript scriptTag)
 {
     TagMap tagmap = PowerTagHelper.FindTagMapWithKey(powerSNO, scriptTag);
     if (tagmap != null)
         return tagmap[scriptTag];
     else
         return null;
 }
Ejemplo n.º 7
0
        private static bool LoadIdentifier(int powerSNO, TagKeyScript scriptTag, GameAttributeMap attributes, Random rand,
                                           int numb1, int numb2, int numb3, int numb4,
                                           out float result)
        {
            switch (numb1)
            {
                case 0:
                    return LoadAttribute(powerSNO, attributes, numb2, out result);

                case 1: // slevel
                    result = attributes[GameAttribute.Skill, powerSNO];
                    return true;

                case 22: // absolute power formula ref
                    return Evaluate(numb2, new TagKeyScript(numb3), attributes, rand, out result);

                default:
                    if (numb1 >= 23 && numb1 <= 62) // SF_N, relative power formula ref
                    {
                        int SF_N = numb1 - 23;
                        TagKeyScript relativeTag = PowerTagHelper.GenerateTagForScriptFormula(SF_N);
                        return Evaluate(powerSNO, relativeTag, attributes, rand, out result);
                    }
                    else if (numb1 >= 63 && numb1 <= 72) // known gamebalance power table id range
                    {
                        result = BinaryIntToFloat(numb1); // simply store id, used later by Table()
                        return true;
                    }
                    else
                    {
                        Logger.Error("unknown identifier");
                        result = 0;
                        return false;
                    }
            }
        }