Splitting and Tribbling Enemies

SubmittedDecember 14, 2016

0.0 rating

Featured Screenshot

Author

ZoriaRPG

Download Quest

[]

Download Script Package

SplittingandTribblingEnemies.zip

Description

Ordinarily, only walking enemy types, and some other types, may split on hit, split on death, or tribble. This header grants you the power to make any enemy do one, or more of these.

You may choose to use the ffcs, to handle splitting/tribbling enemies on a per-screen basis, or the global function (see the supplied example global active script) to do so game-wide.

Script Setup Details

Requires: std.zh

Compile, adding this to your buffer, or import directives.

FFC Usage
There are three ffcs supplied wit the package:
SplitOnDeath: Makes any enemy split on death.
SplitOnHit: Makes any enemy split on hit.
BasicTribble: This allows you to make a tribbling enemy.

FFC Set-Up
Place the ffc on the screen, and configure its arguments:

SplitOnDeath Args
D0: Source Enemy ID.
D1: ID of enemy to split into.
D2: Number of splits. i.e. On death, enemy D0 will split into D2 quantity of D1.
D3: A randomising factor for spawning the splits (x/y coordinates). Suggested value range: 2 to 5.
D4: Sound to play when enemy splits, from Quest->Audio->SFX/Misc
D5: If splitting a gleeok enemy, set this to '1' to ensure that it always spawns at the system default coordinates.

SplitOnHit Args
D0: Source Enemy ID.
D1: ID of enemy to split into.
D2: Number of splits. i.e. When hit, enemy D0 will split into D2 quantity of D1.
D3: A randomising factor for spawning the splits. Suggested value range: 2 to 5.
D4: The sound to play when the enemy splits.
D5: Set to '1' if you wish to prevent the enemy from splitting if it is dying.
D6: If splitting a gleeok enemy, set this to '1' to ensure that it always spawns at the system default coordinates.

BasicTribble Args
D0: The enemy ID of the base enemy that will split when killed. ///
D1: The enemy that the main enemy becomes, when killed. ///
D2: The number of enemies the main enemy splits into. ///
D4: The ID of the enemy that D1 becomes when it 'tribbles up'. Set to '0' to use the main enemy (e.g. zols). ///
D5: The ransomised distance to spawn the split-offs into. Suggested value range: 2 to 5. ///
D6: The timer, for the split-offs, in frames. Thus, '240' would be 5 seconds. ///
When enemy D0 dies, it splits into D2 quantity of enemy D1 at a distance of D0->X and D0->Y +/- D5 pixels. Then, when the duration defined in D6 expires (it is set as a separate timer, on a per-enemy basis), D1 will transform into D4, unless D4 is not set to a positive value, in which case, it transforms into D0.
D7: The sound to play when an enemy splits, or tribbles. Decimal value is for splitting, integer for tribbling.
Format:
#####.xxxx Tribble Sound
xxxxx.#### Split Sound
Example: 103.0024 : Enemy will play sound 103 when it tribbles, and sound 24 when it splits.
Global Version
If you wish to handle these effects globally, you will want to use the global functions:

void TribbleEnemies(int waver, int trib_timer_dur)
* Tribbles enemies based on an internal array 'list[]'
* param 'waver' is the variation in distance (x/y) when enemies spawn.
* Param 'trib_timer_dur' is the time it takes (in frames) for a split enemy to 'grow up'.
* Fill in the array 'list[]' with enemy definitions in the following format:
base_enemy, replace with, number of tribbles, tribbles_become
Example: int list[]={1,10,2,16, 2,102,3,103, 40, 12, 2, 70};
Enemy 1 will become enemy 10 when it splits, and will split into 2 of enemy 10. When it grows up, each enemy 10 becomes enemy 16.
Enemy 2 will become enemy 102 when it splits, and will split into 3 of enemy 102. When it grows up, each enemy 102 becomes enemy 103.
Enemy 40 will become enemy 12 when it splits, and will split into 2 of enemy 12. When it grows up, each enemy 12 becomes enemy 70.
* You may expand on this list, or reduce it, or otherwise change it as desired.
* Each entry to the list is a set of four values.

void SplitOnDeath(int dist_flux)
* Splits enemies (when they die) based on an internal array 'list[]'
* param 'dist_flux' is the variation in distance (x/y) when enemies spawn.
* Fill in the array 'list[]' with enemy definitions in the following format:
base_enemy, replace with, number of replacements
Example: int list[]={1,10,2, 2,102,3, 40, 12, 5};
Enemy 1 will become enemy 10 when it dies, and will split into 2 of enemy 10.
Enemy 2 will become enemy 102 when it dies, and will split into 3 of enemy 102.
Enemy 40 will become enemy 12 when it dies, and will split into 5 of enemy 12.
* You may expand on this list, or reduce it, or otherwise change it as desired.
* Each entry to the list is a set of three values.

