TombEngine/TombEngine/Game/control/lot.cpp
TokyoSU 2ba8257468
Enemy firing system refactor (#1069)
* Refactored gunflash.

- Fixed rendering of gunflash.
- Improved gen.bat with some comment.
- Now entity can shoot with 2 weapon (left and right) like lara.

* Fix compiling error

* Move muzzleFlash to creature struct

- Removed BiteInfo and remplaced it by CreatureBiteInfo.
- Fixed Mafia2 and Cybord muzzleflash pos.
- Added dynamic light and smoke when entity shoot. (only for weapon)

* Able to switch GUN_FLASH mesh.

* Improve CreatureEffect/Effect2

Pass bite directly instead.

* Fixed TR5 and TR4 biteInfo

* Finished implementing gunflash for creatures.

- Fix snowmobile gun crash.
- Fix knifethrower not throwing knife.

* Removed traps cpp/h.

* Update Changes.txt

* Update Changes.txt

* Update effects.cpp

* Fixed build error

* Update setup.cpp

- Removed old ObjectObjects() and TrapObjects() and move the code to TR5 objects.

* Fix mpgun gunflash not playing when dead.

* Fixed snowmobile gun not appearing correctly

- Fixed crash if ID_GUN_FLASH2 not exist  and creature like snomobile driver shoot.
- Fix the snowmobile driver AI that where commented (was disabled to test the gunflash).

* Improved AssignObjectAnimations

* Added new lot for snowmobile gun

- Allow the snowmobile to drop from 4 block !

* Fixed savegame crash

* Change what @Lwmte reviewed.

* Added todo for snowmobile gun.

- reverted NO_JOINT in CreatureBiteInfo causing error when compiling.

* Fix compile error caused by the develop merge

* Minor formatting

* Update people.cpp

---------

Co-authored-by: Sezz <sezzary@outlook.com>
Co-authored-by: Kubsy <80340234+Kubsy@users.noreply.github.com>
2023-04-28 16:52:35 +01:00

279 lines
6.8 KiB
C++

#include "framework.h"
#include "Game/control/lot.h"
#include "Game/control/box.h"
#include "Game/camera.h"
#include "Game/itemdata/creature_info.h"
#include "Game/items.h"
#include "Game/misc.h"
#include "Game/Lara/lara.h"
#include "Specific/level.h"
#include "Specific/setup.h"
#define DEFAULT_FLY_UPDOWN_SPEED 16
#define DEFAULT_SWIM_UPDOWN_SPEED 32
int SlotsUsed;
std::vector<CreatureInfo*> ActiveCreatures;
void InitializeLOTarray(int itemNumber)
{
auto* item = &g_Level.Items[itemNumber];
auto* creature = GetCreatureInfo(item);
if (!creature->LOT.Initialized)
{
creature->LOT.Node = std::vector<BoxNode>(g_Level.Boxes.size(), BoxNode{});
creature->LOT.Initialized = true;
}
}
bool EnableEntityAI(short itemNum, bool always, bool makeTarget)
{
ItemInfo* item = &g_Level.Items[itemNum];
if (item->IsCreature())
return true;
InitializeSlot(itemNum, makeTarget);
ActiveCreatures.push_back(item->Data);
return item->IsCreature();
}
void DisableEntityAI(short itemNumber)
{
auto* item = &g_Level.Items[itemNumber];
if (!item->IsCreature())
return;
auto* creature = GetCreatureInfo(item);
creature->ItemNumber = NO_ITEM;
KillItem(creature->AITargetNumber);
ActiveCreatures.erase(std::find(ActiveCreatures.begin(), ActiveCreatures.end(), creature));
item->Data = nullptr;
}
void InitializeSlot(short itemNumber, bool makeTarget)
{
auto* item = &g_Level.Items[itemNumber];
auto* object = &Objects[item->ObjectNumber];
item->Data = CreatureInfo();
auto* creature = GetCreatureInfo(item);
InitializeLOTarray(itemNumber);
creature->ItemNumber = itemNumber;
creature->Mood = MoodType::Bored;
creature->JointRotation[0] = 0;
creature->JointRotation[1] = 0;
creature->JointRotation[2] = 0;
creature->JointRotation[3] = 0;
creature->Alerted = false;
creature->HeadLeft = false;
creature->HeadRight = false;
creature->ReachedGoal = false;
creature->HurtByLara = false;
creature->Patrol = false;
creature->JumpAhead = false;
creature->MonkeySwingAhead = false;
creature->MaxTurn = ANGLE(1);
creature->Flags = 0;
creature->Enemy = nullptr;
creature->LOT.CanJump = false;
creature->LOT.CanMonkey = false;
creature->LOT.IsAmphibious = false; // True for crocodile by default as only the crocodile can move in water and on land.
creature->LOT.IsJumping = false;
creature->LOT.IsMonkeying = false;
creature->LOT.Fly = NO_FLYING;
creature->LOT.BlockMask = BLOCKED;
creature->AITargetNumber = NO_ITEM;
creature->AITarget = nullptr;
if (makeTarget)
{
creature->AITargetNumber = CreateItem();
if (creature->AITargetNumber != NO_ITEM)
creature->AITarget = &g_Level.Items[creature->AITargetNumber];
}
switch (object->LotType)
{
default:
case LotType::Basic:
creature->LOT.Step = CLICK(1);
creature->LOT.Drop = -CLICK(2);
creature->LOT.Zone = ZoneType::Basic;
break;
// Can jump.
case LotType::Skeleton:
creature->LOT.Step = CLICK(1);
creature->LOT.Drop = -CLICK(2);
creature->LOT.CanJump = true;
creature->LOT.Zone = ZoneType::Skeleton;
break;
// Can fly.
case LotType::Flyer:
creature->LOT.Step = SECTOR(20);
creature->LOT.Drop = -SECTOR(20);
creature->LOT.Fly = DEFAULT_FLY_UPDOWN_SPEED;
creature->LOT.Zone = ZoneType::Flyer;
break;
// Can swim.
case LotType::Water:
creature->LOT.Step = SECTOR(20);
creature->LOT.Drop = -SECTOR(20);
creature->LOT.Zone = ZoneType::Water;
if (item->ObjectNumber == ID_CROCODILE)
{
creature->LOT.Fly = DEFAULT_SWIM_UPDOWN_SPEED / 2; // Slower than the other underwater creatures.
creature->LOT.IsAmphibious = true; // Can walk and swim.
}
else if (item->ObjectNumber == ID_BIG_RAT)
{
creature->LOT.Fly = NO_FLYING; // Can't swim underwater, only on the surface.
creature->LOT.IsAmphibious = true; // Can walk and swim.
}
else
{
creature->LOT.Fly = DEFAULT_SWIM_UPDOWN_SPEED;
}
break;
case LotType::SnowmobileGun:
creature->LOT.Step = CLICK(1);
creature->LOT.Drop = -BLOCK(1);
creature->LOT.Zone = ZoneType::Human;
break;
// Can climb.
case LotType::Human:
creature->LOT.Step = BLOCK(1);
creature->LOT.Drop = -BLOCK(1);
creature->LOT.Zone = ZoneType::Human;
break;
// Can climb and jump.
case LotType::HumanPlusJump:
creature->LOT.Step = BLOCK(1);
creature->LOT.Drop = -BLOCK(1);
creature->LOT.CanJump = true;
creature->LOT.Zone = ZoneType::Human;
break;
// Can climb, jump, monkeyswing.
case LotType::HumanPlusJumpAndMonkey:
creature->LOT.Step = BLOCK(1);
creature->LOT.Drop = -BLOCK(1);
creature->LOT.CanJump = true;
creature->LOT.CanMonkey = true;
creature->LOT.Zone = ZoneType::Human;
break;
case LotType::Spider:
creature->LOT.Step = CLICK(2);
creature->LOT.Drop = -BLOCK(1);
creature->LOT.Zone = ZoneType::Human;
break;
case LotType::Blockable:
creature->LOT.Step = CLICK(1);
creature->LOT.Drop = -CLICK(2);
creature->LOT.BlockMask = BLOCKABLE;
creature->LOT.Zone = ZoneType::Basic;
break;
case LotType::Ape:
creature->LOT.Step = CLICK(2);
creature->LOT.Drop = -BLOCK(1);
creature->LOT.Zone = ZoneType::Human;
break;
}
ClearLOT(&creature->LOT);
if (itemNumber != Lara.ItemNumber)
CreateZone(item);
SlotsUsed++;
}
void SetEntityTarget(short itemNum, short target)
{
auto* item = &g_Level.Items[itemNum];
auto* creature = GetCreatureInfo(item);
creature->AITargetNumber = target;
if (creature->AITargetNumber != NO_ITEM)
creature->AITarget = &g_Level.Items[creature->AITargetNumber];
else
creature->AITarget = nullptr;
}
void ClearLOT(LOTInfo* LOT)
{
LOT->Head = NO_BOX;
LOT->Tail = NO_BOX;
LOT->SearchNumber = 0;
LOT->TargetBox = NO_BOX;
LOT->RequiredBox = NO_BOX;
auto* node = LOT->Node.data();
for(auto& node : LOT->Node)
{
node.exitBox = NO_BOX;
node.nextExpansion = NO_BOX;
node.searchNumber = 0;
}
}
void CreateZone(ItemInfo* item)
{
auto* creature = GetCreatureInfo(item);
auto* room = &g_Level.Rooms[item->RoomNumber];
item->BoxNumber = GetSector(room, item->Pose.Position.x - room->x, item->Pose.Position.z - room->z)->Box;
if (creature->LOT.Fly)
{
auto* node = creature->LOT.Node.data();
creature->LOT.ZoneCount = 0;
for (size_t i = 0; i < g_Level.Boxes.size(); i++)
{
node->boxNumber = i;
node++;
creature->LOT.ZoneCount++;
}
}
else
{
int* zone = g_Level.Zones[(int)creature->LOT.Zone][0].data();
int* flippedZone = g_Level.Zones[(int)creature->LOT.Zone][1].data();
int zoneNumber = zone[item->BoxNumber];
int flippedZoneNumber = flippedZone[item->BoxNumber];
auto* node = creature->LOT.Node.data();
creature->LOT.ZoneCount = 0;
for (size_t i = 0; i < g_Level.Boxes.size(); i++)
{
if (*zone == zoneNumber || *flippedZone == flippedZoneNumber)
{
node->boxNumber = i;
node++;
creature->LOT.ZoneCount++;
}
zone++;
flippedZone++;
}
}
}