예제 #1
0
void ai_balrog(Object *o)
{
bool fall = true;

	// he is greenish when he first appears in Gum Room
	if (DoesCurrentStageUseSpriteset(NPCSET_FROG))
		o->sprite = SPR_BALROG_GREEN;
	
	switch(o->state)
	{
		case 0:
		{
			o->flags &= ~FLAG_IGNORE_SOLID;
			o->xinertia = 0;
			o->balrog.smoking = false;
			
			o->frame = 0;
			randblink(o, 4, 8);
		}
		break;
		
		case 10:		// he jumps and flys away
			o->xinertia = 0;
			o->frame = 2;
			o->timer = 0;
			o->state++;
		case 11:
		{
			if (++o->timer <= 20) break;
			
			o->state++;
			o->yinertia = -0x800;
			o->flags |= FLAG_IGNORE_SOLID;
		}
		case 12:
		{
			fall = false;
			o->frame = 3;
			o->yinertia -= 0x10;
			if (o->y < 0)
			{
				o->Delete();
				sound(SND_QUAKE);
				game.quaketime = 30;
			}
		}
		break;
		
		// he looks shocked and shakes, then flys away
		// used when he is "hit by something"
		case 20:
		{
			o->state = 21;
			o->frame = 5;
			o->xinertia = 0;
			o->timer = o->timer2 = 0;
			SmokeClouds(o, 4, 8, 8);
			sound(SND_BIG_CRASH);
			o->balrog.smoking = 1;
		}
		case 21:
		{
			o->timer2++;
			o->x += ((o->timer2 >> 1) & 1) ? (1<<CSF) : -(1<<CSF);
			
			if (++o->timer > 100)
				o->state = 10;
			
			o->yinertia += 0x20;
			LIMITY(0x5ff);
		}
		break;
		
		case 30:	// he smiles for a moment
			o->frame = 6;
			o->timer = 0;
			o->state = 31;
		case 31: if (++o->timer > 100) o->state = o->frame = 0;
		break;
		
		// flashing white (spell casted on him)
		// this only works in Gum Room before balfrog fight, as the normal
		// non-greenish spritesheet doesn't include the required frame.
		case 40:
			o->state = 41;
			o->animtimer = 0;
			o->animframe = 0;
		case 41:
		{
			static const int flash_seq[] = { 5, 7 };
			o->animate_seq(1, flash_seq, 2);
		}
		break;
		case 42:
			o->timer = 0;
			o->state = 43;
		case 43:
			// flashing visibility
			// (transforming into Balfrog stage boss;
			//	our flashing is interlaced with his)
			o->timer++;
			o->invisible = (o->timer & 2) ? false : true;
		break;
		
		case 50:	// he faces away
			o->frame = 8;
			o->xinertia = 0;
		break;
		
		case 60:	// he walks
			o->state = 61;
			balrog_walk_init(o);
		case 61:
		{
			balrog_walk_animation(o);
			XMOVE(0x200);
		}
		break;
		
		// he is teleported away (looking distressed)
		// this is when he is sent to Labyrinth at end of Sand Zone
		case 70:
			o->xinertia = 0;
			o->timer = 0;
			o->frame = 7;
			o->state++;
		case 71:
			if (DoTeleportOut(o, 2))
				o->Delete();
		break;
		
		case 80:	// hands up and shakes
			o->frame = 5;
			o->state = 81;
		case 81:
		{
			if (++o->timer & 2)
				o->x += (1 << CSF);
			else
				o->x -= (1 << CSF);
		}
		break;
		
		// fly up and lift Curly & PNPC
		// (post-Ballos ending scene)
		case 100:
		{
			o->state = 101;
			o->timer = 0;
			o->frame = 2;	// prepare for jump
		}
		case 101:
		{
			if (++o->timer > 20)
			{
				o->state = 102;
				o->timer = 0;
				o->frame = 3;	// fly up
				
				DeleteObjectsOfType(OBJ_NPC_PLAYER);
				DeleteObjectsOfType(OBJ_CURLY);
				
				CreateObject(0, 0, OBJ_BALROG_PASSENGER, 0, 0, LEFT)->linkedobject = o;
				CreateObject(0, 0, OBJ_BALROG_PASSENGER, 0, 0, RIGHT)->linkedobject = o;
				
				o->yinertia = -0x800;
				o->flags |= FLAG_IGNORE_SOLID;	// so can fly through ceiling
				fall = false;
			}
		}
		break;
		case 102:	// flying up during escape seq
		{
			fall = false;
			
			// bust through ceiling
			int y = ((o->y + (4<<CSF)) >> CSF) / TILE_H;
			if (y < 35 && y >= 0)
			{
				int x = (o->CenterX() >> CSF) / TILE_W;
				
				if (map.tiles[x][y] != 0)
				{
					// smoke needs to go at the bottom of z-order or you can't
					// see any of the characters through all the smoke.
					map_ChangeTileWithSmoke(x, y, 0, 4, false, lowestobject);
					map_ChangeTileWithSmoke(x-1, y, 0, 4, false, lowestobject);
					map_ChangeTileWithSmoke(x+1, y, 0, 4, false, lowestobject);
					
					megaquake(10, 0);
					sound(SND_MISSILE_HIT);
				}
			}
			
			if (o->Bottom() < -(20<<CSF))
			{
				quake(30, 0);
				o->Delete();
			}
		}
		break;
		
		case 500:	// used during Balfrog death scene
		{
			fall = false;
		}
		break;
	}
예제 #2
0
// 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;
	}
}