mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-12 08:04:09 +02:00
#13 activation triggers for doors & switches
This commit is contained in:
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
@@ -225,7 +225,8 @@ struct Camera : Controller {
|
||||
|
||||
pos = pos.lerp(destPos, min(1.0f, Core::deltaTime * 2.0f));
|
||||
|
||||
FloorInfo info = getFloorInfo((int)pos.x, (int)pos.z);
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(room, (int)pos.x, (int)pos.z, info);
|
||||
|
||||
if (info.roomNext != 255)
|
||||
room = info.roomNext;
|
||||
|
301
src/controller.h
301
src/controller.h
@@ -26,7 +26,7 @@ struct Controller {
|
||||
WALK = 1 << 6,
|
||||
ACTION = 1 << 7,
|
||||
WEAPON = 1 << 8,
|
||||
DEATH = 1 << 11 };
|
||||
DEATH = 1 << 9 };
|
||||
|
||||
float animTime;
|
||||
int animIndex;
|
||||
@@ -41,12 +41,20 @@ struct Controller {
|
||||
|
||||
float turnTime;
|
||||
|
||||
Controller(TR::Level *level, int entity) : level(level), entity(entity), velocity(0.0f), animTime(0.0f), animPrevFrame(0), health(100), turnTime(0.0f) {
|
||||
struct Action {
|
||||
TR::Action action;
|
||||
int value;
|
||||
|
||||
Action(TR::Action action, int value) : action(action), value(value) {}
|
||||
} nextAction;
|
||||
|
||||
Controller(TR::Level *level, int entity) : level(level), entity(entity), velocity(0.0f), animTime(0.0f), animPrevFrame(0), health(100), turnTime(0.0f), nextAction(TR::Action::NONE, 0) {
|
||||
TR::Entity &e = getEntity();
|
||||
pos = vec3((float)e.x, (float)e.y, (float)e.z);
|
||||
angle = vec3(0.0f, e.rotation / 16384.0f * PI * 0.5f, 0.0f);
|
||||
stand = STAND_GROUND;
|
||||
animIndex = getModel().animation;
|
||||
state = level->anims[animIndex].state;
|
||||
}
|
||||
|
||||
void updateEntity() {
|
||||
@@ -90,29 +98,6 @@ struct Controller {
|
||||
return getEntity().room;
|
||||
}
|
||||
|
||||
TR::Room::Sector& getSector(int roomIndex, int x, int z, int &dx, int &dz) const {
|
||||
ASSERT(roomIndex >= 0 && roomIndex < level->roomsCount);
|
||||
TR::Room &room = level->rooms[roomIndex];
|
||||
|
||||
int sx = x - room.info.x;
|
||||
int sz = z - room.info.z;
|
||||
|
||||
sx = clamp(sx, 0, (room.xSectors - 1) << 10);
|
||||
sz = clamp(sz, 0, (room.zSectors - 1) << 10);
|
||||
|
||||
dx = sx & 1023; // mod 1024
|
||||
dz = sz & 1023;
|
||||
sx >>= 10; // div 1024
|
||||
sz >>= 10;
|
||||
|
||||
return room.sectors[sx * room.zSectors + sz];
|
||||
}
|
||||
|
||||
TR::Room::Sector& getSector(int &dx, int &dz) const {
|
||||
TR::Entity &entity = getEntity();
|
||||
return getSector(entity.room, entity.x, entity.z, dx, dz);
|
||||
}
|
||||
|
||||
int setAnimation(int index, int frame = -1) {
|
||||
animIndex = index;
|
||||
TR::Animation &anim = level->anims[animIndex];
|
||||
@@ -150,7 +135,7 @@ struct Controller {
|
||||
|
||||
int getOverlap(int fromX, int fromY, int fromZ, int toX, int toZ, int &delta) const {
|
||||
int dx, dz;
|
||||
TR::Room::Sector &s = getSector(getEntity().room, fromX, fromZ, dx, dz);
|
||||
TR::Room::Sector &s = level->getSector(getEntity().room, fromX, fromZ, dx, dz);
|
||||
|
||||
if (s.boxIndex == 0xFFFF) return NO_OVERLAP;
|
||||
|
||||
@@ -179,108 +164,9 @@ struct Controller {
|
||||
return floor;
|
||||
}
|
||||
|
||||
struct FloorInfo {
|
||||
int floor, ceiling;
|
||||
int roomNext, roomBelow, roomAbove;
|
||||
int floorIndex;
|
||||
};
|
||||
|
||||
FloorInfo getFloorInfo(int x, int z) {
|
||||
return getFloorInfo(getRoomIndex(), x, z);
|
||||
}
|
||||
|
||||
FloorInfo getFloorInfo(int roomIndex, int x, int z) {
|
||||
int dx, dz;
|
||||
TR::Room::Sector &s = getSector(roomIndex, x, z, dx, dz);
|
||||
|
||||
FloorInfo info;
|
||||
info.floor = 256 * (int)s.floor;
|
||||
info.ceiling = 256 * (int)s.ceiling;
|
||||
info.roomNext = 255;
|
||||
info.roomBelow = s.roomBelow;
|
||||
info.roomAbove = s.roomAbove;
|
||||
info.floorIndex = s.floorIndex;
|
||||
|
||||
if (!s.floorIndex) return info;
|
||||
|
||||
TR::FloorData *fd = &level->floors[s.floorIndex];
|
||||
TR::FloorData::Command cmd;
|
||||
|
||||
do {
|
||||
cmd = (*fd++).cmd;
|
||||
|
||||
switch (cmd.func) {
|
||||
|
||||
case TR::FD_PORTAL :
|
||||
info.roomNext = (*fd++).data;
|
||||
break;
|
||||
|
||||
case TR::FD_FLOOR : // floor & ceiling
|
||||
case TR::FD_CEILING : {
|
||||
TR::FloorData::Slant slant = (*fd++).slant;
|
||||
int sx = (int)slant.x;
|
||||
int sz = (int)slant.z;
|
||||
if (cmd.func == TR::FD_FLOOR) {
|
||||
info.floor -= sx * (sx > 0 ? (dx - 1024) : dx) >> 2;
|
||||
info.floor -= sz * (sz > 0 ? (dz - 1024) : dz) >> 2;
|
||||
} else {
|
||||
info.ceiling -= sx * (sx < 0 ? (dx - 1024) : dx) >> 2;
|
||||
info.ceiling += sz * (sz > 0 ? (dz - 1024) : dz) >> 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TR::FD_TRIGGER : {
|
||||
TR::FloorData::TriggerInfo info = (*fd++).triggerInfo;
|
||||
TR::FloorData::TriggerCommand trigCmd;
|
||||
do {
|
||||
trigCmd = (*fd++).triggerCmd; // trigger action
|
||||
switch (trigCmd.func) {
|
||||
case 0 :
|
||||
/*
|
||||
if (getEntity().id == 0 && cmd.sub == 2) {
|
||||
TR::Entity &e = level->entities[trigCmd.args];
|
||||
for (int i = 0; i < level->modelsCount; i++)
|
||||
if (e.id == level->models[i].id) {
|
||||
TR::Animation *anim = &level->anims[level->models[i].animation];
|
||||
for (int j = 0; j < anim->scCount; j++)
|
||||
LOG("state: %d\n", anim->state);
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
break; // activate item
|
||||
case 1 : break; // switch to camera
|
||||
case 2 : break; // camera delay
|
||||
case 3 : break; // flip map
|
||||
case 4 : break; // flip on
|
||||
case 5 : break; // flip off
|
||||
case 6 : break; // look at item
|
||||
case 7 : break; // end level
|
||||
case 8 : break; // play soundtrack
|
||||
case 9 : break; // special hadrdcode trigger
|
||||
case 10 : break; // secret found
|
||||
case 11 : break; // clear bodies
|
||||
case 12 : break; // flyby camera sequence
|
||||
case 13 : break; // play cutscene
|
||||
}
|
||||
// ..
|
||||
} while (!trigCmd.end);
|
||||
break;
|
||||
}
|
||||
|
||||
case TR::FD_KILL :
|
||||
health = 0;
|
||||
break;
|
||||
|
||||
default : LOG("unknown func: %d\n", cmd.func);
|
||||
}
|
||||
|
||||
} while (!cmd.end);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void playSound(int id) const {
|
||||
// LOG("play sound %d\n", id);
|
||||
|
||||
int16 a = level->soundsMap[id];
|
||||
TR::SoundInfo &b = level->soundsInfo[a];
|
||||
if (b.chance == 0 || (rand() & 0x7fff) <= b.chance) {
|
||||
@@ -314,7 +200,8 @@ struct Controller {
|
||||
void collide() {
|
||||
TR::Entity &entity = getEntity();
|
||||
|
||||
FloorInfo info = getFloorInfo(entity.x, entity.z);
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(entity.room, entity.x, entity.z, info);
|
||||
|
||||
if (info.roomNext != 0xFF)
|
||||
entity.room = info.roomNext;
|
||||
@@ -345,6 +232,16 @@ struct Controller {
|
||||
}
|
||||
}
|
||||
|
||||
void activateNext() { // activate next entity (for triggers)
|
||||
if (nextAction.action == TR::Action::NONE) return;
|
||||
|
||||
Controller *controller = (Controller*)level->entities[nextAction.value].controller;
|
||||
nextAction.action = TR::Action::NONE;
|
||||
if (controller)
|
||||
controller->activate();
|
||||
}
|
||||
|
||||
virtual void activate() {}
|
||||
virtual void updateVelocity() {}
|
||||
virtual void move() {}
|
||||
virtual Stand getStand() { return STAND_AIR; }
|
||||
@@ -381,93 +278,97 @@ struct Controller {
|
||||
}
|
||||
|
||||
virtual void updateBegin() {
|
||||
animTime += Core::deltaTime;
|
||||
mask = getInputMask();
|
||||
state = getState(stand = getStand());
|
||||
}
|
||||
|
||||
virtual void updateEnd() {
|
||||
int frameIndex = int(animTime * 30.0f);
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
bool endFrame = frameIndex > anim->frameEnd - anim->frameStart;
|
||||
|
||||
// apply animation commands
|
||||
int16 *ptr = &level->commands[anim->animCommand];
|
||||
|
||||
for (int i = 0; i < anim->acCount; i++) {
|
||||
int cmd = *ptr++;
|
||||
switch (cmd) {
|
||||
case TR::ANIM_CMD_MOVE : { // cmd position
|
||||
int16 sx = *ptr++;
|
||||
int16 sy = *ptr++;
|
||||
int16 sz = *ptr++;
|
||||
if (endFrame) {
|
||||
pos = pos + vec3(sx, sy, sz).rotateY(angle.y);
|
||||
updateEntity();
|
||||
LOG("move: %d %d %d\n", (int)sx, (int)sy, (int)sz);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TR::ANIM_CMD_SPEED : { // cmd jump speed
|
||||
int16 sy = *ptr++;
|
||||
int16 sz = *ptr++;
|
||||
if (endFrame) {
|
||||
LOG("jump: %d %d\n", (int)sy, (int)sz);
|
||||
velocity.x = sinf(angleExt) * sz;
|
||||
velocity.y = sy;
|
||||
velocity.z = cosf(angleExt) * sz;
|
||||
stand = STAND_AIR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TR::ANIM_CMD_EMPTY : // empty hands
|
||||
break;
|
||||
case TR::ANIM_CMD_KILL : // kill
|
||||
break;
|
||||
case TR::ANIM_CMD_SOUND : { // play sound
|
||||
int frame = (*ptr++);
|
||||
int id = (*ptr++) & 0x3FFF;
|
||||
int idx = frame - anim->frameStart;
|
||||
|
||||
if (idx > animPrevFrame && idx <= frameIndex) {
|
||||
playSound(id);
|
||||
// LOG("play sound %d\n", getEntity().id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TR::ANIM_CMD_SPECIAL : // special commands
|
||||
if (frameIndex != animPrevFrame && frameIndex + anim->frameStart == ptr[0]) {
|
||||
switch (ptr[1]) {
|
||||
case TR::ANIM_CMD_SPECIAL_FLIP : angle.y = angle.y + PI; break;
|
||||
case TR::ANIM_CMD_SPECIAL_BUBBLE : /* playSound(TR::SND_BUBBLE); */ break;
|
||||
case TR::ANIM_CMD_SPECIAL_CTRL : LOG("water out ?\n"); break;
|
||||
default : LOG("unknown special cmd %d\n", (int)ptr[1]);
|
||||
}
|
||||
}
|
||||
ptr += 2;
|
||||
break;
|
||||
default :
|
||||
LOG("unknown animation command %d\n", cmd);
|
||||
}
|
||||
}
|
||||
|
||||
if (endFrame) // if animation is end - switch to next
|
||||
setAnimation(anim->nextAnimation, anim->nextFrame);
|
||||
else
|
||||
animPrevFrame = frameIndex;
|
||||
|
||||
updateVelocity();
|
||||
move();
|
||||
collide();
|
||||
|
||||
updateEntity();
|
||||
}
|
||||
|
||||
virtual void updateState() {}
|
||||
|
||||
virtual void updateAnimation(bool commands) {
|
||||
int frameIndex = int((animTime += Core::deltaTime) * 30.0f);
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
bool endFrame = frameIndex > anim->frameEnd - anim->frameStart;
|
||||
|
||||
// apply animation commands
|
||||
if (commands) {
|
||||
int16 *ptr = &level->commands[anim->animCommand];
|
||||
|
||||
for (int i = 0; i < anim->acCount; i++) {
|
||||
int cmd = *ptr++;
|
||||
switch (cmd) {
|
||||
case TR::ANIM_CMD_MOVE : { // cmd position
|
||||
int16 sx = *ptr++;
|
||||
int16 sy = *ptr++;
|
||||
int16 sz = *ptr++;
|
||||
if (endFrame) {
|
||||
pos = pos + vec3(sx, sy, sz).rotateY(angle.y);
|
||||
updateEntity();
|
||||
LOG("move: %d %d %d\n", (int)sx, (int)sy, (int)sz);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TR::ANIM_CMD_SPEED : { // cmd jump speed
|
||||
int16 sy = *ptr++;
|
||||
int16 sz = *ptr++;
|
||||
if (endFrame) {
|
||||
LOG("jump: %d %d\n", (int)sy, (int)sz);
|
||||
velocity.x = sinf(angleExt) * sz;
|
||||
velocity.y = sy;
|
||||
velocity.z = cosf(angleExt) * sz;
|
||||
stand = STAND_AIR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TR::ANIM_CMD_EMPTY : // empty hands
|
||||
break;
|
||||
case TR::ANIM_CMD_KILL : // kill
|
||||
break;
|
||||
case TR::ANIM_CMD_SOUND : { // play sound
|
||||
int frame = (*ptr++);
|
||||
int id = (*ptr++) & 0x3FFF;
|
||||
int idx = frame - anim->frameStart;
|
||||
|
||||
if (idx > animPrevFrame && idx <= frameIndex) {
|
||||
if (getEntity().id != ENTITY_ENEMY_BAT) // temporary mute the bat
|
||||
playSound(id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TR::ANIM_CMD_SPECIAL : // special commands
|
||||
if (frameIndex != animPrevFrame && frameIndex + anim->frameStart == ptr[0]) {
|
||||
switch (ptr[1]) {
|
||||
case TR::ANIM_CMD_SPECIAL_FLIP : angle.y = angle.y + PI; break;
|
||||
case TR::ANIM_CMD_SPECIAL_BUBBLE : /* playSound(TR::SND_BUBBLE); */ break;
|
||||
case TR::ANIM_CMD_SPECIAL_CTRL : LOG("water out ?\n"); break;
|
||||
default : LOG("unknown special cmd %d\n", (int)ptr[1]);
|
||||
}
|
||||
}
|
||||
ptr += 2;
|
||||
break;
|
||||
default :
|
||||
LOG("unknown animation command %d\n", cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (endFrame) { // if animation is end - switch to next
|
||||
setAnimation(anim->nextAnimation, anim->nextFrame);
|
||||
activateNext();
|
||||
} else
|
||||
animPrevFrame = frameIndex;
|
||||
}
|
||||
|
||||
virtual void update() {
|
||||
updateBegin();
|
||||
updateState();
|
||||
updateAnimation(true);
|
||||
updateVelocity();
|
||||
updateEnd();
|
||||
}
|
||||
};
|
||||
|
27
src/debug.h
27
src/debug.h
@@ -340,7 +340,7 @@ namespace Debug {
|
||||
|
||||
bool current = (int)p.x == x && (int)p.z == z;
|
||||
debugFloor(level, f, c, s.floorIndex, s.boxIndex, current);
|
||||
|
||||
/*
|
||||
if (current && s.boxIndex != 0xFFFF && level.boxes[s.boxIndex].overlap != 0xFFFF) {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glColor4f(0.0f, 1.0f, 0.0f, 0.25f);
|
||||
@@ -349,6 +349,7 @@ namespace Debug {
|
||||
debugOverlaps(level, s.boxIndex);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,6 +395,16 @@ namespace Debug {
|
||||
Core::setBlending(bmAlpha);
|
||||
}
|
||||
|
||||
void entities(const TR::Level &level) {
|
||||
for (int i = 0; i < level.entitiesCount; i++) {
|
||||
TR::Entity &e = level.entities[i];
|
||||
|
||||
char buf[255];
|
||||
sprintf(buf, "%d", (int)e.id);
|
||||
Debug::Draw::text(vec3(e.x, e.y, e.z), vec4(0.8, 0.0, 0.0, 1), buf);
|
||||
}
|
||||
}
|
||||
|
||||
void lights(const TR::Level &level) {
|
||||
// int roomIndex = level.entities[lara->entity].room;
|
||||
// int lightIndex = getLightIndex(lara->pos, roomIndex);
|
||||
@@ -471,7 +482,7 @@ namespace Debug {
|
||||
int fSize = sizeof(TR::AnimFrame) + m.mCount * sizeof(uint16) * 2;
|
||||
|
||||
TR::Animation *anim = controller ? &level.anims[controller->animIndex] : &level.anims[m.animation];
|
||||
TR::AnimFrame *frame = (TR::AnimFrame*)&level.frameData[anim->frameOffset + (controller ? int((controller->animTime * 30.0f / anim->frameRate)) * fSize : 0) >> 1];
|
||||
TR::AnimFrame *frame = (TR::AnimFrame*)&level.frameData[(anim->frameOffset + (controller ? int((controller->animTime * 30.0f / anim->frameRate)) * fSize : 0) >> 1)];
|
||||
|
||||
//mat4 m;
|
||||
//m.identity();
|
||||
@@ -528,6 +539,18 @@ namespace Debug {
|
||||
}
|
||||
}
|
||||
|
||||
void info(const TR::Level &level, const TR::Entity &entity) {
|
||||
char buf[255];
|
||||
sprintf(buf, "DIP = %d, TRI = %d", Core::stats.dips, Core::stats.tris);
|
||||
Debug::Draw::text(vec2(16, 16), vec4(1.0f), buf);
|
||||
sprintf(buf, "pos = (%d, %d, %d), room = %d", entity.x, entity.y, entity.z, entity.room);
|
||||
Debug::Draw::text(vec2(16, 32), vec4(1.0f), buf);
|
||||
|
||||
TR::Level::FloorInfo info;
|
||||
level.getFloorInfo(entity.room, entity.x, entity.z, info);
|
||||
sprintf(buf, "floor = %d, roomBelow = %d, roomAbove = %d, height = %d", info.floorIndex, info.roomBelow, info.roomAbove, info.floor - info.ceiling);
|
||||
Debug::Draw::text(vec2(16, 48), vec4(1.0f), buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
202
src/format.h
202
src/format.h
@@ -39,14 +39,46 @@ namespace TR {
|
||||
SND_BUBBLE = 37,
|
||||
};
|
||||
|
||||
enum {
|
||||
TRIGGER_ACTIVATE = 0,
|
||||
TRIGGER_PAD = 1,
|
||||
TRIGGER_SWITCH = 2,
|
||||
TRIGGER_KEY = 3,
|
||||
TRIGGER_PICKUP = 4,
|
||||
TRIGGER_HEAVY = 5,
|
||||
TRIGGER_ANTIPAD = 6,
|
||||
TRIGGER_COMBAT = 7,
|
||||
TRIGGER_DUMMY = 8,
|
||||
TRIGGER_ANTI = 9
|
||||
};
|
||||
|
||||
enum Action {
|
||||
NONE = -1, // no action
|
||||
ACTIVATE = 0, // activate item
|
||||
CAMERA_SWITCH = 1, // switch to camera
|
||||
CAMERA_DELAY = 2, // camera delay
|
||||
FLIP_MAP = 3, // flip map
|
||||
FLIP_ON = 4, // flip on
|
||||
FLIP_OFF = 5, // flip off
|
||||
LOOK_AT = 6, // look at item
|
||||
END = 7, // end level
|
||||
SOUNDTRACK = 8, // play soundtrack
|
||||
HARDCODE = 9, // special hadrdcode trigger
|
||||
SECRET = 10, // secret found
|
||||
CLEAR_BODIES = 11, // clear bodies
|
||||
CAMERA_FLYBY = 12, // flyby camera sequence
|
||||
CUTSCENE = 13, // play cutscene
|
||||
};
|
||||
|
||||
|
||||
#define DATA_PORTAL 0x01
|
||||
#define DATA_FLOOR 0x02
|
||||
#define DATA_CEILING 0x03
|
||||
|
||||
|
||||
#define ENTITY_FLAG_CLEAR 0x0080
|
||||
#define ENTITY_FLAG_VISIBLE 0x0100
|
||||
#define ENTITY_FLAG_MASK 0x3E00
|
||||
#define ENTITY_FLAG_ACTIVE 0x3E00
|
||||
|
||||
|
||||
#define ENTITY_LARA 0
|
||||
#define ENTITY_LARA_CUT 77
|
||||
@@ -71,25 +103,41 @@ namespace TR {
|
||||
#define ENTITY_ENEMY_MUMMY 24
|
||||
#define ENTITY_ENEMY_LARSON 27
|
||||
|
||||
#define ENTITY_CRYSTAL 83
|
||||
#define ENTITY_BLADE 36
|
||||
|
||||
#define ENTITY_MEDIKIT_SMALL 93
|
||||
#define ENTITY_MEDIKIT_BIG 94
|
||||
#define ENTITY_CRYSTAL 83
|
||||
|
||||
#define ENTITY_VIEW_TARGET 169
|
||||
#define ENTITY_MEDIKIT_SMALL 93
|
||||
#define ENTITY_MEDIKIT_BIG 94
|
||||
|
||||
#define ENTITY_TRAP_FLOOR 35
|
||||
#define ENTITY_TRAP_SPIKES 37
|
||||
#define ENTITY_TRAP_STONE 38
|
||||
#define ENTITY_TRAP_DART 40
|
||||
#define ENTITY_TRAP_FLOOR 35
|
||||
#define ENTITY_TRAP_SPIKES 37
|
||||
#define ENTITY_TRAP_STONE 38
|
||||
#define ENTITY_TRAP_DART 40
|
||||
|
||||
#define ENTITY_SWITCH 55
|
||||
#define ENTITY_SWITCH 55
|
||||
#define ENTITY_SWITCH_WATER 56
|
||||
|
||||
#define ENTITY_GUN_SHOTGUN 85
|
||||
#define ENTITY_DOOR_1 57
|
||||
#define ENTITY_DOOR_2 58
|
||||
#define ENTITY_DOOR_3 59
|
||||
#define ENTITY_DOOR_4 60
|
||||
#define ENTITY_DOOR_BIG_1 61
|
||||
#define ENTITY_DOOR_BIG_2 62
|
||||
#define ENTITY_DOOR_5 63
|
||||
#define ENTITY_DOOR_6 64
|
||||
#define ENTITY_DOOR_FLOOR_1 65
|
||||
#define ENTITY_DOOR_FLOOR_2 66
|
||||
|
||||
#define ENTITY_AMMO_UZI 91
|
||||
#define ENTITY_AMMO_SHOTGUN 89
|
||||
#define ENTITY_AMMO_MAGNUM 90
|
||||
#define ENTITY_GUN_SHOTGUN 85
|
||||
|
||||
#define ENTITY_AMMO_UZI 91
|
||||
#define ENTITY_AMMO_SHOTGUN 89
|
||||
#define ENTITY_AMMO_MAGNUM 90
|
||||
|
||||
#define ENTITY_HOLE_PUZZLE 118
|
||||
#define ENTITY_HOLE_KEY 137
|
||||
#define ENTITY_VIEW_TARGET 169
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
@@ -306,8 +354,8 @@ namespace TR {
|
||||
};
|
||||
|
||||
struct AnimFrame {
|
||||
MinMax box;
|
||||
TR::Vertex pos; // Starting offset for this model
|
||||
MinMax box;
|
||||
Vertex pos; // Starting offset for this model
|
||||
int16 aCount;
|
||||
uint16 angles[0]; // angle frames in YXZ order
|
||||
|
||||
@@ -579,7 +627,7 @@ namespace TR {
|
||||
// lights
|
||||
r.lights = new Room::Light[stream.read(r.lightsCount)];
|
||||
for (int i = 0; i < r.lightsCount; i++) {
|
||||
TR::Room::Light &light = r.lights[i];
|
||||
Room::Light &light = r.lights[i];
|
||||
stream.read(light.x);
|
||||
stream.read(light.y);
|
||||
stream.read(light.z);
|
||||
@@ -711,13 +759,127 @@ namespace TR {
|
||||
delete[] soundOffsets;
|
||||
}
|
||||
|
||||
TR::StaticMesh* getMeshByID(int id) const { // TODO: map this
|
||||
// common methods
|
||||
|
||||
StaticMesh* getMeshByID(int id) const { // TODO: map this
|
||||
for (int i = 0; i < staticMeshesCount; i++)
|
||||
if (staticMeshes[i].id == id)
|
||||
return &staticMeshes[i];
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
struct FloorInfo {
|
||||
int floor, ceiling;
|
||||
int roomNext, roomBelow, roomAbove;
|
||||
int floorIndex;
|
||||
bool kill;
|
||||
int trigger;
|
||||
FloorData::TriggerInfo trigInfo;
|
||||
FloorData::TriggerCommand trigCmd[16];
|
||||
int trigCmdCount;
|
||||
};
|
||||
|
||||
Room::Sector& getSector(int roomIndex, int x, int z, int &dx, int &dz) const {
|
||||
ASSERT(roomIndex >= 0 && roomIndex < roomsCount);
|
||||
Room &room = rooms[roomIndex];
|
||||
|
||||
int sx = x - room.info.x;
|
||||
int sz = z - room.info.z;
|
||||
|
||||
sx = clamp(sx, 0, (room.xSectors - 1) * 1024);
|
||||
sz = clamp(sz, 0, (room.zSectors - 1) * 1024);
|
||||
|
||||
dx = sx % 1024;
|
||||
dz = sz % 1024;
|
||||
sx /= 1024;
|
||||
sz /= 1024;
|
||||
|
||||
return room.sectors[sx * room.zSectors + sz];
|
||||
}
|
||||
|
||||
void getFloorInfo(int roomIndex, int x, int z, FloorInfo &info) const {
|
||||
int dx, dz;
|
||||
Room::Sector &s = getSector(roomIndex, x, z, dx, dz);
|
||||
|
||||
info.floor = 256 * (int)s.floor;
|
||||
info.ceiling = 256 * (int)s.ceiling;
|
||||
info.roomNext = 255;
|
||||
info.roomBelow = s.roomBelow;
|
||||
info.roomAbove = s.roomAbove;
|
||||
info.floorIndex = s.floorIndex;
|
||||
info.kill = false;
|
||||
info.trigger = -1;
|
||||
info.trigCmdCount = 0;
|
||||
|
||||
if (!s.floorIndex) return;
|
||||
|
||||
FloorData *fd = &floors[s.floorIndex];
|
||||
FloorData::Command cmd;
|
||||
|
||||
do {
|
||||
cmd = (*fd++).cmd;
|
||||
|
||||
switch (cmd.func) {
|
||||
|
||||
case FD_PORTAL :
|
||||
info.roomNext = (*fd++).data;
|
||||
break;
|
||||
|
||||
case FD_FLOOR : // floor & ceiling
|
||||
case FD_CEILING : {
|
||||
FloorData::Slant slant = (*fd++).slant;
|
||||
int sx = (int)slant.x;
|
||||
int sz = (int)slant.z;
|
||||
if (cmd.func == FD_FLOOR) {
|
||||
info.floor -= sx * (sx > 0 ? (dx - 1024) : dx) >> 2;
|
||||
info.floor -= sz * (sz > 0 ? (dz - 1024) : dz) >> 2;
|
||||
} else {
|
||||
info.ceiling -= sx * (sx < 0 ? (dx - 1024) : dx) >> 2;
|
||||
info.ceiling += sz * (sz > 0 ? (dz - 1024) : dz) >> 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FD_TRIGGER : {
|
||||
info.trigger = cmd.sub;
|
||||
info.trigCmdCount = 0;
|
||||
info.trigInfo = (*fd++).triggerInfo;
|
||||
FloorData::TriggerCommand trigCmd;
|
||||
do {
|
||||
trigCmd = (*fd++).triggerCmd; // trigger action
|
||||
info.trigCmd[info.trigCmdCount++] = trigCmd;
|
||||
switch (trigCmd.func) {
|
||||
case 0 : break; // activate item
|
||||
case 1 : break; // switch to camera
|
||||
case 2 : break; // camera delay
|
||||
case 3 : break; // flip map
|
||||
case 4 : break; // flip on
|
||||
case 5 : break; // flip off
|
||||
case 6 : break; // look at item
|
||||
case 7 : break; // end level
|
||||
case 8 : break; // play soundtrack
|
||||
case 9 : break; // special hadrdcode trigger
|
||||
case 10 : break; // secret found
|
||||
case 11 : break; // clear bodies
|
||||
case 12 : break; // flyby camera sequence
|
||||
case 13 : break; // play cutscene
|
||||
}
|
||||
// ..
|
||||
} while (!trigCmd.end);
|
||||
break;
|
||||
}
|
||||
|
||||
case FD_KILL :
|
||||
info.kill = true;
|
||||
break;
|
||||
|
||||
default : LOG("unknown func: %d\n", cmd.func);
|
||||
}
|
||||
|
||||
} while (!cmd.end);
|
||||
}
|
||||
|
||||
}; // struct Level
|
||||
}
|
||||
|
||||
#endif
|
94
src/lara.h
94
src/lara.h
@@ -99,7 +99,7 @@ struct Lara : Controller {
|
||||
// level 2 (pool)
|
||||
pos = vec3(70067, -256, 29104);
|
||||
angle = vec3(0.0f, -0.68f, 0.0f);
|
||||
getEntity().room = 15;
|
||||
getEntity().room = 15;
|
||||
*/
|
||||
/*
|
||||
// level 2 (wolf)
|
||||
@@ -129,8 +129,9 @@ struct Lara : Controller {
|
||||
bool waterOut(int &outState) {
|
||||
vec3 dst = pos + getDir() * 32.0f;
|
||||
|
||||
FloorInfo infoCur = getFloorInfo((int)pos.x, (int)pos.z),
|
||||
infoDst = getFloorInfo(infoCur.roomAbove, (int)dst.x, (int)dst.z);
|
||||
TR::Level::FloorInfo infoCur, infoDst;
|
||||
level->getFloorInfo(getEntity().room, (int)pos.x, (int)pos.z, infoCur),
|
||||
level->getFloorInfo(infoCur.roomAbove, (int)dst.x, (int)dst.z, infoDst);
|
||||
|
||||
if (infoDst.roomBelow == 0xFF && pos.y - infoDst.floor <= 256) { // possibility check
|
||||
if (!setState(STATE_STOP)) { // can't set water out state
|
||||
@@ -151,6 +152,77 @@ struct Lara : Controller {
|
||||
return false;
|
||||
}
|
||||
|
||||
void performTrigger() {
|
||||
TR::Entity &e = getEntity();
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(e.room, e.x, e.z, info);
|
||||
|
||||
if (!info.trigCmdCount) return; // has no trigger
|
||||
bool isActive = (level->entities[info.trigCmd[0].args].flags & ENTITY_FLAG_ACTIVE);
|
||||
if (info.trigInfo.once == 1 && (level->entities[info.trigCmd[0].args].flags & ENTITY_FLAG_ACTIVE)) return; // once trigger is already activated
|
||||
|
||||
int actionState = 0;
|
||||
switch (info.trigger) {
|
||||
case TR::TRIGGER_ACTIVATE :
|
||||
if (isActive) return;
|
||||
actionState = state;
|
||||
break;
|
||||
case TR::TRIGGER_PAD :
|
||||
if (stand != STAND_GROUND || isActive) return;
|
||||
actionState = state;
|
||||
break;
|
||||
case TR::TRIGGER_SWITCH :
|
||||
if (mask & ACTION) {
|
||||
actionState = isActive ? STATE_SWITCH_OFF : STATE_SWITCH_ON;
|
||||
} else
|
||||
return;
|
||||
break;
|
||||
case TR::TRIGGER_KEY :
|
||||
if (isActive) return;
|
||||
if (mask & ACTION)
|
||||
// if (entity.id == ENTITY_PUZZLE_1)
|
||||
// actionState = STATE_USE_PUZZLE;
|
||||
// else
|
||||
actionState = STATE_USE_KEY;
|
||||
else
|
||||
return;
|
||||
break;
|
||||
case TR::TRIGGER_PICKUP :
|
||||
if ((mask & ACTION) && stand == STAND_GROUND)
|
||||
actionState = STATE_PICK_UP;
|
||||
else
|
||||
return;
|
||||
break;
|
||||
default :
|
||||
return;
|
||||
}
|
||||
|
||||
// try to activate Lara state
|
||||
if (!setState(actionState)) return;
|
||||
|
||||
// build trigger activation chain
|
||||
for (int i = 0; i < info.trigCmdCount; i++) {
|
||||
if (info.trigCmd[i].func != TR::Action::ACTIVATE) continue; // TODO: other trigger types
|
||||
Controller *controller = (Controller*)level->entities[info.trigCmd[i].args].controller;
|
||||
if (!controller) {
|
||||
LOG("! next activation entity %d has no controller\n", level->entities[info.trigCmd[i].args].id);
|
||||
playSound(2);
|
||||
return;
|
||||
} else
|
||||
controller->nextAction = (i < info.trigCmdCount - 1) ? Action(TR::Action::ACTIVATE, info.trigCmd[i + 1].args) : Action(TR::Action::NONE, 0);
|
||||
}
|
||||
|
||||
if (info.trigCmd[0].func != TR::Action::ACTIVATE) return; // see above TODO
|
||||
|
||||
// activate first entity in chain
|
||||
Controller *controller = (Controller*)level->entities[info.trigCmd[0].args].controller;
|
||||
if (info.trigger == TR::TRIGGER_KEY) {
|
||||
nextAction = controller->nextAction;
|
||||
controller->nextAction.action = TR::Action::NONE;
|
||||
} else
|
||||
controller->activate();
|
||||
}
|
||||
|
||||
virtual Stand getStand() {
|
||||
if (stand == STAND_ONWATER && state != STATE_DIVE && state != STATE_STOP)
|
||||
return stand;
|
||||
@@ -161,7 +233,8 @@ struct Lara : Controller {
|
||||
int extra = isMovingState(state) ? 256 : 0;
|
||||
|
||||
TR::Entity &e = getEntity();
|
||||
FloorInfo info = getFloorInfo(e.x, e.z);
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(e.room, e.x, e.z, info);
|
||||
if (info.roomBelow == 0xFF && e.y + extra >= info.floor)
|
||||
return STAND_GROUND;
|
||||
|
||||
@@ -235,7 +308,7 @@ struct Lara : Controller {
|
||||
if (mask & FORTH) return STATE_RUN;
|
||||
if (mask & BACK) return STATE_FAST_BACK;
|
||||
if (mask & LEFT) return turnTime < FAST_TURN_TIME ? STATE_TURN_LEFT : STATE_FAST_TURN;
|
||||
if (mask & RIGHT) return turnTime < FAST_TURN_TIME ? STATE_TURN_RIGHT : STATE_FAST_TURN;
|
||||
if (mask & RIGHT) return turnTime < FAST_TURN_TIME ? STATE_TURN_RIGHT : STATE_FAST_TURN;
|
||||
return STATE_STOP;
|
||||
}
|
||||
|
||||
@@ -249,6 +322,7 @@ struct Lara : Controller {
|
||||
}
|
||||
|
||||
if (mask & JUMP) return STATE_SWIM;
|
||||
|
||||
return (state == STATE_SWIM || velocity.y > GLIDE_SPEED) ? STATE_GLIDE : STATE_TREAD;
|
||||
}
|
||||
|
||||
@@ -306,6 +380,8 @@ struct Lara : Controller {
|
||||
}
|
||||
|
||||
virtual void updateState() {
|
||||
performTrigger();
|
||||
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
|
||||
int fCount = anim->frameEnd - anim->frameStart;
|
||||
@@ -340,7 +416,6 @@ struct Lara : Controller {
|
||||
} else
|
||||
lState = false;
|
||||
#endif
|
||||
|
||||
// calculate turn tilt
|
||||
if (state == STATE_RUN && (mask & (LEFT | RIGHT))) {
|
||||
if (mask & LEFT) angle.z -= Core::deltaTime * TURN_TILT;
|
||||
@@ -401,7 +476,7 @@ struct Lara : Controller {
|
||||
case STATE_SURF_RIGHT :
|
||||
angleExt += PI * 0.5f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void updateVelocity() {
|
||||
@@ -467,7 +542,8 @@ struct Lara : Controller {
|
||||
vec3 p = pos;
|
||||
pos = pos + offset;
|
||||
|
||||
FloorInfo info = getFloorInfo((int)pos.x, (int)pos.z);
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(getEntity().room, (int)pos.x, (int)pos.z, info);
|
||||
|
||||
int delta;
|
||||
int d = getOverlap((int)p.x, (int)p.y, (int)p.z, (int)pos.x, (int)pos.z, delta);
|
||||
@@ -518,7 +594,7 @@ struct Lara : Controller {
|
||||
case STAND_ONWATER :
|
||||
break;
|
||||
}
|
||||
} else
|
||||
} else
|
||||
updateEntity();
|
||||
}
|
||||
};
|
||||
|
28
src/level.h
28
src/level.h
@@ -7,6 +7,7 @@
|
||||
#include "lara.h"
|
||||
#include "enemy.h"
|
||||
#include "camera.h"
|
||||
#include "trigger.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include "debug.h"
|
||||
@@ -72,6 +73,25 @@ struct Level {
|
||||
case ENTITY_ENEMY_LARSON :
|
||||
entity.controller = new Enemy(&level, i);
|
||||
break;
|
||||
case ENTITY_DOOR_1 :
|
||||
case ENTITY_DOOR_2 :
|
||||
case ENTITY_DOOR_3 :
|
||||
case ENTITY_DOOR_4 :
|
||||
case ENTITY_DOOR_5 :
|
||||
case ENTITY_DOOR_6 :
|
||||
case ENTITY_DOOR_BIG_1 :
|
||||
case ENTITY_DOOR_BIG_2 :
|
||||
case ENTITY_DOOR_FLOOR_1 :
|
||||
case ENTITY_DOOR_FLOOR_2 :
|
||||
case ENTITY_BLADE :
|
||||
entity.controller = new Trigger(&level, i, true);
|
||||
break;
|
||||
case ENTITY_SWITCH :
|
||||
case ENTITY_SWITCH_WATER :
|
||||
case ENTITY_HOLE_PUZZLE :
|
||||
case ENTITY_HOLE_KEY :
|
||||
entity.controller = new Trigger(&level, i, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,7 +380,7 @@ struct Level {
|
||||
|
||||
if (fIndexB == 0) {
|
||||
nextAnim = &level.anims[anim->nextAnimation];
|
||||
fIndexB = (anim->nextFrame - nextAnim->frameStart) / anim->frameRate;
|
||||
fIndexB = (anim->nextFrame - nextAnim->frameStart) / nextAnim->frameRate;
|
||||
} else
|
||||
nextAnim = anim;
|
||||
|
||||
@@ -553,10 +573,12 @@ struct Level {
|
||||
|
||||
#ifdef _DEBUG
|
||||
Debug::begin();
|
||||
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||
Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||
// Debug::Level::lights(level);
|
||||
// Debug::Level::portals(level);
|
||||
Debug::Level::meshes(level);
|
||||
// Debug::Level::meshes(level);
|
||||
Debug::Level::entities(level);
|
||||
Debug::Level::info(level, lara->getEntity());
|
||||
Debug::end();
|
||||
#endif
|
||||
}
|
||||
|
@@ -19,8 +19,8 @@
|
||||
|
||||
#else
|
||||
#define ASSERT(expr)
|
||||
// #define LOG(...) ((void)0)
|
||||
#define LOG(...) printf(__VA_ARGS__)
|
||||
#define LOG(...) ((void)0)
|
||||
// #define LOG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
|
||||
|
@@ -109,6 +109,7 @@
|
||||
<ClInclude Include="..\shader.h" />
|
||||
<ClInclude Include="..\texture.h" />
|
||||
<ClInclude Include="..\format.h" />
|
||||
<ClInclude Include="..\trigger.h" />
|
||||
<ClInclude Include="..\utils.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
Reference in New Issue
Block a user