void SplitOnHit(int dist_flux)
* Splits enemies (when they are damaged by any lweapon) based on an internal array 'list[]'
* param 'dist_flux' is the variation in distance (x/y) when enemies spawn.
* Fill in the array 'list[]' with enemy definitions in the following format:
base_enemy, replace with, number of replacements
Example: int list[]={1,10,2, 2,102,3, 40, 12, 5};
Enemy 1 will become enemy 10 when it is damaged, and will split into 2 of enemy 10.
Enemy 2 will become enemy 102 when it is damaged, and will split into 3 of enemy 102.
Enemy 40 will become enemy 12 when it is damaged, and will split into 5 of enemy 12.
* You may expand on this list, or reduce it, or otherwise change it as desired.
* Each entry to the list is a set of three values.

Script Contents

//////////////////////////////////////
/// Splitting On Death ///
/// v0.8.9 ///
/// 20th June, 2016 ///
/// By: ZoriaRPG ///
////////////////////////////////////////////////////////////////////////////////////////
/// D0: Source Enemy ID. ///
/// D1: ID of enemy to split into. ///
/// D2: Number of splits. i.e. On death, enemy D0 will split into D2 quantity of D1. ///
/// D3: A randomising factor for spawning the splits. Suggested value range: 2 to 5. ///
/// D4: Sound to play when enemy splits, from Quest->Audio->SFX/Misc ///
/// D5: If splitting a gleeok enemy, set this to '1' to ensure that it always spawns ///
/// at the system default coordinates. ///
/// ///
/// Requested by Cukeman on PureZC.net ///
////////////////////////////////////////////////////////////////////////////////////////

//SplitOnDeath ffc a[]
//Loops
const int SPLTR_Q = 0;
const int SPLTR_W = 1;
const int SPLTR_E = 2;
const int SPLTR_R = 3;
const int SPLTR_T = 4;
const int SPLTR_U = 5;
//X/Y Positions
const int SPLTR_X = 6;
const int SPLTR_Y = 7;

//SplitOnHit fff n[]
const int SPLTR_ENEM_BASE = 0;
const int SPLTR_ENEM_REPL = 1;

//Clamp values for constraints on spawning npcs on-screen.
//! If the defaults give you trouble, change them to 255, and 175, respectively.
const int MAX_SPAWN_NPX_X = 255;
const int MAX_SPAWN_NPC_Y = 175;

const int FFC_TRIB_SPLIT_DEBUG_ON = 0;
const int GLEEOK_SPAWN_X = 112;
const int GLEEOK_SPAWN_Y =32;

ffc script SplitOnDeath {
void run(int enem_id, int splits_into, int number_of_splits, int dist_flux, split_sfx, int gleeok_override ){
npc n[2]; int a[10];
Waitframes(5); //Enemies require five frames, to spawn.
// If a 'No Return' flag is set, and there are no enemies on the screen,
// cleanly exit the script and make the ffc slot available.
if ( ( Screen->State[ST_ENEMYNORETURN] || Screen->State[ST_TEMPNORETURN] ) && !Screen->NumNPCs() ){
this->Data = 0; this->Script = 0; Quit();
}
while(true){
for ( a[SPLTR_Q] = 1; a[SPLTR_Q] NumNPCs(); a[SPLTR_Q]++ ) {
n[SPLTR_ENEM_BASE] = Screen->LoadNPC(a[SPLTR_Q]);
if ( n[SPLTR_ENEM_BASE]->isValid() ) {
// If it's dying, not removed, and the correct enemy ID...
if ( n[SPLTR_ENEM_BASE]->ID == enem_id && n[SPLTR_ENEM_BASE]->HP HP > -9999 && n[SPLTR_ENEM_BASE]->X != -32768 && n[SPLTR_ENEM_BASE]->Y != -32768 ) {
a[SPLTR_X] = n[SPLTR_ENEM_BASE]->X; //Store its position, so that we know where to spawn its splits.
a[SPLTR_Y] = n[SPLTR_ENEM_BASE]->Y;
n[SPLTR_ENEM_BASE]->HitXOffset = -200; //Hide the source enemy.
n[SPLTR_ENEM_BASE]->HitYOffset = -200;
n[SPLTR_ENEM_BASE]->DrawXOffset = -200;
n[SPLTR_ENEM_BASE]->DrawYOffset = -200;
n[SPLTR_ENEM_BASE]->HP = -9999; //Kill the original enemy.
Remove(n[SPLTR_ENEM_BASE]);
Waitframes(1);

for ( a[SPLTR_W] = 0; a[SPLTR_W] 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);
//if ( Game->GuyCount[Game->GetCurScreen()] GuyCount[Game->GetCurScreen()]++;
}

}
}
}
if ( Game->GuyCount[Game->GetCurScreen()] != Screen->NumNPCs() ) Game->GuyCount[Game->GetCurScreen()] = Screen->NumNPCs();

if ( ( Screen->State[ST_ENEMYNORETURN] || Screen->State[ST_TEMPNORETURN] ) && !Screen->NumNPCs() ) {
this->Data = 0; this->Script = 0; Quit();
// Free up the slot if we're done.
}
if (FFC_TRIB_SPLIT_DEBUG_ON) Screen->DrawInteger(6,4,4,FONT_Z1, 1, 0, 16, 16, Game->GuyCount[Game->GetCurScreen()], 0, 128);
Screen->DrawInteger(6,12,4,FONT_Z1, 1, 0, 16, 16, Screen->NumNPCs(), 0, 128);
Waitframe();
}
}
}

