Code:
// =================================================
// crawlie Custom Enemy - This enemy crawls along the ground towards
// the player and will hop over obstacles. The ffc treats the enemy
// as four tiles large (with the ffc at the very center).
//
// INPUT:
// D0 = The number of this FFC
// D1 = hit points of this FFC, ***PLUS 100***
// There is a very good reason for the plus 100, dont forget it.
// D2 = number of the first of 4 FFCs making up this enemy.
// D4 -D4+3
// For a smaller enemy, just leave some of these FFCs blank.
// Ensure all of these FFCs are LINKED to the FFC running this script.
// The script expects each FFC to start out facing left. It will use
// the original combo of each FFC + 1 for facing right graphics.
// All higher variables
// D3 = Speed at which the ffc walks towards the player
// D4 = Height of hops
// ==================================================
ffc script crawlie_CE{
void run (int this_ffc_number, int hit_points, int body_ffc_number, int walk_speed, int hop_height){
// ---------------------------
// GENERAL ENEMY SETUP (same for all)
// ---------------------------
ffc this_ffc = Screen->LoadFFC(this_ffc_number);
npc ghosted_enemy = Screen->CreateNPC(85);
ghosted_enemy->HP = hit_points;
ffc body1 = Screen->LoadFFC(body_ffc_number);
ffc body2 = Screen->LoadFFC(body_ffc_number+1);
ffc body3 = Screen->LoadFFC(body_ffc_number+2);
ffc body4 = Screen->LoadFFC(body_ffc_number+3);
int original_CSet = body1->CSet;
int prev_health = ghosted_enemy->HP;
// The health of the ghosted enemy last frame
int invuln_counter = 0; // Enemy is invulnerable briefly after being damaged.
int state = 0; // State 0 = moving normally
// State 1 = reacting to damage
// State 2 = enemy is dead
// --------------------------
// SPECIFIC ENEMY SETUP (varies)
// --------------------------
int original_combo1 = body1->Data;
int original_combo2 = body2->Data;
int original_combo3 = body3->Data;
int original_combo4 = body4->Data;
while(true){
// --------------------------
// ENEMY DAMAGE CONTROL (same for all)
// --------------------------
if (invuln_counter <= 0){
ghosted_enemy->X = this_ffc->X;
ghosted_enemy->Y = this_ffc->Y;
body1->CSet = original_CSet;
body2->CSet = original_CSet;
body3->CSet = original_CSet;
body4->CSet = original_CSet;
}
else{
ghosted_enemy->X = -16;
ghosted_enemy->Y = -16;
invuln_counter--;
body1->CSet++;
body2->CSet++;
body3->CSet++;
body4->CSet++;
if(this_ffc->X < Link->X){this_ffc->Vx=-0.5;}
else {this_ffc->Vx=0.5;}
if(this_ffc->Y < Link->Y){this_ffc->Vy=-0.5;}
else {this_ffc->Vy=0.5;}
}
// check to see if enemy has been damaged
if (prev_health > ghosted_enemy->HP){
invuln_counter = 40;
}
// if hit points are exhausted, enemy vanishes
if (ghosted_enemy->HP < 100){
this_ffc->Vx = 300;
if ( state <= 1 ){ Game->PlaySound(10); state = 2; }
ghosted_enemy->HP = 0;
}
if ( invuln_counter <= 1){
// --------------------------
// ENEMY MOVEMENT (varies per enemy!)
// --------------------------
// This enemy responds to gravity and this ffc
// expects to be in the very middle of four combos.
if(canMove(this_ffc->X, this_ffc->Y+25)){
this_ffc->Vy = this_ffc->Vy+0.2;
if ( this_ffc->Vy >2){ this_ffc->Vy = 2;}
}
else{ this_ffc->Vy = 0;}
if(this_ffc->X < Link->X){
this_ffc->Vx=walk_speed;
body1->Data = original_combo1+1;
body2->Data = original_combo2+1;
body3->Data = original_combo3+1;
body4->Data = original_combo4+1;
if(!canMove(this_ffc->X+25, this_ffc->Y)){
this_ffc->Vy = -hop_height;
}
}
else {
this_ffc->Vx=-walk_speed;
body1->Data = original_combo1;
body2->Data = original_combo2;
body3->Data = original_combo3;
body4->Data = original_combo4;
if(!canMove(this_ffc->X-18, this_ffc->Y)){
this_ffc->Vy = -hop_height;
}
}
} // end of movement
// --------------------
// Stop enemy from leaving (unless dead)
// --------------------
if ( state != 2 ){
if ( (!canMove(this_ffc->X-18, this_ffc->Y)) && (this_ffc->Vx < 0)){this_ffc->Vx=0;}
if ( (!canMove(this_ffc->X+25, this_ffc->Y)) && (this_ffc->Vx > 0)){this_ffc->Vx=0;}
if ( (!canMove(this_ffc->X, this_ffc->Y-18)) && (this_ffc->Vy < 0)){this_ffc->Vy=0;}
if ( (!canMove(this_ffc->X, this_ffc->Y+25)) && (this_ffc->Vy > 0)){this_ffc->Vy=0;}
}
// --------------------
// Necessary cleanup
// --------------------
prev_health = ghosted_enemy->HP;
Waitframe();
}// end of while loop
} // end of void run
// ===================================
// Collision detection function
// ===================================
bool canMove(int x, int y){
// x=23, y=130
// Obviously in range...
if(x<0 || x>255 || y<0 || y>175)
return false;
int mask=1111b;
// x % 16 = 7, so
// mask = 1111 & 0011 = 0011
if(x%16<8)
mask&=0011b;
else
mask&=1100b;
// y % 16 = 2, so
// mask = 0011 & 0101 = 0001
if(y%16<8)
mask&=0101b;
else
mask&=1010b;
// All but the top-right quarter of the combo is solid, so ComboS = 1011
// mask & ComboS = 0001 & 1011 = 0001
// The result wasn't 0, so return false
return ((Screen->ComboS[ComboAt(x, y)]&mask)==0);
}// end of canMove
} // end of ffc script
// =================================================
// hopper Custom Enemy - This enemy hops along the ground
// and changes direction when it bumps into a wall. The
// ffc running this script expects the enemy to be one tile
// large for collision with wall purposes.
//
// INPUT:
// D0 = The number of this FFC
// D1 = hit points of this FFC, ***PLUS 100***
// There is a very good reason for the plus 100, dont forget it.
// D2 = number of the first of 4 FFCs making up this enemy.
// D4 -D4+3
// For a smaller enemy, just leave some of these FFCs blank.
// Ensure all of these FFCs are LINKED to the FFC running this script.
// The script expects each FFC to start out facing left. It will use
// the original combo of each FFC + 1 for facing right graphics.
// D3 = hopper's horizontal speed
// D4 = hopper's jump height
// D5 = hopper's initial direction (-1 left, 1 right)
// ==================================================
ffc script hopper_CE{
void run (int this_ffc_number, int hit_points, int body_ffc_number, int walk_speed, int hop_height, int dir){
// ---------------------------
// GENERAL ENEMY SETUP (same for all)
// ---------------------------
ffc this_ffc = Screen->LoadFFC(this_ffc_number);
npc ghosted_enemy = Screen->CreateNPC(85);
ghosted_enemy->HP = hit_points;
ffc body1 = Screen->LoadFFC(body_ffc_number);
ffc body2 = Screen->LoadFFC(body_ffc_number+1);
ffc body3 = Screen->LoadFFC(body_ffc_number+2);
ffc body4 = Screen->LoadFFC(body_ffc_number+3);
int original_CSet = body1->CSet;
int prev_health = ghosted_enemy->HP;
// The health of the ghosted enemy last frame
int invuln_counter = 0; // Enemy is invulnerable briefly after being damaged.
int state = 0; // State 0 = moving normally
// State 1 = reacting to damage
// State 2 = enemy is dead
// --------------------------
// SPECIFIC ENEMY SETUP (varies)
// --------------------------
int original_combo1 = body1->Data;
int original_combo2 = body2->Data;
int original_combo3 = body3->Data;
int original_combo4 = body4->Data;
while(true){
// --------------------------
// ENEMY DAMAGE CONTROL (same for all)
// --------------------------
if (invuln_counter <= 0){
ghosted_enemy->X = this_ffc->X;
ghosted_enemy->Y = this_ffc->Y;
body1->CSet = original_CSet;
body2->CSet = original_CSet;
body3->CSet = original_CSet;
body4->CSet = original_CSet;
}
else{
ghosted_enemy->X = -16;
ghosted_enemy->Y = -16;
invuln_counter--;
body1->CSet++;
body2->CSet++;
body3->CSet++;
body4->CSet++;
if(this_ffc->X < Link->X){this_ffc->Vx=-0.5;}
else {this_ffc->Vx=0.5;}
if(this_ffc->Y < Link->Y){this_ffc->Vy=-0.5;}
else {this_ffc->Vy=0.5;}
}
// check to see if enemy has been damaged
if (prev_health > ghosted_enemy->HP){
invuln_counter = 40;
}
// if hit points are exhausted, enemy vanishes
if (ghosted_enemy->HP < 100){
this_ffc->Vx = 300;
if ( state <= 1 ){ Game->PlaySound(10); state = 2; }
ghosted_enemy->HP = 0;
}
if ( invuln_counter <= 1){
// --------------------------
// ENEMY MOVEMENT (varies per enemy!)
// --------------------------
// This enemy responds to gravity and this ffc
// expects to be at the BOTTOM MIDDLE of the enemy.
if(canMove(this_ffc->X, this_ffc->Y+17)){
this_ffc->Vy = this_ffc->Vy+0.2;
if ( this_ffc->Vy >2){ this_ffc->Vy = 2;}
}
else{ this_ffc->Vy = -hop_height; }
this_ffc->Vx = (dir)*(walk_speed);
if(dir == 1){
body1->Data = original_combo1+1;
body2->Data = original_combo2+1;
body3->Data = original_combo3+1;
body4->Data = original_combo4+1;
if(!canMove(this_ffc->X+18, this_ffc->Y)){
dir = -1;
}
}
else {
this_ffc->Vx=-walk_speed;
body1->Data = original_combo1;
body2->Data = original_combo2;
body3->Data = original_combo3;
body4->Data = original_combo4;
if(!canMove(this_ffc->X-2, this_ffc->Y)){
dir = 1;
}
}
} // end of movement
// --------------------
// Stop enemy from leaving (unless dead)
// --------------------
if ( state != 2 ){
if ( (!canMove(this_ffc->X-2, this_ffc->Y)) && (this_ffc->Vx < 0)){this_ffc->Vx=0;}
if ( (!canMove(this_ffc->X+18, this_ffc->Y)) && (this_ffc->Vx > 0)){this_ffc->Vx=0;}
if ( (!canMove(this_ffc->X, this_ffc->Y-2)) && (this_ffc->Vy < 0)){this_ffc->Vy=0;}
if ( (!canMove(this_ffc->X, this_ffc->Y+17)) && (this_ffc->Vy > 0)){this_ffc->Vy=0;}
}
// --------------------
// Necessary cleanup
// --------------------
prev_health = ghosted_enemy->HP;
Waitframe();
}// end of while loop
} // end of void run
// ===================================
// Collision detection function
// ===================================
bool canMove(int x, int y){
// x=23, y=130
// Obviously in range...
if(x<0 || x>255 || y<0 || y>175)
return false;
int mask=1111b;
// x % 16 = 7, so
// mask = 1111 & 0011 = 0011
if(x%16<8)
mask&=0011b;
else
mask&=1100b;
// y % 16 = 2, so
// mask = 0011 & 0101 = 0001
if(y%16<8)
mask&=0101b;
else
mask&=1010b;
// All but the top-right quarter of the combo is solid, so ComboS = 1011
// mask & ComboS = 0001 & 1011 = 0001
// The result wasn't 0, so return false
return ((Screen->ComboS[ComboAt(x, y)]&mask)==0);
}// end of canMove
} // end of ffc script
// =================================================
// Diamond Custom Enemy - This enemy moves at an angle
// and bounces off of the walls and celings. This script
// expects the enemy to be one-tile large for collision purposes.
//
// INPUT:
// D0 = The number of this FFC
// D1 = hit points of this FFC, ***PLUS 100***
// There is a very good reason for the plus 100, dont forget it.
// D2 = number of the first of 4 FFCs making up this enemy.
// D4 -D4+3
// For a smaller enemy, just leave some of these FFCs blank.
// Ensure all of these FFCs are LINKED to the FFC running this script.
// The script expects each FFC to start out facing left. It will use
// the original combo of each FFC + 1 for facing right graphics.
// D3 = Initial X velocity
// D4 = Initial Y velocity
// ==================================================
ffc script diamond_CE{
void run (int this_ffc_number, int hit_points, int body_ffc_number, int initial_X, int initial_Y){
// ---------------------------
// GENERAL ENEMY SETUP (same for all)
// ---------------------------
ffc this_ffc = Screen->LoadFFC(this_ffc_number);
npc ghosted_enemy = Screen->CreateNPC(85);
ghosted_enemy->HP = hit_points;
ffc body1 = Screen->LoadFFC(body_ffc_number);
ffc body2 = Screen->LoadFFC(body_ffc_number+1);
ffc body3 = Screen->LoadFFC(body_ffc_number+2);
ffc body4 = Screen->LoadFFC(body_ffc_number+3);
int original_CSet = body1->CSet;
int prev_health = ghosted_enemy->HP;
// The health of the ghosted enemy last frame
int invuln_counter = 0; // Enemy is invulnerable briefly after being damaged.
int state = 0; // State 0 = moving normally
// State 1 = reacting to damage
// State 2 = enemy is dead
// --------------------------
// SPECIFIC ENEMY SETUP (varies)
// --------------------------
this_ffc->Vx = initial_X;
this_ffc->Vy = initial_Y;
while(true){
// --------------------------
// ENEMY DAMAGE CONTROL (same for all)
// --------------------------
if (invuln_counter <= 0){
ghosted_enemy->X = this_ffc->X;
ghosted_enemy->Y = this_ffc->Y;
body1->CSet = original_CSet;
body2->CSet = original_CSet;
body3->CSet = original_CSet;
body4->CSet = original_CSet;
}
else{
ghosted_enemy->X = -16;
ghosted_enemy->Y = -16;
invuln_counter--;
body1->CSet++;
body2->CSet++;
body3->CSet++;
body4->CSet++;
if(this_ffc->X < Link->X){this_ffc->Vx=-0.5;}
else {this_ffc->Vx=0.5;}
if(this_ffc->Y < Link->Y){this_ffc->Vy=-0.5;}
else {this_ffc->Vy=0.5;}
}
// check to see if enemy has been damaged
if (prev_health > ghosted_enemy->HP){
invuln_counter = 40;
}
// if hit points are exhausted, enemy vanishes
if (ghosted_enemy->HP < 100){
this_ffc->Vx = 300;
if ( state <= 1 ){ Game->PlaySound(10); state = 2; }
ghosted_enemy->HP = 0;
}
if ( invuln_counter <= 1){
// --------------------------
// ENEMY MOVEMENT (varies per enemy!)
// --------------------------
// Just reverses X and Y velocity on hitting a wall.
if ( (!canMove(this_ffc->X-2, this_ffc->Y)) && (this_ffc->Vx < 0)){this_ffc->Vx=-this_ffc->Vx;}
if ( (!canMove(this_ffc->X+17, this_ffc->Y)) && (this_ffc->Vx > 0)){this_ffc->Vx=-this_ffc->Vx;}
if ( (!canMove(this_ffc->X, this_ffc->Y-2)) && (this_ffc->Vy < 0)){this_ffc->Vy=-this_ffc->Vy;}
if ( (!canMove(this_ffc->X, this_ffc->Y+17)) && (this_ffc->Vy > 0)){this_ffc->Vy=-this_ffc->Vy;}
} // end of movement
// --------------------
// Stop enemy from leaving (unless dead)
// --------------------
if ( state != 2 ){
if ( (!canMove(this_ffc->X-2, this_ffc->Y)) && (this_ffc->Vx < 0)){this_ffc->Vx=0;}
if ( (!canMove(this_ffc->X+17, this_ffc->Y)) && (this_ffc->Vx > 0)){this_ffc->Vx=0;}
if ( (!canMove(this_ffc->X, this_ffc->Y-2)) && (this_ffc->Vy < 0)){this_ffc->Vy=0;}
if ( (!canMove(this_ffc->X, this_ffc->Y+17)) && (this_ffc->Vy > 0)){this_ffc->Vy=0;}
}
// --------------------
// Necessary cleanup
// --------------------
prev_health = ghosted_enemy->HP;
Waitframe();
}// end of while loop
} // end of void run
// ===================================
// Collision detection function
// ===================================
bool canMove(int x, int y){
// x=23, y=130
// Obviously in range...
if(x<0 || x>255 || y<0 || y>175)
return false;
int mask=1111b;
// x % 16 = 7, so
// mask = 1111 & 0011 = 0011
if(x%16<8)
mask&=0011b;
else
mask&=1100b;
// y % 16 = 2, so
// mask = 0011 & 0101 = 0001
if(y%16<8)
mask&=0101b;
else
mask&=1010b;
// All but the top-right quarter of the combo is solid, so ComboS = 1011
// mask & ComboS = 0001 & 1011 = 0001
// The result wasn't 0, so return false
return ((Screen->ComboS[ComboAt(x, y)]&mask)==0);
}// end of canMove
} // end of ffc script
Notice that these three enemies vary only by how they move; the rest of how they work is taken care of by the same code.