From 92eb327b7ba59e7068224bb31dfbba84633bc4d8 Mon Sep 17 00:00:00 2001 From: "Johnny C. Lam" Date: Tue, 15 Oct 2013 01:24:39 +0000 Subject: [PATCH] Split the generic "operator" node into "arithmetic" and "compare" nodes. "Arithmetic" and "compare" nodes return different things when computed, so split the computation into separate functions. Modify the arithmetic computations so that the resulting values have an origin of atTime, since all computations will ultimately be carried out at t = atTime. git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@1044 d5049fe3-3747-40f7-a4b5-f36d6801af5f --- OvaleBestAction.lua | 361 +++++++++++++++++++++++++-------------------------- OvaleCompile.lua | 30 ++++- 2 files changed, 198 insertions(+), 193 deletions(-) diff --git a/OvaleBestAction.lua b/OvaleBestAction.lua index f250fea..5bfdec3 100644 --- a/OvaleBestAction.lua +++ b/OvaleBestAction.lua @@ -143,6 +143,179 @@ local function ComputeAnd(element, atTime) return startB, endB, prioriteB, elementB end +local function ComputeArithmetic(element, atTime) + local self = OvaleBestAction + local startA, endA, _, elementA = self:Compute(element.a, atTime) + local startB, endB, _, elementB = self:Compute(element.b, atTime) + + -- Take intersection of (startA, endA) and (startB, endB) + if isBefore(startA, startB) then + startA = startB + end + if isAfter(endA, endB) then + endA = endB + end + if not isBefore(startA, endA) then + return nil + end + + --[[ + A(t) = a + (t - b)*c + B(t) = x + (t - y)*z + + Silently "typecast" non-values to a constant value of 0. + --]] + local a = elementA and elementA.value or 0 + local b = elementA and elementA.origin or 0 + local c = elementA and elementA.rate or 0 + local x = elementB and elementB.value or 0 + local y = elementB and elementB.origin or 0 + local z = elementB and elementB.rate or 0 + + Ovale:Logf("%f+(t-%f)*%f %s %f+(t-%f)*%f [%d]", a, b, c, element.operator, x, y, z, element.nodeId) + + -- result(t) = l + (t - m) * n + local l, m, n + + --[[ + A(t) = a + (t - b)*c = a + (t - t0 + t0 - b)*c = [a + (t0 - b)*c] + (t - t0)*c = A(t0) + (t - t0)*c + B(t) = x + (t - y)*z = x + (t - t0 + t0 - y)*z = [x + (t0 - y)*z] + (t - t0)*z = B(t0) + (t - t0)*z + --]] + local A = a + (atTime - b)*c + local B = x + (atTime - y)*z + + if element.operator == "+" then + --[[ + A(t) = A(t0) + (t - t0)*c + B(t) = B(t0) + (t - t0)*z + + A(t) + B(t) = [A(t0) + B(t0)] + (t - t0)*(c + z) + --]] + l = A + B + m = atTime + n = c + z + elseif element.operator == "-" then + --[[ + A(t) = A(t0) + (t - t0)*c + B(t) = B(t0) + (t - t0)*z + + A(t) - B(t) = [A(t0) - B(t0)] + (t - t0)*(c - z) + --]] + l = A - B + m = atTime + n = c - z + elseif element.operator == "*" then + --[[ + A(t) = A(t0) + (t - t0)*c + B(t) = B(t0) + (t - t0)*z + --]] + if c == 0 then + l = A * B + m = atTime + n = A * z + elseif z == 0 then + l = A * B + m = atTime + n = c * B + else + Ovale:Error("at least one value must be constant when multiplying") + return nil + end + elseif element.operator == "/" then + --[[ + A(t) = A(t0) + (t - t0)*c + A(t)/B(t0) = [A(t0)/B(t0)] + (t - t0)*[c / B(t0)] + + Divide by B(t0) instead of B(t) to allow constructs like {target.Health() / target.TimeToDie()}. + --]] + l = A / B + m = atTime + n = c / B + elseif element.operator == "%" then + if c == 0 and z == 0 then + l = A % B + m = atTime + n = 0 + else + Ovale:Error("Parameters of % must be constants") + return nil + end + end + Ovale:Logf("result = %f+(t-%f)*%f [%d]", l, m, n, element.nodeId) + return startA, endA, OVALE_DEFAULT_PRIORITY, PutValue(element, l, m, n) +end + +local function ComputeCompare(element, atTime) + local self = OvaleBestAction + local startA, endA, _, elementA = self:Compute(element.a, atTime) + local startB, endB, _, elementB = self:Compute(element.b, atTime) + + -- Take intersection of (startA, endA) and (startB, endB) + if isBefore(startA, startB) then + startA = startB + end + if isAfter(endA, endB) then + endA = endB + end + if not isBefore(startA, endA) then + return nil + end + + --[[ + A(t) = a + (t - b)*c + B(t) = x + (t - y)*z + + Silently "typecast" non-values to a constant value of 0. + --]] + local a = elementA and elementA.value or 0 + local b = elementA and elementA.origin or 0 + local c = elementA and elementA.rate or 0 + local x = elementB and elementB.value or 0 + local y = elementB and elementB.origin or 0 + local z = elementB and elementB.rate or 0 + + Ovale:Logf("%f+(t-%f)*%f %s %f+(t-%f)*%f [%d]", a, b, c, element.operator, x, y, z, element.nodeId) + + --[[ + A(t) = B(t) + a + (t - b)*c = x + (t - y)*z + a + t*c - b*c = x + t*z - y*z + t*c - t*z = (x - y*z) - (a - b*c) + t*(c - z) = B(0) - A(0) + --]] + local A = a - b*c + local B = x - y*z + if c == z then + if (element.operator == "==" and A == B) + or (element.operator == "<" and A < B) + or (element.operator == "<=" and A <= B) + or (element.operator == ">" and A > B) + or (element.operator == ">=" and A >= B) then + return startA, endA + end + else + local t = (B - A)/(c - z) + if (c > z and element.operator == "<") + or (c > z and element.operator == "<=") + or (c < z and element.operator == ">") + or (c < z and element.operator == ">=") then + -- (startA, endA) intersect (-inf, t) + endA = minTime(endA, t) + end + if (c < z and element.operator == "<") + or (c < z and element.operator == "<=") + or (c > z and element.operator == ">") + or (c > z and element.operator == ">=") then + -- (startA, endA) intersect (t, inf) + startA = maxTime(startA, t) + end + if isBefore(startA, endA) then + return startA, endA + end + end + return nil +end + local function ComputeCustomFunction(element, atTime) Ovale:Logf("custom function %s", element.name) local self = OvaleBestAction @@ -396,191 +569,6 @@ local function ComputeOr(element, atTime) return startB, endB end -local function ComputeOperator(element, atTime) - local self = OvaleBestAction - local startA, endA, prioA, elementA = self:Compute(element.a, atTime) - local startB, endB, prioB, elementB = self:Compute(element.b, atTime) - if not elementA or not elementB then - Ovale:Logf("operator %s: elementA or elementB is nil", element.operator) - return nil - end - - -- A(t) = a + (t - b) * c - -- B(t) = x + (t - y) * z - local a, b, c - local x, y, z - - if elementA then - a = elementA.value - b = elementA.origin - c = elementA.rate - else - -- A boolean used in a number context has the value 1 - a = 1 - b = 0 - c = 0 - end - if elementB then - x = elementB.value - y = elementB.origin - z = elementB.rate - else - x = 1 - y = 0 - z = 0 - end - - if startA == endA then - startA, endA = 0, nil - a, b, c = 0, 0, 0 - end - if startB == endB then - startB, endB = 0, nil - x, y, z = 0, 0, 0 - end - - if isBefore(startA, startB) then - startA = startB - end - if isAfter(endA, endB) then - endA = endB - end - - if not a or not x or not b or not y then - Ovale:Logf("operator %s: a or x is nil", element.operator) - return nil - end - - Ovale:Logf("%f+(t-%f)*%f %s %f+(t-%f)*%f", a, b, c, element.operator, x, y, z) - - -- result(t) = l + (t - m) * n - local l, m, n - - if element.operator == "*" then - if c == 0 then - l = a * x - m = y - n = a * z - elseif z == 0 then - l = x * a - m = b - n = x * c - else - Ovale:Error("at least one value must be constant when multiplying") - return nil - end - elseif element.operator == "+" then - if c + z == 0 then - l = (a + x) - (b - y) * c - m = 0 - n = 0 - else - l = a + x - m = (b * c + y * z) / (c + z) - n = c + z - end - elseif element.operator == "-" then - if c - z == 0 then - l = (a - x) - (b - y) * c - m = 0 - n = 0 - else - l = a - x - m = (b * c - y * z) / (c - z) - n = c - z - end - elseif element.operator == "/" then - if z ~= 0 then - -- To allow constructs like {target.Health() / target.DeadIn()} - x = x + (atTime - y) * z - end - l = a / x - m = b - n = c / x - elseif element.operator == "%" then - if c == 0 and z == 0 then - l = c % z - m = 0 - n = 0 - else - Ovale:Error("Parameters of % must be constants") - return nil - end - else - -- Comparisons - -- a + (t-b)*c = x + (t-y)*z - -- (t-b)*c - (t-y)*z = x-a - -- t*c - b*c - t*z + y*z = x-a - -- t*(c-z) = x-a + b*c - y*z - -- t = (x-a + b*c - y*z)/(c-z) - local A, B, t - if c == z then - A = a - b * c - B = x - y * z - else - t = (x - a + b * c - y * z) / (c - z) - end - if element.operator == "<" then - if c == z then - if A < B then - return startA, endA - else - return nil - end - elseif c > z then - return startA, minTime(endA, t) - else - return maxTime(startA, t), endA - end - elseif element.operator == "<=" then - if c == z then - if A <= B then - return startA, endA - else - return nil - end - elseif c > z then - return startA, minTime(endA, t) - else - return maxTime(startA, t), endA - end - elseif element.operator == ">" then - if c == z then - if A > B then - return startA, endA - else - return nil - end - elseif c < z then - return startA, minTime(endA, t) - else - return maxTime(startA, t), endA - end - elseif element.operator == ">=" then - if c == z then - if A >= B then - return startA, endA - else - return nil - end - elseif c < z then return - startA, minTime(endA, t) - else - return maxTime(startA, t), endA - end - elseif element.operator == "==" then - if c == z and A == B then - return startA, endA - else - return nil - end - end - end - - Ovale:Logf("result = %f+(t-%f)*%f", l, m, n) - return startA, endA, OVALE_DEFAULT_PRIORITY, PutValue(element, l, m, n) -end - local function ComputeUnless(element, atTime) Ovale:Logf("%s [%d]", element.type, element.nodeId) local self = OvaleBestAction @@ -633,13 +621,14 @@ end local OVALE_COMPUTE_VISITOR = { ["and"] = ComputeAnd, + ["arithmetic"] = ComputeArithmetic, + ["compare"] = ComputeCompare, ["customfunction"] = ComputeCustomFunction, ["function"] = ComputeFunction, ["group"] = ComputeGroup, ["if"] = ComputeAnd, ["lua"] = ComputeLua, ["not"] = ComputeNot, - ["operator"] = ComputeOperator, ["or"] = ComputeOr, ["unless"] = ComputeUnless, ["value"] = ComputeValue, diff --git a/OvaleCompile.lua b/OvaleCompile.lua index a67aeef..ba48388 100644 --- a/OvaleCompile.lua +++ b/OvaleCompile.lua @@ -432,13 +432,29 @@ local function ParseOr(a,b) return AddNode(node) end -local function ParseOp(a, op, b) - local node = self_pool:Get() - node.type = "operator" - node.operator = op - node.a = self_node[tonumber(a)] - node.b = self_node[tonumber(b)] - return AddNode(node) +local ParseOp +do + local operator = { + ["+"] = "arithmetic", + ["-"] = "arithmetic", + ["*"] = "arithmetic", + ["/"] = "arithmetic", + ["%"] = "arithmetic", + ["<"] = "compare", + ["<="] = "compare", + ["=="] = "compare", + [">="] = "compare", + [">"] = "compare", + } + + function ParseOp(a, op, b) + local node = self_pool:Get() + node.type = operator[op] + node.operator = op + node.a = self_node[tonumber(a)] + node.b = self_node[tonumber(b)] + return AddNode(node) + end end local function ParseGroup(text) -- 1.7.9.5