Esempio n. 1
0
void ai_black_lightning(Object *o)
{
  ANIMATE(0, 0, 1);
  o->yinertia = 0x1000;

  if (o->blockd)
  {
    effect(o->CenterX(), o->Bottom(), EFFECT_BOOMFLASH);
    SmokeXY(o->CenterX(), o->Bottom(), 3, o->Width() / CSFI, 4);
    o->Delete();
  }
}
Esempio n. 2
0
void ai_counter_bomb(Object *o)
{
	/*debug("state: %d", o->state);
	debug("timer: %d", o->timer);
	debug("timer2: %d", o->timer2);*/
	
	switch(o->state)
	{
		case 0:
		{
			o->state = 1;
			o->ymark = o->y;
			
			o->timer = random(0, 50);
			o->timer2 = 0;
		}
		case 1:
		{	// desync if multiple enemies
			if (--o->timer < 0)
			{
				o->timer = 0;
				o->state = 2;
				o->yinertia = 0x300;
			}
		}
		break;
		
		case 2:		// ready
		{
			if (pdistlx(80 << CSF) || o->shaketime)
			{
				o->state = 3;
				o->timer = 0;
			}
		}
		break;
		
		case 3:		// counting down...
		{
			if (--o->timer < 0)
			{
				if (o->timer2 < 5)
				{
					Object *number = CreateObject(o->CenterX() + (8 << CSF), \
												  o->y + (16 << CSF), \
												  OBJ_COUNTER_BOMB_NUMBER);
					
					number->frame = o->timer2++;
					o->timer = 60;
				}
				else
				{
					// expand bounding box to cover explosion area
					o->x = o->CenterX();
					o->y = o->CenterY();
					o->invisible = true;
					o->sprite = SPR_BBOX_PUPPET_1;
					sprites[o->sprite].bbox.x1 = -128;
					sprites[o->sprite].bbox.y1 = -100;
					sprites[o->sprite].bbox.x2 = 128;
					sprites[o->sprite].bbox.y2 = 100;
					o->damage = 30;
					
					o->yinertia = 0;
					o->state = 4;
					
					// make kaboom
					sound(SND_EXPLOSION1);
					quake(20);
					SmokeXY(o->CenterX(), o->CenterY(), 100, 128, 100);
					
					return;
				}
			}
		}
		break;
		
		case 4:		// exploding (one frame only to give time for bbox to damage player)
			o->Delete();
			return;
	}
	
	ANIMATE(4, 0, 2);
	
	if (o->state == 2 || o->state == 3)
	{
		o->yinertia += (o->y > o->ymark) ? -0x10 : 0x10;
		LIMITY(0x100);
	}
}
Esempio n. 3
0
void ai_deleet(Object *o)
{
	// trigger counter
	if (o->hp < (1000 - DELEET_HP) && o->state < 2)
	{
		o->state = 2;
		o->timer = 0;
		o->frame = 2;
		
		o->flags |= FLAG_INVULNERABLE;
		sound(SND_CHEST_OPEN);
	}
	
	switch(o->state)
	{
		case 0:
		{
			o->state = 1;
			o->x += (TILE_W / 2) << CSF;
			o->y += (TILE_H / 2) << CSF;
			
			if (o->dir == LEFT)
				o->y += (8<<CSF);
			else
				o->x += (8<<CSF);
		}
		case 1:
		{
			if (o->shaketime)
				o->timer2++;
			else
				o->timer2 = 0;
			
			o->frame = (o->timer2 & 2) ? 1 : 0;
		}
		break;
		
		case 2:
		{
			int counter = -1;
			
			switch(o->timer)
			{
				case 0:		counter = 0; break;	// 5
				case 50:	counter = 1; break;	// 4
				case 100:	counter = 2; break;	// 3
				case 150:	counter = 3; break;	// 2
				case 200:	counter = 4; break;	// 1
				
				case 250:
				{
					o->state = 3;
					o->sprite = SPR_BBOX_PUPPET_1;
					o->invisible = true;
					
					sprites[o->sprite].bbox.x1 = -48;
					sprites[o->sprite].bbox.x2 = 48;
					sprites[o->sprite].bbox.y1 = -48;
					sprites[o->sprite].bbox.y2 = 48;
					o->damage = 12;
					
					quake(10);
					SmokeXY(o->x, o->y, 40, 48, 48);
					
					o->flags &= ~FLAG_SHOOTABLE;
					o->flags &= ~FLAG_INVULNERABLE;
					
					if (o->dir == LEFT)
					{
						int x = (o->x >> CSF) / TILE_W;
						int y = ((o->y >> CSF) - 8) / TILE_H;
						
						map.tiles[x][y] = 0;
						map.tiles[x][y+1] = 0;
					}
					else
					{
						int x = ((o->x >> CSF) - 8) / TILE_W;
						int y = (o->y >> CSF) / TILE_H;
						
						map.tiles[x][y] = 0;
						map.tiles[x+1][y] = 0;
					}
					
				}
				break;
			}
			
			if (counter != -1)
			{
				CreateObject(o->x, o->y - (8<<CSF), \
						OBJ_COUNTER_BOMB_NUMBER)->frame = counter;
			}
			
			o->timer++;
		}
Esempio n. 4
0
void CoreBoss::Run()
{
bool do_thrust = false;
int i;

	if (!o) return;
	//stat("state = %d", o->state);
	
	switch(o->state)
	{
		case CORE_SLEEP:	break;			// core is asleep
		
		// Core's mouth is closed.
		// Core targets player point but does not update it during the state.
		// This is also the state set via BOA to awaken the core.
		case CORE_CLOSED:
		{
			o->state = CORE_CLOSED+1;
			o->timer = 0;
			
			StopWaterStream();
			o->xmark = player->x;
			o->ymark = player->y;
		}
		case CORE_CLOSED+1:
		{
			// open mouth after 400 ticks
			if (o->timer > 400)
			{
				if (++o->timer2 > 3)
				{	// every 3rd time do gusting left and big core blasts
					o->timer2 = 0;
					o->state = CORE_GUST;
				}
				else
				{
					o->state = CORE_OPEN;
				}
				
				do_thrust = true;
			}
		}
		break;
		
		// Core's mouth is open.
		// Core moves towards player, and updates the position throughout
		// the state (is "aggressive" about seeking him).
		// Core fires ghosties, and curly targets it.
		case CORE_OPEN:
		{
			o->state = CORE_OPEN+1;
			o->timer = 0;
			// gonna open mouth, so save the current HP so we'll
			// know how much damage we've taken this time.
			o->savedhp = o->hp;
		}
		case CORE_OPEN+1:
		{
			o->xmark = player->x;
			o->ymark = player->y;
			
			// must call constantly for red-flashing when hit
			OPEN_MOUTH;
			
			// hint curly to target us
			if ((o->timer % 64) == 1)
			{
				o->CurlyTargetHere();
			}
			
			// spawn ghosties
			if (o->timer < 200)
			{
				if ((o->timer % 20)==0)
				{
					CreateObject(o->x + (random(-48, -16) << CSF), \
						     	 o->y + (random(-64, 64) << CSF), \
							 	 OBJ_CORE_GHOSTIE);
				}
			}
			
			// close mouth when 400 ticks have passed or we've taken more than 200 damage
			if (o->timer > 400 || (o->savedhp - o->hp) >= 200)
			{
				o->state = CORE_CLOSED;
				CLOSE_MOUTH;
				do_thrust = true;
			}
		}
		break;
		
		
		case CORE_GUST:
		{
			o->state = CORE_GUST+1;
			o->timer = 0;
			
			StartWaterStream();
		}
		case CORE_GUST+1:
		{
			// spawn water droplet effects and push player
			Object *droplet = CreateObject(player->x + ((random(-50, 150)<<CSF)*2), \
								   		   player->y + (random(-160, 160)<<CSF),
								   		   OBJ_FAN_DROPLET);
			droplet->dir = LEFT;
			player->xinertia -= 0x20;
			
			OPEN_MOUTH;
			
			// spawn the big white blasts
			if (o->timer==300 || o->timer==350 || o->timer==400)
			{
				EmFireAngledShot(pieces[CFRONT], OBJ_CORE_BLAST, 0, 3<<CSF);
				sound(SND_LIGHTNING_STRIKE);
			}
			
			if (o->timer > 400)
			{
				o->state = CORE_CLOSED;
				CLOSE_MOUTH;
				do_thrust = true;
			}
		}
		break;
		
		
		case 500:		// defeated!!
		{
			StopWaterStream();
			map.wlforcestate = WL_CALM;
			
			o->state = 501;
			o->timer = 0;
			o->xinertia = o->yinertia = 0;
			game.curlytarget.timeleft = 0;
			
			CLOSE_MOUTH;
			
			game.quaketime = 20;
			SmokeXY(pieces[CBACK]->x, pieces[CBACK]->CenterY(), 20, 128, 64);
			
			// tell all the MC's to retreat
			for(i=0;i<5;i++)
			{
				pieces[i]->flags &= ~(FLAG_SHOOTABLE & FLAG_INVULNERABLE);
				pieces[i]->state = MC_RETREAT;
			}
		}
		case 501:
		{
			o->timer++;
			if ((o->timer & 0x0f) != 0)
			{
				SmokeXY(pieces[CBACK]->x, pieces[CBACK]->CenterY(), 1, 64, 32);
			}
			
			if (o->timer & 2)
				o->x -= (1 << CSF);
			else
				o->x += (1 << CSF);
			
			#define CORE_DEATH_TARGET_X		0x7a000
			#define CORE_DEATH_TARGET_Y		0x16000
			o->xinertia += (o->x > CORE_DEATH_TARGET_X) ? -0x80 : 0x80;
			o->yinertia += (o->y > CORE_DEATH_TARGET_Y) ? -0x80 : 0x80;
		}
		break;
		
		case 600:			// teleported away by Misery
		{
			o->xinertia = 0;
			o->yinertia = 0;
			o->state++;
			//sound(SND_TELEPORT);
			
			pieces[CFRONT]->clip_enable = pieces[CBACK]->clip_enable = 1;
			o->timer = sprites[pieces[CFRONT]->sprite].h;
		}
		case 601:
		{
			pieces[CFRONT]->display_xoff = pieces[CBACK]->display_xoff = random(-8, 8);
			
			pieces[CFRONT]->clipy2 = o->timer;
			pieces[CBACK]->clipy2 = o->timer;
			
			if (--o->timer < 0)
			{
				pieces[CFRONT]->invisible = true;
				pieces[CBACK]->invisible = true;
				
				// restore status bars
				game.stageboss.object = NULL;
				game.bossbar.object = NULL;
				o->Delete(); o = NULL;
				return;
			}
		}
		break;
	}
	
	
	if (do_thrust)
	{
		// tell all the minicores to jump to a new position
		for(i=0;i<5;i++)
		{
			pieces[i]->state = MC_THRUST;
		}
		
		quake(20);
		sound(SND_CORE_THRUST);
	}
	
	
	// fire the minicores in any awake non-dead state
	if (o->state >= CORE_CLOSED && o->state < 500)
	{
		o->timer++;
		
		// fire off each minicore sequentially...
		switch(o->timer)
		{
			case 80+0:   pieces[0]->state = MC_CHARGE_FIRE; break;
			case 80+30:  pieces[1]->state = MC_CHARGE_FIRE; break;
			case 80+60:  pieces[2]->state = MC_CHARGE_FIRE; break;
			case 80+90:  pieces[3]->state = MC_CHARGE_FIRE; break;
			case 80+120: pieces[4]->state = MC_CHARGE_FIRE; break;
		}
		
		// move main core towards a spot in front of target
		o->xinertia += (o->x > (o->xmark + (160<<CSF))) ? -4 : 4;
		o->yinertia += (o->y > o->ymark - (o->Height() / 2)) ? -4 : 4;
	}
	
	// set up our shootable status--you never actually hit the core (CFRONT),
	// but if it's mouth is open, make us, the invisible controller object, shootable.
	if (pieces[CFRONT]->frame==2)
	{
		o->flags &= ~FLAG_SHOOTABLE;
		pieces[CFRONT]->flags |= FLAG_INVULNERABLE;
	}
	else
	{
		o->flags |= FLAG_SHOOTABLE;
		pieces[CFRONT]->flags &= ~FLAG_INVULNERABLE;
	}
	
	LIMITX(0x80);
	LIMITY(0x80);
}
Esempio n. 5
0
// spawn a cloud of smoke centered around object o and starting within "range" distance.
void SmokeClouds(Object *o, int nclouds, int rangex, int rangey, Object *push_behind)
{
	SmokeXY(o->CenterX(), o->CenterY(), nclouds, rangex, rangey, push_behind);
}
// handles his "looping" flight/rush attacks
static void run_flight(Object *o)
{
	switch(o->state)
	{
		// flying left or right
		case BP_FLY_LR:
		{
			o->state++;
			o->animtimer = 0;
			o->frame = 6;		// flying horizontally
			
			o->yinertia = 0;
			o->damage = DMG_RUSH;
			
			FACEPLAYER;
			XMOVE(RUSH_SPEED);
		}
		case BP_FLY_LR+1:
		{
			ANIMATE(1, 6, 7);
			
			// smacked into wall?
			if ((o->blockl && o->dir == LEFT) || \
				(o->blockr && o->dir == RIGHT))
			{
				o->xinertia = 0;
				o->state = BP_HIT_WALL;
				o->damage = DMG_NORMAL;
				o->timer = 0;
				megaquake(10);
			}
			
			// reached player?
			// this has to be AFTER smacked-into-wall check for proper behavior
			// if player stands in spikes at far left/right of arena.
			if (pdistlx(RUSH_DIST))
				o->state = BP_PREPARE_FLY_UD;
		}
		break;
		
		// smacked into wall while flying L/R
		case BP_HIT_WALL:
		{
			o->frame = 6;
			
			if (++o->timer > 30)
			{
				if (o->timer2 <= 3)
					o->state = BP_PREPARE_FLY_LR;
				else
					o->state = BP_RETURN_TO_GROUND;
			}
		}
		break;
		
		
		// flying up
		case BP_FLY_UP:
		{
			o->state++;
			o->timer = 0;
			o->animtimer = 0;
			
			o->frame = 8;		// vertical flight
			o->dir = LEFT;		// up-facing frame
			
			o->yinertia = -RUSH_SPEED;
			o->xinertia = 0;
			o->damage = DMG_RUSH;
		}
		case BP_FLY_UP+1:
		{
			ANIMATE(1, 8, 9);
			
			// hit ceiling? (to make this happen, break his loop and jump ABOVE him
			// while he is in the air, at the part where he would normally be
			// coming back down at you).
			if (o->blocku)
			{
				o->state = BP_HIT_CEILING;
				o->damage = DMG_NORMAL;
				o->timer = 0;
				
				SmokeXY(o->CenterX(), o->Top(), 8);
				megaquake(10);
				
				spawn_bones(o, UP);
			}
			
			// reached player? (this check here isn't exactly the same as pdistly;
			// it's important that it checks the player's top and not his center).
			if ((abs(player->y - o->y) < RUSH_DIST) && o->timer2 < 4)
				o->state = BP_PREPARE_FLY_LR;
		}
		break;
		
		case BP_HIT_CEILING:	// hit ceiling
		{
			o->frame = 8;
			
			if (++o->timer > 30)
			{
				if (o->timer2 <= 3)
					o->state = BP_PREPARE_FLY_LR;
				else
					o->state = BP_RETURN_TO_GROUND;
			}
		}
		break;
		
		
		// flying down
		case BP_FLY_DOWN:
		{
			o->state++;
			o->timer = 0;
			o->animtimer = 0;
			
			o->frame = 8;		// vertical flight
			o->dir = RIGHT;		// down-facing frame
			
			o->yinertia = RUSH_SPEED;
			o->xinertia = 0;
			o->damage = DMG_RUSH;
		}
		case BP_FLY_DOWN+1:
		{
			ANIMATE(1, 8, 9);
			
			if (o->blockd)
			{
				o->state = BP_HIT_FLOOR;
				o->damage = DMG_NORMAL;
				o->timer = 0;
				
				SmokeXY(o->CenterX(), o->Bottom(), 8);
				megaquake(10);
				
				spawn_bones(o, DOWN);
				FACEPLAYER;
			}
			
			if (pdistly(RUSH_DIST) && o->timer2 < 4)
				o->state = BP_PREPARE_FLY_LR;
		}
		break;
		
		case BP_HIT_FLOOR:	// hit floor
		{
			o->frame = 3;
			
			if (++o->timer > 30)
			{
				o->state = BP_FIGHTING_STANCE;
				o->timer = 120;
			}
		}
		break;
		
		
		// come back to ground while facing head on
		case BP_RETURN_TO_GROUND:
		{
			o->frame = 4;		// face screen frame
			o->dir = LEFT;		// non-flashing version
			
			o->state++;
		}
		case BP_RETURN_TO_GROUND+1:
		{
			ANIMATE(1, 4, 5);
			
			o->yinertia += 0x40;
			LIMITY(0x5ff);
			
			if (o->blockd && o->yinertia >= 0)
			{
				o->state++;
				o->timer = 0;
				o->frame = 3; 	// landed
				
				FACEPLAYER;
			}
		}
		break;
		
		case BP_RETURN_TO_GROUND+2:
		{
			o->xinertia *= 3;
			o->xinertia /= 4;
			
			if (++o->timer > 10)
			{
				o->state = BP_FIGHTING_STANCE;
				o->timer = 140;
			}
		}
		break;
	}
}