I got a request to make an update to this script from the database to make it summonable via an item script, and suddenly after using the script, the FFC was no longer colliding properly with Link.
https://www.purezc.n...=scripts&id=137
Here's a test file with the item included:
https://www.mediafir...ftItem.qst/file
And a video of how to trigger the bug:
And the script itself:
ffc script FFCRaft{ void BEEGBEEGTRACE(ffc this){ Screen->DrawInteger(6, this->X, this->Y, FONT_Z3SMALL, 0x01, 0x0F, -1, -1, Cond(this->Flags[FFCF_ETHEREAL], 1, 0), 0, 128); Screen->DrawInteger(6, this->X, this->Y+8, FONT_Z3SMALL, 0x01, 0x0F, -1, -1, this->X, 4, 128); Screen->DrawInteger(6, this->X, this->Y+16, FONT_Z3SMALL, 0x01, 0x0F, -1, -1, this->Y, 4, 128); Screen->DrawInteger(6, this->X, this->Y+24, FONT_Z3SMALL, 0x01, 0x0F, -1, -1, this->EffectWidth, 4, 128); Screen->DrawInteger(6, this->X, this->Y+32, FONT_Z3SMALL, 0x01, 0x0F, -1, -1, this->EffectHeight, 4, 128); } bool CheckWater(int x, int y){ int c = Screen->ComboT[ComboAt(x, y)]; if(c==CT_WATER||c==CT_SWIMWARP||c==CT_DIVEWARP||(c>=CT_SWIMWARPB&&c<=CT_SWIMWARPD)||(c>=CT_DIVEWARPB&&c<=CT_DIVEWARPD)) return true; else return false; } bool CanPlaceRaft(int X, int Y){ for(int x=0; x<3; x++){ for(int y=0; y<3; y++){ if(!CheckWater(X+x*7.5, Y+y*7.5)) return false; } } return true; } void run(){ int whichHitbox; ffc raftHitbox; // int scriptName[] = "RaftHitbox"; // int hitboxSlot = Game->GetFFCScript(scriptName); int SavedDMap = Game->GetCurDMap(); int SavedScreen = Game->GetCurScreen(); int StartX = this->X; int StartY = this->Y; int DrownX = -1; int DrownY = -1; int NewScreenCounter = -1; this->Flags[FFCF_ETHEREAL] = false; this->Flags[FFCF_PRELOAD] = true; while(true){ while(!SquareCollision(Link->X+4, Link->Y+4, 8, this->X+4, this->Y+4, 8)){ // if(whichHitbox){ // raftHitbox = Screen->LoadFFC(whichHitbox); // raftHitbox->X = 0; // raftHitbox->Y = 0; // raftHitbox->EffectWidth = 16; // raftHitbox->EffectHeight = 16; // raftHitbox->Script = 0; // raftHitbox->Data = 0; // whichHitbox = 0; // } if(Link->Action==LA_DROWNING&&DrownX>-1){ this->X = DrownX; this->Y = DrownY; } else if(Link->Action==LA_DROWNING){ this->X = StartX; this->Y = StartY; } BEEGBEEGTRACE(this); Waitframe(); } this->Flags[FFCF_CARRYOVER] = true; while(true){ // if(whichHitbox){ // raftHitbox = Screen->LoadFFC(whichHitbox); // raftHitbox->X = this->X-8; // raftHitbox->Y = this->Y-8; // raftHitbox->EffectWidth = 32; // raftHitbox->EffectHeight = 32; // } // else{ // whichHitbox = RunFFCScript(hitboxSlot, 0); // if(whichHitbox){ // raftHitbox = Screen->LoadFFC(whichHitbox); // raftHitbox->X = this->X-8; // raftHitbox->Y = this->Y-8; // raftHitbox->EffectWidth = 32; // raftHitbox->EffectHeight = 32; // } // } if(Link->Action==LA_SWIMMING) Link->Action = LA_WALKING; if(Link->Action==LA_DROWNING&&DrownX>-1){ this->X = DrownX; this->Y = DrownY; } else if(Link->Action==LA_DROWNING){ this->X = StartX; this->Y = StartY; } else if(CanPlaceRaft(Link->X, Link->Y)){ this->X = Link->X; this->Y = Link->Y; } else if(CanPlaceRaft(GridX(Link->X+8), Link->Y)){ this->X = GridX(Link->X+8); this->Y = Link->Y; } else if(CanPlaceRaft(Link->X, GridY(Link->Y+8))){ this->X = Link->X; this->Y = GridY(Link->Y+8); } if((SavedDMap!=Game->GetCurDMap()||SavedScreen!=Game->GetCurScreen())&&Link->Action!=LA_SCROLLING){ Link->Action = LA_NONE; SavedDMap = Game->GetCurDMap(); SavedScreen = Game->GetCurScreen(); for(int i=1; i<32; i++){ ffc f = Screen->LoadFFC(i); if(f->Script==this->Script&&f!=this){ f->Data = 0; f->Script = 0; } } if((Link->X==0&&Link->Y==0)||(Link->X==240&&Link->Y==0)||(Link->X==0&&Link->Y==160)||(Link->X==240&&Link->Y==160)){ if(Link->Dir==DIR_LEFT) this->X = 240; else if(Link->Dir==DIR_RIGHT) this->X = 0; else if(Link->Dir==DIR_UP) this->Y = 160; else if(Link->Dir==DIR_DOWN) this->Y = 0; } else{ if(Link->X==0) this->X = 240; else if(Link->X==240) this->X = 0; if(Link->Y==0) this->Y = 160; else if(Link->Y==160) this->Y = 0; } NewScreenCounter = 1; } else if(NewScreenCounter>0) NewScreenCounter--; else if(NewScreenCounter==0){ Link->Action = LA_NONE; DrownX = Link->X; DrownY = Link->Y; NewScreenCounter = -1; } if(!SquareCollision(Link->X+4, Link->Y+4, 8, this->X+4, this->Y+4, 8)&&NewScreenCounter==-1){ break; } BEEGBEEGTRACE(this); Waitframe(); } this->Flags[FFCF_CARRYOVER] = false; } } } //This is a dummy script to record which FFC is the raft's hitbox ffc script RaftHitbox{ void run(){ while(true){ Waitframe(); } } } const int SFX_SUMMONRAFT = 60; //Sound when summoning the raft const int SFX_ERROR = 6; //Error sound const int CMB_PLAYERRAFT = 1196; //Combo used for the player raft const int CS_PLAYERRAFT = 3; //CSet used for the player raft (probably shouldn't actually be 3) const int FFC_PLAYERRAFT = 32; //FFC reserved for player raft. Do not use this on screens with water or the raft may overwrite them when scrolling item script SummonRaft{ void run(){ int scriptName[] = "FFCRaft"; int raftSlot = Game->GetFFCScript(scriptName); int x = Link->X+8; int y = Link->Y+8; if(Link->Dir==DIR_UP){ y = Link->Y-1-4; } if(Link->Dir==DIR_DOWN){ y = Link->Y+16+4; } if(Link->Dir==DIR_LEFT){ x = Link->X-1-4; } if(Link->Dir==DIR_RIGHT){ x = Link->X+16+4; } int pos = ComboAt(x, y); if(Screen->ComboT[pos]!=CT_WATER){ Game->PlaySound(SFX_ERROR); Quit(); } else{ bool cantPlace; for(int i=1; i<=32; ++i){ ffc f = Screen->LoadFFC(i); if(f->Script==raftSlot){ if(LinkCollision(f)) cantPlace = true; if(ComboAt(f->X+8, f->Y+8)==pos) cantPlace = true; } } if(cantPlace){ Game->PlaySound(SFX_ERROR); Quit(); } else{ Game->PlaySound(SFX_SUMMONRAFT); for(int i=1; i<=32; ++i){ ffc f = Screen->LoadFFC(i); if(f->Script==raftSlot){ f->Script = 0; f->Data = 0; lweapon spawn = CreateLWeaponAt(LW_SCRIPT10, f->X, f->Y); spawn->UseSprite(22); spawn->NumFrames = 3; spawn->ASpeed = 3; spawn->DeadState = spawn->NumFrames*spawn->ASpeed; spawn->CollDetection = false; } } ffc raft = Screen->LoadFFC(FFC_PLAYERRAFT); raft->X = ComboX(pos); raft->Y = ComboY(pos); raft->Data = CMB_PLAYERRAFT; raft->CSet = CS_PLAYERRAFT; raft->Script = raftSlot; lweapon spawn = CreateLWeaponAt(LW_SCRIPT10, raft->X, raft->Y); spawn->UseSprite(22); spawn->NumFrames = 3; spawn->ASpeed = 3; spawn->DeadState = spawn->NumFrames*spawn->ASpeed; spawn->CollDetection = false; } } } }
I tried solving the problem with Dimi and Rob, but we couldn't find anything that should be causing the issue on my end. The FFC is in the same spot before and after, it's not ethereal, and its EffectWidth and EffectHeight are the same. The only difference is it's a different FFC slot being used before and after when the raft script is being recreated, though I see no reason that would affect collision. As far as I can tell this seems to be a bug.
If anyone has any idea what's going on here I'd love to know. Apologies if it turns out this isn't an engine bug. The behavior seems to be the same between all versions, but this collision is wack and inconsistent.