const int CMB_MINECART = 7688; //Combo of the minecart, first of 16
//1-4: Minecart, stationary, 4-way
//5-8: Minecart, moving, 4-way
//9-12: Minecart, front layer, 4-way
//13-16: Link riding in minecart, 4-way
const int CS_MINECART = 2;
const int CMB_MINECART_TRACK = 7680; //First of a set of 7 minecart track combos.
//Only these combos when placed on layer 0 will actually function as minecart tracks
//1: Up/Down
//2: Left/Right
//3: Right/Down
//4: Left/Down
//5: Right/Up
//6: Left/Up
//7: Exit pad
const int SFX_MINECART = 65; //Looping sound of the minecart on the tracks
const int MINECART_SFX_FREQ = 30; //How often the sound loops
const int MINECART_LINKYOFFSET = -10; //Offset Link's sprite is drawn at compared to the minecart
const int DAMAGE_MINECART_COLLISION = 8; //How much damage the minecart does when it hits enemies
const int LW_MINECART_DAMAGE = 2; //Weapon type the minecart's hitbox uses. LW_BEAM by default
int GBCart[80];
const int GBC_DIR = 65;
const int GBC_CURID = 66;
const int GBC_FIRSTLOAD = 67;
const int GBC_ACTIVEFFC = 68;
void Minecart_Init(){
Link->DrawYOffset = 0;
Link->CollDetection = true;
GBCart[GBC_DIR] = -1;
if(GBCart[GBC_FIRSTLOAD]==0){
for(int i=0; i<64; i++){
GBCart[i] = -1;
}
GBCart[GBC_FIRSTLOAD] = 1;
}
}
void DisableButtonItem(int itm){
if(GetEquipmentA()==itm){
Link->PressA = false;
Link->InputA = false;
}
else if(GetEquipmentB()==itm){
Link->PressB = false;
Link->InputB = false;
}
}
void Minecart_DisableItems(){
DisableButtonItem(I_ROCSFEATHER);
}
void Minecart_Update1(){
if(GBCart[GBC_DIR]>-1){
Minecart_DisableItems();
}
}
void Minecart_Update2(){
if(GBCart[GBC_DIR]>-1){
int scr[] = "GBMinecart_FFC";
Link->DrawYOffset = MINECART_LINKYOFFSET;
Link->CollDetection = false;
if(Link->Action==LA_SCROLLING){
GBCart[GBC_ACTIVEFFC] = -1;
Minecart_Draw(ScrollingLinkX(), ScrollingLinkY(), GBCart[GBC_DIR], true);
}
else if(GBCart[GBC_ACTIVEFFC]>0){
ffc f = Screen->LoadFFC(GBCart[GBC_ACTIVEFFC]);
if(f->Script==Game->GetFFCScript(scr)){
Link->X = f->X;
Link->Y = f->Y;
}
}
if(Minecart_CountFFCs(Game->GetFFCScript(scr), GBCart[GBC_CURID])==0){
ffc f = Screen->LoadFFC(GBCart[GBC_ACTIVEFFC]);
if(f->Script!=Game->GetFFCScript(scr)||f->InitD[1]!=GBCart[GBC_CURID]){
if(Link->X>=0&&Link->X<=240&&Link->Y>=0&&Link->Y<=160){
int args[8];
args[0] = GBCart[GBC_DIR];
args[1] = GBCart[GBC_CURID];
args[2] = 0;
args[3] = 1;
f = Screen->LoadFFC(RunFFCScript(Game->GetFFCScript(scr), args));
f->CSet = CS_MINECART;
GBCart[GBC_ACTIVEFFC] = FFCNum(f);
f->Flags[FFCF_PRELOAD] = true;
f->X = Link->X;
f->Y = Link->Y;
}
}
}
}
}
int Minecart_CountFFCs(int scrpt, int id){
int count;
for(int i=1; i<=32; i++){
ffc f = Screen->LoadFFC(i);
if(f->Script==scrpt&&f->InitD[1]==id&&f->InitD[3]==1)
count++;
}
return count;
}
void Minecart_Draw(int x, int y, int dir, bool linkInside){
int layer = 2;
if(ScreenFlag(1, 4))
layer = 1;
dir = Clamp(dir, 0, 3);
if(linkInside){
Screen->FastCombo(layer, x, y, CMB_MINECART+4+dir, CS_MINECART, 128);
if(Link->Action==LA_WALKING||Link->Action==LA_NONE||Link->Action==LA_SCROLLING){
Screen->FastCombo(layer, x, y+MINECART_LINKYOFFSET, CMB_MINECART+12+Link->Dir, 6, 128);
Link->Invisible = true;
}
else
Link->Invisible = false;
Screen->FastCombo(4, x, y, CMB_MINECART+8+dir, CS_MINECART, 128);
}
else{
Screen->FastCombo(layer, x, y, CMB_MINECART+dir, CS_MINECART, 128);
}
}
global script GBMinecart_Slot2{
void run(){
ScrollingDraws_Init();
Minecart_Init();
while(true){
ScrollingDraws_Update();
Minecart_Update1();
Waitdraw();
Minecart_Update2();
Waitframe();
}
}
}
ffc script GBMinecart_FFC{
void run(int startDir, int ID, int start, int spawned){
int ffcNum = FFCNum(this);
int tempID;
if(ID>0)
tempID = Clamp(ID-1, 0, 63);
if(GBCart[GBC_DIR]<=-1||GBCart[GBC_CURID]!=ID)
this->Data = CMB_MINECART+startDir;
else if(spawned==0){
if(Link->X<=0||Link->X>=240||Link->Y<=0||Link->Y>=160){
this->Data = 0;
Quit();
}
else{
GBCart[GBC_DIR] = -1;
Waitframe();
}
}
else{
if(GBCart[GBC_ACTIVEFFC]==-1)
GBCart[GBC_ACTIVEFFC] = ffcNum;
}
if(spawned==0&&GBCart[GBC_DIR]==-1&&ID>0){
if(GBCart[tempID]==-1){
if(start){
GBCart[tempID] = Game->GetCurScreen();
}
else{
this->Data = 0;
Quit();
}
}
else if(GBCart[tempID]!=Game->GetCurScreen()&&GBCart[GBC_FIRSTLOAD]==1){
this->Data = 0;
Quit();
}
}
int lastDir = startDir;
int sfxCounter;
lweapon hitbox;
while(true){
while(GBCart[GBC_DIR]==-1||GBCart[GBC_CURID]!=ID){
this->Data = CMB_MINECART+startDir;
if(Link->Y<this->Y)
this->Flags[FFCF_OVERLAY] = true;
else
this->Flags[FFCF_OVERLAY] = false;
if(GBMinecart_Collision(this)){
while(Link->Z>0){
WaitNoAction();
}
this->Flags[FFCF_OVERLAY] = false;
Link->Dir = AngleDir4(Angle(Link->X, Link->Y, this->X, this->Y));
Link->Jump = 2;
Game->PlaySound(SFX_JUMP);
int angle = Angle(Link->X, Link->Y, this->X, this->Y+MINECART_LINKYOFFSET);
int dist = Distance(Link->X, Link->Y, this->X, this->Y+MINECART_LINKYOFFSET);
int linkX = Link->X;
int linkY = Link->Y;
for(int i=0; i<26; i++){
linkX += VectorX(dist/26, angle);
linkY += VectorY(dist/26, angle);
Link->X = linkX;
Link->Y = linkY;
WaitNoAction();
}
Link->DrawYOffset = MINECART_LINKYOFFSET;
Link->CollDetection = false;
GBCart[GBC_DIR] = startDir;
GBCart[GBC_CURID] = ID;
GBCart[GBC_ACTIVEFFC] = FFCNum(this);
sfxCounter = 0;
}
Waitframe();
}
while(GBCart[GBC_DIR]!=-1&&GBCart[GBC_CURID]==ID){
int cp = ComboAt(this->X+8, this->Y+8);
lastDir = GBCart[GBC_DIR];
GBCart[GBC_DIR] = GBMinecart_NextDirection(cp, GBCart[GBC_DIR]);
for(int i=0; i<8&&GBCart[GBC_DIR]>-1; i++){
if(sfxCounter==0)
Game->PlaySound(SFX_MINECART);
sfxCounter++;
if(sfxCounter>MINECART_SFX_FREQ)
sfxCounter = 0;
if(GBCart[GBC_DIR]==DIR_UP)
this->Y -= 2;
else if(GBCart[GBC_DIR]==DIR_DOWN)
this->Y += 2;
else if(GBCart[GBC_DIR]==DIR_LEFT)
this->X -= 2;
else if(GBCart[GBC_DIR]==DIR_RIGHT)
this->X += 2;
this->Data = FFCS_INVISIBLE_COMBO;
hitbox = GBMinecart_UpdateHitbox(hitbox, this->X, this->Y, true);
Minecart_Draw(this->X, this->Y, GBCart[GBC_DIR], true);
Link->X = this->X;
Link->Y = this->Y;
Waitframe();
}
this->X = GridX(this->X+8);
this->Y = GridY(this->Y+8);
if(GBCart[GBC_DIR]<=-1){
if(GBCart[GBC_DIR]<-1)
lastDir = Abs(GBCart[GBC_DIR])-2;
GBCart[GBC_DIR] = -1;
this->Data = CMB_MINECART+lastDir;
Link->DrawYOffset = 0;
Link->Invisible = false;
Link->CollDetection = true;
cp = GBMinecart_ComboInFront(cp, lastDir);
Link->Dir = AngleDir4(Angle(Link->X, Link->Y, ComboX(cp), ComboY(cp)));
Link->Y += MINECART_LINKYOFFSET;
Link->Jump = 2;
Game->PlaySound(SFX_JUMP);
int angle = Angle(Link->X, Link->Y, ComboX(cp), ComboY(cp));
int dist = Distance(Link->X, Link->Y, ComboX(cp), ComboY(cp));
int linkX = Link->X;
int linkY = Link->Y;
for(int i=0; i<26; i++){
linkX += VectorX(dist/26, angle);
linkY += VectorY(dist/26, angle);
Link->X = linkX;
Link->Y = linkY;
hitbox = GBMinecart_UpdateHitbox(hitbox, this->X, this->Y, false);
WaitNoAction();
}
startDir = OppositeDir(lastDir);
if(GBCart[GBC_CURID]>0){
tempID = Clamp(GBCart[GBC_CURID]-1, 0, 63);
GBCart[tempID] = Game->GetCurScreen();
}
//MooshPit_ResetEntry();
}
}
}
}
int GBMinecart_NextDirection(int cp, int dir){
int up[6] = {1, 0, 0, 0, 1, 1};
int down[6] = {1, 0, 1, 1, 0, 0};
int left[6] = {0, 1, 0, 1, 0, 1};
int right[6] = {0, 1, 1, 0, 1, 0};
int directions[4] = {up, down, left, right};
int c;
//Combo under
c = Screen->ComboD[cp];
if(c>=CMB_MINECART_TRACK&&c<=CMB_MINECART_TRACK+5)
c = Clamp(c-CMB_MINECART_TRACK, 0, 5);
else
c = -1;
int frontDir = -1;
int d = directions[dir];
if(d[c]==1&&frontDir==-1){
frontDir = dir;
}
else{
for(int i=0; i<4; i++){
if(i!=OppositeDir(dir)&&i!=dir){
d = directions[i];
if(d[c]==1){
int c2 = Screen->ComboD[GBMinecart_ComboInFront(cp, i)];
if(c2>=CMB_MINECART_TRACK&&c2<=CMB_MINECART_TRACK+5)
return i;
if(c2==CMB_MINECART_TRACK+6)
return -2-i;
else
return OppositeDir(dir);
}
}
}
}
c = Screen->ComboD[GBMinecart_ComboInFront(cp, dir)];
if(c>=CMB_MINECART_TRACK&&c<=CMB_MINECART_TRACK+6)
c = Clamp(c-CMB_MINECART_TRACK, 0, 6);
else
c = -1;
if(c==-1)
return OppositeDir(dir);
else if(c==6)
return -1;
if(frontDir>-1)
return frontDir;
return dir;
}
int GBMinecart_ComboInFront(int cp, int dir){
if(cp<16&&dir==DIR_UP)
return cp;
else if(cp>159&&dir==DIR_DOWN)
return cp;
else if(cp%16==0&&dir==DIR_LEFT)
return cp;
else if(cp%16==15&&dir==DIR_RIGHT)
return cp;
if(dir==DIR_UP)
cp -= 16;
else if(dir==DIR_DOWN)
cp += 16;
else if(dir==DIR_LEFT)
cp--;
else if(dir==DIR_RIGHT)
cp++;
return cp;
}
bool GBMinecart_Collision(ffc this){
if(Abs(Link->X-this->X)<12&&Abs(Link->Y-this->Y)<10)
return true;
return false;
}
lweapon GBMinecart_UpdateHitbox(lweapon hitbox, int x, int y, bool alive){
if(hitbox->isValid()){
hitbox->X = x;
hitbox->Y = y;
hitbox->Dir = GBCart[GBC_DIR];
hitbox->Step = 0;
hitbox->DeadState = -1;
hitbox->DrawYOffset = -1000;
if(!alive){
hitbox->DeadState = 0;
}
}
else{
if(alive){
hitbox = CreateLWeaponAt(LW_MINECART_DAMAGE, x, y);
hitbox->Dir = GBCart[GBC_DIR];
hitbox->Damage = DAMAGE_MINECART_COLLISION;
hitbox->Step = 0;
hitbox->DeadState = -1;
hitbox->DrawYOffset = -1000;
}
}
return hitbox;
}
}
ffc script GBMinecart_Shutter{
void run(){
int thisData = this->Data;
int thisCSet = this->CSet;
this->Data = FFCS_INVISIBLE_COMBO;
int cp = ComboAt(this->X+8, this->Y+8);
int underCombo = Screen->ComboD[cp];
int underCSet = Screen->ComboC[cp];
int LinkX = Link->X;
if(LinkX<=0)
LinkX = 240;
else if(LinkX>=240)
LinkX = 0;
int LinkY = Link->Y;
if(LinkY<=0)
LinkY = 160;
else if(LinkY>=160)
LinkY = 0;
if(!(Abs(this->X-LinkX)<20&&Abs(this->Y-LinkY)<20)){
Screen->ComboD[cp] = thisData;
Screen->ComboC[cp] = thisCSet;
while(GBCart[GBC_DIR]==-1||!(Abs(this->X-Link->X)<20&&Abs(this->Y-Link->Y)<20)){
Waitframe();
}
Game->PlaySound(SFX_SHUTTER);
Screen->ComboD[cp] = underCombo;
Screen->ComboC[cp] = underCSet;
this->Data = thisData+1;
this->CSet = thisCSet;
Waitframes(4);
this->Data = FFCS_INVISIBLE_COMBO;
}
else{
Waitframe();
}
while(true){
while(GBCart[GBC_DIR]>-1&&(Abs(this->X-Link->X)<20&&Abs(this->Y-Link->Y)<20)){
Waitframe();
}
Game->PlaySound(SFX_SHUTTER);
this->Data = thisData+1;
this->CSet = thisCSet;
Waitframes(4);
Screen->ComboD[cp] = thisData;
Screen->ComboC[cp] = thisCSet;
this->Data = FFCS_INVISIBLE_COMBO;
while(GBCart[GBC_DIR]==-1||!(Abs(this->X-Link->X)<20&&Abs(this->Y-Link->Y)<20)){
Waitframe();
}
Game->PlaySound(SFX_SHUTTER);
Screen->ComboD[cp] = underCombo;
Screen->ComboC[cp] = underCSet;
this->Data = thisData+1;
this->CSet = thisCSet;
Waitframes(4);
this->Data = FFCS_INVISIBLE_COMBO;
}
}
}
ffc script GBMinecart_ResetID{
void run(int id1, int id2, int id3, int id4, int id5, int id6, int id7, int id8){
if(Distance(Link->X, Link->Y, this->X, this->Y)<16){
int ids[8];
ids[0] = id1;
ids[1] = id2;
ids[2] = id3;
ids[3] = id4;
ids[4] = id5;
ids[5] = id6;
ids[6] = id7;
ids[7] = id8;
for(int i=0; i<8; i++){
int tempID = Clamp(ids[i]-1, 0, 63);
if(ids[i]>0)
GBCart[tempID] = -1;
}
}
}
}