const int CUTSCENETRIGGER_SHOW_HITBOXES = 0; //For debugging problems with the script's hitboxes, set this to 1.
const int C_CUTSCENETRIGGER_HITBOX = 0x01; //Color for the debug hitboxes
const int C_CUTSCENETRIGGER_HITBOX_INACTIVE = 0x81; //Color for disabled debug hitboxes
const int D_CUTSCENETRIGGER = 0; //Screen->D used for cutscene triggers
//D0: The DMap to warp to for the cutscene
//D1: The screen to warp to IN DECIMAL. Screens in ZQuest are numbered in hex but FFCs only take arguments
// in decimal, so you'll have to convert.
//D2: Width of the trigger hitbox
//D3: Height of the trigger hitbox
//D4: Set this to a number 1-17 to make the cutscene only play once. By giving FFCs different D4 arguments,
// you can have multiple triggers for different permanent cutscenes on a screen.
//D5: If you want the trigger to check for a flag under Link, set this to the number of the flag.
// If you want it check for a flag just being on the screen, set to the flag + 1000
// If you want it to check for an item, set this to a negative Item ID.
// If you want it to check for not having an item, set to the negative Item ID - 1000
//D6: The X position to try to walk Link to. 0 for no target point.
//D7: The Y position to try to walk Link to. 0 for no target point.
//A. Delay: Set to >0 if you can activate this trigger immediately even when entering the screen on top of it
ffc script CutsceneTrigger{
void run(int newDMap, int newScreen, int w, int h, int oneUse, int checkItemorFlag, int targetX, int targetY){
int dbit;
if(oneUse>0){
dbit = 1<<(oneUse-1);
}
if(this->Delay==0){
//If Link starts standing on the cutscene hitbox, wait for him to step off
while(Link->X+8 >= this->X && Link->X+8 <= this->X+w-1 && Link->Y+12 >= this->Y && Link->Y+12 <= this->Y+h-1 && CanTriggerCutscene(checkItemorFlag)){
if(CUTSCENETRIGGER_SHOW_HITBOXES){
Screen->Rectangle(6, this->X-1, this->Y-1, this->X+w-1+1, this->Y+h-1+1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, false, 64);
Screen->Rectangle(6, this->X, this->Y, this->X+w-1, this->Y+h-1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, false, 128);
Screen->Rectangle(6, this->X+1, this->Y+1, this->X+w-1-1, this->Y+h-1-1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, true, 64);
}
Waitframe();
}
}
//Check if the cutscene has already been triggered
if(oneUse&&Screen->D[D_CUTSCENETRIGGER]&dbit){
Quit();
}
while(true){
int c = C_CUTSCENETRIGGER_HITBOX;
if(!CanTriggerCutscene(checkItemorFlag))
c = C_CUTSCENETRIGGER_HITBOX_INACTIVE;
if(CUTSCENETRIGGER_SHOW_HITBOXES){
Screen->Rectangle(6, this->X-1, this->Y-1, this->X+w-1+1, this->Y+h-1+1, c, 1, 0, 0, 0, false, 64);
Screen->Rectangle(6, this->X, this->Y, this->X+w-1, this->Y+h-1, c, 1, 0, 0, 0, false, 128);
Screen->Rectangle(6, this->X+1, this->Y+1, this->X+w-1-1, this->Y+h-1-1, c, 1, 0, 0, 0, false, 64);
}
//Find if Link has collided with the trigger hitbox
if(Link->X+8 >= this->X && Link->X+8 <= this->X+w-1 && Link->Y+12 >= this->Y && Link->Y+12 <= this->Y+h-1 ){
if(CUTSCENETRIGGER_SHOW_HITBOXES){
Screen->Rectangle(6, this->X+2, this->Y+2, this->X+w-1-2, this->Y+h-1-2, c, 1, 0, 0, 0, true, 64);
}
//If Link meets one the requirements to trigger the cutscene, break out of the loop
if(CanTriggerCutscene(checkItemorFlag))
break;
}
Waitframe();
}
if(targetX>0||targetY>0){
//Move Link either until he's in position or 4 seconds have passed
for(int i=0; i<=240&&(Link->X!=targetX||Link->Y!=targetY); i++){
//Prevent moving around while moving Link into position
Link->InputStart = false; Link->PressStart = false;
Link->InputMap = false; Link->PressMap = false;
NoAction();
//Apply inputs that should be active
if(Abs(Link->X-targetX)<=2){
Link->X = targetX;
}
else{
if(Link->X<targetX)
Link->InputRight = true;
else if(Link->X>targetX)
Link->InputLeft = true;
}
if(Abs(Link->Y-targetY)<=2){
Link->Y = targetY;
}
else{
if(Link->Y<targetY)
Link->InputDown = true;
else if(Link->Y>targetY)
Link->InputUp = true;
}
Waitframe();
}
}
if(oneUse){
Screen->D[D_CUTSCENETRIGGER] |= dbit;
}
Link->PitWarp(newDMap, newScreen);
}
bool CanTriggerCutscene(int checkItemorFlag){
//If Link meets one the requirements to trigger the cutscene, return true
if(checkItemorFlag==0){
return true;
}
//If the checkItemorFlag argument is negative, check for an item
else if(checkItemorFlag<0){
if(checkItemorFlag<-1000){
checkItemorFlag += 1000;
if(!Link->Item[Abs(checkItemorFlag)])
return true;
}
else{
if(Link->Item[Abs(checkItemorFlag)])
return true;
}
}
//Else check for a screen flag
else{
//If >1000, the trigger becomes active even if Link isn't standing on the flag
if(checkItemorFlag>1000){
checkItemorFlag -= 1000;
for(int i=0; i<176; ++i){
if(ComboFI(i, checkItemorFlag))
return true;
}
}
//Otherwise check if Link is standing on the flag
else{
if(ComboFI(Link->X+8, Link->Y+12, checkItemorFlag))
return true;
}
}
return false;
}
}
//It's dangerous to make unscripted cutscenes that give Link control while they're playing, take this!
ffc script InputDisable{
void run(){
while(true){
Link->InputStart = false; Link->PressStart = false;
Link->InputMap = false; Link->PressMap = false;
NoAction();
Waitframe();
}
}
}
//For playing sounds in cutscenes
//D0: SFX to play
//D1: Delay in frames
ffc script PlaySoundWithDelay{
void run(int sfx, int delay){
Waitframes(delay);
Game->PlaySound(sfx);
}
}
//For playing messages in cutscenes
//D0: Message string to play
//D1: Delay in frames
ffc script PlayMessageWithDelay{
void run(int msg, int delay){
Waitframes(delay);
Screen->Message(msg);
}
}
//Okay I probably don't really need all these little scripts, but in making non-scripted cutscenes I got a little nitpicky :P
//D0: Direction to set Link to
ffc script SetLinkDirection{
void run(int dir){
Link->Dir = dir;
}
}