#include "lot.h" #include "..\Global\global.h" #include #define DEFAULT_FLY_UPDOWN_SPEED 16 #define DEFAULT_SWIM_UPDOWN_SPEED 32 void InitialiseLOTarray(int allocMem) { 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++) { creature->itemNum = NO_ITEM; creature->LOT.node = (BOX_NODE*)GameMalloc(sizeof(BOX_NODE) * NumberBoxes); } SlotsUsed = 0; } int EnableBaddieAI(short itemNum, int always) { ITEM_INFO* item = &Items[itemNum]; if (item->data != NULL) return true; else if (SlotsUsed >= NUM_SLOTS) { int cameraDistance = 0; 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; cameraDistance = SQUARE(deltaX) + SQUARE(deltaY) + SQUARE(deltaZ); } int slotToDisable = -1; CREATURE_INFO* creature = BaddieSlots; for (int slot = 0; slot < NUM_SLOTS; slot++, creature++) { 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); 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++) { 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) { ITEM_INFO* item = &Items[itemNum]; OBJECT_INFO* obj = &Objects[item->objectNumber]; CREATURE_INFO* creature = &BaddieSlots[slot]; item->data = creature; creature->itemNum = itemNum; creature->mood = BORED_MOOD; 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->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) creature->LOT.isJumping = false; creature->LOT.isMonkeying = false; creature->maximumTurn = ANGLE(1); creature->flags = 0; creature->enemy = NULL; creature->LOT.fly = NO_FLYING; creature->LOT.blockMask = BLOCKED; if (obj->intelligent) { // 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; } 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; } 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++; } } } void Inject_Lot() { INJECT(0x0045B0C0, InitialiseLOTarray); INJECT(0x0045B1A0, EnableBaddieAI); INJECT(0x0045B150, DisableBaddieAI); INJECT(0x0045B740, ClearLOT); INJECT(0x0045B5E0, CreateZone); }