const int NPC_SPINNING_TILE_PLACEHOLDER = 85; //Enemy used as a placeholder for spinning tile rooms (to hold shutters closed) //D0: Layer to check for flags on (use one >2 so it doesn't do additional behaviors) //D1: Combo for spinning tile spawner, 0 to advance the combo at each position by 1 //D2: CSet for spinning tile spawner, 0 to ignore //D3: Delay between each tile that spawns in the sequence (60ths of a second) //D4: Initial delay before spawning tiles (60ths of a second) //D5: If >0 auto generate a spinning tile pattern on all combos with this flag (on layer specified by D0) //D6: If >0, create a placeholder enemy that exists until all tiles have been spawned ffc script SpinningTileSpawner{ void run(int whichlayer, int cmb, int cset, int delay, int initdelay, int autopattern, int useplaceholder){ int i; int j; //Create a placeholder enemy to hold shutters open if needed npc placeholder; if(useplaceholder){ placeholder = CreateNPCAt(NPC_SPINNING_TILE_PLACEHOLDER, 120, -32); placeholder->CollDetection = false; placeholder->HP = 10000; } mapdata lyr = Game->LoadTempScreen(whichlayer); int patternStep = 1; int maxSteps; //Figure out auto generated patterns int numTiles = 0; int pattern[176]; int orderPos[176]; int seed[2]; seed[0] = autopattern; seed[1] = 111; if(autopattern>0){ //Populate an array with all the flagged positions for(i=0; i<176; ++i){ if(lyr->ComboF[i]==autopattern){ orderPos[numTiles] = i; ++numTiles; } } //If the flag isn't found, report something went wrong if(numTiles==0){ printf("No instance of flag %d (D5) found on layer %d (D0) onscreen. Are your D0 and D5 set up correctly?\n", autopattern, whichlayer); } else{ //Scramble the positions in the array for(i=0; i<704; ++i){ int a = STS_srand(seed, numTiles); int b = STS_srand(seed, numTiles); int backup = orderPos[a]; orderPos[a] = orderPos[b]; orderPos[b] = backup; } //Set pattern flag array based on the scrambled positions for(i=0; i<numTiles; ++i){ pattern[orderPos[i]] = i+1; } } maxSteps = numTiles; } else{ //If not auto generated, get the max number of steps by the highest numbered flag for(i=0; i<176; ++i){ if(lyr->ComboF[i]>0){ if(lyr->ComboF[i]>maxSteps) maxSteps = lyr->ComboF[i]; } } } Waitframes(initdelay); //Repeat for as many combos as there can be on screen for(i=0; i<maxSteps; ++i){ //Scan the screen for the marker flags for(j=0; j<176; ++j){ int orderFlag = lyr->ComboF[j]; //Use the array if pattern is auto generated if(autopattern>0&&orderFlag==autopattern){ orderFlag = pattern[j]; } if(orderFlag==patternStep){ if(cmb>0) Screen->ComboD[j] = cmb; else ++Screen->ComboD[j]; if(cset>0) Screen->ComboC[j] = cset; } } ++patternStep; Waitframes(delay); } Waitframes(30); while(true){ if(NumNPCsOf(NPC_SPINTILE)==0) break; Waitframe(); } Waitframes(30); //Kill the placeholder enemy if it was created if(placeholder->isValid()){ placeholder->Remove(); } } //Seeded randomization stuff for autogenerated patterns void STS_XORShift_SetSeed(int seed, int x, int y) { seed[0] = x & 0xFFFF; seed[1] = y & 0xFFFF; } int STS_XORShift_Next(int seed) { int t = seed[0] ^ ((seed[0] << 5) & 0xFFFF); seed[0] = seed[1]; seed[1] = (seed[1] ^ (seed[1] >> 1)); seed[1] ^= t ^ (t >> 3); return seed[1]; } int STS_srand(int seed, int max){ if(seed[0]==-1) return Rand(max); else return STS_XORShift_Next(seed)%max; } } const int SPR_SPINNINGTILEBREAK = 95; //Sprite to display when the tile breaks const int SIZE_SPINNINTILEBREAK = 1; //Width/Height of the sprite const int SFX_SPINNINGTILEBREAK = 4; //Sound to play when the tile breaks const bool SPINNINGTILE_BREAK_SOLID = true; //Whether or not solidity breaks the tile npc script SpinningTileBreakSolid{ void run(){ int tileYOff; int yOffTimer; while(true){ ++yOffTimer; tileYOff = -(yOffTimer>>4); //Wait for the enemy to touch solidity or die if((SPINNINGTILE_BREAK_SOLID&&SpinningTileIsSolid(this->X+8, this->Y+8))||this->HP<=0){ lweapon l = CreateLWeaponAt(LW_SPARKLE, this->X, this->Y+tileYOff); l->UseSprite(SPR_SPINNINGTILEBREAK); if(SIZE_SPINNINTILEBREAK>1){ l->Extend = 3; l->TileWidth = SIZE_SPINNINTILEBREAK; l->TileHeight = SIZE_SPINNINTILEBREAK; l->DrawXOffset = -(SIZE_SPINNINTILEBREAK-1)*8; l->DrawYOffset = -(SIZE_SPINNINTILEBREAK-1)*8; } l->CollDetection = false; //Only play the sound when the enemy is onscreen if(this->X>=0&&this->X<=240&&this->Y>=0&&this->Y<=160) Game->PlaySound(SFX_SPINNINGTILEBREAK); this->Remove(); } Waitframe(); } } bool SpinningTileIsSolid(int x, int y){ mapdata l1 = Game->LoadTempScreen(1); mapdata l2 = Game->LoadTempScreen(2); int pos = ComboAt(x, y); int bit; if(x%16<8){ if(y%16<8) bit = 0001b; else bit = 0010b; } else{ if(y%16<8) bit = 0100b; else bit = 1000b; } int solidity; switch(Screen->ComboT[pos]){ case CT_LADDERHOOKSHOT: case CT_LADDERONLY: case CT_HOOKSHOTONLY: case CT_WATER: case CT_SWIMWARP: case CT_SWIMWARPB: case CT_SWIMWARPC: case CT_SWIMWARPD: case CT_DIVEWARP: case CT_DIVEWARPB: case CT_DIVEWARPC: case CT_DIVEWARPD: break; default: solidity |= Screen->ComboS[pos]; break; } switch(l1->ComboT[pos]){ case CT_LADDERHOOKSHOT: case CT_LADDERONLY: case CT_HOOKSHOTONLY: case CT_WATER: case CT_SWIMWARP: case CT_SWIMWARPB: case CT_SWIMWARPC: case CT_SWIMWARPD: case CT_DIVEWARP: case CT_DIVEWARPB: case CT_DIVEWARPC: case CT_DIVEWARPD: break; default: solidity |= l1->ComboS[pos]; break; } switch(l2->ComboT[pos]){ case CT_LADDERHOOKSHOT: case CT_LADDERONLY: case CT_HOOKSHOTONLY: case CT_WATER: case CT_SWIMWARP: case CT_SWIMWARPB: case CT_SWIMWARPC: case CT_SWIMWARPD: case CT_DIVEWARP: case CT_DIVEWARPB: case CT_DIVEWARPC: case CT_DIVEWARPD: break; default: solidity |= l2->ComboS[pos]; break; } return solidity&bit; } }