mirror of
https://github.com/XProger/OpenLara.git
synced 2025-01-17 21:09:00 +01:00
This commit is contained in:
parent
36fce871cb
commit
ba5ffaf977
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
@ -57,8 +57,10 @@ struct Camera : Controller {
|
||||
|
||||
virtual void update() {
|
||||
int lookAt = -1;
|
||||
if (owner->target > -1) lookAt = owner->target;
|
||||
if (actTargetEntity > -1) lookAt = actTargetEntity;
|
||||
if (owner->target > -1) lookAt = owner->target;
|
||||
|
||||
owner->viewTarget = lookAt;
|
||||
|
||||
if (timer > 0.0f) {
|
||||
timer -= Core::deltaTime;
|
||||
|
@ -52,7 +52,9 @@ struct Controller {
|
||||
meshes[i] = model->mStart + i;
|
||||
}
|
||||
|
||||
void meshSwap(TR::Model *model, int mask) {
|
||||
void meshSwap(TR::Model *model, int mask = 0xFFFFFFFF) {
|
||||
if (!meshes) initMeshOverrides();
|
||||
|
||||
for (int i = 0; i < model->mCount; i++) {
|
||||
int index = model->mStart + i;
|
||||
if (((1 << i) & mask) && level->meshOffsets[index])
|
||||
|
14
src/format.h
14
src/format.h
@ -9,6 +9,10 @@
|
||||
|
||||
namespace TR {
|
||||
|
||||
enum {
|
||||
FLOOR_BLOCK = -127,
|
||||
};
|
||||
|
||||
enum {
|
||||
ANIM_CMD_NONE ,
|
||||
ANIM_CMD_OFFSET ,
|
||||
@ -387,6 +391,7 @@ namespace TR {
|
||||
PUZZLE_4 = 113, // sprite
|
||||
|
||||
HOLE_PUZZLE = 118,
|
||||
HOLE_PUZZLE_SET = 122,
|
||||
|
||||
PICKUP = 126, // sprite
|
||||
|
||||
@ -766,6 +771,7 @@ namespace TR {
|
||||
|
||||
struct {
|
||||
Model *muzzleFlash;
|
||||
Model *puzzleSet;
|
||||
} extra;
|
||||
|
||||
Level(const char *name, bool demo) {
|
||||
@ -899,7 +905,8 @@ namespace TR {
|
||||
memset(&extra, 0, sizeof(extra));
|
||||
for (int i = 0; i < modelsCount; i++)
|
||||
switch (models[i].type) {
|
||||
case Entity::MUZZLE_FLASH : extra.muzzleFlash = &models[i]; break;
|
||||
case Entity::MUZZLE_FLASH : extra.muzzleFlash = &models[i]; break;
|
||||
case Entity::HOLE_PUZZLE_SET : extra.puzzleSet = &models[i]; break;
|
||||
default : ;
|
||||
}
|
||||
}
|
||||
@ -1032,6 +1039,9 @@ namespace TR {
|
||||
info.trigger = Trigger::ACTIVATE;
|
||||
info.trigCmdCount = 0;
|
||||
|
||||
if (s.floor == -127)
|
||||
return;
|
||||
|
||||
Room::Sector *sBelow = &s;
|
||||
while (sBelow->roomBelow != 0xFF) sBelow = &getSector(sBelow->roomBelow, x, z, dx, dz);
|
||||
info.floor = 256 * sBelow->floor;
|
||||
@ -1072,7 +1082,7 @@ namespace TR {
|
||||
if (ey >= y - 128 && ey < info.floor)
|
||||
info.floor = ey;
|
||||
if (ey < y - 128 && ey > info.ceiling)
|
||||
info.ceiling = ey + (e.type == Entity::TRAP_FLOOR ? 256 : 0);
|
||||
info.ceiling = ey + (e.type == Entity::TRAP_FLOOR ? 0 : 256);
|
||||
break;
|
||||
}
|
||||
|
||||
|
65
src/lara.h
65
src/lara.h
@ -24,6 +24,7 @@
|
||||
|
||||
#define PICKUP_FRAME_GROUND 40
|
||||
#define PICKUP_FRAME_UNDERWATER 16
|
||||
#define PUZZLE_FRAME 80
|
||||
|
||||
#define MAX_TRIGGER_ACTIONS 64
|
||||
|
||||
@ -193,8 +194,9 @@ struct Lara : Character {
|
||||
|
||||
Inventory inventory;
|
||||
int lastPickUp;
|
||||
int viewTarget;
|
||||
|
||||
Lara(TR::Level *level, int entity, bool home) : Character(level, entity, 1000), home(home), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos) {
|
||||
Lara(TR::Level *level, int entity, bool home) : Character(level, entity, 1000), home(home), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos), viewTarget(-1) {
|
||||
animation.setAnim(ANIM_STAND);
|
||||
getEntity().flags.active = 1;
|
||||
initMeshOverrides();
|
||||
@ -264,12 +266,12 @@ struct Lara : Character {
|
||||
pos = vec3(31390, -2048, 33472);
|
||||
angle = vec3(0.0f, 0.0f, 0.0f);
|
||||
getEntity().room = 63;
|
||||
|
||||
*/
|
||||
// level 2 (trap door)
|
||||
pos = vec3(21987, -1024, 29144);
|
||||
angle = vec3(0.0f, PI * 3.0f * 0.5f, 0.0f);
|
||||
getEntity().room = 61;
|
||||
|
||||
/*
|
||||
// level 3a
|
||||
pos = vec3(41015, 3584, 34494);
|
||||
angle = vec3(0.0f, -PI, 0.0f);
|
||||
@ -376,6 +378,15 @@ struct Lara : Character {
|
||||
return wpnCurrent == Weapon::EMPTY || arms[0].anim == Weapon::Anim::NONE;
|
||||
}
|
||||
|
||||
bool canLookAt() {
|
||||
return (stand == STAND_GROUND || stand == STAND_SLIDE)
|
||||
&& state != STATE_REACH
|
||||
&& state != STATE_PUSH_BLOCK
|
||||
&& state != STATE_PULL_BLOCK
|
||||
&& state != STATE_PUSH_PULL_READY
|
||||
&& state != STATE_PICK_UP;
|
||||
}
|
||||
|
||||
bool canDrawWeapon() {
|
||||
return wpnCurrent != Weapon::EMPTY
|
||||
&& emptyHands()
|
||||
@ -713,7 +724,8 @@ struct Lara : Character {
|
||||
} else
|
||||
animation.overrideMask &= ~(BODY_ARM_R | BODY_ARM_L);
|
||||
|
||||
lookAt(target);
|
||||
|
||||
lookAt(viewTarget);
|
||||
|
||||
if (wpnCurrent == Weapon::SHOTGUN)
|
||||
aimShotgun();
|
||||
@ -725,15 +737,16 @@ struct Lara : Character {
|
||||
float speed = 8.0f * Core::deltaTime;
|
||||
quat rot;
|
||||
|
||||
bool can = canLookAt();
|
||||
// chest
|
||||
if ((stand == STAND_GROUND || stand == STAND_SLIDE) && aim(target, 7, vec4(-PI * 0.4f, PI * 0.4f, -PI * 0.9f, PI * 0.9f), rot))
|
||||
if (can && aim(target, 7, vec4(-PI * 0.4f, PI * 0.4f, -PI * 0.9f, PI * 0.9f), rot))
|
||||
rotChest = rotChest.slerp(quat(0, 0, 0, 1).slerp(rot, 0.5f), speed);
|
||||
else
|
||||
rotChest = rotChest.slerp(quat(0, 0, 0, 1), speed);
|
||||
animation.overrides[7] = rotChest * animation.overrides[7];
|
||||
|
||||
// head
|
||||
if (aim(target, 14, vec4(-PI * 0.25f, PI * 0.25f, -PI * 0.5f, PI * 0.5f), rot))
|
||||
if (can && aim(target, 14, vec4(-PI * 0.25f, PI * 0.25f, -PI * 0.5f, PI * 0.5f), rot))
|
||||
rotHead = rotHead.slerp(rot, speed);
|
||||
else
|
||||
rotHead = rotHead.slerp(quat(0, 0, 0, 1), speed);
|
||||
@ -941,15 +954,21 @@ struct Lara : Character {
|
||||
return;
|
||||
break;
|
||||
case TR::Level::Trigger::KEY :
|
||||
actionState = STATE_USE_KEY;
|
||||
if (level->entities[info.trigCmd[0].args].flags.active)
|
||||
return;
|
||||
actionState = level->entities[info.trigCmd[0].args].type == TR::Entity::HOLE_KEY ? STATE_USE_KEY : STATE_USE_PUZZLE;
|
||||
if (isActive || !isPressed(ACTION) || state == actionState || !emptyHands()) // TODO: STATE_USE_PUZZLE
|
||||
return;
|
||||
if (!checkAngle(level->entities[info.trigCmd[0].args].rotation))
|
||||
return;
|
||||
if (animation.canSetState(actionState) && !useItem(TR::Entity::NONE, level->entities[info.trigCmd[0].args].type)) {
|
||||
playSound(TR::SND_NO, pos, Sound::PAN);
|
||||
if (animation.canSetState(actionState)) {
|
||||
if (false) { //!useItem(TR::Entity::NONE, level->entities[info.trigCmd[0].args].type)) {
|
||||
playSound(TR::SND_NO, pos, Sound::PAN);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
return;
|
||||
}
|
||||
lastPickUp = info.trigCmd[0].args; // TODO: it's not pickup, it's key/puzzle hole
|
||||
break;
|
||||
case TR::Level::Trigger::PICKUP :
|
||||
if (!isActive) // check if item is not picked up
|
||||
@ -964,6 +983,9 @@ struct Lara : Character {
|
||||
if (!animation.setState(actionState)) return;
|
||||
|
||||
if (info.trigger == TR::Level::Trigger::SWITCH || info.trigger == TR::Level::Trigger::KEY) {
|
||||
if (info.trigger == TR::Level::Trigger::KEY)
|
||||
level->entities[info.trigCmd[0].args].flags.active = true;
|
||||
|
||||
TR::Entity &p = level->entities[info.trigCmd[0].args];
|
||||
angle.y = p.rotation;
|
||||
angle.x = 0;
|
||||
@ -1370,14 +1392,23 @@ struct Lara : Character {
|
||||
}
|
||||
|
||||
virtual void doCustomCommand(int curFrame, int prevFrame) {
|
||||
if (state == STATE_PICK_UP) {
|
||||
TR::Entity &item = level->entities[lastPickUp];
|
||||
if (!item.flags.invisible) {
|
||||
int pickupFrame = stand == STAND_GROUND ? PICKUP_FRAME_GROUND : PICKUP_FRAME_UNDERWATER;
|
||||
if (animation.isFrameActive(pickupFrame)) {
|
||||
item.flags.invisible = true;
|
||||
inventory.add(item.type, 1);
|
||||
switch (state) {
|
||||
case STATE_PICK_UP : {
|
||||
TR::Entity &item = level->entities[lastPickUp];
|
||||
if (!item.flags.invisible) {
|
||||
int pickupFrame = stand == STAND_GROUND ? PICKUP_FRAME_GROUND : PICKUP_FRAME_UNDERWATER;
|
||||
if (animation.isFrameActive(pickupFrame)) {
|
||||
item.flags.invisible = true;
|
||||
inventory.add(item.type, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_USE_PUZZLE : {
|
||||
TR::Entity &item = level->entities[lastPickUp];
|
||||
if (animation.isFrameActive(PUZZLE_FRAME))
|
||||
((Controller*)item.controller)->meshSwap(level->extra.puzzleSet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -385,7 +385,7 @@ struct Level {
|
||||
}
|
||||
|
||||
void renderEntity(const TR::Entity &entity) {
|
||||
// if (entity.room != lara->getRoomIndex()) return;
|
||||
//if (entity.room != lara->getRoomIndex()) return;
|
||||
if (entity.type == TR::Entity::NONE) return;
|
||||
ASSERT(entity.controller);
|
||||
|
||||
@ -495,7 +495,7 @@ struct Level {
|
||||
// Debug::Level::portals(level);
|
||||
// Debug::Level::meshes(level);
|
||||
Debug::Level::entities(level);
|
||||
// Debug::Level::info(level, lara->getEntity(), lara->animation);
|
||||
Debug::Level::info(level, lara->getEntity(), lara->animation);
|
||||
Debug::end();
|
||||
#endif
|
||||
}
|
||||
|
15
src/sound.h
15
src/sound.h
@ -196,10 +196,9 @@ namespace Sound {
|
||||
OGG(Stream *stream, int channels) : Decoder(stream, channels), size(stream->size), pos(0) {
|
||||
buffer = new char[size]; // TODO: file streaming
|
||||
stream->raw(buffer, size);
|
||||
int error;
|
||||
alloc.alloc_buffer_length_in_bytes = 256 * 1024;
|
||||
alloc.alloc_buffer = new char[alloc.alloc_buffer_length_in_bytes];
|
||||
ogg = stb_vorbis_open_memory((unsigned char*)buffer, size, &error, &alloc);
|
||||
ogg = stb_vorbis_open_memory((unsigned char*)buffer, size, NULL, &alloc);
|
||||
stb_vorbis_info info = stb_vorbis_get_info(ogg);
|
||||
channels = info.channels;
|
||||
}
|
||||
@ -220,7 +219,10 @@ namespace Sound {
|
||||
return i;
|
||||
}
|
||||
|
||||
// TODO: replay
|
||||
virtual void replay() {
|
||||
stb_vorbis_close(ogg);
|
||||
ogg = stb_vorbis_open_memory((unsigned char*)buffer, size, NULL, &alloc);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -321,8 +323,11 @@ namespace Sound {
|
||||
while (i < count) {
|
||||
int res = decoder->decode(&frames[i], count - i);
|
||||
if (res == 0) {
|
||||
if (i == 0) isPlaying = false;
|
||||
break;
|
||||
if (!(flags & Flags::LOOP)) {
|
||||
if (i == 0) isPlaying = false;
|
||||
break;
|
||||
} else
|
||||
decoder->replay();
|
||||
}
|
||||
i += res;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ struct Trigger : Controller {
|
||||
}
|
||||
}
|
||||
|
||||
if (!inState())
|
||||
if (!inState() && entity.type != TR::Entity::HOLE_KEY && entity.type != TR::Entity::HOLE_PUZZLE)
|
||||
animation.setState(state != baseState ? baseState : (entity.type == TR::Entity::TRAP_BLADE ? 2 : (baseState ^ 1)));
|
||||
|
||||
updateAnimation(true);
|
||||
@ -179,8 +179,45 @@ struct Block : Controller {
|
||||
|
||||
|
||||
struct Door : Trigger {
|
||||
int8 *floor[2], orig[2];
|
||||
|
||||
Door(TR::Level *level, int entity) : Trigger(level, entity, true) {}
|
||||
Door(TR::Level *level, int entity) : Trigger(level, entity, true) {
|
||||
TR::Entity &e = getEntity();
|
||||
TR::Level::FloorInfo info;
|
||||
vec3 p = pos - getDir() * 1024.0f;
|
||||
|
||||
level->getFloorInfo(e.room, (int)p.x, (int)p.y, (int)p.z, info);
|
||||
int dx, dz;
|
||||
TR::Room::Sector *s = &level->getSector(e.room, (int)p.x, (int)p.z, dx, dz);
|
||||
|
||||
orig[0] = *(floor[0] = &s->floor);
|
||||
|
||||
if (info.roomNext != 0xFF) {
|
||||
s = &level->getSector(info.roomNext, e.x, e.z, dx, dz);
|
||||
orig[1] = *(floor[1] = &s->floor);
|
||||
} else
|
||||
floor[1] = NULL;
|
||||
|
||||
updateBlock();
|
||||
}
|
||||
|
||||
void updateBlock() {
|
||||
int8 v[2];
|
||||
if (getEntity().flags.active) {
|
||||
v[0] = orig[0];
|
||||
v[1] = orig[1];
|
||||
} else
|
||||
v[0] = v[1] = TR::FLOOR_BLOCK;
|
||||
|
||||
if (floor[0]) *floor[0] = v[0];
|
||||
if (floor[1]) *floor[1] = v[1];
|
||||
}
|
||||
|
||||
virtual bool activate(ActionCommand *cmd) {
|
||||
bool res = Trigger::activate(cmd);
|
||||
updateBlock();
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
struct DoorFloor : Trigger {
|
||||
@ -235,7 +272,7 @@ struct TrapFloor : Trigger {
|
||||
e.room = info.roomBelow;
|
||||
|
||||
if (pos.y > info.floor) {
|
||||
pos.y = info.floor;
|
||||
pos.y = (float)info.floor;
|
||||
animation.setState(STATE_DOWN);
|
||||
}
|
||||
updateEntity();
|
||||
|
Loading…
x
Reference in New Issue
Block a user