Пример #1
0
// set the x&y inertia of object o so that it travels towards [destx,desty].
// rand_variance is a random amount of inaccuracy, in 0-255 degrees, to introduce
// into the toss.
// speed is how quickly to throw the object, in CSF'd coordinates.
void ThrowObject(Object *o, int destx, int desty, int rand_variance, int speed)
{
	uint8_t angle = GetAngle(o->x, o->y, destx, desty);
	
	if (rand_variance)
		angle += random(-rand_variance, rand_variance);
	
	ThrowObjectAtAngle(o, angle, speed);
}
Пример #2
0
// boss-fight igor
void ai_boss_igor(Object *o)
{
	enum
	{
		STATE_INIT = 0,
		STATE_STAND,
		
		STATE_BEGIN_ATTACK,
		STATE_WALK,
		
		STATE_JUMPING,
		STATE_LANDED,
		
		STATE_PUNCH,
		STATE_PUNCH_2,
		STATE_PUNCH_3,
		
		STATE_MOUTH_BLAST,
		STATE_MOUTH_BLAST_2
	};
	
	switch(o->state)
	{
		case STATE_INIT:
		{
			o->damage = 0;
			o->xinertia = 0;
			
			o->state = STATE_STAND;
			o->frame = 0;
			o->animtimer = 0;
		}
		case STATE_STAND:
		{
			ANIMATE(5, 0, 1);
			if (++o->timer > 50)
			{
				o->state = STATE_BEGIN_ATTACK;
			}
		}
		break;
		
		case STATE_BEGIN_ATTACK:
		{
			o->state = STATE_WALK;
			o->frame = 2;
			o->animtimer = 0;
			o->timer = 0;
			
			FACEPLAYER;
			o->igor.fireattack = false;
			
			// when health is less than halfway, then use
			// the mouth blast attack every third time.
			if (++o->timer2 >= 3 && \
				o->hp <= (objprop[o->type].initial_hp / 2))
			{
				o->timer2 = 0;
				o->igor.fireattack = true;
				o->dir ^= 1;	// walk away from player
			}
			
		}	// fall thru
		case STATE_WALK:
		{
			ANIMATE(3, 2, 5);
			XMOVE(0x200);
			
			if (o->igor.fireattack)
			{	// begin mouth-blast attack
				if (++o->timer > 16)
				{
					o->state = STATE_MOUTH_BLAST;
					o->xinertia = 0;
					o->frame = 10;
				}
			}
			else
			{
				if (o->dir == LEFT)
				{
					if (o->x <= player->x + player->Width())
						o->state = STATE_PUNCH;
				}
				else
				{
					if (o->x + o->Width() >= player->x)
						o->state = STATE_PUNCH;
				}
				
				// if we don't reach him after a while, do a jump
				if (++o->timer > 50)
				{
					o->frame = 10;
					o->yinertia = -0x400;
					o->state = STATE_JUMPING;
					o->timer = 0;
					
					o->xinertia *= 2;
					o->xinertia /= 3;
					
					o->damage = 2;
				}
			}
		}
		break;
		
		case STATE_PUNCH:
		{
			o->xinertia = 0;
			
			o->state = STATE_PUNCH_2;
			o->frame = 6;
			o->timer = 0;
		}
		case STATE_PUNCH_2:
		{
			if (++o->timer > 12)
			{
				sound(SND_EXPL_SMALL);
				
				// sprite appears identical, but has a wider bounding box.
				o->sprite = SPR_IGOR_PUNCHING;
				o->damage = 5;
				
				o->state = STATE_PUNCH_3;
				o->frame = 7;
				o->timer = 0;
			}
		}
		break;
		case STATE_PUNCH_3:
		{
			if (++o->timer > 10)
			{
				o->state = STATE_INIT;
				o->frame = 0;
				o->damage = 0;
				
				// return to normal-size bounding box
				o->sprite = SPR_IGOR;
			}
		}
		break;
		
		case STATE_JUMPING:
		{
			if (o->blockd)
			{
				sound(SND_QUAKE);
				SmokeSide(o, 4, DOWN);
				
				o->state = STATE_LANDED;
				o->frame = 11;
				o->timer = 0;
			}
		}
		break;
		
		case STATE_LANDED:
		{
			o->xinertia = 0;
			if (++o->timer > 10)
			{
				o->state = STATE_INIT;
				o->frame = 0;
				o->damage = 0;
			}
		}
		break;
		
		case STATE_MOUTH_BLAST:
		{
			FACEPLAYER;
			o->timer = 0;
			o->state++;
		}
		case STATE_MOUTH_BLAST_2:
		{
			o->timer++;
			
			// flash mouth
			o->frame = 8;
			if (o->timer > 50 && (o->timer & 2))
				o->frame = 9;
			
			// fire shots
			if (o->timer > 100)
			{
				if ((o->timer % 6) == 1)
				{
					sound(SND_BLOCK_DESTROY);
					Object *shot = SpawnObjectAtActionPoint(o, OBJ_IGOR_SHOT);
					
					int angle = (o->dir == LEFT) ? 136 : 248;
					angle += random(-16, 16);
					ThrowObjectAtAngle(shot, angle, 0x580);
				}
				
				if (o->timer > 132)		// fires 6 shots
				{
					o->state = STATE_INIT;
					o->timer = 0;
				}
			}
		}
		break;
	}
	
	o->yinertia += 0x40;
	LIMITY(0x5ff);
}
Пример #3
0
void ai_boss_doctor(Object *o)
{
	//AIDEBUG;
	
	/*if (o->state > 2 && o->state < 500)
	{
		o->state = 937;
		StartScript(410);
		return;
	}*/
	
	switch(o->state)
	{
		case 0:
		{
			o->y += (8 << CSF);
			o->frame = 3;
			o->state = 1;
			o->BringToFront();		// make sure in front of doctor_crowned
			crystal_tofront = true;	// make sure front crystal is in front of us
		}
		break;
		
		case 2:		// transforming (script)
		{
			o->timer++;
			o->frame = (o->timer & 2) ? 0 : 3;
			
			if (o->timer > 50)
				o->state = 10;
		}
		break;
		
		case 10:	// base state/falling (script)
		{
			o->yinertia += 0x80;
			o->flags |= FLAG_SHOOTABLE;
			o->damage = 3;
			
			if (o->blockd)
			{
				o->state = 20;
				o->timer = 0;
				o->frame = 0;
				
				o->savedhp = o->hp;
				FACEPLAYER;
			}
		}
		break;
		
		// fire wave shot
		case 20:
		{
			o->timer++;
			
			if (o->timer < 50)
			{
				if ((o->hp - o->savedhp) > 20)
					o->timer = 50;
			}
			
			if (o->timer == 50)
			{	// arm across chest
				FACEPLAYER;
				o->frame = 4;
			}
			
			if (o->timer == 80)
			{
				Object *shot;
				o->frame = 5;	// arm cast out
				
				shot = SpawnObjectAtActionPoint(o, OBJ_DOCTOR_SHOT);
				shot->dir = o->dir;
				shot->angle = 0;
				
				shot = SpawnObjectAtActionPoint(o, OBJ_DOCTOR_SHOT);
				shot->dir = o->dir;
				shot->angle = 0x80;
				
				sound(SND_FUNNY_EXPLODE);
			}
			
			if (o->timer == 120)
				o->frame = 0;	// arm down
			
			if (o->timer > 130)
			{
				if ((o->hp - o->savedhp) > 50)
				{
					o->state = 100;
					o->timer = 0;
				}
				
				if (o->timer > 160)
				{
					o->state = 100;
					o->timer = 0;
				}
			}
		}
		break;
		
		// big "explosion" blast
		case 30:
		{
			o->state = 31;
			o->timer = 0;
			o->frame = 6;
			o->xmark = o->x;
			o->flags |= FLAG_SHOOTABLE;
		}
		case 31:
		{
			o->x = o->xmark;
			if (++o->timer & 2) o->x += (1 << CSF);
			
			if (o->timer > 50)
			{
				o->state = 32;
				o->timer = 0;
				o->frame = 7;
				
				sound(SND_LIGHTNING_STRIKE);
				
				for(int angle=8;angle<256;angle+=16)
				{
					Object *shot = SpawnObjectAtActionPoint(o, OBJ_DOCTOR_BLAST);
					ThrowObjectAtAngle(shot, angle, 0x400);
				}
			}
		}
		break;
		case 32:	// after blast
		{
			if (++o->timer > 50)
				o->state = 100;
		}
		break;
		
		// teleport away
		case 100:
		{
			o->state = 101;
			o->flags &= ~FLAG_SHOOTABLE;
			o->damage = 0;
			
			dr_tp_out_init(o);
		}
		case 101:
		{
			if (dr_tp_out(o))
			{
				o->state = 102;
				o->timer = 0;
				o->invisible = true;
				
				// decide where we're going to go now, so the red crystal
				// can start moving towards it. But, it's important not to
				// actually move until the last possible second, or we could
				// drag our floattext along with us (and give away our position).
				o->xmark = (random(5, 35) * TILE_W) << CSF;
				o->ymark = (random(5, 7) * TILE_H) << CSF;
			}
		}
		break;
		
		case 102:	// invisible: waiting to reappear
		{
			if (++o->timer > 40)
			{
				o->state = 103;
				o->timer = 16;
				o->frame = 2;
				o->yinertia = 0;
				
				o->x = o->xmark;
				o->y = o->ymark;
				
				FACEPLAYER;
			}
		}
		break;
		
		// tp back in
		case 103:
		{
			o->state++;
			dr_tp_in_init(o);
		}
		case 104:
		{
			if (dr_tp_in(o))
			{
				o->flags |= FLAG_SHOOTABLE;
				o->damage = 3;
				
				if (++o->timer2 >= 4)
				{	// big explode
					o->timer2 = 0;
					o->state = 30;
				}
				else
				{	// another wave shot
					o->state = 10;
				}
			}
		}
		break;
		
		// defeated!
		case 500:
		{
			o->flags &= ~FLAG_SHOOTABLE;
			o->frame = 6;
			
			// fall to earth
			o->yinertia += 0x10;
			if (o->blockd && o->yinertia >= 0)
			{
				o->state = 501;
				o->timer = 0;
				
				o->xmark = o->x;
				FACEPLAYER;
			}
		}
		break;
		
		case 501:	// flashing (transforming into Doctor 2)
		{
			FACEPLAYER;
			o->frame = 8;
			
			o->x = o->xmark;
			if (!(++o->timer & 2))
				o->x += (1 << CSF);
		}
		break;
	}
	
	// enable per-frame bbox
	COPY_PFBOX;
	
	// set crystal follow position
	if (o->state >= 10)
	{
		if (o->invisible)	// teleporting
		{
			crystal_xmark = o->xmark;
			crystal_ymark = o->ymark;
		}
		else
		{
			crystal_xmark = o->x;
			crystal_ymark = o->y;
		}
	}
	
	LIMITY(0x5ff);
}