Having problem with a damage calculation...

For questions about using Classic.

Post » Tue Sep 27, 2011 12:46 pm

In my game, the player will be able to access a menu and change their elemental attack mid-stage. There are four elements: lightning/wind, fire, earth, and water/ice.

I wanted the enemies to have a variety of possible elemental defenses. From normal damage, to double damage, to half damage, to zero damage. And in my attempt to to this all in as few events as possible, as efficiently as possible, I gave the Enemy group 4 variables: lightning, fire, earth, and water. Now I didn't have to make separate groups for different elemental enemies, and if I wanted to allow an enemy to have more than one elemental defense, or a contradicting one, I could!

Just so you know what I planned...

Lightning weapon VS neutral enemy = normal damage.
Fire weapon VS fire-resistant enemy = 0.5 damage.
Earth weapon VS earth-weakness enemy = 2x damage.
Water weapon VS water-immune enemy = no damage.

What I tried for the variables was this:
1 = normal damage to that element.
2 = double damage to that element.
0 = immunity to that element.
0.5 = half damage to that element.

That was my plan in working out some calculation to handle all that stuff. "Base Damage" is how much damage an attack would be able to do, having given the Attack family a "Base Damage" variable so all objects under that family could have that variable, but modified for each hit box. I also gave that family its own set of elemental variables just so I wouldn't have to make new families for each element either. If an attack didn't have one of the elements, that element would be set at 0.

Attack.Value('Base Damage')*((Attack.Value('Lightning')*.Value('Lightning'))*(Attack.Value('Fire')*.Value('Fire'))*(Attack.Value('Earth')*.Value('Earth'))*(Attack.Value('Water')*.Value('Water')))*global('Attack Strength')*global('Extra Attack')

Now obviously, throwing ALL the elemental variables for the enemies and attacks gives us a little problem. Sure, it'd be novel if an attack had ALL elemental properties, used against an enemy weak to fire, but resistant to ice, since theoretically we could do something like that. But before we think of that, this calculation needs fixing. We can't even have ONE elemental attack against an enemy because we're multiplying by zeros here, and that sets the entire equation to 0.

Would anyone happen to have any ideas or ways around this? Any suggestions? I doubt it, but I wouldn't imagine Construct would have an expression where something multiplied by zero could still equal 1. And I wanted this to be as universal as possible, done on one event, so I couldn't have to code specific weaknesses and resistances for each enemy, or certain properties into every attack's hit box. I just change some variables and I'm done.
B
4
S
2
G
4
Posts: 164
Reputation: 1,878

Post » Tue Sep 27, 2011 6:55 pm

First problem:
Instead of multiplying element by elementexistence, use e to the power of ee. If an element exists, ee equals 1, else it equals 0

x^1 = x
x^0 = 1

(This works even if x = 0. 0^0 = 1, 0^1 = 0)

So, if e is 2 and ee is 1, the result is
2^1 = 2

If it doesn't exist, it's
2^0 = 1

Second problem:
Instead of multiplying all, split base damage into 4 parts (l = lightning, le = lightningexistance, f = fire, fe = fireexistance, etc.):

[code]dmg = (b / 4) * l^le + (b / 4) * f^fe + (b / 4) * e^ee + (b / 4) * w^we[/code]

If an element doesn't exist, it will result to 1, so if no element exists, you'll get base damage as the result.
Image
B
23
S
8
G
10
Posts: 1,820
Reputation: 8,242

Post » Wed Sep 28, 2011 7:13 am

The reason I was multiplying was because I wanted the elemental defenses to be multipliers. Just in case I wanted to do something like have an omni-elemental attack. An attack with all of the elements present. Now let's say we have an enemy who's weak to one element, but resistant against another. The 2x and 0.5 would cancel each other out. And the resistances and weaknesses could continue if the enemy was weak to more than one element, or resistant to more than one.

I'll try putting in your calculation and see what it's like. ^^; Not very good at math, so I can't even imagine what it'd be like until I put it in. I can't visualize this stuff very well. I'm gonna have to try it out. ^_^;
B
4
S
2
G
4
Posts: 164
Reputation: 1,878

Post » Wed Sep 28, 2011 10:31 am

