Ejemplo n.º 1
0
void ai_green_devil(Object *o)
{
	switch(o->state)
	{
		case 0:
		{
			o->flags |= FLAG_SHOOTABLE;
			o->ymark = o->y;
			o->yinertia = random(-5<<CSF, 5<<CSF);
			o->damage = 3;
			o->state = 1;
		}
		case 1:
		{
			ANIMATE(2, 0, 1);
			o->yinertia += (o->y < o->ymark) ? 0x80 : -0x80;
			
			XACCEL(0x20);
			LIMITX(0x400);
			
			if (o->dir == LEFT)
			{
				if (o->x < -o->Width())
					o->Delete();
			}
			else
			{
				if (o->x > ((map.xsize * TILE_W) << CSF) + o->Width())
					o->Delete();
			}
		}
		break;
	}
	
}
Ejemplo n.º 2
0
void ai_fuzz(Object *o)
{
    FACEPLAYER;

    switch(o->state)
    {
    case 0:
    {
        o->angle += 4;

        if (!o->linkedobject)
        {
            o->xinertia = random(-0x200, 0x200);
            o->yinertia = random(-0x200, 0x200);
            o->state = 1;
        }
    }
    break;

    // base destroyed, simple sinusoidal player-seek
    case 1:
    {
        o->xinertia += (o->x > player->x) ? -0x20 : 0x20;
        o->yinertia += (o->y > player->y) ? -0x20 : 0x20;

        LIMITX(0x800);
        LIMITY(0x200);
    }
    break;
    }
}
Ejemplo n.º 3
0
// red energy for doctor. In a completely different role,
// it's also used for the dripping blood from Ballos's final form.
void ai_red_energy(Object *o)
{

        switch(o->angle) {
        case UP: {
                o->yinertia -= 0x40;
                if (o->blocku && o->yinertia < 0) o->Delete();
        }
        break;

        case DOWN: {
                o->yinertia += 0x40;
                if (o->blockd && o->yinertia > 0) o->Delete();

                if (++o->timer > 50)
                        o->Delete();

                if (o->yinertia > 0x5ff)
                        o->yinertia = 0x5ff;
        }
        break;

        case RIGHT: {
                if (!o->linkedobject) {
                        o->Delete();
                        return;
                }

                if (o->state == 0) {
                        o->state = 1;
                        o->flags |= FLAG_IGNORE_SOLID;

                        o->xinertia = random(-0x600, 0x600);
                        o->yinertia = random(-0x600, 0x600);

                        // accel speed
                        o->speed = (512 / random(16, 51));

                        // x/y limit
                        int limit = random(0x80, 0x100);

                        o->timer2 = (limit * 2);	// x limit
                        o->timer3 = (limit * 3);	// y limit (form elongated sphere)
                }

                int tgtx = o->linkedobject->x + (4<<CSF);
                if (o->x < tgtx) 		o->xinertia += o->speed;
                else if (o->x > tgtx)	o->xinertia -= o->speed;

                if (o->y < o->linkedobject->y) 		o->yinertia += o->speed;
                else if (o->y > o->linkedobject->y) o->yinertia -= o->speed;

                LIMITX(o->timer2);
                LIMITY(o->timer3);
        }
        }

        o->frame = random(0, 1);
}
Ejemplo n.º 4
0
void ai_bute_flying(Object *o)
{
        //AIDEBUG;
        if (run_bute_defeated(o, BUTE_HP))
                return;

        switch(o->state) {
        case 0: {
                o->invisible = true;
                o->state = 1;
        }
        case 1: {
                if (o->dir == LEFT) {
                        if (player->x > (o->x - (288<<CSF)) && \
                                        player->x < (o->x - (272<<CSF))) {
                                o->state = 10;
                        }
                } else {
                        if (player->x < (o->x + (288<<CSF)) && \
                                        player->x > (o->x + (272<<CSF))) {
                                o->state = 10;
                        }
                }
        }
        break;

        case 10: {
                o->state = 11;
                o->invisible = false;
                o->flags |= FLAG_SHOOTABLE;
                o->damage = 5;
        }
        case 11: {
                FACEPLAYER;
                ANIMATE(1, 0, 1);

                XACCEL(0x10);
                o->yinertia += (o->y > player->y) ? -0x10 : 0x10;

                LIMITX(0x5ff);
                LIMITY(0x5ff);

                if ((o->blockl && o->xinertia < 0) || \
                                (o->blockr && o->xinertia > 0)) {
                        o->xinertia = -o->xinertia;
                }

                if ((o->blockd && o->yinertia > 0) || \
                                (o->blocku && o->yinertia < 0)) {
                        o->yinertia = -o->yinertia;
                }


        }
        break;
        }

}
Ejemplo n.º 5
0
void ai_bat_circle(Object *o)
{
	switch(o->state)
	{
		case 0:
		{
			uint8_t angle;
			o->state = 1;
			
			// set up initial direction and target x,y
			angle = random(0, 255);
			o->xinertia = sin_table[angle];
			
			angle += 64;
			o->xmark = (o->x + (sin_table[angle] * 8));
			
			angle = random(0, 255);
			o->yinertia = sin_table[angle];
			
			angle += 64;
			o->ymark = (o->y + (sin_table[angle] * 8));
		}
		case 1:
			// circle around our target point
			ANIMATE(1, 2, 4);
			FACEPLAYER;
			o->xinertia += (o->x > o->xmark) ? -0x10 : 0x10;
			o->yinertia += (o->y > o->ymark) ? -0x10 : 0x10;
			LIMITX(0x200);
			LIMITY(0x200);
			
			if (!o->timer2)
			{
				if (pdistlx(0x1000) && (player->y > o->y) && pdistly(0xC000))
				{	// dive attack
					o->xinertia /= 2;
					o->yinertia = 0;
					o->state = 2;
					o->frame = 5;		// mouth showing teeth
				}
			}
			else o->timer2--;
		break;
		
		case 2:	// dive attack
			o->yinertia += 0x40;
			LIMITY(0x5ff);
			
			if (o->blockd)
			{
				o->yinertia = 0;
				o->xinertia *= 2;
				o->timer2 = 120;		// delay before can dive again
				o->state = 1;
			}
		break;
	}
}
Ejemplo n.º 6
0
void ai_miserys_bubble(Object *o)
{
    Object *target;

    switch(o->state)
    {
    case 0:
    {
        // find the Toroko object we are to home in on
        target = mbubble_find_target();
        if (!target)
        {
            o->state = 9999;
            return;
        }

        o->xmark = target->x - (6 << CSF);
        o->ymark = target->y - (6 << CSF);

        ThrowObject(o, o->xmark, o->ymark, 0, (2 << CSF));
        o->state = 1;

        // correct values: 0x3F0, 0xAE
        NX_LOG("Computed toss values xi: 0x%x, 0x%x\n", o->xinertia, o->yinertia);
        NX_LOG("Target x/y: 0x%x, 0x%x\n", target->x, target->y);
    }
    case 1:
        ANIMATE(1, 0, 1);

        if (abs(o->x - o->xmark) <= (3 << CSF) && \
                abs(o->y - o->ymark) <= (3 << CSF))
        {
            o->state = 2;
            o->frame = 2;
            sound(SND_BUBBLE);

            if ((target = mbubble_find_target()))
                target->invisible = true;
        }
        break;

    case 2:
    {
        ANIMATE(1, 2, 3);

        o->xinertia -= 0x20;
        o->yinertia -= 0x20;
        LIMITX(0x5FF);
        LIMITY(0x5FF);

        if (o->y < -1000)
            o->Delete();
    }
    break;
    }
}
Ejemplo n.º 7
0
void ai_boss_misery(Object *o)
{
  /*debug("state: %d", o->state);
  debug("timer: %d", o->timer);
  debug("timer2: %d", o->timer2);*/

  switch (o->state)
  {
    // fight begin and default/base state
    case STATE_FIGHTING:
    {
      o->flags |= FLAG_SHOOTABLE;
      o->savedhp = o->hp;

      o->timer    = 0;
      o->frame    = 0;
      o->xinertia = 0;
      o->state++;
    }
    case STATE_FIGHTING + 1:
    {
      FACEPLAYER;

      o->yinertia += (o->y < o->ymark) ? 0x20 : -0x20;
      LIMITY(0x200);

      if (++o->timer > 200 || (o->savedhp - o->hp) >= 80)
      {
        o->state = STATE_FLASH_FOR_SPELL;
        o->timer = 0;
      }
    }
    break;
  }

  run_spells(o);
  run_teleport(o);

  run_intro(o);
  run_defeated(o);

  LIMITX(0x200);
  LIMITY(0x400);
}
Ejemplo n.º 8
0
void ai_misery_ball(Object *o)
{
  switch (o->state)
  {
    case 0:
    {
      o->state    = 1;
      o->ymark    = o->y;
      o->xinertia = 0;
      o->yinertia = -0x200;
    }
    case 1:
    {
      ANIMATE(2, 0, 1);

      o->xinertia += (o->x < player->x) ? 0x10 : -0x10;
      o->yinertia += (o->y < o->ymark) ? 0x20 : -0x20;
      LIMITX(0x200);
      LIMITY(0x200);

      if (pdistlx(8 * CSFI) && player->y > o->y)
      {
        o->state = 10;
        o->timer = 0;
      }
    }
    break;

    case 10: // black lightning
    {
      if (++o->timer > 10)
      {
        NXE::Sound::SoundManager::getInstance()->playSfx(NXE::Sound::SFX::SND_LIGHTNING_STRIKE);
        CreateObject(o->x, o->y, OBJ_BLACK_LIGHTNING);
        o->Delete();
      }

      o->frame = (o->timer & 2) ? 2 : 1;
    }
    break;
  }
}
Ejemplo n.º 9
0
// The Doctor's red crystal.
// There are actually two, one is behind him and one is in front
// and they alternate visibility as they spin around him so it looks 3D.
//
// This function has to be an aftermove, otherwise, because one is in front
// and the other behind, one will be checking crystal_xmark before the Doctor
// updates it, and the other afterwards, and they will get out of sync.
void aftermove_red_crystal(Object *o)
{
	ANIMATE(3, 0, 1);
	
	switch(o->state)
	{
		case 0:
		{
			if (crystal_xmark != 0)
			{
				o->state = 1;
				crystal_tofront = true;
			}
		}
		break;
		
		case 1:
		{
			o->xinertia += (o->x < crystal_xmark) ? 0x55 : -0x55;
			o->yinertia += (o->y < crystal_ymark) ? 0x55 : -0x55;
			LIMITX(0x400);
			LIMITY(0x400);
			
			if ((o->dir == LEFT && o->xinertia > 0) || \
				(o->dir == RIGHT && o->xinertia < 0))
			{
				o->invisible = true;
			}
			else
			{
				o->invisible = false;
			}
		}
		break;
	}
	
	if (crystal_tofront && o->dir == LEFT)
	{
		o->BringToFront();
		crystal_tofront = false;
	}
}
Ejemplo n.º 10
0
void ai_core_ghostie(Object *o)
{
char hit = 0;

	if (o->xinertia > 0 && o->blockr) hit = 1;
	if (o->xinertia < 0 && o->blockl) hit = 1;
	if (o->yinertia > 0 && o->blockd) hit = 1;
	if (o->yinertia < 0 && o->blocku) hit = 1;
	
	o->xinertia -= 0x20;
	LIMITX(0x400);
	
	if (hit)
	{
		effect(o->CenterX(), o->CenterY(), EFFECT_FISHY);
		o->Delete();
	}
	
	ai_animate2(o);
}
Ejemplo n.º 11
0
void ai_bute_archer_red(Object *o)
{
	//DebugCrosshair(o->x, o->y, 0, 255, 255);
	
	switch(o->state)
	{
		case 0:
		{
			o->state = 1;
			
			o->xmark = o->x;
			o->ymark = o->y;
			
			if (o->dir == LEFT)
				o->xmark -= (128<<CSF);
			else
				o->xmark += (128<<CSF);
			
			o->xinertia = random(-0x400, 0x400);
			o->yinertia = random(-0x400, 0x400);
		}
		case 1:		// come on screen
		{
			ANIMATE(1, 0, 1);
			
			if ((o->dir == LEFT && o->x < o->xmark) || \
				(o->dir == RIGHT && o->x > o->xmark))
			{
				o->state = 20;
			}
		}
		break;
		
		case 20:	// aiming
		{
			o->state = 21;
			o->timer = random(0, 150);
			
			o->frame = 2;
			o->animtimer = 0;
		}
		case 21:
		{
			ANIMATE(2, 2, 3);
			
			if (++o->timer > 300 || \
				(pdistlx(112<<CSF) && pdistly(16<<CSF)))
			{
				o->state = 30;
			}
		}
		break;
		
		case 30:	// flashing to fire
		{
			o->state = 31;
			o->timer = 0;
			o->animtimer = 0;
			o->frame = 3;
		}
		case 31:
		{
			ANIMATE(1, 3, 4);
			
			if (++o->timer > 30)
			{
				o->state = 40;
				o->frame = 5;
				
				Object *arrow = CreateObject(o->x, o->y, OBJ_BUTE_ARROW);
				arrow->dir = o->dir;
				arrow->xinertia = (o->dir == RIGHT) ? 0x800 : -0x800;
			}
		}
		break;
		
		case 40:	// fired
		{
			o->state = 41;
			o->timer = 0;
			o->animtimer = 0;
		}
		case 41:
		{
			ANIMATE(2, 5, 6);
			
			if (++o->timer > 40)
			{
				o->state = 50;
				o->timer = 0;
				o->xinertia = 0;
				o->yinertia = 0;
			}
		}
		break;
		
		case 50:	// retreat offscreen
		{
			ANIMATE(1, 0, 1);
			XACCEL(-0x20);
			
			if (o->Right() < 0 || o->Left() > ((map.xsize * TILE_W) << CSF))
				o->Delete();
		}
		break;
	}
	
	// sinusoidal hover around set point
	if (o->state != 50)
	{
		o->xinertia += (o->x < o->xmark) ? 0x2A : -0x2A;
		o->yinertia += (o->y < o->ymark) ? 0x2A : -0x2A;
		LIMITX(0x400);
		LIMITY(0x400);
	}
	
}
Ejemplo n.º 12
0
void ai_bute_sword_red(Object *o)
{
	switch(o->state)
	{
		case 0:
		{
			o->state = 1;
			o->sprite = SPR_BUTE_SWORD_RED_FALLING;
			o->MoveAtDir(o->dir, 0x600);
			o->dir = 0;
		}
		case 1:
		{
			ANIMATE(2, 0, 3);
			
			if (++o->timer == 8)
				o->flags &= ~FLAG_IGNORE_SOLID;
			
			if (o->timer >= 16)
			{
				o->state = 10;
				o->sprite = SPR_BUTE_SWORD_RED;
				o->frame = 0;
				
				o->flags |= FLAG_SHOOTABLE;
				o->damage = 5;
			}
		}
		break;
		
		case 10:
		{
			ANIMATE(1, 0, 1);
			FACEPLAYER;
			
			// when player is below them, they come towards him,
			// when player is above, they sweep away.
			if (player->CenterY() > (o->y + (24 << CSF)))
			{
				XACCEL(0x10);
			}
			else
			{
				XACCEL(-0x10);
			}
			
			o->yinertia += (o->y <= player->y) ? 0x10 : -0x10;
			
			if ((o->blockl && o->xinertia < 0) || \
				(o->blockr && o->xinertia > 0))
			{
				o->xinertia = -o->xinertia;
			}
			
			if ((o->blocku && o->yinertia <= 0) || \
				(o->blockd && o->yinertia >= 0))
			{
				o->yinertia = -o->yinertia;
			}
			
			LIMITX(0x5ff);
			LIMITY(0x5ff);
		}
		break;
	}
}
Ejemplo n.º 13
0
void ai_jelly(Object *o)
{
	switch(o->state)
	{
		case 0:
		{
			o->nxflags |= NXFLAG_SLOW_WHEN_HURT;
			o->timer = random(0, 20);
			o->xmark = o->x;
			o->ymark = o->y;
			
			o->xinertia = (o->dir == LEFT) ? 0x200 : -0x200;
			o->state = 1;
		}
		case 1:
		{
			if (--o->timer <= 0)
			{
				o->state = 10;
			}
			else break;
		}
		case 10:
		{
			if (++o->timer > 10)
			{
				o->timer = o->frame = 0;
				o->state = 11;
			}
		}
		break;
		
		case 11:
		{
			if (++o->animtimer > 5)
			{
				o->animtimer = 0;
				o->frame++;
			}
			
			if (o->frame == 2)
			{
				o->xinertia += (o->dir == LEFT) ? -0x100 : +0x100;
				o->yinertia -= 0x200;
			}
			else if (o->frame > 2)
			{
				o->state = 12;
				o->frame = 3;
			}
		}
		break;
		
		case 12:
		{
			o->timer++;
			if (o->y > o->ymark && o->timer > 10)
			{
				o->timer = 0;
				o->state = 10;
				o->frame = 0;
			}
		}
		break;
	}
	
	o->dir = (o->x > o->xmark) ? LEFT : RIGHT;
	
	if (o->blockl) o->dir = RIGHT;
	if (o->blockr) o->dir = LEFT;
	if (o->blockd) o->yinertia = -0x200;
	
	o->yinertia += 0x20;
	
	LIMITX(0x100);
	LIMITY(0x200);
}
Ejemplo n.º 14
0
void ai_npc_sue(Object *o)
{
	switch(o->state)
	{
		case 0:		// stand and blink
			o->timer = 0;
			o->frame = 0;
			o->xinertia = 0;
			o->sue.carried_by = NULL;
			randblink(o, 1, 4);
		break;
		
		case 3:		// walking
		case 4:		// walking
		case 5:		// face away
			ai_generic_npc(o);
		break;
		
		// got punched by Igor
		case 6:
			o->state = 7;
			o->frame = 7;
			o->timer = 0;
			sound(SND_ENEMY_SQUEAK);
		case 7:
			if (++o->timer > 10)
				o->state = 0;
		break;
		
		// got punched extra hard by Igor
		// flys through air backwards and crashes
		case 8:
			o->state = 9;
			o->frame = 7;
			o->timer = 0;
			sound(SND_ENEMY_SQUEAK);
			
			o->yinertia = -0x200;
			XMOVE(-0x400);
		case 9:
			if (++o->timer > 3 && o->blockd)
			{
				o->state = 10;
				o->dir ^= 1;
			}
		break;
		case 10:
			o->xinertia = 0;
			o->frame = 8;
		break;
		
		// punching the air (when she tells Igor "I'm not afraid of you!")
		case 11:
			o->state = 12;
			o->timer = 0;
			o->animframe = 0;
			o->animtimer = 0;
		case 12:
		{
			const static int punchframes[] = { 10, 0 };
			o->animate_seq(8, punchframes, 2);
		}
		break;
		
		// picked up & carried away by Igor
		case 13:
			o->frame = 11;
			o->xinertia = 0;
			o->yinertia = 0;
			o->state = 14;
			
			// find Igor
			o->sue.carried_by = FindObjectByID2(501);
			if (!o->sue.carried_by)
				NX_ERR("-- Could not find entity carrying Sue (ID 501)\n");
		case 14:	// being carried--see aftermove routine
			o->frame = 9;
		break;
		
		// spawn red crystal and call it to us (Undead Core intro)
		case 15:
		{
			o->PushBehind(dr_create_red_crystal(o->x+(128<<CSF), o->y));
			
			o->state = 16;
			o->xinertia = 0;
			o->frame = 0;
		}
		case 16:
		{
			crystal_xmark = o->x - (18<<CSF);
			crystal_ymark = o->y - (8<<CSF);
		}
		break;
		case 17:	// look up (still followed by red crystal)
		{
			o->xinertia = 0;
			o->frame = 12;
			
			crystal_xmark = o->x;
			crystal_ymark = o->y - (8<<CSF);
		}
		break;
		
		// run away from DOCTOR_GHOST and hide behind player
		case 20:
		{
			o->state = 21;
			o->frame = 2;
			o->animtimer = 0;
		}
		case 21:
		{
			ANIMATE(2, 2, 5);
			XMOVE(0x400);
			
			if (o->x < player->x - (8<<CSF))
			{
				o->dir = RIGHT;
				o->state = 0;
			}
		}
		break;
		
		// run, during "we've got to get out of here" post-undead core cutscene.
		case 30:
		{
			o->state = 31;
			o->frame = 2;
			o->animtimer = 0;
		}
		case 31:
		{
			ANIMATE(2, 2, 5);
			XMOVE(0x400);
		}
		break;
		
		case 40:	// she jumps off the island
		{
			o->state = 41;
			o->frame = 9;
			o->yinertia = -0x400;
		}
		break;
		
		/*default:
			NX_ERR("-- Sue entered unhandled state %d (0x%02x)\n", o->state, o->state);
			exit(1);*/
	}
	
	o->yinertia += 0x40;
	LIMITX(0x400);
	LIMITY(0x5ff);
}
Ejemplo n.º 15
0
void ai_toroko(Object *o)
{
	switch(o->state)
	{
		case 0:		// stand and blink
			o->frame = 0;
			o->xinertia = 0;
			randblink(o, 1, 4);
		break;
		
		case 3:		// run away!!
			o->state = 4;
			o->frame = 1;
			o->animtimer = 0;
		case 4:
			ANIMATE(2, 1, 4);
			
			if (o->blockl) { o->dir = RIGHT; o->xinertia = 0x200; }
			if (o->blockr) { o->dir = LEFT; o->xinertia = -0x200; }
			
			XMOVE(0x400);
		break;
		
		case 6:		// hop and run away!!
			o->state = 7;
			o->frame = 1;
			o->animtimer = 0;
			o->yinertia = -0x400;
			o->toro.left_ground = false;
		case 7:
			ANIMATE(2, 1, 4);
			XMOVE(0x100);
			
			if (!o->toro.left_ground)
			{
				if (!o->blockd)
					o->toro.left_ground = true;
			}
			else
			{
				if (o->blockd)
				{
					o->toro.left_ground = false;
					o->state = 3;
				}
			}
		break;
		
		// small hop straight up/down from Balrog
		// shaking the ground, used in Shack
		case 8:
			o->frame = 1;
			o->timer = 0;
			o->state = 9;
			o->yinertia = -0x200;
			o->toro.left_ground = false;
		case 9:
		{
			if (!o->toro.left_ground)
			{
				if (!o->blockd)
					o->toro.left_ground = true;
			}
			else
			{
				if (o->blockd)
				{
					o->toro.left_ground = false;
					o->state = 0;
				}
			}
		}
		break;
		
		case 10:	// eeks and falls down
			o->state = 11;
			o->frame = 5;
			o->yinertia = -(2 << CSF);
			sound(SND_ENEMY_SQUEAK);
			XMOVE(0x100);
		break;
		case 11:	// falling down
			if (o->blockd)
			{
				o->state = 12;
				o->frame = 6;
				o->flags |= FLAG_SCRIPTONACTIVATE;
				o->xinertia = 0;
			}
		break;
	}
	
	o->yinertia += 0x40;
	LIMITX(0x400);
	LIMITY(0x5ff);
}
Ejemplo n.º 16
0
// Kulala
void ai_giant_jelly(Object *o)
{
	switch(o->state)
	{
		case 0:		// frozen/in stasis. waiting for player to shoot.
			o->frame = 4;
			if (o->shaketime)
			{
				quake(30);
				o->state = 10;
				o->frame = 0;
				o->timer = 0;
			}
		break;
		
		case 10:	// falling
		{
			o->flags |= FLAG_SHOOTABLE;
			o->flags &= ~FLAG_INVULNERABLE;
			
			if (++o->timer > 40)
			{
				o->timer = 0;
				o->animtimer = 0;
				o->state = 11;
			}
		}
		break;
		
		case 11:	// animate thrust
		{
			ANIMATE_FWD(5);
			if (o->frame >= 3)
			{
				o->frame = 3;
				o->state = 12;
			}
		}
		break;
		
		case 12:	// thrusting upwards
		{
			o->yinertia = -0x155;
			if (++o->timer > 20)
			{
				o->state = 10;
				o->frame = 0;
				o->timer = 0;
			}
		}
		break;
		
		case 20:	// shot/freeze over/go invulnerable
		{
			o->frame = 4;
			o->xinertia >>= 1;
			o->yinertia += 0x20;
			
			if (!o->shaketime)
			{
				o->state = 10;
				o->frame = 0;
				o->timer = 30;
			}
		}
		break;
	}
	
	if (o->shaketime)
	{
		if (++o->timer3 > 12)
		{
			o->state = 20;
			o->frame = 4;
			o->flags &= ~FLAG_SHOOTABLE;
			o->flags |= FLAG_INVULNERABLE;
		}
	}
	else
	{
		o->timer3 = 0;
	}
	
	if (o->state >= 10)
	{
		if (o->blockl) { o->timer2 = 50; o->dir = RIGHT; }
		if (o->blockr) { o->timer2 = 50; o->dir = LEFT; }
		
		if (o->timer2 > 0)
		{
			o->timer2--;
			XACCEL(0x80);
		}
		else
		{
			o->timer2 = 50;
			FACEPLAYER;
		}
		
		o->yinertia += 0x10;
		if (o->blockd) o->yinertia = -0x300;
	}
	
	LIMITX(0x100);
	LIMITY(0x300);
}
Ejemplo n.º 17
0
void ai_bat_hang(Object *o)
{
	switch(o->state)
	{
		case 0:
			o->state = 1;
		case 1:		// hanging and waiting
			if (!random(0, 100))
			{
				o->state = 2;
				o->timer = 0;
				o->frame = 1;
			}
			
			if (pdistlx(0x1000) && pdistly2(0x1000, 0x9000))
			{
				o->frame = 0;
				o->state = 3;
			}
		break;
		
		case 2:		// blinking
			if (++o->timer > 8)
			{
				o->state = 1;
				o->frame = 0;
			}
		break;
		
		case 3:		// at attention
			o->frame = 0;
			if (o->shaketime || pdistlx(0x2800))
			{
				o->frame = 1;
				o->animtimer = 0;
				o->state = 4;
				o->timer = 0;
			}
		break;
		
		case 4:		// falling
			o->yinertia += 0x20;
			LIMITY(0x5ff);
			
			o->timer++;
			if (o->timer > 20 || o->blockd)
			{
				if (o->blockd || ((player->y - 0x2000) < o->y))
				{	// start flying
					o->animtimer = 0;
					o->frame = 2;
					o->state = 5;
					o->ymark = o->y;
					if (o->blockd) o->yinertia = -0x200;
				}
			}
		break;
		
		case 5:		// flying
			ANIMATE(1, 2, 4);
			FACEPLAYER;
			
			o->xinertia += (o->x > player->x) ? -0x20 : 0x20;
			o->yinertia += (o->y > o->ymark) ? -0x10 : 0x10;
			
			LIMITX(0x200);
			LIMITY(0x200);
			
			if (o->blockd) o->yinertia = -0x200;
			if (o->blockr) o->yinertia = 0x200;
		break;
	}
}
Ejemplo n.º 18
0
void ai_critter(Object *o)
{
	switch(o->state)
	{
		case 0:
		{
			if (o->type == OBJ_POWER_CRITTER)
			{	// altered physics for Power Critter
				o->critter.jumpheight = 0x2800;
				o->critter.jumpgrav = 0x1C;
				o->critter.falldmg = 12;
			}
			else
			{
				o->critter.jumpheight = 0;
				o->critter.jumpgrav = 0x40;
				o->critter.falldmg = 3;
				
				if (o->type == OBJ_CRITTER_HOPPING_BLUE || 			// first cave
					o->type == OBJ_CRITTER_HOPPING_GREEN || 		// egg 1
					o->type == OBJ_CRITTER_HOPPING_AQUA ||			// egg 2
					o->type == OBJ_CRITTER_HOPPING_RED)				// last cave
				{
					o->critter.canfly = false;
					
					// critters in egg1 only 2 dmg
					if (o->type == OBJ_CRITTER_HOPPING_GREEN)
						o->critter.falldmg = 2;
					
					// critters in First Cave don't jump as high
					if (o->type != OBJ_CRITTER_HOPPING_BLUE)
					{
						o->critter.jumpgrav = 0x2C;
					}
				}
				else
				{
					// critters are purple in Maze
					o->sprite = SPR_CRITTER_FLYING_CYAN;
					
					o->critter.canfly = true;
				}
			}
			
			o->state = 1;
		} //fall thru
		case 1:
		{
			o->frame = 0;
			
			if (o->timer >= 8)
			{
				int attack_dist = (o->critter.canfly) ? (96 << CSF) : (64 << CSF);
				
				// close enough to attack?
				if (pdistlx(attack_dist) && pdistly2(96<<CSF, 48<<CSF))
				{
					o->state = 2;
					o->frame = 0;
					o->timer = 0;
				}
				else if (pdistlx(attack_dist + (32<<CSF)) && pdistly2(128<<CSF, 48<<CSF))
				{	// no, but close enough to look up at "attention" and watch player
					FACEPLAYER;
					o->frame = 1;
					o->timer = 8;	// reset timer to stop watching
				}
				else
				{
					// once a little time has passed stop watching him if he turns his back
					if ((o->x > player->x && player->dir==LEFT) || \
						(o->x < player->x && player->dir==RIGHT))
					{
						if (++o->timer >= 150)
						{
							o->frame = 0;
							o->timer = 8;
						}
					}
					else o->timer = 8;
				}
			}
			else
			{
				o->timer++;
			}
			
			if (o->shaketime)
			{	// attack if shot
				o->state = 2;
				o->frame = 0;
				o->timer = 0;
			}
		}
		break;
		
		case 2:		// start jump
		{
			if (++o->timer > 8)
			{
				o->state = 3;
				o->frame = 2;
				o->yinertia = -1228;
				sound(SND_ENEMY_JUMP);
				
				FACEPLAYER;
				XMOVE(0x100);
			}
		}
		break;
		
		case 3:		// jumping
		{
			// enter flying phase as we start to come down or
			// if we hit the ceiling.
			if (o->yinertia > 0x100 || o->blocku)
			{
				// during flight we will sine-wave oscilliate around this position
				o->ymark = (o->y - o->critter.jumpheight);
				
				o->state = 4;
				o->frame = 3;
				o->timer = 0;
			}
			else
			{
				if (o->blockd && o->yinertia >= 0)
				{	// jumped onto a platform before we got to fly--land immediately
					goto landed;
				}
				break;
			}
		}	// fall-thru
		case 4:		// flying
		{
			FACEPLAYER;
			
			// time to come down yet?
			// (come down immediately if we are not one of the flying critters)
			if (!o->critter.canfly || \
				o->blockl || o->blockr || o->blocku || \
				++o->timer > 100)
			{
				o->damage = o->critter.falldmg;			// increased damage if falls on player
				o->state = 5;
				o->frame = 2;
				o->yinertia /= 2;
			}
			else
			{
				// run the propeller
				ANIMATE(0, 3, 5);
				if ((o->timer & 3)==1) sound(SND_CRITTER_FLY);
				
				if (o->blockd) o->yinertia = -0x200;
			}
		}
		break;
		
		case 5:		// coming down from flight
		{
			if (o->blockd)
			{	// landed
landed: ;
				o->damage = 2;			// reset to normal damage
				o->state = 1;
				
				o->frame = 0;
				o->timer = 0;
				o->xinertia = 0;
				
				sound(SND_THUD);
			}
		}
		break;
	}
	
	if (o->state == 4)		// flying
	{
		// fly towards player
		o->xinertia += (o->x > player->x) ? -0x20 : 0x20;
		// sine-wave oscillate
		o->yinertia += (o->y > o->ymark) ? -0x10 : 0x10;
		
		LIMITX(0x200);
		LIMITY(0x200);
	}
	else if (o->state == 3 && o->yinertia < 0)	// jumping up
	{
		o->yinertia += o->critter.jumpgrav;
	}
	else
	{
		o->yinertia += 0x40;
	}
	
	LIMITY(0x5ff);
}
Ejemplo n.º 19
0
void ai_buyobuyo(Object *o)
{
    bool deleteme = false;
    ANIMATE(6, 0, 1);

    switch(o->state)
    {
    case 0:
    {
        // shoot up down at player...
        o->yinertia = (o->dir == LEFT) ? -0x600 : 0x600;
        o->state = 1;
        o->timer = 0;
    }
    case 1:
    {
        o->timer++;		// inc fly time
        // reached height of player yet?
        if (pdistly(0x2000))
        {
            o->state = 2;
            ai_buyobuyo(o);
            return;
        }
    }
    break;

    case 2:
    {
        // this slight "minimum fly time" keeps the underwater ones from
        // smacking into the floor if the player is underwater with them
        if (++o->timer > 3)
        {
            FACEPLAYER;
            o->xmark = o->x;
            o->ymark = o->y;

            o->xinertia = random(0, 1) ? 0x200 : -0x200;
            o->yinertia = random(0, 1) ? 0x200 : -0x200;

            o->state = 3;
        }
    }
    break;

    case 3:
    {
        if (o->x > o->xmark) o->xinertia -= 0x20;
        if (o->x < o->xmark) o->xinertia += 0x20;
        if (o->y > o->ymark) o->yinertia -= 0x20;
        if (o->y < o->ymark) o->yinertia += 0x20;
        LIMITX(0x400);
        LIMITY(0x400);

        // move the point we are bobbling around
        o->xmark += (o->dir == LEFT) ? -(1 << CSF) : (1 << CSF);
        //debugVline(o->xmark, 0, 0xff, 0);

        if (++o->timer > 300)
            deleteme = true;
    }
    break;
    }

    if ((o->blockl && o->xinertia < 0) || \
            (o->blockr && o->xinertia > 0) || \
            (o->blocku && o->yinertia < 0) || \
            (o->blockd && o->yinertia > 0))
    {
        deleteme = true;
    }

    if (deleteme)
    {
        effect(o->CenterX(), o->CenterY(), EFFECT_STARPOOF);
        o->Delete();
        return;
    }
}
Ejemplo n.º 20
0
// his lightning-strike attack
static void run_lightning(Object *o)
{
	switch(o->state)
	{
		// lightning strikes (targeting player)
		case BP_LIGHTNING_STRIKE:
		{
			o->xmark = player->x;
			o->yinertia = -0x600;
			
			o->timer = 0;
			o->timer2 = 0;
			o->animtimer = 0;
			
			o->frame = 4;		// facing screen
			o->dir = LEFT;		// not flashing
			
			o->state++;
		}
		case BP_LIGHTNING_STRIKE+1:
		{
			ANIMATE(1, 4, 5);
			
			o->xinertia += (o->x < o->xmark) ? 0x40 : -0x40;
			o->yinertia += (o->y < FLOAT_Y) ? 0x40 : -0x40;
			LIMITX(0x400);
			LIMITY(0x400);
			
			// run firing
			if (++o->timer > 200)
			{
				int pos = (o->timer % 40);
				
				if (pos == 1)
				{
					// spawn lightning target
					CreateObject(player->CenterX(), LIGHTNING_Y, OBJ_BALLOS_TARGET)->dir = LEFT;
					o->dir = RIGHT;		// switch to flashing frames
					o->animtimer = 0;
					
					// after 8 attacks, switch to even-spaced strikes
					if (++o->timer2 >= 8)
					{
						o->xinertia = 0;
						o->yinertia = 0;
						
						o->dir = RIGHT;		// flashing
						o->frame = 5;		// flash red then white during screen flash
						o->animtimer = 1;	// desync animation from screen flashes so it's visible
						
						o->state++;
						o->timer = 0;
						o->timer2 = 0;
					}
				}
				else if (pos == 20)
				{
					o->dir = LEFT;		// stop flashing
				}
			}
		}
		break;
		
		// lightning strikes (evenly-spaced everywhere)
		case BP_LIGHTNING_STRIKE+2:
		{
			ANIMATE(1, 4, 5);
			o->timer++;
			
			if (o->timer == 40)
				flashscreen.Start();
			
			if (o->timer > 50)
			{
				if ((o->timer % 10) == 1)
				{
					CreateObject((o->timer2 * TILE_W) << CSF, \
								 LIGHTNING_Y, OBJ_BALLOS_TARGET)->dir = LEFT;
					o->timer2 += 4;
					
					if (o->timer2 >= 40)
						o->state = BP_RETURN_TO_GROUND;
				}
			}
		}
		break;
	}
}
Ejemplo n.º 21
0
void XBoss::run_tread(int index)
{
	Object *o = treads[index];
	
	switch(o->state)
	{
		case 0:
		{
			o->flags |= (FLAG_SOLID_BRICK | FLAG_INVULNERABLE | FLAG_NOREARTOPATTACK);
			o->state = STATE_TREAD_STOPPED;
		}
		case STATE_TREAD_STOPPED:
		{
			o->frame = 0;
			o->damage = 0;
			o->flags &= ~FLAG_BOUNCY;
		}
		break;
		
		case STATE_TREAD_RUN:
		{
			o->flags |= FLAG_BOUNCY;
			o->timer = 0;
			o->frame = 2;
			o->animtimer = 0;
			
			o->state++;
		}
		case STATE_TREAD_RUN+1:
		{
			ANIMATE(0, 2, 3);
			XACCEL(0x20);
			
			if (++o->timer > 30)
			{
				o->flags &= ~FLAG_BOUNCY;
				o->frame = 0;
				o->animtimer = 0;
				o->state++;
			}
		}
		break;
		case STATE_TREAD_RUN+2:
		{
			ANIMATE(1, 0, 1);
			XACCEL(0x20);
			
			o->timer++;
		}
		break;
		
		case STATE_TREAD_BRAKE:
		{
			o->frame = 2;
			o->animtimer = 0;
			
			o->flags |= FLAG_BOUNCY;
			o->state++;
		}
		case STATE_TREAD_BRAKE+1:
		{
			ANIMATE(0, 2, 3);
			XACCEL(0x20);
			
			if ((o->dir == RIGHT && o->xinertia > 0) || \
				(o->dir == LEFT && o->xinertia < 0))
			{
				o->xinertia = 0;
				o->state = STATE_TREAD_STOPPED;
			}
		}
		break;
	}
	
	// make motor noise
	switch(o->state)
	{
		case STATE_TREAD_RUN+1:
		case STATE_TREAD_BRAKE+1:
		{
			if (o->timer & 1)
				sound(SND_MOTOR_SKIP);
		}
		break;
		
		case STATE_TREAD_RUN+2:
		{
			if ((o->timer % 4) == 1)
				sound(SND_MOTOR_RUN);
		}
		break;
	}
	
	// determine if player is in a position where he could get run over.
	if (o->state > STATE_TREAD_STOPPED && o->xinertia != 0)
	{
		if (abs(player->y - o->CenterY()) <= (5 << CSF))
			o->damage = 10;
		else
			o->damage = 0;
	}
	else
	{
		o->damage = 0;
	}
	
	LIMITX(0x400);
}
Ejemplo n.º 22
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);
}
Ejemplo n.º 23
0
void ai_block_moveh(Object *o)
{
	int px = player->CenterX();
	int objx = o->CenterX();
	
	switch(o->state)
	{
		case 0:
         NX_LOG("ai_block_moveh - state 0.\n");
			o->flags |= FLAG_SOLID_BRICK;
			o->smushdamage = 100;
			o->state = (o->dir == LEFT) ? 10:20;
		break;
		
		case 10:	// at right edge, ready to travel left
         NX_LOG("ai_block_moveh - state 10.\n");
			if (((px > objx) && (px - objx) < 0x3200) || \
				((px < objx) && (objx - px) < 0x32000))
			{
				if (pdistly(0x3200))
				{
					o->state = 30;
					o->timer = 0;
				}
			}
		break;
		
		case 20:	// at left edge, ready to travel right
         NX_LOG("ai_block_moveh - state 20.\n");
			if (((px > objx) && (px - objx) < 0x32000) || \
				((px < objx) && (objx - px) < 0x3200))
			{
				if (pdistly(0x3200))
				{
					o->state = 30;
					o->timer = 0;
				}
			}
		break;
		
		case 30:	// traveling
		{
         NX_LOG("ai_block_moveh - state 30.\n");
			XACCEL(0x20);
			LIMITX(0x200);
			
			// hit edge
			if ((o->dir == RIGHT && o->blockr) || (o->dir == LEFT && o->blockl))
			{
				SmokeSide(o, 4, o->dir);
				quake(10);
				
				o->xinertia = 0;
				o->dir ^= 1;
				o->state = (o->dir==LEFT) ? 10 : 20;
			}
			
			if ((++o->timer % 10) == 6)
				sound(SND_BLOCK_MOVE);
		}
		break;
	}
}
Ejemplo n.º 24
0
void ai_balrog_boss_running(Object *o)
{
	// try to catch player
	if (o->state == STATE_CHARGE+1 || o->state == STATE_JUMP)
	{
		if ((pdistlx(12 << CSF) && pdistly(8 << CSF)) && o->timer > 8)
		{
			hurtplayer(2);
			balrog_grab_player(o);
			o->state = STATE_CAUGHT_PLAYER;
		}
	}
	
	switch(o->state)
	{
		case 0:
		{
			FACEPLAYER;
			o->flags |= FLAG_SHOOTABLE;
			o->frame = 0;
			o->state = 1;
		}
		case 1:
		{
			if (++o->timer > 30)
			{
				o->state = STATE_CHARGE;
				o->timer2++;
			}
		}
		break;
		
		// running towards player
		case STATE_CHARGE:
		{
			o->state++;
			o->timer = 0;
			o->frame = 9;
			o->animtimer = 0;
		}
		case STATE_CHARGE+1:
		{
			XACCEL(0x10);
			walking_animation(o);
			
			if (++o->timer > 75 || \
				(o->dir == LEFT && o->blockl) ||
				(o->dir == RIGHT && o->blockr))
			{
				o->frame = 0;
				o->state = STATE_SLOW_DOWN;
				break;
			}
			
			// can jump every 3rd time, but if he catches the player
			// before he gets a chance to he does NOT jump on the next charge.
			if ((o->timer2 & 3) == 0)
			{
				if (o->timer > 25)
				{	// initiate jump
					o->frame = 3;
					o->yinertia = -0x400;
					o->state = STATE_JUMP;
				}
			}
		}
		break;
		
		// jumping
		case STATE_JUMP:
		{
			if (o->blockd && o->yinertia >= 0)
			{
				o->frame = 2;		// <-- Landed frame.
				quake(30);
				o->state = STATE_SLOW_DOWN;
			}
		}
		break;
		
		// slowing down after charging or jumping
		case STATE_SLOW_DOWN:
		{
			o->xinertia *= 4;
			o->xinertia /= 5;
			
			if (o->xinertia == 0)
				o->state = 0;
		}
		break;
		
		// caught player
		case STATE_CAUGHT_PLAYER:
		{
			if (balrog_toss_player_away(o))
				o->state = 0;
		}
		break;
	}
	
	o->yinertia += 0x20;
	LIMITX(0x400);
	LIMITY(0x5FF);
}