Issue with Attack Formula

RedFoxGaming

Veteran
Veteran
Joined
Jan 14, 2018
Messages
85
Reaction score
16
First Language
English
Primarily Uses
RMMV
So I am trying to implement DnD style dice rolls into damage calculation, and the formula I have works, except for one slight issue that I cannot seem to figure out. I have implemented a multiple hits system into the formula as well, but it doesn't appear to be working. I still do damage, even if I hit 0 times. Here is the formula:
V[1] = 1st 1d20
V[2] = 1d8
V[3] = 2nd 1d20
V[4] = # successful hits

Code:
v[1] = Math.floor(Math.random() * (21 - 1)) + 1; v[2] = Math.floor(Math.random() * (9 - 0)) + 0; for(i = 0; i < Math.floor(a.agi / 16) + 1; i++) { v[3] = Math.floor(Math.random() * (21 - 1)) + 1; if(v[3] >= 8) { v[4] = v[4] + 1; } } if(v[1] + (a.atk / 4) >= b.def) { ((v[2] + a.atk / 4) - b.def) * v[4]; } else if(v[1] + (a.atk / 4) < b.def) { 0; } else if(v[1] = 1) { 0; } else if(v[1] = 20) {v[4] = Math.floor(a.agi / 16) + 1; (v[2] + a.atk / 4) * v[4]; }
 

rainyday

Villager
Member
Joined
Nov 5, 2019
Messages
8
Reaction score
3
First Language
English
Primarily Uses
RMMV
You need to put return statements in your else if statements so that the damage value you want doesn't get changed. I'd also highly recommend making a javascript function that calculates this damage for you, because it'll make your formula much more readable and if you plan on using multiple skills with this same formula it'll save you time if you decide to change something, because you'll be able to edit the function instead of each individual skill.
 

RedFoxGaming

Veteran
Veteran
Joined
Jan 14, 2018
Messages
85
Reaction score
16
First Language
English
Primarily Uses
RMMV
What would be the easiest way to make a function to do this. I don't know anything about Java script. I only know enough about C# and it's similarities to Javascript to make that line of code work, even if it didn't work as intended
 

rainyday

Villager
Member
Joined
Nov 5, 2019
Messages
8
Reaction score
3
First Language
English
Primarily Uses
RMMV
Open up rpg_objects.js with a program like notepad++ and past this in the Game_Action section

Code:
Game_Action.prototype.dndAttack = function(a,b){
    $gameVariables.setValue(1,Math.floor(Math.random() * (21 - 1)) + 1);
    $gameVariables.setValue(2,Math.floor(Math.random() * (9 - 0)) + 0);
    $gameVariables.setValue(4,0);
    for(i = 0; i < Math.floor(a.agi / 16) + 1; i++) {
        $gameVariables.setValue(3,Math.floor(Math.random() * (21 - 1)) + 1);
        if($gameVariables.value(3) >= 8) {
            $gameVariables.setValue(4,$gameVariables.value(4) + 1);
            }
        }
    if($gameVariables.value(1) + (a.atk / 4) >= b.def) {
        return (($gameVariables.value(2) + a.atk / 4) - b.def) * $gameVariables.value(4);
        } else if($gameVariables.value(1) + (a.atk / 4) < b.def) {
            return 0;
            } else if(v[1] = 1)    {
                return 0;
            } else if(v[1] = 20) {
                $gameVariables.setValue(4, Math.floor(a.agi / 16) + 1);
                return ($gameVariables.value(2) + a.atk / 4) * $gameVariables.value(4);
            }
    }

Then, in the formula box of your skill, type this.dndAttack(a,b)
 

Aesica

undefined
Veteran
Joined
May 12, 2018
Messages
979
Reaction score
920
First Language
English
Primarily Uses
RMMV
So I had to break your formula down into a human-readable format:

Code:
v[1] = Math.floor(Math.random() * (21 - 1)) + 1;
v[2] = Math.floor(Math.random() * (9 - 0)) + 0;
for(i = 0; i < Math.floor(a.agi / 16) + 1; i++)
{
    v[3] = Math.floor(Math.random() * (21 - 1)) + 1;
    if(v[3] >= 8)
    {
        v[4] = v[4] + 1;
    }
}
if(v[1] + (a.atk / 4) >= b.def)
{
    ((v[2] + a.atk / 4) - b.def) * v[4];
}
else if(v[1] + (a.atk / 4) < b.def)
{
    0;
}
else if(v[1] = 1)
{
    0;
}
else if(v[1] = 20)
{
    v[4] = Math.floor(a.agi / 16) + 1;
    (v[2] + a.atk / 4) * v[4];
}
Yeah, the mistake you're making is that just a formula by itself, "(v[2] + a.atk / 4) * v[4];" or even just "0;" is not actually going to do anything. What you need to do is have whatever that number is be the last thing in the formula box, with no semicolon after it. So:

