Merge branch 'master' into NewTRMath

This commit is contained in:
asasas9500 2020-11-14 16:19:45 -03:00
commit e1ff9ba698
15 changed files with 1093 additions and 848 deletions

View file

@ -8,30 +8,151 @@
BITE_INFO apeBite = { 0, -19, 75, 15 };
#define ATTACK_DAMAGE 200
#define TOUCH (0xFF00)
#define DIE_ANIM 7
#define VAULT_ANIM 19
#define RUN_TURN ANGLE(5)
#define DISPLAY_ANGLE ANGLE(45)
#define ATTACK_RANGE SQUARE(430)
#define PANIC_RANGE SQUARE(WALL_SIZE*2)
#define JUMP_CHANCE 0xa0
#define WARN1_CHANCE (JUMP_CHANCE + 0xA0)
#define WARN2_CHANCE (WARN1_CHANCE + 0xA0)
#define RUNLEFT_CHANCE (WARN2_CHANCE + 0x110)
#define ATTACK_FLAG 1
#define TURNL_FLAG 2
#define TURNR_FLAG 4
#define SHIFT 75
enum ape_anims {
APE_EMPTY,
APE_STOP,
APE_WALK,
APE_RUN,
APE_ATTACK1,
APE_DEATH,
APE_WARNING,
APE_WARNING2,
APE_RUNLEFT,
APE_RUNRIGHT,
APE_JUMP,
APE_VAULT
};
void ApeVault(short item_number, short angle)
{
ITEM_INFO *item;
CREATURE_INFO *ape;
long long y, xx, yy, x_floor, y_floor;
short room_number;
item = &g_Level.Items[item_number];
ape = (CREATURE_INFO *)item->data;
if (ape->flags & TURNL_FLAG)
{
item->pos.yRot -= 0x4000;
ape->flags -= TURNL_FLAG;
}
else if (item->flags & TURNR_FLAG)
{
item->pos.yRot += 0x4000;
ape->flags -= TURNR_FLAG;
}
xx = item->pos.zPos >> WALL_SHIFT;
yy = item->pos.xPos >> WALL_SHIFT;
y = item->pos.yPos;
room_number = item->roomNumber;
CreatureAnimation(item_number, angle, 0);
if (item->pos.yPos > y - STEP_SIZE * 3 / 2)
return;
x_floor = item->pos.zPos >> WALL_SHIFT;
y_floor = item->pos.xPos >> WALL_SHIFT;
if (xx == x_floor)
{
if (yy == y_floor)
return;
if (yy < y_floor)
{
item->pos.xPos = (y_floor << WALL_SHIFT) - SHIFT;
item->pos.yRot = 0x4000;
}
else
{
item->pos.xPos = (yy << WALL_SHIFT) + SHIFT;
item->pos.yRot = -0x4000;
}
}
else if (yy == y_floor)
{
if (xx < x_floor)
{
item->pos.zPos = (x_floor << WALL_SHIFT) - SHIFT;
item->pos.yRot = 0;
}
else
{
item->pos.zPos = (xx << WALL_SHIFT) + SHIFT;
item->pos.yRot = -0x8000;
}
}
else
{
// diagonal
}
switch (CreatureVault(item_number, angle, 2, 75))
{
case 2:
// creature->maximumTurn = 0;
item->pos.yPos = y;
item->animNumber = Objects[ID_APE].animIndex + VAULT_ANIM;
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
item->currentAnimState = APE_VAULT;
break;
default:
return;
}
}
void ApeControl(short itemNum)
{
short head, angle, random;
if (!CreatureActive(itemNum))
return;
ITEM_INFO* item = &g_Level.Items[itemNum];
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
short head = 0;
short angle = 0;
short random = 0;
AI_INFO info;
head = angle = 0;
if (item->hitPoints <= 0)
{
if (item->currentAnimState != 5)
if (item->currentAnimState != APE_DEATH)
{
item->animNumber = Objects[item->objectNumber].animIndex + 7 + (short)(GetRandomControl() / 0x4000);
item->animNumber = Objects[item->objectNumber].animIndex + DIE_ANIM + (short)(GetRandomControl() / 0x4000);
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
item->currentAnimState = 5;
item->currentAnimState = APE_DEATH;
}
}
else
{
AI_INFO info;
CreatureAIInfo(item, &info);
if (info.ahead)
@ -42,112 +163,112 @@ void ApeControl(short itemNum)
angle = CreatureTurn(item, creature->maximumTurn);
if (item->hitStatus || info.distance < SQUARE(2048))
creature->flags |= 1;
if (item->hitStatus || info.distance < PANIC_RANGE)
creature->flags |= ATTACK_FLAG;
switch (item->currentAnimState)
{
case 1:
if (creature->flags & 2)
case APE_STOP:
if (creature->flags & TURNL_FLAG)
{
item->pos.yRot -= ANGLE(90);
creature->flags -= 2;
creature->flags -= TURNL_FLAG;
}
else if (item->flags & 4)
else if (item->flags & TURNR_FLAG)
{
item->pos.yRot += ANGLE(90);
creature->flags -= 4;
creature->flags -= TURNR_FLAG;
}
if (item->requiredAnimState)
item->goalAnimState = item->requiredAnimState;
else if (info.bite && info.distance < SQUARE(430))
item->goalAnimState = 4;
else if (!(creature->flags & 1) &&
else if (info.bite && info.distance < ATTACK_RANGE)
item->goalAnimState = APE_ATTACK1;
else if (!(creature->flags & ATTACK_FLAG) &&
info.zoneNumber == info.enemyZone && info.ahead)
{
random = (short)(GetRandomControl() / 32);
if (random < 0xA0)
item->goalAnimState = 10;
else if (random < 0x140)
item->goalAnimState = 6;
else if (random < 0x1E0)
item->goalAnimState = 7;
else if (random < 0x2F0)
if (random < JUMP_CHANCE)
item->goalAnimState = APE_JUMP;
else if (random < WARN1_CHANCE)
item->goalAnimState = APE_WARNING;
else if (random < WARN2_CHANCE)
item->goalAnimState = APE_WARNING2;
else if (random < RUNLEFT_CHANCE)
{
item->goalAnimState = 8;
item->goalAnimState = APE_RUNLEFT;
creature->maximumTurn = 0;
}
else
{
item->goalAnimState = 9;
item->goalAnimState = APE_RUNRIGHT;
creature->maximumTurn = 0;
}
}
else
item->goalAnimState = 3;
item->goalAnimState = APE_RUN;
break;
case 3:
creature->maximumTurn = ANGLE(5);
case APE_RUN:
creature->maximumTurn = RUN_TURN;
if (creature->flags == 0 && info.angle > -ANGLE(45) && info.angle < ANGLE(45))
item->goalAnimState = 1;
else if (info.ahead && (item->touchBits & 0xFF00))
if (creature->flags == 0 && info.angle > -DISPLAY_ANGLE && info.angle < DISPLAY_ANGLE)
item->goalAnimState = APE_STOP;
else if (info.ahead && (item->touchBits & TOUCH))
{
item->requiredAnimState = 4;
item->goalAnimState = 1;
item->requiredAnimState = APE_ATTACK1;
item->goalAnimState = APE_STOP;
}
else if (creature->mood != ESCAPE_MOOD)
{
random = (short)GetRandomControl();
if (random < 0xA0)
if (random < JUMP_CHANCE)
{
item->requiredAnimState = 10;
item->goalAnimState = 1;
item->requiredAnimState = APE_JUMP;
item->goalAnimState = APE_STOP;
}
else if (random < 0x140)
else if (random < WARN1_CHANCE)
{
item->requiredAnimState = 6;
item->goalAnimState = 1;
item->requiredAnimState = APE_WARNING;
item->goalAnimState = APE_STOP;
}
else if (random < 0x1E0)
else if (random < WARN2_CHANCE)
{
item->requiredAnimState = 7;
item->goalAnimState = 1;
item->requiredAnimState = APE_WARNING2;
item->goalAnimState = APE_STOP;
}
}
break;
case 8:
if (!(creature->flags & 4))
case APE_RUNLEFT:
if (!(creature->flags & TURNR_FLAG))
{
item->pos.yRot -= ANGLE(90);
creature->flags |= 4;
creature->flags |= TURNR_FLAG;
}
item->goalAnimState = 1;
item->goalAnimState = APE_STOP;
break;
case 9:
if (!(creature->flags & 2))
case APE_RUNRIGHT:
if (!(creature->flags & TURNL_FLAG))
{
item->pos.yRot += ANGLE(90);
creature->flags |= 2;
creature->flags |= TURNL_FLAG;
}
item->goalAnimState = 1;
item->goalAnimState = APE_STOP;
break;
case 4:
if (!item->requiredAnimState && (item->touchBits & 0xFF00))
case APE_ATTACK1:
if (!item->requiredAnimState && (item->touchBits & TOUCH))
{
CreatureEffect(item, &apeBite, DoBloodSplat);
LaraItem->hitPoints -= 200;
LaraItem->hitPoints -= ATTACK_DAMAGE;
LaraItem->hitStatus = true;
item->requiredAnimState = 1;
item->requiredAnimState = APE_STOP;
}
break;
}
@ -155,32 +276,10 @@ void ApeControl(short itemNum)
CreatureJoint(item, 0, head);
if (item->currentAnimState != 11)
if (item->currentAnimState != APE_VAULT)
{
if (creature->flags & 2)
{
item->pos.yRot -= ANGLE(90);
creature->flags -= 2;
}
else if (item->flags & 4)
{
item->pos.yRot += ANGLE(90);
creature->flags -= 4;
}
switch (CreatureVault(itemNum, angle, 2, 75))
{
case 2:
creature->maximumTurn = 0;
item->animNumber = Objects[item->objectNumber].animIndex + 19;
item->currentAnimState = 11;
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
break;
default:
return;
}
ApeVault(itemNum, angle);
}
else
CreatureAnimation(itemNum, angle, 0);
}
}

View file

@ -1,3 +1,3 @@
#pragma once
void ApeControl(short itemNum);
void ApeControl(short itemNum);

View file

@ -8,6 +8,40 @@
BITE_INFO bearBite = { 0, 96, 335, 14 };
enum bearStates{
BEAR_STROLL,
BEAR_STOP,
BEAR_WALK,
BEAR_RUN,
BEAR_REAR,
BEAR_ROAR,
BEAR_ATTACK1,
BEAR_ATTACK2,
BEAR_EAT,
BEAR_DEATH
};
#define TOUCH 0x2406C
#define ROAR_CHANCE 0x50
#define REAR_CHANCE 0x300
#define DROP_CHANCE 0x600
#define REAR_RANGE SQUARE(WALL_SIZE*2)
#define ATTACK_RANGE SQUARE(WALL_SIZE)
#define PAT_RANGE SQUARE(600)
#define RUN_TURN ANGLE(5)
#define WALK_TURN ANGLE(2)
#define EAT_RANGE SQUARE(WALL_SIZE*3/4)
#define CHARGE_DAMAGE 3
#define SLAM_DAMAGE 200
#define ATTACK_DAMAGE 200
#define PAT_DAMAGE 400
void BearControl(short itemNum)
{
if (!CreatureActive(itemNum))
@ -17,48 +51,55 @@ void BearControl(short itemNum)
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
short head = 0;
short angle = 0;
short angle;
if (item->hitPoints <= 0)
{
if (item->currentAnimState != 9)
{
// if (item->currentAnimState != 9)
// {
angle = CreatureTurn(item, ANGLE(1));
switch (item->currentAnimState)
{
case 2:
item->goalAnimState = 4;
case BEAR_WALK:
{
item->goalAnimState = BEAR_REAR;
break;
case 3:
case 0:
item->goalAnimState = 1;
}
case BEAR_RUN:
case BEAR_STROLL:
{
item->goalAnimState = BEAR_STOP;
break;
case 4:
}
case BEAR_REAR:
{
creature->flags = 1;
item->goalAnimState = 9;
item->goalAnimState = BEAR_DEATH;
break;
case 1:
}
case BEAR_STOP:
{
creature->flags = 0;
item->goalAnimState = 9;
item->goalAnimState = BEAR_DEATH;
break;
case 9:
if (creature->flags && (item->touchBits & 0x2406C))
}
case BEAR_DEATH:
{
if (creature->flags && (item->touchBits & TOUCH))
{
LaraItem->hitPoints -= 200;
LaraItem->hitPoints -= SLAM_DAMAGE;
LaraItem->hitStatus = 1;
creature->flags = 0;
}
item->animNumber = Objects[item->objectNumber].animIndex + 20;
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
item->currentAnimState = 9;
// item->animNumber = Objects[item->objectNumber].animIndex + 20;
// item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
// item->currentAnimState = 9;
break;
}
}
}
// }
}
else
{
@ -76,18 +117,20 @@ void BearControl(short itemNum)
if (item->hitStatus)
creature->flags = 1;
const bool Laradead = (LaraItem->hitPoints <= 0);
switch (item->currentAnimState)
{
case 1:
if (LaraItem->hitPoints <= 0)
case BEAR_STOP:
if (Laradead)
{
if (info.bite && info.distance < SQUARE(768))
if (info.bite && info.distance < EAT_RANGE)
{
item->goalAnimState = 8;
item->goalAnimState = BEAR_EAT;
}
else
{
item->goalAnimState = 0;
item->goalAnimState = BEAR_STROLL;
}
}
else if (item->requiredAnimState)
@ -96,70 +139,70 @@ void BearControl(short itemNum)
}
else if (creature->mood == BORED_MOOD)
{
item->goalAnimState = 0;
item->goalAnimState = BEAR_STROLL;
}
else
{
item->goalAnimState = 3;
item->goalAnimState = BEAR_RUN;
}
break;
case 0:
creature->maximumTurn = ANGLE(2);
case BEAR_STROLL:
creature->maximumTurn = WALK_TURN;
if (LaraItem->hitPoints <= 0 && (item->touchBits & 0x2406C) && info.ahead)
if (Laradead && (item->touchBits & TOUCH) && info.ahead)
{
item->goalAnimState = 1;
item->goalAnimState = BEAR_STOP;
}
else if (creature->mood != BORED_MOOD)
{
item->goalAnimState = 1;
item->goalAnimState = BEAR_STOP;
if (creature->mood == ESCAPE_MOOD)
{
item->requiredAnimState = 0;
item->requiredAnimState = BEAR_STROLL;
}
}
else if (GetRandomControl() < 0x50)
else if (GetRandomControl() < ROAR_CHANCE)
{
item->requiredAnimState = 5;
item->goalAnimState = 1;
item->requiredAnimState = BEAR_ROAR;
item->goalAnimState = BEAR_STOP;
}
break;
case 3:
creature->maximumTurn = ANGLE(5);
case BEAR_RUN:
creature->maximumTurn = RUN_TURN;
// if the bear slams you it hurts
if (item->touchBits & 0x2406C)
if (item->touchBits & TOUCH)
{
LaraItem->hitPoints -= 3;
LaraItem->hitPoints -= CHARGE_DAMAGE;
LaraItem->hitStatus = true;
}
if (creature->mood == BORED_MOOD || LaraItem->hitPoints <= 0)
if (creature->mood == BORED_MOOD || Laradead)
{
item->goalAnimState = 1;
item->goalAnimState = BEAR_STOP;
}
else if (info.ahead && !item->requiredAnimState)
{
// bear may rear up, but not after he's taken some bullets!
if (!creature->flags && info.distance < SQUARE(2048) && GetRandomControl() < 0x300)
if (!creature->flags && info.distance < REAR_RANGE && GetRandomControl() < REAR_CHANCE)
{
item->requiredAnimState = 4;
item->goalAnimState = 1;
item->requiredAnimState = BEAR_REAR;
item->goalAnimState = BEAR_STOP;
}
else if (info.distance < SQUARE(1024))
else if (info.distance < ATTACK_RANGE)
{
item->goalAnimState = 6;
item->goalAnimState = BEAR_ATTACK1;
}
}
break;
case 4:
case BEAR_REAR:
if (creature->flags)
{
item->requiredAnimState = 0;
item->goalAnimState = 1;
item->requiredAnimState = BEAR_STROLL;
item->goalAnimState = BEAR_STOP;
}
else if (item->requiredAnimState)
{
@ -167,62 +210,62 @@ void BearControl(short itemNum)
}
else if (creature->mood == BORED_MOOD || creature->mood == ESCAPE_MOOD)
{
item->goalAnimState = 1;
item->goalAnimState = BEAR_STOP;
}
else if (info.bite && info.distance < SQUARE(600))
else if (info.bite && info.distance < PAT_RANGE)
{
item->goalAnimState = 7;
item->goalAnimState = BEAR_ATTACK2;
}
else
{
item->goalAnimState = 2;
item->goalAnimState = BEAR_WALK;
}
break;
case 2:
case BEAR_WALK:
if (creature->flags)
{
item->requiredAnimState = 0;
item->goalAnimState = 4;
item->requiredAnimState = BEAR_STROLL;
item->goalAnimState = BEAR_REAR;
}
else if (info.ahead && (item->touchBits & 0x2406C))
else if (info.ahead && (item->touchBits & TOUCH))
{
item->goalAnimState = 4;
item->goalAnimState = BEAR_REAR;
}
else if (creature->mood == ESCAPE_MOOD)
{
item->goalAnimState = 4;
item->requiredAnimState = 0;
item->goalAnimState = BEAR_REAR;
item->requiredAnimState = BEAR_STROLL;
}
else if (creature->mood == BORED_MOOD || GetRandomControl() < 0x50)
else if (creature->mood == BORED_MOOD || GetRandomControl() < ROAR_CHANCE)
{
item->requiredAnimState = 5;
item->goalAnimState = 4;
item->requiredAnimState = BEAR_ROAR;
item->goalAnimState = BEAR_REAR;
}
else if (info.distance > SQUARE(2048) || GetRandomControl() < 0x600)
else if (info.distance > REAR_RANGE || GetRandomControl() < DROP_CHANCE)
{
item->requiredAnimState = 1;
item->goalAnimState = 4;
item->requiredAnimState = BEAR_STOP;
item->goalAnimState = BEAR_REAR;
}
break;
case 7:
if (!item->requiredAnimState && (item->touchBits & 0x2406C))
case BEAR_ATTACK2:
if (!item->requiredAnimState && (item->touchBits & TOUCH))
{
LaraItem->hitPoints -= 400;
LaraItem->hitPoints -= PAT_DAMAGE;
LaraItem->hitStatus = true;
item->requiredAnimState = 4;
item->requiredAnimState = BEAR_REAR;
}
break;
case 6:
if (!item->requiredAnimState && (item->touchBits & 0x2406C))
case BEAR_ATTACK1:
if (!item->requiredAnimState && (item->touchBits & TOUCH))
{
CreatureEffect(item, &bearBite, DoBloodSplat);
LaraItem->hitPoints -= 200;
LaraItem->hitPoints -= ATTACK_DAMAGE;
LaraItem->hitStatus = true;
item->requiredAnimState = 1;
item->requiredAnimState = BEAR_STOP;
}
break;
@ -231,4 +274,4 @@ void BearControl(short itemNum)
CreatureJoint(item, 0, head);
CreatureAnimation(itemNum, angle, 0);
}
}

View file

@ -1,3 +1,3 @@
#pragma once
void BearControl(short itemNum);
void BearControl(short itemNum);

View file

@ -24,10 +24,14 @@ void InitialiseDoppelganger(short itemNum)
void DoppelgangerControl(short itemNum)
{
ITEM_INFO* item;
ITEM_INFO* ref;
FLOOR_INFO* floor;
int h, lh;
int x, y, z;
short room_num;
short xRef, zRef;
ref = find_a_fucking_item(ID_BACON_REFERENCE);
item = &g_Level.Items[itemNum];
@ -41,9 +45,11 @@ void DoppelgangerControl(short itemNum)
{
// TODO: fix evil lara moving.
room_num = item->roomNumber;
x = item->pos.xPos; // 2*36*WALL_SIZE - LaraItem->pos.xPos;
y = item->pos.yPos; // LaraItem->pos.yPos;
z = item->pos.zPos; // 2*60*WALL_SIZE - LaraItem->pos.zPos;
xRef = ref->pos.xPos;
zRef = ref->pos.zPos;
x = 2 * ref->pos.xPos - LaraItem->pos.xPos;
y = LaraItem->pos.yPos;
z = 2 * ref->pos.zPos - LaraItem->pos.zPos;
floor = GetFloor(x, y, z, &room_num);
h = GetFloorHeight(floor, x, y, z);
item->floor = h;
@ -52,9 +58,9 @@ void DoppelgangerControl(short itemNum)
lh = GetFloorHeight(floor, LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos);
item->frameNumber = LaraItem->frameNumber;
item->animNumber = LaraItem->animNumber;
//item->pos.xPos = x;
//item->pos.yPos = y;
//item->pos.zPos = z;
item->pos.xPos = x;
item->pos.yPos = y;
item->pos.zPos = z;
item->pos.xRot = LaraItem->pos.xRot;
item->pos.yRot = LaraItem->pos.yRot - ANGLE(180);
item->pos.zRot = LaraItem->pos.zRot;

View file

@ -1,4 +1,4 @@
#pragma once
void InitialiseDoppelganger(short itemNum);
void DoppelgangerControl(short itemNum);
void DoppelgangerControl(short itemNum);

View file

@ -9,11 +9,47 @@
BITE_INFO wolfBite = { 0, -14, 174, 6 };
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);
item->frameNumber = 96;
item->frameNumber = SLEEP_FRAME;
}
void WolfControl(short itemNum)
@ -21,25 +57,26 @@ void WolfControl(short itemNum)
if (!CreatureActive(itemNum))
return;
short head;
short angle;
short tilt;
ITEM_INFO* item = &g_Level.Items[itemNum];
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
short head = 0;
short angle = 0;
short tilt = 0;
head = angle = tilt = 0;
AI_INFO info;
if (item->hitPoints <= 0)
{
if (item->currentAnimState != 11)
if (item->currentAnimState != STATE_DEATH)
{
item->animNumber = Objects[item->objectNumber].animIndex + 20 + (short)(GetRandomControl() / 11000);
item->animNumber = Objects[ID_WOLF].animIndex + DIE_ANIM + (short)(GetRandomControl() / 11000);
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
item->currentAnimState = 11;
item->currentAnimState = STATE_DEATH;
}
}
else
{
AI_INFO info;
CreatureAIInfo(item, &info);
if (info.ahead)
@ -52,128 +89,128 @@ void WolfControl(short itemNum)
switch (item->currentAnimState)
{
case 8:
case STATE_SLEEP:
head = 0;
if (creature->mood == ESCAPE_MOOD || info.zoneNumber == info.enemyZone)
{
item->requiredAnimState = 9;
item->goalAnimState = 1;
item->requiredAnimState = STATE_CROUCH;
item->goalAnimState = STATE_STOP;
}
else if (GetRandomControl() < 0x20)
else if (GetRandomControl() < WAKE_CHANCE)
{
item->requiredAnimState = 2;
item->goalAnimState = 1;
item->requiredAnimState = STATE_WALK;
item->goalAnimState = STATE_STOP;
}
break;
case 1:
case STATE_STOP:
if (item->requiredAnimState)
item->goalAnimState = item->requiredAnimState;
else
item->goalAnimState = 2;
item->goalAnimState = STATE_WALK;
break;
case 2:
creature->maximumTurn = ANGLE(2);
case STATE_WALK:
creature->maximumTurn = WALK_TURN;
if (creature->mood != BORED_MOOD)
{
item->goalAnimState = 5;
item->requiredAnimState = 0;
item->goalAnimState = STATE_STALK;
item->requiredAnimState = STATE_EMPTY;
}
else if (GetRandomControl() < 0x20)
else if (GetRandomControl() < SLEEP_CHANCE)
{
item->requiredAnimState = 8;
item->goalAnimState = 1;
item->requiredAnimState = STATE_SLEEP;
item->goalAnimState = STATE_STOP;
}
break;
case 9:
case STATE_CROUCH:
if (item->requiredAnimState)
item->goalAnimState = item->requiredAnimState;
else if (creature->mood == ESCAPE_MOOD)
item->goalAnimState = 3;
item->goalAnimState = STATE_RUN;
else if (info.distance < SQUARE(345) && info.bite)
item->goalAnimState = 12;
item->goalAnimState = STATE_BITE;
else if (creature->mood == STALK_MOOD)
item->goalAnimState = 5;
item->goalAnimState = STATE_STALK;
else if (creature->mood == BORED_MOOD)
item->goalAnimState = 1;
item->goalAnimState = STATE_STOP;
else
item->goalAnimState = 3;
item->goalAnimState = STATE_RUN;
break;
case 5:
creature->maximumTurn = ANGLE(2);
case STATE_STALK:
creature->maximumTurn = STALK_TURN;
if (creature->mood == ESCAPE_MOOD)
item->goalAnimState = 3;
item->goalAnimState = STATE_RUN;
else if (info.distance < SQUARE(345) && info.bite)
item->goalAnimState = 12;
item->goalAnimState = STATE_BITE;
else if (info.distance > SQUARE(3072))
item->goalAnimState = 3;
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))
item->goalAnimState = 3;
item->goalAnimState = STATE_RUN;
}
else if (GetRandomControl() < 0x180)
else if (GetRandomControl() < HOWL_CHANCE)
{
item->requiredAnimState = 7;
item->goalAnimState = 9;
item->requiredAnimState = STATE_HOWL;
item->goalAnimState = STATE_CROUCH;
}
else if (creature->mood == BORED_MOOD)
item->goalAnimState = 9;
item->goalAnimState = STATE_CROUCH;
break;
case 3:
creature->maximumTurn = ANGLE(5);
creature->maximumTurn = RUN_TURN;
tilt = angle;
if (info.ahead && info.distance < SQUARE(1536))
if (info.ahead && info.distance < ATTACK_RANGE)
{
if (info.distance > (SQUARE(1536) / 2) &&
if (info.distance > (ATTACK_RANGE / 2) &&
(info.enemyFacing > FRONT_ARC || info.enemyFacing < -FRONT_ARC))
{
item->requiredAnimState = 5;
item->goalAnimState = 9;
item->requiredAnimState = STATE_STALK;
item->goalAnimState = STATE_CROUCH;
}
else
{
item->goalAnimState = 6;
item->requiredAnimState = 0;
item->goalAnimState = STATE_ATTACK;
item->requiredAnimState = STATE_EMPTY;
}
}
else if (creature->mood == STALK_MOOD && info.distance < SQUARE(3072))
else if (creature->mood == STALK_MOOD && info.distance < STALK_RANGE)
{
item->requiredAnimState = 5;
item->goalAnimState = 9;
item->requiredAnimState = STATE_STALK;
item->goalAnimState = STATE_CROUCH;
}
else if (creature->mood == BORED_MOOD)
item->goalAnimState = 9;
item->goalAnimState = STATE_CROUCH;
break;
case 6:
case STATE_ATTACK:
tilt = angle;
if (!item->requiredAnimState && (item->touchBits & 0x774F))
if (!item->requiredAnimState && (item->touchBits & TOUCH))
{
CreatureEffect(item, &wolfBite, DoBloodSplat);
LaraItem->hitPoints -= 50;
LaraItem->hitPoints -= LUNGE_DAMAGE;
LaraItem->hitStatus = true;
item->requiredAnimState = 3;
item->requiredAnimState = STATE_RUN;
}
item->goalAnimState = 3;
item->goalAnimState = STATE_RUN;
break;
case 12:
if (!item->requiredAnimState && (item->touchBits & 0x774F) && info.ahead)
if (!item->requiredAnimState && (item->touchBits & TOUCH) && info.ahead)
{
CreatureEffect(item, &wolfBite, DoBloodSplat);
LaraItem->hitPoints -= 100;
LaraItem->hitPoints -= BITE_DAMAGE;
LaraItem->hitStatus = true;
item->requiredAnimState = 9;
item->requiredAnimState = STATE_CROUCH;
}
break;
}
@ -182,4 +219,4 @@ void WolfControl(short itemNum)
CreatureTilt(item, tilt);
CreatureJoint(item, 0, head);
CreatureAnimation(itemNum, angle, tilt);
}
}

