Making Interesting NPC Routes with Script Calls Part 2
June 29, 2021
June 29, 2021

Making Interesting NPC Routes with Script Calls Part 2

Making Interesting NPC Routes with Script Calls Part 2



June 29, 2021

Have you ever wanted to show a balloon icon in a move route to draw your players’ eyes to an event? How about creating a creepy flickering effect for a ghost in a horror game? Or maybe you wanted an event to become visible only if the player is nearby? Today let’s take a look at some more script calls we can use in move routes that will make all that possible.

We’ve already covered some interesting ways to use script calls in an event’s autonomous movement section in a previous tutorial, but while working on it there were a few other cool script calls that needed a bit more testing before they would fit into a tutorial. That testing is all done, so let’s learn a few new ways we can use script calls to make our events’ move routes even better!

And like last time, we’ll be making use of the MZ’s Script Call Reference sheet.

Showing Balloons in the Move Route

Balloons are a great way to draw the players’ eyes to a certain event, such as a sign or quest giver that will move the game’s plot along. There isn’t a button to show a balloon in a move route, but we can get around that with a script call! So let’s start by making an event that could use a balloon above it, in this case a sign.

The event only needs one page for this example, but if we wanted the balloon to disappear after the player interacts with the event then we could do that easily by having a second page where the move route doesn’t include the balloon script call.

The script call itself is $gameTemp.requestBalloon(target, balloonId); , where target tells the engine which event the balloon will appear above and balloonId tells us which balloon is used (starting at 1 for the exclamation point). The engine needs the target to be exact, so we can’t just put something like ‘12’ and have it know to show the balloon above event number 12. Instead, we need to use $gameMap.event(N) as the target, with N being the event’s id. But since we want the balloon to appear over this event, we can use $gameMap.event(this.eventId()) to have the engine use this event’s id.

So to have the exclamation balloon show above our sign event, our script call is $gameTemp.requestBalloon($gameMap.event(this.eventId()), 1); .

There is a possible error we need to keep in mind if we use this script call though. If we only have that script call in the move route then the engine will keep trying to show the balloon without waiting for it to finish, leading to an odd appearance:

A simple wait command will fix that problem, our our sign’s move route looks like this:

All that’s left is to playtest and make sure that our sign has a very obvious balloon popping up overhead.

Randomizing Opacity

Flickering lights and shadowy ghosts can add a lot of atmosphere to horror games or just a spooky dungeon. But to get a flickering effect we would need to use the change opacity command, which only allows numbers. So if we wanted it to look like it’s a ‘random’ flicker, we’d need to put a ton of opacity changes into the move route and some eagle-eyed players could still notice the pattern.

So instead, what if we added some real randomization to the opacity changes? Let’s take a look at how we can do that with some script calls. First thing we need is to set up our flickering ghost event.

Our ghost’s move route needs two script calls to get a really good random flicker: one to change the opacity and one to set a wait time. We’ll be using this.setOpacity(num); to change the ghost’s opacity, all we need to do is replace num with a code to pick a random number. The code we need to do that is (Math.random() * (max - min) + min) so that we can control the mix and max for the opacity. So if we want the opacity to be a random number between 50 (mostly transparent) and 255 (fully opaque), we need to make the max 255 and the two min 50.

Put it all together and we get this.setOpacity(Math.random() * (255 - 50) + 50);

Now that we have our opacity randomized, we can move on to the random wait time. While we could use the wait command, a more inconsistent wait between opacity changes can make the flickering feel even more random. The base script call we’ll be using is this._waitCount = num - 1 , where we’ll replace the num with the same Math.random code we used previously and swap out the min and max with 1 and 30 so the wait time will be between 1 and 30 frames.

With both of the script calls ready to go, we can put them both in the ghost’s move route and then playtest to make sure our ghost’s flickering is suitably random.

Proximity-Based Move Routes

