[SOLVED]Yanfly Chain Lightning modification

woootbm

Super Sand Legend
Veteran
Joined
Apr 26, 2014
Messages
192
Reaction score
113
First Language
English
Primarily Uses
RMMV
Hey again all!

So I'm trying to create a chain lightning spell. Yanfly actually made a whole "Tips and Tricks" video about this using his Target Core and Damage Core plugins:

Code:
<Damage Formula>
// Set the chain multiplier to a value if it doesn't exist.
this._chainmultiplier = this._chainmultiplier || 1.0;
// This is the damage formula.
value = user.mat + 1000;
// Apply the chain multiplier to the damage formula.
value *= this._chainmultiplier;
// Reduce the chain multiplier per target.
this._chainmultiplier -= 0.2;
</Damage Formula>

<Custom Target Eval>
// Adds the selected target to the target list.
targets.push(target);
// Grab the group of alive foes as candidates.
var members = foes.aliveMembers();
// Remove the target from the group of candidates.
members.splice(members.indexOf(target), 1);
// This is the number of extra targets to select with Chain Lightning.
var extraTargets = 3;
// Loop the extra targets.
while (extraTargets--) {
  // Grab a random foe from the alive foes.
  var member = members[Math.floor(Math.random() * members.length)];
  // Check to see if the member exists.
  if (member) {
   // Add the member to the group of targets.
   targets.push(member);
   // Remove the member as a viable candidate.
   members.splice(members.indexOf(member), 1);
  }
}
</Custom Target Eval>
I wanted to change this a little bit. I didn't want the less-damage-each-hit part, but that was easy to fix. I just removed the damage formula at the beginning. The next part was that I wanted it to be able to repeat targets if there are less targets available than hits. I made the following brute force version (I also lowered the targets by one, but that's easy enough to change):


Code:
<Custom Target Eval>
targets.push(target);
var members = foes.aliveMembers();
members.splice(members.indexOf(target), 1);
var extraTargets = 2;
while (extraTargets--) {
var member = members[Math.floor(Math.random() * members.length)];
if (member) {
targets.push(member);
}
}
</Custom Target Eval>
What happens with this one is that it works normally if there are enough targets. But if there aren't, it simply hits the last target for the remaining hits. Funny enough, if there's only one target it only hits once. So my bumbling about in the code almost worked.

So, to sum this all up: say I have only two targets. How do I get this to bounce back and forth between the two for all of the hits?
 

Astfgl66

Veteran
Veteran
Joined
Jan 5, 2016
Messages
703
Reaction score
549
First Language
French
Primarily Uses
I find it best to go through this one line at a time, in order to understand what's going on.
Let's run through your code 1 line at a time with 3 enemies [a,b,c]
Initial target is a
I'll put an explanation in comments as for the state of the program besides each important line

Code:
<Custom Target Eval>
targets.push(target); //target is now [a]
var members = foes.aliveMembers(); //members is now [a,b,c]
members.splice(members.indexOf(target), 1); //members is now [b,c]
var extraTargets = 2;
while (extraTargets--) { //will run two times
var member = members[Math.floor(Math.random() * members.length)]; //picks a random element in members and add it to the target array
if (member) {
targets.push(member); //lets say first loop adds b, second loop can add b or c again lets say b
}
}
//targets is now [a,b,b], possibilities are [a,b,c] [a,c,b] [a,c,c]
</Custom Target Eval>
This but with 2 enemies a,b:

Code:
<Custom Target Eval>
targets.push(target); // a is the initial target = [a]
var members = foes.aliveMembers(); //members is now [a,b]
members.splice(members.indexOf(target), 1); //removes a from the members array, members is now [b]
var extraTargets = 2;
while (extraTargets--) { //still runs two times
var member = members[Math.floor(Math.random() * members.length)]; //picks a random element from members
if (member) {
targets.push(member); //members only contains b, so only it will be picked  and added to the array
}
}
//targets is [a,b,b] this is the only solution
</Custom Target Eval>

This, but with only one enemy a:
Code:
<Custom Target Eval>
targets.push(target); // a is the initial target = [a]
var members = foes.aliveMembers(); //members is now [a]
members.splice(members.indexOf(target), 1); //removes a from the members array, members is now []
var extraTargets = 2;
while (extraTargets--) {//still runs two times
var member = members[Math.floor(Math.random() * members.length)]; //picks a random element from members and adds it to the array,
if (member) {
targets.push(member); //but members is empty
}
}
//targets is [a]
</Custom Target Eval>
Do you see where you went wrong?

Hint:
You shouldn't remove the initial target if you want the spell to bounce back to it.
 

woootbm