const int DYING_ENEMY_NO_SPLIT = 0; //Set to '1' if you want to prevent dying enemies from spitting (from Split on Hit)

//////////////////////////////////////
/// Splitting When Hit ///
/// v0.8.9 ///
/// 20th June, 2016 ///
/// By: ZoriaRPG ///
////////////////////////////////////////////////////////////////////////////////////////
/// D0: Source Enemy ID. ///
/// D1: ID of enemy to split into. ///
/// D2: Number of splits. i.e. When hit, enemy D0 will split into D2 quantity of D1. ///
/// D3: A randomising factor for spawning the splits. Suggested value range: 2 to 5. ///
/// D4: The sound to play when the enemy splits. ///
/// D5: Set to '1' if you wish to prevent the enemy from splitting if it is dying. ///
/// D6: If splitting a gleeok enemy, set this to '1' to ensure that it always spawns ///
/// at the system default coordinates. ///
/// ///
/// Requested by Cukeman on PureZC.net ///
////////////////////////////////////////////////////////////////////////////////////////

ffc script SplitOnHit {
void run(int enem_id, int splits_into, int number_of_splits, int dist_flux, split_sfx, int dying_no_split, int gleeok_override ){
npc n[2]; int a[10];
Waitframes(5); //Enemies require five frames, to spawn.
// If a 'No Return' flag is set, and there are no enemies on the screen,
// cleanly exit the script and make the ffc slot available.
if ( ( Screen->State[ST_ENEMYNORETURN] || Screen->State[ST_TEMPNORETURN] ) && !Screen->NumNPCs() ){
this->Data = 0; this->Script = 0; Quit();
}
while(true){
for ( a[SPLTR_Q] = 1; a[SPLTR_Q] NumNPCs(); a[SPLTR_Q]++ ) {
n[SPLTR_ENEM_BASE] = Screen->LoadNPC(a[SPLTR_Q]);
if ( n[SPLTR_ENEM_BASE]->isValid() ) {
// If it's dying, not removed, and the correct enemy ID...
if ( n[SPLTR_ENEM_BASE]->ID == enem_id && (
( !DYING_ENEMY_NO_SPLIT && !dying_no_split ) ||
( ( dying_no_split || DYING_ENEMY_NO_SPLIT ) && n[SPLTR_ENEM_BASE]->HP > 0 ) ) )
{
//Read lweapons, check collision, and see if the weapon is blocked
for ( a[SPLTR_W] = 1; a[SPLTR_W] 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[SPLTR_ENEM_BASE]) && 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[SPLTR_ENEM_BASE]->Defense[ LWeaponToNPCD(l->ID) ] < 3 ) {
//Can be damaged by the weapon
//for ( a[SPLTR_E] = 0; a[SPLTR_E] X; //Store its position, so that we know where to spawn its splits.
a[SPLTR_Y] = n[SPLTR_ENEM_BASE]->Y;
n[SPLTR_ENEM_BASE]->HitXOffset = -200; //Hide the source enemy.
n[SPLTR_ENEM_BASE]->HitYOffset = -200;
n[SPLTR_ENEM_BASE]->DrawXOffset = -200;
n[SPLTR_ENEM_BASE]->DrawYOffset = -200;

n[SPLTR_ENEM_BASE]->HP = -9999; //Kill the original enemy.
Remove(n[SPLTR_ENEM_BASE]);
while(n[SPLTR_ENEM_BASE]->isValid()) Waitframe();
//! Split on hit doesn't kill the original?
//! Should it??!
//We could add an arg for instant-kill though. ?
//! Need this to avoid splitting if collision with that weapon.
//! No, we can red the defs and see if it's an one-shot, and nto split, if it is.
//! We ALREADY do this. NPCD_ONEHITKILL is '14', so it's > 3

//! This may be funky with shielded enemies, too.
//}

for ( a[SPLTR_E] = 0; a[SPLTR_E] 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 ( Game->GuyCount[Game->GetCurScreen()] GuyCount[Game->GetCurScreen()]++;
if ( split_sfx ) Game->PlaySound(split_sfx);
}

}
}
}
}
}
}
}
if ( Game->GuyCount[Game->GetCurScreen()] != Screen->NumNPCs() ) Game->GuyCount[Game->GetCurScreen()] = Screen->NumNPCs();

