Pikifen/Object script

This page will guide you on how to write a script for enemy objects in Pikifen. Although it is recommended to follow this guide from start to finish, you may jump straight to a section that explains a specific problem you may be having. To note is that you can also copy and paste an existing enemy's scripts and properties and adjust them to your liking, instead of creating everything from scratch.

Introduction
The script is basically that: a script, like in a movie or theater. Something like: "When the bad guy says 'I'll get you', you say 'never!'. When the bad guy throws the punch, you dodge to the side." Except we'll be instructing the enemies to do what they need to do. "When a Pikmin shows up, you move to it. When the Pikmin is close, you lunge in for a bite."

For this, you'll need to understand some concepts: an action is an instruction we'll tell the enemy to do, like moving somewhere, focusing its sights on an object, changing its animation to the sleeping one, etc. An event is the same as the "when"s on the previous example. An event can be something like when a Pikmin approaches, when it reaches its intended destination, when its current animation finishes, etc. So, in essence, when an event happens, the object will perform some actions. That's the basics of it.

There is one more concept: a state. To make it easier, you can think of a state like a state of mind in a human: sleeping, hungry, disturbed, thinking about what to cook, etc. Except states for enemies can be anything you want. For an enemy like a Red Bulborb, the states would be sleeping, chasing prey, chewing, shaking, going back home, etc. States are important, because depending on the state, we may want the same event to trigger different actions. For instance, suppose a Pikmin comes near. What is the Red Bulborb to do? Well, it depends on its state: if it's sleeping, it must wake up, but if it is awake, it should lunge in for a chomp.

One final note: "mob" (short for "mobile object") is an alternate name for "object".

Creating the script
If you haven't already, follow the object type tutorial to create your own enemy. We'll be writing the script on a file called, on the same folder. Create the file if it is not there already.

On this text file, add a  block. Inside of this, we'll be adding our enemy script. For the rest of this tutorial, we'll be creating a very basic (and varied) Red Bulborb.

Creating a state
We'll need to start the script with a state. Let's think of the most "normal" state for a Bulborb, to serve as a starting point. That would probably be the sleeping state, right? Most Bulborbs we see in the games are asleep when first met, so it makes sense to start here. You can name a state whatever you want (so long as you don't use spaces), but for the sake of clarity, let's call it. Ok, now we're going to have to specify what events and actions can take place while in this state. In order for the engine to understand what events/actions belong to this state, we'll need to a block for this state, create a  line, and the matching   line.

Your script should be looking like this: script { sleeping { } }

Looking out for an event
Let's see, in this state, there's not much the Bulborb can do except wake up. Let's make it so that it wakes up when a Pikmin or leader touches it. For clarity, let's call Pikmin and leaders "opponents", since they are the sort of object the Red Bulborbs want to take down. We have to write the name of the event, which in this case, is. All events start with  (as in: "on the event that this happens, do that"), and in this case, this event triggers every time the Red Bulborb is near an opponent. What now? Well, we need to specify what actions to take. To recap: on the state of sleeping, when an opponent touches it, the Bulborb will perform some actions that we will specify later (waking up).

Because the engine needs to know what actions to perform on this event, we need to open up the event as a block with curly braces.

Performing an action
Let's assume that you already have animations for the Bulborb – these include waking up, walking, biting, going back to sleep, etc.

What we want now is for the Bulborb to wake up. Visually, we want its animation to change from the one where it is sleeping to the one where it wakes up and gets on its feet. For that, we can type. That  word at the start tells the engine that the enemy needs to change animations, while the other word specifies what the animation is. Here, it is assumed that the animation for waking up is in fact called, but you can name it whatever you want.

So, when the Bulborb is in the sleeping state, the engine will look out for the event in which an opponent touches it. When that happens, the Bulborb will perform an action in which it changes its animation to waking up. Makes sense, right? Except there isn't much else that will happen. A Pikmin touches it, the Bulborb visually changes to an animation where it wakes up, but then what? Well, right after it begins its waking up animation, the engine will realize that an opponent is touching it (yet still). And because the Bulborb is still in the "sleeping" state, which is a state that is looking out for the "opponent is touching" event...it will just trigger the event again and again, which will keep restarting the animation. And it will keep doing this until the Pikmin walks away. The logical solution would be to change its state right after setting its animation, so that it may wake up in peace, without being interrupted by the constant "opponent is touching" events.

Add the line  after the line with the animation change action. This action will make its state change. Well, now that we've said that, we should also create this new "waking_up" state, then. Create it below the "sleeping" state's block. If you want, you can add an empty line between the two states to make it easier to read. The script should be looking like this, so far:

script { sleeping { on_near_opponent { set_animation waking_up set_state waking_up }   }    waking_up { } }

On enter
Although it is not the case, imagine that we wanted to make a grumble sound play, and an "exclamation mark" particle effect whenever the Bulborb wakes up. That's fine, we would just add more actions to the event. But now imagine that there were more ways for the Bulborb to wake up. Like we wanted it to wake up if an internal alarm set off (a creature can't stay asleep forever, right?), or even when a bomb rock explosion happens nearby. No problem, we would just add the events for those to the "sleeping" state, and make those events do the same. Except...it is a bit of a pain having to copy and paste the exact same set of animation+sound+particle+state actions for every one of those events. Well, there is an alternative way, which is much more organized.