View file

@ -1,4 +1,4 @@
#pragma once
void InitialiseWolf(short itemNum);
void WolfControl(short itemNum);
void WolfControl(short itemNum);

View file

@ -26,7 +26,7 @@ static void StartBaddy(OBJECT_INFO* obj)
obj->initialise = InitialiseWolf;
obj->control = WolfControl;
obj->collision = CreatureCollision;
obj->shadowSize = 128;
obj->shadowSize = UNIT_SHADOW / 2;
obj->hitPoints = 6;
obj->pivotLength = 375;
obj->radius = 340;
@ -152,7 +152,13 @@ static void StartBaddy(OBJECT_INFO* obj)
static void StartObject(OBJECT_INFO* obj)
{
obj = &Objects[ID_BACON_REFERENCE];
if (obj->loaded)
{
obj->drawRoutine = nullptr;
obj->collision = AIPickupCollision;
obj->hitPoints = 0;
}
}
static void StartTrap(OBJECT_INFO* obj)

View file

@ -12,7 +12,18 @@
BITE_INFO TroopsBite1 = { 0, 300, 64, 7 };
#define STATE_TROOPS_STOP 1
#define STATE_TROOPS_WALK 2
#define STATE_TROOPS_RUN 3
#define STATE_TROOPS_ATTACK1 5
#define STATE_TROOPS_ATTACK2 6
#define STATE_TROOPS_DEATH 7
#define STATE_TROOPS_AIM1 8
#define STATE_TROOPS_AIM2 9
#define STATE_TROOPS_AIM3 10
#define STATE_TROOPS_ATTACK3 11
#define STATE_TROOPS_KILLED_BY_SCORPION 15
#define STATE_TROOPS_ATTACKED_BY_SCORPION 16
void InitialiseTroops(short itemNumber)
{
@ -22,12 +33,12 @@ void InitialiseTroops(short itemNumber)
if (item->triggerFlags == 1)
{
item->goalAnimState = item->currentAnimState = 16;
item->goalAnimState = item->currentAnimState = STATE_TROOPS_ATTACKED_BY_SCORPION;
item->animNumber = Objects[item->objectNumber].animIndex + 27;
}
else
{
item->goalAnimState = item->currentAnimState = 1;
item->goalAnimState = item->currentAnimState = STATE_TROOPS_STOP;
item->animNumber = Objects[item->objectNumber].animIndex + 12;
}
@ -39,18 +50,23 @@ void TroopsControl(short itemNumber)
if (!CreatureActive(itemNumber))
return;
&g_Level.Items[32].currentAnimState;
ITEM_INFO* item = &g_Level.Items[itemNumber];
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
OBJECT_INFO* obj = &Objects[item->objectNumber];
short angle = 0;
short tilt = 0;
short joint0 = 0;
short joint1 = 0;
short joint2 = 0;
short rot = 0;
int dx = 0;
int dy = 0;
int dz = 0;
int distance = 0;
if (item->firedWeapon)
@ -69,14 +85,17 @@ void TroopsControl(short itemNumber)
if (item->hitPoints <= 0)
{
if (item->currentAnimState != 7 && item->currentAnimState != 15)
if (item->currentAnimState != STATE_TROOPS_DEATH
&& item->currentAnimState != STATE_TROOPS_KILLED_BY_SCORPION)
{
if (creature->enemy && creature->enemy->objectNumber == ID_BIG_SCORPION && (item->itemFlags[0] < 80))
if (creature->enemy
&& creature->enemy->objectNumber == ID_BIG_SCORPION
&& item->itemFlags[0] < 80)
{
if (creature->enemy->animNumber == Objects[ID_BIG_SCORPION].animIndex + 6)
{
item->animNumber = Objects[item->objectNumber].animIndex + 23;
if (item->currentAnimState == 16)
if (item->currentAnimState == STATE_TROOPS_ATTACKED_BY_SCORPION)
{
item->frameNumber = g_Level.Anims[item->animNumber].frameBase += 37;
}
@ -84,8 +103,8 @@ void TroopsControl(short itemNumber)
{
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
}
item->goalAnimState = 15;
item->currentAnimState = 15;
item->goalAnimState = STATE_TROOPS_KILLED_BY_SCORPION;
item->currentAnimState = STATE_TROOPS_KILLED_BY_SCORPION;
angle = 0;
@ -107,7 +126,7 @@ void TroopsControl(short itemNumber)
else
{
item->animNumber = Objects[item->objectNumber].animIndex + 19;
item->currentAnimState = 7;
item->currentAnimState = STATE_TROOPS_DEATH;
item->frameNumber = g_Level.Anims[item->frameNumber].frameBase;
}
}
@ -137,7 +156,7 @@ void TroopsControl(short itemNumber)
dx = currentItem->pos.xPos - item->pos.xPos;
dy = currentItem->pos.yPos - item->pos.yPos;
dz = currentItem->pos.zPos - item->pos.zPos;
distance = dx * dx + dy * dy + dz * dz;
distance = SQUARE(dx) + SQUARE(dy) + SQUARE(dz);
if (distance < minDistance)
{
@ -149,11 +168,10 @@ void TroopsControl(short itemNumber)
}
}
if (creature->hurtByLara && item->currentAnimState != 16)
if (creature->hurtByLara && item->currentAnimState != STATE_TROOPS_ATTACKED_BY_SCORPION)
creature->enemy = LaraItem;
AI_INFO info;
AI_INFO info;
CreatureAIInfo(item, &info);
int distance = 0;
@ -166,18 +184,20 @@ void TroopsControl(short itemNumber)
{
dx = LaraItem->pos.xPos - item->pos.xPos;
dz = LaraItem->pos.zPos - item->pos.zPos;
distance = dx * dx + dz * dz;
distance = SQUARE(dx) + SQUARE(dz);
rot = phd_atan(dz, dx) - item->pos.yRot;
}
if (!creature->hurtByLara && creature->enemy == LaraItem)
creature->enemy = NULL;
GetCreatureMood(item, &info, TIMID);
CreatureMood(item, &info, TIMID);
// Vehicle handling
if (Lara.Vehicle != NO_ITEM && info.bite)
creature->mood == ESCAPE_MOOD;
CreatureMood(item, &info, TIMID);
angle = CreatureTurn(item, creature->maximumTurn);
if (item->hitStatus)
@ -185,7 +205,7 @@ void TroopsControl(short itemNumber)
switch (item->currentAnimState)
{
case 1:
case STATE_TROOPS_STOP:
creature->flags = 0;
creature->maximumTurn = 0;
joint2 = rot;
@ -194,7 +214,7 @@ void TroopsControl(short itemNumber)
{
if (abs(info.angle) >= ANGLE(10))
{
if ((info.angle & 0x8000u) == 0)
if (info.angle >= 0)
{
item->pos.yRot += ANGLE(10);
}
@ -214,22 +234,22 @@ void TroopsControl(short itemNumber)
joint2 = AIGuard(creature);
if (!(byte)GetRandomControl())
{
if (item->currentAnimState == 1)
if (item->currentAnimState == STATE_TROOPS_STOP)
{
item->goalAnimState = 4;
break;
}
item->goalAnimState = 1;
item->goalAnimState = STATE_TROOPS_STOP;
}
}
else if (item->aiBits & PATROL1)
{
item->goalAnimState = 2;
item->goalAnimState = STATE_TROOPS_WALK;
joint2 = 0;
}
else if (creature->mood == ESCAPE_MOOD)
{
item->goalAnimState = 3;
item->goalAnimState = STATE_TROOPS_RUN;
}
else if (Targetable(item, &info))
{
@ -237,16 +257,16 @@ void TroopsControl(short itemNumber)
{
if (GetRandomControl() >= 0x4000)
{
item->goalAnimState = 10;
item->goalAnimState = STATE_TROOPS_AIM3;
}
else
{
item->goalAnimState = 8;
item->goalAnimState = STATE_TROOPS_AIM1;
}
}
else
{
item->goalAnimState = 2;
item->goalAnimState = STATE_TROOPS_WALK;
}
}
else
@ -256,66 +276,67 @@ void TroopsControl(short itemNumber)
{
if (!creature->mood || info.distance <= SQUARE(2048))
{
item->goalAnimState = 2;
item->goalAnimState = STATE_TROOPS_WALK;
break;
}
item->goalAnimState = 3;
item->goalAnimState = STATE_TROOPS_RUN;
}
else
{
item->goalAnimState = 1;
item->goalAnimState = STATE_TROOPS_STOP;
}
}
break;
case 2:
case STATE_TROOPS_WALK:
creature->flags = 0;
joint2 = rot;
creature->maximumTurn = ANGLE(5);
if (item->aiBits & PATROL1)
{
item->goalAnimState = 2;
item->goalAnimState = STATE_TROOPS_WALK;
}
else if (creature->mood == 2)
else if (creature->mood == ESCAPE_MOOD)
{
item->goalAnimState = 3;
item->goalAnimState = STATE_TROOPS_RUN;
}
else
{
if ((item->aiBits & GUARD) || (item->aiBits & GUARD) &&
if ((item->aiBits & GUARD) || (item->aiBits & FOLLOW) &&
(creature->reachedGoal || distance > SQUARE(2048)))
{
item->goalAnimState = 1;
item->goalAnimState = STATE_TROOPS_STOP;
break;
}
if (Targetable(item, &info))
{
if (info.distance < SQUARE(3072) || info.enemyZone != info.zoneNumber)
{
item->goalAnimState = 1;
item->goalAnimState = STATE_TROOPS_STOP;
break;
}
item->goalAnimState = 9;
item->goalAnimState = STATE_TROOPS_AIM2;
}
else if (creature->mood)
{
if (info.distance > SQUARE(2048))
{
item->goalAnimState = 3;
item->goalAnimState = STATE_TROOPS_RUN;
}
}
else if (info.ahead)
{
item->goalAnimState = 1;
item->goalAnimState = STATE_TROOPS_STOP;
break;
}
}
break;
case 3:
case STATE_TROOPS_RUN:
if (info.ahead)
{
joint2 = info.angle;
@ -326,20 +347,21 @@ void TroopsControl(short itemNumber)
if ((item->aiBits & GUARD) || (item->aiBits & FOLLOW) &&
(creature->reachedGoal || distance > SQUARE(2048)))
{
item->goalAnimState = 2;
item->goalAnimState = STATE_TROOPS_WALK;
break;
}
if (creature->mood != ESCAPE_MOOD)
{
if (Targetable(item, &info))
{
item->goalAnimState = 2;
item->goalAnimState = STATE_TROOPS_WALK;
break;
}
if (!creature->mood || creature->mood == STALK_MOOD &&
if (creature->mood == BORED_MOOD || creature->mood == STALK_MOOD &&
!(item->aiBits & FOLLOW) && info.distance < SQUARE(2048))
{
item->goalAnimState = 2;
item->goalAnimState = STATE_TROOPS_WALK;
}
}
@ -355,22 +377,22 @@ void TroopsControl(short itemNumber)
joint2 = AIGuard(creature);
if (!(byte)GetRandomControl())
{
item->goalAnimState = 1;
item->goalAnimState = STATE_TROOPS_STOP;
}
}
else if (Targetable(item, &info))
{
item->goalAnimState = 5;
item->goalAnimState = STATE_TROOPS_ATTACK1;
}
else if (creature->mood || !info.ahead)
{
item->goalAnimState = 1;
item->goalAnimState = STATE_TROOPS_STOP;
}
break;
case 5:
case 6:
case STATE_TROOPS_ATTACK1:
case STATE_TROOPS_ATTACK2:
if (info.ahead)
{
joint0 = info.angle;
@ -389,8 +411,8 @@ void TroopsControl(short itemNumber)
break;
case 8:
case 10:
case STATE_TROOPS_AIM1:
case STATE_TROOPS_AIM3:
creature->flags = 0;
if (info.ahead)
@ -400,17 +422,17 @@ void TroopsControl(short itemNumber)
if (Targetable(item, &info))
{
item->goalAnimState = item->currentAnimState != 8 ? 11 : 5;
item->goalAnimState = item->currentAnimState != STATE_TROOPS_AIM1 ? STATE_TROOPS_ATTACK1 : STATE_TROOPS_ATTACK3;
}
else
{
item->goalAnimState = 1;
item->goalAnimState = STATE_TROOPS_STOP;
}
}
break;
case 9:
case STATE_TROOPS_AIM2:
creature->flags = 0;
if (info.ahead)
@ -420,23 +442,23 @@ void TroopsControl(short itemNumber)
if (Targetable(item, &info))
{
item->goalAnimState = 6;
item->goalAnimState = STATE_TROOPS_ATTACK2;
}
else
{
item->goalAnimState = 2;
item->goalAnimState = STATE_TROOPS_WALK;
}
}
break;
case 11:
if (item->goalAnimState != 1
case STATE_TROOPS_ATTACK3:
if (item->goalAnimState != STATE_TROOPS_STOP
&& (creature->mood == ESCAPE_MOOD ||
info.distance > SQUARE(3072) ||
!Targetable(item, &info)))
{
item->goalAnimState = 1;
item->goalAnimState = STATE_TROOPS_STOP;
}
if (info.ahead)
@ -457,11 +479,11 @@ void TroopsControl(short itemNumber)
break;
case 16:
case STATE_TROOPS_ATTACKED_BY_SCORPION:
creature->maximumTurn = 0;
break;
case 17u:
case 17:
if (!WeaponEnemyTimer && !(GetRandomControl() & 0x7F))
{
item->goalAnimState = 4;

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,10 @@ void InitialiseRaisingBlock(short itemNumber)
AddActiveItem(itemNumber);
item->status = ITEM_ACTIVE;
}
// Get height from animations
ANIM_FRAME* frame = &g_Level.Frames[g_Level.Anims[Objects[item->objectNumber].animIndex].framePtr];
item->itemFlags[7] = (short)abs(frame->boundingBox.Y1 - frame->boundingBox.Y2);
}
void ControlRaisingBlock(short itemNumber)
@ -36,20 +40,20 @@ void ControlRaisingBlock(short itemNumber)
{
if (item->triggerFlags == -1)
{
AlterFloorHeight(item, -255);
//AlterFloorHeight(item, -255);
}
else if (item->triggerFlags == -3)
{
AlterFloorHeight(item, -1023);
//AlterFloorHeight(item, -1023);
}
else
{
AlterFloorHeight(item, -1024);
//AlterFloorHeight(item, -item->itemFlags[7]);
}
}
else
{
AlterFloorHeight(item, -2048);
//AlterFloorHeight(item, -item->itemFlags[7]);
}
item->itemFlags[2] = 1;
@ -89,22 +93,22 @@ void ControlRaisingBlock(short itemNumber)
{
if (item->triggerFlags == -1)
{
AlterFloorHeight(item, 255);
//AlterFloorHeight(item, 255);
item->itemFlags[2] = 0;
}
else if (item->triggerFlags == -3)
{
AlterFloorHeight(item, 1023);
//AlterFloorHeight(item, 1023);
item->itemFlags[2] = 0;
}
else
{
AlterFloorHeight(item, 1024);
//AlterFloorHeight(item, item->itemFlags[7]);
}
}
else
{
AlterFloorHeight(item, 2048);
//AlterFloorHeight(item, item->itemFlags[7]);
}
item->itemFlags[2] = 0;
@ -129,4 +133,26 @@ void ControlRaisingBlock(short itemNumber)
item->itemFlags[1] -= 64;
}
}
}
std::tuple<std::optional<int>, bool> RaisingBlockFloor(short itemNumber, int x, int y, int z)
{
const auto& item = g_Level.Items[itemNumber];
if (abs(item.pos.xPos - x) <= SECTOR(1) / 2 && abs(item.pos.zPos - z) <= SECTOR(1) / 2)
{
auto height = item.pos.yPos - item.itemFlags[7] * item.itemFlags[1] / 4096;
return std::make_tuple(std::optional{height}, y > height && y < item.pos.yPos);
}
return std::make_tuple(std::nullopt, false);
}
std::tuple<std::optional<int>, bool> RaisingBlockCeiling(short itemNumber, int x, int y, int z)
{
const auto& item = g_Level.Items[itemNumber];
if (abs(item.pos.xPos - x) <= SECTOR(1) / 2 && abs(item.pos.zPos - z) <= SECTOR(1) / 2)
{
auto height = item.pos.yPos - item.itemFlags[7] * item.itemFlags[1] / 4096;
return std::make_tuple(std::optional{item.pos.yPos}, y > height && y < item.pos.yPos);
}
return std::make_tuple(std::nullopt, false);
}

View file

@ -1,4 +1,6 @@
#pragma once
void InitialiseRaisingBlock(short itemNumber);
void ControlRaisingBlock(short itemNumber);
void ControlRaisingBlock(short itemNumber);
std::tuple<std::optional<int>, bool> RaisingBlockFloor(short itemNumber, int x, int y, int z);
std::tuple<std::optional<int>, bool> RaisingBlockCeiling(short itemNumber, int x, int y, int z);

View file

@ -903,6 +903,8 @@ static void StartObject(OBJECT_INFO *obj)
{
obj->initialise = InitialiseRaisingBlock;
obj->control = ControlRaisingBlock;
obj->floor = RaisingBlockFloor;
obj->ceiling = RaisingBlockCeiling;
obj->saveFlags = true;
}
}

View file

@ -805,6 +805,7 @@ typedef enum GAME_OBJECT_ID
ID_WATERFALLSS1,
ID_WATERFALLSS2,
ID_FISHTANK,
ID_BACON_REFERENCE,
ID_MESHSWAP1 = 1100,
ID_MESHSWAP2,