TombEngine/TR5Main/Objects/TR1/Entity/tr1_wolf.cpp

223 lines
5.1 KiB
C++
Raw Normal View History

#include "framework.h"
#include "tr1_wolf.h"
#include "items.h"
#include "box.h"
#include "effect.h"
#include "lara.h"
#include "setup.h"
#include "level.h"
BITE_INFO wolfBite = { 0, -14, 174, 6 };
2020-11-12 23:16:27 -06:00
enum wolfStates {
STATE_EMPTY,
STATE_STOP,
STATE_WALK,
STATE_RUN,
STATE_JUMP,
STATE_STALK,
STATE_ATTACK,
STATE_HOWL,
STATE_SLEEP,
STATE_CROUCH,
STATE_FASTTURN,
STATE_DEATH,
STATE_BITE
};
#define TOUCH (0x774f)
#define SLEEP_FRAME 96
#define DIE_ANIM 20
#define ATTACK_RANGE SQUARE(WALL_SIZE*3/2)
#define STALK_RANGE SQUARE(WALL_SIZE*3)
#define BITE_DAMAGE 100
#define LUNGE_DAMAGE 50
#define WAKE_CHANCE 0x20
#define SLEEP_CHANCE 0x20
#define HOWL_CHANCE 0x180
#define WALK_TURN ANGLE(2)
#define RUN_TURN ANGLE(5)
#define STALK_TURN ANGLE(2)
void InitialiseWolf(short itemNum)
{
ITEM_INFO* item = &g_Level.Items[itemNum];
ClearItem(itemNum);
2020-11-12 23:16:27 -06:00
item->frameNumber = SLEEP_FRAME;
}
void WolfControl(short itemNum)
{
if (!CreatureActive(itemNum))
return;
2020-11-12 23:16:27 -06:00
short head;
short angle;
short tilt;
ITEM_INFO* item = &g_Level.Items[itemNum];
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
2020-11-12 23:16:27 -06:00
head = angle = tilt = 0;
AI_INFO info;
if (item->hitPoints <= 0)
{
2020-11-12 23:16:27 -06:00
if (item->currentAnimState != STATE_DEATH)
{
2020-11-12 23:16:27 -06:00
item->animNumber = Objects[ID_WOLF].animIndex + DIE_ANIM + (short)(GetRandomControl() / 11000);
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
2020-11-12 23:16:27 -06:00
item->currentAnimState = STATE_DEATH;
}
}
else
{
CreatureAIInfo(item, &info);
if (info.ahead)
head = info.angle;
GetCreatureMood(item, &info, TIMID);
CreatureMood(item, &info, TIMID);
angle = CreatureTurn(item, creature->maximumTurn);
switch (item->currentAnimState)
{
2020-11-12 23:16:27 -06:00
case STATE_SLEEP:
head = 0;
if (creature->mood == ESCAPE_MOOD || info.zoneNumber == info.enemyZone)
{
2020-11-12 23:16:27 -06:00
item->requiredAnimState = STATE_CROUCH;
item->goalAnimState = STATE_STOP;
}
2020-11-12 23:16:27 -06:00
else if (GetRandomControl() < WAKE_CHANCE)
{
2020-11-12 23:16:27 -06:00
item->requiredAnimState = STATE_WALK;
item->goalAnimState = STATE_STOP;
}
break;
2020-11-12 23:16:27 -06:00
case STATE_STOP:
if (item->requiredAnimState)
item->goalAnimState = item->requiredAnimState;
else
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_WALK;
break;
2020-11-12 23:16:27 -06:00
case STATE_WALK:
creature->maximumTurn = WALK_TURN;
if (creature->mood != BORED_MOOD)
{
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_STALK;
item->requiredAnimState = STATE_EMPTY;
}
2020-11-12 23:16:27 -06:00
else if (GetRandomControl() < SLEEP_CHANCE)
{
2020-11-12 23:16:27 -06:00
item->requiredAnimState = STATE_SLEEP;
item->goalAnimState = STATE_STOP;
}
break;
2020-11-12 23:16:27 -06:00
case STATE_CROUCH:
if (item->requiredAnimState)
item->goalAnimState = item->requiredAnimState;
else if (creature->mood == ESCAPE_MOOD)
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_RUN;
else if (info.distance < SQUARE(345) && info.bite)
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_BITE;
else if (creature->mood == STALK_MOOD)
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_STALK;
else if (creature->mood == BORED_MOOD)
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_STOP;
else
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_RUN;
break;
2020-11-12 23:16:27 -06:00
case STATE_STALK:
creature->maximumTurn = STALK_TURN;
if (creature->mood == ESCAPE_MOOD)
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_RUN;
else if (info.distance < SQUARE(345) && info.bite)
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_BITE;
else if (info.distance > SQUARE(3072))
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_RUN;
else if (creature->mood == ATTACK_MOOD)
{
if (!info.ahead || info.distance > SQUARE(1536) ||
(info.enemyFacing < FRONT_ARC && info.enemyFacing > -FRONT_ARC))
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_RUN;
}
2020-11-12 23:16:27 -06:00
else if (GetRandomControl() < HOWL_CHANCE)
{
2020-11-12 23:16:27 -06:00
item->requiredAnimState = STATE_HOWL;
item->goalAnimState = STATE_CROUCH;
}
else if (creature->mood == BORED_MOOD)
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_CROUCH;
break;
case 3:
2020-11-12 23:16:27 -06:00
creature->maximumTurn = RUN_TURN;
tilt = angle;
2020-11-12 23:16:27 -06:00
if (info.ahead && info.distance < ATTACK_RANGE)
{
2020-11-12 23:16:27 -06:00
if (info.distance > (ATTACK_RANGE / 2) &&
(info.enemyFacing > FRONT_ARC || info.enemyFacing < -FRONT_ARC))
{
2020-11-12 23:16:27 -06:00
item->requiredAnimState = STATE_STALK;
item->goalAnimState = STATE_CROUCH;
}
else
{
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_ATTACK;
item->requiredAnimState = STATE_EMPTY;
}
}
2020-11-12 23:16:27 -06:00
else if (creature->mood == STALK_MOOD && info.distance < STALK_RANGE)
{
2020-11-12 23:16:27 -06:00
item->requiredAnimState = STATE_STALK;
item->goalAnimState = STATE_CROUCH;
}
else if (creature->mood == BORED_MOOD)
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_CROUCH;
break;
2020-11-12 23:16:27 -06:00
case STATE_ATTACK:
tilt = angle;
2020-11-12 23:16:27 -06:00
if (!item->requiredAnimState && (item->touchBits & TOUCH))
{
CreatureEffect(item, &wolfBite, DoBloodSplat);
2020-11-12 23:16:27 -06:00
LaraItem->hitPoints -= LUNGE_DAMAGE;
LaraItem->hitStatus = true;
2020-11-12 23:16:27 -06:00
item->requiredAnimState = STATE_RUN;
}
2020-11-12 23:16:27 -06:00
item->goalAnimState = STATE_RUN;
break;
case 12:
2020-11-12 23:16:27 -06:00
if (!item->requiredAnimState && (item->touchBits & TOUCH) && info.ahead)
{
CreatureEffect(item, &wolfBite, DoBloodSplat);
2020-11-12 23:16:27 -06:00
LaraItem->hitPoints -= BITE_DAMAGE;
LaraItem->hitStatus = true;
2020-11-12 23:16:27 -06:00
item->requiredAnimState = STATE_CROUCH;
}
break;
}
}
CreatureTilt(item, tilt);
CreatureJoint(item, 0, head);
CreatureAnimation(itemNum, angle, tilt);
2020-11-12 23:16:27 -06:00
}