TombEngine/TR5Main/Game/lot.cpp

301 lines
7.4 KiB
C++
Raw Normal View History

2018-08-19 09:46:58 +02:00
#include "lot.h"
#include "..\Global\global.h"
#include <stdio.h>
#define DEFAULT_FLY_UPDOWN_SPEED 16
#define DEFAULT_SWIM_UPDOWN_SPEED 32
void InitialiseLOTarray(int allocMem)
2018-08-19 09:46:58 +02:00
{
DB_Log(0, "InitialiseLOTarray - DLL");
if (allocMem)
BaddieSlots = (CREATURE_INFO*)GameMalloc(sizeof(CREATURE_INFO) * NUM_SLOTS);
CREATURE_INFO* creature = BaddieSlots;
for (int i = 0; i < NUM_SLOTS; i++, creature++)
2018-08-19 09:46:58 +02:00
{
creature->itemNum = NO_ITEM;
creature->LOT.node = (BOX_NODE*)GameMalloc(sizeof(BOX_NODE) * NumberBoxes);
}
SlotsUsed = 0;
}
int EnableBaddieAI(short itemNum, int always)
2018-08-19 09:46:58 +02:00
{
ITEM_INFO* item = &Items[itemNum];
if (item->data != NULL)
return true;
else if (SlotsUsed >= NUM_SLOTS)
{
int cameraDistance = 0;
2018-08-19 09:46:58 +02:00
if (!always)
{
int deltaX = (item->pos.xPos - Camera.pos.x) >> 8;
int deltaY = (item->pos.yPos - Camera.pos.y) >> 8;
int deltaZ = (item->pos.zPos - Camera.pos.z) >> 8;
2018-08-19 09:46:58 +02:00
cameraDistance = SQUARE(deltaX) + SQUARE(deltaY) + SQUARE(deltaZ);
}
int slotToDisable = -1;
2018-08-19 09:46:58 +02:00
CREATURE_INFO* creature = BaddieSlots;
for (int slot = 0; slot < NUM_SLOTS; slot++, creature++)
2018-08-19 09:46:58 +02:00
{
item = &Items[creature->itemNum];
int deltaX = (item->pos.xPos - Camera.pos.x) >> 8;
int deltaY = (item->pos.yPos - Camera.pos.y) >> 8;
int deltaZ = (item->pos.zPos - Camera.pos.z) >> 8;
int distance = SQUARE(deltaX) + SQUARE(deltaY) + SQUARE(deltaZ);
2018-08-19 09:46:58 +02:00
if (distance > cameraDistance)
{
cameraDistance = distance;
slotToDisable = slot;
}
}
if (slotToDisable < 0)
return false;
Items[BaddieSlots[slotToDisable].itemNum].status = ITEM_INVISIBLE;
DisableBaddieAI(BaddieSlots[slotToDisable].itemNum);
InitialiseSlot(itemNum, slotToDisable);
return true;
}
else
{
CREATURE_INFO* creature = BaddieSlots;
for (int slot = 0; slot < NUM_SLOTS; slot++, creature++)
2018-08-19 09:46:58 +02:00
{
if (creature->itemNum == NO_ITEM)
{
InitialiseSlot(itemNum, slot);
return true;
}
}
}
return false;
}
void DisableBaddieAI(short itemNumber)
{
ITEM_INFO* item = &Items[itemNumber];
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
item->data = NULL;
if (creature)
{
creature->itemNum = NO_ITEM;
SlotsUsed--;
}
}
void InitialiseSlot(short itemNum, short slot)
2018-08-19 09:46:58 +02:00
{
ITEM_INFO* item = &Items[itemNum];
OBJECT_INFO* obj = &Objects[item->objectNumber];
CREATURE_INFO* creature = &BaddieSlots[slot];
2018-08-19 09:46:58 +02:00
item->data = creature;
creature->itemNum = itemNum;
creature->mood = BORED_MOOD;
creature->jointRotation[0] = 0;
creature->jointRotation[1] = 0;
2018-08-19 09:46:58 +02:00
creature->jointRotation[2] = 0;
creature->jointRotation[3] = 0;
2018-08-19 09:46:58 +02:00
creature->alerted = false;
creature->headLeft = false;
creature->headRight = false;
creature->reachedGoal = false;
creature->hurtByLara = false;
creature->patrol2 = false;
creature->jumpAhead = false;
creature->monkeyAhead = false;
creature->alerted = false;
creature->LOT.canJump = false;
creature->LOT.canMonkey = false;
creature->LOT.isAmphibious = false; // only land (only crocodile can be amphibious)
2018-08-19 09:46:58 +02:00
creature->LOT.isJumping = false;
creature->LOT.isMonkeying = false;
creature->maximumTurn = ANGLE(1);
2018-08-19 09:46:58 +02:00
creature->flags = 0;
creature->enemy = NULL;
creature->LOT.fly = NO_FLYING;
creature->LOT.blockMask = BLOCKED;
if (obj->intelligent)
2018-08-19 09:46:58 +02:00
{
// simple check to set hitEffect to blood or smoke by default if intelligent enabled and no value assigned to hitEffect !
// undead have smoke instead of blood !
if (!obj->hitEffect)
{
if (obj->undead)
obj->hitEffect = HIT_SMOKE;
else if (!obj->undead && obj->hitPoints)
obj->hitEffect = HIT_BLOOD;
}
// init the basic zone for intelligent creature.
// ignore if the zoneType is specified in the Objects[] already.
if (obj->zoneType == ZONE_NULL)
obj->zoneType = ZONE_BASIC;
2018-08-19 09:46:58 +02:00
}
switch (obj->zoneType)
{
default:
case ZONE_NULL:
break;
case ZONE_SKELLY:
// Can jump
creature->LOT.step = SECTOR(1) - CLICK(3);
creature->LOT.drop = -(SECTOR(1) - CLICK(3));
creature->LOT.canJump = true;
creature->LOT.zone = ZONE_SKELLY;
break;
case ZONE_BASIC:
creature->LOT.step = SECTOR(1) - CLICK(3);
creature->LOT.drop = -(SECTOR(1) - CLICK(3));
creature->LOT.zone = ZONE_BASIC;
break;
case ZONE_FLYER:
// Can fly
creature->LOT.step = SECTOR(20);
creature->LOT.drop = -SECTOR(20);
creature->LOT.fly = DEFAULT_FLY_UPDOWN_SPEED;
creature->LOT.zone = ZONE_FLYER;
break;
case ZONE_WATER:
// Can swim
creature->LOT.step = SECTOR(20);
creature->LOT.drop = -SECTOR(20);
if (item->objectNumber == ID_CROCODILE)
{
creature->LOT.fly = DEFAULT_SWIM_UPDOWN_SPEED / 2; // crocodile is more slower than the other creature when swimming.
creature->LOT.isAmphibious = true; // crocodile can walk and swim.
}
else
{
creature->LOT.fly = DEFAULT_SWIM_UPDOWN_SPEED;
}
creature->LOT.zone = ZONE_WATER;
break;
case ZONE_HUMAN_CLASSIC:
// Can climb
creature->LOT.step = SECTOR(1);
creature->LOT.drop = -SECTOR(1);
creature->LOT.zone = ZONE_HUMAN_CLASSIC;
break;
case ZONE_HUMAN_JUMP:
// Can climb and jump
creature->LOT.step = SECTOR(1);
creature->LOT.drop = -SECTOR(1);
creature->LOT.canJump = true;
creature->LOT.zone = ZONE_HUMAN_CLASSIC;
break;
case ZONE_HUMAN_JUMP_AND_MONKEY:
// Can climb, jump, monkey
creature->LOT.step = SECTOR(1);
creature->LOT.drop = -SECTOR(1);
creature->LOT.canJump = true;
creature->LOT.canMonkey = true;
creature->LOT.zone = ZONE_HUMAN_CLASSIC;
break;
case ZONE_SPIDER:
creature->LOT.step = SECTOR(1) - CLICK(2);
creature->LOT.drop = -(SECTOR(1) - CLICK(2));
creature->LOT.zone = ZONE_HUMAN_CLASSIC;
break;
}
2018-08-19 09:46:58 +02:00
ClearLOT(&creature->LOT);
if (itemNum != Lara.itemNumber)
CreateZone(item);
SlotsUsed++;
}
void ClearLOT(LOT_INFO* LOT)
{
LOT->head = NO_BOX;
LOT->tail = NO_BOX;
LOT->searchNumber = 0;
LOT->targetBox = NO_BOX;
LOT->requiredBox = NO_BOX;
BOX_NODE* node = LOT->node;
for (int i = 0; i < NumberBoxes; i++)
{
node->exitBox = NO_BOX;
node->nextExpansion = NO_BOX;
node->searchNumber = 0;
node++;
}
}
void CreateZone(ITEM_INFO* item)
{
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
ROOM_INFO* r = &Rooms[item->roomNumber];
item->boxNumber = XZ_GET_SECTOR(r, item->pos.xPos - r->x, item->pos.zPos - r->z).box;
if (creature->LOT.fly)
{
BOX_NODE* node = creature->LOT.node;
creature->LOT.zoneCount = 0;
for (int i = 0; i < NumberBoxes; i++)
{
node->boxNumber = i;
node++;
creature->LOT.zoneCount++;
}
}
else
{
short* zone = GroundZones[creature->LOT.zone];
short* flippedZone = GroundZones[creature->LOT.zone + 1];
short zoneNumber = zone[item->boxNumber];
short flippedZoneNumber = flippedZone[item->boxNumber];
BOX_NODE* node = creature->LOT.node;
creature->LOT.zoneCount = 0;
for (int i = 0; i < NumberBoxes; i++)
{
if (*zone == zoneNumber || *flippedZone == flippedZoneNumber)
{
node->boxNumber = i;
node++;
creature->LOT.zoneCount++;
}
zone++;
flippedZone++;
}
}
}
2018-08-19 09:46:58 +02:00
void Inject_Lot()
{
INJECT(0x0045B0C0, InitialiseLOTarray);
INJECT(0x0045B1A0, EnableBaddieAI);
INJECT(0x0045B150, DisableBaddieAI);
INJECT(0x0045B740, ClearLOT);
INJECT(0x0045B5E0, CreateZone);
2018-08-19 09:46:58 +02:00
}