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 }; 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) void ApeControl(short itemNum)
{ {
short head, angle, random;
if (!CreatureActive(itemNum)) if (!CreatureActive(itemNum))
return; return;
ITEM_INFO* item = &g_Level.Items[itemNum]; ITEM_INFO* item = &g_Level.Items[itemNum];
CREATURE_INFO* creature = (CREATURE_INFO*)item->data; CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
AI_INFO info;
short head = 0; head = angle = 0;
short angle = 0;
short random = 0;
if (item->hitPoints <= 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->frameNumber = g_Level.Anims[item->animNumber].frameBase;
item->currentAnimState = 5; item->currentAnimState = APE_DEATH;
} }
} }
else else
{ {
AI_INFO info;
CreatureAIInfo(item, &info); CreatureAIInfo(item, &info);
if (info.ahead) if (info.ahead)
@ -42,112 +163,112 @@ void ApeControl(short itemNum)
angle = CreatureTurn(item, creature->maximumTurn); angle = CreatureTurn(item, creature->maximumTurn);
if (item->hitStatus || info.distance < SQUARE(2048)) if (item->hitStatus || info.distance < PANIC_RANGE)
creature->flags |= 1; creature->flags |= ATTACK_FLAG;
switch (item->currentAnimState) switch (item->currentAnimState)
{ {
case 1: case APE_STOP:
if (creature->flags & 2) if (creature->flags & TURNL_FLAG)
{ {
item->pos.yRot -= ANGLE(90); 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); item->pos.yRot += ANGLE(90);
creature->flags -= 4; creature->flags -= TURNR_FLAG;
} }
if (item->requiredAnimState) if (item->requiredAnimState)
item->goalAnimState = item->requiredAnimState; item->goalAnimState = item->requiredAnimState;
else if (info.bite && info.distance < SQUARE(430)) else if (info.bite && info.distance < ATTACK_RANGE)
item->goalAnimState = 4; item->goalAnimState = APE_ATTACK1;
else if (!(creature->flags & 1) && else if (!(creature->flags & ATTACK_FLAG) &&
info.zoneNumber == info.enemyZone && info.ahead) info.zoneNumber == info.enemyZone && info.ahead)
{ {
random = (short)(GetRandomControl() / 32); random = (short)(GetRandomControl() / 32);
if (random < 0xA0) if (random < JUMP_CHANCE)
item->goalAnimState = 10; item->goalAnimState = APE_JUMP;
else if (random < 0x140) else if (random < WARN1_CHANCE)
item->goalAnimState = 6; item->goalAnimState = APE_WARNING;
else if (random < 0x1E0) else if (random < WARN2_CHANCE)
item->goalAnimState = 7; item->goalAnimState = APE_WARNING2;
else if (random < 0x2F0) else if (random < RUNLEFT_CHANCE)
{ {
item->goalAnimState = 8; item->goalAnimState = APE_RUNLEFT;
creature->maximumTurn = 0; creature->maximumTurn = 0;
} }
else else
{ {
item->goalAnimState = 9; item->goalAnimState = APE_RUNRIGHT;
creature->maximumTurn = 0; creature->maximumTurn = 0;
} }
} }
else else
item->goalAnimState = 3; item->goalAnimState = APE_RUN;
break; break;
case 3: case APE_RUN:
creature->maximumTurn = ANGLE(5); creature->maximumTurn = RUN_TURN;
if (creature->flags == 0 && info.angle > -ANGLE(45) && info.angle < ANGLE(45)) if (creature->flags == 0 && info.angle > -DISPLAY_ANGLE && info.angle < DISPLAY_ANGLE)
item->goalAnimState = 1; item->goalAnimState = APE_STOP;
else if (info.ahead && (item->touchBits & 0xFF00)) else if (info.ahead && (item->touchBits & TOUCH))
{ {
item->requiredAnimState = 4; item->requiredAnimState = APE_ATTACK1;
item->goalAnimState = 1; item->goalAnimState = APE_STOP;
} }
else if (creature->mood != ESCAPE_MOOD) else if (creature->mood != ESCAPE_MOOD)
{ {
random = (short)GetRandomControl(); random = (short)GetRandomControl();
if (random < 0xA0) if (random < JUMP_CHANCE)
{ {
item->requiredAnimState = 10; item->requiredAnimState = APE_JUMP;
item->goalAnimState = 1; item->goalAnimState = APE_STOP;
} }
else if (random < 0x140) else if (random < WARN1_CHANCE)
{ {
item->requiredAnimState = 6; item->requiredAnimState = APE_WARNING;
item->goalAnimState = 1; item->goalAnimState = APE_STOP;
} }
else if (random < 0x1E0) else if (random < WARN2_CHANCE)
{ {
item->requiredAnimState = 7; item->requiredAnimState = APE_WARNING2;
item->goalAnimState = 1; item->goalAnimState = APE_STOP;
} }
} }
break; break;
case 8: case APE_RUNLEFT:
if (!(creature->flags & 4)) if (!(creature->flags & TURNR_FLAG))
{ {
item->pos.yRot -= ANGLE(90); item->pos.yRot -= ANGLE(90);
creature->flags |= 4; creature->flags |= TURNR_FLAG;
} }
item->goalAnimState = 1; item->goalAnimState = APE_STOP;
break; break;
case 9: case APE_RUNRIGHT:
if (!(creature->flags & 2)) if (!(creature->flags & TURNL_FLAG))
{ {
item->pos.yRot += ANGLE(90); item->pos.yRot += ANGLE(90);
creature->flags |= 2; creature->flags |= TURNL_FLAG;
} }
item->goalAnimState = 1; item->goalAnimState = APE_STOP;
break; break;
case 4: case APE_ATTACK1:
if (!item->requiredAnimState && (item->touchBits & 0xFF00)) if (!item->requiredAnimState && (item->touchBits & TOUCH))
{ {
CreatureEffect(item, &apeBite, DoBloodSplat); CreatureEffect(item, &apeBite, DoBloodSplat);
LaraItem->hitPoints -= 200; LaraItem->hitPoints -= ATTACK_DAMAGE;
LaraItem->hitStatus = true; LaraItem->hitStatus = true;
item->requiredAnimState = 1; item->requiredAnimState = APE_STOP;
} }
break; break;
} }
@ -155,32 +276,10 @@ void ApeControl(short itemNum)
CreatureJoint(item, 0, head); CreatureJoint(item, 0, head);
if (item->currentAnimState != 11) if (item->currentAnimState != APE_VAULT)
{ {
if (creature->flags & 2) ApeVault(itemNum, angle);
{
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;
}
} }
else else
CreatureAnimation(itemNum, angle, 0); CreatureAnimation(itemNum, angle, 0);
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,4 +1,4 @@
#pragma once #pragma once
void InitialiseWolf(short itemNum); 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->initialise = InitialiseWolf;
obj->control = WolfControl; obj->control = WolfControl;
obj->collision = CreatureCollision; obj->collision = CreatureCollision;
obj->shadowSize = 128; obj->shadowSize = UNIT_SHADOW / 2;
obj->hitPoints = 6; obj->hitPoints = 6;
obj->pivotLength = 375; obj->pivotLength = 375;
obj->radius = 340; obj->radius = 340;
@ -152,7 +152,13 @@ static void StartBaddy(OBJECT_INFO* obj)
static void StartObject(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) static void StartTrap(OBJECT_INFO* obj)

View file

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

View file

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