Let's think about this: the animation, sound, and particle effect all happen when? When the Bulborb wakes up. When do we know exactly that the Bulborb woke up? When it enters the "waking_up" state. Regardless of how it got there (opponent touch, biological alarm, etc.), we know that if it got to this state, it means that it must perform the wake-up routine that involves all of those things. Luckily, we can specify what should happen when an object enters a state. Go to the "waking_up" state and add an event called. In here, place the usual actions. Oh, but because the sound and particle only belong to that a hypothetical scenario, the only action you should put here is the animation change we wrote earlier. Remember to remove the animation action from the sleeping state's  event.

So, to recap, while sleeping, whenever an opponent touches it, it will change state to waking up. When it enters this "waking up" state, it will perform its animation to wake up. Makes a bit more sense this way, and it's also more organized. Keep this in mind when you want to switch to a state using multiple ways.

On animation end
Ok, now that the Red Bulborb can enter the "waking up" animation, what should it do while in it? Well, it shouldn't really be willing to fight, should it? It is still getting up, so it's not ready for that. In fact, it cannot do anything while in this state except finish getting up. As soon as it finishes though, it should probably look around for whatever woke it up. Ok, so on the event that it finishes getting up, it shall begin examining its surroundings. But how do we know that it finished getting up? Considering that games are simpler than real life, we know how long the Bulborb takes to wake up, since its animation is always the same. We could then wait for that amount of time, but we don't need anything that complex. There is an event that will trigger every time the current animation finishes. So, the best way to go about this is: "on the event that its waking up animation finishes". The event that checks this is called. As for what actions to perform, it would make sense to enter a state where it analyzes its surroundings and acts according to what it decides at the time (going back to sleep, chasing prey, etc.).

Your script should look like so:

script { sleeping { on_near_opponent { set_state waking_up }   }    waking_up { on_enter { set_animation waking_up }       on_animation_end { set_state examining }   }    examining { } }

Moving
Let's speed up the tutorial a bit. On the "examining" state, we can set its animation to the animation where it looks around left and right in search of something to do. If it was asleep and woke up because of a nearby Pikmin, it will perform the waking up animation, enter the examining state, spot the Pikmin, and go for it. Makes sense. If it can't find anything to do by the point it finishes looking around, it should head back home (the spawn point) and fall asleep. Let's handle that scenario. On the "examining" state (where its animation is set to looking around when the state is entered), on the event that it finishes its animation, it should change to a state where it's focused on returning home. You might find it weird why the Bulborb would try to go home right after waking up, but remember that we can use the "examining" state elsewhere too, like after it finished eating all Pikmin, or has wandered too far.

On this "returning home" state, we must tell the Bulborb to walk home. The action that does this is simple enough:. It would make sense to make this action run whenever the "returning_home" state is entered, of course. Now, on this same state, we want to make it so that on the event that it reaches its home, it proceeds to fall asleep. The event that checks if an object has reached its destination is. Here, we can set it to a state where it falls asleep.

