diff --git a/TR5Main/Objects/TR1/Entity/tr1_ape.cpp b/TR5Main/Objects/TR1/Entity/tr1_ape.cpp index 586db2653..1792ecb14 100644 --- a/TR5Main/Objects/TR1/Entity/tr1_ape.cpp +++ b/TR5Main/Objects/TR1/Entity/tr1_ape.cpp @@ -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); -} \ No newline at end of file +} diff --git a/TR5Main/Objects/TR1/Entity/tr1_ape.h b/TR5Main/Objects/TR1/Entity/tr1_ape.h index e48ae6b64..1936b8d11 100644 --- a/TR5Main/Objects/TR1/Entity/tr1_ape.h +++ b/TR5Main/Objects/TR1/Entity/tr1_ape.h @@ -1,3 +1,3 @@ #pragma once -void ApeControl(short itemNum); \ No newline at end of file +void ApeControl(short itemNum); diff --git a/TR5Main/Objects/TR1/Entity/tr1_bear.cpp b/TR5Main/Objects/TR1/Entity/tr1_bear.cpp index d15be40ce..89ed98bb3 100644 --- a/TR5Main/Objects/TR1/Entity/tr1_bear.cpp +++ b/TR5Main/Objects/TR1/Entity/tr1_bear.cpp @@ -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); -} \ No newline at end of file +} diff --git a/TR5Main/Objects/TR1/Entity/tr1_bear.h b/TR5Main/Objects/TR1/Entity/tr1_bear.h index b8810d504..4b90c944d 100644 --- a/TR5Main/Objects/TR1/Entity/tr1_bear.h +++ b/TR5Main/Objects/TR1/Entity/tr1_bear.h @@ -1,3 +1,3 @@ #pragma once -void BearControl(short itemNum); \ No newline at end of file +void BearControl(short itemNum); diff --git a/TR5Main/Objects/TR1/Entity/tr1_doppelganger.cpp b/TR5Main/Objects/TR1/Entity/tr1_doppelganger.cpp index 44293b647..142e1b8eb 100644 --- a/TR5Main/Objects/TR1/Entity/tr1_doppelganger.cpp +++ b/TR5Main/Objects/TR1/Entity/tr1_doppelganger.cpp @@ -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; diff --git a/TR5Main/Objects/TR1/Entity/tr1_doppelganger.h b/TR5Main/Objects/TR1/Entity/tr1_doppelganger.h index 6ce07b0a4..422c866af 100644 --- a/TR5Main/Objects/TR1/Entity/tr1_doppelganger.h +++ b/TR5Main/Objects/TR1/Entity/tr1_doppelganger.h @@ -1,4 +1,4 @@ #pragma once void InitialiseDoppelganger(short itemNum); -void DoppelgangerControl(short itemNum); \ No newline at end of file +void DoppelgangerControl(short itemNum); diff --git a/TR5Main/Objects/TR1/Entity/tr1_wolf.cpp b/TR5Main/Objects/TR1/Entity/tr1_wolf.cpp index e20b3ae4f..6d9b52915 100644 --- a/TR5Main/Objects/TR1/Entity/tr1_wolf.cpp +++ b/TR5Main/Objects/TR1/Entity/tr1_wolf.cpp @@ -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); -} \ No newline at end of file +} diff --git a/TR5Main/Objects/TR1/Entity/tr1_wolf.h b/TR5Main/Objects/TR1/Entity/tr1_wolf.h index 71763efac..314797cae 100644 --- a/TR5Main/Objects/TR1/Entity/tr1_wolf.h +++ b/TR5Main/Objects/TR1/Entity/tr1_wolf.h @@ -1,4 +1,4 @@ #pragma once void InitialiseWolf(short itemNum); -void WolfControl(short itemNum); \ No newline at end of file +void WolfControl(short itemNum); diff --git a/TR5Main/Objects/TR1/tr1_objects.cpp b/TR5Main/Objects/TR1/tr1_objects.cpp index e547c337a..9a352851f 100644 --- a/TR5Main/Objects/TR1/tr1_objects.cpp +++ b/TR5Main/Objects/TR1/tr1_objects.cpp @@ -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) diff --git a/TR5Main/Objects/TR4/Entity/tr4_troops.cpp b/TR5Main/Objects/TR4/Entity/tr4_troops.cpp index 4909de2d8..59b539171 100644 --- a/TR5Main/Objects/TR4/Entity/tr4_troops.cpp +++ b/TR5Main/Objects/TR4/Entity/tr4_troops.cpp @@ -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; diff --git a/TR5Main/Objects/TR5/Object/tr5_pushableblock.cpp b/TR5Main/Objects/TR5/Object/tr5_pushableblock.cpp index c76ab2356..a826c13ac 100644 --- a/TR5Main/Objects/TR5/Object/tr5_pushableblock.cpp +++ b/TR5Main/Objects/TR5/Object/tr5_pushableblock.cpp @@ -1,545 +1,546 @@ -#include "framework.h" -#include "tr5_pushableblock.h" -#include "lara.h" -#include "draw.h" - -#include "items.h" -#include "collide.h" -#include "effect.h" -#include "box.h" -#include "level.h" -#include "input.h" -#include "sound.h" - -OBJECT_COLLISION_BOUNDS PushableBlockBounds = { - 0x0000, 0x0000, 0xFF00, 0x0000, - 0x0000, 0x0000, 0xF8E4, 0x071C, - 0xEAAC, 0x1554, 0xF8E4, 0x071C -}; - -PHD_VECTOR PushableBlockPos = { 0, 0, 0 }; -bool DoPushPull = 0; - -void ClearMovableBlockSplitters(int x, int y, int z, short roomNumber) -{ - FLOOR_INFO* floor = GetFloor(x, y, z, &roomNumber); - g_Level.Boxes[floor->box].flags &= (~BLOCKED); - short height = g_Level.Boxes[floor->box].height; - short baseRoomNumber = roomNumber; - - floor = GetFloor(x + SECTOR(1), y, z, &roomNumber); - if (floor->box != NO_BOX) - { - if (g_Level.Boxes[floor->box].height == height && (g_Level.Boxes[floor->box].flags & BLOCKABLE) && (g_Level.Boxes[floor->box].flags & BLOCKED)) - ClearMovableBlockSplitters(x + SECTOR(1), y, z, roomNumber); - } - - roomNumber = baseRoomNumber; - floor = GetFloor(x - SECTOR(1), y, z, &roomNumber); - if (floor->box != NO_BOX) - { - if (g_Level.Boxes[floor->box].height == height && (g_Level.Boxes[floor->box].flags & BLOCKABLE) && (g_Level.Boxes[floor->box].flags & BLOCKED)) - ClearMovableBlockSplitters(x - SECTOR(1), y, z, roomNumber); - } - - roomNumber = baseRoomNumber; - floor = GetFloor(x, y, z + SECTOR(1), &roomNumber); - if (floor->box != NO_BOX) - { - if (g_Level.Boxes[floor->box].height == height && (g_Level.Boxes[floor->box].flags & BLOCKABLE) && (g_Level.Boxes[floor->box].flags & BLOCKED)) - ClearMovableBlockSplitters(x, y, z + SECTOR(1), roomNumber); - } - - roomNumber = baseRoomNumber; - floor = GetFloor(x, y, z - SECTOR(1), &roomNumber); - if (floor->box != NO_BOX) - { - if (g_Level.Boxes[floor->box].height == height && (g_Level.Boxes[floor->box].flags & BLOCKABLE) && (g_Level.Boxes[floor->box].flags & BLOCKED)) - ClearMovableBlockSplitters(x, y, z - SECTOR(1), roomNumber); - } -} - -void InitialisePushableBlock(short itemNum) -{ - ITEM_INFO* item = &g_Level.Items[itemNum]; - - ClearMovableBlockSplitters(item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber); - - //if (item->status != ITEM_INVISIBLE && item->triggerFlags >= 64) - // AlterFloorHeight(item, -((item->triggerFlags - 64) * 256)); -} - -void PushableBlockControl(short itemNumber) -{ - ITEM_INFO* item = &g_Level.Items[itemNumber]; - - PHD_VECTOR pos; - pos.x = 0; - pos.y = 0; - pos.z = 0; - - short quadrant = (unsigned short)(LaraItem->pos.yRot + ANGLE(45)) / ANGLE(90); - - int x, z; - FLOOR_INFO* floor; - ROOM_INFO* r; - int height; - short roomNumber; - - switch (LaraItem->animNumber) - { - case LA_PUSHABLE_PUSH: - if ((LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 30 - || LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 67) - && (LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 78 - || LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 125) - && (LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 140 - || LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 160)) - { - if (DoPushPull) - { - SoundEffect(SFX_PUSH_BLOCK_END, &item->pos, 2); - DoPushPull = 0; - } - } - else - { - SoundEffect(SFX_PUSHABLE_SOUND, &item->pos, 2); - DoPushPull = 1; - } - - GetLaraJointPosition(&pos, LM_LHAND); - - switch (quadrant) - { - case NORTH: - z = pos.z + item->itemFlags[2] - LaraItem->itemFlags[2]; - if (abs(item->pos.zPos - z) < SECTOR(1) / 2 && item->pos.zPos < z) - item->pos.zPos = z; - break; - - case EAST: - x = pos.x + item->itemFlags[0] - LaraItem->itemFlags[0]; - if (abs(item->pos.xPos - x) < SECTOR(1) / 2 && item->pos.xPos < x) - item->pos.xPos = x; - break; - - case SOUTH: - z = pos.z + item->itemFlags[2] - LaraItem->itemFlags[2]; - if (abs(item->pos.zPos - z) < SECTOR(1) / 2 && item->pos.zPos > z) - item->pos.zPos = z; - break; - - case WEST: - x = pos.x + item->itemFlags[0] - LaraItem->itemFlags[0]; - if (abs(item->pos.xPos - x) < SECTOR(1) / 2 && item->pos.xPos > x) - item->pos.xPos = x; - break; - - default: - break; - } - - if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd - 1) - { - if (TrInput & IN_ACTION) - { - if (!TestBlockPush(item, CLICK(4), quadrant)) - LaraItem->goalAnimState = LS_STOP; - } - else - { - LaraItem->goalAnimState = LS_STOP; - } - } - break; - - case LA_PUSHABLE_PULL: - if ((LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 40 - || LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 122) - && (LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 130 - || LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 170)) - { - if (DoPushPull) - { - SoundEffect(SFX_PUSH_BLOCK_END, &item->pos, 2); - DoPushPull = false; - } - } - else - { - SoundEffect(SFX_PUSHABLE_SOUND, &item->pos, 2); - DoPushPull = true; - } - - GetLaraJointPosition(&pos, LM_LHAND); - - switch (quadrant) - { - case NORTH: - z = pos.z + item->itemFlags[2] - LaraItem->itemFlags[2]; - if (abs(item->pos.zPos - z) < SECTOR(1) / 2 && item->pos.zPos > z) - item->pos.zPos = z; - break; - - case EAST: - x = pos.x + item->itemFlags[0] - LaraItem->itemFlags[0]; - if (abs(item->pos.xPos - x) < SECTOR(1) / 2 && item->pos.xPos > x) - item->pos.xPos = x; - break; - - case SOUTH: - z = pos.z + item->itemFlags[2] - LaraItem->itemFlags[2]; - if (abs(item->pos.zPos - z) < SECTOR(1) / 2 && item->pos.zPos < z) - item->pos.zPos = z; - break; - - case WEST: - x = pos.x + item->itemFlags[0] - LaraItem->itemFlags[0]; - if (abs(item->pos.xPos - x) < SECTOR(1) / 2 && item->pos.xPos < x) - item->pos.xPos = x; - break; - - default: - break; - } - - if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd - 1) - { - if (TrInput & IN_ACTION) - { - if (!TestBlockPull(item, CLICK(4), quadrant)) - LaraItem->goalAnimState = LS_STOP; - } - else - { - LaraItem->goalAnimState = LS_STOP; - } - } - break; - case LA_PUSHABLE_PUSH_TO_STAND: - case LA_PUSHABLE_PULL_TO_STAND: - if (LaraItem->frameNumber == g_Level.Anims[LA_PUSHABLE_PUSH_TO_STAND].frameBase - || LaraItem->frameNumber == g_Level.Anims[LA_PUSHABLE_PULL_TO_STAND].frameBase) - { - item->pos.xPos = item->pos.xPos & 0xFFFFFE00 | 0x200; - item->pos.zPos = item->pos.zPos & 0xFFFFFE00 | 0x200; - } - - if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd) - { - roomNumber = item->roomNumber; - floor = GetFloor(item->pos.xPos, item->pos.yPos - CLICK(1), item->pos.zPos, &roomNumber); - GetFloorHeight(floor, item->pos.xPos, item->pos.yPos - CLICK(1), item->pos.zPos); - TestTriggers(TriggerIndex, 1, item->flags & 0x3E00); - RemoveActiveItem(itemNumber); - item->status = ITEM_NOT_ACTIVE; - - if (item->triggerFlags >= 64) - { - //AlterFloorHeight(item, -((item->triggerFlags - 64) * 256)); - AdjustStopperFlag(item, item->itemFlags[0] + 0x8000, 0); - } - } - break; - } -} - -void PushableBlockCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) -{ - ITEM_INFO* item = &g_Level.Items[itemNum]; - - short roomNumber = item->roomNumber; - FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos - 256, item->pos.zPos, &roomNumber); - - if ((!(TrInput & IN_ACTION) - || l->currentAnimState != LS_STOP - || l->animNumber != LA_STAND_IDLE - || l->gravityStatus - || Lara.gunStatus - || item->status == ITEM_INVISIBLE - || item->triggerFlags < 0) - && (!Lara.isMoving || Lara.generalPtr != item)) - { - if ((l->currentAnimState != LS_PUSHABLE_GRAB - || (l->frameNumber != g_Level.Anims[LA_PUSHABLE_GRAB].frameBase + 19) - || Lara.cornerX != (int)item)) - { - if (item->triggerFlags < 64) - ObjectCollision(itemNum, l, coll); - return; - } - - short quadrant = (unsigned short)(LaraItem->pos.yRot + ANGLE(45)) / ANGLE(90); - - if (TrInput & IN_FORWARD) - { - if (!TestBlockPush(item, CLICK(4), quadrant)) - return; - l->goalAnimState = LS_PUSHABLE_PUSH; - } - else if (TrInput & IN_BACK) - { - if (!TestBlockPull(item, CLICK(4), quadrant)) - return; - l->goalAnimState = LS_PUSHABLE_PULL; - } - else - { - return; - } - - item->status = ITEM_ACTIVE; - AddActiveItem(itemNum); - Lara.headYrot = 0; - Lara.headXrot = 0; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - - PHD_VECTOR pos; - pos.x = 0; - pos.y = 0; - pos.z = 0; - - GetLaraJointPosition(&pos, LM_LHAND); - - l->itemFlags[0] = pos.x; - l->itemFlags[2] = pos.z; - - item->itemFlags[0] = item->pos.xPos; - item->itemFlags[2] = item->pos.zPos; - - if (item->triggerFlags >= 64) - { - //AlterFloorHeight(item, ((item->triggerFlags - 64) * 256)); - AdjustStopperFlag(item, item->itemFlags[0], 0); - } - } - else - { - short roomNumber = l->roomNumber; - FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos - CLICK(1), item->pos.zPos, &roomNumber); - if (roomNumber == item->roomNumber) - { - BOUNDING_BOX* bounds = GetBoundsAccurate(item); - - PushableBlockBounds.boundingBox.X1 = (bounds->X1 / 2) - 100; - PushableBlockBounds.boundingBox.X2 = (bounds->X2 / 2) + 100; - PushableBlockBounds.boundingBox.Z1 = bounds->Z1 - 200; - PushableBlockBounds.boundingBox.Z2 = 0; - - short rot = item->pos.yRot; - item->pos.yRot = (l->pos.yRot + ANGLE(45)) & 0xC000; - - if (TestLaraPosition(&PushableBlockBounds, item, l)) - { - unsigned short quadrant = (unsigned short)((item->pos.yRot / 0x4000) + ((rot + 0x2000) / 0x4000)); - if (quadrant & 1) - PushableBlockPos.z = bounds->X1 - 35; - else - PushableBlockPos.z = bounds->Z1 - 35; - - if (item->triggerFlags > 64) - { - // For now don't use auto-align function because it can collide with climb up moves of Lara - - LaraItem->pos.xRot = item->pos.xRot; - LaraItem->pos.yRot = item->pos.yRot; - LaraItem->pos.zRot = item->pos.zRot; - - l->animNumber = LA_PUSHABLE_GRAB; - l->frameNumber = g_Level.Anims[l->animNumber].frameBase; - l->currentAnimState = LS_PUSHABLE_GRAB; - l->goalAnimState = LS_PUSHABLE_GRAB; - Lara.isMoving = false; - Lara.gunStatus = LG_HANDS_BUSY; - Lara.cornerX = (int)item; - item->pos.yRot = rot; - } - else - { - if (MoveLaraPosition(&PushableBlockPos, item, l)) - { - l->animNumber = LA_PUSHABLE_GRAB; - l->frameNumber = g_Level.Anims[l->animNumber].frameBase; - l->currentAnimState = LS_PUSHABLE_GRAB; - l->goalAnimState = LS_PUSHABLE_GRAB; - Lara.isMoving = false; - Lara.gunStatus = LG_HANDS_BUSY; - Lara.cornerX = (int)item; - item->pos.yRot = rot; - } - else - { - Lara.generalPtr = item; - item->pos.yRot = rot; - } - } - } - else - { - if (Lara.isMoving && Lara.generalPtr == item) - { - Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; - } - item->pos.yRot = rot; - } - } - } -} - -int TestBlockMovable(ITEM_INFO* item, int blokhite) -{ - short roomNum = item->roomNumber; - FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNum); - if (floor->floor == NO_HEIGHT / CLICK(1)) - return true; - else if (floor->floor * CLICK(1) != item->pos.yPos - blokhite) - return false; - - return true; -} - -int TestBlockPush(ITEM_INFO* item, int blockhite, unsigned short quadrant) -{ - int x = item->pos.xPos; - int y = item->pos.yPos; - int z = item->pos.zPos; - - short roomNum = item->roomNumber; - switch (quadrant) - { - case NORTH: - z += SECTOR(1); - break; - - case EAST: - x += SECTOR(1); - break; - - case SOUTH: - z -= SECTOR(1); - break; - - case WEST: - x -= SECTOR(1); - break; - } - - FLOOR_INFO* floor = GetFloor(x, y, z, &roomNum); - ROOM_INFO* r = &g_Level.Rooms[roomNum]; - if (XZ_GET_SECTOR(r, x - r->x, z - r->z).stopper) - return false; - - if (GetFloorHeight(floor, x, y - CLICK(1), z) != y) - return false; - - GetFloorHeight(floor, x, y, z); - if (HeightType) - return false; - - int ceiling = y - blockhite + 100; - floor = GetFloor(x, ceiling, z, &roomNum); - if (GetCeiling(floor, x, ceiling, z) > ceiling) - return false; - - int oldX = item->pos.xPos; - int oldZ = item->pos.zPos; - item->pos.xPos = x; - item->pos.zPos = z; - GetCollidedObjects(item, 256, 1, &CollidedItems[0], 0, 1); - item->pos.xPos = oldX; - item->pos.zPos = oldZ; - - return CollidedItems[0] == NULL; -} - -int TestBlockPull(ITEM_INFO* item, int blockhite, short quadrant) -{ - int xadd = 0; - int zadd = 0; - - switch (quadrant) - { - case NORTH: - zadd = -SECTOR(1); - break; - - case EAST: - xadd = -SECTOR(1); - break; - - case SOUTH: - zadd = SECTOR(1); - break; - - case WEST: - xadd = SECTOR(1); - break; - } - - int x = item->pos.xPos + xadd; - int y = item->pos.yPos; - int z = item->pos.zPos + zadd; - short roomNum = item->roomNumber; - FLOOR_INFO* floor = GetFloor(x, y - 256, z, &roomNum); - - ROOM_INFO* r = &g_Level.Rooms[roomNum]; - if (XZ_GET_SECTOR(r, x - r->x, z - r->z).stopper) - return false; - - if (GetFloorHeight(floor, x, y - CLICK(1), z) != y) - return false; - - if (GetFloor(x, y - blockhite, z, &quadrant)->ceiling * CLICK(1) > y - blockhite) - return false; - - int oldX = item->pos.xPos; - int oldZ = item->pos.zPos; - item->pos.xPos = x; - item->pos.zPos = z; - GetCollidedObjects(item, 256, 1, &CollidedItems[0], 0, 1); - item->pos.xPos = oldX; - item->pos.zPos = oldZ; - - if (CollidedItems[0] != NULL) - return false; - - x += xadd; - z += zadd; - roomNum = item->roomNumber; - floor = GetFloor(x, y - CLICK(1), z, &roomNum); - - if (GetFloorHeight(floor, x, y - CLICK(1), z) != y) - return false; - - if (GetFloor(x, y - 762, z, &roomNum)->ceiling * CLICK(1) > y - 762) - return false; - - x = LaraItem->pos.xPos + xadd; - z = LaraItem->pos.zPos + zadd; - - roomNum = LaraItem->roomNumber; - GetFloor(x, y, z, &roomNum); - - r = &g_Level.Rooms[roomNum]; - if (XZ_GET_SECTOR(r, x - r->x, z - r->z).stopper) - return false; - - oldX = LaraItem->pos.xPos; - oldZ = LaraItem->pos.zPos; - LaraItem->pos.xPos = x; - LaraItem->pos.zPos = z; - GetCollidedObjects(LaraItem, 256, 1, &CollidedItems[0], 0, 1); - LaraItem->pos.xPos = oldX; - LaraItem->pos.zPos = oldZ; - - return (CollidedItems[0] == NULL); -} - -std::tuple, bool> PushableBlockFloor(short itemNumber, int x, int y, int z) -{ +#include "framework.h" +#include "tr5_pushableblock.h" +#include "lara.h" +#include "draw.h" + +#include "items.h" +#include "collide.h" +#include "effect.h" +#include "box.h" +#include "level.h" +#include "input.h" +#include "sound.h" + +OBJECT_COLLISION_BOUNDS PushableBlockBounds = { + 0x0000, 0x0000, 0xFF00, 0x0000, + 0x0000, 0x0000, 0xF8E4, 0x071C, + 0xEAAC, 0x1554, 0xF8E4, 0x071C +}; + +PHD_VECTOR PushableBlockPos = { 0, 0, 0 }; +int DoPushPull = 0; + +void ClearMovableBlockSplitters(int x, int y, int z, short roomNumber) +{ + FLOOR_INFO* floor = GetFloor(x, y, z, &roomNumber); + g_Level.Boxes[floor->box].flags &= (~BLOCKED); + short height = g_Level.Boxes[floor->box].height; + short baseRoomNumber = roomNumber; + + floor = GetFloor(x + 1024, y, z, &roomNumber); + if (floor->box != NO_BOX) + { + if (g_Level.Boxes[floor->box].height == height && (g_Level.Boxes[floor->box].flags & BLOCKABLE) && (g_Level.Boxes[floor->box].flags & BLOCKED)) + ClearMovableBlockSplitters(x + 1024, y, z, roomNumber); + } + + roomNumber = baseRoomNumber; + floor = GetFloor(x - 1024, y, z, &roomNumber); + if (floor->box != NO_BOX) + { + if (g_Level.Boxes[floor->box].height == height && (g_Level.Boxes[floor->box].flags & BLOCKABLE) && (g_Level.Boxes[floor->box].flags & BLOCKED)) + ClearMovableBlockSplitters(x - 1024, y, z, roomNumber); + } + + roomNumber = baseRoomNumber; + floor = GetFloor(x, y, z + 1024, &roomNumber); + if (floor->box != NO_BOX) + { + if (g_Level.Boxes[floor->box].height == height && (g_Level.Boxes[floor->box].flags & BLOCKABLE) && (g_Level.Boxes[floor->box].flags & BLOCKED)) + ClearMovableBlockSplitters(x, y, z + 1024, roomNumber); + } + + roomNumber = baseRoomNumber; + floor = GetFloor(x, y, z - 1024, &roomNumber); + if (floor->box != NO_BOX) + { + if (g_Level.Boxes[floor->box].height == height && (g_Level.Boxes[floor->box].flags & BLOCKABLE) && (g_Level.Boxes[floor->box].flags & BLOCKED)) + ClearMovableBlockSplitters(x, y, z - 1024, roomNumber); + } +} + +void InitialisePushableBlock(short itemNum) +{ + ITEM_INFO* item = &g_Level.Items[itemNum]; + + ClearMovableBlockSplitters(item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber); + + //if (item->status != ITEM_INVISIBLE && item->triggerFlags >= 64) + // AlterFloorHeight(item, -((item->triggerFlags - 64) * 256)); +} + +void PushableBlockControl(short itemNumber) +{ + ITEM_INFO* item = &g_Level.Items[itemNumber]; + + PHD_VECTOR pos; + pos.x = 0; + pos.y = 0; + pos.z = 0; + + short quadrant = (unsigned short)(LaraItem->pos.yRot + ANGLE(45)) / ANGLE(90); + + int x, z; + FLOOR_INFO* floor; + ROOM_INFO* r; + int height; + short roomNumber; + + switch (LaraItem->animNumber) + { + case LA_PUSHABLE_PUSH: + if ((LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 30 + || LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 67) + && (LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 78 + || LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 125) + && (LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 140 + || LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 160)) + { + if (DoPushPull) + { + SoundEffect(SFX_PUSH_BLOCK_END, &item->pos, 2); + DoPushPull = 0; + } + } + else + { + SoundEffect(SFX_PUSHABLE_SOUND, &item->pos, 2); + DoPushPull = 1; + } + + GetLaraJointPosition(&pos, LM_LHAND); + + switch (quadrant) + { + case 0: + z = pos.z + item->itemFlags[2] - LaraItem->itemFlags[2]; + if (abs(item->pos.zPos - z) < 512 && item->pos.zPos < z) + item->pos.zPos = z; + break; + + case 1: + x = pos.x + item->itemFlags[0] - LaraItem->itemFlags[0]; + if (abs(item->pos.xPos - x) < 512 && item->pos.xPos < x) + item->pos.xPos = x; + break; + + case 2: + z = pos.z + item->itemFlags[2] - LaraItem->itemFlags[2]; + if (abs(item->pos.zPos - z) < 512 && item->pos.zPos > z) + item->pos.zPos = z; + break; + + case 3: + x = pos.x + item->itemFlags[0] - LaraItem->itemFlags[0]; + if (abs(item->pos.xPos - x) < 512 && item->pos.xPos > x) + item->pos.xPos = x; + break; + + default: + break; + } + + if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd - 1) + { + if (TrInput & IN_ACTION) + { + if (!TestBlockPush(item, 1024, quadrant)) + LaraItem->goalAnimState = LS_STOP; + } + else + { + LaraItem->goalAnimState = LS_STOP; + } + } + break; + + case LA_PUSHABLE_PULL: + if ((LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 40 + || LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 122) + && (LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 130 + || LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 170)) + { + if (DoPushPull) + { + SoundEffect(SFX_PUSH_BLOCK_END, &item->pos, 2); + DoPushPull = 0; + } + } + else + { + SoundEffect(SFX_PUSHABLE_SOUND, &item->pos, 2); + DoPushPull = 1; + } + + GetLaraJointPosition(&pos, LM_LHAND); + + switch (quadrant) + { + case NORTH: + z = pos.z + item->itemFlags[2] - LaraItem->itemFlags[2]; + if (abs(item->pos.zPos - z) < 512 && item->pos.zPos > z) + item->pos.zPos = z; + break; + + case EAST: + x = pos.x + item->itemFlags[0] - LaraItem->itemFlags[0]; + if (abs(item->pos.xPos - x) < 512 && item->pos.xPos > x) + item->pos.xPos = x; + break; + + case SOUTH: + z = pos.z + item->itemFlags[2] - LaraItem->itemFlags[2]; + if (abs(item->pos.zPos - z) < 512 && item->pos.zPos < z) + item->pos.zPos = z; + break; + + case WEST: + x = pos.x + item->itemFlags[0] - LaraItem->itemFlags[0]; + if (abs(item->pos.xPos - x) < 512 && item->pos.xPos < x) + item->pos.xPos = x; + break; + + default: + break; + } + + if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd - 1) + { + if (TrInput & IN_ACTION) + { + if (!TestBlockPull(item, 1024, quadrant)) + LaraItem->goalAnimState = LS_STOP; + } + else + { + LaraItem->goalAnimState = LS_STOP; + } + } + break; + case LA_PUSHABLE_PUSH_TO_STAND: + case LA_PUSHABLE_PULL_TO_STAND: + if (LaraItem->frameNumber == g_Level.Anims[LA_PUSHABLE_PUSH_TO_STAND].frameBase + || LaraItem->frameNumber == g_Level.Anims[LA_PUSHABLE_PULL_TO_STAND].frameBase) + { + item->pos.xPos = item->pos.xPos & 0xFFFFFE00 | 0x200; + item->pos.zPos = item->pos.zPos & 0xFFFFFE00 | 0x200; + } + + if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd) + { + roomNumber = item->roomNumber; + floor = GetFloor(item->pos.xPos, item->pos.yPos - 256, item->pos.zPos, &roomNumber); + GetFloorHeight(floor, item->pos.xPos, item->pos.yPos - 256, item->pos.zPos); + TestTriggers(TriggerIndex, 1, item->flags & 0x3E00); + RemoveActiveItem(itemNumber); + item->status = ITEM_NOT_ACTIVE; + + if (item->triggerFlags >= 64) + { + //AlterFloorHeight(item, -((item->triggerFlags - 64) * 256)); + AdjustStopperFlag(item, item->itemFlags[0] + 0x8000, 0); + } + } + break; + } +} + +void PushableBlockCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) +{ + ITEM_INFO* item = &g_Level.Items[itemNum]; + + short roomNumber = item->roomNumber; + FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos - 256, item->pos.zPos, &roomNumber); + + if ((!(TrInput & IN_ACTION) + || l->currentAnimState != LS_STOP + || l->animNumber != LA_STAND_IDLE + || l->gravityStatus + || Lara.gunStatus + || item->status == ITEM_INVISIBLE + || item->triggerFlags < 0) + && (!Lara.isMoving || Lara.generalPtr != item)) + { + if ((l->currentAnimState != LS_PUSHABLE_GRAB + || (l->frameNumber != g_Level.Anims[LA_PUSHABLE_GRAB].frameBase + 19) + || Lara.cornerX != (int)item)) + { + if (item->triggerFlags < 64) + ObjectCollision(itemNum, l, coll); + return; + } + + short quadrant = (unsigned short)(LaraItem->pos.yRot + ANGLE(45)) / ANGLE(90); + + if (TrInput & IN_FORWARD) + { + if (!TestBlockPush(item, 1024, quadrant)) + return; + l->goalAnimState = LS_PUSHABLE_PUSH; + } + else if (TrInput & IN_BACK) + { + if (!TestBlockPull(item, 1024, quadrant)) + return; + l->goalAnimState = LS_PUSHABLE_PULL; + } + else + { + return; + } + + item->status = ITEM_ACTIVE; + AddActiveItem(itemNum); + Lara.headYrot = 0; + Lara.headXrot = 0; + Lara.torsoYrot = 0; + Lara.torsoXrot = 0; + + PHD_VECTOR pos; + pos.x = 0; + pos.y = 0; + pos.z = 0; + + GetLaraJointPosition(&pos, LM_LHAND); + + l->itemFlags[0] = pos.x; + l->itemFlags[2] = pos.z; + + item->itemFlags[0] = item->pos.xPos; + item->itemFlags[2] = item->pos.zPos; + + if (item->triggerFlags >= 64) + { + //AlterFloorHeight(item, ((item->triggerFlags - 64) * 256)); + AdjustStopperFlag(item, item->itemFlags[0], 0); + } + } + else + { + short roomNumber = l->roomNumber; + FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos - 256, item->pos.zPos, &roomNumber); + if (roomNumber == item->roomNumber) + { + BOUNDING_BOX* bounds = GetBoundsAccurate(item); + + PushableBlockBounds.boundingBox.X1 = (bounds->X1 / 2) - 100; + PushableBlockBounds.boundingBox.X2 = (bounds->X2 / 2) + 100; + PushableBlockBounds.boundingBox.Z1 = bounds->Z1 - 200; + PushableBlockBounds.boundingBox.Z2 = 0; + + short rot = item->pos.yRot; + item->pos.yRot = (l->pos.yRot + ANGLE(45)) & 0xC000; + + if (TestLaraPosition(&PushableBlockBounds, item, l)) + { + unsigned short quadrant = (unsigned short)((item->pos.yRot / 0x4000) + ((rot + 0x2000) / 0x4000)); + if (quadrant & 1) + PushableBlockPos.z = bounds->X1 - 35; + else + PushableBlockPos.z = bounds->Z1 - 35; + + if (item->triggerFlags > 64) + { + // For now don't use auto-align function because it can collide with climb up moves of Lara + + LaraItem->pos.xRot = item->pos.xRot; + LaraItem->pos.yRot = item->pos.yRot; + LaraItem->pos.zRot = item->pos.zRot; + + l->animNumber = LA_PUSHABLE_GRAB; + l->frameNumber = g_Level.Anims[l->animNumber].frameBase; + l->currentAnimState = LS_PUSHABLE_GRAB; + l->goalAnimState = LS_PUSHABLE_GRAB; + Lara.isMoving = false; + Lara.gunStatus = LG_HANDS_BUSY; + Lara.cornerX = (int)item; + item->pos.yRot = rot; + } + else + { + if (MoveLaraPosition(&PushableBlockPos, item, l)) + { + l->animNumber = LA_PUSHABLE_GRAB; + l->frameNumber = g_Level.Anims[l->animNumber].frameBase; + l->currentAnimState = LS_PUSHABLE_GRAB; + l->goalAnimState = LS_PUSHABLE_GRAB; + Lara.isMoving = false; + Lara.gunStatus = LG_HANDS_BUSY; + Lara.cornerX = (int)item; + item->pos.yRot = rot; + } + else + { + Lara.generalPtr = item; + item->pos.yRot = rot; + } + } + } + else + { + if (Lara.isMoving && Lara.generalPtr == item) + { + Lara.isMoving = false; + Lara.gunStatus = LG_NO_ARMS; + } + item->pos.yRot = rot; + } + } + } +} + +int TestBlockMovable(ITEM_INFO* item, int blokhite) +{ + short roomNumber = item->roomNumber; + FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber); + if (floor->floor == NO_HEIGHT / 256) + return 1; + + if (floor->floor * 256 != item->pos.yPos - blokhite) + return 0; + + return 1; +} + +int TestBlockPush(ITEM_INFO* item, int blockhite, unsigned short quadrant) +{ + int x = item->pos.xPos; + int y = item->pos.yPos; + int z = item->pos.zPos; + + short roomNum = item->roomNumber; + switch (quadrant) + { + case NORTH: + z += 1024; + break; + + case EAST: + x += 1024; + break; + + case SOUTH: + z -= 1024; + break; + + case WEST: + x -= 1024; + break; + } + + FLOOR_INFO* floor = GetFloor(x, y, z, &roomNum); + ROOM_INFO* r = &g_Level.Rooms[roomNum]; + if (XZ_GET_SECTOR(r, x - r->x, z - r->z).stopper) + return 0; + + if (GetFloorHeight(floor, x, y - 256, z) != y) + return 0; + + GetFloorHeight(floor, x, y, z); + if (HeightType) + return 0; + + int ceiling = y - blockhite + 100; + floor = GetFloor(x, ceiling, z, &roomNum); + if (GetCeiling(floor, x, ceiling, z) > ceiling) + return 0; + + int oldX = item->pos.xPos; + int oldZ = item->pos.zPos; + item->pos.xPos = x; + item->pos.zPos = z; + GetCollidedObjects(item, 256, 1, &CollidedItems[0], 0, 1); + item->pos.xPos = oldX; + item->pos.zPos = oldZ; + + return CollidedItems[0] == NULL; +} + +int TestBlockPull(ITEM_INFO* item, int blockhite, short quadrant) +{ + int xadd = 0; + int zadd = 0; + + switch (quadrant) + { + case NORTH: + zadd = -1024; + break; + + case EAST: + xadd = -1024; + break; + + case SOUTH: + zadd = 1024; + break; + + case WEST: + xadd = 1024; + break; + } + + int x = item->pos.xPos + xadd; + int y = item->pos.yPos; + int z = item->pos.zPos + zadd; + short roomNum = item->roomNumber; + FLOOR_INFO* floor = GetFloor(x, y - 256, z, &roomNum); + + ROOM_INFO* r = &g_Level.Rooms[roomNum]; + if (XZ_GET_SECTOR(r, x - r->x, z - r->z).stopper) + return 0; + + if (GetFloorHeight(floor, x, y - 256, z) != y) + return 0; + + if (GetFloor(x, y - blockhite, z, &quadrant)->ceiling * 256 > y - blockhite) + return 0; + + int oldX = item->pos.xPos; + int oldZ = item->pos.zPos; + item->pos.xPos = x; + item->pos.zPos = z; + GetCollidedObjects(item, 256, 1, &CollidedItems[0], 0, 1); + item->pos.xPos = oldX; + item->pos.zPos = oldZ; + + if (CollidedItems[0] != NULL) + return 0; + + x += xadd; + z += zadd; + roomNum = item->roomNumber; + floor = GetFloor(x, y - 256, z, &roomNum); + + if (GetFloorHeight(floor, x, y - 256, z) != y) + return 0; + + if (GetFloor(x, y - 762, z, &roomNum)->ceiling * 256 > y - 762) + return 0; + + x = LaraItem->pos.xPos + xadd; + z = LaraItem->pos.zPos + zadd; + + roomNum = LaraItem->roomNumber; + GetFloor(x, y, z, &roomNum); + + r = &g_Level.Rooms[roomNum]; + if (XZ_GET_SECTOR(r, x - r->x, z - r->z).stopper) + return 0; + + oldX = LaraItem->pos.xPos; + oldZ = LaraItem->pos.zPos; + LaraItem->pos.xPos = x; + LaraItem->pos.zPos = z; + GetCollidedObjects(LaraItem, 256, 1, &CollidedItems[0], 0, 1); + LaraItem->pos.xPos = oldX; + LaraItem->pos.zPos = oldZ; + + return (CollidedItems[0] == NULL); +} + +std::tuple, bool> PushableBlockFloor(short itemNumber, int x, int y, int z) +{ const auto& item = g_Level.Items[itemNumber]; if (item.status != ITEM_INVISIBLE && item.triggerFlags >= 64 && abs(item.pos.xPos - x) <= SECTOR(1) / 2 && abs(item.pos.zPos - z) <= SECTOR(1) / 2) { @@ -547,10 +548,10 @@ std::tuple, bool> PushableBlockFloor(short itemNumber, int x, return std::make_tuple(std::optional{height}, y > height && y < item.pos.yPos); } return std::make_tuple(std::nullopt, false); -} - -std::tuple, bool> PushableBlockCeiling(short itemNumber, int x, int y, int z) -{ +} + +std::tuple, bool> PushableBlockCeiling(short itemNumber, int x, int y, int z) +{ const auto& item = g_Level.Items[itemNumber]; if (item.status != ITEM_INVISIBLE && item.triggerFlags >= 64 && abs(item.pos.xPos - x) <= SECTOR(1) / 2 && abs(item.pos.zPos - z) <= SECTOR(1) / 2) { @@ -558,4 +559,4 @@ std::tuple, bool> PushableBlockCeiling(short itemNumber, int return std::make_tuple(std::optional{item.pos.yPos}, y > height && y < item.pos.yPos); } return std::make_tuple(std::nullopt, false); -} +} diff --git a/TR5Main/Objects/TR5/Object/tr5_raisingblock.cpp b/TR5Main/Objects/TR5/Object/tr5_raisingblock.cpp index f899406ac..12e33028b 100644 --- a/TR5Main/Objects/TR5/Object/tr5_raisingblock.cpp +++ b/TR5Main/Objects/TR5/Object/tr5_raisingblock.cpp @@ -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; } -} \ No newline at end of file +} + +std::tuple, 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, 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); +} diff --git a/TR5Main/Objects/TR5/Object/tr5_raisingblock.h b/TR5Main/Objects/TR5/Object/tr5_raisingblock.h index b600e8331..22293736f 100644 --- a/TR5Main/Objects/TR5/Object/tr5_raisingblock.h +++ b/TR5Main/Objects/TR5/Object/tr5_raisingblock.h @@ -1,4 +1,6 @@ #pragma once void InitialiseRaisingBlock(short itemNumber); -void ControlRaisingBlock(short itemNumber); \ No newline at end of file +void ControlRaisingBlock(short itemNumber); +std::tuple, bool> RaisingBlockFloor(short itemNumber, int x, int y, int z); +std::tuple, bool> RaisingBlockCeiling(short itemNumber, int x, int y, int z); diff --git a/TR5Main/Objects/TR5/tr5_objects.cpp b/TR5Main/Objects/TR5/tr5_objects.cpp index a16850e89..26718c75d 100644 --- a/TR5Main/Objects/TR5/tr5_objects.cpp +++ b/TR5Main/Objects/TR5/tr5_objects.cpp @@ -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; } } diff --git a/TR5Main/Objects/objectslist.h b/TR5Main/Objects/objectslist.h index d4b658281..191b792ee 100644 --- a/TR5Main/Objects/objectslist.h +++ b/TR5Main/Objects/objectslist.h @@ -805,6 +805,7 @@ typedef enum GAME_OBJECT_ID ID_WATERFALLSS1, ID_WATERFALLSS2, ID_FISHTANK, + ID_BACON_REFERENCE, ID_MESHSWAP1 = 1100, ID_MESHSWAP2,