Jump to content

Photo

Elemental Damage


  • Please log in to reply
77 replies to this topic

#1 grayswandir

grayswandir

    semi-genius

  • Members

Posted 10 August 2013 - 03:46 AM

I just wrote up a very rough script on how to handle elemental damage.

 

Example Quest

 

Code

 

This defines two elements, ice and fire. If you hit an elemental enemy with the same element weapon, they only take half damage. The example quest gives you a fire sword and an ice sword.

 

You define the element of a weapon by setting it's damage. The actual damage starts at the ten's place, and the element is the one's place. So if you set a sword to do 61 damage, it will do 6 fire damage. If you set it to do 42 damage, it will do 4 ice damage.

 

Enemies are assigned an element at Misc Attribute 11, with the same element numbers. This conflicts with Ghosted enemies, but if you're using them you can probably assign an element in the actual enemy script easily enough.

 

This works by giving every enemy a lot of extra hp when they first appear, and then checking their health every frame to see what kind of 'hit' they took last frame and rearranging their health accordingly. Once they pass below the extra amount of hp they were given, they are killed off.

 

This could probably be very easily modified to create weapons that do other weird effects, not just varying amounts of damage.


Edited by grayswandir, 10 August 2013 - 03:59 AM.


#2 Binx

Binx

    Formerly Lineas

  • Members
  • Real Name:Brian
  • Location:Lancaster, CA

Posted 10 August 2013 - 04:28 AM

ok, let's see if I understand this correctly before I go trying to modify this to suit my needs (awesome script, by the way). I set the constants for all my elements, that part I get, but I'm supposed to use enemy misc attribute 11, so what's "MISC_NPC_ELEMENT = 2"? And I'm not quite sure I understand how the damage calculations work, there, either. I know it's going to be a lot more lines of code to do it for 3 elements instead of 2, but if I get a better grasp of which equations are doing what (Like this one "int damage = (hit * 0.2) >> 0;" is that saying to multiply the damage assignment by 0.2? or Am I misreading it again)

 

Jeez I feel dumb with this stuff, and I'm usually so good at math!

 

 

EDIT: Wait... No, that part is used to divide out the damage attribute to determine how strong the attack is, since the damage uses the "10's" digit, isn't it? I assume it's dividing by 5 because ZC does damage calculations in 2's? Well, I guess that answers my question about whether or not it would affect scripted projectiles (Like a scripted sword beam that carries the fire element, for example).


Edited by Lineas, 10 August 2013 - 04:36 AM.


#3 Binx

Binx

    Formerly Lineas

  • Members
  • Real Name:Brian
  • Location:Lancaster, CA

Posted 10 August 2013 - 02:19 PM

So, I think what I want to do, in order to achieve my desired effect is change this:

  if (element == n->Misc[MISC_NPC_ELEMENT]) {
    damage >>= 1;}

to this

  if (element == n->Misc[MISC_NPC_ELEMENT]) {
    damage = 0;}
  if (element = 1 && Misc[MISC_NPC_ELEMENT] = 2) {
    damage *= 2;}
  if (element = 2 && MISC_NPC_ELEMENT = 3) {
    damage *= 2;}
  if (element = 3 && MISC_NPC_ELEMENT = 1) {
    damage *= 2;}
  if (element = 1 && MISC_NPC_ELEMENT = 3) {
    damage >>= 1;}
  if (element = 2 && MISC_NPC_ELEMENT = 1) {
    damage >>= 1;}
  if (element = 3 && MISC_NPC_ELEMENT = 2) {
    damage >>= 1;}

Am I on the right track, here?



#4 grayswandir

grayswandir

    semi-genius

  • Members

Posted 10 August 2013 - 03:08 PM

Yeah, it looks like you got it. (Just remember to use == and not =.)

 

Though if you're going to have a lot of elements, I'd probably just stick that all in a function:

int GetDamageMultiplier(int attackElement, int targetElement) {
  if (attackElement == targetElement) {return 0;}
  else if (attackElement == && 1 targetElement == 2) {return 2;}
  // Rest of the elements here.
 
  // Finally, return 1 if for some reason we haven't found a multiplier yet.
  return 1;}

 

And then you can just have the line:

damage *= GetDamageMultiplier(element, n->Misc[MISC_NPC_ELEMENT]);


#5 Binx

Binx

    Formerly Lineas

  • Members
  • Real Name:Brian
  • Location:Lancaster, CA

Posted 10 August 2013 - 03:35 PM

So, the new code should look something like:

// The fake amount of hp.
const int NPC_FAKE_HP = 100;

