Example #1
0
void ai_ballos_skull(Object *o)
{
	ANIMATE(8, 0, 3);
	
	switch(o->state)
	{
		case 0:
		{
			o->state = 100;
			o->frame = random(0, 16) & 3;
		}
		case 100:
		{
			o->yinertia += 0x40;
			LIMITY(0x700);
			
			if (o->timer++ & 2)
			{
				(SmokePuff(o->x, o->y))->PushBehind(o);
			}
			
			if (o->y > 0x10000)
			{
				o->flags &= ~FLAG_IGNORE_SOLID;
				
				if (o->blockd)
				{
					o->yinertia = -0x200;
					o->state = 110;
					o->flags |= FLAG_IGNORE_SOLID;
					
					quake(10, SND_BLOCK_DESTROY);
					
					for(int i=0;i<4;i++)
					{
						Object *s = SmokePuff(o->x + random(-12<<CSF, 12<<CSF), \
											  o->y + 0x2000);
						
						s->xinertia = random(-0x155, 0x155);
						s->yinertia = random(-0x600, 0);
						s->PushBehind(o);
					}
				}
			}
		}
		break;
		
		case 110:
		{
			o->yinertia += 0x40;
			
			if (o->Top() >= (map.ysize * TILE_H) << CSF)
			{
				o->Delete();
			}
		}
		break;
	}
}
Example #2
0
void SmokeXY(int x, int y, int nclouds, int rangex, int rangey, Object *push_behind)
{
Object *s;

	for(int i=0;i<nclouds;i++)
	{
		s = SmokePuff(x + (random(-rangex, rangex) << CSF), \
			 	      y + (random(-rangey, rangey) << CSF));
		

	}
}
Example #3
0
void OmegaBoss::Run(void)
{
	Object *&o = game.stageboss.object;
	
	if (omg.defeated)
		return;
	
	switch(o->state)
	{
		case 0:	break;	// waiting for trigger by script
		
		case OMG_WAIT:	// waits for a moment then go to omg.nextstate
		{
			o->state++;
			omg.timer = 0;
		}
		case OMG_WAIT+1:
		{
			if (++omg.timer >= OMEGA_WAIT_TIME)
			{
				omg.timer = 0;
				o->state = omg.nextstate;
			}
		}
		break;
		
		case OMG_APPEAR:
		{
			omg.timer = 0;
			o->frame = 0;
			o->state = OMG_MOVE;
			omg.movedir = -OMEGA_SPEED;
			o->flags |= FLAG_SOLID_MUSHY;
		}
		case OMG_MOVE:	// rising up/going back into ground
		{
			o->frame = 0;
			o->y += omg.movedir;
			
			game.quaketime = 2;
			
			omg.timer++;
			if ((omg.timer & 3) == 0) sound(SND_QUAKE);
			
			if (omg.timer >= omg.movetime)
			{
				if (omg.movedir < 0)
				{	// was rising out of ground
					omg.nextstate = OMG_JAWS_OPEN;
					o->state = OMG_WAIT;
				}
				else
				{	// was going back into ground
					omg.timer = 0;
					o->state = OMG_UNDERGROUND;
					o->flags &= ~(FLAG_SOLID_MUSHY | FLAG_SOLID_BRICK);
				}
			}
		}
		break;
		
		case OMG_JAWS_OPEN:			// jaws opening
		{
			o->state++;
			omg.animtimer = 0;
			sound(SND_JAWS);
			o->sprite = SPR_OMG_OPENED;			// select "open" bounding box
		}
		case OMG_JAWS_OPEN+1:
		{
			omg.animtimer++;
			if (omg.animtimer > 2)
			{
				omg.animtimer = 0;
				o->frame++;
				if (o->frame==3)
				{
					o->state = OMG_FIRE;
					omg.firecounter = 0;
					o->flags |= FLAG_SHOOTABLE;
				}
			}
		}
		break;
		
		case OMG_FIRE:	// throwing out red stuff
		{
			omg.firecounter++;
			
			if (omg.firecounter > omg.startfiring && omg.firecounter < omg.stopfiring)
			{
				if ((omg.firecounter % omg.firefreq)==0)
				{
					Object *shot;
					
					sound(SND_EM_FIRE);
					
					shot = SpawnObjectAtActionPoint(o, OBJ_OMEGA_SHOT);
					shot->xinertia = random(-omg.shotxspd, omg.shotxspd);
					shot->yinertia = -0x333;
					if (omg.form==2 || random(0, 9) < 8)
					{
						shot->sprite = SPR_OMG_BULLET_NORMAL;
						shot->flags = FLAG_SHOOTABLE;
					}
					else
					{
						shot->sprite = SPR_OMG_BULLET_HARD;
						shot->flags = (FLAG_SHOOTABLE | FLAG_INVULNERABLE);
					}
					
					shot->timer = (random(0, 7) >= 4) ? random(300, 400):0;
					shot->damage = 4;
				}
			}
			else if (omg.firecounter >= omg.endfirestate || sound_is_playing(SND_MISSILE_HIT))
			{	// snap jaws shut
				omg.animtimer = 0;
				o->state = OMG_JAWS_CLOSE;
				sound(SND_JAWS);
			}
		}
		break;
		
		case OMG_JAWS_CLOSE:	// jaws closing
		{
			omg.animtimer++;
			if (omg.animtimer > 2)
			{
				omg.animtimer = 0;
				
				o->frame--;
				if (o->frame == 0)
				{
					sound_stop(SND_JAWS);
					sound(SND_BLOCK_DESTROY);
					
					o->sprite = SPR_OMG_CLOSED;		// select "closed" bounding box
					
					o->flags &= ~FLAG_SHOOTABLE;
					o->damage = 0;
					
					if (omg.form == 1)
					{	// form 1: return to sand
						o->state = OMG_WAIT;
						omg.nextstate = OMG_MOVE;
						omg.movedir = OMEGA_SPEED;
						omg.movetime = OMEGA_SINK_DEPTH;
					}
					else
					{	// form 2: jump
						sound(SND_FUNNY_EXPLODE);
						if (o->x < player->x) o->xinertia = 0xC0;
										 else o->xinertia = -0xC0;
						o->state = OMG_JUMP;
						o->yinertia = -0x5FF;
						omg.orgy = o->y;
					}
				}
			}
			
			// hurt player if he was standing in the middle when the jaws shut
			if (player->riding == o)
			{
				hurtplayer(OMEGA_DAMAGE);
			}
		}
		break;
		
		case OMG_UNDERGROUND:		// underground waiting to reappear
		{
			if (++omg.timer >= 120)
			{
				omg.timer = 0;
				o->state = OMG_APPEAR;
				
				o->x = omg.orgx + (random(-64, 64) << CSF);
				o->y = omg.orgy;
				omg.movetime = OMEGA_RISE_HEIGHT;
				
				// switch to jumping out of ground when we get low on life
				if (omg.form==1 && o->hp <= HP_TRIGGER_POINT)
				{
					o->flags |= FLAG_SOLID_MUSHY;
					
					omg.form = 2;
					omg.firefreq = 5;
					omg.shotxspd = 0x155;
					omg.startfiring = 0;
					omg.stopfiring = 30;
					omg.endfirestate = 50;
					omg.movetime = OMEGA_RISE_HEIGHT+3;
				}
			}
		}
		break;
		
		case OMG_JUMP:	// init for jump
		{
			omg.orgy = o->y;
			o->state++;
			omg.timer = 0;
		}
		case OMG_JUMP+1:	// jumping
		{
			o->yinertia += 0x24;
			if (o->yinertia > 0x5ff) o->yinertia = 0x5ff;
			
			if (o->yinertia > 0)
			{	// coming down
				
				pieces[LEFTLEG]->sprite = pieces[RIGHTLEG]->sprite = SPR_OMG_LEG_ONGROUND;
				
				// retract legs a little when we hit the ground
				if (pieces[LEFTLEG]->blockd || pieces[RIGHTLEG]->blockd)
				{
					o->xinertia = 0;
					omg.leg_descend -= o->yinertia;
					if (++omg.timer >= 3)
					{
						o->yinertia = 0;
						o->state = OMG_JAWS_OPEN;
					}
				}
				
				// --- squash player if we land on him -------------
				// if top of player is higher than bottom of our bounding box
				// but bottom of player's bounding box is not...
				if (player->blockd)
				{
					int omg_bottom = o->y + (sprites[o->sprite].solidbox.y2 << CSF);
					if (player->y <= omg_bottom)
					{
						if (player->y + (sprites[player->sprite].solidbox.y2 << CSF) >= omg_bottom)
						{
							if (hitdetect(o, player))	// easy way to verify the X's are lined up
							{	// SQUISH!
								hurtplayer(OMEGA_DAMAGE);
							}
						}
					}
				}
			}
			else
			{	// jumping up; extend legs
				omg.leg_descend = (omg.orgy - o->y) + LEGD_MIN;
				if (omg.leg_descend > LEGD_MAX) omg.leg_descend = LEGD_MAX;
				pieces[LEFTLEG]->sprite = pieces[RIGHTLEG]->sprite = SPR_OMG_LEG_INAIR;
			}
		}
		break;
		
		/// victory
		case OMG_EXPLODING:
		{
			omg.timer = 0;
			o->state++;
		}
		case OMG_EXPLODING+1:
		{
			int x, y;
			
			o->xinertia = o->yinertia = 0;
			
			x = o->CenterX() + (random(-48, 48)<<CSF);
			y = o->CenterY() + (random(-48, 24)<<CSF);
			SmokePuff(x, y);
			effect(x, y, EFFECT_BOOMFLASH);
			
			game.quaketime = 2;
			
			if ((omg.timer % 12)==0) sound(SND_ENEMY_HURT_BIG);
			
			if (++omg.timer > 100)
			{
				omg.timer = 0;
				starflash.Start(o->CenterX(), o->CenterY());
				o->state = OMG_EXPLODED;
			}
			else if (omg.timer==24)
			{
				StartScript(210);
			}
		}
		break;
		
		case OMG_EXPLODED:
		{
			game.quaketime = 40;
			
			if (++omg.timer > 50)
			{
				o->Delete();
				for(int i=0;i<NUM_PIECES;i++)
					pieces[i]->Delete();
				
				omg.defeated = true;
				return;
			}
		}
		break;
	}
	
	// implement shaking when shot
	// we do it manually instead of used the usual shared code
	// because we want all the pieces to shake at once
	if (o->hp != omg.lasthp && !omg.shaketimer)
	{
		omg.shaketimer = 3;
		// why did I write this? anyway, I'm sure it's important
		if (o->x > player->x) o->display_xoff = -1;
						 else o->display_xoff = 1;
		
		omg.lasthp = o->hp;
	}
	if (omg.shaketimer)
	{
		int xoff = -o->display_xoff;
		
		if (!--omg.shaketimer) xoff = 0;
		
		o->display_xoff = xoff;
		pieces[LEFTLEG]->display_xoff = xoff;
		pieces[RIGHTLEG]->display_xoff = xoff;
		pieces[LEFTSTRUT]->display_xoff = xoff;
		pieces[RIGHTSTRUT]->display_xoff = xoff;
	}
	
	if (o->state)
	{
		o->blockl |= pieces[LEFTLEG]->blockl;
		o->blockr |= pieces[RIGHTLEG]->blockr;
		
		pieces[LEFTLEG]->x = o->x - (4 << CSF); pieces[LEFTLEG]->y = o->y + omg.leg_descend;
		pieces[RIGHTLEG]->x = o->x + (38 << CSF); pieces[RIGHTLEG]->y = o->y + omg.leg_descend;
		pieces[LEFTSTRUT]->x = o->x + (9 << CSF); pieces[LEFTSTRUT]->y = o->y + (27 << CSF);
		pieces[RIGHTSTRUT]->x = o->x + (43 << CSF); pieces[RIGHTSTRUT]->y = o->y + (27 << CSF);
	}
}
Example #4
0
void XBoss::Run()
{
Object *o = mainobject;
int i;

	if (!mainobject) return;
	if (o->state == 0 || (!X.initilized && o->state != STATE_X_APPEAR))
	{
		o->hp = 1;
		o->x = -(Graphics::SCREEN_WIDTH << CSF);
		return;
	}
	
	switch(o->state)
	{
		// script triggered us to initilize/appear
		// (there is a hvtrigger, right before player first walks by us
		// and sees us inactive, which sends us this ANP).
		case STATE_X_APPEAR:
		{
			if (!X.initilized)
			{
				Init();
				X.initilized = true;
			}
		}
		break;
		
		// script has triggered the fight to begin
		case STATE_X_FIGHT_BEGIN:
		{
			o->timer = 0;
			o->state++;
		}
		case STATE_X_FIGHT_BEGIN+1:
		{
			if (++o->timer > 100)
			{
				FACEPLAYER;
				o->timer = 0;
				o->state = STATE_X_TRAVEL;
			}
		}
		break;
		
		// starts the treads and moves us in the currently-facing direction
		case STATE_X_TRAVEL:
		{
			// count number of times we've traveled, we brake
			// and attack every third time.
			o->timer2++;
			
			o->timer = 0;
			o->state++;
		}
		case STATE_X_TRAVEL+1:
		{
			o->timer++;
			
			// trigger the treads to start moving,
			// and put them slightly out of sync with each-other.
			for(int i=0;i<4;i++)
			{
				if (o->timer == tread_turnon_times[i])
				{
					treads[i]->state = STATE_TREAD_RUN;
					treads[i]->dir = o->dir;
				}
			}
			
			if (o->timer > 120)
			{
				// time to attack? we attack every 3rd travel
				// if so skid to a stop, that's the first step.
				if (o->timer2 >= 3)
				{
					o->timer2 = 0;
					
					o->dir ^= 1;
					o->state = STATE_X_BRAKE;
					o->timer = 0;
				}
				else
				{
					// passed player? skid and turn around.
					if ((o->dir == RIGHT && o->x > player->x) || \
					 	(o->dir == LEFT  && o->x < player->x))
					{
						o->dir ^= 1;
						o->state = STATE_X_TRAVEL;
					}
				}
			}
		}
		break;
		
		// skidding to a stop in preparation to attack
		case STATE_X_BRAKE:
		{
			o->timer = 0;
			o->state++;
		}
		case STATE_X_BRAKE+1:
		{
			o->timer++;
			
			// trigger the treads to start braking,
			// and put them slightly out of sync with each-other.
			for(int i=0;i<4;i++)
			{
				if (o->timer == tread_turnon_times[i])
				{
					treads[i]->state = STATE_TREAD_BRAKE;
					treads[i]->dir = o->dir;
				}
			}
			
			if (o->timer > 50)
			{
				o->state = STATE_X_OPEN_DOORS;
				o->timer = 0;
			}
		}
		break;
		
		// doors opening to attack
		case STATE_X_OPEN_DOORS:
		{
			o->timer = 0;
			o->savedhp = o->hp;
			
			// select type of attack depending on where we are in the battle
			if (!AllTargetsDestroyed())
			{
				SetStates(doors, 2, STATE_DOOR_OPENING);
				o->state = STATE_X_FIRE_TARGETS;
			}
			else
			{
				SetStates(doors, 2, STATE_DOOR_OPENING_PARTIAL);
				o->state = STATE_X_FIRE_FISHIES;
			}
		}
		break;
		
		// firing targets (early battle)
		case STATE_X_FIRE_TARGETS:
		{
			if (doors[0]->state == STATE_DOOR_FINISHED)
			{
				doors[0]->state = 0;
				SetStates(targets, 4, STATE_TARGET_FIRE);
			}
			
			if (++o->timer > 300 || AllTargetsDestroyed())
			{
				o->state = STATE_X_CLOSE_DOORS;
				o->timer = 0;
			}
		}
		break;
		
		// firing fishy missiles (late battle)
		case STATE_X_FIRE_FISHIES:
		{
			if (doors[0]->state == STATE_DOOR_FINISHED)
			{
				doors[0]->state = 0;
				
				SetStates(fishspawners, 4, STATE_FISHSPAWNER_FIRE);
				internals->flags |= FLAG_SHOOTABLE;
			}
			
			if (++o->timer > 300 || (o->savedhp - o->hp) > 200)
			{
				o->state = STATE_X_CLOSE_DOORS;
				o->timer = 0;
			}
		}
		break;
		
		// doors closing after attack
		case STATE_X_CLOSE_DOORS:
		{
			o->timer = 0;
			o->state++;
			
			SetStates(doors, 2, STATE_DOOR_CLOSING);
		}
		case STATE_X_CLOSE_DOORS+1:
		{
			if (doors[0]->state == STATE_DOOR_FINISHED)
			{
				doors[0]->state = 0;
				
				// just turn off everything for both types of attacks;
				// turning off the attack type that wasn't enabled isn't harmful.
				SetStates(targets, 4, 0);
				SetStates(fishspawners, 4, 0);
				internals->flags &= ~FLAG_SHOOTABLE;
			}
			
			if (++o->timer > 50)
			{
				FACEPLAYER;
				o->state = STATE_X_TRAVEL;
				o->timer = 0;
			}
		}
		break;
		
		// exploding
		case STATE_X_EXPLODING:
		{
			SetStates(fishspawners, 4, 0);
			KillObjectsOfType(OBJ_X_FISHY_MISSILE);
			
			StartScript(1000);
			o->timer = 0;
			o->state++;
		}
		case STATE_X_EXPLODING+1:
		{
			game.quaketime = 2;
			o->timer++;
			
			if ((o->timer % 8) == 0)
				sound(SND_ENEMY_HURT_BIG);
			
			SmokePuff(o->CenterX() + (random(-72, 72) << CSF),
					  o->CenterY() + (random(-64, 64) << CSF));
			
			if (o->timer > 100)
			{
				starflash.Start(o->CenterX(), o->CenterY());
				sound(SND_EXPLOSION1);
				o->timer = 0;
				o->state++;
			}
		}
		break;
		case STATE_X_EXPLODING+2:
		{
			game.quaketime = 40;
			if (++o->timer > 50)
			{
				CreateObject(o->x, o->y - (24 << CSF), OBJ_X_DEFEATED);
				DeleteMonster();
				return;
			}
		}
		break;
	}
	
	// call AI for all tread pieces
	for(i=0;i<4;i++)
	{
		run_tread(i);
		run_fishy_spawner(i);
	}
}