2020-05-27 09:21:20 +02:00
|
|
|
#include "framework.h"
|
2020-05-30 15:55:23 +02:00
|
|
|
#include "tr1_wolf.h"
|
2020-05-27 09:21:20 +02:00
|
|
|
#include "items.h"
|
|
|
|
#include "box.h"
|
|
|
|
#include "effect.h"
|
|
|
|
#include "lara.h"
|
|
|
|
#include "setup.h"
|
|
|
|
#include "level.h"
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2019-12-05 17:35:57 +01:00
|
|
|
void InitialiseWolf(short itemNum)
|
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
ITEM_INFO* item = &g_Level.Items[itemNum];
|
2019-12-05 17:35:57 +01:00
|
|
|
ClearItem(itemNum);
|
2020-11-12 23:16:27 -06:00
|
|
|
item->frameNumber = SLEEP_FRAME;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void WolfControl(short itemNum)
|
|
|
|
{
|
|
|
|
if (!CreatureActive(itemNum))
|
|
|
|
return;
|
|
|
|
|
2020-11-12 23:16:27 -06:00
|
|
|
short head;
|
|
|
|
short angle;
|
|
|
|
short tilt;
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
ITEM_INFO* item = &g_Level.Items[itemNum];
|
2019-12-05 17:35:57 +01:00
|
|
|
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
|
2020-11-12 23:16:27 -06:00
|
|
|
head = angle = tilt = 0;
|
|
|
|
AI_INFO info;
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
if (item->hitPoints <= 0)
|
|
|
|
{
|
2020-11-12 23:16:27 -06:00
|
|
|
if (item->currentAnimState != STATE_DEATH)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-11-12 23:16:27 -06:00
|
|
|
item->animNumber = Objects[ID_WOLF].animIndex + DIE_ANIM + (short)(GetRandomControl() / 11000);
|
2020-07-21 09:56:47 +02:00
|
|
|
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
|
2020-11-12 23:16:27 -06:00
|
|
|
item->currentAnimState = STATE_DEATH;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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:
|
2019-12-05 17:35:57 +01:00
|
|
|
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;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
2020-11-12 23:16:27 -06:00
|
|
|
else if (GetRandomControl() < WAKE_CHANCE)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-11-12 23:16:27 -06:00
|
|
|
item->requiredAnimState = STATE_WALK;
|
|
|
|
item->goalAnimState = STATE_STOP;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2020-11-12 23:16:27 -06:00
|
|
|
case STATE_STOP:
|
2019-12-05 17:35:57 +01:00
|
|
|
if (item->requiredAnimState)
|
|
|
|
item->goalAnimState = item->requiredAnimState;
|
|
|
|
else
|
2020-11-12 23:16:27 -06:00
|
|
|
item->goalAnimState = STATE_WALK;
|
2019-12-05 17:35:57 +01:00
|
|
|
break;
|
|
|
|
|
2020-11-12 23:16:27 -06:00
|
|
|
case STATE_WALK:
|
|
|
|
creature->maximumTurn = WALK_TURN;
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
if (creature->mood != BORED_MOOD)
|
|
|
|
{
|
2020-11-12 23:16:27 -06:00
|
|
|
item->goalAnimState = STATE_STALK;
|
|
|
|
item->requiredAnimState = STATE_EMPTY;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
2020-11-12 23:16:27 -06:00
|
|
|
else if (GetRandomControl() < SLEEP_CHANCE)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-11-12 23:16:27 -06:00
|
|
|
item->requiredAnimState = STATE_SLEEP;
|
|
|
|
item->goalAnimState = STATE_STOP;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2020-11-12 23:16:27 -06:00
|
|
|
case STATE_CROUCH:
|
2019-12-05 17:35:57 +01:00
|
|
|
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;
|
2019-12-05 17:35:57 +01:00
|
|
|
else if (info.distance < SQUARE(345) && info.bite)
|
2020-11-12 23:16:27 -06:00
|
|
|
item->goalAnimState = STATE_BITE;
|
2019-12-05 17:35:57 +01:00
|
|
|
else if (creature->mood == STALK_MOOD)
|
2020-11-12 23:16:27 -06:00
|
|
|
item->goalAnimState = STATE_STALK;
|
2019-12-05 17:35:57 +01:00
|
|
|
else if (creature->mood == BORED_MOOD)
|
2020-11-12 23:16:27 -06:00
|
|
|
item->goalAnimState = STATE_STOP;
|
2019-12-05 17:35:57 +01:00
|
|
|
else
|
2020-11-12 23:16:27 -06:00
|
|
|
item->goalAnimState = STATE_RUN;
|
2019-12-05 17:35:57 +01:00
|
|
|
break;
|
|
|
|
|
2020-11-12 23:16:27 -06:00
|
|
|
case STATE_STALK:
|
|
|
|
creature->maximumTurn = STALK_TURN;
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
if (creature->mood == ESCAPE_MOOD)
|
2020-11-12 23:16:27 -06:00
|
|
|
item->goalAnimState = STATE_RUN;
|
2019-12-05 17:35:57 +01:00
|
|
|
else if (info.distance < SQUARE(345) && info.bite)
|
2020-11-12 23:16:27 -06:00
|
|
|
item->goalAnimState = STATE_BITE;
|
2019-12-05 17:35:57 +01:00
|
|
|
else if (info.distance > SQUARE(3072))
|
2020-11-12 23:16:27 -06:00
|
|
|
item->goalAnimState = STATE_RUN;
|
2019-12-05 17:35:57 +01:00
|
|
|
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;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
2020-11-12 23:16:27 -06:00
|
|
|
else if (GetRandomControl() < HOWL_CHANCE)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-11-12 23:16:27 -06:00
|
|
|
item->requiredAnimState = STATE_HOWL;
|
|
|
|
item->goalAnimState = STATE_CROUCH;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
else if (creature->mood == BORED_MOOD)
|
2020-11-12 23:16:27 -06:00
|
|
|
item->goalAnimState = STATE_CROUCH;
|
2019-12-05 17:35:57 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
2020-11-12 23:16:27 -06:00
|
|
|
creature->maximumTurn = RUN_TURN;
|
2019-12-05 17:35:57 +01:00
|
|
|
tilt = angle;
|
|
|
|
|
2020-11-12 23:16:27 -06:00
|
|
|
if (info.ahead && info.distance < ATTACK_RANGE)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-11-12 23:16:27 -06:00
|
|
|
if (info.distance > (ATTACK_RANGE / 2) &&
|
2019-12-05 17:35:57 +01:00
|
|
|
(info.enemyFacing > FRONT_ARC || info.enemyFacing < -FRONT_ARC))
|
|
|
|
{
|
2020-11-12 23:16:27 -06:00
|
|
|
item->requiredAnimState = STATE_STALK;
|
|
|
|
item->goalAnimState = STATE_CROUCH;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-11-12 23:16:27 -06:00
|
|
|
item->goalAnimState = STATE_ATTACK;
|
|
|
|
item->requiredAnimState = STATE_EMPTY;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
}
|
2020-11-12 23:16:27 -06:00
|
|
|
else if (creature->mood == STALK_MOOD && info.distance < STALK_RANGE)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-11-12 23:16:27 -06:00
|
|
|
item->requiredAnimState = STATE_STALK;
|
|
|
|
item->goalAnimState = STATE_CROUCH;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
else if (creature->mood == BORED_MOOD)
|
2020-11-12 23:16:27 -06:00
|
|
|
item->goalAnimState = STATE_CROUCH;
|
2019-12-05 17:35:57 +01:00
|
|
|
break;
|
|
|
|
|
2020-11-12 23:16:27 -06:00
|
|
|
case STATE_ATTACK:
|
2019-12-05 17:35:57 +01:00
|
|
|
tilt = angle;
|
2020-11-12 23:16:27 -06:00
|
|
|
if (!item->requiredAnimState && (item->touchBits & TOUCH))
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
CreatureEffect(item, &wolfBite, DoBloodSplat);
|
2020-11-12 23:16:27 -06:00
|
|
|
LaraItem->hitPoints -= LUNGE_DAMAGE;
|
2019-12-05 17:35:57 +01:00
|
|
|
LaraItem->hitStatus = true;
|
2020-11-12 23:16:27 -06:00
|
|
|
item->requiredAnimState = STATE_RUN;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
2020-11-12 23:16:27 -06:00
|
|
|
item->goalAnimState = STATE_RUN;
|
2019-12-05 17:35:57 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 12:
|
2020-11-12 23:16:27 -06:00
|
|
|
if (!item->requiredAnimState && (item->touchBits & TOUCH) && info.ahead)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
CreatureEffect(item, &wolfBite, DoBloodSplat);
|
2020-11-12 23:16:27 -06:00
|
|
|
LaraItem->hitPoints -= BITE_DAMAGE;
|
2019-12-05 17:35:57 +01:00
|
|
|
LaraItem->hitStatus = true;
|
2020-11-12 23:16:27 -06:00
|
|
|
item->requiredAnimState = STATE_CROUCH;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CreatureTilt(item, tilt);
|
|
|
|
CreatureJoint(item, 0, head);
|
|
|
|
CreatureAnimation(itemNum, angle, tilt);
|
2020-11-12 23:16:27 -06:00
|
|
|
}
|