User Tag List

Page 1 of 2 1 2 LastLast
Results 1 to 10 of 16

Thread: Custom Bosses and You

  1. #1
    Wizrobe C-Dawg's Avatar
    Join Date
    Jan 2002
    Posts
    4,205
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    6,611
    Level
    24
    vBActivity - Bars
    Lv. Percent
    99.9%

    Custom Bosses and You

    Zodiac is chock-full of custom bosses; probably 20 or so at last count. I've settled on a specific custom boss code that is easy to modify and I encourage everyone to make use of it themselves. The script can be used for standard birds-eye view games just as well as sideview.

    Warning, however. You will have to add code to make your enemy behave the way you want. That's inevitable. But if you follow this format, alot of things (damage, flashing, etc) will be taken care of for you.

    I'll use the most recent boss, Tentaplus, as an example.

    Code:
    // =================================================
    // Tentaplus - This script codes the Pieces Master, Tentaplus.  Has
    // three attack patterns: (1) loop-de-looping around the middle of the
    // screen; (2) chasing player and trying to grab her in his tentacles (if
    // succeeds, Tentaplus holds player stationary and drains her health to
    // its own); (3) swooping over the top or bottom of screen spraying 
    // bubbles.
    // Throughout combat, tentaplus babies will swarm around it, making the
    // tentaplus impossible to hit.  Periodically, squid torpedoes
    // will emerge from the walls.  Coordinate one to hit Tentaplus, and the
    // babies will fall away, making Tentaplus temporarily vulnerable.
    // INPUT:
    // D0 = The number of the FFC centered on the body.
    // D1 = hit points of this FFC
    // D2 = number of the first of 6 FFC making up the body
    // 	  of the ship:  1 2 3
    //                    4 5 6
    //	  16x64 and makes up the final right collumn of the boss.
    // D3 = number of first of 12 FFCs making up bubbles sprayed by Tentaplus.
    // D4 = number of first of 3 FFCs making up torpedoes
    // ==================================================
    
    ffc script Tentaplus_CE{
    
    	void run (int this_ffc_number, int hit_points, int body_ffc_number, int bubble_ffc_number, int torpedo_ffc_number){
    
    		// ---------------------------
    		// GENERAL ENEMY SETUP (same for all)
    		// ---------------------------
    
    		ffc this_ffc = Screen->LoadFFC(this_ffc_number);
    		int head_location_X;
    		int head_location_Y;
    
    		boss_flag = true;
    
    		npc ghosted_enemy = Screen->CreateNPC(85);
    		ghosted_enemy->HP = hit_points;
    
    		npc ghosted_damage_enemy = Screen->CreateNPC(200);
    
    		ffc body1 = Screen->LoadFFC(body_ffc_number);
    		ffc body2 = Screen->LoadFFC(body_ffc_number+1);
    		ffc body3 = Screen->LoadFFC(body_ffc_number+2);
    
    		ffc bubble1 = Screen->LoadFFC(bubble_ffc_number); bubble1->X = -16; bubble1->Y = -16;
    		ffc bubble2 = Screen->LoadFFC(bubble_ffc_number+1); bubble2->X = -16; bubble2->Y = -16;
    		ffc bubble3 = Screen->LoadFFC(bubble_ffc_number+2); bubble3->X = -16; bubble3->Y = -16;
    		ffc bubble4 = Screen->LoadFFC(bubble_ffc_number+3); bubble4->X = -16; bubble4->Y = -16;
    		ffc bubble5 = Screen->LoadFFC(bubble_ffc_number+4); bubble5->X = -16; bubble5->Y = -16;
    		ffc bubble6 = Screen->LoadFFC(bubble_ffc_number+5); bubble6->X = -16; bubble6->Y = -16;
    		ffc bubble7 = Screen->LoadFFC(bubble_ffc_number+6); bubble7->X = -16; bubble7->Y = -16;
    		ffc bubble8 = Screen->LoadFFC(bubble_ffc_number+7); bubble8->X = -16; bubble8->Y = -16;
    		ffc bubble9 = Screen->LoadFFC(bubble_ffc_number+8); bubble9->X = -16; bubble9->Y = -16;
    		ffc bubble10 = Screen->LoadFFC(bubble_ffc_number+9); bubble10->X = -16; bubble10->Y = -16;
    		ffc bubble11 = Screen->LoadFFC(bubble_ffc_number+10); bubble11->X = -16; bubble11->Y = -16;
    		ffc bubble12 = Screen->LoadFFC(bubble_ffc_number+11); bubble12->X = -16; bubble12->Y = -16;
    		
    		ffc torpedo1 = Screen->LoadFFC(torpedo_ffc_number); torpedo1->X = -16; torpedo1->Y = -16;
    		ffc torpedo2 = Screen->LoadFFC(torpedo_ffc_number+1); torpedo2->X = -16; torpedo2->Y = -16;
    		ffc torpedo3 = Screen->LoadFFC(torpedo_ffc_number+2); torpedo3->X = -16; torpedo3->Y = -16;
    
    		int torpedo_counter = 250;  // countdown till torpedo fires
    
    		int torpedo_explosion1_counter = 0;		// Keeps track of explosion timing.
    		int torpedo_explosion2_counter = 0;	
    		int torpedo_explosion3_counter = 0;			
    
    		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 = normal movement
    									// State 1 = reacting to damage
    									// State 2 = enemy is dead
    		int state_counter = 0;
    		int shot_counter = 0;
    		int attack_state = 0;  		// Start in wait mode
    		
    		int wobble = 0;
    
    		int target_X;
    		int target_Y;
    
    		item end_boss;
    
    		// --------------------------
    		// Enemy Projectile Setup
    		// --------------------------
    		// We don't have arrays.  We only have 32 FFCs.  So to make 25+ projectiles,
    		// we make a bunch of enemies!
    
    		int first_projectile_enemy_number = Screen->NumNPCs() + 1;
    		int i;
    		npc current_enemy;
    
    		for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 25; i++){
    			
    			current_enemy = Screen->CreateNPC(190);
    			current_enemy->X = -16;				// Hide ze enemy off the screen
    			current_enemy->Y = -16;
    			current_enemy->WeaponDamage = 0;		// Used as Vx
    			current_enemy->BossPal = 0;			// Used as Vy
    			current_enemy->HP = 99999;
    		}
    
    		// So now there are 25 baddies off the screen waiting patiently.
    
    		while(true){
    
    		// --------------------------
    		// DRAW ENEMY LIFE BAR
    		// --------------------------
    
    		Screen->Rectangle(4,11,9,18,70,108,1,0,0,0,true,128);
    
    		if(ghosted_enemy->HP>=100){
    			Screen->Rectangle(4,11,(71-((62*(ghosted_enemy->HP-100)) / (hit_points-100))),17,70,101,1,0,0,0,true,128);
    		}
    		Screen->DrawTile(3,8,71,15118,1,1,6,1,0,0, 0,0,true,128);
    
    		// --------------------------
    		// ENEMY DAMAGE CONTROL 
    		// --------------------------
    
    			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;						
    
    			}
    			else{
    				ghosted_enemy->X = -16;
    				ghosted_enemy->Y = -16;
    				invuln_counter--;
    				body1->CSet++;
    			}
    
    			// check to see if enemy has been damaged
    			if (prev_health > ghosted_enemy->HP){
    				invuln_counter = 20;
    			}
    		
    			// if hit points are exhausted, enemy explodes
    
    			if ((ghosted_enemy->HP < 100)&&(ghosted_enemy->HP > 0)){
    		
    				boss_flag = false;
    
    				ghosted_enemy->X = -16;
    				ghosted_enemy->Y = -16;
    				ghosted_enemy->HP--;
    				wobble++;
    
    				Screen->Circle(3,this_ffc->X,this_ffc->Y,2*wobble,109,1,0,0,0,true,128);
    				Screen->Circle(3,this_ffc->X,this_ffc->Y,(64*Cos(wobble)),109,1,0,0,0,true,128);
    
    				Screen->Circle(3,this_ffc->X + Rand(48) - 24,this_ffc->Y + Rand(48) - 24,
    				8 + Rand(8),109,1,0,0,0,true,128);
    
    				if(ghosted_enemy->HP == 50) {Game->PlaySound(84);;}
    
    				if(!((this_ffc->Data >= 3756) && (this_ffc->Data <= 3765))){
    
    					Game->PlaySound(88);
    					this_ffc->Data = 3756;
    					body1->Data = 3756;
    					body2->Data = 3756;
    					body3->Data = 3756;
    				}
    
    				for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 72; i++){
    					current_enemy = Screen->LoadNPC(i);
    					current_enemy->HP = 0;
    				}	
    		
    				if(ghosted_enemy->HP<=2){
    					end_boss = Screen->CreateItem(62);
    					end_boss->X = Link->X;
    					end_boss->Y = Link->Y;
    				}
    
    			}
    
    			if (ghosted_enemy->HP>100){	
    	
    		// --------------------------
    		// ENEMY MOVEMENT (varies per enemy!)
    		// --------------------------
    
    			// Attack State 0
    			// ----------------------------
    			// Loop-de-looping in middle of screen.
    			// Babies swarming, invincible.
    			// ----------------------------
    			
    			if ( attack_state == 0){
    
    				ghosted_enemy->X = -16;
    				ghosted_enemy->Y = -16;
    
    				target_X = 120 + 72*Sin(wobble);
    				target_Y = 72 + 64*Cos(wobble);
    
    				wobble++;
    
    				body1->Data = 3856; 
    				body1->X = this_ffc->X-16;
    				body1->Y = this_ffc->Y-16;
    				body2->Data = 3863;
    				body2->X = this_ffc->X;
    				body2->Y = this_ffc->Y+16;
    				body3->Data = 3867;
    				body3->X = this_ffc->X;
    				body3->Y = this_ffc->Y+32;
    
    				if(this_ffc->X < target_X){this_ffc->Vx = this_ffc->Vx+0.2;}
    				else{this_ffc->Vx = this_ffc->Vx-0.2;}
    				if(this_ffc->Y < target_Y){this_ffc->Vy = this_ffc->Vy+0.2;}
    				else{this_ffc->Vy = this_ffc->Vy-0.2;}
    
    				if(this_ffc->Vx>1){this_ffc->Vx=1;}
    				if(this_ffc->Vx<-1){this_ffc->Vx=-1;}
    				if(this_ffc->Vy>1){this_ffc->Vy=1;}
    				if(this_ffc->Vy<-1){this_ffc->Vy=-1;}
    
    				if(state_counter >= 400){
    					state_counter = 0;
    					wobble = 0;
    					attack_state = 1;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    
    				}else{
    					state_counter++;
    				}	
    
    				// Move babies a swarm around Tentaplus
    
    				for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 25; i++){
    			
    					current_enemy = Screen->LoadNPC(i);
    
    					if(current_enemy->X<this_ffc->X-32){
    						current_enemy->WeaponDamage = 1 + Rand(2);
    					}
    					if(current_enemy->X>this_ffc->X+32){
    						current_enemy->WeaponDamage = 1 + Rand(2) +10;
    					}
    
    					if(current_enemy->Y<this_ffc->Y-32){
    						current_enemy->BossPal = 1 + Rand(2);
    					}
    					if(current_enemy->Y>this_ffc->Y+32){
    						current_enemy->BossPal = 1 + Rand(2) +10;
    					}
    					
    				}
    
    
    			}
    
    			// Attack State 1
    			// ----------------------------
    			// Chasing player in attempt to trap
    			// her in its tentacles.
    			// ----------------------------
    
    			if ( attack_state == 1){
    
    				ghosted_enemy->X = -16;
    				ghosted_enemy->Y = -16;
    
    				target_X = Link->X;
    				target_Y = Link->Y - 32;
    
    				wobble++;
    
    				body1->Data = 3892; 
    				body1->X = this_ffc->X-16;
    				body1->Y = this_ffc->Y-16;
    				body2->Data = 0;
    				body2->X = this_ffc->X;
    				body2->Y = this_ffc->Y+16;
    				body3->Data = 0;
    				body3->X = this_ffc->X;
    				body3->Y = this_ffc->Y+32;
    
    				if(this_ffc->X < target_X){this_ffc->Vx = this_ffc->Vx+0.2;}
    				else{this_ffc->Vx = this_ffc->Vx-0.2;}
    				if(this_ffc->Y < target_Y){this_ffc->Vy = this_ffc->Vy+0.2;}
    				else{this_ffc->Vy = this_ffc->Vy-0.2;}
    
    				if(this_ffc->Vx>1){this_ffc->Vx=1;}
    				if(this_ffc->Vx<-1){this_ffc->Vx=-1;}
    				if(this_ffc->Vy>1){this_ffc->Vy=1;}
    				if(this_ffc->Vy<-1){this_ffc->Vy=-1;}
    
    				if((Abs(this_ffc->X-Link->X)<8)&&(this_ffc->Y<Link->Y)&&(Abs(this_ffc->Y-Link->Y)<32)){
    					attack_state = 2;
    					state_counter = 0;
    					wobble = 0;
    				}
    
    				if(state_counter >= 100){
    					state_counter = 0;
    					wobble = 0;
    					attack_state = 3;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    
    				}else{
    					state_counter++;
    				}	
    
    				// Move babies a swarm around Tentaplus
    
    				for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 25; i++){
    			
    					current_enemy = Screen->LoadNPC(i);
    
    					if(current_enemy->X<this_ffc->X-32){
    						current_enemy->WeaponDamage = 1 + Rand(2);
    					}
    					if(current_enemy->X>this_ffc->X+32){
    						current_enemy->WeaponDamage = 1 + Rand(2) +10;
    					}
    
    					if(current_enemy->Y<this_ffc->Y-32){
    						current_enemy->BossPal = 1 + Rand(2);
    					}
    					if(current_enemy->Y>this_ffc->Y+32){
    						current_enemy->BossPal = 1 + Rand(2) +10;
    					}
    					
    				}
    			}
    
    			// Attack State 2
    			// ----------------------------
    			// Successful!  Player held, her health
    			// decreases while Tentaplus's increases.
    			// ----------------------------
    
    			if ( attack_state == 2){
    
    				ghosted_enemy->X = -16;
    				ghosted_enemy->Y = -16;
    
    				this_ffc->Vx = 0;
    				this_ffc->Vy = 0;
    
    				ghosted_enemy->HP++;
    				if(wobble>=5){
    					wobble = 0;
    					Link->HP--;
    				}else{
    					wobble++;
    				}
    		
    				Link->X = this_ffc->X;
    				Link->Y = this_ffc->Y+32;
    
    				body1->Data = 3904; 
    				body1->X = this_ffc->X-16;
    				body1->Y = this_ffc->Y-16;
    				body2->Data = 3875;
    				body2->X = this_ffc->X;
    				body2->Y = this_ffc->Y+16;
    				body3->Data = 3879;
    				body3->X = this_ffc->X;
    				body3->Y = this_ffc->Y+32;
    
    				if(state_counter >= 100){
    					state_counter = 0;
    					wobble = 0;
    					attack_state = 0;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    				}else{
    					state_counter++;
    				}	
    
    				// Move babies a swarm around Tentaplus
    
    				for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 25; i++){
    			
    					current_enemy = Screen->LoadNPC(i);
    
    					if(current_enemy->X<this_ffc->X-32){
    						current_enemy->WeaponDamage = 1 + Rand(2);
    					}
    					if(current_enemy->X>this_ffc->X+32){
    						current_enemy->WeaponDamage = 1 + Rand(2) +10;
    					}
    
    					if(current_enemy->Y<this_ffc->Y-32){
    						current_enemy->BossPal = 1 + Rand(2);
    					}
    					if(current_enemy->Y>this_ffc->Y+32){
    						current_enemy->BossPal = 1 + Rand(2) +10;
    					}
    					
    				}
    
    			}
    
    			// Attack State 3
    			// ----------------------------
    			// Swoops top or bottom of screen
    			// spraying bubbles.
    			// ----------------------------
    
    			if ( attack_state == 3){
    
    				ghosted_enemy->X = -16;
    				ghosted_enemy->Y = -16;
    
    				target_X = 120 + 60*Sin(3*wobble); 
    				target_Y = 16;
    
    				wobble++;
    
    				body1->Data = 3856; 
    				body1->X = this_ffc->X-16;
    				body1->Y = this_ffc->Y-16;
    				body2->Data = 3863;
    				body2->X = this_ffc->X;
    				body2->Y = this_ffc->Y+16;
    				body3->Data = 3867;
    				body3->X = this_ffc->X;
    				body3->Y = this_ffc->Y+32;
    
    				if(this_ffc->X < target_X){this_ffc->Vx = this_ffc->Vx+0.2;}
    				else{this_ffc->Vx = this_ffc->Vx-0.2;}
    				if(this_ffc->Y < target_Y){this_ffc->Vy = this_ffc->Vy+0.2;}
    				else{this_ffc->Vy = this_ffc->Vy-0.2;}
    
    				if(this_ffc->Vx>2){this_ffc->Vx=2;}
    				if(this_ffc->Vx<-2){this_ffc->Vx=-2;}
    				if(this_ffc->Vy>2){this_ffc->Vy=2;}
    				if(this_ffc->Vy<-2){this_ffc->Vy=-2;}
    
    				if((Abs(this_ffc->X-Link->X)<8)&&(this_ffc->Y<Link->Y)&&(Abs(this_ffc->Y-Link->Y)<32)){
    					attack_state = 2;
    					state_counter = 0;
    					wobble = 0;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    				}
    
    				if((state_counter==25)||(state_counter==85)){
    					bubble1->Data = 3883;
    					bubble1->CSet = original_CSet;
    					bubble1->X = this_ffc->X;
    					bubble1->Y = this_ffc->Y;
    					bubble1->Vx = -0.5;
    					bubble1->Vy = -2;
    
    					bubble7->Data = 3883;
    					bubble7->CSet = original_CSet;
    					bubble7->X = this_ffc->X;
    					bubble7->Y = this_ffc->Y;
    					bubble7->Vx = 0.5;
    					bubble7->Vy = -2;
    
    					Game->PlaySound(89);
    				}
    				if((state_counter==35)||(state_counter==95)){
    					bubble2->Data = 3883;
    					bubble2->CSet = original_CSet;
    					bubble2->X = this_ffc->X;
    					bubble2->Y = this_ffc->Y;
    					bubble2->Vx = 0.5;
    					bubble2->Vy = -2;
    
    					bubble8->Data = 3883;
    					bubble8->CSet = original_CSet;
    					bubble8->X = this_ffc->X;
    					bubble8->Y = this_ffc->Y;
    					bubble8->Vx = -0.5;
    					bubble8->Vy = -2;
    					Game->PlaySound(89);
    				}
    				if((state_counter==45)||(state_counter==105)){
    					bubble3->Data = 3883;
    					bubble3->CSet = original_CSet;
    					bubble3->X = this_ffc->X;
    					bubble3->Y = this_ffc->Y;
    					bubble3->Vx = -0.5;
    					bubble3->Vy = -2;
    
    					bubble9->Data = 3883;
    					bubble9->CSet = original_CSet;
    					bubble9->X = this_ffc->X;
    					bubble9->Y = this_ffc->Y;
    					bubble9->Vx = 0.5;
    					bubble9->Vy = -2;
    					Game->PlaySound(89);
    				}
    				if((state_counter==55)||(state_counter==115)){
    					bubble4->Data = 3883;
    					bubble4->CSet = original_CSet;
    					bubble4->X = this_ffc->X;
    					bubble4->Y = this_ffc->Y;
    					bubble4->Vx = 0.5;
    					bubble4->Vy = -2;
    
    					bubble10->Data = 3883;
    					bubble10->CSet = original_CSet;
    					bubble10->X = this_ffc->X;
    					bubble10->Y = this_ffc->Y;
    					bubble10->Vx = -0.5;
    					bubble10->Vy = -2;
    					Game->PlaySound(89);
    				}
    				if((state_counter==65)||(state_counter==125)){
    					bubble5->Data = 3883;
    					bubble5->CSet = original_CSet;
    					bubble5->X = this_ffc->X;
    					bubble5->Y = this_ffc->Y;
    					bubble5->Vx = -0.5;
    					bubble5->Vy = -2;
    
    					bubble11->Data = 3883;
    					bubble11->CSet = original_CSet;
    					bubble11->X = this_ffc->X;
    					bubble11->Y = this_ffc->Y;
    					bubble11->Vx = 0.5;
    					bubble11->Vy = -2;
    					Game->PlaySound(89);
    				}
    				if((state_counter==75)||(state_counter==135)){
    					bubble6->Data = 3883;
    					bubble6->CSet = original_CSet;
    					bubble6->X = this_ffc->X;
    					bubble6->Y = this_ffc->Y;
    					bubble6->Vx = 0.5;
    					bubble6->Vy = -2;
    
    					bubble12->Data = 3883;
    					bubble12->CSet = original_CSet;
    					bubble12->X = this_ffc->X;
    					bubble12->Y = this_ffc->Y;
    					bubble12->Vx = -0.5;
    					bubble12->Vy = -2;
    					Game->PlaySound(89);
    				}
    
    				if(state_counter >= 150){
    					state_counter = 0;
    					wobble = 0;
    					attack_state = 0;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    
    				}else{
    					state_counter++;
    				}	
    
    				// Move babies a swarm around Tentaplus
    
    				for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 25; i++){
    			
    					current_enemy = Screen->LoadNPC(i);
    
    					if(current_enemy->X<this_ffc->X-32){
    						current_enemy->WeaponDamage = 1 + Rand(2);
    					}
    					if(current_enemy->X>this_ffc->X+32){
    						current_enemy->WeaponDamage = 1 + Rand(2) +10;
    					}
    
    					if(current_enemy->Y<this_ffc->Y-32){
    						current_enemy->BossPal = 1 + Rand(2);
    					}
    					if(current_enemy->Y>this_ffc->Y+32){
    						current_enemy->BossPal = 1 + Rand(2) +10;
    					}
    					
    				}
    
    			}
    
    			// Attack State 4
    			// ----------------------------
    			// Hit by torpedo! Babies scatter
    			// and Tentaplus is vulnerable.
    			// ----------------------------
    
    			if ( attack_state == 4){
    
    				ghosted_enemy->X = this_ffc->X;
    				ghosted_enemy->Y = this_ffc->Y;
    
    				this_ffc->Vx = 0;
    				this_ffc->Vy = 0;
    
    				body1->Data = 3868; 
    				body1->X = this_ffc->X-16;
    				body1->Y = this_ffc->Y-16;
    				body2->Data = 0;
    				body2->X = this_ffc->X;
    				body2->Y = this_ffc->Y+16;
    				body3->Data = 0;
    				body3->X = this_ffc->X;
    				body3->Y = this_ffc->Y+32;
    
    				if(state_counter >= 200){
    					state_counter = 0;
    					wobble = 0;
    					attack_state = 5;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    
    				}else{
    					state_counter++;
    				}	
    
    			}
    
    			// Attack State 5
    			// ----------------------------
    			// Recovering from torpedo hit; 
    			// babies returning.
    			// ----------------------------
    
    			if ( attack_state == 5){
    
    				ghosted_enemy->X = this_ffc->X;
    				ghosted_enemy->Y = this_ffc->Y;
    
    				this_ffc->Vx = 0;
    				this_ffc->Vy = 0;
    
    				body1->Data = 3868; 
    				body1->X = this_ffc->X-16;
    				body1->Y = this_ffc->Y-16;
    				body2->Data = 0;
    				body2->X = this_ffc->X;
    				body2->Y = this_ffc->Y+16;
    				body3->Data = 0;
    				body3->X = this_ffc->X;
    				body3->Y = this_ffc->Y+32;
    
    				if(state_counter >= 100){
    					state_counter = 0;
    					wobble = 0;
    					attack_state = 0;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    
    				}else{
    					state_counter++;
    				}	
    
    				for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 25; i++){
    			
    					current_enemy = Screen->LoadNPC(i);
    
    					if(current_enemy->X<this_ffc->X-32){
    						current_enemy->WeaponDamage = 1 + Rand(2);
    					}
    					if(current_enemy->X>this_ffc->X+32){
    						current_enemy->WeaponDamage = 1 + Rand(2) +10;
    					}
    
    					if(current_enemy->Y<this_ffc->Y-32){
    						current_enemy->BossPal = 1 + Rand(2);
    					}
    					if(current_enemy->Y>this_ffc->Y+32){
    						current_enemy->BossPal = 1 + Rand(2) +10;
    					}
    					
    				}
    
    			}
    CONT'D BELOW

  2. #2
    Wizrobe C-Dawg's Avatar
    Join Date
    Jan 2002
    Posts
    4,205
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    6,611
    Level
    24
    vBActivity - Bars
    Lv. Percent
    99.9%

    Re: Custom Bosses and You

    Code:
    // Move Babies
    			// ---------------------------
    
    				for(i = first_projectile_enemy_number-1; i < first_projectile_enemy_number + 25; i++){
    			
    					current_enemy = Screen->LoadNPC(i);
    
    					if(current_enemy->WeaponDamage > 10){
    						if((current_enemy->X -(current_enemy->WeaponDamage-10))>-16){
    							current_enemy->X = current_enemy->X -(current_enemy->WeaponDamage-10);
    						}
    					}else{
    						if((current_enemy->X +(current_enemy->WeaponDamage))<256){
    							current_enemy->X = current_enemy->X +(current_enemy->WeaponDamage);
    						}
    					}
    
    					if(current_enemy->BossPal > 10){
    						if((current_enemy->Y -(current_enemy->BossPal-10))>-16){
    							current_enemy->Y = current_enemy->Y -(current_enemy->BossPal-10);
    						}
    					}else{
    						if((current_enemy->Y +(current_enemy->BossPal))<176){
    							current_enemy->Y = current_enemy->Y +(current_enemy->BossPal);
    						}
    					}						
    				}
    
    			// Move Bubbles
    			// ---------------------------
    
    			bubble1->Vy = bubble1->Vy + 0.2;
    			if(bubble1->Vy > 2){bubble1->Vy = 2;}
    			if(bubble1->Y>260){bubble1->Y=-16;}
    			bubble2->Vy = bubble2->Vy + 0.2;
    			if(bubble2->Vy > 2){bubble2->Vy = 2;}
    			if(bubble2->Y>260){bubble2->Y=-16;}
    			bubble3->Vy = bubble3->Vy + 0.2;
    			if(bubble3->Vy > 2){bubble3->Vy = 2;}
    			if(bubble3->Y>260){bubble3->Y=-16;}
    			bubble4->Vy = bubble4->Vy + 0.2;
    			if(bubble4->Vy > 2){bubble4->Vy = 2;}
    			if(bubble4->Y>260){bubble4->Y=-16;}
    			bubble5->Vy = bubble5->Vy + 0.2;
    			if(bubble5->Vy > 2){bubble5->Vy = 2;}
    			if(bubble5->Y>260){bubble5->Y=-16;}
    			bubble6->Vy = bubble6->Vy + 0.2;
    			if(bubble6->Vy > 2){bubble6->Vy = 2;}
    			if(bubble6->Y>260){bubble6->Y=-16;}
    			bubble7->Vy = bubble7->Vy + 0.2;
    			if(bubble7->Vy > 2){bubble7->Vy = 2;}
    			if(bubble7->Y>260){bubble7->Y=-16;}
    			bubble8->Vy = bubble8->Vy + 0.2;
    			if(bubble8->Vy > 2){bubble8->Vy = 2;}
    			if(bubble8->Y>260){bubble8->Y=-16;}
    			bubble9->Vy = bubble9->Vy + 0.2;
    			if(bubble9->Vy > 2){bubble9->Vy = 2;}
    			if(bubble9->Y>260){bubble9->Y=-16;}
    			bubble10->Vy = bubble10->Vy + 0.2;
    			if(bubble10->Vy > 2){bubble10->Vy = 2;}
    			if(bubble10->Y>260){bubble10->Y=-16;}
    			bubble11->Vy = bubble11->Vy + 0.2;
    			if(bubble11->Vy > 2){bubble11->Vy = 2;}
    			if(bubble11->Y>260){bubble11->Y=-16;}
    			bubble12->Vy = bubble12->Vy + 0.2;
    			if(bubble12->Vy > 2){bubble12->Vy = 2;}
    			if(bubble12->Y>260){bubble12->Y=-16;}
    
    			// Move Torpedo (and handle explosion)
    			// ---------------------------
    
    			if(torpedo_counter <= 1){
    				torpedo_counter = 250;
    				if(torpedo1->X<0){
    					torpedo1->Data = 3871;
    					if(Rand(2)<1){
    						if(Rand(2)<1){
    							torpedo1->X=16; torpedo1->Y=32;
    						}else{
    							torpedo1->X=224; torpedo1->Y=32;
    						}
    					}else{
    						if(Rand(2)<1){
    							torpedo1->X=16; torpedo1->Y=128;
    						}else{
    							torpedo1->X=224; torpedo1->Y=128;
    						}
    					}
    				}else{
    					if(torpedo2->X<0){
    						torpedo2->Data = 3871;
    						if(Rand(2)<1){
    							if(Rand(2)<1){
    								torpedo2->X=16; torpedo2->Y=32;
    							}else{
    								torpedo2->X=224; torpedo2->Y=32;
    							}
    						}else{
    							if(Rand(2)<1){
    								torpedo2->X=16; torpedo2->Y=128;
    							}else{
    								torpedo2->X=224; torpedo2->Y=128;
    							}
    						}
    					}else{
    						if(torpedo3->X<0){
    							torpedo3->Data = 3871;
    							if(Rand(2)<1){
    								if(Rand(2)<1){
    									torpedo3->X=16; torpedo3->Y=32;
    								}else{
    									torpedo3->X=224; torpedo3->Y=32;
    								}
    							}else{
    								if(Rand(2)<1){
    									torpedo3->X=16; torpedo3->Y=128;
    								}else{
    									torpedo3->X=224; torpedo3->Y=128;
    								}
    							}
    						}
    					}
    				}
    
    			}else{
    				torpedo_counter--;
    			}
    
    			if((torpedo1->X>0)&&(torpedo1->Data==3871)){
    
    				if(torpedo1->X<Link->X){torpedo1->Vx = torpedo1->Vx+0.1;}
    				else{torpedo1->Vx = torpedo1->Vx-0.1;}
    				if(torpedo1->Y<Link->Y){torpedo1->Vy = torpedo1->Vy+0.1;}
    				else{torpedo1->Vy = torpedo1->Vy-0.1;}
    
    				if(torpedo1->Vx > 1){torpedo1->Vx=1;}
    				if(torpedo1->Vx < -1){torpedo1->Vx=-1;}
    				if(torpedo1->Vy > 1){torpedo1->Vy=1;}
    				if(torpedo1->Vy < -1){torpedo1->Vy=-1;}
    
    				if(((Abs(torpedo1->X-Link->X)<16)&&(Abs(torpedo1->Y-Link->Y)<16)) || ((Abs(torpedo1->X-this_ffc->X)<16)&&(Abs(torpedo1->Y-this_ffc->Y)<16)) ){
    			
    					torpedo1->Data = 3887;
    					torpedo_explosion1_counter = 50;
    					Game->PlaySound(84);
    					torpedo1->Vx = 0;
    					torpedo1->Vy = 0;
    
    					if((Abs(torpedo1->X-this_ffc->X)<24)&&(Abs(torpedo1->Y-this_ffc->Y)<24)){
    						attack_state = 4;
    						state_counter = 0;
    						Game->PlaySound(69);
    					}
    					
    				}
    			}
    
    			if(torpedo1->Data == 3887){
    
    					if(torpedo_explosion1_counter <= 0){torpedo1->Data = 0;torpedo1->X=-16;}
    					else{torpedo_explosion1_counter--;}
    
    					Screen->Circle(3,torpedo1->X,torpedo1->Y,torpedo_explosion1_counter,109,1,0,0,0,true,128);
    					Screen->Circle(3,torpedo1->X + Rand(48) - 24,torpedo1->Y + Rand(48) - 24,8 + Rand(8),109,1,0,0,0,true,128);
    
    					if( (Abs(torpedo1->X - Link->X) < 24) && (Abs(torpedo1->Y - Link->Y) < 24) ){
    						ghosted_damage_enemy->X = Link->X;
    						ghosted_damage_enemy->Y = Link->Y;
    					}	
    					else{
    						ghosted_damage_enemy->X = -16;
    						ghosted_damage_enemy->Y = -16;
    					}
    			}
    
    			if((torpedo2->X>0)&&(torpedo2->Data==3871)){
    
    				if(torpedo2->X<Link->X){torpedo2->Vx = torpedo2->Vx+0.1;}
    				else{torpedo2->Vx = torpedo2->Vx-0.1;}
    				if(torpedo2->Y<Link->Y){torpedo2->Vy = torpedo2->Vy+0.1;}
    				else{torpedo2->Vy = torpedo2->Vy-0.1;}
    
    				if(torpedo2->Vx > 1){torpedo2->Vx=1;}
    				if(torpedo2->Vx < -1){torpedo2->Vx=-1;}
    				if(torpedo2->Vy > 1){torpedo2->Vy=1;}
    				if(torpedo2->Vy < -1){torpedo2->Vy=-1;}
    
    				if( ((Abs(torpedo2->X-Link->X)<16)&&(Abs(torpedo2->Y-Link->Y)<16)) || ((Abs(torpedo2->X-this_ffc->X)<16)&&(Abs(torpedo2->Y-this_ffc->Y)<16))){
    			
    					torpedo2->Data = 3887;
    					torpedo_explosion2_counter = 50;
    					Game->PlaySound(84);
    					torpedo2->Vx = 0;
    					torpedo2->Vy = 0;
    
    					if((Abs(torpedo2->X-this_ffc->X)<24)&&(Abs(torpedo2->Y-this_ffc->Y)<24)){
    						attack_state = 4;
    						state_counter = 0;
    						Game->PlaySound(69);
    					}
    					
    				}
    			}
    
    			if(torpedo2->Data == 3887){
    
    					if(torpedo_explosion2_counter <= 0){torpedo2->Data = 0;torpedo2->X=-16;}
    					else{torpedo_explosion2_counter--;}
    
    					Screen->Circle(3,torpedo2->X,torpedo2->Y,torpedo_explosion2_counter,109,1,0,0,0,true,128);
    					Screen->Circle(3,torpedo2->X + Rand(48) - 24,torpedo2->Y + Rand(48) - 24,8 + Rand(8),109,1,0,0,0,true,128);
    
    					if( (Abs(torpedo2->X - Link->X) < 24) && (Abs(torpedo2->Y - Link->Y) < 24)){
    						ghosted_damage_enemy->X = Link->X;
    						ghosted_damage_enemy->Y = Link->Y;
    					}	
    					else{
    						ghosted_damage_enemy->X = -16;
    						ghosted_damage_enemy->Y = -16;
    					}
    			}
    
    			if((torpedo3->X>0)&&(torpedo3->Data==3871)){
    
    				if(torpedo3->X<Link->X){torpedo3->Vx = torpedo3->Vx+0.1;}
    				else{torpedo3->Vx = torpedo3->Vx-0.1;}
    				if(torpedo3->Y<Link->Y){torpedo3->Vy = torpedo3->Vy+0.1;}
    				else{torpedo3->Vy = torpedo3->Vy-0.1;}
    
    				if(torpedo3->Vx > 1){torpedo3->Vx=1;}
    				if(torpedo3->Vx < -1){torpedo3->Vx=-1;}
    				if(torpedo3->Vy > 1){torpedo3->Vy=1;}
    				if(torpedo3->Vy < -1){torpedo3->Vy=-1;}
    
    				if( ((Abs(torpedo3->X-Link->X)<16)&&(Abs(torpedo3->Y-Link->Y)<16)) || ((Abs(torpedo3->X-this_ffc->X)<16)&&(Abs(torpedo3->Y-this_ffc->Y)<16))){
    			
    					torpedo3->Data = 3887;
    					torpedo_explosion3_counter = 50;
    					Game->PlaySound(84);
    					torpedo3->Vx = 0;
    					torpedo3->Vy = 0;
    
    					if((Abs(torpedo3->X-this_ffc->X)<24)&&(Abs(torpedo3->Y-this_ffc->Y)<24)){
    						attack_state = 4;
    						state_counter = 0;
    						Game->PlaySound(69);
    					}
    					
    				}
    			}
    
    			if(torpedo3->Data == 3887){
    
    					if(torpedo_explosion3_counter <= 0){torpedo3->Data = 0;torpedo3->X=-16;}
    					else{torpedo_explosion3_counter--;}
    
    					Screen->Circle(3,torpedo3->X,torpedo3->Y,torpedo_explosion3_counter,109,1,0,0,0,true,128);
    					Screen->Circle(3,torpedo3->X + Rand(48) - 24,torpedo3->Y + Rand(48) - 24,8 + Rand(8),109,1,0,0,0,true,128);
    
    					if( (Abs(torpedo3->X - Link->X) < 24) && (Abs(torpedo3->Y - Link->Y) < 24)){
    						ghosted_damage_enemy->X = Link->X;
    						ghosted_damage_enemy->Y = Link->Y;
    					}	
    					else{
    						ghosted_damage_enemy->X = -16;
    						ghosted_damage_enemy->Y = -16;
    					}
    			}
    	
    			} // end of movement
    
    		// --------------------
    		// 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

  3. #3
    Wizrobe C-Dawg's Avatar
    Join Date
    Jan 2002
    Posts
    4,205
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    6,611
    Level
    24
    vBActivity - Bars
    Lv. Percent
    99.9%

    Re: Custom Bosses and You

    Oh criminey, that's alot of code. So let's break it down and show you what it's doing and what you need to modify to make your own custom bosses.

    Code:
    // =================================================
    // Tentaplus - This script codes the Pieces Master, Tentaplus.  Has
    // three attack patterns: (1) loop-de-looping around the middle of the
    // screen; (2) chasing player and trying to grab her in his tentacles (if
    // succeeds, Tentaplus holds player stationary and drains her health to
    // its own); (3) swooping over the top or bottom of screen spraying 
    // bubbles.
    // Throughout combat, tentaplus babies will swarm around it, making the
    // tentaplus impossible to hit.  Periodically, squid torpedoes
    // will emerge from the walls.  Coordinate one to hit Tentaplus, and the
    // babies will fall away, making Tentaplus temporarily vulnerable.
    // INPUT:
    // D0 = The number of the FFC centered on the body.
    // D1 = hit points of this FFC
    // D2 = number of the first of 3 FFC making up the body
    // 	  of the boss: one 4x4 ffc making up the body, and two 1x1 making 
    //        tenatcles
    //	  16x64 and makes up the final right collumn of the boss.
    // D3 = number of first of 12 FFCs making up bubbles sprayed by Tentaplus.
    // D4 = number of first of 3 FFCs making up torpedoes
    // ==================================================
    This is the header. It's where you explain how the code will work generally, and indicate what your variables mean. I reccomend doing this first, so you have a general idea of what you're going to be coding. Deciding how many FFCs you want to use and what they'll be used for lets you go on to modify the setup section accordingly.

    Code:
    ffc script Tentaplus_CE{
    
    	void run (int this_ffc_number, int hit_points, int body_ffc_number, int bubble_ffc_number, int torpedo_ffc_number){
    
    		// ---------------------------
    		// GENERAL ENEMY SETUP (same for all)
    		// ---------------------------
    
    		ffc this_ffc = Screen->LoadFFC(this_ffc_number);
    		int head_location_X;
    		int head_location_Y;
    
    		boss_flag = true;
    
    		npc ghosted_enemy = Screen->CreateNPC(85);
    		ghosted_enemy->HP = hit_points;
    
    		npc ghosted_damage_enemy = Screen->CreateNPC(200);
    
    		ffc body1 = Screen->LoadFFC(body_ffc_number);
    		ffc body2 = Screen->LoadFFC(body_ffc_number+1);
    		ffc body3 = Screen->LoadFFC(body_ffc_number+2);
    
    		ffc bubble1 = Screen->LoadFFC(bubble_ffc_number); bubble1->X = -16; bubble1->Y = -16;
    		ffc bubble2 = Screen->LoadFFC(bubble_ffc_number+1); bubble2->X = -16; bubble2->Y = -16;
    		ffc bubble3 = Screen->LoadFFC(bubble_ffc_number+2); bubble3->X = -16; bubble3->Y = -16;
    		ffc bubble4 = Screen->LoadFFC(bubble_ffc_number+3); bubble4->X = -16; bubble4->Y = -16;
    		ffc bubble5 = Screen->LoadFFC(bubble_ffc_number+4); bubble5->X = -16; bubble5->Y = -16;
    		ffc bubble6 = Screen->LoadFFC(bubble_ffc_number+5); bubble6->X = -16; bubble6->Y = -16;
    		ffc bubble7 = Screen->LoadFFC(bubble_ffc_number+6); bubble7->X = -16; bubble7->Y = -16;
    		ffc bubble8 = Screen->LoadFFC(bubble_ffc_number+7); bubble8->X = -16; bubble8->Y = -16;
    		ffc bubble9 = Screen->LoadFFC(bubble_ffc_number+8); bubble9->X = -16; bubble9->Y = -16;
    		ffc bubble10 = Screen->LoadFFC(bubble_ffc_number+9); bubble10->X = -16; bubble10->Y = -16;
    		ffc bubble11 = Screen->LoadFFC(bubble_ffc_number+10); bubble11->X = -16; bubble11->Y = -16;
    		ffc bubble12 = Screen->LoadFFC(bubble_ffc_number+11); bubble12->X = -16; bubble12->Y = -16;
    		
    		ffc torpedo1 = Screen->LoadFFC(torpedo_ffc_number); torpedo1->X = -16; torpedo1->Y = -16;
    		ffc torpedo2 = Screen->LoadFFC(torpedo_ffc_number+1); torpedo2->X = -16; torpedo2->Y = -16;
    		ffc torpedo3 = Screen->LoadFFC(torpedo_ffc_number+2); torpedo3->X = -16; torpedo3->Y = -16;
    
    		int torpedo_counter = 250;  // countdown till torpedo fires
    
    		int torpedo_explosion1_counter = 0;		// Keeps track of explosion timing.
    		int torpedo_explosion2_counter = 0;	
    		int torpedo_explosion3_counter = 0;			
    
    		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 = normal movement
    									// State 1 = reacting to damage
    									// State 2 = enemy is dead
    		int state_counter = 0;
    		int shot_counter = 0;
    		int attack_state = 0;  		// Start in wait mode
    		
    		int wobble = 0;
    
    		int target_X;
    		int target_Y;
    
    		item end_boss;
    Okay, that was all set-up code. All variables needed are instantiated, and pointers to the FFCs you need are also set up. You can modify this section right away, based on what FFCs you decided to use. In this case, for example, I'm using FFCs for 12 bubble projectiles the enemy will use. But you can set up whatever FFCs you like. I strongly reccomend using descriptive names to keep them straight.

    Don't change the ghosted_enemy code, though. That's what is handling boss damage.

    EDIT: Oh, and the boss_flag variable is a global variable I use to stop my custom weapons from slowing the game down when there are dozens of enemies on the screen. You might not need that. You'd need to delete it once here and once again in the enemy death section.

    Code:
    		// --------------------------
    		// Enemy Projectile Setup
    		// --------------------------
    		// We don't have arrays.  We only have 32 FFCs.  So to make 25+ projectiles,
    		// we make a bunch of enemies!
    
    		int first_projectile_enemy_number = Screen->NumNPCs() + 1;
    		int i;
    		npc current_enemy;
    
    		for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 25; i++){
    			
    			current_enemy = Screen->CreateNPC(190);
    			current_enemy->X = -16;				// Hide ze enemy off the screen
    			current_enemy->Y = -16;
    			current_enemy->WeaponDamage = 0;		// Used as Vx
    			current_enemy->BossPal = 0;			// Used as Vy
    			current_enemy->HP = 99999;
    		}
    
    		// So now there are 25 baddies off the screen waiting patiently.
    My most recent breakthrough- using custom enemies as additional projectiles. This gets around the 32 FFC limitation. This is optional - if you don't need dozens of bullets spraying all around, you don't need this bit. But if you do, then you'll notice I'm using WeaponDamage as if it was the enemy's Vx and BossPal as the enemy's Vy. Neither of these variables is actually used by the enemy, as it's a custom Fire-type enemy. Since I can't put negative numbers in these fields, I limit the speed of the enemies to 9 or less. If the speed is set at 10 or higher, then, I know it's actually meant to be a NEGATIVE number. That is, the second significant figure is actually a sign bit.

    Code:
    		while(true){
    
    		// --------------------------
    		// DRAW ENEMY LIFE BAR
    		// --------------------------
    
    		Screen->Rectangle(4,11,9,18,70,108,1,0,0,0,true,128);
    
    		if(ghosted_enemy->HP>=100){
    			Screen->Rectangle(4,11,(71-((62*(ghosted_enemy->HP-100)) / (hit_points-100))),17,70,101,1,0,0,0,true,128);
    		}
    		Screen->DrawTile(3,8,71,15118,1,1,6,1,0,0, 0,0,true,128);
    This script does exactly what it says. It draws a rectangular life bar that goes down in proportion to the hit points of ghosted_enemy (which measures the boss' hit points.) You need to change the value in drawtile (currently 15118) if you want your own custom tile to display at the bottom of the life bar. If you don't want a life bar, you can delete this entirely.

    Code:
    		// --------------------------
    		// ENEMY DAMAGE CONTROL 
    		// --------------------------
    
    			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;						
    
    			}
    			else{
    				ghosted_enemy->X = -16;
    				ghosted_enemy->Y = -16;
    				invuln_counter--;
    				body1->CSet++;
    			}
    
    			// check to see if enemy has been damaged
    			if (prev_health > ghosted_enemy->HP){
    				invuln_counter = 20;
    			}
    		
    			// if hit points are exhausted, enemy explodes
    
    			if ((ghosted_enemy->HP < 100)&&(ghosted_enemy->HP > 0)){
    		
    				boss_flag = false;
    
    				ghosted_enemy->X = -16;
    				ghosted_enemy->Y = -16;
    				ghosted_enemy->HP--;
    				wobble++;
    
    				Screen->Circle(3,this_ffc->X,this_ffc->Y,2*wobble,109,1,0,0,0,true,128);
    				Screen->Circle(3,this_ffc->X,this_ffc->Y,(64*Cos(wobble)),109,1,0,0,0,true,128);
    
    				Screen->Circle(3,this_ffc->X + Rand(48) - 24,this_ffc->Y + Rand(48) - 24,
    				8 + Rand(8),109,1,0,0,0,true,128);
    
    				if(ghosted_enemy->HP == 50) {Game->PlaySound(84);;}
    
    				if(!((this_ffc->Data >= 3756) && (this_ffc->Data <= 3765))){
    
    					Game->PlaySound(88);
    					this_ffc->Data = 3756;
    					body1->Data = 3756;
    					body2->Data = 3756;
    					body3->Data = 3756;
    				}
    
    				for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 72; i++){
    					current_enemy = Screen->LoadNPC(i);
    					current_enemy->HP = 0;
    				}	
    		
    				if(ghosted_enemy->HP<=2){
    					end_boss = Screen->CreateItem(62);
    					end_boss->X = Link->X;
    					end_boss->Y = Link->Y;
    				}
    
    			}
    This section deals with enemy damage and final explosion. If you don't change it, the boss will flash after each hit and be briefly invulnerable. You can de-activate this behavior if you wish by changing these lines:

    if (prev_health > ghosted_enemy->HP){
    invuln_counter = 20;
    }

    so that invuln_counter isn't set so high. On the other hand, you can increase the boss's invulnerability period by increasing the value of invuln_counter.

    You'll also have to add or subtract commands to change CSets for body1, body2, or however many body ffcs you're using.

    Code:
    			if (ghosted_enemy->HP>100){	
    	
    		// --------------------------
    		// ENEMY MOVEMENT (varies per enemy!)
    		// --------------------------
    
    			// Attack State 0
    			// ----------------------------
    			// Loop-de-looping in middle of screen.
    			// Babies swarming, invincible.
    			// ----------------------------
    			
    			if ( attack_state == 0){
    
    				ghosted_enemy->X = -16;
    				ghosted_enemy->Y = -16;
    
    				target_X = 120 + 72*Sin(wobble);
    				target_Y = 72 + 64*Cos(wobble);
    
    				wobble++;
    
    				body1->Data = 3856; 
    				body1->X = this_ffc->X-16;
    				body1->Y = this_ffc->Y-16;
    				body2->Data = 3863;
    				body2->X = this_ffc->X;
    				body2->Y = this_ffc->Y+16;
    				body3->Data = 3867;
    				body3->X = this_ffc->X;
    				body3->Y = this_ffc->Y+32;
    
    				if(this_ffc->X < target_X){this_ffc->Vx = this_ffc->Vx+0.2;}
    				else{this_ffc->Vx = this_ffc->Vx-0.2;}
    				if(this_ffc->Y < target_Y){this_ffc->Vy = this_ffc->Vy+0.2;}
    				else{this_ffc->Vy = this_ffc->Vy-0.2;}
    
    				if(this_ffc->Vx>1){this_ffc->Vx=1;}
    				if(this_ffc->Vx<-1){this_ffc->Vx=-1;}
    				if(this_ffc->Vy>1){this_ffc->Vy=1;}
    				if(this_ffc->Vy<-1){this_ffc->Vy=-1;}
    
    				if(state_counter >= 400){
    					state_counter = 0;
    					wobble = 0;
    					attack_state = 1;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    
    				}else{
    					state_counter++;
    				}	
    
    				// Move babies a swarm around Tentaplus
    
    				for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 25; i++){
    			
    					current_enemy = Screen->LoadNPC(i);
    
    					if(current_enemy->X<this_ffc->X-32){
    						current_enemy->WeaponDamage = 1 + Rand(2);
    					}
    					if(current_enemy->X>this_ffc->X+32){
    						current_enemy->WeaponDamage = 1 + Rand(2) +10;
    					}
    
    					if(current_enemy->Y<this_ffc->Y-32){
    						current_enemy->BossPal = 1 + Rand(2);
    					}
    					if(current_enemy->Y>this_ffc->Y+32){
    						current_enemy->BossPal = 1 + Rand(2) +10;
    					}
    					
    				}
    
    
    			}
    
    			// Attack State 1
    			// ----------------------------
    			// Chasing player in attempt to trap
    			// her in its tentacles.
    			// ----------------------------
    
    			if ( attack_state == 1){
    
    				ghosted_enemy->X = -16;
    				ghosted_enemy->Y = -16;
    
    				target_X = Link->X;
    				target_Y = Link->Y - 32;
    
    				wobble++;
    
    				body1->Data = 3892; 
    				body1->X = this_ffc->X-16;
    				body1->Y = this_ffc->Y-16;
    				body2->Data = 0;
    				body2->X = this_ffc->X;
    				body2->Y = this_ffc->Y+16;
    				body3->Data = 0;
    				body3->X = this_ffc->X;
    				body3->Y = this_ffc->Y+32;
    
    				if(this_ffc->X < target_X){this_ffc->Vx = this_ffc->Vx+0.2;}
    				else{this_ffc->Vx = this_ffc->Vx-0.2;}
    				if(this_ffc->Y < target_Y){this_ffc->Vy = this_ffc->Vy+0.2;}
    				else{this_ffc->Vy = this_ffc->Vy-0.2;}
    
    				if(this_ffc->Vx>1){this_ffc->Vx=1;}
    				if(this_ffc->Vx<-1){this_ffc->Vx=-1;}
    				if(this_ffc->Vy>1){this_ffc->Vy=1;}
    				if(this_ffc->Vy<-1){this_ffc->Vy=-1;}
    
    				if((Abs(this_ffc->X-Link->X)<8)&&(this_ffc->Y<Link->Y)&&(Abs(this_ffc->Y-Link->Y)<32)){
    					attack_state = 2;
    					state_counter = 0;
    					wobble = 0;
    				}
    
    				if(state_counter >= 100){
    					state_counter = 0;
    					wobble = 0;
    					attack_state = 3;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    
    				}else{
    					state_counter++;
    				}	
    
    				// Move babies a swarm around Tentaplus
    
    				for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 25; i++){
    			
    					current_enemy = Screen->LoadNPC(i);
    
    					if(current_enemy->X<this_ffc->X-32){
    						current_enemy->WeaponDamage = 1 + Rand(2);
    					}
    					if(current_enemy->X>this_ffc->X+32){
    						current_enemy->WeaponDamage = 1 + Rand(2) +10;
    					}
    
    					if(current_enemy->Y<this_ffc->Y-32){
    						current_enemy->BossPal = 1 + Rand(2);
    					}
    					if(current_enemy->Y>this_ffc->Y+32){
    						current_enemy->BossPal = 1 + Rand(2) +10;
    					}
    					
    				}
    			}
    
    			// Attack State 2
    			// ----------------------------
    			// Successful!  Player held, her health
    			// decreases while Tentaplus's increases.
    			// ----------------------------
    
    			if ( attack_state == 2){
    
    				ghosted_enemy->X = -16;
    				ghosted_enemy->Y = -16;
    
    				this_ffc->Vx = 0;
    				this_ffc->Vy = 0;
    
    				ghosted_enemy->HP++;
    				if(wobble>=5){
    					wobble = 0;
    					Link->HP--;
    				}else{
    					wobble++;
    				}
    		
    				Link->X = this_ffc->X;
    				Link->Y = this_ffc->Y+32;
    
    				body1->Data = 3904; 
    				body1->X = this_ffc->X-16;
    				body1->Y = this_ffc->Y-16;
    				body2->Data = 3875;
    				body2->X = this_ffc->X;
    				body2->Y = this_ffc->Y+16;
    				body3->Data = 3879;
    				body3->X = this_ffc->X;
    				body3->Y = this_ffc->Y+32;
    
    				if(state_counter >= 100){
    					state_counter = 0;
    					wobble = 0;
    					attack_state = 0;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    				}else{
    					state_counter++;
    				}	
    
    				// Move babies a swarm around Tentaplus
    
    				for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 25; i++){
    			
    					current_enemy = Screen->LoadNPC(i);
    
    					if(current_enemy->X<this_ffc->X-32){
    						current_enemy->WeaponDamage = 1 + Rand(2);
    					}
    					if(current_enemy->X>this_ffc->X+32){
    						current_enemy->WeaponDamage = 1 + Rand(2) +10;
    					}
    
    					if(current_enemy->Y<this_ffc->Y-32){
    						current_enemy->BossPal = 1 + Rand(2);
    					}
    					if(current_enemy->Y>this_ffc->Y+32){
    						current_enemy->BossPal = 1 + Rand(2) +10;
    					}
    					
    				}
    
    			}
    
    			// Attack State 3
    			// ----------------------------
    			// Swoops top or bottom of screen
    			// spraying bubbles.
    			// ----------------------------
    
    			if ( attack_state == 3){
    
    				ghosted_enemy->X = -16;
    				ghosted_enemy->Y = -16;
    
    				target_X = 120 + 60*Sin(3*wobble); 
    				target_Y = 16;
    
    				wobble++;
    
    				body1->Data = 3856; 
    				body1->X = this_ffc->X-16;
    				body1->Y = this_ffc->Y-16;
    				body2->Data = 3863;
    				body2->X = this_ffc->X;
    				body2->Y = this_ffc->Y+16;
    				body3->Data = 3867;
    				body3->X = this_ffc->X;
    				body3->Y = this_ffc->Y+32;
    
    				if(this_ffc->X < target_X){this_ffc->Vx = this_ffc->Vx+0.2;}
    				else{this_ffc->Vx = this_ffc->Vx-0.2;}
    				if(this_ffc->Y < target_Y){this_ffc->Vy = this_ffc->Vy+0.2;}
    				else{this_ffc->Vy = this_ffc->Vy-0.2;}
    
    				if(this_ffc->Vx>2){this_ffc->Vx=2;}
    				if(this_ffc->Vx<-2){this_ffc->Vx=-2;}
    				if(this_ffc->Vy>2){this_ffc->Vy=2;}
    				if(this_ffc->Vy<-2){this_ffc->Vy=-2;}
    
    				if((Abs(this_ffc->X-Link->X)<8)&&(this_ffc->Y<Link->Y)&&(Abs(this_ffc->Y-Link->Y)<32)){
    					attack_state = 2;
    					state_counter = 0;
    					wobble = 0;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    				}
    
    				if((state_counter==25)||(state_counter==85)){
    					bubble1->Data = 3883;
    					bubble1->CSet = original_CSet;
    					bubble1->X = this_ffc->X;
    					bubble1->Y = this_ffc->Y;
    					bubble1->Vx = -0.5;
    					bubble1->Vy = -2;
    
    					bubble7->Data = 3883;
    					bubble7->CSet = original_CSet;
    					bubble7->X = this_ffc->X;
    					bubble7->Y = this_ffc->Y;
    					bubble7->Vx = 0.5;
    					bubble7->Vy = -2;
    
    					Game->PlaySound(89);
    				}
    				if((state_counter==35)||(state_counter==95)){
    					bubble2->Data = 3883;
    					bubble2->CSet = original_CSet;
    					bubble2->X = this_ffc->X;
    					bubble2->Y = this_ffc->Y;
    					bubble2->Vx = 0.5;
    					bubble2->Vy = -2;
    
    					bubble8->Data = 3883;
    					bubble8->CSet = original_CSet;
    					bubble8->X = this_ffc->X;
    					bubble8->Y = this_ffc->Y;
    					bubble8->Vx = -0.5;
    					bubble8->Vy = -2;
    					Game->PlaySound(89);
    				}
    				if((state_counter==45)||(state_counter==105)){
    					bubble3->Data = 3883;
    					bubble3->CSet = original_CSet;
    					bubble3->X = this_ffc->X;
    					bubble3->Y = this_ffc->Y;
    					bubble3->Vx = -0.5;
    					bubble3->Vy = -2;
    
    					bubble9->Data = 3883;
    					bubble9->CSet = original_CSet;
    					bubble9->X = this_ffc->X;
    					bubble9->Y = this_ffc->Y;
    					bubble9->Vx = 0.5;
    					bubble9->Vy = -2;
    					Game->PlaySound(89);
    				}
    				if((state_counter==55)||(state_counter==115)){
    					bubble4->Data = 3883;
    					bubble4->CSet = original_CSet;
    					bubble4->X = this_ffc->X;
    					bubble4->Y = this_ffc->Y;
    					bubble4->Vx = 0.5;
    					bubble4->Vy = -2;
    
    					bubble10->Data = 3883;
    					bubble10->CSet = original_CSet;
    					bubble10->X = this_ffc->X;
    					bubble10->Y = this_ffc->Y;
    					bubble10->Vx = -0.5;
    					bubble10->Vy = -2;
    					Game->PlaySound(89);
    				}
    				if((state_counter==65)||(state_counter==125)){
    					bubble5->Data = 3883;
    					bubble5->CSet = original_CSet;
    					bubble5->X = this_ffc->X;
    					bubble5->Y = this_ffc->Y;
    					bubble5->Vx = -0.5;
    					bubble5->Vy = -2;
    
    					bubble11->Data = 3883;
    					bubble11->CSet = original_CSet;
    					bubble11->X = this_ffc->X;
    					bubble11->Y = this_ffc->Y;
    					bubble11->Vx = 0.5;
    					bubble11->Vy = -2;
    					Game->PlaySound(89);
    				}
    				if((state_counter==75)||(state_counter==135)){
    					bubble6->Data = 3883;
    					bubble6->CSet = original_CSet;
    					bubble6->X = this_ffc->X;
    					bubble6->Y = this_ffc->Y;
    					bubble6->Vx = 0.5;
    					bubble6->Vy = -2;
    
    					bubble12->Data = 3883;
    					bubble12->CSet = original_CSet;
    					bubble12->X = this_ffc->X;
    					bubble12->Y = this_ffc->Y;
    					bubble12->Vx = -0.5;
    					bubble12->Vy = -2;
    					Game->PlaySound(89);
    				}
    
    				if(state_counter >= 150){
    					state_counter = 0;
    					wobble = 0;
    					attack_state = 0;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    
    				}else{
    					state_counter++;
    				}	
    
    				// Move babies a swarm around Tentaplus
    
    				for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 25; i++){
    			
    					current_enemy = Screen->LoadNPC(i);
    
    					if(current_enemy->X<this_ffc->X-32){
    						current_enemy->WeaponDamage = 1 + Rand(2);
    					}
    					if(current_enemy->X>this_ffc->X+32){
    						current_enemy->WeaponDamage = 1 + Rand(2) +10;
    					}
    
    					if(current_enemy->Y<this_ffc->Y-32){
    						current_enemy->BossPal = 1 + Rand(2);
    					}
    					if(current_enemy->Y>this_ffc->Y+32){
    						current_enemy->BossPal = 1 + Rand(2) +10;
    					}
    					
    				}
    
    			}
    
    			// Attack State 4
    			// ----------------------------
    			// Hit by torpedo! Babies scatter
    			// and Tentaplus is vulnerable.
    			// ----------------------------
    
    			if ( attack_state == 4){
    
    				ghosted_enemy->X = this_ffc->X;
    				ghosted_enemy->Y = this_ffc->Y;
    
    				this_ffc->Vx = 0;
    				this_ffc->Vy = 0;
    
    				body1->Data = 3868; 
    				body1->X = this_ffc->X-16;
    				body1->Y = this_ffc->Y-16;
    				body2->Data = 0;
    				body2->X = this_ffc->X;
    				body2->Y = this_ffc->Y+16;
    				body3->Data = 0;
    				body3->X = this_ffc->X;
    				body3->Y = this_ffc->Y+32;
    
    				if(state_counter >= 200){
    					state_counter = 0;
    					wobble = 0;
    					attack_state = 5;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    
    				}else{
    					state_counter++;
    				}	
    
    			}
    
    			// Attack State 5
    			// ----------------------------
    			// Recovering from torpedo hit; 
    			// babies returning.
    			// ----------------------------
    
    			if ( attack_state == 5){
    
    				ghosted_enemy->X = this_ffc->X;
    				ghosted_enemy->Y = this_ffc->Y;
    
    				this_ffc->Vx = 0;
    				this_ffc->Vy = 0;
    
    				body1->Data = 3868; 
    				body1->X = this_ffc->X-16;
    				body1->Y = this_ffc->Y-16;
    				body2->Data = 0;
    				body2->X = this_ffc->X;
    				body2->Y = this_ffc->Y+16;
    				body3->Data = 0;
    				body3->X = this_ffc->X;
    				body3->Y = this_ffc->Y+32;
    
    				if(state_counter >= 100){
    					state_counter = 0;
    					wobble = 0;
    					attack_state = 0;
    					this_ffc->Vx = 0;
    					this_ffc->Vy = 0;
    
    				}else{
    					state_counter++;
    				}	
    
    				for(i = first_projectile_enemy_number; i < first_projectile_enemy_number + 25; i++){
    			
    					current_enemy = Screen->LoadNPC(i);
    
    					if(current_enemy->X<this_ffc->X-32){
    						current_enemy->WeaponDamage = 1 + Rand(2);
    					}
    					if(current_enemy->X>this_ffc->X+32){
    						current_enemy->WeaponDamage = 1 + Rand(2) +10;
    					}
    
    					if(current_enemy->Y<this_ffc->Y-32){
    						current_enemy->BossPal = 1 + Rand(2);
    					}
    					if(current_enemy->Y>this_ffc->Y+32){
    						current_enemy->BossPal = 1 + Rand(2) +10;
    					}
    					
    				}
    
    			}
    Ah, the enemy movement section. This is truly the meat and potatoes of the custom boss code. You need to tell the enemy how to move and what to do. I like to start by organizing the boss behavior into "attack states." How you break it down is kind of arbitrary, but thinking about the attack in states will help organize your code. I start by putting in the comments you see at the start of each attack state, telling me generally how the enemy is going to act. Then, for each state, go back and enter code describing how the FFCs and any NPCs move during each state, when the state ends (does it end after a certain number of tics of state_counter? Does it end when the enemy catches the player? When the enemy is damaged?) and what state it goes to next.

    Notice that for any attack_state in which you want the enemy to be vulnerable, you need to move ghosted_enemy to the boss' vulnerable point. When the boss is not vulnerable, move ghosted_enemy to -16,-16, where it will be safe from harm.

    EDIT - One other note. For each attack state, the boss' graphics need to be set to match. If the boss is attacking, it might look different from when it's jumping. I've taken to just loading my combos directly (body1->Data = 1234; for instance). It might be better practice to load the combos in variables so they can be changed more easily. For now, you have to change the combo numbers assigned directly in the code.

  4. #4
    Wizrobe C-Dawg's Avatar
    Join Date
    Jan 2002
    Posts
    4,205
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    6,611
    Level
    24
    vBActivity - Bars
    Lv. Percent
    99.9%

    Re: Custom Bosses and You

    Code:
    			// Move Babies
    			// ---------------------------
    
    				for(i = first_projectile_enemy_number-1; i < first_projectile_enemy_number + 25; i++){
    			
    					current_enemy = Screen->LoadNPC(i);
    
    					if(current_enemy->WeaponDamage > 10){
    						if((current_enemy->X -(current_enemy->WeaponDamage-10))>-16){
    							current_enemy->X = current_enemy->X -(current_enemy->WeaponDamage-10);
    						}
    					}else{
    						if((current_enemy->X +(current_enemy->WeaponDamage))<256){
    							current_enemy->X = current_enemy->X +(current_enemy->WeaponDamage);
    						}
    					}
    
    					if(current_enemy->BossPal > 10){
    						if((current_enemy->Y -(current_enemy->BossPal-10))>-16){
    							current_enemy->Y = current_enemy->Y -(current_enemy->BossPal-10);
    						}
    					}else{
    						if((current_enemy->Y +(current_enemy->BossPal))<176){
    							current_enemy->Y = current_enemy->Y +(current_enemy->BossPal);
    						}
    					}						
    				}
    
    			// Move Bubbles
    			// ---------------------------
    
    			bubble1->Vy = bubble1->Vy + 0.2;
    			if(bubble1->Vy > 2){bubble1->Vy = 2;}
    			if(bubble1->Y>260){bubble1->Y=-16;}
    			bubble2->Vy = bubble2->Vy + 0.2;
    			if(bubble2->Vy > 2){bubble2->Vy = 2;}
    			if(bubble2->Y>260){bubble2->Y=-16;}
    			bubble3->Vy = bubble3->Vy + 0.2;
    			if(bubble3->Vy > 2){bubble3->Vy = 2;}
    			if(bubble3->Y>260){bubble3->Y=-16;}
    			bubble4->Vy = bubble4->Vy + 0.2;
    			if(bubble4->Vy > 2){bubble4->Vy = 2;}
    			if(bubble4->Y>260){bubble4->Y=-16;}
    			bubble5->Vy = bubble5->Vy + 0.2;
    			if(bubble5->Vy > 2){bubble5->Vy = 2;}
    			if(bubble5->Y>260){bubble5->Y=-16;}
    			bubble6->Vy = bubble6->Vy + 0.2;
    			if(bubble6->Vy > 2){bubble6->Vy = 2;}
    			if(bubble6->Y>260){bubble6->Y=-16;}
    			bubble7->Vy = bubble7->Vy + 0.2;
    			if(bubble7->Vy > 2){bubble7->Vy = 2;}
    			if(bubble7->Y>260){bubble7->Y=-16;}
    			bubble8->Vy = bubble8->Vy + 0.2;
    			if(bubble8->Vy > 2){bubble8->Vy = 2;}
    			if(bubble8->Y>260){bubble8->Y=-16;}
    			bubble9->Vy = bubble9->Vy + 0.2;
    			if(bubble9->Vy > 2){bubble9->Vy = 2;}
    			if(bubble9->Y>260){bubble9->Y=-16;}
    			bubble10->Vy = bubble10->Vy + 0.2;
    			if(bubble10->Vy > 2){bubble10->Vy = 2;}
    			if(bubble10->Y>260){bubble10->Y=-16;}
    			bubble11->Vy = bubble11->Vy + 0.2;
    			if(bubble11->Vy > 2){bubble11->Vy = 2;}
    			if(bubble11->Y>260){bubble11->Y=-16;}
    			bubble12->Vy = bubble12->Vy + 0.2;
    			if(bubble12->Vy > 2){bubble12->Vy = 2;}
    			if(bubble12->Y>260){bubble12->Y=-16;}
    
    			// Move Torpedo (and handle explosion)
    			// ---------------------------
    
    			if(torpedo_counter <= 1){
    				torpedo_counter = 250;
    				if(torpedo1->X<0){
    					torpedo1->Data = 3871;
    					if(Rand(2)<1){
    						if(Rand(2)<1){
    							torpedo1->X=16; torpedo1->Y=32;
    						}else{
    							torpedo1->X=224; torpedo1->Y=32;
    						}
    					}else{
    						if(Rand(2)<1){
    							torpedo1->X=16; torpedo1->Y=128;
    						}else{
    							torpedo1->X=224; torpedo1->Y=128;
    						}
    					}
    				}else{
    					if(torpedo2->X<0){
    						torpedo2->Data = 3871;
    						if(Rand(2)<1){
    							if(Rand(2)<1){
    								torpedo2->X=16; torpedo2->Y=32;
    							}else{
    								torpedo2->X=224; torpedo2->Y=32;
    							}
    						}else{
    							if(Rand(2)<1){
    								torpedo2->X=16; torpedo2->Y=128;
    							}else{
    								torpedo2->X=224; torpedo2->Y=128;
    							}
    						}
    					}else{
    						if(torpedo3->X<0){
    							torpedo3->Data = 3871;
    							if(Rand(2)<1){
    								if(Rand(2)<1){
    									torpedo3->X=16; torpedo3->Y=32;
    								}else{
    									torpedo3->X=224; torpedo3->Y=32;
    								}
    							}else{
    								if(Rand(2)<1){
    									torpedo3->X=16; torpedo3->Y=128;
    								}else{
    									torpedo3->X=224; torpedo3->Y=128;
    								}
    							}
    						}
    					}
    				}
    
    			}else{
    				torpedo_counter--;
    			}
    
    			if((torpedo1->X>0)&&(torpedo1->Data==3871)){
    
    				if(torpedo1->X<Link->X){torpedo1->Vx = torpedo1->Vx+0.1;}
    				else{torpedo1->Vx = torpedo1->Vx-0.1;}
    				if(torpedo1->Y<Link->Y){torpedo1->Vy = torpedo1->Vy+0.1;}
    				else{torpedo1->Vy = torpedo1->Vy-0.1;}
    
    				if(torpedo1->Vx > 1){torpedo1->Vx=1;}
    				if(torpedo1->Vx < -1){torpedo1->Vx=-1;}
    				if(torpedo1->Vy > 1){torpedo1->Vy=1;}
    				if(torpedo1->Vy < -1){torpedo1->Vy=-1;}
    
    				if(((Abs(torpedo1->X-Link->X)<16)&&(Abs(torpedo1->Y-Link->Y)<16)) || ((Abs(torpedo1->X-this_ffc->X)<16)&&(Abs(torpedo1->Y-this_ffc->Y)<16)) ){
    			
    					torpedo1->Data = 3887;
    					torpedo_explosion1_counter = 50;
    					Game->PlaySound(84);
    					torpedo1->Vx = 0;
    					torpedo1->Vy = 0;
    
    					if((Abs(torpedo1->X-this_ffc->X)<24)&&(Abs(torpedo1->Y-this_ffc->Y)<24)){
    						attack_state = 4;
    						state_counter = 0;
    						Game->PlaySound(69);
    					}
    					
    				}
    			}
    
    			if(torpedo1->Data == 3887){
    
    					if(torpedo_explosion1_counter <= 0){torpedo1->Data = 0;torpedo1->X=-16;}
    					else{torpedo_explosion1_counter--;}
    
    					Screen->Circle(3,torpedo1->X,torpedo1->Y,torpedo_explosion1_counter,109,1,0,0,0,true,128);
    					Screen->Circle(3,torpedo1->X + Rand(48) - 24,torpedo1->Y + Rand(48) - 24,8 + Rand(8),109,1,0,0,0,true,128);
    
    					if( (Abs(torpedo1->X - Link->X) < 24) && (Abs(torpedo1->Y - Link->Y) < 24) ){
    						ghosted_damage_enemy->X = Link->X;
    						ghosted_damage_enemy->Y = Link->Y;
    					}	
    					else{
    						ghosted_damage_enemy->X = -16;
    						ghosted_damage_enemy->Y = -16;
    					}
    			}
    
    			if((torpedo2->X>0)&&(torpedo2->Data==3871)){
    
    				if(torpedo2->X<Link->X){torpedo2->Vx = torpedo2->Vx+0.1;}
    				else{torpedo2->Vx = torpedo2->Vx-0.1;}
    				if(torpedo2->Y<Link->Y){torpedo2->Vy = torpedo2->Vy+0.1;}
    				else{torpedo2->Vy = torpedo2->Vy-0.1;}
    
    				if(torpedo2->Vx > 1){torpedo2->Vx=1;}
    				if(torpedo2->Vx < -1){torpedo2->Vx=-1;}
    				if(torpedo2->Vy > 1){torpedo2->Vy=1;}
    				if(torpedo2->Vy < -1){torpedo2->Vy=-1;}
    
    				if( ((Abs(torpedo2->X-Link->X)<16)&&(Abs(torpedo2->Y-Link->Y)<16)) || ((Abs(torpedo2->X-this_ffc->X)<16)&&(Abs(torpedo2->Y-this_ffc->Y)<16))){
    			
    					torpedo2->Data = 3887;
    					torpedo_explosion2_counter = 50;
    					Game->PlaySound(84);
    					torpedo2->Vx = 0;
    					torpedo2->Vy = 0;
    
    					if((Abs(torpedo2->X-this_ffc->X)<24)&&(Abs(torpedo2->Y-this_ffc->Y)<24)){
    						attack_state = 4;
    						state_counter = 0;
    						Game->PlaySound(69);
    					}
    					
    				}
    			}
    
    			if(torpedo2->Data == 3887){
    
    					if(torpedo_explosion2_counter <= 0){torpedo2->Data = 0;torpedo2->X=-16;}
    					else{torpedo_explosion2_counter--;}
    
    					Screen->Circle(3,torpedo2->X,torpedo2->Y,torpedo_explosion2_counter,109,1,0,0,0,true,128);
    					Screen->Circle(3,torpedo2->X + Rand(48) - 24,torpedo2->Y + Rand(48) - 24,8 + Rand(8),109,1,0,0,0,true,128);
    
    					if( (Abs(torpedo2->X - Link->X) < 24) && (Abs(torpedo2->Y - Link->Y) < 24)){
    						ghosted_damage_enemy->X = Link->X;
    						ghosted_damage_enemy->Y = Link->Y;
    					}	
    					else{
    						ghosted_damage_enemy->X = -16;
    						ghosted_damage_enemy->Y = -16;
    					}
    			}
    
    			if((torpedo3->X>0)&&(torpedo3->Data==3871)){
    
    				if(torpedo3->X<Link->X){torpedo3->Vx = torpedo3->Vx+0.1;}
    				else{torpedo3->Vx = torpedo3->Vx-0.1;}
    				if(torpedo3->Y<Link->Y){torpedo3->Vy = torpedo3->Vy+0.1;}
    				else{torpedo3->Vy = torpedo3->Vy-0.1;}
    
    				if(torpedo3->Vx > 1){torpedo3->Vx=1;}
    				if(torpedo3->Vx < -1){torpedo3->Vx=-1;}
    				if(torpedo3->Vy > 1){torpedo3->Vy=1;}
    				if(torpedo3->Vy < -1){torpedo3->Vy=-1;}
    
    				if( ((Abs(torpedo3->X-Link->X)<16)&&(Abs(torpedo3->Y-Link->Y)<16)) || ((Abs(torpedo3->X-this_ffc->X)<16)&&(Abs(torpedo3->Y-this_ffc->Y)<16))){
    			
    					torpedo3->Data = 3887;
    					torpedo_explosion3_counter = 50;
    					Game->PlaySound(84);
    					torpedo3->Vx = 0;
    					torpedo3->Vy = 0;
    
    					if((Abs(torpedo3->X-this_ffc->X)<24)&&(Abs(torpedo3->Y-this_ffc->Y)<24)){
    						attack_state = 4;
    						state_counter = 0;
    						Game->PlaySound(69);
    					}
    					
    				}
    			}
    
    			if(torpedo3->Data == 3887){
    
    					if(torpedo_explosion3_counter <= 0){torpedo3->Data = 0;torpedo3->X=-16;}
    					else{torpedo_explosion3_counter--;}
    
    					Screen->Circle(3,torpedo3->X,torpedo3->Y,torpedo_explosion3_counter,109,1,0,0,0,true,128);
    					Screen->Circle(3,torpedo3->X + Rand(48) - 24,torpedo3->Y + Rand(48) - 24,8 + Rand(8),109,1,0,0,0,true,128);
    
    					if( (Abs(torpedo3->X - Link->X) < 24) && (Abs(torpedo3->Y - Link->Y) < 24)){
    						ghosted_damage_enemy->X = Link->X;
    						ghosted_damage_enemy->Y = Link->Y;
    					}	
    					else{
    						ghosted_damage_enemy->X = -16;
    						ghosted_damage_enemy->Y = -16;
    					}
    			}
    	
    			} // end of movement
    Sometimes you want additional code to move seperate pieces of the boss around while the main boss is going through it's attack_states. So here, the torpedoes, bubbles, and baby tentaplus' move around on their own, independent of the state.

    Code:
    		// --------------------
    		// 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
    The last bit just does some minimal cleanup and includes canMove, which I use alot for custom enemy code.

    If you want to see more examples of boss behavior, check out Zodiac, unpassworded, in the Quest Announcement Forum.

  5. #5
    Keese ScaryBinary's Avatar
    Join Date
    Dec 2006
    Age
    49
    Posts
    94
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    916
    Level
    10
    vBActivity - Bars
    Lv. Percent
    51.79%

    Re: Custom Bosses and You

    Wow. Awesome job. I didn't try it out yet, but just by looking at the code...that's some ingenious stuff there, and it's a great example for dweebs like me who haven't messed with custom bosses too much yet. Well done.

  6. #6
    Wizrobe C-Dawg's Avatar
    Join Date
    Jan 2002
    Posts
    4,205
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    6,611
    Level
    24
    vBActivity - Bars
    Lv. Percent
    99.9%

    Re: Custom Bosses and You

    From your surprise, I take it you haven't been keeping up with Zodiac's development, eh?

  7. #7
    Keese ScaryBinary's Avatar
    Join Date
    Dec 2006
    Age
    49
    Posts
    94
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    916
    Level
    10
    vBActivity - Bars
    Lv. Percent
    51.79%

    Re: Custom Bosses and You

    Quote Originally Posted by C-Dawg View Post
    From your surprise, I take it you haven't been keeping up with Zodiac's development, eh?
    I have to admit I'm typically off in my own little world.

    I'm downloading Zodiac now! Screenshots look wicked.

  8. #8
    I shall exalt myself over all Armagedddon Games bigjoe's Avatar
    Join Date
    Apr 2000
    Age
    39
    Posts
    5,621
    Mentioned
    87 Post(s)
    Tagged
    6 Thread(s)
    vBActivity - Stats
    Points
    6,573
    Level
    24
    vBActivity - Bars
    Lv. Percent
    93.52%

    Re: Custom Bosses and You

    It's good to see that advanced enemies and bosses can now be completely independent of warp related trickery.

    I was playing Zodiac, by the way, and noticed that you have some enemies which appear to be connected to a regular enemy, but are larger than 16x16. Can you identify which script handles that? Enemies that are larger than 16x16 will be essential in the quest that I am working on, as they fit better with LTTP Style Big Link.


  9. #9
    Wizrobe C-Dawg's Avatar
    Join Date
    Jan 2002
    Posts
    4,205
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    6,611
    Level
    24
    vBActivity - Bars
    Lv. Percent
    99.9%

    Re: Custom Bosses and You

    Same way I do bosses. The only difference between normal scripted enemies of any size and bosses is: 1. life bar and 2. death animation. Normal enemies are usually less complex, but they dont have to be.

    Any script in Zodiac ending is CE is a custom enemy. Some of the earlier ones like bouncer_ce are designed and already set up to be a 2x2 enemy and you don't have to do any work on the setup. You might check those out.

    By the way, for those interested, getting a custom boss from drawing board to perfect functioning takes about 2 or 3 hours now. So there's no excuse for not learning to script anymore!

  10. #10
    Wizrobe
    Join Date
    Dec 2006
    Age
    29
    Posts
    3,693
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    8,935
    Level
    28
    vBActivity - Bars
    Lv. Percent
    42.97%

    Re: Custom Bosses and You

    Wow, I have to look at that script!
    Quote Originally Posted by rock_nog View Post
    Well of course eveything's closed for Easter - don't you know of the great Easter tradition of people barricading themselves up to protect themselves from the return of Zombie Christ?


Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
About us
Armageddon Games is a game development group founded in 1997. We are extremely passionate about our work and our inspirations are mostly drawn from games of the 8-bit and 16-bit era.
Social