if ( ( Screen->State[ST_ENEMYNORETURN] || Screen->State[ST_TEMPNORETURN] ) && !Screen->NumNPCs() ) {
this->Data = 0; this->Script = 0; Quit();
// Free up the slot if we're done.
}
if (FFC_TRIB_SPLIT_DEBUG_ON) Screen->DrawInteger(6,4,4,FONT_Z1, 1, 0, 16, 16, Game->GuyCount[Game->GetCurScreen()], 0, 128);
Screen->DrawInteger(6,12,4,FONT_Z1, 1, 0, 16, 16, Screen->NumNPCs(), 0, 128);
Waitframe();
}
}
}

//////////////////////////////////////
/// Tribble Enemies ///
/// v0.8.9 ///
/// 20th June, 2016 ///
/// By: ZoriaRPG ///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Enemies using this script work similarly to Vires, and Zols, that split into tribble enemies. ///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// D0: The enemy ID of the base enemy that will split when killed. ///
/// D1: The enemy that the main enemy becomes, when killed. ///
/// D2: The number of enemies the main enemy splits into. ///
/// D4: The ID of the enemy that D1 becomes when it 'tribbles up'. Set to '0' to use the main enemy (e.g. zols). ///
/// D5: The ransomised distance to spawn the split-offs into. Suggested value range: 2 to 5. ///
/// D6: The timer, for the split-offs, in frames. Thus, '240' would be 5 seconds. ///
/// -> When enemy D0 dies, it splits into D2 quantity of enemy D1 at a distance of D0->X and D0->Y +/- D5 pixels. ///
/// -> Then, when the duration defined in D6 expires (it is set as a separate timer, on a per-enemy basis), ///
/// -> D1 will transform into D4, unless D4 is not set to a positive value, in which case, it transforms into D0. ///
/// D7: The sound to play when an enemy splits, or tribbles. Decimal value is for splitting, integer for tribbling. ///
/// Format: #####.xxxx Tribble Sound ///
/// xxxxx.#### Split Sound ///
/// ///
/// Requested by: idontknow8 on PureZC.net ///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Tribble FFC n[]
const int TRIB_BASE = 0;
const int TRIB_INTO = 1;
const int TRIB_BASE2 = 2;
const int TRIB_FINAL = 3;
const int TRIB_INIT = 4;

//Tribble NPC->Misc[]
const int TRIB_TIME = 3;

// Tribble FFC a[]
const int TRIB_Q = 0;
const int TRIB_W = 1;
const int TRIB_E = 2;
const int TRIB_X = 4;
const int TRIB_Y = 5;
const int TRIB_BECOMES = 6;
const int TRIB_R = 7;
const int TRIB_T = 8;
const int TRIB_SFX_SPLIT = 10;
const int TRIB_SFX_EVOLV = 11;

const int TRIB_TIME_DEFAULT = 240;

ffc script BasicTribble{
void run(int base_enemy, int tribbles_into, int num_tribbles, int tribbles_become, int waver, int trib_time, int split_sfx){
int a[12]; //a vars array, for loops and stats
npc n[6]; //an npc array
a[10] = split_sfx <> 0)) * 10000;
//Handle making the splits of the main enemy tribble up.
if ( tribbles_become <= 0 ) a[TRIB_BECOMES] = base_enemy; //Split-off enemies will turn into the main enemy, unless D3 is set.
else a[TRIB_BECOMES] = tribbles_become;
if ( trib_time State[ST_ENEMYNORETURN] || Screen->State[ST_TEMPNORETURN] ) && !Screen->NumNPCs() ) {
this->Data = 0; this->Script = 0; Quit();
}

//Initialise timers in any enemies that will tribnle upward that are on the screen when the ffc loads.
for ( a[TRIB_Q] = 1; a[TRIB_Q] 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 ( n[TRIB_INIT]->ID == tribbles_into && !n[TRIB_INIT]->Misc[TRIB_TIME] ) n[TRIB_INIT]->Misc[TRIB_TIME] = trib_time; //If the timer is positive, decrement it.
}
}

//int makenew;

