import "std.zh"
import "ghost.zh"
import "string.zh"
//Global Variables
int TimesContinued;//Tracks how many times you've continued.
global script Active{
void run(){
//Increases variable when you F6.
//Used to prevent cheating past spinners.
TimesContinued++;
}
}
global script OnContinue{
void run(){
//Increases variable when you load the game after saving.
//Used to prevent cheating past spinners.
TimesContinued++;
}
}
global script OnExit{
void run(){
TimesContinued++;
}
}
//Test if one location is between two others.
//D0- Location to test
//D1- Lower bound
//D2- Higher bound
bool Between(int loc,int greaterthan, int lessthan){
if(loc>=greaterthan && loc<=lessthan)return true;
return false;
}
//Floor Spinner
const int FLOOR_SPINNER_SFX = 78;//Sound made by spinner.
const int FLOOR_SPINNER_REST_COMBO = 29620;//Counterclockwise spinner at rest.
//Clockwise is one more.
const int FLOOR_SPINNER_BASE_COMBO = 29622;//Base of spinner with counterclockwise lights.
//Clockwise is one more.
const int SPINNER_CSET = 8;//Cset used by spinner.
//D0- True if clockwise rotation. False if not.
//D1- Screen->D register to store having already rotated. Register zero is reserved.
ffc script Floor_Spinner{
void run(bool Clockwise,int perm){
int SpinDestination;//Determines destination.
float angle;//Handles rotation.
//Controls spin phase.
bool Spinning = false;
bool HasSpun;//Tells the script if this spinner has already spun.
bool TimeStored = false;//Tells script if Screen->D zero has already been altered.
//If nothing is stored in Screen->D zero.
if(!TimeStored && Screen->D[0]==0){
//Alter it to match times you've continued.
Screen->D[0]= TimesContinued;
//Make it never do this again.
TimeStored= true;
}
//Screen->D zero has a value in it.
else{
//Screen->D zero is not equal to the global variable.
if(Screen->D[0]!=TimesContinued){
//Change it to be equal to the global variable.
Screen->D[0]= TimesContinued;
//Reset the spinner.
Screen->D[perm]= 0;
}
}
//Based on current value of the register, determine if this spinner has already spun.
if(Screen->D[perm]==0)HasSpun = false;
else HasSpun= true;
//Change appearance accordingly.
if((Clockwise && !HasSpun)||(!Clockwise && HasSpun))
this->Data = FLOOR_SPINNER_REST_COMBO+1;
else if((Clockwise && HasSpun)||(!Clockwise && !HasSpun))
this->Data = FLOOR_SPINNER_REST_COMBO;
while(true){
//First time visiting with a clockwise or already visited CCW.
if((Clockwise && !HasSpun)||(!Clockwise && HasSpun)){
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
///Approach from top.
if(Between(Link->X,this->X+2,this->X+(this->TileWidth*16)-2) &&
Between(Link->Y+16,this->Y+2,this->Y+8) &&
Between(Link->X+16,this->X+2,this->X+(this->TileWidth*16)-2)){
//Go to right.
SpinDestination = 1;
//Start spin phase.
Spinning = true;
}
//Approach from bottom.
else if(Between(Link->X,this->X+2,this->X+(this->TileWidth*16)-2) &&
Between(Link->Y,this->Y+24,this->Y+(this->TileHeight*16)-2) &&
Between(Link->X+16,this->X+2,this->X+(this->TileWidth*16)-2)){
//Go to left.
SpinDestination = 3;
Spinning = true;
}
//Approach from left.
else if(Between(Link->Y,this->Y+2,this->Y+(this->TileHeight*16)-2) &&
Between(Link->Y+16,this->Y+2,this->Y+(this->TileHeight*16)-2) &&
Between(Link->X+16,this->X+2,this->X+(this->TileWidth*16)-2)){
//Go to top.
SpinDestination = 0;
Spinning = true;
}
//Approach from right.
else if(Between(Link->Y,this->Y+2,this->Y+(this->TileHeight*16)-2) &&
Between(Link->Y+16,this->Y+2,this->Y+(this->TileHeight*16)-2) &&
Between(Link->X,this->X+24,this->X+(this->TileWidth*16)-2)){
//Go to bottom.
SpinDestination = 2;
Spinning = true;
}
}
//Return to clockwise or first time visited CCW.
else if((Clockwise && HasSpun)||(!Clockwise && !HasSpun)){
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
//Approach from top.
if(Between(Link->X,this->X+2,this->X+(this->TileWidth*16)-2) &&
Between(Link->Y+16,this->Y+2,this->Y+8) &&
Between(Link->X+16,this->X+2,this->X+(this->TileWidth*16)-2)){
//Go to left.
SpinDestination = 2;
Spinning = true;
}
//Approach from bottom.
else if(Between(Link->X,this->X+2,this->X+(this->TileWidth*16)-2) &&
Between(Link->Y,this->Y+24,this->Y+(this->TileHeight*16)-2) &&
Between(Link->X+16,this->X+2,this->X+(this->TileWidth*16)-2)){
//Go to right.
SpinDestination = 1;
Spinning = true;
}
//Approach from left.
else if(Between(Link->Y,this->Y+2,this->Y+(this->TileHeight*16)-2) &&
Between(Link->Y+16,this->Y+2,this->Y+(this->TileHeight*16)-2) &&
Between(Link->X+16,this->X+2,this->X+(this->TileWidth*16)-2)){
//Go to bottom
SpinDestination = 3;
Spinning = true;
}
//Approach from right.
else if(Between(Link->Y,this->Y+2,this->Y+(this->TileHeight*16)-2) &&
Between(Link->Y+16,this->Y+2,this->Y+(this->TileHeight*16)-2) &&
Between(Link->X,this->X+24,this->X+(this->TileWidth*16)-2)){
//Go to top.
SpinDestination = 0;
Spinning = true;
}
}
//Time to spin now.
if(Spinning){
//First time on a clockwise spinner or return to a counterclockwise spinner.
if((Clockwise && !HasSpun)||(!Clockwise && HasSpun)){
//From left to top.
if(SpinDestination ==0){
//Set starting position.
angle = 180;
while(angle<270){
//Make the ffc invisible.
//You don't have to use the ghost.zh invisible combo, I just find it easier.
this->Data= GH_INVISIBLE_COMBO;
//Keep Link immobile.
NoAction();
//Handles rotation.
angle= (angle+2)%360;
//Draw combos corresponding to the spinner's appearance and rotate them.
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
Screen->DrawCombo(2, this->X, this->Y, FLOOR_SPINNER_REST_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, this->X, this->Y, angle, 1, -1, true, 128);
//Play a sound.
Game->PlaySound(FLOOR_SPINNER_SFX);
//Rotate Link.
Link->X = (this->X+16)+ 20 * Cos(angle);
Link->Y = (this->Y+16)+ 20 * Sin(angle);
Waitframe();
}
//If this spinner hadn't spun before...
if(!HasSpun){
//Set Screen->D register.
Screen->D[perm]= 1;
//Change variable.
HasSpun = true;
}
//This spinner has spun before.
else if(HasSpun){
Screen->D[perm]= 0;
HasSpun = false;
}
//Reset ffc to visible.
this->Data = FLOOR_SPINNER_REST_COMBO;
//Handles leaving spinner.
SpinnerExit(DIR_UP,this,Clockwise,HasSpun);
Spinning = false;
}
//From top to right.
else if(SpinDestination ==1){
angle = 270;
while(angle!=0){
this->Data= GH_INVISIBLE_COMBO;
NoAction();
angle= (angle+2)%360;
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
Screen->DrawCombo(2, this->X, this->Y, FLOOR_SPINNER_REST_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, this->X, this->Y, angle, 1, -1, true, 128);
Game->PlaySound(FLOOR_SPINNER_SFX);
Link->X = (this->X+16)+ 20 * Cos(angle);
Link->Y = (this->Y+16)+ 20 * Sin(angle);
Waitframe();
}
if(!HasSpun){
Screen->D[perm]= 1;
HasSpun = true;
}
else if(HasSpun){
Screen->D[perm]= 0;
HasSpun = false;
}
this->Data = FLOOR_SPINNER_REST_COMBO;
SpinnerExit(DIR_RIGHT,this,Clockwise,HasSpun);
Spinning = false;
}
//From right to bottom.
else if(SpinDestination ==2){
angle = 0;
while(angle<90){
this->Data= GH_INVISIBLE_COMBO;
NoAction();
angle= (angle+2)%360;
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
Screen->DrawCombo(2, this->X, this->Y, FLOOR_SPINNER_REST_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, this->X, this->Y, angle, 1, -1, true, 128);
Game->PlaySound(FLOOR_SPINNER_SFX);
Link->X = (this->X+16)+ 20 * Cos(angle);
Link->Y = (this->Y+16)+ 20 * Sin(angle);
Waitframe();
}
if(!HasSpun){
Screen->D[perm]= 1;
HasSpun = true;
}
else if(HasSpun){
Screen->D[perm]= 0;
HasSpun = false;
}
this->Data = FLOOR_SPINNER_REST_COMBO;
SpinnerExit(DIR_DOWN,this,Clockwise,HasSpun);
Spinning = false;
}
//From bottom to left.
else if(SpinDestination ==3){
angle = 90;
while(angle<180){
this->Data= GH_INVISIBLE_COMBO;
NoAction();
angle= (angle+2)%360;
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
Screen->DrawCombo(2, this->X, this->Y, FLOOR_SPINNER_REST_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, this->X, this->Y, angle, 1, -1, true, 128);
Game->PlaySound(FLOOR_SPINNER_SFX);
Link->X = (this->X+16)+ 20 * Cos(angle);
Link->Y = (this->Y+16)+ 20 * Sin(angle);
Waitframe();
}
if(!HasSpun){
Screen->D[perm]= 1;
HasSpun = true;
}
else if(HasSpun){
Screen->D[perm]= 0;
HasSpun = false;
}
this->Data = FLOOR_SPINNER_REST_COMBO;
SpinnerExit(DIR_LEFT,this,Clockwise,HasSpun);
Spinning = false;
}
}
//Return to a clockwise spinner that has spun, or first visit to a counterclockwise spinner.
else if((Clockwise && HasSpun)||(!Clockwise && !HasSpun)){
//From right to top.
if(SpinDestination ==0){
angle = 360;
while(angle>270){
this->Data= GH_INVISIBLE_COMBO;
NoAction();
angle= (angle-2)%360;
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
Screen->DrawCombo(2, this->X, this->Y, FLOOR_SPINNER_REST_COMBO, 3, 3, SPINNER_CSET, -1,-1, this->X, this->Y, angle, 1, -1, true, 128);
Game->PlaySound(FLOOR_SPINNER_SFX);
Link->X = (this->X+16)+ 20 * Cos(angle);
Link->Y = (this->Y+16)+ 20 * Sin(angle);
Waitframe();
}
if(!HasSpun){
Screen->D[perm]= 1;
HasSpun = true;
}
else if(HasSpun){
Screen->D[perm]= 0;
HasSpun = false;
}
this->Data = FLOOR_SPINNER_REST_COMBO+1;
SpinnerExit(DIR_UP,this,Clockwise,HasSpun);
Spinning = false;
}
//From bottom to right.
else if(SpinDestination ==1){
angle = 90;
while(angle>0){
this->Data= GH_INVISIBLE_COMBO;
NoAction();
angle= (angle-2)%360;
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
Screen->DrawCombo(2, this->X, this->Y, FLOOR_SPINNER_REST_COMBO, 3, 3, SPINNER_CSET, -1,-1, this->X, this->Y, angle, 1, -1, true, 128);
Game->PlaySound(FLOOR_SPINNER_SFX);
Link->X = (this->X+16)+ 20 * Cos(angle);
Link->Y = (this->Y+16)+ 20 * Sin(angle);
Waitframe();
}
if(!HasSpun){
Screen->D[perm]= 1;
HasSpun = true;
}
else if(HasSpun){
Screen->D[perm]= 0;
HasSpun = false;
}
this->Data = FLOOR_SPINNER_REST_COMBO+1;
SpinnerExit(DIR_RIGHT,this,Clockwise,HasSpun);
Spinning = false;
}
//From top to left.
else if(SpinDestination ==2){
angle = 270;
while(angle>180){
this->Data= GH_INVISIBLE_COMBO;
NoAction();
angle= (angle-2)%360;
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
Screen->DrawCombo(2, this->X, this->Y, FLOOR_SPINNER_REST_COMBO, 3, 3, SPINNER_CSET, -1,-1, this->X, this->Y, angle, 1, -1, true, 128);
Game->PlaySound(FLOOR_SPINNER_SFX);
Link->X = (this->X+16)+ 20 * Cos(angle);
Link->Y = (this->Y+16)+ 20 * Sin(angle);
Waitframe();
}
if(!HasSpun){
Screen->D[perm]= 1;
HasSpun = true;
}
else if(HasSpun){
Screen->D[perm]= 0;
HasSpun = false;
}
this->Data = FLOOR_SPINNER_REST_COMBO+1;
SpinnerExit(DIR_LEFT,this,Clockwise,HasSpun);
Spinning = false;
}
//From left to bottom
else if(SpinDestination ==3){
angle = 180;
while(angle>90){
this->Data= GH_INVISIBLE_COMBO;
NoAction();
angle= (angle-2)%360;
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
Screen->DrawCombo(2, this->X, this->Y, FLOOR_SPINNER_REST_COMBO, 3, 3, SPINNER_CSET, -1,-1, this->X, this->Y, angle, 1, -1, true, 128);
Game->PlaySound(FLOOR_SPINNER_SFX);
Link->X = (this->X+16)+ 20 * Cos(angle);
Link->Y = (this->Y+16)+ 20 * Sin(angle);
Waitframe();
}
if(!HasSpun){
Screen->D[perm]= 1;
HasSpun = true;
}
else if(HasSpun){
Screen->D[perm]= 0;
HasSpun = false;
}
this->Data = FLOOR_SPINNER_REST_COMBO+1;
SpinnerExit(DIR_DOWN,this,Clockwise,HasSpun);
Spinning = false;
}
}
}
Waitframe();
if((Clockwise && !HasSpun)||(!Clockwise && HasSpun))
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
else if((Clockwise && HasSpun)||(!Clockwise && !HasSpun))
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
}
}
//Handles exiting spinner.
//Based on direction, makes Link walk that way for 10 frames and be unable to do anything else.
void SpinnerExit (int dir,ffc this, bool Clockwise, bool HasSpun){
if (dir == DIR_UP){
for (int i = 0; i < 10; i++){
NoAction();
Link->InputUp = true;
Waitframe();
if((Clockwise && !HasSpun)||(!Clockwise && HasSpun))
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
else if((Clockwise && HasSpun)||(!Clockwise && !HasSpun))
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
}
}
else if (dir == DIR_DOWN){
for (int i = 0; i < 10; i++){
NoAction();
Link->InputDown = true;
Waitframe();
if((Clockwise && !HasSpun)||(!Clockwise && HasSpun))
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
else if((Clockwise && HasSpun)||(!Clockwise && !HasSpun))
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
}
}
else if (dir == DIR_LEFT){
for (int i = 0; i < 10; i++){
NoAction();
Link->InputLeft = true;
Waitframe();
if((Clockwise && !HasSpun)||(!Clockwise && HasSpun))
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
else if((Clockwise && HasSpun)||(!Clockwise && !HasSpun))
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
}
}
else if (dir == DIR_RIGHT){
for (int i = 0; i < 10; i++){
NoAction();
Link->InputRight = true;
Waitframe();
if((Clockwise && !HasSpun)||(!Clockwise && HasSpun))
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
else if((Clockwise && HasSpun)||(!Clockwise && !HasSpun))
Screen->DrawCombo(1, this->X, this->Y, FLOOR_SPINNER_BASE_COMBO+1, 3, 3, SPINNER_CSET, -1,-1, 0, 0, 0, 1, -1, true, 128);
}
}
}
}