Copy to Clipboard Test

No Cycle Spinning Tiles [2.55] Code

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;
	}
}