Well, I did have exactly that in mind (the multiple elements influencing each other), but maybe I didn't understand the use of the two variables correctly?
I thought one variable would have a value somewhere between 0 and 2 (the one I called 'lightning', 'fire', etc. And the second one would have a value of either 0 or 1 (according to your explanation: "If an attack didn't have one of the elements, that element would be set at 0."), the one I called "...existance"

If both assumptions are given, then that formula works quite good. Let's just look at the four damage examples you made in the first post and pretend they are an "omni-elemental" attack. Let's say, base attack is 40. Then

dmg = 10 * 1^1 + 10 * 0.5^1 + 10 * 2^1 + 10 * 0^1 = 10 + 5 + 20 + 0 = 35

5 lower than the base attack, which makes absolutely sense, because while there is a double damage there is also a half damage, a normal damage and last but not least no damage.

Each of the 4 elements will always influence the result by 25%. If there is only one element, you'd double only 25% of the result (which would lead to 50 in the example above, where base attack was 40). If that was not the intention, that formula won't work for you, of course.

If you rather want something like "double the base damage, no matter what element is active", then I currently can't think of a reliable solution in only one formula, as you seem to aim for. (But maybe others can :) )
Image
B
23
S
8
G
10
Posts: 1,820
Reputation: 8,242

Post » Wed Sep 28, 2011 2:35 pm

You know, I've been sort of lost on your equation for awhile. Maybe I just put it in wrong or... I'm just being incredibly stupid. For example, I put in...

Attack hit box:
Base damage = 10
Lightning = 1
Fire = 0
Earth = 0
Water = 0

Enemy defense:
Lightning = 1
Fire = 1
Earth = 1
Water = 1

Now, I assume this would mean that the damage given to the enemy would be 10, but after trying it out, turned out to be 2.5. I... think I might've missed something. Did I? Or should it happen like that?

Then again, your original post had dividing the base damage by 4, but in that second post, you don't...
B
4
S
2
G
4
Posts: 164
Reputation: 1,878

Post » Wed Sep 28, 2011 7:56 pm

[QUOTE=Kisai]Then again, your original post had dividing the base damage by 4, but in that second post, you don't...[/QUOTE]But yes, I did :)
"Let's say, base attack is 40"
"dmg = 10 * 1^1 + 10 * 0.5^1 + 10 * 2^1 + 10 * 0^1"

[QUOTE=Kisai]
Attack hit box:
Base damage = 10
Lightning = 1
Fire = 0
Earth = 0
Water = 0

Enemy defense:
Lightning = 1
Fire = 1
Earth = 1
Water = 1

Now, I assume this would mean that the damage given to the enemy would be 10, but after trying it out, turned out to be 2.5. I... think I might've missed something. Did I? Or should it happen like that?[/QUOTE] It depends on how you put in the values to the formula. Remember, 0^1 equals 0, but 0^0 equals 1, so if you raise 'attack' to the power of 'defense', you get 1^1, 0^1, 0^1, 0^1
That's three times 0, and one time 1. Every element influences 25% of the result, so the result is 2.5

The one variable that is set to 0 if that element doesn't exist, should be the power. In that case you'd get
1^1, 1^0, 1^0, 1^0
That's four times 1, which would result to 10
Image
B
23
S
8
G
10
Posts: 1,820
Reputation: 8,242

Post » Wed Sep 28, 2011 8:26 pm

Here's the damage formula I'm using for my game, in calculator mode. Basically the way it's designed is that each time a hero's attack object collides with an enemy object this big ol' calculation gets run for the two objects. It incorporates arrays in the calculator, but in my actual game it's a mix between array values and private variables.

Linkity link link:
http://dl.dropbox.com/u/20459682/attack_calculator.cap

In the calculations the elemental resistances are string values, initials. I use "FindToken" to compare the elemental resistances with the attack element. If I want to do no elemental resistances I set them to 0, and if I want to do no attack element I set it to -1, since "FindToken" does count 0 and 0 as an elemental match, since technically they are. I just use letters for readability.

Anyway, maybe that can give you some ideas? I know it seems convoluted and a lot of events to run at once, but Construct does it all really quickly, and it works like a charm.TL222011-09-28 20:27:54
B
56
S
20
G
7
Posts: 305
Reputation: 8,754

Post » Thu Sep 29, 2011 10:01 am

Oh... I guess you did. ^^; Sorry. Guess I wasn't reading well-enough. But honestly I start getting lost when I try to put the calculation into Construct. Having to turn everything into variables and whatnot starts getting me confused.

But I can't seem to master this thing. It doesn't seem like I can get the attack to be modified by anything I put in for the enemy's element, or the attack's. I even put in a few random hundreds for both, and still, it's only doing the base damage. Maybe it's some Construct glitchery?

Argh, this whole thing is starting to make me look and feel dumber and dumber. Defeated and ridiculed by my own ambitions...

And... that example .cap... Wow. That is a LOT... And using arrays? That would make things difficult when trying to attack more than one enemy at once.
B
4
S
2
G
4
Posts: 164
Reputation: 1,878

Post » Thu Sep 29, 2011 7:05 pm

Why don't you just stop saving space and split the event into three subevents?

First event:
set global1 to: Attack.Value('BaseDamage')*Attack.Value('lightning')*Defender.Value('Lightning')
set global2 to: Attack.Value('BaseDamage')*Attack.Value('Fire')*Defender.Value('Fire')
set global3 to: Attack.Value('BaseDamage')*Attack.Value('Earth')*Defender.Value('Earth')
set global4 to: Attack.Value('BaseDamage')*Attack.Value('Water')*Defender.Value('Water')

Second event:
if any of the global variables 1 to 4 are "0" set them to "1"

and finally:
set global('Attack') to : global1*global2*global3*global4*global('AttackStrength')*global('ExtraDamage')

I know that's a lot of global variables and events but I don't think there's another simple and easily understandable way to do it.
Hope this helps.
B
6
S
1
G
1
Posts: 69
Reputation: 1,019

Post » Fri Sep 30, 2011 9:11 pm

[QUOTE=Kisai]And... that example .cap... Wow. That is a LOT... And using arrays? That would make things difficult when trying to attack more than one enemy at once.[/QUOTE]

Heh, it's not as much as you might think. It's really just using the same checking logic for different parts of the array (weakness, resistance, absorption, immunity). And you don't have to use arrays (though I highly recommend it!). I'm just using arrays for database stuff, things that I don't want to have to change every instance of every sprite for if I want to make a game balance edit, so I can just reference a database entry for it. I'm making an action adventure RPG so it's kinda necessary for me.

But yea, if you want a complex combat system, you're going to have to get a little complex. The key thing to remember to do is make sure it's readable and organized, or else you'll run into problems debugging later.

I'm sure tulamide or R0J0hound could find a one condition/one action way to do what I did but the method I threw out seems to work just fine.
B
56
S
20
G
7
Posts: 305
Reputation: 8,754

Next

Return to Help & Support using Construct Classic

Who is online

Users browsing this forum: No registered users and 1 guest