New Skills – Dynamite Throw

Text-post only today, sorry bout it! Reddit user BunPuncherExtreme has come up with a skill combination as awesome as his name. For each of seven negative status effects in the game (things like Poison or Silence), the “spy” class has an attack that will deal *extra* damage, in essence exploiting the negative state. It reminds me a lot of the Feast of Corruption skill from Guild Wars 2 – dealing extra damage for every condition on the enemy. The skill, appropriately, is called Exploit. And we can build it in our formula box!

Theory

BunPuncher is absolutely on the right track when building his damage formula. This is what he started with

d=0; for s in [3,4,5,6,7,8]; if b.state?(s); d+= ((d+a.mat*4+a.luk*4-b.def)/2); end; end; dd=0
for s in [3,4,5,6,7,8]
    if b.state?(s)
        d+= ((d+a.mat*4+a.luk*4-b.def)/2)
    end
end
d

Let’s break this down:

  • Set our damage to 0
  • We have an array of state ids – these are the IDs of things like Poison and Blind and Confuse. We ask “for every state in this bucket…”
  • If the enemy has that state
  • Add something to the damage value. Note that d is in the equation – what that means is that the impact of the second condition is more than the first, and so on and so on.
  • Repeat for every state in the array of negative states
  • And then return the total damage number

But this is so long! And looks miserable in a damage formula. You’ve gotta worry about several “end”s, and a ton of semicolons.

Each and If

First things first, .each is a preferred method of doing for loops in Ruby. The loop above can be written as:

[3,4,5,6,7,8].each {|s|
    if b.state?(s)
        d+= ((d+a.mat*4+a.luk*4-b.def)/2)
    end
}

That doesn’t look like it saves us much, but it does when you realize that “if”s can be written at the end of a line of code. Think of this as natural language. Rather than writing “if a” then new line then “do b,” you can just write “do b if a.” And the best part is, this requires no “end.” We can condense all of the above to the following:

d=0; [3,4,5,6,7,8].each {|s| d+= ((d+a.mat*4+a.luk*4-b.def)/2) if b.state?(s)}; d

Hot damn! Now the only semicolons are necessary for setting our “d” variable at the beginning, and returning it at the end.

And

There’s another way to do it, and it’s about equal length. But for completeness, I wanted to share. Let’s go back to our initial theory here. We want to see how many states out of a particular array the enemy has and adjust our damage accordingly.  Ruby can use & to compare two arrays and return a third that is the intersection of both. So for example:

[1,3,5,7] & [1,2,3,4]

Returns [1,3]. If we call .size on our new array, we can find out that there are 2 states out of our bucket of negative states that are on the enemy right now.  More specifically, we use:

d=0; ([13,4,5,6,7,8] & b.states).size.times{d +=  (d+a.mat*4+a.luk*4-b.def)/2};d

This formula occasionally has the potential to be much shorter – we could actually rewrite our formula in most instances to take advantage of the .times operator. But this is only the case when the damage is linear. If, for example, our damage was (a.atk – b.def) * number of negative states on the enemy, we could eliminate the d= stuff entirely. But because we’re rebuilding it in on each loop, it would take an extremely complicated formula to do this without looping.

Have at it!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s