Chasing
What about moving towards a Pikmin? On the examining state, in the event that it spots a Pikmin, it should move towards it to try to eat it, right? But let's think about what it means to "spot a Pikmin". Enemies can only spot Pikmin if they are close enough – if they're within vision reach. And once the enemy gets close to the Pikmin, it will only lunge for the kill if the Pikmin is within biting reach. All of these reaches are things you have to define yourself.

When in a state, an enemy can consider something to be "near" it if it is within a certain reach. It can also consider the object it is focused on to be "out of reach". Since in the examining state, a "near" Pikmin is any Pikmin that is within eyesight reach, and in the chasing state, it's any Pikmin that's fairly close, you have to change what "near" means. So, add the line  to the   event of the sleeping state. This will set the "near" reach to a reach we'll call "wake_up". We can name reaches whatever we want; let's worry only about the names for now, since we'll actually declare their values later. For the examining state, set the "near" reach to "search". This way, a Pikmin will only be considered "in reach" if it's within "waking up" reach when sleeping, and if it's within "searching" reach when examining.

Now that the reach is set, we can be on the lookout for the  event on the examining state. When this event happens, well, we want the Bulborb to start chasing after the Pikmin. In order for the engine to keep track of what object our enemy is going to go towards, we need to say that the Bulborb will take focus on the Pikmin. On the  event, we can perform the action. This will make the Bulborb focus on whatever object triggered the event. This "focus" mechanic is also useful when losing track of the focused object: imagine that the Bulborb focuses on a Red Pikmin, and is going to chase it, but eventually, said Pikmin drowns. You would want the Bulborb to do something because it lost track of its prey, right?

Now that we've got that Pikmin focused, we want to move to it. Let's create a state for when the Bulborb is chasing. You may have guessed it, but the action that makes the Bulborb move to our focused Pikmin mob is. In addition, let's add an  event. This will trigger when the Pikmin is out of reach, which should happen when the Pikmin is so far away that the Bulborb can't see it any more. But just like before, this is another "reach". So, when entering the chasing state, use, so that the   event triggers whenever the focused Pikmin is off of this "chase" reach. You don't need to worry about the Pikmin dying or disappearing – that will also trigger the  event. Now that you're handling this event, you can make the Bulborb go back to the examining state, if the Pikmin it was chasing got out of reach.

Attacking
In the "chasing" state, our Bulborb is in pursuit. It's got its sights locked on to the Pikmin, and is always moving in its direction. On the event that it gets near (remember to update the "reach"!), it should take a bite. The general way biting works in the Pikmin games is that an enemy clamps its jaws in front of it, and any Pikmin that get hit will be caught in its mouth. In reality, there is a limit: if you have a massive group of Pikmin bundled together, and a Red Bulborb chomps through the group, it will only be able to catch 3 in Pikmin, or 5 in Pikmin 2. This behavior can be replicated on the engine as well.

In order for the whole "catching" part to work, we need to keep in mind something about animations; read the animation tutorial if you need a reminder. Each object has a set of body parts, and they are named. Enemies like a Red Bulborb should have a "mouth" body part, because this is the body part that will be keeping hold of any captured Pikmin.

When the Bulborb begins lunging, its mouth is no longer a passive body part sitting around doing whatever. The creature will open its mouth and will use it to capture Pikmin. So, on the beginning of its lunging procedure (likely when the Bulborb enters the "lunging" state), we should let the engine know that its "mouth" body part is now a Pikmin-eating body part. To do so, use the action. The  action makes some body parts start trapping Pikmin. The "5" there is the maximum number of Pikmin that can be caught at once. Finally, the "mouth" part is the name of the body part that will be made to trap Pikmin. From here on out, any Pikmin that touch the "mouth" body part will squeal and become trapped in its mouth.

