const int GLOBAL_TRIB_FFC_ const int GLOBAL_TRIB_NPC_MISC_TIMER = 3; const int GLOBAL_TRIB_NPC_MISC_FLAG = 7; const int GLOBAL_TRIB_NPC_MISC_IDS = 8; //Low value is the enemy it will split into, high is the enemy it will tribble into. //We need an index to hold the number of splits. int GetTribbleID(npc n){ return (n->Misc[GLOBAL_TRIB_NPC_MISC_IDS] << 0); } int GetSplitID(npc n){ return (n->Misc[GLOBAL_TRIB_NPC_MISC_IDS] - (n->Misc[GLOBAL_TRIB_NPC_MISC_IDS] >> 0)) * 10000; } bool IsTribble(npc n) { if ( n->Misc[GLOBAL_TRIB_NPC_MISC_FLAG] % 4 == 0 ) return true; } bool IsSplitOnDeath(npc n) { return (n->Misc[GLOBAL_TRIB_NPC_MISC_FLAG] == 1); } bool IsSplitOnHit(npc n) { return ( n->Misc[GLOBAL_TRIB_NPC_MISC_FLAG] == 2); } void IsSplitOnHit(npc n) { n->Misc[GLOBAL_TRIB_NPC_MISC_FLAG] = 2; } void IsSplitOnDeath(npc n) { n->Misc[GLOBAL_TRIB_NPC_MISC_FLAG] = 1; } void IsTribble(npc n) { n->Misc[GLOBAL_TRIB_NPC_MISC_FLAG] = 4; } const int NPC_SPLIT_DEATH = 1; const int NPC_SPLIT_HIT = 2; const int NPC_TRIBBLES_INTO = 4; const int NPC_TRIBBLES_BECOME = 8; ffc script SplitAndTribble{ void run(int enemy_id, int splits_into, int number_of_splits, int tribbles_into, int tribbles_become, int split_sfx, int gleeok_override, int trib_time ffc f){ npc n[256]; npc npointers[256]; int a[256]; int npcflags[256]; Waitframes(5); //Wait for npcs to spawn. if ( ( Screen->State[ST_ENEMYNORETURN] || Screen->State[ST_TEMPNORETURN] ) && !Screen->NumNPCs() ) { this->Data = 0; this->Script = 0; Quit(); //Clean up the ffc if there are no enemies. } //Initialise timers in any enemies that will tribble upward that are on the screen when the ffc loads. for ( a[TRIB_Q] = 1; a[TRIB_Q] <= Screen->NumNPCs(); a[TRIB_Q]++ ) { n[TRIB_INIT] = Screen->LoadNPC(a[TRIB_Q]); //Load the enemy. if ( n[TRIB_INIT]->isValid()){ //Verify that it is valid... if ( IsTribble(n[TRIB_INIT] && !n[TRIB_INIT]->Misc[GLOBAL_TRIB_NPC_MISC_TIMER] ) n[TRIB_INIT]->Misc[GLOBAL_TRIB_NPC_MISC_TIMER] = trib_time; //If the timer is positive, decrement it. } } while(true) { //Check all the npcs to see if they tribble, and reduce their timers. for ( a[SPLTR_Q] = 1; a[SPLTR_Q] < Screen->NumNPCs(); a[SPLTR_Q]--; ) { npc n[0] = Screen->LoadNPC(a[SPLTR_Q]); if ( n[0]->isValid ) { if ( IsTribble(n[0]) && n[0]->Misc[GLOBAL_TRIB_NPC_MISC_TIMER] > 0 ) n[0]->Misc[GLOBAL_TRIB_NPC_MISC_TIMER]--; } } //Ensure that Game->GuyCount[] is updated if ( Game->GuyCount[Game->GetCurScreen()] != Screen->NumNPCs() ) Game->GuyCount[Game->GetCurScreen()] = Screen->NumNPCs(); //Do cleanup if all enemies are dead. if ( ( Screen->State[ST_ENEMYNORETURN] || Screen->State[ST_TEMPNORETURN] ) && !Screen->NumNPCs() ) { this->Data = 0; this->Script = 0; Quit(); } /// Check if any of the enemies on the screen have flags that they tribble, or split. for ( a[SPLTR_q] = 0; a[SPLTR_q] <= Screen->NumNPCs(); a[SPLTR_q]++ ) { n[0] = Screen->LoadNPC[a[SPLTR_q]]; //Load the npc if ( n[0]->isValid() ) { //if it is a valid pointer if ( n[0]->Misc[GLOBAL_TRIB_NPC_MISC_FLAG] != 0 ) { //If so, store its pointer in the npointers[] array npointers[a[SPLTR_q]] = n[0]; //If it has a flag marked, find out what kind of flag it is. if ( IsSplitOnDeath(n[0]) && !IsSplitOnHit(n[0]) && !IsTribble(n[0]) ) { //if it splits on death //Check its HP and see if we shuld split it. if ( n[0]->HP < 1 && n[0]->HP > -9999 && n[0]->X != -32768 && n[0]->Y != -32768 ) { a[SPLTR_X] = n[0]->X; //Store its position, so that we know where to spawn its splits. a[SPLTR_Y] = n[0]->Y; n[0]->HitXOffset = -200; //Hide the source enemy. n[0]->HitYOffset = -200; n[0]->DrawXOffset = -200; n[0]->DrawYOffset = -200; n[0]->HP = -9999; //Kill the original enemy. Remove(n[0]); Waitframes(1); //Replace it with the number of splits for ( a[SPLTR_W] = 0; a[SPLTR_W] < number_of_splits; a[SPLTR_W]++ ) { n[SPLTR_ENEM_REPL] = Screen->CreateNPC(splits_into); if ( gleeok_override && n[SPLTR_ENEM_REPL]->Type == NPCT_GLEEOK ) { //Force it to spawn where Gleeoks belong. n[SPLTR_ENEM_REPL]->X = GLEEOK_SPAWN_X; n[SPLTR_ENEM_REPL]->Y = GLEEOK_SPAWN_Y; } else { n[SPLTR_ENEM_REPL]->X = Clamp(a[SPLTR_X]+Rand( (dist_flux * -1), dist_flux), 0, MAX_SPAWN_NPX_X), n[SPLTR_ENEM_REPL]->Y = Clamp(a[SPLTR_Y]+Rand( (dist_flux * -1), dist_flux), 0, MAX_SPAWN_NPC_Y) ); } if ( split_sfx ) Game->PlaySound(split_sfx); } } } //End split on death //if it splits on hit... if ( !IsSplitOnDeath(n[0]) && IsSplitOnHit(n[0]) && !IsTribble(n[0]) ) { //if it splits on death //if it isn't dying, or we don't care... if ( !DYING_ENEMY_NO_SPLIT || ( DYING_ENEMY_NO_SPLIT && n[0]->HP > 0 ) ) { //See if it's been hit... //Read lweapons, check collision, and see if the weapon is blocked for ( a[SPLTR_W] = 1; a[SPLTR_W] <= Screen->NumLWeapons(); a[SPLTR_W]++ ) { //Read the lweapons on the screen, loadfing them lweapon l = Screen->LoadLWeapon(a[SPLTR_W]); if ( l->isValid() ) { //If it's valid if ( Collision(l,n[0]) && l->CollDetection ) { //Remove(l); //Kill the lweapon. l->CollDetection = false; //Stop it from colliding constantl;y. //Check for collision with that weapon and the enemy //Check if any of the defs block this weapon. if ( n[0]->Defense[ LWeaponToNPCD(l->ID) ] < 3 ) { //Can be damaged by the weapon a[SPLTR_X] = n[0]->X; //Store its position, so that we know where to spawn its splits. a[SPLTR_Y] = n[0]->Y; n[0]->HitXOffset = -200; //Hide the source enemy. n[0]->HitYOffset = -200; n[0]->DrawXOffset = -200; n[0]->DrawYOffset = -200; n[0]->HP = -9999; //Kill the original enemy. Remove(n[0]); while(n[0]->isValid()) Waitframe(); //Wait for it to die, so that we don;t spawn extra enemies... //The spawn the splits. for ( a[SPLTR_E] = 0; a[SPLTR_E] < number_of_splits; a[SPLTR_E]++ ) { n[1] = Screen->CreateNPC(splits_into); if ( gleeok_override && n[1]->Type == NPCT_GLEEOK ) { //Force it to spawn where Gleeoks belong. n[1]->X = GLEEOK_SPAWN_X; n[1]->Y = GLEEOK_SPAWN_Y; } else { n[1]->X = Clamp(a[SPLTR_X]+Rand( (dist_flux * -1), dist_flux), 0, MAX_SPAWN_NPX_X), n[1]->Y = Clamp(a[SPLTR_Y]+Rand( (dist_flux * -1), dist_flux), 0, MAX_SPAWN_NPC_Y) ); } //if ( Game->GuyCount[Game->GetCurScreen()] < 10 ) Game->GuyCount[Game->GetCurScreen()]++; if ( split_sfx ) Game->PlaySound(split_sfx); } } } } } } } //End split on hit //If it tribbles if ( !IsSplitOnDeath(n[0]) && !IsSplitOnHit(n[0]) && IsTribble(n[0]) ) { //handle making the main enemy split. for ( a[TRIB_W] = 1; a[TRIB_W] <= Screen->NumNPCs(); a[TRIB_W]++ ) { n[0] = Screen->LoadNPC(a[TRIB_W]); //Parse each npc onthe screen if ( n[0]->isValid() ) { if ( n[0]->HP <= 0 && n[TRIB_BASE]->HP > -9999 && n[TRIB_BASE]->ID == base_enemy && n[TRIB_BASE]->X != -32768 && n[TRIB_BASE]->Y != -32768){ n[0]->DrawXOffset = -200; n[0]->DrawYOffset = -200; n[0]->HitXOffset = -200; n[0]->HitYOffset = -200; a[TRIB_X] = n[0]->X; a[TRIB_Y] = n[0]->Y; n[0]->HP = -9999; //Kill the original. Remove(n[0]); while ( n[0]->isValid() ) { Waitframe(); } //A delay to make the spawning feel less insant...and prevent evil ZC issues. for ( a[TRIB_E] = 0; a[TRIB_E] < num_tribbles; a[TRIB_E]++ ) { n[1] = CreateNPCAt(tribbles_into, Clamp(a[TRIB_X] + Rand( (waver * -1), waver ), 0, MAX_SPAWN_NPX_X), Clamp(a[TRIB_Y] + Rand( (waver * -1), waver ), 0, MAX_SPAWN_NPC_Y ) ); //make the new enemies. n[1]->Misc[TRIB_TIME] = trib_time; if ( a[TRIB_SFX_SPLIT] ) Game->PlaySound(a[TRIB_SFX_SPLIT]); } } } } } //End tribble split //If it tribbles up, and its timer is t zero... if ( n[0]->isValid() ) { if ( !IsSplitOnDeath(n[0]) && !IsSplitOnHit(n[0]) && IsTribble(n[0]) && n[0]->Misc[GLOBAL_TRIB_NPC_MISC_TIMER] <= 0 && n[0]->HP > 0 ) { //if its timer is at zero //if the timer for a specific enemy has run out...transform it. a[TRIB_X] = n[0]->X; a[TRIB_Y] = n[0]->Y; n[0]->DrawXOffset = -200; //Hide the main enemy. n[0]->DrawYOffset = -200; n[0]->HitXOffset = -200; n[0]->HitYOffset = -200; n[0]->HP = -9999; Remove(n[0]); //...the spawn its replacement. while ( n[0]->isValid() ) { Waitframe(); } //A delay to make the spawning feel less insant...and prevent evil ZC issues. n[1] = CreateNPCAt(a[TRIB_BECOMES], a[TRIB_X], a[TRIB_Y]); if ( a[TRIB_SFX_EVOLV] ) Game->PlaySound(a[TRIB_SFX_EVOLV]); } } //End tribble up. } //End main flag check } //End initial validity check. } //End Q loop Waitframe(); } //End while loop. } //End run } //End ffc script.