Did you know there’s a built-in script call to check how close two events are to each other? It can be easy to overlook if you’re not sure how to use it, but once we figure it out it means we can make events change based on player proximity without needing to add a new plugin to our projects.

The script call we’ll use is $gameMap.distance(x1, y1, x2, y2) , which compares the x and y coordinates of the two included events to see how close they are in tiles. So if we put $gameMap.distance($gamePlayer.x, $gamePlayer.y), $gameMap.event(n).x, $gameMap.event(n).y) into a variable we’d get a number back that compares the player’s coordinates to event n’s coordinates. The number for the distance is determined using an equation that pretty much forms diamond pattern around the first event, similar to this example:

But we don’t need to put our script call into a variable to use it in a move route, instead we can use it in a conditional branch, something like $gameMap.distance(x1, y1, x2, y2) > num ? (result if true) : (result if false) .

To see this in action we’ll need an event, in this case a sleeping boy who will appear to wake up if the player is within 2 tiles.

The boy’s event will use two pages, the first one with his sleeping sprite and the second page (which is active when self-switch A is On) with his awake sprite.

Both pages will have the same script call in the move route, that will check if the player is within 2 tiles of the sprite and turn self-switch A On if true or Off if false. We’ve already talked about the self-switch script call in a previous tutorial, so let’s take a look at how the whole thing works together:

$gameMap.distance(this.x, this.y, $gamePlayer.x, $gamePlayer.y) <= 2 ? $gameSelfSwitches.setValue([$gameMap._mapId, this.eventId(), 'A'], true) : $gameSelfSwitches.setValue([$gameMap._mapId, this.eventId(), 'A'], false)

As we can see, longer script calls are difficult to read (and debug) in the move route’s script command, so for longer codes it’s best to write them out in a separate program so you can easily read the whole thing.

With the script call copied into both move routes, we just need to playtest and make sure it works properly.

Now our sleepy boy will change depending on if the player is close or not. But what if we want to use this proximity check method to have multiple changes to an event?

Multiple Proximity-Based Effects in One Move Route

To see an event change depending on how close/far the player is, let’s create a laser beam event that has its opacity increase as the player approaches. If the player is within 2 tiles then the beams are fully opaque, and each tile beyond that will decrease the opacity by 50.

We could set it all up in a single script call with multiple conditions, but it’s easier to put each condition in its own script call using if ($gameMap.distance(x1, y1, x2, y2) > num) {result if true} . To get the effect we want we’ll need six script call commands, with each one focusing on a different distance. We’ve already covered the script calls we need to get these to work, so let’s just see how they all are written:

if ($gameMap.distance(this.x, this.y, $gamePlayer.x, $gamePlayer.y) <= 2) {this.setOpacity(255);}

if ($gameMap.distance(this.x, this.y, $gamePlayer.x, $gamePlayer.y) == 3) {this.setOpacity(200);}

if ($gameMap.distance(this.x, this.y, $gamePlayer.x, $gamePlayer.y) == 4) {this.setOpacity(150);}

if ($gameMap.distance(this.x, this.y, $gamePlayer.x, $gamePlayer.y) == 5) {this.setOpacity(100);}

if ($gameMap.distance(this.x, this.y, $gamePlayer.x, $gamePlayer.y) == 6) {this.setOpacity(50);}

if ($gameMap.distance(this.x, this.y, $gamePlayer.x, $gamePlayer.y) >= 7) {this.setOpacity(0);}

Each script call gets placed into its own script command:

And we end up with a move route that looks like this:

All that’s left is to playtest and make sure our laser bars appear as we approach them and disappear if we leave. If it isn’t changing at a certain point, then we just need to double-check our script calls to make sure we haven’t accidentally mistyped anything.

With this new knowledge, you could create creepy ghosts to scare your players that disappear when they try to approach or have sparkles show on interactable items if the player is near them. Where would you use these script calls in your games?

Recommended Posts