When the lunge animation is over, you should set the "mouth" body part back to normal, so Pikmin don't accidentally get caught later when the enemy is, for instance, walking. To do this, write. Then, we'll (likely) want to change to a chewing state, where the Bulborb is chewing, and after it is done, kill off any caught Pikmin. This is controlled by the  and   actions, which will make it swallow some (randomly picked) or all captured Pikmin. On the flip-side, if you use, the enemy will safely release all captured Pikmin.

Variables
The Red Bulborb lunges. But did it capture any Pikmin? We need to know this in order to decide if the creature should start chomping, or if it should flop to the ground. We can ask the engine this question and it will be able to give us an answer. Once the lunge animation is over, add the action. This is what we use to get info of all sorts; in this case, we want to know the amount of chomped Pikmin currently in its mouth. But what do we do with this information?

We'll save it somewhere known as a variable. This is some space in memory dedicated to saving a value, and we can change it or retrieve it at any point. In our case, the variable will hold the amount of chomped Pikmin. And what about its name? In the previous paragraph, we called it  (short for "Pikmin in mouth"), but you can call any variable whatever you like. From here on out, whenever you need to refer to the number of Pikmin in its mouth, you can access the value in this "pim" variable by writing. When the script is run, it will replace  with 0, or 1, or whatever else "pim" is worth at the time.

It's generally good practice to declare a starting value for your variables. For this, you can create an  block outside of the   block, and in it, add. This will set the value of the "pim" variable to 0. Any actions inside this block will be run when the object is created, so you always know what the starting value of every variable is.

Conditions
Now to actually decide what to do after the lunge. The creature's behavior splits into two here: if it caught something, it should change to a chomping state, else, it should flop to the ground. This conditional logic can be written in the script.

After pointing down how many Pikmin got bit, let's run an  action. Write it down as such:. This action, when run, will check the number of Pikmin in its mouth, via our "pim" variable. Naturally, in this case, we want to check if more than zero Pikmin got caught. Then this action will change the flow of the script: if the Bulborb caught Pikmin, the script continues on to the next actions. So after this  action, add the action to enter a chewing state.

But what if it didn't capture anything? Well, write an  action after the action that sets to the chewing state. And after that, write the logic to change to a flopping state. With all of this logic, the engine will enter that  action, and if it realizes the condition is false, it will jump to the actions after the "else". To wrap up the conditional part of this event, after the action that changes to the flopping state, you will need to add an  action. With this, the engine knows that what comes after is no longer a part of the conditional logic, and its flow works like normal.

Note that you don't always need to add an "else" part to your condition. Also, you may want to indent (add another tab at the start) lines inside the "if" and "else" parts. This example is simple, but more complex conditions and flows will be much easier to read if you can easily tell what belongs to what part of the condition just from the way the text is laid out.

Death
The enemy can die at (almost) any moment. When that happens, the engine automatically jumps the script into a different state, so you don't need to worry about listening to the death event on every single state. To specify what state it should jump into, go out of the  block, and write a line with. This way, the engine knows that when the enemy's HP reaches 0, it must enter the "dying" state.

There are two parts to an enemy's death. The start, and the end. When an enemy's HP reaches 0, you likely want to make them perform a fainting animation, as well as call a special action that will run some extra code related to an enemy beginning to die (this code will, amongst other things, create the sparkling particles). This is done with the action. When it's time to register the enemy as completely dead (like when the fainting animation ends), you need to call the action. This will make the object carriable, release a spirit, etc.

Timers
Remember earlier when the idea of having the Bulborb wake up due to a biological timer came up? Let's implement that. Let's say that every time the Bulborb falls asleep, its biological clock sets an alarm for 20 seconds, at which point, it will wake up on its own, look around, and if there's nothing going on, fall asleep again. When the Bulborb falls asleep, so when the "sleeping" state is entered, use the following action:. This will start an internal timer for the object that will tick in 20 seconds.

On the sleeping state, look out for the  event. This will be triggered when the timer reaches 0. This would be the time to change the state to the "waking_up" state. When a timer reaches 0, it deactivates, so if you have a timer that you want to tick every X seconds, you need to set the timer again at that point. Other than that, there is one important question: what if the Red Bulborb's sleep is interrupted by a leader or Pikmin walking near? The timer would keep going, which is something we likely don't want. You can kill the timer by simply typing.