someFunction(); 25

Will do 25 damage

25; // followed by some other stuff, like additional "if...else" checks, etc

Won't do anything useful in most cases.

Another thing, your dice rolling is a bit wonky and eitiher has unnecessary extras in it or even may not give proper results:
  • v[1] = Math.floor(Math.random() * (21 - 1)) + 1; // 21 - 1 isn't necessary, just use 20
  • v[1] = Math.floor(Math.random() * 20) + 1; // same as above, but without the excess
  • v[3] has the same weirdness going on as v[1]

  • v[2] = Math.floor(Math.random() * (9 - 0)) + 0; // result is going to be 0 through 8. Why 9 - 0? That's the same as just 9
  • v[2] = Math.floor(Math.random() * 8) + 1; // valid d8 roll

  • v[4] doesn't appear to be initialized anywhere in this formula, so if you're not doing so elsewhere, attempting to increment it is just going to result in NaN (not a number) which will break any numeric calculation that tries to use it.

  • Finally, as I said earlier, you're not saving your damage results into anything. Just calling "0;" by itself isn't going to work. You need the intended damage result to be the LAST thing in the formula box, after everything else. So save all your formula values to a temp variable (c = 0, c = a.atk - b.def, etc) and then have "c" by itself as the last thing in the formula box. So:
  • v[1] = 3; if (v[1] > 2) { v[2] = 5; c = v[1] + v[2]; } else { c = 0; } c
  • notice how we're saving a formula to c, then having c by itself as the last thiing
Edit: If you use @rainyday 's method (which I'd recommend because it gets all that bloat out of your formula box) I'd actually suggest making a new text file (save it as whatever-you-want.js) into your plugins folder, and then add it as a plugin. You shouldn't really edit core js files because, if you ever go to update your game to a newer version of MV, you risk losing that edit.
 

RedFoxGaming

Veteran
Veteran
Joined
Jan 14, 2018
Messages
85
Reaction score
16
First Language
English
Primarily Uses
RMMV
Okay, that helps a lot. I did not realize the final result in the formula box had to come very last. Also me not initializing V[4] is why the hits was not working. I'll probably will write a small plug in to do this, because it is a little irritating in a one line box.

I do have a question though. If I want to use one plug in to handle every formula, and call this.dndAttack(a, b) like above? I would want to add a third argument to it and in the formula box, if MV has a function to do so, the third argument will be the skillID of the skill currently being used. If not, I could do it manually.

The other thing, does Javascript have a Switch Case branch like C#? I would much rather use this than a 100 else if statements. Thank you for all your help too.
 

rainyday

Villager
Member
Joined
Nov 5, 2019
Messages
8
Reaction score
3
First Language
English
Primarily Uses
RMMV
You shouldn't have to add another argument, you can just type this.dndAttack in the formula box like in the attached image. If you want different checks on your rolls, you could add conditionals like this.dndAttack(a,b,c,d), where c and d are integers that you wanna check(and so on for additional checks).

And yeah, javascript has a switch case function, done like
switch(obj){
case(value):
code;
break;
}
 

Attachments

Aesica

undefined
Veteran
Joined
May 12, 2018
Messages
979
Reaction score
920
First Language
English
Primarily Uses
RMMV
I do have a question though. If I want to use one plug in to handle every formula, and call this.dndAttack(a, b) like above? I would want to add a third argument to it and in the formula box, if MV has a function to do so, the third argument will be the skillID of the skill currently being used. If not, I could do it manually.
Game_Action has a way to reference the item/skill in question directly, so inside the function provided, you could reference it like so:

Code:
Game_Action.prototype.dndAttack = function(a,b){
    $gameVariables.setValue(1,Math.floor(Math.random() * (21 - 1)) + 1);
    $gameVariables.setValue(2,Math.floor(Math.random() * (9 - 0)) + 0);
    $gameVariables.setValue(4,0);
    var skillId = this.item().id; // this will fetch the id of either the item or the skill
    // ...etc
If you only want skills to reference this, the id number is all you need. Otherwise, you'll also have to do something like this:

Code:
if (this._item._dataClass === "item") // item stuff
else if (this._item._dataClass === "skill") // skill stuff
 

gstv87

Veteran
Veteran
Joined
Oct 20, 2015
Messages
1,893
Reaction score
893
First Language
Spanish
Primarily Uses
RMVXA
final damage calculation should be moved over to the item apply method or the battle manager.
skills should only provide the boundary values for that formula.
 

RedFoxGaming

Veteran
Veteran
Joined
Jan 14, 2018
Messages
85
Reaction score
16
First Language
English
Primarily Uses
RMMV
So I'm guessing the a and b arguments passed in the function are passed because the original function uses 2 arguments? So I won't use a or b, but if I want checks I can just add past the b?

Sorry, Javascript is just so different from any other language I have ever fooled with.

Say I want to do different stuff based on the skill ID, could I do this in the formula box?

this.dndAttack(a,b,this.item().id)

And check the third argument in the function?
Game_Action.prototype.dndAttack = function(a, b, c) {}?
 

Aesica

undefined
Veteran
Joined
May 12, 2018
Messages
979
Reaction score
920
First Language
English
Primarily Uses
RMMV
If you want to get the skill id in the formula box directly, use this.item().id
 

RedFoxGaming

Veteran
Veteran
Joined
Jan 14, 2018
Messages
85
Reaction score
16
First Language
English
Primarily Uses
RMMV
So here is what I came up with, although this is for my main project. I will probably want to do more with this, but I want to make sure I can get this code working first.
Code:
Game_Action.prototype.customAttack = function(a,b,type,base){
    var acc;
    var eva;
    var phits;
    var ahits;
    var damage;
    var random1;
    var random2;
    $gameVariables.setValue(1,0); //Using this value to give access to text boxes in game to record
    //actual hits landed
    switch(type){
        case(1): //Physical Attack
            acc = a.hit;
            eva = b.eva;
            phits = Math.floor(a.agi / 16);
            ahits = 0;
            damage = 0;
            if(phits < 1) { phits = 1; }
            if(phits > 16) { phits = 16; }
            if(a.isStateAffected(99)) { phits = phits * 2; }
            if(a.isStateAffected(99)) { phits = phits / 2; }
            if(a.atk < b.def) { acc = acc / 2; }
            //Actual damage calculation time
            for(i=0; i < phits; i++){
                random1 = Math.floor(Math.random() * 100) + 1;
                random2 = Math.floor(Math.random() * 100) + 1;
                if(random1 > 100 - acc && random2 > eva){
                    ahits++;
                }
            }
            $gameVariables.setValue(1,ahits); //Actually set the value
            if(a.atk >= b.def) {
                damage = ((a.atk * 4) - (b.def * 4)) * ahits;
                return damage;
            }
            else if(a.atk < b.def) {
                damage = 1 * ahits;
                return damage;
            }
            break;
        case(2): //White Magic type attack
            acc = a.hit;
            eva = b.eva;
            phits = Math.floor(a.mat / 32);
            ahits = 0;
            damage = 0;
            if(phits < 1) { phits = 1; }
            if(phits > 6) { phits = 6; }
            if(a.mdf < b.mdf) { acc = acc / 2; }
            for(i=0; i < phits; i++){
                random1 = Math.floor(Math.random() * 100) + 1;
                random2 = Math.floor(Math.random() * 100) + 1;
                if(random1 > 100 - acc && random2 > eva){
                    ahits++;
                }
            }
            if(a.mdf >= b.mdf){
                damage = (base + (a.mdf - b.mdf)) * ahits;
                return damage;
            }
            else if(a.mdf < b.mdf){
                damage = (base / 4 + (a.mdf - b.mdf)) * ahits;
                return damage;
            }
            break;
        case(3): //Black Magic type attack
            acc = a.hit;
            eva = b.eva;
            phits = Math.floor(a.mat / 32);
            ahits = 0;
            damage = 0;
            if(phits < 1) { phits = 1; }
            if(phits > 6) { phits = 6; }
            if(a.mat < b.mdf) { acc = acc / 2; }
            for(i=0; i < phits; i++){
                random1 = Math.floor(Math.random() * 100) + 1;
                random2 = Math.floor(Math.random() * 100) + 1;
                if(random1 > 100 - acc && random2 > eva){
                    ahits++;
                }
            }
            if(a.mat >= b.mdf){
                damage = (base + (a.mat - b.mdf)) * ahits;
                return damage;
            }
            else if(a.mat < b.mdf){
                damage = (base / 4 + (a.mat - b.mdf)) * ahits;
                return damage;
            }
            break;
    }
}

EDIT: Well, I tested this, and while the code does not crash, the resulting damage is always 0, and I am not sure why yet, because I don't even know how to set breakpoints in the script and debug it that way if MV let's you do that.

In my formula box, I have this: this.customAttack(a,b,1,0)
for the regular physical attack.

Mods, if you want to move this into Javascript help, since this is what this turned into, you can.

Edit 2: I actually have this code in my own file, do I have to import Game_Action before me making a prototype function will work?
 
Last edited:

rainyday

Villager
Member
Joined
Nov 5, 2019
Messages
8
Reaction score
3
First Language
English
Primarily Uses
RMMV
If you have your code in its own file, did you add it in the plugin manager? Also you should initialize your variables with a value, even if it's just 0, so they're not null
 

Aesica

undefined
Veteran
Joined
May 12, 2018
Messages
979
Reaction score
920
First Language
English
Primarily Uses
RMMV
Code:
            if(a.isStateAffected(99)) { phits = phits * 2; }
            if(a.isStateAffected(99)) { phits = phits / 2; }
Both if statements are checking for the exact same thing, so the net result will be no effect (n * 2 / 2 == n)

Now, for testing individual parts of your code, you can use console.log(someValueHere) to dump things to the debug console. I'd suggest putting different console.log statements in your various if...else blocks to see if that section gets reached or if the damage is consistently 0 because none of the if statement contents are being reached.

For example:

Code:
            if(a.mdf >= b.mdf){
                damage = (base + (a.mdf - b.mdf)) * ahits;
                console.log("(a.mdf >= b.mdf) : " + damage); // the string portion is to help identify which if statement we're seeing results for
                return damage;
            }
 

RedFoxGaming

Veteran
Veteran
Joined
Jan 14, 2018
Messages
85
Reaction score
16
First Language
English
Primarily Uses
RMMV
I know I'm checking the same thing twice there. That's just a place holder until I fill up the database and figure out what state ID those particular states end up being. I actually meant to just comment it out and forgot to. And when I get home I'll check parts of the code with console.log.

Also in the code, I just based it off of the code that was posted above. Is the (a, b) arguments actually needed? Can I just make the function Game_Action.prototype.customAttack = function(type, base)?
 

Aesica

undefined
Veteran
Joined
May 12, 2018
Messages
979
Reaction score
920
First Language
English
Primarily Uses
RMMV
Without the a, b arguments, the function won't know what a and b are. So yeah, they're needed.
 

RedFoxGaming

Veteran
Veteran
Joined
Jan 14, 2018
Messages
85
Reaction score
16
First Language
English
Primarily Uses
RMMV
Oh wait. Now I realize why they are there and what the a and b are actually doing as arguments. My bad
 

RedFoxGaming

Veteran
Veteran
Joined
Jan 14, 2018
Messages
85
Reaction score
16
First Language
English
Primarily Uses
RMMV
Okay, I got it figured out now and it is working. Console.log is very helpful. Turns out, it was failing the check at if(random1 > 100 - acc && random2 > eva). I couldn't figure out why it kept failing this, until I started outputting the variables into the console. Apparently, a.hit and b.eva don't return a whole number, they return a percent decimal value, which means they were always below 1. I had to do this to fix the issue:
acc = Math.floor(a.hit * 100);
eva = Math.floor(b.eva * 100);

And now the script appears to be working properly.
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

Oh, stop with the Melodrama...

...Listen to it instead!

anybody else like getting baked whilst coding?

When you go to the beach watch out for coconuts. Coconuts are more dangerous than sharks. Fact.
Try to get into pixelart again, so far its a sucess.
Also finally found a useful pixeltutorial which helps a lot.
♫ Anyone knows an ant can't move a rubber tree plant, but he's got high hopes, he's got high hopes, he's got high apple pie in the sky hopes ♫

Forum statistics

Threads
93,615
Messages
913,983
Members
123,180
Latest member
tdominach
Top