import "std.zh" import "ffcscript_LA.zh" import "stdExtra.zh" // Generalised Enemy Explosions, from LinksAwakening_v0.54.zs // Sub-version 0.2.7 // 3rd July, 2015 //Enemy Explosion Settings const int ENEMIES_ALWAYS_EXPLODE = 1; //Set to '0' if enemies only explode when a player has a Piece of Power power-up. const int EXPLOSIONS_RUN_WITH_FFCS = 1; //If set to 1, enemy explosions on death will run from FFCs //rather than from the global active infinite loop. //Enemy Explosion Constants const int FFC_ENEMY_EXPLODE = 1; //Set to FFC script slot for death explosion FFC animation. const int FFC_NUM_OF_EXPLOSIONS = 4; //Base number of explosions when killing an enemy. const int FFC_EXPLOSION_SPRITE = 17; //Sprite for the explosion. const int FFC_EXPLOSION_EXTEND = 3; //Size of explosion eweapon. const int FFC_EXPLOSION_TILEWIDTH = 1; //Width of explosion, in tiles. const int FFC_EXPLOSION_TILEHEIGHT = 1; //Height of explosion, in tiles. const int FFC_EXPLOSIONS_MINIBOSS_EXTRA = 4; //Add this many explosions if the enemy is a miniboss. const int FFC_EXPLOSIONS_BOSS_EXTRA = 12; //Add this many explosions if the enemy is a full boss. const int FFC_EXPLOSIONS_FINALBOSS_EXTRA = 16; //Add this many explosions if the enemy is the FINAL boss. const int FFC_EXPLOSION_DELAY = 8; //The delay (in frames) between explosions. const int FFC_EXPLOSION_SPRITE_NORMAL_ENEM = 87; //The sprite to use for Normal Enemy deaths. const int FFC_EXPLOSION_SPRITE_ENEM_MINIBOSS = 9; //The sprite to use for Minoboss deaths. const int FFC_EXPLOSION_SPRITE_ENEM_BOSS = 17; //The sprite to use for Boss deaths. const int FFC_EXPLOSION_SPRITE_ENEM_FINAL_BOSS = 81; //The sprite to use for your Final Boss (does not work with Ganon rooms). const int SFX_ENEMY_EXPLOSION = 100; //Explosion SFX const int FINAL_BOSS_ID = 78; //Enemy ID of the FINAL boss. Ganon, by default. //An invisible combo reference, as a spare, that we aren't using. const int EXPLODE_INVIS_COMBO = 735; //Constants for determining enemy types. Do not change. const int ENEM_TYPE_NORMAL = 0; const int ENEM_TYPE_MINIBOSS = 1; const int ENEM_TYPE_BOSS = 2; const int ENEM_TYPE_FINAL_BOSS = 3; //Arrays // A list of Boss enemies, by Enemy ID // Add, or remove values from this list, to increase, or decrease the enemies treated // as Bosses for determining the number of explosions. int BossList[]={ 58, 61, 62, 63, 64, 65, 71, 72, 73, 76, 77, 93, 94, 103, 104, 105, 109, 110, 111, 112, 114, 121, 122}; // A list of Mini-boss enemies by Enemy ID // Add, or remove values from this list, to increase, or decrease the enemies treated // as Mini-bosses for determining the number of explosions. int MiniBossList[]={ 59, 66, 67, 68, 69, 70, 71, 74, 75}; //Cause enemies to have a death animation explosion with custom sprites. //Run before Waitdraw() in the infinite ( while(true) ) loop of your global active script. //You need only call this one function to run the entirety of this code. void EnemiesExplodeOnDeath(){ if ( EXPLOSIONS_RUN_WITH_FFCS ) { //If this setting is enabled... EnemyExplosionFFC(); //Run this function. } else { //Otherwise... EnemyExplosion(); //Run this instead. } } //Example global script: global script active_explosions{ void run(){ while(true){ EnemiesExplodeOnDeath(); Waitdraw(); Waitframe(); } } } //Routines /// ! Check these functions to ensure they aren't broken ! //Death explosion animation function, for global use. void EnemyExplosion(){ int fX; //Set up variables to hold X/Y coordinates. int fY; bool isBoss; bool isMiniBoss; bool isFinalBoss; int numExplosions; int enemID; int explosionCount = numExplosions; eweapon explosion; int enemType; int explodeTimer = 60; for ( int q = 1; q <= Screen->NumNPCs(); q++ ) { //Run a for loop to read every enemy on the screen... //Otherwise... npc n = Screen->LoadNPC(q); //Declare an npc variable, if ( n->isValid() ) { if ( n->ID == FINAL_BOSS_ID ) { isFinalBoss = true; enemType = ENEM_TYPE_FINAL_BOSS; } for ( int e = 0; e <= SizeOfArray(BossList); e++ ) { if ( isFinalBoss) break; enemID = BossList[e]; if ( n->ID == enemID ) { isBoss = true; enemType = ENEM_TYPE_BOSS; break; } } for ( int e = 0; e <= SizeOfArray(MiniBossList); e++ ) { if ( isBoss ) break; enemID = MiniBossList[e]; if ( n->ID == enemID ) { isMiniBoss = true; enemType = ENEM_TYPE_MINIBOSS; break; } } if ( !ENEMIES_ALWAYS_EXPLODE && !isBoss && !isMiniBoss && !isFinalBoss ){ //If these flags are all disabled, exit this function. break; } //Determine number of explosions by type of enemy... if ( isMiniBoss ) { numExplosions = FFC_NUM_OF_EXPLOSIONS + FFC_EXPLOSIONS_MINIBOSS_EXTRA; } else if ( isBoss ) { numExplosions = FFC_NUM_OF_EXPLOSIONS + FFC_EXPLOSIONS_BOSS_EXTRA; } else if ( isFinalBoss ) { numExplosions = FFC_NUM_OF_EXPLOSIONS + FFC_EXPLOSIONS_FINALBOSS_EXTRA; } else numExplosions = FFC_NUM_OF_EXPLOSIONS; Trace(numExplosions); //and assign it to each valid NPC in the for loop. if ( n->HP <= 0 ) { //if the NPC is dead, or dying... fX = n->X; //Set the variables to the coordinates of that NPC. fY = n->Y; for ( int q = 0; q <= numExplosions; q++ ) { eweapon explosion; //Create a dummy eweapon to use for animations... //Run a for loop, to make a timed series of explosions... if ( numExplosions) { //Run only if there are explision to make. explosion = Screen->CreateEWeapon(EW_SCRIPT1); //Make an explosion.. Game->PlaySound(SFX_ENEMY_EXPLOSION); explosion->CollDetection = false; //...that doesn;t hurt anyone... if ( enemType == ENEM_TYPE_NORMAL ) { explosion->X = fX + Rand(-8,8); //at X coordinates fX plus a slightly randomised offset. explosion->Y = fY + Rand(-8,8); //at Y coordinates fX plus a slightly randomised offset. explosion->UseSprite(FFC_EXPLOSION_SPRITE_NORMAL_ENEM); //...using this sprite } else if ( enemType == ENEM_TYPE_MINIBOSS ) { explosion->X = fX + Rand(-12,12); //at X coordinates fX plus a slightly randomised offset. explosion->Y = fY + Rand(-12,12); //at Y coordinates fX plus a slightly randomised offset. explosion->UseSprite(FFC_EXPLOSION_SPRITE_ENEM_MINIBOSS); //...using this sprite } else if ( enemType == ENEM_TYPE_BOSS ) { explosion->X = fX + Rand(-16,16); //at X coordinates fX plus a slightly randomised offset. explosion->Y = fY + Rand(-16,16); //at Y coordinates fX plus a slightly randomised offset. explosion->UseSprite(FFC_EXPLOSION_SPRITE_ENEM_BOSS); //...using this sprite } else if ( enemType == ENEM_TYPE_FINAL_BOSS ) { explosion->X = fX + Rand(-24,24); //at X coordinates fX plus a slightly randomised offset. explosion->Y = fY + Rand(-24,24); //at Y coordinates fX plus a slightly randomised offset. explosion->UseSprite(FFC_EXPLOSION_SPRITE_ENEM_FINAL_BOSS); //...using this sprite } else { explosion->X = fX + Rand(-10,10); //at X coordinates fX plus a slightly randomised offset. explosion->Y = fY + Rand(-10,10); //at Y coordinates fX plus a slightly randomised offset. explosion->UseSprite(FFC_EXPLOSION_SPRITE); //...using this sprite } explosion->Extend = FFC_EXPLOSION_EXTEND; //...with extended size explosion->TileWidth = FFC_EXPLOSION_TILEWIDTH; //...this many tiles wide explosion->TileHeight = FFC_EXPLOSION_TILEHEIGHT; ///...this many tiles high //Waitframe(); //..pause, then go back to the top of this loop, to repeat until the number of // explosions is a total matching FFC_NUM_OF_EXPLOSIONS + FFC_EXPLOSION_PIECE_OF_POWER_EXTRA_BLASTS explosion->DeadState = WDS_ARROW; //Kill the dummy eweapon //Remove(explosion); //and remove it. Trace(explodeTimer); explodeTimer--; } } explosion->DeadState = WDS_DEAD; //Kill the dummy eweapon Remove(explosion); //and remove it. } } } } //Alternate to EnemyExplosion() that calls an FFC with its own Waitframe(). void EnemyExplosionFFC(){ int fX; //Set up variables to hold X/Y coordinates. int fY; bool isBoss; bool isMiniBoss; bool isFinalBoss; int numExplosions; int enemID; for ( int q = 1; q <= Screen->NumNPCs(); q++ ) { //Run a for loop to read every enemy on the screen... npc n = Screen->LoadNPC(q); //Declare an npc variable, int enemType; if ( n->isValid() ) { //and assign it to each valid NPC in the for loop. if ( n->ID == FINAL_BOSS_ID ) { isFinalBoss = true; enemType = ENEM_TYPE_FINAL_BOSS; } for ( int e = 0; e <= SizeOfArray(BossList); e++ ) { if ( isFinalBoss ) break; enemID = BossList[e]; if ( n->ID == enemID ) { isBoss = true; enemType = ENEM_TYPE_BOSS; break; } } for ( int e = 0; e <= SizeOfArray(MiniBossList); e++ ) { if ( isBoss ) break; enemID = MiniBossList[e]; if ( n->ID == enemID ) { isMiniBoss = true; enemType = ENEM_TYPE_MINIBOSS; break; } } if ( !ENEMIES_ALWAYS_EXPLODE && !isBoss && !isMiniBoss && !isFinalBoss ){ //If these flags are both disabled, exit this function. break; } //Determine number of explosions by type of enemy... if ( isMiniBoss ) { numExplosions = FFC_NUM_OF_EXPLOSIONS + FFC_EXPLOSIONS_MINIBOSS_EXTRA; } else if ( isBoss ) { numExplosions = FFC_NUM_OF_EXPLOSIONS + FFC_EXPLOSIONS_BOSS_EXTRA; } else if ( isFinalBoss ) { numExplosions = FFC_NUM_OF_EXPLOSIONS + FFC_EXPLOSIONS_FINALBOSS_EXTRA; } else numExplosions = FFC_NUM_OF_EXPLOSIONS; int str1[]="Number of explosions:"; TraceS(str1); TraceS(numExplosions); if ( n->HP <= 0 ) { //if the NPC is dead, or dying... fX = n->X; //Assign its coordinates to the variables... fY = n->Y; Trace(numExplosions); Trace(fX); Trace(fY); int f_args[4]={fX,fY,numExplosions,enemType}; //...then make an array, and assign those variables as its indices. //if ( numExplosions ) int str[]="Running FFC Script"; TraceS(str); RunFFCScript(FFC_ENEMY_EXPLODE, f_args); //Launch the FFC script designated by FFC_ENEMY_EXPLODE //using the values stored in the array f_args as the FFC //arguments D0 and D1. } } } } //FFC Script: If you wish to use an FFC to generate this effect, assign this to a slot, update the constant above, then recompile. //FFC of death animation explosion, to use as alternative to global function. //Do not call this directly, by assigning it to a screen FFC. This is designed to automatically run when needed. //...unless you want something to look like it is perpetually exploding, but then, this will need modification to do that. ffc script Explosion{ void run (int fX, int fY, int numExplosions, int enemType){ //Inputs for coordinates. //These args are to accept input by the instruction: RunFFCScript(FFC_ENEMY_EXPLODE, args[]) from other functions. eweapon explosion; //Create a dummy eweapon. this->X = fX; this->Y = fY; int explosionCount = numExplosions; while ( explosionCount > 0 ) { for ( int q = 0; q <= numExplosions; q++ ) { //Run a for loop, to make a timed series of explosions... explosion = Screen->CreateEWeapon(EW_SCRIPT1); //Make an explosion.. Game->PlaySound(SFX_ENEMY_EXPLOSION); explosion->CollDetection = false; //...that doesn;t hurt anyone... if ( enemType == ENEM_TYPE_NORMAL ) { explosion->X = this->X + Rand(-8,8); //at X coordinates fX plus a slightly randomised offset. explosion->Y = this->Y + Rand(-8,8); //at Y coordinates fX plus a slightly randomised offset. explosion->UseSprite(FFC_EXPLOSION_SPRITE_NORMAL_ENEM); //...using this sprite } else if ( enemType == ENEM_TYPE_MINIBOSS ) { explosion->X = this->X + Rand(-12,12); //at X coordinates fX plus a slightly randomised offset. explosion->Y = this->Y + Rand(-12,12); //at Y coordinates fX plus a slightly randomised offset. explosion->UseSprite(FFC_EXPLOSION_SPRITE_ENEM_MINIBOSS); //...using this sprite } else if ( enemType == ENEM_TYPE_BOSS ) { explosion->X = this->X + Rand(-16,16); //at X coordinates fX plus a slightly randomised offset. explosion->Y = this->Y + Rand(-16,16); //at Y coordinates fX plus a slightly randomised offset. explosion->UseSprite(FFC_EXPLOSION_SPRITE_ENEM_BOSS); //...using this sprite } else if ( enemType == ENEM_TYPE_FINAL_BOSS ) { explosion->X = this->X + Rand(-24,24); //at X coordinates fX plus a slightly randomised offset. explosion->Y = this->Y + Rand(-24,24); //at Y coordinates fX plus a slightly randomised offset. explosion->UseSprite(FFC_EXPLOSION_SPRITE_ENEM_FINAL_BOSS); //...using this sprite } else { explosion->X = this->X + Rand(-10,10); //at X coordinates fX plus a slightly randomised offset. explosion->Y = this->Y + Rand(-10,10); //at Y coordinates fX plus a slightly randomised offset. explosion->UseSprite(FFC_EXPLOSION_SPRITE); //...using this sprite } explosion->Extend = FFC_EXPLOSION_EXTEND; //...with extended size explosion->TileWidth = FFC_EXPLOSION_TILEWIDTH; //...this many tiles wide explosion->TileHeight = FFC_EXPLOSION_TILEHEIGHT; ///...this many tiles high for ( int w = 0; w <= FFC_EXPLOSION_DELAY; w++){ Waitframe(); } explosion->DeadState = WDS_DEAD; //Kill the eweapon Remove(explosion); //...and remove it. explosionCount--; Waitframe(); //..pause, then go back to the top of this loop, to repeat until the number of // explosions is a total matching FFC_NUM_OF_EXPLOSIONS + FFC_EXPLOSION_PIECE_OF_POWER_EXTRA_BLASTS } Waitframe(); } explosion->DeadState = WDS_DEAD; //Kill the eweapon Remove(explosion); //...and remove it. this->X = -100; this->Y = -100; this->Data = 0; //...set the FFC script slot back to a usable state. Quit(); //...and exit. } }