while(true){
//handle making the main enemy split.
for ( a[TRIB_W] = 1; a[TRIB_W] NumNPCs(); a[TRIB_W]++ ) {
n[TRIB_BASE] = Screen->LoadNPC(a[TRIB_W]); //Parse each npc onthe screen
if ( n[TRIB_BASE]->isValid() ) {
if ( n[TRIB_BASE]->HP HP > -9999 && n[TRIB_BASE]->ID == base_enemy && n[TRIB_BASE]->X != -32768 && n[TRIB_BASE]->Y != -32768){
n[TRIB_BASE]->DrawXOffset = -200;
n[TRIB_BASE]->DrawYOffset = -200;
n[TRIB_BASE]->HitXOffset = -200;
n[TRIB_BASE]->HitYOffset = -200;
a[TRIB_X] = n[TRIB_BASE]->X;
a[TRIB_Y] = n[TRIB_BASE]->Y;
n[TRIB_BASE]->HP = -9999; //Kill the original.
Remove(n[TRIB_BASE]);
//makenew++;

while ( n[TRIB_BASE]->isValid() ) { Waitframe(); } //A delay to make the spawning feel less insant...and prevent evil ZC issues.

for ( a[TRIB_E] = 0; a[TRIB_E] Misc[TRIB_TIME] = trib_time;
if ( a[TRIB_SFX_SPLIT] ) Game->PlaySound(a[TRIB_SFX_SPLIT]);

//if ( Game->GuyCount[Game->GetCurScreen()] GuyCount[Game->GetCurScreen()]++;

}

}
}
}

//Reduce timers, if they exist.
for ( a[TRIB_R] = 1; a[TRIB_R] NumNPCs(); a[TRIB_R]++ ) {
//Count down the individual enemy timers.
n[TRIB_BASE2] = Screen->LoadNPC(a[TRIB_R]); //Load the enemy.
if ( n[TRIB_BASE2]->isValid()){ //Verify that it is valid...
if ( n[TRIB_BASE2]->ID == tribbles_into && n[TRIB_BASE2]->Misc[TRIB_TIME] > 0 ) n[TRIB_BASE2]->Misc[TRIB_TIME]--; //If the timer is positive, decrement it.
}
}

//Check to see if timers have reached zero.
for ( a[TRIB_T] = 1; a[TRIB_T] NumNPCs(); a[TRIB_T]++ ) {
n[TRIB_BASE2] = Screen->LoadNPC(a[TRIB_T]); //Load the enemy.
if ( n[TRIB_BASE2]->isValid()){ //Verify that it is valid...
if ( n[TRIB_BASE2]->ID == tribbles_into && n[TRIB_BASE2]->Misc[TRIB_TIME] HP > 0) {
//if the timer for a specific enemy has run out...transform it.
a[TRIB_X] = n[TRIB_BASE2]->X;
a[TRIB_Y] = n[TRIB_BASE2]->Y;
n[TRIB_BASE2]->DrawXOffset = -200; //Hide the main enemy.
n[TRIB_BASE2]->DrawYOffset = -200;
n[TRIB_BASE2]->HitXOffset = -200;
n[TRIB_BASE2]->HitYOffset = -200;

n[TRIB_BASE2]->HP = -9999;
Remove(n[TRIB_BASE2]);
//...the spawn its replacement.
while ( n[TRIB_BASE2]->isValid() ) { Waitframe(); } //A delay to make the spawning feel less insant...and prevent evil ZC issues.

n[TRIB_FINAL] = CreateNPCAt(a[TRIB_BECOMES], a[TRIB_X], a[TRIB_Y]);
if ( a[TRIB_SFX_EVOLV] ) Game->PlaySound(a[TRIB_SFX_EVOLV]);
//break;
//Waitframes(5);
//if ( Game->GuyCount[Game->GetCurScreen()] GuyCount[Game->GetCurScreen()]++;

}
}
}
if ( Game->GuyCount[Game->GetCurScreen()] != Screen->NumNPCs() ) Game->GuyCount[Game->GetCurScreen()] = Screen->NumNPCs();
if ( ( Screen->State[ST_ENEMYNORETURN] || Screen->State[ST_TEMPNORETURN] ) && !Screen->NumNPCs() ) {
this->Data = 0; this->Script = 0; Quit();
}
if (FFC_TRIB_SPLIT_DEBUG_ON) {
Screen->DrawInteger(6,4,4,FONT_Z1, 1, 0, 16, 16, Game->GuyCount[Game->GetCurScreen()], 0, 128);
Screen->DrawInteger(6,12,4,FONT_Z1, 1, 0, 16, 16, Screen->NumNPCs(), 0, 128);

}
Waitframe();
}
}
}

/////////////////////////////
/// Global Functions ///
/// for Splitting ///
/// and Tribbling Enemies ///
//////////////////////////////////////////////////////////////////
/// Call before Waitdraw(); ///
//////////////////////////////////////////////////////////////////

const int TRIBBLE_DIST_FLUX = 3;
const int NPCM_TRIBBLEUP_TO = 6; //Index to store the index to tribble up to.
const int NPCM_TRIBBLE_TIMER = 5; //Index to holsd the timer for tribbling up.
const int TRIBLE_TIME_DUR = 200;

