This pretty much means what you have to do is make your script prioritize checks. Then you also have to make sure your script knows when and when it can not, apply these priorities. For example, you do a check for swimming(is the player in water?). Then you do grabbing. If you don't account for whether the player is swimming or not, your player could end up being able to grab things while in water. Hence, the swim check goes BEFORE the grab check. That way you can say, "is the player swimming? If not, proceed with grabbing! If they are, ignore even considering if the player can grab." This turns into a whooooole mess of moving things around so each check interacts with the other correctly.
There are ways to lessen the burden, though. A while ago I figured out a nifty way to set the player to idle. Normally I'd constantly set the player's mode back to IDLE at the beginning on the timeout. This worked... except eventually problems arose: movement was always taking gani priority over anything else. So if you had a command like, "/setani sit" that set your player's ani to sit while not on a chair, the script would immediately set the player back to idle. Also, if you have various modes of idle, then you had to constantly figure out which to set it back to(regular idle, carrying object idle, riding a horse idle...). So I created a function: ReturnIdle(). Whenever you want to return the player to idle mode, run it. I also made it public so that external scripts could call it(for example, I had a sign NPC that had to set the player back to idle. If I used setani("idle",null)... 1) it didn't account for the custom gani names the movement used, and 2) if the player was say... riding a horse, it would cause the player's horse to disappear until the player was done reading. I also allowed the function to account for a parameter: ReturnIdle(omitsettinggani?). If set to true, it wouldn't force set the player's ani. It would only set the player's MODE to idle. This is used in the actual movement script so loops are not being made(setani("idle",null) > setani("walk",null) > setani("idle",null) > setani("walk",null) > setani("idle",null) > setani("walk",null)). However, for external NPC's I can leave it as null, or false, and it will forcefully set the player's ani along with it(in case the player is frozen, and thus the movement script is not processing said data).
Another cool thing I figured out is the ability to replicate the replaceani() function. How? When the script is created, establish the base gani array(player.ganis). This is an array that the script uses to set the player's gani's. It contains all the arrays that reflect the various modes of the player. This is not a static copy of gani's, however. We create a copy of that array as a static, and call it "default gani's". Then, we can take the player.gani array and change the gani's as we like. When we need to, we can revert back to the back-up default gani's. It's fairly simply
PHP Code:
public function ReplaceGani(defgani,newgani) {
temp.ganifound = this.defaultganis.index(defgani);
if (newgani == null) player.ganis[ganifound] = this.defaultganis[ganifound];
else player.ganis[ganifound] = newgani;
}
Hmm... otherwise I can't think of much to explain. I'm not very good at tutorials. Though I will detail one more thing: enumerators. They are very important for this script(not needed, but they help so much!), as they are used to keep track of the player's mode. What they do, is they take a list of strings/words, and allow you to use them in place of integers(numbers). Prior to GS2 and enumerators, you had to do something similar with numbers. player.movemode = 0, player.movemode = 7... in the end that's very hard to keep track of. You could also do something like player.movemode = "idle", and such, but strings are harder to work with. So enumerators create the best of both worlds!
PHP Code:
enum {
IDLE,WALK,GRAB,PULL,PUSH,SIT,SWIM
}
The above means I can use the defined words in place of numbers. player.movemode = GRAB, for example. But Graal will read GRAB as 2, because it is the 2nd index in the enumerator(much like arrays, they start at 0). So if you do player.chat = player.movemode, it will echo an integer instead of IDLE/WALK and so on. But as far as reading the script goes, they make it so much more easier.
One more thing... you'll notice I use vars like player.speed to store variables. This is strictly to simplify the script. However, they are not secure! You should instead use more secure methods to store important gameplay data like the player's speed(clientr.vars).