Pikifen/Object script

From Pikmin Fanon
Jump to: navigation, search

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.


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".

Red Bulborb guide[edit]

Creating the script[edit]

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 Script.txt, on the same folder. Create the file if it is not there already.

On this text file, add a script 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[edit]

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 sleeping. 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 sleeping { line, and the matching } line.

Your script should be looking like this:

script {
    sleeping {

Looking out for an event[edit]

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 comes near. For clarity, let's call Pikmin and leaders "opponents", since they technically belong to a different "team" than the Red Bulborb. We have to write the name of the event, which in this case, is on_opponent_in_reach. All events start with on_ (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 draws near, the Bulborb will perform some actions that we will specify later (waking up).

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

Performing an action[edit]

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 animation = waking_up. That animation part at the start tells the engine that the enemy needs to change animations, while the part after the equals sign specifies what the animation is. Here, it is assumed that the animation for waking up is in fact called waking_up, 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 gets near. 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 walks up close to 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 close (yet still). And because the Bulborb is still in the "sleeping" state, which is a state that is looking out for the "opponent is within reach" 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 within reach" events.

Add the line state = waking_up 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 {
            animation = waking_up
            state = waking_up
    waking_up {

On enter[edit]

Although it is not the case, imagine that we wanted to make a grumble sound play, and a "bubble pop" 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 (bomb rock noise, 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 on_enter. 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 on_opponent_in_reach event.

So, to recap, while sleeping, whenever an opponent comes within reach, 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[edit]

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 animation finishes". The event that checks this is called on_animation_end. 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 {
            state = waking_up
    waking_up {
        on_enter {
            animation = waking_up
        on_animation_end {
            state = examining
    examining {


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: move = home. It would make sense to make this action run whenever the "returning_home" event 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 on_reach_destination. Here, we can set it to a state where it falls asleep.


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 sleeping state, a "near" Pikmin is any Pikmin that is very close, in the examining state, it's any Pikmin that's 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 near_reach = wake_up to the on_enter 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" (and as such, trigger the on_opponent_in_reach events) 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 on_opponent_in_reach 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 on_opponent_in_reach event, we can perform the action focus = mob. This will make the Bulborb focus on whatever mob triggered the event. It is also useful for 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? This "focus" mechanic allows that to happen.

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 move = focused_mob. In addition, let's add an on_focus_off_reach 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 far_reach = chase, so that the on_focus_off_reach 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 on_focus_off_reach 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.


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 hitboxes, and they are named. Enemies like a Red Bulborb should use a "mouth" hitbox, because this is the hitbox 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. It 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" hitbox is now a Pikmin-eating hitbox. To do so, use the action chomp = 5 mouth. The chomp action controls everything about hitboxes that trap 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 hitbox that will be made to trap Pikmin. From here on out, any Pikmin that touch the "mouth" hitbox will squeal and become trapped in its mouth.

Two events control what the Bulborb should do next. on_mouth_occupied will trigger when the Bulborb has Pikmin captured. on_mouth_empty will trigger when there are no captured Pikmin. As a result, it is a good idea to have a state dedicated to examining the mouth, which will make the Bulborb do something depending on which of the two events gets triggered. You could make it so that if its mouth is occupied, it moves on to a chewing state, whereas if it's empty, it should move to a state where it failed the lunge, flopped on the ground, and will slowly get back up. You might also want to make the mouth hitboxes return to normal at this point, which can be done by setting the active chomping hitboxes to none; this is done by the action chomp = (i.e. the "chomp" action with no data).

What about eating and killing the capture Pikmin, or releasing them without harm? This is controlled by the eat action. eat = all will make the enemy eat all captured Pikmin. If instead of all you write a number, the enemy will only eat those many Pikmin and keep the others trapped. If you type eat = (i.e. the "eat" action with no data), the enemy will safely release all captured Pikmin.


There are two parts to an enemy's death. The start, and the end. The on_death event is triggered when the enemy's health drops to 0. You should try to have this event on all or almost all states. 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 special_function = die_start.

When it's time to register the enemy as completely dead, you need to call the action special_function = die_end. This will make the object carriable, release a ghost, etc. In general, when an enemy dies, you want to enter a "dying" state, call the "die_start" special function, set its animation to something related to collapsing, wait for the animation to finish, and then run the "die_end" special function.

Bottomless pits[edit]

What about when the enemy falls into a bottomless pit? You want it to die, right? Well, once again, you'll have to specify yourself on the script what happens when an enemy falls into a pit. For this, use on_bottomless_pit, and once again, try to place this on most states, or at least the ones where the enemy moves (not much point in checking if an enemy fell in a pit if it's sleeping, since it shouldn't be able to fall down one if it's standing still, right?) Also, you may not want the enemy to go through its death animation. The point of falling into a pit is to quickly be out of sight and forgotten into nothingness. The best way would be to make the engine acknowledge the enemy's death and instantly delete the object (preferably in that order!). For the former, simply call the die_end special function, and for the latter, use the delete special function.


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: timer = 20. This will start an internal timer for the object that will tick in 20 seconds.

On the sleeping state, look out for the on_timer 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 don't want. You can kill the timer by simply typing timer = 0.


This part is a bit of a stretch, but since it is a tutorial, let's do it anyway. Let's say that every time the Bulborb wakes up, only to find nothing nearby, it gets annoyed. If it gets annoyed twice in a row, it will stay asleep without waking up the next time a Pikmin walks near. If you kept being pranked to wake up, only for it to be nothing, by the third time, you'd refuse to get up, right? How can we keep tab of how many times the Bulborb woke up in vain? Well, the number of times it gets annoyed should increase whenever the Red Bulborb looks around and fails to find anything of interest. So onward to the on_animation_end event of the "examining" state.

In here, we'll increment the number of times it got annoyed by one. But wait, what is keeping tab of this? Don't worry, the enemy's object can keep tab of this and any other variable. Write the action inc_var = annoyances. The inc_var action is responsible for incrementing a variable. But wait, you say, where is the variable? We never specified we wanted a variable! The truth is that any variable can be created at any time, and it starts off with an empty value (or 0, if we're talking about numbers). So, the first time we refer to the variable (that we named "annoyances"), it will be created on the spot with the value 0. It will then be incremented by one. So, the very first time this part of the script runs, an "annoyances" variable will be created inside the object, it will be worth 0, and instantly get incremented to 1. The next time the Bulborb becomes annoyed, the variable already exists, so it merely becomes increased to 2.

Now, to do something with this variable. We want to make it so that when a Pikmin or leader comes near, the Bulborb ignores them, if it suffered 2 or more past annoyances. Well, we can check if the "annoyances" variable is worth 2, and if so, refuse to wake up. How can we check? Using the if actions. On the "sleeping" state, on the event that an opponent comes near, we'll check the annoyance level. If it is at 2 or more, nothing should happen. Otherwise, it should switch to the "waking up" state as usual. The way the if actions work is that they change the flow of the script slightly, by only running the next action if the condition they test for is true. So, we only want the waking up procedure if the annoyances are less than 2.

Write if_less = annoyances 2. This if_less is a version of if that – you guessed it – will only run the next action if the variable is less than whatever number we give it. As the first word, we write "annoyances" – that's the name of our variable – and on the second, the number we want to compare to. Then, as the next line, we have the action to switch states. So to recap, if the number of annoyances is less than 2, then it'll run the next action – switch to the "waking_up" state. If not, it won't. That's exactly what we want, so that's all there is to it.

There are more ways to change the values inside of variables, as well as check their values before performing an action. At its most basic state, a variable has some text or number inside. You can set a variable's value like so: var = rage high, which would set a "rage" variable to the value "high". We could then use an if to only run an action if the variable matched an exact value. We would do this with if = rage high. For all variations of if, check the full list of actions.

Script-related parameters[edit]

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 Script.txt file, which you should still be on, add the following parameter to the usual parameters: first_state = sleeping.

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 parameters, and are as normal as weight or rotation speed. The following parameters exist, and you should try to declare them all. Go back to the Data.txt file to add them:

  • big_damage_interval: Whenever the enemy loses this much health, a "big damage" event is thrown. This is useful to make an enemy shake every time they receive a lot of damage, for instance. Setting this to something like 10% or 20% of the max health is usually the way to go.
  • territory_radius: 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 reaches. Inside, one per line, you declare the reaches, in the format <name> = <distance 1> <angle 1> <distance 2> <angle 2>. What does this mean? Well, let's fill in the "wake_up" reach. Type down wake_up = 10 360. 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 search = 250 180 30 360 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 attack = 40 30 (Pikmin within this reach are ready to be chomped), and chase = 250 360 (focused Pikmin outside of this reach will be considered lost).

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.

List of events[edit]

Event Description
on_enter Triggered when the current state is entered.
on_leave Triggered when the current state is left.
on_animation end Triggered when the current animation finishes. Technically, this is triggered when the current animation begins looping.
on_big_damage Triggered when the object takes considerable damage, as defined by the big_damage_interval parameter. If the current state cannot handle this event, it will continue being sent until an event shows up that can handle it.
on_damage Triggered when the object takes any sort of damage.
on_death Triggered when the object's health reaches 0.
on_face_object Triggered when the object is both facing (within a near_angle angle) and near (within near_radius distance) another object.
on_face_opponent Same as on_face_opponent, but for opponents only.
on_far_from_home Triggered when the object is far enough away from its home (as per the territory_radius parameter).
on_lose_focused_mob Triggered when the object can no longer see the focused object, either because it disappeared, or because it's farther than sight_radius.
on_mouth_empty Triggered when the object has no Pikmin captured in its mouth.
on_mouth_occupied Triggered when the object has at least one Pikmin captured in its mouth.
on_near_object Triggered when the object is near any object, within the distance defined by near_radius.
on_near_opponent Same as on_near_object, but for opponents only.
on_pikmin_land Triggered when a thrown Pikmin lands on it.
on_pikmin_latch Triggered when a thrown Pikmin latches on to it.
on_reach_destination Triggered when it reaches its destination by moving there with the move action.
on_see_object Triggered when it sees any other object, within the distance defined by the sight_radius parameter.
on_see_opponent Same as on_see_object, but for opponents only.
on_touch_opponent Triggered when it touches an opponent.
on_timer Triggered when the internal timer reaches 0.

List of actions[edit]

Action Description
animation Changes to and begins the specified animation.
chomp Controls what hitboxes will be used to trap Pikmin from here on out. If you don't specify any data, it means no hitboxes will be used for chomping any more. Otherwise, the first word is the maximum number of Pikmin that can be caught, and the second, third, etc. words are the names of the hitbox(es) that will be used for trapping.
eat Controls what to do with trapped Pikmin. If the data is all, all captured Pikmin are instantly swallowed and killed. If the data is a number, only that number out of the captured Pikmin will be swallowed. If you don't specify any data, all captured Pikmin are safely freed.
focus Focuses on the object that triggered the event.
gravity Sets how gravity affects this object. 1 is normal, 0 is no gravity, 0.5 is half gravity, -1 is upwards gravity, etc.
health Sets the object's health to the specified number. If the first word is "relative", then the amount in the second word will be used to add or remove from the current health.
hide Sets whether or not the engine should hide this object's shadow and health. This is useful, for instance, when a Sheargrub digs underground.
if Only executes the next action if the value of the variable in the first word matches the value in the second word.
if_less Only executes the next action if the value of the variable in the first word is smaller than the value in the second word.
if_more Only executes the next action if the value of the variable in the first word is larger than the value in the second word.
if_not Only executes the next action if the value of the variable in the first word is different from the value in the second word.
inc_var Increments the specified variable.
move Tells the object to begin moving in a straight line somewhere. If the data is focused_mob, it moves towards the focused object, following it as it moves. If it is home, it moves towards its home. If it is stop, the object stops in place, and if the second word is vertically, it will kill all vertical momentum. If the first word is vertically, the second word will be used to set how much it will move up or down (positive number means up). If the first word is randomly, it tells the object to move in a random direction. If the first word is relative, the second and third words indicate what point (X and Y) the object will move to, relative to its current position. Finally, if you only have two words, and they are numbers, these specify the map coordinates that the object will move towards.
particle Begin emitting particles. Specify the particle generator in the parameters. If nothing is specified, it stops emitting particles.
special_function If the data is die_start, it runs the procedure related the start of the object's death sequence. If the data is die_end, it runs the procedure related to the finishing of the object's death sequence. If the data is delete, it deletes the object from the world.
state Instantly changes to the specified state.
timer Starts the timer with the specified time period.
var Sets the variable in the first word to be worth the value in the second word.


  • 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.