void TribbleEnemies(int waver, int trib_timer_dur){
int list[]={1,10,2,16, 2,102,3,103, 40, 12, 2, 70};
//Format: base_enemy, replace with, number of tribbles, tribbles_become
npc n[2]; int a[6]; //a 0 = q, 1 = w, 2 = e; 3 = n->X, 4 = n->Y; 5 = r
for ( a[0] = 1; a[0] NumNPCs(); a[0]++ ) {
n[0] = Screen->LoadNPC(a[0]);
if ( n[0]->isValid() ) {
// If it's dying, not removed, and the correct enemy ID...
for ( a[1] = 0; a[1] ID == list[a[1]] ) {
if ( n[0]->HP HP > -9999 && n[0]->X != -32768 && n[0]->Y != -32768 ) {
a[3] = n->X; //Store its position, so that we know where to spawn its splits.
a[4] = n->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]);

//Read how many enemies to make, and make one per iteration.
for ( a[5] = 0; a[5] Misc[NPCM_TRIBBLEUP_TO] = list[a[0]+3]; //Store the ID of the enemy to trible it up to.
n[1]->Misc[NPCM_TRIBBLE_TIMER] = trib_timer_dur;
//if ( Game->GuyCount[Game->GetCurScreen()] GuyCount[Game->GetCurScreen()]++;

}

}
}
}
if ( n[0]->Misc[NPCM_TRIBBLEUP_TO] > 0 && n[0]->Misc[NPCM_TRIBBLE_TIMER] > 0 ) n[0]->Misc[NPCM_TRIBBLE_TIMER]--;
//Reduce tribbling enemy timers.
if ( n[0]->Misc[NPCM_TRIBBLEUP_TO] > 0 && n[0]->Misc[NPCM_TRIBBLE_TIMER] == 0 ) {
//Cause it to tribble upward.
a[3] = n->X; //Store its position, so that we know where to spawn its splits.
a[4] = n->Y;
n[0]->HitXOffset = -200; //Hide the source enemy.
n[0]->HitYOffset = -200;
n[0]->DrawXOffset = -200;
n[0]->DrawYOffset = -200;
n[1] = CreateNPCAt(n[0]->Misc[NPCM_TRIBBLEUP_TO],
Clamp(a[3] + Rand( (waver * -1), waver ), 0, MAX_SPAWN_NPX_X),
Clamp(a[4] + Rand( (waver * -1), waver ), 0, MAX_SPAWN_NPC_Y)); //make the new enemies.
n[0]->HP = -9999; //Kill the original enemy.
Remove(n[0]);
}

}
}
//if ( Game->GuyCount[Game->GetCurScreen()] != Screen->NumNPCs() ) Game->GuyCount[Game->GetCurScreen()] = Screen->NumNPCs();
}

//Split on Death globally

const int SPLITONDEATH_DIST_FLUX = 3;

void SplitOnDeath(int dist_flux){
int list[]={1,10,2, 2,102,3, 40, 12, 5};
//Format: base_enemy, replace with, number of replacements
npc n[2]; int a[6]; //a 0 = q, 1 = w, 2 = e; 3 = n->X, 4 = n->Y; 5 = r
for ( a[0] = 1; a[0] NumNPCs(); a[0]++ ) {
n[0] = Screen->LoadNPC(a[0]);
if ( n[0]->isValid() ) {
// If it's dying, not removed, and the correct enemy ID...
for ( a[1] = 0; a[1] ID == list[a[1]] ) {
if ( n[0]->HP HP > -9999 && n[0]->X != -32768 && n[0]->Y != -32768 ) {

a[3] = n->X; //Store its position, so that we know where to spawn its splits.
a[4] = n->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]);

for ( a[2] = 0; a[2] GuyCount[Game->GetCurScreen()] GuyCount[Game->GetCurScreen()]++;

}

}
}
}
}
}
//if ( Game->GuyCount[Game->GetCurScreen()] != Screen->NumNPCs() ) Game->GuyCount[Game->GetCurScreen()] = Screen->NumNPCs();
}

//Global Split on hit

const int SPLITONHIT_DIST_FLUX = 3;

void SplitOnHit(int dist_flux){
int list[]={1,10,2, 2,102,3, 40, 12, 5};
//Format: base_enemy, replace with, number of replacements
npc n[2]; int a[8]; //a 0 = q, 1 = w, 2 = e; 3 = n->X, 4 = n->Y; 5 = r; 6 = t ; 7 = y
for ( a[0] = 1; a[0] NumNPCs(); a[0]++ ) {
n[0] = Screen->LoadNPC(a[0]);
if ( n[0]->isValid() ) {
// If it's dying, not removed, and the correct enemy ID...
for ( a[1] = 0; a[1] ID == list[a[1]] && ( !DYING_ENEMY_NO_SPLIT || ( DYING_ENEMY_NO_SPLIT && n[0]->HP > 0 ) ) ) {
//Read lweapons, check collision, and see if the weapon is blocked
for ( a[6] = 1; a[6] NumLWeapons(); a[6]++ ) {
//Read the lweapons on the screen, loadfing them
lweapon l = Screen->LoadLWeapon(a[6]);
if ( l->isValid() ) { //If it's valid
if ( Collision(l,n[0]) ) {
//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) ] X; //Store its position, so that we know where to spawn its splits.
a[4] = n->Y;
//if ) {
//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]);

for ( a[2] = 0; a[2] GuyCount[Game->GetCurScreen()] GuyCount[Game->GetCurScreen()]++;

}

}
}
}
}
}
}
}
}
//if ( Game->GuyCount[Game->GetCurScreen()] != Screen->NumNPCs() ) Game->GuyCount[Game->GetCurScreen()] = Screen->NumNPCs();
}