const int ELEMENT_FIRE = 1;
const int ELEMENT_FOREST = 2;
const int ELEMENT_WATER = 3;
const int ELEMENT_WIND = 4;
const int ELEMENT_ICE = 5;
const int ELEMENT_EARTH = 6;
const int ELEMENT_LIGHT=7;
const int ELEMENT_SHADOW = 8;
const int ELEMENT_SPIRIT = 9;

// Misc slot for enemy initialization state.
const int MISC_NPC_INIT = 0;
// Misc slot for npc's hp last frame..
const int MISC_NPC_OLD_HP = 1;
// Misc slot for npc's element.
const int MISC_NPC_ELEMENT = 2;

int GetDamageMultiplier(int attackElement, int targetElement) {
  if (attackElement == targetElement) {return 0;}
  else if (attackElement == ELEMENT_FIRE && targetElement == ELEMENT_FOREST) {return 2;}
  else if (attackElement == ELEMENT_FOREST && targetElement == ELEMENT_WATER) {return 2;}
  else if (attackElement == ELEMENT_WATER && targetElement == ELEMENT_FIRE) {return 2;}
  else if (attackElement == ELEMENT_WIND && targetElement == ELEMENT_ICE) {return 2;}
  else if (attackElement == ELEMENT_ICE && targetElement == ELEMENT_EARTH) {return 2;}
  else if (attackElement == ELEMENT_EARTH && targetElement == ELEMENT_WIND) {return 2;}
  else if (attackElement == ELEMENT_LIGHT && targetElement == ELEMENT_SHADOW) {return 2;}
  else if (attackElement == ELEMENT_SHADOW && targetElement == ELEMENT_SPIRIT) {return 2;}
  else if (attackElement == ELEMENT_SPIRIT && targetElement == ELEMENT_LIGHT) {return 2;}
  else if (attackElement == ELEMENT_FIRE && targetElement == ELEMENT_WATER) {return 0.5;}
  else if (attackElement == ELEMENT_FOREST && targetElement == ELEMENT_FIRE) {return 0.5;}
  else if (attackElement == ELEMENT_WATER && targetElement == ELEMENT_FOREST) {return 0.5;}
  else if (attackElement == ELEMENT_WIND && targetElement == ELEMENT_EARTH) {return 0.5;}
  else if (attackElement == ELEMENT_ICE && targetElement == ELEMENT_WIND) {return 0.5;}
  else if (attackElement == ELEMENT_EARTH && targetElement == ELEMENT_ICE) {return 0.5;}
  else if (attackElement == ELEMENT_LIGHT && targetElement == ELEMENT_SPIRIT) {return 0.5;}
  else if (attackElement == ELEMENT_SHADOW && targetElement == ELEMENT_LIGHT) {return 0.5;}
  else if (attackElement == ELEMENT_SPIRIT && targetElement == ELEMENT_SHADOW) {return 0.5;}

  // Finally, return 1 if for some reason we haven't found a multiplier yet.
  return 1;}

// Updates all npcs.
void NPC_Update() {
  for (int i = 1; i <= Screen->NumNPCs(); i++) {
    NPC_Update(Screen->LoadNPC(i));}}

// Updates this npc.
void NPC_Update(npc n) {
  NPC_Initialize(n);
  NPC_Damage(n);}

// If this NPC hasn't been initialized, do so and mark it.
void NPC_Initialize(npc n) {
  // Exit out if they've already been initialized.
  if (n->Misc[MISC_NPC_INIT] != 0) {return;}
  // Set their new HP to increase by the fake amount
  n->HP += NPC_FAKE_HP;
  // Record their current HP.
  n->Misc[MISC_NPC_OLD_HP] = n->HP;
  // Set their element to Misc Attribute 11.
  n->Misc[MISC_NPC_ELEMENT] = n->Attributes[10];
  // Mark them as initialized.
  n->Misc[MISC_NPC_INIT] = 1;}

// Take damage as appropriate.
void NPC_Damage(npc n) {
  // See if we took any hits, and quit if we didn't.
  int hit = n->Misc[MISC_NPC_OLD_HP] - n->HP;
  if (hit <= 0) {return;}
  // Go back up to the hp we had before (so we can subtract the proper
  // amount this time.)
  n->HP = n->Misc[MISC_NPC_OLD_HP];
  // Item editor only let's us specify damage in increments of 2,
  // so half the damage here where we interpret it.
  hit >>= 1;
  // Interpret the hit value.
  int element = hit % 10;
  int damage = (hit * 0.2) >> 0;
  // Damage multipliers
  damage *= GetDamageMultiplier(element, n->Misc[MISC_NPC_ELEMENT]);
  // Apply damage.
  n->HP -= damage;
  // Update the 'old' value to the new amount.
  n->Misc[MISC_NPC_OLD_HP] = n->HP;
  // If actual hp has hit 0, die.
  if (n->HP <= NPC_FAKE_HP) {
    n->HP = 0;}}

  //Then you add this line to the while(true) loop of your global script, before any other damage multipliers
