Miransu's EV USER Guide

From Danmakufu Wiki
Jump to: navigation, search

In v0.12m, the only way to pass information from one script to another was through the use of common data. In some cases, common data was used to tell a certain script that it is time to execute some code. In ph3, though, these scenarios can make use of the new @Event and NotifyEvent. As you can pass event arguments using NotifyEvent, you can do almost anything with @Event. Here you will learn how this can be done.

Before we start

It would be useful to know the functions needed, first of all. Here is the documentation for the functions, NotifyEvent and NotifyEventAll.

Another thing before we start: it would be advisable to think of something we can actually do with the EV_USER series. One of the first things that comes to mind is to handle the spawning of items. In fact, that is exactly what we will be doing today with EV_USER.


@Event

It's really likely that you've had a stage or a plural script with an empty @Event not really knowing what to do with it. If so, you will soon find a use for it.

If you have made a player script or a boss before, this might seem a bit familiar to you.

@Event {
	alternative(GetEventType)
	case(EV_REQUEST_LIFE) { SetScriptResult(3000); }
	case(EV_REQUEST_TIMER) { SetScriptResult(60); }
}

User-defined events are somewhat similar to this.

You should start out with any stage or plural script with an empty @Event. Please refer to this table to check which kind of EV_USER you should use. While it is not strictly required that you use the corresponding EV_USER type, it would be much easier for yourself to know which values handle what things, especially when making a full game.

Script Type   ||    EV_USER Type
================================
Single        ||    EV_USER
Plural        ||    EV_USER
Stage         ||    EV_USER_STAGE
Package       ||    EV_USER_PACKAGE
System        ||    EV_USER_SYSTEM
Player        ||    EV_USER_PLAYER

For this tutorial, a stage script will be used. As NotifyEvent requires the script ID, we will have to find the ID manually, by using common data. That way, we can use this common data to notify the stage script from anywhere. In the stage script's @Initialize:

SetCommonData("Main Stage Script ID", GetOwnScriptID());

This will come in very handy, soon.

Since we are using a stage script, we will use EV_USER_STAGE in our stage's @Event.

@Event {
	alternative(GetEventType)
	case(EV_USER_STAGE) {
		// ---
	}
}

As mentioned before, our goal is to handle the spawning of items. However, we must take little steps, not giant leaps. Let's start by making the stage spawn a single power-up item at a fixed position.

	case(EV_USER_STAGE) {
		CreateItemA1(ITEM_POWER, 96+rand(-50,50), 128+rand(-50,50), 1000);
	}

Once notified, the stage will spawn one item, placed randomly inside a 100 x 100 block with the center at (96, 128).

However, this event is never actually notified throughout your entire script... not yet, at least. Let's fix that.


NotifyEvent

You can call NotifyEvent wherever you want, however many times per frame you want! As situations and scenarios vary, you should figure out where you want to place your NotifyEvent. For example, you might want to make a boss drop power items after a spell is finished. Instead of writing any of the CreateItem series, you will instead place a NotifyEvent there.

function MyStageID { return GetCommonData("Main Stage Script ID", 0); }
loop(10) {
	NotifyEvent(MyStageID, EV_USER_STAGE, NULL);
}

Notice that we put the common data that we set earlier to use. Once EV_USER_STAGE is notified, it will execute whatever code is specified. In this case, it spawns an item. Since we called NotifyEvent ten times, we will have ten items spawned in the same frame.

Event arguments

You would now be ready to add event arguments.

For some reason, only GetEventArgument(0) can be used for user-defined events, so passing multiple values must be done via array.

Stage script's @Event:

	case(EV_USER_STAGE) {
		let arguments = GetEventArgument(0);
		let spawnType = arguments[0];
		let spawnX = arguments[1];
		let spawnY = arguments[2];
		let spawnScore = arguments[3];
		CreateItemA1(spawnType, spawnX, spawnY, spawnScore);
	}

Wherever your NotifyEvent is:

NotifyEvent(MyStageID, EV_USER_STAGE, [ITEM_POWER, GetStgFrameWidth/2, GetStgFrameHeight/2, 10000]);

You would now be spawning a single power item in the middle of the playing field. Notice that the arguments within the array are made to be the same as the arguments required for CreateItemA1.



Multiple cases

That's right, you can have more than just EV_USER in @Event. Actually, EV_USER and its counterparts are all constants, so you can have as many user-defined events being checked by one script as you want. In fact, it would be perfectly safe to have events EV_USER all the way to EV_USER + EV_USER_COUNT.

To translate into code, a player script would theoretically have no problem handling this @Event:

@Event {
	alternative(GetEventType)
	case(EV_USER_PLAYER) { }
	case(EV_USER_PLAYER + 1) { }
	case(EV_USER_PLAYER + 2) { }
	// ... ... ...
	case(EV_USER_PLAYER + EV_USER_COUNT) { }
}

Look at all the possibilities that ph3 opens up for you. What you can do with the magic of EV_USER and NotifyEvent is only limited by your imagination.



NotifyEvent from packages to stages or vice versa

There's one thing you'll have to be aware of. When you use plain NotifyEvent from a stage/plural/etc. to notify a package, the @Event is not notified. Same goes for the other way around (package to single/plural/etc.) However, using NotifyEventAll will notify the @Event of any currently-running script without fail... Just be careful not to accidentally notify identical EV_USER events all at once!

On that note, have fun with your user-defined events!