TombEngine/TR5Main/Objects/TR2/tr2_skidman.cpp
2019-12-08 07:38:22 +01:00

247 lines
No EOL
6.3 KiB
C++

#include "../newobjects.h"
#include "../../Game/items.h"
#include "../../Game/collide.h"
#include "../../Game/lara.h"
#include "../../Game/lot.h"
#include "../../Game/Box.h"
#include "../../Game/people.h"
#include "../../Game/sphere.h"
extern LaraExtraInfo g_LaraExtra;
enum SKIDMAN_STATE { SMAN_EMPTY, SMAN_WAIT, SMAN_MOVING, SMAN_STARTLEFT, SMAN_STARTRIGHT, SMAN_LEFT, SMAN_RIGHT, SMAN_DEATH };
#define SMAN_MIN_TURN (ANGLE(6)/3)
#define SMAN_TARGET_ANGLE ANGLE(15)
#define SMAN_WAIT_RANGE SQUARE(WALL_SIZE*4)
#define SMAN_DEATH_ANIM 10
BITE_INFO skidooLeft = { 240, -190, 540, 0 };
BITE_INFO skidooRight = { -240, -190, 540, 0 };
void InitialiseSkidman(short itemNum)
{
short skidoo_item;
ITEM_INFO* item, *skidoo;
skidoo_item = CreateItem();
if (skidoo_item != NO_ITEM)
{
item = &Items[itemNum];
skidoo = &Items[skidoo_item];
skidoo->objectNumber = ID_SNOWMOBILE_GUN;
skidoo->pos.xPos = item->pos.xPos;
skidoo->pos.yPos = item->pos.yPos;
skidoo->pos.zPos = item->pos.zPos;
skidoo->pos.yRot = item->pos.yRot;
skidoo->roomNumber = item->roomNumber;
skidoo->flags = ITEM_INVISIBLE;
skidoo->shade = -1;
InitialiseItem(skidoo_item);
// The skidman remembers his skidoo
item->data = (void*)skidoo_item;
LevelItems++;
}
else
{
printf("FATAL: cannot create skidoo for SKIDMAN !");
}
}
void SkidManCollision(short itemNum, ITEM_INFO* laraitem, COLL_INFO* coll)
{
ITEM_INFO* item;
item = &Items[itemNum];
if (!TestBoundsCollide(item, laraitem, coll->radius))
return;
if (!TestCollision(item, laraitem))
return;
if (coll->enableBaddiePush)
{
if (item->speed > 0)
ItemPushLara(item, laraitem, coll, coll->enableSpaz, 0);
else
ItemPushLara(item, laraitem, coll, 0, 0);
}
/* If Lara is walking and hit by skidoo, gets hurt a lot */
if (g_LaraExtra.Vehicle == NO_ITEM && item->speed > 0)
{
laraitem->hitStatus = true;
laraitem->hitPoints -= 100;
}
}
void SkidManControl(short riderNum)
{
ITEM_INFO* item, * rider;
CREATURE_INFO* skidman;
AI_INFO info;
short angle, item_number;
int damage;
rider = &Items[riderNum];
if (rider->data == NULL)
{
printf("FATAL: rider data not contains the skidoo itemNumber !");
return;
}
item_number = (short)rider->data;
item = &Items[item_number];
/* Need to activate AI for skidoo (it's the skidoo that holds the brain) if not done yet */
if (!item->data)
{
EnableBaddieAI(item_number, TRUE);
item->status = ITEM_ACTIVE;
}
skidman = (CREATURE_INFO*)item->data;
angle = 0;
if (item->hitPoints <= 0)
{
if (rider->currentAnimState != SMAN_DEATH)
{
/* Separate skidoo from rider */
rider->pos.xPos = item->pos.xPos;
rider->pos.yPos = item->pos.yPos;
rider->pos.zPos = item->pos.zPos;
rider->pos.yRot = item->pos.yRot;
rider->roomNumber = item->roomNumber;
rider->animNumber = Objects[ID_SNOWMOBILE_DRIVER].animIndex + SMAN_DEATH_ANIM;
rider->frameNumber = Anims[rider->animNumber].frameBase;
rider->currentAnimState = SMAN_DEATH;
/* Break Lara's lock */
if (Lara.target == item)
Lara.target = NULL;
}
else
AnimateItem(rider);
/* Make skidoo stop */
if (item->currentAnimState == SMAN_MOVING || item->currentAnimState == SMAN_WAIT)
item->goalAnimState = SMAN_WAIT;
else
item->goalAnimState = SMAN_MOVING;
}
else
{
/* As skidoo has the brain, it needs to know if the rider was hurt */
CreatureAIInfo(item, &info);
GetCreatureMood(item, &info, VIOLENT);
CreatureMood(item, &info, VIOLENT);
angle = CreatureTurn(item, ANGLE(6)/2);
switch (item->currentAnimState)
{
case SMAN_WAIT:
if (skidman->mood == BORED_MOOD)
break;
else if (abs(info.angle) < SMAN_TARGET_ANGLE && info.distance < SMAN_WAIT_RANGE)
break;
item->goalAnimState = SMAN_MOVING;
break;
case SMAN_MOVING:
if (skidman->mood == BORED_MOOD)
item->goalAnimState = SMAN_WAIT;
else if (abs(info.angle) < SMAN_TARGET_ANGLE && info.distance < SMAN_WAIT_RANGE)
item->goalAnimState = SMAN_WAIT;
else if (angle < -SMAN_MIN_TURN)
item->goalAnimState = SMAN_STARTLEFT;
else if (angle > SMAN_MIN_TURN)
item->goalAnimState = SMAN_STARTRIGHT;
break;
case SMAN_STARTLEFT:
case SMAN_LEFT:
if (angle < -SMAN_MIN_TURN)
item->goalAnimState = SMAN_LEFT;
else
item->goalAnimState = SMAN_MOVING;
break;
case SMAN_STARTRIGHT:
case SMAN_RIGHT:
if (angle < -SMAN_MIN_TURN)
item->goalAnimState = SMAN_LEFT;
else
item->goalAnimState = SMAN_MOVING;
break;
}
}
/* Shoot them guns */
if (rider->currentAnimState != SMAN_DEATH)
{
if (!skidman->flags && abs(info.angle) < SMAN_TARGET_ANGLE && LaraItem->hitPoints > 0)
{
damage = (g_LaraExtra.Vehicle != NO_ITEM) ? 10 : 50; // more damage if Lara on foot
if (ShotLara(item, &info, &skidooLeft, 0, damage) + ShotLara(item, &info, &skidooRight, 0, damage))
skidman->flags = 5;
}
if (skidman->flags)
{
SoundEffect(43, &item->pos, 0);
skidman->flags--;
}
}
/* Use 'head_rotation' to store which track is required */
if (item->currentAnimState == SMAN_WAIT)
{
SoundEffect(153, &item->pos, 0);
skidman->jointRotation[0] = 0;
}
else
{
skidman->jointRotation[0] = (skidman->jointRotation[0] == 1) ? 2 : 1;
DoSnowEffect(item);
SoundEffect(155, &item->pos, 4 + ((0x10000 - (100 - item->speed) * 100) << 8));
}
CreatureAnimation(item_number, angle, 0);
/* Move rider to save position and animation as skidoo */
if (rider->currentAnimState != SMAN_DEATH)
{
rider->pos.xPos = item->pos.xPos;
rider->pos.yPos = item->pos.yPos;
rider->pos.zPos = item->pos.zPos;
rider->pos.yRot = item->pos.yRot;
if (item->roomNumber != rider->roomNumber)
ItemNewRoom(riderNum, item->roomNumber);
rider->animNumber = item->animNumber + (Objects[ID_SNOWMOBILE_DRIVER].animIndex - Objects[ID_SNOWMOBILE_GUN].animIndex);
rider->frameNumber = item->frameNumber + (Anims[rider->animNumber].frameBase - Anims[item->animNumber].frameBase);
}
else if (rider->status == ITEM_DEACTIVATED && item->speed == 0 && item->fallspeed == 0)
{
/* If rider has reached end of his death animation, turn his skidoo into one that Lara can ride */
RemoveActiveItem(riderNum);
rider->collidable = false;
rider->hitPoints = -16384;
rider->flags |= ONESHOT;
DisableBaddieAI(item_number);
item->objectNumber = ID_SNOWMOBILE;
item->status = ITEM_DEACTIVATED;
InitialiseSkidoo(item_number);
((SKIDOO_INFO*)item->data)->armed = true;
}
}