Sparen's Basic Ph3 Item Tutorial

From Danmakufu Wiki
Jump to: navigation, search

NOTE: This tutorial is meant for those with limited experience in ph3. This is NOT a tutorial for those trying to learn how to make custom item scripts. It is meant for those who want to be able to spawn items without them magically never appearing.

In this tutorial, I will explain how item functions work, why they never appear for some people, and will provide code for people to use. If you want to understand why it works the way it does, please read the following: Sparen's 0.12m to ph3 Transition Guide#NotifyEventAll (Advanced) as well as Miransu's EV_USER tutorial.

Well then. Let's get started.

Item Functions

For reference: Item Functions

For starters, we will use CreateItemA1, the most basic of item functions.

Arguments:
    1) type
        ITEM_1UP     ITEM_1UP_S    : life
        ITEM_SPELL   ITEM_SPELL_S  : bomb
        ITEM_POINT   ITEM_POINT_S  : point
        ITEM_POWER   ITEM_POWER_S  : power
        ITEM_USER                  : user-defined
    2) x-coordinate
    3) y-coordinate
    4) scoring
Return Value
    Object ID

CreateShotA1 creates an item at the specified points. The types ending in "_S" will create a smaller version of the specified item. "scoring" is the value the spawned item will add to your score. As can be seen here, this function is designed to create an item at a certain location with a certain score value. This is the most generic your items will be. If you want further control, you will be using CreateItemA2 or, if you want full control over your custom items, CreateItemU1 and CreateItemU2, neither of which will be covered in this tutorial.

CreateItemA2 is similar to CreateItemA1.

Arguments:
   1) type
   2) x-coordinate
   3) y-coordinate
   4) x-coordinate destination
   5) y-coordinate destination
   6) scoring
Return Value
   Object ID

The only difference is that you can specify the destination of the item before it falls down. For example, you can make the items fly out in a circle and then fall down. Spinning effects will require other techniques, however.

Why is my item not appearing?!

Well, first, let us see some code.

   task TFinalize {
       while(ObjEnemy_GetInfo(objBoss,INFO_LIFE)>0){yield;}
       loop(12){yield;}
       CreateItemA1(ITEM_POWER, ObjMove_GetX(objBoss), ObjMove_GetX(objBoss), 1500);
       DeleteShotAll(TYPE_ALL,TYPE_ITEM); //All shots become point items
       Obj_Delete(objBoss);
       DeleteShotAll(TYPE_ALL,TYPE_IMMEDIATE);
       SetAutoDeleteObject(true);
       CloseScript(GetOwnScriptID());
       return;
   }

Chances are, your TFinalize or whatever code you use when you eliminate the boss looks vaguely like this, with the boss being deleted, spawning an item at the boss's location, and having SetAutoDeleteObject to true, since that takes care of deleting all of your graphics and everything.

However... your item never appears.

You stare at the code. You stare some more. And then... a few tries later...

You still don't get why it's not showing up.

"It's got to be a bug in Danamakufu!" you say to yourself (I'm not the only one who thought this).

But no, it is not. Look carefully at the following code:

       SetAutoDeleteObject(true);

Now, think about what this function is supposed to do. It... automatically deletes objects, right? Like, graphics and...

Chances are, you will understand right then and now why your code fails to work. If not, here's the short story: your item is an object, and at the end of the #Single, SetAutoDeleteObject(true) will delete that object.

So... how do you avoid this? Well, that's the next part of the tutorial.

Utilizing NotifyEventAll and a Stage to spawn items

Well, you can't spawn the item in the script, right?

First thing's first. DO NOT SetAutoDeleteObject(false). This is not recommended. Instead... use the way Danmakufu communicates between scripts. CommonData is not advisable, but NotifyEvent is.

For those transferring in from 0.12m, you may want to read up on @Event and EV_USER. But for those who have a hazy notion of what these are, here's the short story.

In your stage (of plural, although this specific tutorial will assume you are storing data in a stage), go to your @Event, which probably doesn't have too much in it.

Do the following:

 @Event{
   alternative(GetEventType())
   case(EV_USER_STAGE+1){
     let arg = GetEventArgument(0);//x, y
     CreateItemA1(ITEM_POWER, arg[0], arg[1], 1500);
   }
 }

If you have stuff in @Event already, just add the case{}. If you are already using EV_USER_STAGE+1, use EV_USER_STAGE+10 or some other number.

Then, in TFinalize, or wherever you are trying to spawn your item, use the following instead:

   NotifyEventAll(EV_USER_STAGE+1, [ObjMove_GetX(objBoss), ObjMove_GetY(objBoss)]);

This will notify ALL @Event routines running in all of your open scripts, and will trigger every case of EV_USER_STAGE+1. Inside the brackets is an array containing the x and y coordinates used to spawn the item.

When Danmakufu finds EV_USER_STAGE+1 in the stage, it will let arg equal the Event Argument, which is the array containing the boss's x and y coordinates. Then it will create an item at those x and y locations.

And voila. Your item should spawn.

A very simple TFinalize with the NotifyEvent code would look like the following, although there will undeniably be differences.

   task TFinalize {
       while(ObjEnemy_GetInfo(objBoss,INFO_LIFE)>0){yield;}
       loop(12){yield;}
       NotifyEventAll(EV_USER_STAGE+1, [ObjMove_GetX(objBoss), ObjMove_GetY(objBoss)]);
       DeleteShotAll(TYPE_ALL,TYPE_ITEM); //All shots become point items
       Obj_Delete(objBoss);
       DeleteShotAll(TYPE_ALL,TYPE_IMMEDIATE);
       SetAutoDeleteObject(true);
       CloseScript(GetOwnScriptID());
       return;
   }

Closing Notes

This tutorial is short, but I hope people find it useful.

--Sparen of Iria