// Versions that accept an array pointer as an input.

void TribbleEnemies(int waver, int trib_timer_dur, int list){
//int list[]={1,10,2,16, 2,102,3,103, 40, 12, 2, 70};
//Format: base_enemy, replace with, number of tribbles, tribbles_become
npc n[2]; int a[6]; //a 0 = q, 1 = w, 2 = e; 3 = n->X, 4 = n->Y; 5 = r
for ( a[0] = 1; a[0] NumNPCs(); a[0]++ ) {
n[0] = Screen->LoadNPC(a[0]);
if ( n[0]->isValid() ) {
// If it's dying, not removed, and the correct enemy ID...
for ( a[1] = 0; a[1] ID == list[a[1]] ) {
if ( n[0]->HP HP > -9999 && n[0]->X != -32768 && n[0]->Y != -32768 ) {
a[3] = n->X; //Store its position, so that we know where to spawn its splits.
a[4] = n->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]);

//Read how many enemies to make, and make one per iteration.
for ( a[5] = 0; a[5] Misc[NPCM_TRIBBLEUP_TO] = list[a[0]+3]; //Store the ID of the enemy to trible it up to.
n[1]->Misc[NPCM_TRIBBLE_TIMER] = trib_timer_dur;
//if ( Game->GuyCount[Game->GetCurScreen()] GuyCount[Game->GetCurScreen()]++;

}

}
}
}
if ( n[0]->Misc[NPCM_TRIBBLEUP_TO] > 0 && n[0]->Misc[NPCM_TRIBBLE_TIMER] > 0 ) n[0]->Misc[NPCM_TRIBBLE_TIMER]--;
//Reduce tribbling enemy timers.
if ( n[0]->Misc[NPCM_TRIBBLEUP_TO] > 0 && n[0]->Misc[NPCM_TRIBBLE_TIMER] == 0 ) {
//Cause it to tribble upward.
a[3] = n->X; //Store its position, so that we know where to spawn its splits.
a[4] = n->Y;
n[0]->HitXOffset = -200; //Hide the source enemy.
n[0]->HitYOffset = -200;
n[0]->DrawXOffset = -200;
n[0]->DrawYOffset = -200;
n[1] = CreateNPCAt(n[0]->Misc[NPCM_TRIBBLEUP_TO],
Clamp(a[3] + Rand( (waver * -1), waver ), 0, MAX_SPAWN_NPX_X),
Clamp(a[4] + Rand( (waver * -1), waver ), 0, MAX_SPAWN_NPC_Y) ); //make the new enemies.
n[0]->HP = -9999; //Kill the original enemy.
Remove(n[0]);
}

}
}
//if ( Game->GuyCount[Game->GetCurScreen()] != Screen->NumNPCs() ) Game->GuyCount[Game->GetCurScreen()] = Screen->NumNPCs();
}

//Split on Death globally

void SplitOnDeath(int dist_flux, int list){
//int list[]={1,10,2, 2,102,3, 40, 12, 5};
//Format: base_enemy, replace with, number of replacements
npc n[2]; int a[6]; //a 0 = q, 1 = w, 2 = e; 3 = n->X, 4 = n->Y; 5 = r
for ( a[0] = 1; a[0] NumNPCs(); a[0]++ ) {
n[0] = Screen->LoadNPC(a[0]);
if ( n[0]->isValid() ) {
// If it's dying, not removed, and the correct enemy ID...
for ( a[1] = 0; a[1] ID == list[a[1]] ) {
if ( n[0]->HP HP > -9999 && n[0]->X != -32768 && n[0]->Y != -32768 ) {

a[3] = n->X; //Store its position, so that we know where to spawn its splits.
a[4] = n->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]);

for ( a[2] = 0; a[2] GuyCount[Game->GetCurScreen()] GuyCount[Game->GetCurScreen()]++;

}

}
}
}
}
}
//if ( Game->GuyCount[Game->GetCurScreen()] != Screen->NumNPCs() ) Game->GuyCount[Game->GetCurScreen()] = Screen->NumNPCs();
}

//Global Split on hit

