The video for this lesson is Experiment 354 by Miransu Uwabami. A legacy script no longer compatible with the current versions of ph3, it is nevertheless one of the best danmakufu ph3 scripts ever made.
So tested your danmaku abilities. You've created a number of scripts that you may or may not like. But they're all solo spells! What to do now but make a boss with multiple attacks!
Back in Lesson 2 and Lesson 3, I alluded to multiple types of scripts. For this unit, we will examine the plural, or boss. Although all functionality of a plural can be handled (perhaps more efficiently) in a stage, I will discuss bosses in the context of plural scripts.
It should go without saying, but you should not continue beyond this lesson if you have yet to make a few single scripts. Going farther than this without experience with Danmakufu's syntax, style, and general logic control and script and execution flow is not recommended.
In this lesson, we will focus on the creation of plural scripts and Enemy Boss Scene Objects, objects which store relevant data about a boss and are used for chaining attacks together. Later in this unit, we will discuss boss graphics and animation, sound effects, and text. We will culminate in a discussion of System, Pause, EndScene, Replay Save, and Background files, as we will need to understand these before releasing a plural to the public.
So without further ado, Plurals!
Way back when in Lesson 6, we made our first single script. It had a header with #TouhouDanmakufu and the like. Let's paste that here, with a minor change - we will switch 'Single' with 'Plural' in the header.
#TouhouDanmakufu[Plural]
#ScriptVersion[3]
#Title[]
#Text[]
@Event{
}
@Initialize{
}
@MainLoop{
}
This should look very familiar. Paste this into a text file. Name it something. We're going to do some work!
Let's first place a yield;
in @MainLoop, as we will be using tasks. Now, let's create an empty task called TPlural. This will handle the creation of our boss scene.
We will call this TPlural in @Initialize. Now let's fill it in.
Firstly, we will declare a variable dir to be equal to GetCurrentScriptDirectory()
. This is because we may be calling multiple singles, and the long GetCurrentScriptDirectory()
function name is both tedious to write and very long.
Now let's declare a variable obj. We will assign ObjEnemyBossScene_Create()
to it. This function creates a boss scene object and returns the ID of given object.
As of now, our code should look like this:
#TouhouDanmakufu[Plural]
#ScriptVersion[3]
#Title["My First Boss Script"]
#Text[]
@Event{
}
@Initialize{
TPlural;
}
@MainLoop{
yield;
}
task TPlural{
let dir = GetCurrentScriptDirectory();
let obj = ObjEnemyBossScene_Create();
}
Now, we will begin adding singles to link on. For you, you will most likely have a bunch of singles you want to link. As long as you like at least one, the plural has a purpose.
Let's add the single script 'Nonspell1.txt' to the boss scene. We will use the function ObjEnemyBossScene_Add()
. It takes three parameters: the boss scene object to add to, the lifebar segment (starting from 0) to attach the attack to, and the path to the single script.
ObjEnemyBossScene_Add(obj, 0, dir ~ "./Nonspell1.txt");
Please note that you should always begin from the 0th lifebar and work your way up from there. Otherwise Danmakufu will complain.
Now that we have added Nonspell1.txt to the first lifebar segment, we will load and register the boss scene. To load the boss scene into memory, we will use ObjEnemyBossScene_LoadInThread(obj)
, and to register it, we will use ObjEnemyBossScene_Regist(obj)
.
Now, what exactly do these do? Well, loading it basically loads the plural into memory so that it can be accessed. And as for registering, it does a number of things which we will get into shortly.
First and foremost, registering a boss scene object will run it immediately. You will need the following after registering, within the TPlural task:
while(!Obj_IsDeleted(obj)){
yield;
}
This will wait for the Boss Scene to delete itself (it will delete once it has gone through every single that has been added on). After this, use CloseScript(GetOwnScriptID())
to close the plural script.
So here's our completed sample plural script.
#TouhouDanmakufu[Plural]
#ScriptVersion[3]
#Title["My First Boss Script"]
#Text[]
@Event{
}
@Initialize{
TPlural;
}
@MainLoop{
yield;
}
task TPlural{
let dir = GetCurrentScriptDirectory();
let obj = ObjEnemyBossScene_Create();
ObjEnemyBossScene_Add(obj, 0, dir ~ "./Nonspell1.txt");
ObjEnemyBossScene_Add(obj, 0, dir ~ "./Spell1.txt");
ObjEnemyBossScene_Add(obj, 1, dir ~ "./Nonspell2.txt");
ObjEnemyBossScene_Add(obj, 1, dir ~ "./Spell2.txt");
ObjEnemyBossScene_Add(obj, 2, dir ~ "./Nonspell3.txt");
ObjEnemyBossScene_Add(obj, 2, dir ~ "./Spell3.txt");
ObjEnemyBossScene_Add(obj, 3, dir ~ "./Spell4.txt");
ObjEnemyBossScene_LoadInThread(obj);
ObjEnemyBossScene_Regist(obj);
while(!Obj_IsDeleted(obj)){
yield;
}
CloseScript(GetOwnScriptID());
}
It's a boss with three nonspells and four spells, assuming that all the singles are in the same directory as the plural. But... there are some minor things to keep in mind. When you register a boss scene, it will check through all the single scripts and you will be notified of all errors.
Anyways, we have our first plural script! Try it out, see how it works, etc. A few things to note are that the headers of all single scripts are completely ignored. This means that if you have a bgm or specific player assigned in a single script and you run the plural script that has added that single, the plural script's header will be used. Always. This goes for all danmakufu scripts, whether they be stages, plurals, etc.
Well, that was a short lesson. Let's bring it to a close.
Use the following code for questions 1-3
#TouhouDanmakufu[Plural]
#ScriptVersion[3]
#Title["My First Boss Script"]
#Text[]
@Event{
}
@Initialize{
TPlural;
}
@MainLoop{
//Question 1
}
task TPlural{
let dir = GetCurrentScriptDirectory();
//Question 2
ObjEnemyBossScene_Add(obj, 0, dir ~ "./Nonspell1.txt");
ObjEnemyBossScene_LoadInThread(obj);
//Question 3
while(!Obj_IsDeleted(obj)){
yield;
}
CloseScript(GetOwnScriptID());
}
1) What code should be added to line 14 to allow the task to work properly (assume Lines 19 and 22 are filled correctly)?
2) What code should be added to line 19 to correctly instantiate the Enemy Boss Scene Object?
3) What code should be added to line 22 to correctly run the Boss Scene?
ObjEnemyBossScene_Add()
is used to add single scripts to a plural scriptObjEnemyBossScene_LoadInThread(obj)
is used to load a boss scene and ObjEnemyBossScene_Regist(obj)
is used to register and begin executionN/A