TombEngine/TR5Main/Objects/TR1/tr1_natla.cpp
TokyoSU 8e148277bf Added Entity
- Lara Evil (Atlantis Version)
- Natla and Evil Natla.
- Larson and Pierre (TR1)
- Raptor (TR1)
2019-12-06 15:26:18 +01:00

273 lines
No EOL
6.1 KiB
C++

#include "../newobjects.h"
#include "../../Game/Box.h"
#include "../../Game/people.h"
#include "../../Game/items.h"
#include "../../Game/missile.h"
/* HIT POINTS for Natla when she enters her second stage */
#define NATLA_NEAR_DEATH 200
enum natla_anims {
NATLA_EMPTY, NATLA_STOP, NATLA_FLY, NATLA_RUN, NATLA_AIM, NATLA_SEMIDEATH, NATLA_SHOOT, NATLA_FALL, NATLA_STAND, NATLA_DEATH
};
BITE_INFO natla_gun = { 5, 220, 7, 4 };
#define NATLA_FLYMODE 0x8000
#define NATLA_TIMER 0x7fff
#define NATLA_FIRE_ARC ANGLE(30)
#define NATLA_FLY_TURN ANGLE(5)
#define NATLA_RUN_TURN ANGLE(6)
#define NATLA_LAND_CHANCE 0x100
#define NATLA_DIE_TIME 30*16
#define NATLA_SHOT_DAMAGE 100
void NatlaControl(short itemNum)
{
if (!CreatureActive(itemNum))
return;
ITEM_INFO* item;
FX_INFO* fx;
CREATURE_INFO* natla;
AI_INFO info;
int shoot;
short angle, head, tilt, gun;
short facing = 0;
short fx_number, timer;
item = &Items[itemNum];
natla = (CREATURE_INFO*)item->data;
head = angle = tilt = 0;
gun = natla->jointRotation[0] * 7 / 8;
timer = natla->flags & NATLA_TIMER;
if (item->hitPoints <= 0 && item->hitPoints > -16384)
{
item->goalAnimState = NATLA_DEATH;
}
else if (item->hitPoints <= NATLA_NEAR_DEATH)
{
natla->LOT.step = STEP_SIZE;
natla->LOT.drop = -STEP_SIZE;
natla->LOT.fly = NO_FLYING;
CreatureAIInfo(item, &info);
if (info.ahead)
head = info.angle;
GetCreatureMood(item, &info, VIOLENT);
CreatureMood(item, &info, VIOLENT);
angle = CreatureTurn(item, NATLA_RUN_TURN);
shoot = (info.angle > -NATLA_FIRE_ARC && info.angle < NATLA_FIRE_ARC && Targetable(item, &info));
/* Reset facing */
if (facing)
{
item->pos.yRot += facing;
facing = 0;
}
switch (item->currentAnimState)
{
case NATLA_FALL:
if (item->pos.yPos < item->floor)
{
item->gravityStatus = true;
item->speed = 0;
}
else
{
item->gravityStatus = 0;
item->goalAnimState = NATLA_SEMIDEATH;
item->pos.yPos = item->floor;
timer = 0;
}
break;
case NATLA_STAND:
if (!shoot)
item->goalAnimState = NATLA_RUN;
if (timer >= 20)
{
fx_number = CreatureEffect(item, &natla_gun, ShardGun);
if (fx_number != NO_ITEM)
{
fx = &Effects[fx_number];
gun = fx->pos.xRot;
SoundEffect(123, &fx->pos, NULL);
}
timer = 0;
}
break;
case NATLA_RUN:
tilt = angle;
if (timer >= 20)
{
fx_number = CreatureEffect(item, &natla_gun, ShardGun);
if (fx_number != NO_ITEM)
{
fx = &Effects[fx_number];
gun = fx->pos.xRot;
SoundEffect(123, &fx->pos, NULL);
}
timer = 0;
}
if (shoot)
item->goalAnimState = NATLA_STAND;
break;
case NATLA_SEMIDEATH:
if (timer == NATLA_DIE_TIME)
{
item->goalAnimState = NATLA_STAND;
natla->flags = 0;
timer = 0;
item->hitPoints = NATLA_NEAR_DEATH;
S_CDPlay(54, 0);
}
else
item->hitPoints = -16384;
break;
case NATLA_FLY:
item->goalAnimState = NATLA_FALL;
timer = 0;
break;
case NATLA_STOP:
case NATLA_SHOOT:
case NATLA_AIM:
item->goalAnimState = NATLA_SEMIDEATH;
item->flags = 0;
timer = 0;
break;
}
}
else
{
natla->LOT.step = STEP_SIZE;
natla->LOT.drop = -STEP_SIZE;
natla->LOT.fly = NO_FLYING;
CreatureAIInfo(item, &info);
shoot = (info.angle > -NATLA_FIRE_ARC && info.angle < NATLA_FIRE_ARC && Targetable(item, &info));
if (item->currentAnimState == NATLA_FLY && (natla->flags & NATLA_FLYMODE))
{
if ((natla->flags & NATLA_FLYMODE) && shoot && GetRandomControl() < NATLA_LAND_CHANCE)
natla->flags -= NATLA_FLYMODE;
if (!(natla->flags & NATLA_FLYMODE))
CreatureMood(item, &info, VIOLENT);
natla->LOT.step = WALL_SIZE * 20;
natla->LOT.drop = -WALL_SIZE * 20;
natla->LOT.fly = STEP_SIZE / 8;
CreatureAIInfo(item, &info);
}
else if (!shoot)
natla->flags |= NATLA_FLYMODE;
if (info.ahead)
head = info.angle;
if (item->currentAnimState != NATLA_FLY || (natla->flags & NATLA_FLYMODE))
CreatureMood(item, &info, TIMID);
item->pos.yRot -= facing;
angle = CreatureTurn(item, NATLA_FLY_TURN);
/* Adjust facing if flying, else reset */
if (item->currentAnimState == NATLA_FLY)
{
if (info.angle > NATLA_FLY_TURN)
facing += NATLA_FLY_TURN;
else if (info.angle < -NATLA_FLY_TURN)
facing -= NATLA_FLY_TURN;
else
facing += info.angle;
item->pos.yRot += facing;
}
else
{
item->pos.yRot += facing - angle;
facing = 0;
}
switch (item->currentAnimState)
{
case NATLA_STOP:
timer = 0;
if (natla->flags & NATLA_FLYMODE)
item->goalAnimState = NATLA_FLY;
else
item->goalAnimState = NATLA_AIM;
break;
case NATLA_FLY:
if (!(natla->flags & NATLA_FLYMODE) && item->pos.yPos == item->floor)
item->goalAnimState = NATLA_STOP;
if (timer >= 30)
{
fx_number = CreatureEffect(item, &natla_gun, BombGun);
if (fx_number != NO_ITEM)
{
fx = &Effects[fx_number];
gun = fx->pos.xRot;
SoundEffect(123, &fx->pos, NULL);
}
timer = 0;
}
break;
case NATLA_AIM:
if (item->requiredAnimState)
item->goalAnimState = item->requiredAnimState;
else if (shoot)
item->goalAnimState = NATLA_SHOOT;
else
item->goalAnimState = NATLA_STOP;
break;
case NATLA_SHOOT:
if (!item->requiredAnimState)
{
/* Eat this ... */
fx_number = CreatureEffect(item, &natla_gun, BombGun);
if (fx_number != NO_ITEM)
gun = Effects[fx_number].pos.xRot;
fx_number = CreatureEffect(item, &natla_gun, BombGun);
if (fx_number != NO_ITEM)
Effects[fx_number].pos.yRot += (short)((GetRandomControl() - 0x4000) / 4);
fx_number = CreatureEffect(item, &natla_gun, BombGun);
if (fx_number != NO_ITEM)
Effects[fx_number].pos.yRot += (short)((GetRandomControl() - 0x4000) / 4);
item->requiredAnimState = NATLA_STOP;
}
break;
}
}
CreatureTilt(item, tilt);
/* Aim Natla's gun arm */
CreatureJoint(item, 0, -head);
if (gun)
CreatureJoint(item, 0, gun);
timer++;
natla->flags = (natla->flags & NATLA_FLYMODE) + timer;
/* Actually do animation allowing for collisions */
item->pos.yRot -= facing;
CreatureAnimation(itemNum, angle, tilt);
item->pos.yRot += facing;
}