void SplitOnHit(int dist_flux, int list){
//int list[]={1,10,2, 2,102,3, 40, 12, 5};
//Format: base_enemy, replace with, number of replacements
npc n[2]; int a[8]; //a 0 = q, 1 = w, 2 = e; 3 = n->X, 4 = n->Y; 5 = r; 6 = t ; 7 = y
for ( a[0] = 1; a[0] NumNPCs(); a[0]++ ) {
n[0] = Screen->LoadNPC(a[0]);
if ( n[0]->isValid() ) {
// If it's dying, not removed, and the correct enemy ID...
for ( a[1] = 0; a[1] ID == list[a[1]] && ( !DYING_ENEMY_NO_SPLIT || ( DYING_ENEMY_NO_SPLIT && n[0]->HP > 0 ) ) ) {
//Read lweapons, check collision, and see if the weapon is blocked
for ( a[6] = 1; a[6] NumLWeapons(); a[6]++ ) {
//Read the lweapons on the screen, loadfing them
lweapon l = Screen->LoadLWeapon(a[7]);
if ( l->isValid() ) { //If it's valid
if ( Collision(l,n[0]) ) {
//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) ] X; //Store its position, so that we know where to spawn its splits.
a[4] = n->Y;
//if ) {
//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]);

for ( a[2] = 0; a[2] GuyCount[Game->GetCurScreen()] GuyCount[Game->GetCurScreen()]++;

}

}
}
}
}
}
}
}
}
//if ( Game->GuyCount[Game->GetCurScreen()] != Screen->NumNPCs() ) Game->GuyCount[Game->GetCurScreen()] = Screen->NumNPCs();
}

//std functions for this

//Convert an LWeapon ID to the related NPCD. Returns -1 on error.
//Does not respect Stomp Boots (ZC limitation)
int LWeaponToNPCD(int ltype){
if ( ltype == LW_ARROW ) return NPCD_ARROW;
if ( ltype == LW_BEAM ) return NPCD_BEAM;
if ( ltype == LW_BRANG ) return NPCD_BRANG;
if ( ltype == LW_BOMBBLAST ) return NPCD_BOMB;
if ( ltype == LW_CANEOFBYRNA ) return NPCD_BYRNA;
if ( ltype == LW_FIRE ) return NPCD_FIRE;
if ( ltype == LW_HAMMER ) return NPCD_HAMMER;
if ( ltype == LW_HOOKSHOT ) return NPCD_HOOKSHOT;
if ( ltype == LW_MAGIC ) return NPCD_MAGIC;
if ( ltype == LW_REFBEAM ) return NPCD_REFBEAM;
if ( ltype == LW_REFMAGIC ) return NPCD_REFMAGIC;
if ( ltype == LW_REFFIREBALL ) return NPCD_REFFIREBALL;
if ( ltype == LW_REFROCK ) return NPCD_REFROCK;
if ( ltype == LW_SBOMBBLAST ) return NPCD_SBOMB;
//if ( ltype == LW_STOMP ) return NPCD_STOMP;
if ( ltype == LW_SWORD ) return NPCD_SWORD;
if ( ltype == LW_WAND ) return NPCD_WAND;
if ( ltype == LW_SCRIPT1 ) return NPCD_SCRIPT;
if ( ltype == LW_SCRIPT2 ) return NPCD_SCRIPT;
if ( ltype == LW_SCRIPT3 ) return NPCD_SCRIPT;
if ( ltype == LW_SCRIPT4 ) return NPCD_SCRIPT;
if ( ltype == LW_SCRIPT5 ) return NPCD_SCRIPT;
if ( ltype == LW_SCRIPT6 ) return NPCD_SCRIPT;
if ( ltype == LW_SCRIPT7 ) return NPCD_SCRIPT;
if ( ltype == LW_SCRIPT8 ) return NPCD_SCRIPT;
if ( ltype == LW_SCRIPT9 ) return NPCD_SCRIPT;
if ( ltype == LW_SCRIPT10 ) return NPCD_SCRIPT;
return -1;
}

//Concert an NPCD category to its related lweapon ID.
//Returns '100' if the LWeapon is a script type (as 2.50.2 doesn;t distinguish these indivually)
//Returns -1 on error.
//Does not respect Stomp Boots (ZC limitation)
int NPCDtoLWeapon(int ltype){
if ( ltype == NPCD_ARROW ) return LW_ARROW;
if ( ltype == NPCD_BEAM ) return LW_BEAM;
if ( ltype == NPCD_BRANG ) return LW_BRANG;
if ( ltype == NPCD_BOMB ) return LW_BOMBBLAST;
if ( ltype == NPCD_BYRNA ) return LW_CANEOFBYRNA;
if ( ltype == NPCD_FIRE ) return LW_FIRE;
if ( ltype == NPCD_HAMMER ) return LW_HAMMER;
if ( ltype == NPCD_HOOKSHOT ) return LW_HOOKSHOT;
if ( ltype == NPCD_MAGIC ) return LW_MAGIC;
if ( ltype == NPCD_REFBEAM ) return LW_REFBEAM;
if ( ltype == NPCD_REFMAGIC ) return LW_REFMAGIC;
if ( ltype == NPCD_REFFIREBALL ) return LW_REFFIREBALL;
if ( ltype == NPCD_REFROCK ) return LW_REFROCK;
if ( ltype == NPCD_SBOMB ) return LW_SBOMBBLAST;
//if ( ltype == NPCD_STOMP ) return LW_STOMP;
if ( ltype == NPCD_SWORD ) return LW_SWORD;
if ( ltype == NPCD_WAND ) return LW_WAND;
if ( ltype == NPCD_SCRIPT ) return 100;
return -1;
}

This entry has no reviews.