Script-related attributes
In order for the engine to get a grip on this script, we'll need to specify a few more things. First of all, on the  file, which you should still be on, add the following attribute outside the   block:.

This is so that the engine may know how the Bulborb begins its life. We did decide that the starting point of a Red Bulborb should be the sleeping state, so that is what we'll tell the engine. In addition, along this tutorial, there have been times where "being near" and "within sight distance" have been mentioned, but what are these distances? And surely they must vary by enemy. Well, they're just more attributes, and are as normal as weight or rotation speed. The following attributes exist, and you should try to declare them all. Go back to the  file to add them:


 *  : If an enemy has taken this much damage, it will be considered "itchy". With this, you can listen to the  event, and when it triggers, make the enemy shake the Pikmin off. Handling this event automatically resets the amount of damage, making it possible for the enemy to be itchy again, next time it takes this amount of damage. Setting this to something like 10% or 20% of the max health is usually the way to go.
 *  : In order for the enemy to not shake over and over, if you keep damaging it, you can also specify a minimum time requirement between itches, in seconds.
 *  : How far away from the spawn point must the enemy be before being considered "far from home". For reference, a Red Bulborb has this set to 500.

What about the "reaches" from before? This is where you'll define what a "waking up" reach is, what a "chasing" reach is, etc. Create a block called. Inside, one per line, you declare the reaches, in the format. What does this mean? Well, let's fill in the "wake_up" reach. Type down. What this means is that any Pikmin within 10 units of the Red Bulborb will be considered "in reach". The 360 is because we want this to happen regardless of where the Pikmin is in relation to where the Bulborb is facing, so it's a 360 degree range.

Now, add  for the next range. What about this? Well, this range actually has two parts. The first part means that Pikmin within 180 degrees of the Bulborb's front, and within 250 units, will be considered "in reach". This makes sense: any Pikmin that's within a fair distance in front of the Bulborb should be enough for the enemy to spot it. The second part means that any Pikmin within 30 units, at any angle, will also be considered "in reach". This extra part is useful for when the Pikmin is, for instance, hitting the Bulborb's back. Since the Pikmin is completely behind the Bulborb, it wouldn't be caught by the 250-180 description, since that only finds Pikmin in front. This way, any Pikmin close enough will also be considered "seen" by the Bulborb. The reason why we don't set the within-250-unit reach to 360 degrees is because that would unrealistically make the Bulborb see Pikmin far away that are behind it.

You'll need to tinker with these values until you find some balance you like. The other reaches will be something like  (Pikmin within this reach are ready to be chomped), and   (focused Pikmin outside of this reach will be considered lost).

Other than that, there's the script file's  attribute we filled earlier, and there is also a   attribute, in which you can list states that are meant to ignore the death event (separated by semicolon). If you find that a death even is being sent on states you don't want, add the state's name here. Similarly, there's a  attribute.

This ends the tutorial. From here on out, you would continue the script whichever way you wanted. Know that you can check the scripts of enemies that come packaged with the engine to learn more.

Relative coordinates
Some mob actions allow you to specify some coordinates relative to the object. While the absolute coordinates 50,100 are in the location of the map at X=50, Y=100, the relative coordinates mean that this is at the object's position, plus 50 to the right, and 100 down. This is assuming the object is facing the right.

If it isn't, the coordinates rotate around the object, such that a positive X is always in front of the mob. So for coordinates 50,100, this would mean 50 units in front of the mob, and 100 units to its right, regardless of where it's facing.

The same also applies to relative and absolute angles: a relative angle of 0 means the same angle that the mob is facing.

Precautions

 * When you want to change states, make sure that the action that switches the state is the last one that will be run on the event's code. This is because when a state change action happens, it skips over all other actions that were written after it.
 * When changing a state, make sure that the new state's  event doesn't change to another state in a way that could create an infinite loop. For instance, if changing to state A causes it to change to state B, which causes it to change to state C, which causes it to change to state A again, the engine will crash.