Reverse Polish Notation

From OuroDev
Revision as of 11:33, 3 November 2019 by Jagged (talk | contribs) (Notes from VicariousExp on RPN)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Short Overview of RPN (Reverse Polish Notation) in City of Heroes

City of Heroes uses something called Reverse Polish Notation in its evaluations, which is beyond my scope to explain thoroughly, (just search for it on the internet) but is a stack based approach to Mathematics.

In RPN, you run along an array of numbers until you encounter an operand, upon which you stop and apply the operand to the 2 most recent numbers. What makes this complicated is that City of Heroes uses its own internal functions and operands. However, using a bit of logic, you can crack the code behind how simple functions in City of Heroes works.

Let's use the damage buff version of Defender Vigilance as an example. Vigilance is coded as a flat 30% damage buff which applies multiple additive stacks of 10% damage debuffs when certain conditions are met (party size increases). Each step weakens Vigilance by 10% subtractively.

The code for this looks like this: Requires 0.0 source.TeamSize> 2 > source.TeamSize> is an embedded function (> is not a 'greater than' sign when used without a space after a function name - it seems to be a pointer, so source.TeamSize> means "the team size of the source of this power". I shall use encapsulating brackets () to show that the following is actually one number. Requires (0.0 source.TeamSize>) 2 > It appears that 0.0 is not a number here, it probably just fills in for the variables which source.TeamSize> is pointing to. In effect, the brackets are saying "return the Team Size". Now we can apply normal Math, which I'll use curly braces {} to denote. {Team Size > 2}

It might be counterintuitive, but note that the greater than symbol is referring to the first of the 2 evaluated elements! Don't flip it by mistake. Consider: In RPN, x y - is x - y, not y - x. Now let's break down two more complicated examples:

Defender Vigilance (Using curly braces to show normal math {} and square brackets [] to show what to evaluate next. Normal parentheses are used to encapsulate single elements.) This shows the magnitude of endurance discount which Vigilance gives per allied target. The one line formula looks like this:

MagnitudeExpr            100 kHitPoints% target> - 0 100 minmax 100 / 0.75 * 

We can evaluate it as follows:

 [100 (kHitPoints% target>) -] 0 100 minmax 100 / 0.75 *

Assume target is at 80% health {100 - 80} 0 100 minmax 100 / 0.75 * 20 0 100 minmax 100 / 0.75 * Assume minmax is a sanity check operand which takes 2 preceding args, min and max. 0 100 minmax becomes minmax (minimum 0 and max 100) [20 [0 100] minmax] 100 / 0.75 * Becomes {20 minmax(0,100)} 100 / 0.75 *, evaluating to 20. [20 100 /] 0.75 * [0.2 0.75 *]

 =15% per target

Now for Corruptor Scourge Mechanics

   Requires                 kHitPoints% target>  10 - 100 * 50 10 - /  0 100 minmax rand 100 * < enttype target> critter eq &&

Whew, that's quite a mouthful! Let's take it slowly: [(kHitPoints% target>) 10 -] 100 * 50 10 - / 0 100 minmax rand 100 * < enttype target> critter eq && Let's assume that the target is at 30% health, which would give us a 50% chance of Scourge. [{30 - 10} 100 *] 50 10 - / 0 100 minmax rand 100 * < enttype target> critter eq && {20 * 100} [50 10 -] / 0 100 minmax rand 100 * < enttype target> critter eq && 2000 {50 - 10} / 0 100 minmax rand 100 * < enttype target> critter eq && Why does this evaluate 40? Wouldn't it better just to use 40? Probably because it makes things easier if scourge needs to be altered by someone who can't do math. Lots of people are math illiterate in this world; fortunately you, dear reader, are obviously not one of them. {2000 / 40} (0 100 minmax) rand 100 * < enttype target> critter eq && Based what I know about C++ basic Math library functions, I can assume rand returns a decimal number from 0 to 1. {50 minmax (0,100)} [rand 100 *] < enttype target> critter eq && Since rand gets multiplied by 100, this gives a random number between 0 and 100, which I shall call x. This is what it looks like: [50 x <] [(enttype target>) critter eq] && Since you're a highly educated person, you know that the < (less than) operand will return a boolean value of 0 (false) or 1 (true). I can assume (enttype target>) returns the entity type of the target. eq is short for the equals operand in Boolean logic. I'm going to evaluate this in plain English. {x <50} enttype target> critter eq && && is just the operand for "and", so (Check that x is less than 50) and (Check if target is a critter) Hence Scourge has a 50% chance of proccing on critters.