//Elemental global
        NPC_Update();

And then of course, just adding that one line to my global. Am I correct in my assumptions?

 

 

EDIT: Edited code to use the working script


Edited by Lineas, 10 August 2013 - 06:45 PM.


#6 grayswandir

grayswandir

    semi-genius

  • Members

Posted 10 August 2013 - 03:53 PM

Yeah, looks good.



#7 Binx

Binx

    Formerly Lineas

  • Members
  • Real Name:Brian
  • Location:Lancaster, CA

Posted 10 August 2013 - 04:12 PM

Well, except that I had all the ampersands (&) in the wrong spots, lol. I'm gonna test it out in a bit, here, I'll let you know how it goes :)



#8 MoscowModder

MoscowModder

    Sometimes lurking. Rarely posting.

  • Members
  • Location:Wisconsin

Posted 10 August 2013 - 04:24 PM

To make your code easier to read (for yourself), you should probably replace every "attackElement == #" with one of your ELEMENT_ constants. That way you'll know what's going on when you read that damage multiplier function.



#9 Binx

Binx

    Formerly Lineas

  • Members
  • Real Name:Brian
  • Location:Lancaster, CA

Posted 10 August 2013 - 04:31 PM

Oh, yeah... Good point, I'll probably get around to that, eventually (Luckily, I assigned the element numbers to the same order as the dungeons, so I should always remember that 4 = wind, because the wind temple is level 4). For now, the code works beautifully :)

 

 

EDIT: Okay, I got around to it. 

 

THANK YOU SO MUCH, grayswandir! This is really going to make all the useless vanity items I made have a real purpose :) Plus the more scripts like these I use, the better I get at understanding scripting. One day, I won't suck at this stuff!


Edited by Lineas, 10 August 2013 - 04:42 PM.


#10 Binx

Binx

    Formerly Lineas

  • Members
  • Real Name:Brian
  • Location:Lancaster, CA

Posted 10 August 2013 - 05:43 PM

Hey, a random question about this script (It still works just fine, I was just wondering about this): Why does it add a bunch of HP then kill them after they drop below the added HP level? I mean, why that way, why wouldn't it work if their HP was at its normal level?


Edited by Lineas, 10 August 2013 - 05:43 PM.


#11 grayswandir

grayswandir

    semi-genius

  • Members

Posted 10 August 2013 - 05:46 PM

Yeah, I think it would. I didn't realize this until after I had already posted it, though.



#12 Binx

Binx

    Formerly Lineas

  • Members
  • Real Name:Brian
  • Location:Lancaster, CA

Posted 10 August 2013 - 06:34 PM

Oh, ok.



#13 Binx

Binx

    Formerly Lineas

  • Members
  • Real Name:Brian
  • Location:Lancaster, CA

Posted 10 August 2013 - 09:05 PM

I just thought of something, how do I set damage on NON-elemental weapons? Like, if I want a weapon to do 1 damage, would I put 1 or 10?



#14 grayswandir

grayswandir

    semi-genius

  • Members

Posted 10 August 2013 - 09:09 PM

10, because 1 would be 0 fire damage. Just treat neutral as element 0.

 

I was glad you picked 9 elements, because 9 + neutral is 10 elements, which happens to match up very well with our decimal number system.



#15 Binx

Binx

    Formerly Lineas

  • Members
  • Real Name:Brian
  • Location:Lancaster, CA

Posted 10 August 2013 - 09:13 PM

Well, I can't really say much about that. I always wanted the Ice Cavern in OoT to be a full level, and after WW, I knew I HAD to include Wind and Earth temples as well. It's actually fortunate that I was forced to switch gears on my original ideas, because before the elements were just going to be themes with no impact on the game. I think this give the quest a nice twist. I wasn't really thinking about the numbers.

 

EDIT: Actually, originally, I wasn't going to include Ice at all, but I wanted to use the Ice Rod in game and figured there needed to be an ice level if I did.


Edited by Lineas, 10 August 2013 - 09:14 PM.



0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users