Super Sand Legend
Veteran
Joined
Apr 26, 2014
Messages
192
Reaction score
113
First Language
English
Primarily Uses
RMMV
Ah! I see. Somewhat :hswt: So I removed the first members.splice part. This made it so it always gets all of the jumps with less targets. But this created 2 problems (which I'm pretty sure are actually the same problem):

1. When there is more than 1 target, it can target the same enemy twice in a row, removing the illusion of it "bouncing" between targets.
2. When there is 1 target, it just hits that target every single time.

So I need to somehow tell it to not hit the "previous" target, but to not completely remove that target from the list of possibilities forever. Just for a single bounce.
 

Astfgl66

Veteran
Veteran
Joined
Jan 5, 2016
Messages
703
Reaction score
549
First Language
French
Primarily Uses
I see. You're absolutely right that this is the same problem in both cases.

How would you do that then?
What's the plain english, not code, step by step logic that would work?

Writing code is basically translating a logic program into something the computer understands.
You will never be able to make things work if you don't get the logic right.

Hint:
You want to move the members definition inside the loop so it does the calculation everytime instead of only before the loop.
Then you remove the last target from the members array before picking one.

proposed logic

Code:
get first target, store it in array
loop for two times
  get a list of all targets
  remove last member of target array from list
  get a random element from remaining possible targets
  add it to the target array
end loop
 

woootbm

Super Sand Legend
Veteran
Joined
Apr 26, 2014
Messages
192
Reaction score
113
First Language
English
Primarily Uses
RMMV
I've been trying to get this to work with your advice, and so far it hasn't. Testing it against a fight with 2 enemies, I'm always either getting bounces of a, b or it hits all three but combos of a, b, b or a, a, b are still possible, rather than the desired a, b, a happening 100% (and with more enemies a, b, a would be possible as well, but so would a, b, c etc).

What I've been doing is simply re-arranging the code I have, though. Since my understanding of Java is so low that modifying any lines either results in a script error or something stupid (like it only hits one target 3 times, or it only hits it once). I feel like some part of this needs to be modified somewhere.

Specifically, I'm thinking the "var member = members[Math.floor(Math.random() * members.length)];" part is what needs to be changed. Like it needs something to tell it "but not the last target". The "members.splice(members.indexOf(target), 1);" part might also be the culprit, because it seems like it removes a target from the list forever, rather than being a one-time deal.

For reference, how I perceived your proposed logic was as such:

Code:
<Custom Target Eval>
targets.push(target);
var extraTargets = 2;
while (extraTargets--) {
var members = foes.aliveMembers();
members.splice(members.indexOf(target), 1);
var member = members[Math.floor(Math.random() * members.length)];
if (member) {
targets.push(member);
}
}
</Custom Target Eval>
 

Astfgl66

Veteran
Veteran
Joined
Jan 5, 2016
Messages
703
Reaction score
549
First Language
French
Primarily Uses
You've got it mostly right :), again this can be solved by just reading the code out loud.
Let's do it: three enemies, a b, c initial target a

Code:
<Custom Target Eval>
targets.push(target); //targets is now [a]
var extraTargets = 2;
while (extraTargets--) { //first time //second time
var members = foes.aliveMembers(); //members is [a,b,c] //second loop: members is now [a,b,c]
members.splice(members.indexOf(target), 1); //removes initial target from members array, members is [b,c] //removes initial target again, members is [b,c]
var member = members[Math.floor(Math.random() * members.length)]; //gets random member from members array //gets random member from members array again
if (member) {
targets.push(member); //let's say b, targets is now [a,b] //let's say b, targets is now [a,b,b]
}
}
</Custom Target Eval>
Do you see where you went wrong?

Hint
The target variable contains the initial target, not the last decided target.
You want to remove the last element of targets from the members array instead inside the loop.
 

woootbm

Super Sand Legend
Veteran
Joined
Apr 26, 2014
Messages
192
Reaction score
113
First Language
English
Primarily Uses
RMMV
Haha, well I didn't really understand how to tell it "last target" instead of first target because I didn't quite get the whole "members.indexOf(target), 1". Eventually I tried "members.splice(members.indexOf(member), 1);" because I figured that "1" would be the first "member" that it was creating by the random roll. That didn't work. But, for some reason, using the command a second time during the "if" statement did. Here's what I have:

Code:
<Custom Target Eval>
targets.push(target);
var extraTargets = 2;
while (extraTargets--) {
var members = foes.aliveMembers();
members.splice(members.indexOf(member), 1);
var member = members[Math.floor(Math.random() * members.length)];
if (member) {
targets.push(member);
members.splice(members.indexOf(member), 1);
}
}
</Custom Target Eval>
I've tested this multiple times with troops of sizes 1, 2, and 8. And so far it seems to work? I find the whole thing kind of baffling. I would think I need that splice command only once, in either one of those positions. But neither of those work. Only when I do both. What are your thoughts on this?

I hope further testing down the road doesn't result in script errors :hswt2:
 

Astfgl66

Veteran
Veteran
Joined
Jan 5, 2016
Messages
703
Reaction score
549
First Language
French
Primarily Uses
I don't really get why this works. I'd do the tried and true technique of reading it out loud, but I kinda don't have the time right now.

Here's my proposed solution:

targets is an array.
Arrays have a length property, basically the number of elements in the list,; 1 for 1 element, 2 for 2, so on.
Arrays are numbered from 0, so to get the last element of an array you just have to do:
array[array.length - 1]

Here it'd be:
Code:
members.splice(members.indexOf(targets[targets.length-1]), 1)
I'd advise modifying your code to that, since having code you don't understand is kinda bad down the road if errors arise.

Googling "how to get last member of an array in javascript" would have probably saved you a lot of time and trial and error.
Same about the splice function, googling how it works and trying it out in the console would probably save you a lot of future headaches. Array manipulation is essential stuff which you'll run into every time you want to create a numbered list. Which is pretty much all the time.

You get no kudos for a working answer if you cannot tell me how it works. :kaojoy:
Still I'm glad you've got this sorted out, and I'll be even happier if you learned something about how the code works.
Happy making!
 
Last edited:

woootbm

Super Sand Legend
Veteran
Joined
Apr 26, 2014
Messages
192
Reaction score
113
First Language
English
Primarily Uses
RMMV
Ah, this new code works as well.

I do appreciate learning, but I'm not sure I properly described my ineptitude with Javascript. Like, you say read it out loud but- to me- I'm reading a lot of stuff I just don't understand. Compare it to an actual language like, say, Spanish. I know the basics and some easy words, so I might be able to pronounce a sentence written in Spanish. But considering I don't know like 85% of the words that make up the language, actually understanding what the hell I'm saying is another thing entirely. I'm pretty sure I know less about Java than Spanish, heh.

Like take that latest code. That length - 1 part is surprising for sure. I read that as just changing it from "out of three" to "out of two", but I guess that ",1" is what tells it to remove the last thing done. I guess I thought that meant the first target overall, rather than some temporary assignment of an index made by the other calls. Hm!

I did try to Google the answer, but I usually search for things specifically related to MV. Searching for just regular Javascript is the thing I've learned here then. My searches turned up things that were... not helpful.

Anyway, thanks again! :thumbsup-right:
 

Astfgl66

Veteran
Veteran
Joined
Jan 5, 2016
Messages
703
Reaction score
549
First Language
French
Primarily Uses
Unless you're doing cutting edge programming your problems have already been solved by someone smarter than you. That works for everyone.
The hard part about programming often isn't really the language, it's the logic. If you can write a logic program that will work you can then google how to write every single thing of that program in javascript and it will work. And you already know how to write logic programs, because that's what eventing is all about, praise RPGMaker for easing us into that stuff.

Here's a summary of how I did such things when I started programming three years ago:

get first target, store it in array
loop for two times
get a list of all targets
remove last member of target array from list
get a random element from remaining possible targets
add it to the target array
end loop

What is an array ? Oh it's a numbered list of things, it starts counting from 0.
How do I store things in it? Oh I just have to push things in it, then it gets into the next position
How do I loop two times ? Google says using for loops is usually the norm, and provides the syntax
How to remove an element from an array ? Google says splice.
How to get last element from array? Google says length - 1, because length is the number of elements (so 2 for 2 elements) but the numbering starts from 0 (so the last element is array[1] in a 2 element array), generalizing in a n element array the last element is array[n-1].

Having answered my fair share of plugin requests and related questions, I can tell you that if you come to the js forums having the base logic down and only needing the rpg maker part, you'll have a near instantaneous answer.

Have a nice day!
 

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

Latest Threads

Latest Posts

Latest Profile Posts

What if I start to make final boss first then crawl down from there to make lesser bosses
i don't even know why i bother. Trying to to a simple candle light to flicker. Hour later no progress.
My greatest challenge right now is less of the workload but more of the language barrier which I definitely need a local proofreader (without translation) for. I'm wondering if this is even a legit position for freelancing.
So, the other day i come across to became closer to other developers and realiza im not even a novice. i am lower than thrash rigth now, worse than people that don´t know anything about this things cause i used to think i knew. good news is; today thrash, tommorrow, maybe not so much, and someday, i´ll be a god?
Ahh, end of the day stinky feet, fresh out of the boots. Smells like a job well done. Seriously, I have to rinse my feet when I get home, or it's not fair to my wife.

Forum statistics

Threads
97,833
Messages
947,237
Members
129,051
Latest member
Spaghetti12
Top