TombEngine/TR5Main/Objects/fish.cpp
TokyoSU 713c992d76 Added Sophia
- deleted all the __cdecl except for the #define function. because /Gd enable the __cdecl for function by default.

- added the commented code in FireWeapon for TR3 entity (some function is missing)
2019-12-02 14:49:19 +01:00

489 lines
13 KiB
C++

#include "newobjects.h"
#include "..\Global\global.h"
#include "..\Game\Box.h"
#include "..\Game\items.h"
#include "..\Game\lot.h"
#include "..\Game\control.h"
#include "..\Game\effects.h"
#include "..\Game\draw.h"
#include "..\Game\sphere.h"
#include "..\Game\effect2.h"
#include "..\Game\people.h"
#include "..\Game\Lara.h"
#define PIRAHNA_DAMAGE 4
#define X 0
#define Y 1
#define Z 2
#define XYZ 3
#define MAX_FISH 8
#define OCB_FISH_LETAL 0x1000
#define OCB_FISH_EAT_CARCASS 0x2000
FISH_LEADER_INFO LeaderInfo[MAX_FISH];
FISH_INFO Fishes[MAX_FISH + (MAX_FISH * 24)];
byte FishRanges[1][3] = {
{ 2 << 2, 5 << 2, 3 }
};
int PirahnaHitWait = false;
int CarcassItem = NO_ITEM;
/*uchar temple_fish_ranges[3][3] = {
{ 1 << 2,1 << 2,2 },
{ 1 << 2,4 << 2,2 },
{ 1 << 2,7 << 2,4 },
};
uchar quadchase_fish_ranges[8][3] = {
{ 1 << 2,3 << 2,1 },
{ 0 << 2,3 << 2,2 },
{ 2 << 2,1 << 2,2 },
{ 1 << 2,2 << 2,1 },
{ 1 << 2,4 << 2,2 },
{ 1 << 2,6 << 2,1 },
{ 3 << 2,1 << 2,1 },
{ 4 << 2,1 << 2,1 },
};
uchar house_fish_ranges[7][3] = {
{ 1 << 2,1 << 2,1 }, // Unused.
{ 4 << 2,2 << 2,2 },
{ 6 << 2,2 << 2,2 },
{ 2 << 2,4 << 2,2 },
{ 2 << 2,3 << 2,1 },
{ 5 << 2,2 << 2,2 },
{ 4 << 2,2 << 2,1 },
};
uchar shore_fish_ranges[3][3] = {
{ 3 << 2,3 << 2,6 },
{ 3 << 2,5 << 2,6 },
{ 5 << 2,1 << 2,8 },
};
uchar crash_fish_ranges[1][3] = {
{ 5 << 2,1 << 2,6 },
};
uchar rapids_fish_ranges[2][3] = {
{ 4 << 2,4 << 2,8 },
{ 1 << 2,2 << 2,5 },
};*/
void SetupShoal(int shoalNumber)
{
//if (CurrentLevel == LV_JUNGLE)
//{
LeaderInfo[shoalNumber].xRange = (FishRanges[shoalNumber][0] + 2) << 8;
LeaderInfo[shoalNumber].zRange = (FishRanges[shoalNumber][1] + 2) << 8;
LeaderInfo[shoalNumber].yRange = (FishRanges[shoalNumber][2]) << 8;
//}
/*else if (CurrentLevel == LV_TEMPLE)
{
LeaderInfo[shoalNumber].xRange = (temple_fish_ranges[shoalNumber][0] + 2) << 8;
LeaderInfo[shoalNumber].zRange = (temple_fish_ranges[shoalNumber][1] + 2) << 8;
LeaderInfo[shoalNumber].yRange = (temple_fish_ranges[shoalNumber][2]) << 8;
}
else if (CurrentLevel == LV_QUADBIKE)
{
LeaderInfo[shoalNumber].xRange = (quadchase_fish_ranges[shoalNumber][0] + 2) << 8;
LeaderInfo[shoalNumber].zRange = (quadchase_fish_ranges[shoalNumber][1] + 2) << 8;
LeaderInfo[shoalNumber].yRange = (quadchase_fish_ranges[shoalNumber][2]) << 8;
}
else if (CurrentLevel == LV_GYM)
{
LeaderInfo[shoalNumber].xRange = (house_fish_ranges[shoalNumber][0] + 2) << 8;
LeaderInfo[shoalNumber].zRange = (house_fish_ranges[shoalNumber][1] + 2) << 8;
LeaderInfo[shoalNumber].yRange = (house_fish_ranges[shoalNumber][2]) << 8;
}
else if (CurrentLevel == LV_SHORE)
{
LeaderInfo[shoalNumber].xRange = (shore_fish_ranges[shoalNumber][0] + 2) << 8;
LeaderInfo[shoalNumber].zRange = (shore_fish_ranges[shoalNumber][1] + 2) << 8;
LeaderInfo[shoalNumber].yRange = (shore_fish_ranges[shoalNumber][2]) << 8;
}
else if (CurrentLevel == LV_CRASH)
{
LeaderInfo[shoalNumber].xRange = (crash_fish_ranges[shoalNumber][0] + 2) << 8;
LeaderInfo[shoalNumber].zRange = (crash_fish_ranges[shoalNumber][1] + 2) << 8;
LeaderInfo[shoalNumber].yRange = (crash_fish_ranges[shoalNumber][2]) << 8;
}
else if (CurrentLevel == LV_RAPIDS)
{
LeaderInfo[shoalNumber].xRange = (rapids_fish_ranges[shoalNumber][0] + 2) << 8;
LeaderInfo[shoalNumber].zRange = (rapids_fish_ranges[shoalNumber][1] + 2) << 8;
LeaderInfo[shoalNumber].yRange = (rapids_fish_ranges[shoalNumber][2]) << 8;
}
else
{
LeaderInfo[shoalNumber].xRange = 1 << 8;
LeaderInfo[shoalNumber].zRange = 1 << 8;
LeaderInfo[shoalNumber].yRange = 1 << 8;
}*/
}
void SetupFish(int leader, ITEM_INFO* item)
{
int fishXRange = LeaderInfo[leader].xRange;
int fishYRange = LeaderInfo[leader].yRange;
int fishZRange = LeaderInfo[leader].zRange;
Fishes[leader].x = 0;
Fishes[leader].y = 0;
Fishes[leader].z = 0;
Fishes[leader].angle = 0;
Fishes[leader].speed = (GetRandomControl() & 63) + 8;
Fishes[leader].swim = GetRandomControl() & 63;
for (int i = 0; i < 24; i++)
{
Fishes[MAX_FISH + (leader * 24) + i].x = (GetRandomControl() % (fishXRange << 1)) - fishXRange;
Fishes[MAX_FISH + (leader * 24) + i].y = (GetRandomControl() % fishYRange);
Fishes[MAX_FISH + (leader * 24) + i].destY = (GetRandomControl() % fishYRange);
Fishes[MAX_FISH + (leader * 24) + i].z = (GetRandomControl() % (fishZRange << 1)) - fishZRange;
Fishes[MAX_FISH + (leader * 24) + i].angle = GetRandomControl() & 4095;
Fishes[MAX_FISH + (leader * 24) + i].speed = (GetRandomControl() & 31) + 32;
Fishes[MAX_FISH + (leader * 24) + i].swim = GetRandomControl() & 63;
}
LeaderInfo[leader].on = 1;
LeaderInfo[leader].angle = 0;
LeaderInfo[leader].speed = (GetRandomControl() & 127) + 32;
LeaderInfo[leader].angleTime = 0;
LeaderInfo[leader].speedTime = 0;
}
void ControlFish(short itemNumber)
{
int pirahnaAttack = 0;
int angle = 0;
ITEM_INFO* item = &Items[itemNumber];
ITEM_INFO* enemy = item;
if (!TriggerActive(item))
return;
int leader = item->hitPoints;
if (!LeaderInfo[leader].on)
SetupFish(leader, item);
if (item->triggerFlags & OCB_FISH_LETAL)
{
if ((item->triggerFlags == OCB_FISH_EAT_CARCASS) == 0)
pirahnaAttack = (LaraItem->roomNumber == item->roomNumber);
else
{
if (CarcassItem != -1)
pirahnaAttack = 2;
else
pirahnaAttack = (LaraItem->roomNumber == item->roomNumber);
}
}
else
pirahnaAttack = 0;
if (PirahnaHitWait)
PirahnaHitWait--;
FISH_INFO* fish = (FISH_INFO*)&Fishes[leader];
if (pirahnaAttack)
{
if (pirahnaAttack == 1)
enemy = LaraItem;
else
enemy = &Items[CarcassItem];
LeaderInfo[leader].angle = fish->angle = (-(mGetAngle(fish->x + item->pos.xPos, fish->z + item->pos.zPos, enemy->pos.xPos, enemy->pos.zPos) + 0x4000) >> 4) & 4095;
LeaderInfo[leader].speed = (GetRandomControl() & 63) + 192;
}
int diff = fish->angle - LeaderInfo[leader].angle;
if (diff > 2048)
diff -= 4096;
else if (diff < -2048)
diff += 4096;
if (diff > 128)
{
fish->angAdd -= 4;
if (fish->angAdd < -120)
fish->angAdd = -120;
}
else if (diff < -128)
{
fish->angAdd += 4;
if (fish->angAdd > 120)
fish->angAdd = 120;
}
else
{
fish->angAdd -= fish->angAdd >> 2;
if (abs(fish->angAdd) < 4)
fish->angAdd = 0;
}
fish->angle += fish->angAdd;
if (diff > 1024)
fish->angle += fish->angAdd >> 2;
fish->angle &= 4095;
diff = fish->speed - LeaderInfo[leader].speed;
if (diff < -4)
{
diff = fish->speed + (GetRandomControl() & 3) + 1;
if (diff < 0)
diff = 0;
fish->speed = diff;
}
else if (diff > 4)
{
diff = fish->speed - (GetRandomControl() & 3) - 1;
if (diff > 255)
diff = 255;
fish->speed = diff;
}
fish->swim += fish->speed >> 4;
fish->swim &= 63;
int x = fish->x;
int z = fish->z;
x += -fish->speed * SIN(fish->angle << 4) >> W2V_SHIFT; // -(((rcossin_tbl[(fish->angle << 1)]) * (fish->speed)) >> 13);
z += fish->speed * COS(fish->angle << 4) >> W2V_SHIFT; // (((rcossin_tbl[(fish->angle << 1) + 1]) * (fish->speed)) >> 13);
if (pirahnaAttack == 0)
{
int fishXRange = LeaderInfo[leader].xRange;
int fishZRange = LeaderInfo[leader].zRange;
if (z < -fishZRange)
{
z = -fishZRange;
if (fish->angle < 2048)
LeaderInfo[leader].angle = fish->angle - ((GetRandomControl() & 127) + 128);
else
LeaderInfo[leader].angle = fish->angle + ((GetRandomControl() & 127) + 128);
LeaderInfo[leader].angleTime = (GetRandomControl() & 15) + 8;
LeaderInfo[leader].speedTime = 0;
}
else if (z > fishZRange)
{
z = fishZRange;
if (fish->angle > 3072)
LeaderInfo[leader].angle = fish->angle - ((GetRandomControl() & 127) + 128);
else
LeaderInfo[leader].angle = fish->angle + ((GetRandomControl() & 127) + 128);
LeaderInfo[leader].angleTime = (GetRandomControl() & 15) + 8;
LeaderInfo[leader].speedTime = 0;
}
if (x < -fishXRange)
{
x = -fishXRange;
if (fish->angle < 1024)
LeaderInfo[leader].angle = fish->angle - ((GetRandomControl() & 127) + 128);
else
LeaderInfo[leader].angle = fish->angle + ((GetRandomControl() & 127) + 128);
LeaderInfo[leader].angleTime = (GetRandomControl() & 15) + 8;
LeaderInfo[leader].speedTime = 0;
}
else if (x > fishXRange)
{
x = fishXRange;
if (fish->angle < 3072)
LeaderInfo[leader].angle = fish->angle - ((GetRandomControl() & 127) + 128);
else
LeaderInfo[leader].angle = fish->angle + ((GetRandomControl() & 127) + 128);
LeaderInfo[leader].angleTime = (GetRandomControl() & 15) + 8;
LeaderInfo[leader].speedTime = 0;
}
if ((GetRandomControl() & 15) == 0)
LeaderInfo[leader].angleTime = 0;
if (LeaderInfo[leader].angleTime)
LeaderInfo[leader].angleTime--;
else
{
LeaderInfo[leader].angleTime = (GetRandomControl() & 15) + 8;
int angAdd = ((GetRandomControl() & 63) + 16) - 8 - 32;
if ((GetRandomControl() & 3) == 0)
LeaderInfo[leader].angle += angAdd << 5;
else
LeaderInfo[leader].angle += angAdd;
LeaderInfo[leader].angle &= 4095;
}
if (LeaderInfo[leader].speedTime)
LeaderInfo[leader].speedTime--;
else
{
LeaderInfo[leader].speedTime = (GetRandomControl() & 31) + 32;
if ((GetRandomControl() & 7) == 0)
LeaderInfo[leader].speed = (GetRandomControl() & 127) + 128;
else if ((GetRandomControl() & 3) == 0)
LeaderInfo[leader].speed += (GetRandomControl() & 127) + 32;
else if (LeaderInfo[leader].speed > 140)
LeaderInfo[leader].speed -= (GetRandomControl() & 31) + 48;
else
{
LeaderInfo[leader].speedTime = (GetRandomControl() & 3) + 4;
LeaderInfo[leader].speed += (GetRandomControl() & 31) - 15;
}
}
}
int ftx = x;
int ftz = z;
fish->x = x;
fish->z = z;
fish = (FISH_INFO*)&Fishes[MAX_FISH + (leader * 24)];
for (int i = 0; i < 24; i++)
{
if (item->flags & OCB_FISH_LETAL)
{
PHD_3DPOS pos;
pos.xPos = item->pos.xPos + fish->x;
pos.yPos = item->pos.yPos + fish->y;
pos.zPos = item->pos.zPos + fish->z;
if (FishNearLara(&pos, 256, (pirahnaAttack < 2) ? LaraItem : enemy))
{
if (PirahnaHitWait == 0)
{
DoBloodSplat(item->pos.xPos + fish->x, item->pos.yPos + fish->y, item->pos.zPos + fish->z, 0, 0, (pirahnaAttack < 2) ? LaraItem->roomNumber : enemy->roomNumber);
PirahnaHitWait = 8;
}
if (pirahnaAttack != 2)
LaraItem->hitPoints -= PIRAHNA_DAMAGE;
}
}
angle = (-(mGetAngle(fish->x, fish->z, ftx, ftz) + 0x4000) >> 4) & 4095;
int dx = fish->x - ftx + ((24 - i) << 7);
int dz = fish->z - ftz - ((24 - i) << 7);
dx *= dx;
dz *= dz;
diff = fish->angle - angle;
if (diff > 2048)
diff -= 4096;
else if (diff < -2048)
diff += 4096;
if (diff > 128)
{
fish->angAdd -= 4;
if (fish->angAdd < -92 - (i >> 1))
fish->angAdd = -92 - (i >> 1);
}
else if (diff < -128)
{
fish->angAdd += 4;
if (fish->angAdd > 92 + (i >> 1))
fish->angAdd = 92 + (i >> 1);
}
else
{
fish->angAdd -= fish->angAdd >> 2;
if (abs(fish->angAdd) < 4)
fish->angAdd = 0;
}
fish->angle += fish->angAdd;
if (diff > 1024)
fish->angle += fish->angAdd >> 2;
fish->angle &= 4095;
if ((dx + dz) < (0x100000 + ((i << 7) * (i << 7))))
{
if (fish->speed > 32 + (i << 1))
fish->speed -= fish->speed >> 5;
}
else
{
if (fish->speed < 160 + (i >> 1))
fish->speed += (GetRandomControl() & 3) + 1 + (i >> 1);
if (fish->speed > 160 + (i >> 1) - (i << 2))
fish->speed = 160 + (i >> 1) - (i << 2);
}
if (GetRandomControl() & 1)
fish->speed -= GetRandomControl() & 1;
else
fish->speed += GetRandomControl() & 1;
if (fish->speed < 32)
fish->speed = 32;
else if (fish->speed > 200)
fish->speed = 200;
fish->swim += (fish->speed >> 4) + (fish->speed >> 5);
fish->swim &= 63;
x = fish->x - fish->speed * SIN(fish->angle << 4) >> W2V_SHIFT; // (((rcossin_tbl[(fish->angle << 1)])* (fish->speed)) >> 13);
z = fish->z + fish->speed * COS(fish->angle << 4) >> W2V_SHIFT; //
if (z < -32000)
z = -32000;
else if (z > 32000)
z = 32000;
if (x < -32000)
x = -32000;
else if (x > 32000)
x = 32000;
fish->x = x;
fish->z = z;
if (pirahnaAttack == 0)
{
if (abs(fish->y - fish->destY) < 16)
fish->destY = GetRandomControl() % LeaderInfo[leader].yRange;
}
else
{
int y = enemy->pos.yPos - item->pos.yPos;
if (abs(fish->y - fish->destY) < 16)
fish->destY = y + (GetRandomControl() & 255);
}
fish->y += (fish->destY - fish->y) >> 4;
fish++;
}
}
bool FishNearLara(PHD_3DPOS* pos, int distance, ITEM_INFO* item)
{
int x = pos->xPos - item->pos.xPos;
int y = abs(pos->yPos - item->pos.yPos);
int z = pos->zPos - item->pos.zPos;
if (x < -distance || x > distance || z < -distance || z > distance || y < -WALL_SIZE * 3 || y > WALL_SIZE * 3)
return false;
if (x * x + z * z > SQUARE(distance))
return false;
if (y > distance)
return false;
return true;
}