1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-14 00:54:05 +02:00

#22 refactoring

This commit is contained in:
XProger
2017-11-07 09:04:26 +03:00
parent 9abce0d28b
commit 1292a88e4f
8 changed files with 156 additions and 108 deletions

View File

@@ -121,6 +121,7 @@ struct Controller {
vec3 ambient[6];
float specular;
float intensity;
float timer;
@@ -155,6 +156,7 @@ struct Controller {
joints = m ? new Basis[m->mCount] : NULL;
frameIndex = -1;
specular = 0.0f;
intensity = e.intensity == -1 ? -1.0f : intensityf(e.intensity);
timer = 0.0f;
ambient[0] = ambient[1] = ambient[2] = ambient[3] = ambient[4] = ambient[5] = vec3(intensityf(getRoom().ambient));
targetLight = NULL;
@@ -406,35 +408,52 @@ struct Controller {
virtual void getSaveData(SaveData &data) {
const TR::Entity &e = getEntity();
const TR::Model *m = getModel();
// base
data.x = e.x ^ int32(pos.x);
data.y = e.y ^ int32(pos.y);
data.z = e.z ^ int32(pos.z);
data.rotation = e.rotation.value ^ TR::angle(normalizeAngle(angle.y)).value;
data.type = entity >= level->entitiesBaseCount ? int16(e.type) : 0;
data.flags = e.flags.value ^ flags.value;
data.timer = timer == 0.0f ? 0 : (timer < 0.0f ? -1 : int16(timer * 30.0f));
if (entity < level->entitiesBaseCount) {
data.x = e.x ^ int32(pos.x);
data.y = e.y ^ int32(pos.y);
data.z = e.z ^ int32(pos.z);
data.rotation = e.rotation.value ^ TR::angle(normalizeAngle(angle.y)).value;
data.type = 0;
data.room = e.room ^ roomIndex;
} else {
data.x = int32(pos.x);
data.y = int32(pos.y);
data.z = int32(pos.z);
data.rotation = TR::angle(normalizeAngle(angle.y)).value;
data.type = int16(e.type);
data.room = uint8(roomIndex);
}
data.flags = e.flags.value ^ flags.value;
data.timer = timer == 0.0f ? 0 : (timer < 0.0f ? -1 : int16(timer * 30.0f));
// animation
data.animIndex = m ? (m->animation ^ animation.index) : 0;
data.animFrame = m ? animation.frameIndex : 0;
// common
data.room = e.room ^ roomIndex;
data.extraSize = 0;
data.animIndex = m ? (m->animation ^ animation.index) : 0;
data.animFrame = m ? animation.frameIndex : 0;
data.extraSize = 0;
}
virtual void setSaveData(const SaveData &data) {
const TR::Entity &e = getEntity();
const TR::Model *m = getModel();
// base
pos.x = float(e.x ^ data.x);
pos.y = float(e.y ^ data.y);
pos.z = float(e.z ^ data.z);
angle.y = TR::angle(uint16(e.rotation.value ^ data.rotation));
flags.value = e.flags.value ^ data.flags;
timer = data.timer == -1 ? -1.0f : (timer / 30.0f);
if (entity < level->entitiesBaseCount) {
pos.x = float(e.x ^ data.x);
pos.y = float(e.y ^ data.y);
pos.z = float(e.z ^ data.z);
angle.y = TR::angle(uint16(e.rotation.value ^ data.rotation));
roomIndex = e.room ^ data.room;
} else {
pos.x = float(data.x);
pos.y = float(data.y);
pos.z = float(data.z);
angle.y = TR::angle(uint16(data.rotation));
flags.value = data.flags;
roomIndex = data.room;
}
flags.value = e.flags.value ^ data.flags;
timer = data.timer == -1 ? -1.0f : (timer / 30.0f);
// animation
if (m) animation.setAnim(m->animation ^ data.animIndex, -data.animFrame);
roomIndex = e.room ^ data.room;
}
bool isActive() {
@@ -838,10 +857,10 @@ struct Controller {
for (int i = 0; i < model->mCount; i++)
if (explodeMask & (1 << i)) {
ExplodePart &part = explodeParts[i];
part.velocity.y += GRAVITY * Core::deltaTime;
applyGravity(part.velocity.y);
quat q = quat(vec3(1, 0, 0), PI * Core::deltaTime) * quat(vec3(0, 0, 1), PI * 2.0f * Core::deltaTime);
part.basis = Basis(part.basis.rot * q, part.basis.pos + explodeParts[i].velocity * (Core::deltaTime * 30.0f));
part.basis = Basis(part.basis.rot * q, part.basis.pos + part.velocity * (30.0f * Core::deltaTime));
vec3 p = part.basis.pos;
//TR::Room::Sector *s = level->getSector(part.roomIndex, int(p.x), int(p.y), int(p.z));

View File

@@ -656,9 +656,7 @@ namespace Debug {
const char *TR1_TYPE_NAMES[] = { TR1_TYPES(DECL_STR) };
const char *getEntityName(const TR::Level &level, const TR::Entity &entity) {
if (entity.type == TR::Entity::NONE)
return "NONE";
if (entity.type < 0 || entity.type >= COUNT(TR1_TYPE_NAMES))
if (entity.type >= COUNT(TR1_TYPE_NAMES))
return "UNKNOWN";
return TR1_TYPE_NAMES[entity.type];
}

View File

@@ -96,7 +96,7 @@ struct Enemy : Character {
virtual void updateVelocity() {
if (stand == STAND_AIR && (!flying || health <= 0.0f))
velocity.y += GRAVITY * Core::deltaTime;
applyGravity(velocity.y);
else
velocity = getDir() * animation.getSpeed();

View File

@@ -647,7 +647,7 @@ namespace TR {
struct Entity {
enum ActiveState : uint16 { asNone, asActive, asInactive };
enum Type : int16 { NONE = -1, TR1_TYPES(DECL_ENUM) };
enum Type : uint16 { TR1_TYPES(DECL_ENUM) };
Type type;
int16 room;
@@ -760,16 +760,16 @@ namespace TR {
static Type getItemForHole(Type hole) {
switch (hole) {
case PUZZLE_HOLE_1 : return PUZZLE_1; break;
case PUZZLE_HOLE_2 : return PUZZLE_2; break;
case PUZZLE_HOLE_3 : return PUZZLE_3; break;
case PUZZLE_HOLE_4 : return PUZZLE_4; break;
case KEY_HOLE_1 : return KEY_ITEM_1; break;
case KEY_HOLE_2 : return KEY_ITEM_2; break;
case KEY_HOLE_3 : return KEY_ITEM_3; break;
case KEY_HOLE_4 : return KEY_ITEM_4; break;
case MIDAS_HAND : return LEADBAR; break;
default : return NONE;
case PUZZLE_HOLE_1 : return PUZZLE_1;
case PUZZLE_HOLE_2 : return PUZZLE_2;
case PUZZLE_HOLE_3 : return PUZZLE_3;
case PUZZLE_HOLE_4 : return PUZZLE_4;
case KEY_HOLE_1 : return KEY_ITEM_1;
case KEY_HOLE_2 : return KEY_ITEM_2;
case KEY_HOLE_3 : return KEY_ITEM_3;
case KEY_HOLE_4 : return KEY_ITEM_4;
case MIDAS_HAND : return LEADBAR;
default : return LARA;
}
}
@@ -1431,10 +1431,8 @@ namespace TR {
if (e.type == Entity::CUT_1)
cutEntity = i;
}
for (int i = entitiesBaseCount; i < entitiesCount; i++) {
entities[i].type = Entity::NONE;
for (int i = entitiesBaseCount; i < entitiesCount; i++)
entities[i].controller = NULL;
}
if (version == VER_TR1_PC) {
stream.seek(32 * 256);
@@ -2106,9 +2104,9 @@ namespace TR {
}
int entityAdd(Entity::Type type, int16 room, const vec3 &pos, float rotation, int16 intensity) {
for (int i = entitiesBaseCount; i < entitiesCount; i++)
if (entities[i].type == Entity::NONE) {
Entity &e = entities[i];
for (int i = entitiesBaseCount; i < entitiesCount; i++) {
Entity &e = entities[i];
if (!e.controller) {
e.type = type;
e.room = room;
e.x = int(pos.x);
@@ -2118,14 +2116,13 @@ namespace TR {
e.intensity = intensity;
e.flags.value = 0;
e.modelIndex = getModelIndex(e.type);
e.controller = NULL;
return i;
}
}
return -1;
}
void entityRemove(int entityIndex) {
entities[entityIndex].type = Entity::NONE;
entities[entityIndex].controller = NULL;
}

View File

@@ -313,7 +313,7 @@ struct Inventory {
bool chooseKey(TR::Entity::Type hole) {
TR::Entity::Type type = TR::Entity::getItemForHole(hole);
if (type == TR::Entity::NONE)
if (type == TR::Entity::LARA)
return false;
int index = contains(type);
if (index < 0)
@@ -330,7 +330,7 @@ struct Inventory {
return false;
}
bool toggle(Page curPage = PAGE_INVENTORY, TR::Entity::Type type = TR::Entity::NONE) {
bool toggle(Page curPage = PAGE_INVENTORY, TR::Entity::Type type = TR::Entity::LARA) {
if (phaseRing == 0.0f || phaseRing == 1.0f) {
active = !active;
vec3 p;
@@ -346,7 +346,7 @@ struct Inventory {
phaseSelect = 1.0f;
page = targetPage = curPage;
if (type != TR::Entity::NONE) {
if (type != TR::Entity::LARA) {
int i = contains(type);
if (i >= 0)
pageItemIndex[page] = getLocalIndex(i);

View File

@@ -594,7 +594,7 @@ struct Lara : Character {
case Weapon::Type::SHOTGUN : return TR::Entity::SHOTGUN;
case Weapon::Type::MAGNUMS : return TR::Entity::MAGNUMS;
case Weapon::Type::UZIS : return TR::Entity::UZIS;
default : return TR::Entity::NONE;
default : return TR::Entity::LARA;
}
}
@@ -1535,15 +1535,17 @@ struct Lara : Character {
usedKey = item;
break;
case TR::Entity::INV_LEADBAR :
for (int i = 0; i < level->entitiesCount; i++)
if (level->entities[i].type == TR::Entity::MIDAS_HAND) {
MidasHand *controller = (MidasHand*)level->entities[i].controller;
for (int i = 0; i < level->entitiesCount; i++) {
const TR::Entity &e = level->entities[i];
if (e.controller && e.type == TR::Entity::MIDAS_HAND) {
MidasHand *controller = (MidasHand*)e.controller;
if (controller->interaction) {
controller->invItem = item;
return false; // remove item from inventory
}
return true;
}
}
return false;
default : return false;
}
@@ -1596,11 +1598,10 @@ struct Lara : Character {
for (int i = 0; i < level->entitiesCount; i++) {
TR::Entity &entity = level->entities[i];
if (!entity.isPickup())
if (!entity.controller || !entity.isPickup())
continue;
Controller *controller = (Controller*)entity.controller;
if (!controller) continue;
if (controller->getRoomIndex() != room || controller->flags.invisible || !canPickup(controller))
continue;
@@ -1786,10 +1787,10 @@ struct Lara : Character {
return;
limit = actionState == STATE_USE_PUZZLE ? &TR::Limits::PUZZLE_HOLE : &TR::Limits::KEY_HOLE;
if (!checkInteraction(controller, limit, isPressed(ACTION) || usedKey != TR::Entity::NONE))
if (!checkInteraction(controller, limit, isPressed(ACTION) || usedKey != TR::Entity::LARA))
return;
if (usedKey == TR::Entity::NONE) {
if (usedKey == TR::Entity::LARA) {
if (isPressed(ACTION) && !game->invChooseKey(entity.type))
game->playSound(TR::SND_NO, pos, Sound::PAN); // no compatible items in inventory
return;
@@ -2135,7 +2136,7 @@ struct Lara : Character {
Block* getBlock() {
for (int i = 0; i < level->entitiesCount; i++) {
TR::Entity &e = level->entities[i];
if (!e.isBlock())
if (!e.controller || !e.isBlock())
continue;
Block *block = (Block*)e.controller;
@@ -2547,7 +2548,7 @@ struct Lara : Character {
if (oxygen < LARA_MAX_OXYGEN)
oxygen = min(LARA_MAX_OXYGEN, oxygen += Core::deltaTime * 10.0f);
usedKey = TR::Entity::NONE;
usedKey = TR::Entity::LARA;
}
virtual void updateAnimation(bool commands) {
@@ -2747,8 +2748,8 @@ struct Lara : Character {
// check enemies & doors
for (int i = 0; i < level->entitiesCount; i++) {
const TR::Entity &e = level->entities[i];
if (!e.isCollider()) continue;
if (!e.controller || !e.isCollider()) continue;
Controller *controller = (Controller*)e.controller;

View File

@@ -90,23 +90,34 @@ struct Level : IGame {
char *data;
stream.read(data, stream.size);
char *ptr = data;
int32 eCount = *((int32*)ptr);
ptr += 4;
Controller::first = NULL;
for (int i = level.entitiesBaseCount; i < level.entitiesCount; i++) {
for (int i = 0; i < level.entitiesCount; i++) {
TR::Entity &e = level.entities[i];
if (e.controller) {
delete (Controller*)e.controller;
e.controller = NULL;
Controller *controller = (Controller*)e.controller;
if (controller) {
controller->next = NULL;
controller->flags.state = TR::Entity::asNone;
if (i >= level.entitiesBaseCount) {
delete controller;
e.controller = NULL;
}
}
}
for (int i = 0; i < level.entitiesBaseCount; i++) {
ASSERT(int(ptr - data) < stream.size);
Controller *controller = (Controller*)level.entities[i].controller;
ASSERT(controller);
for (int i = 0; i < eCount; i++) {
Controller::SaveData *saveData = (Controller::SaveData*)ptr;
Controller *controller;
if (i >= level.entitiesBaseCount)
controller = addEntity(TR::Entity::Type(saveData->type), saveData->room, vec3(float(saveData->x), float(saveData->y), float(saveData->z)), TR::angle(saveData->rotation));
else
controller = (Controller*)level.entities[i].controller;
controller->setSaveData(*saveData);
if (controller->flags.state != TR::Entity::asNone) {
if (Controller::first != controller && controller->flags.state != TR::Entity::asNone) {
controller->next = Controller::first;
Controller::first = controller;
}
@@ -119,15 +130,19 @@ struct Level : IGame {
}
virtual void saveGame(int slot) {
char *data = new char[sizeof(Controller::SaveData) * level.entitiesBaseCount];
char *ptr = data;
char *data = new char[4 + sizeof(Controller::SaveData) * level.entitiesCount];
char *ptr = data;
int32 *eCount = (int32*)ptr;
ptr += 4;
for (int i = 0; i < level.entitiesBaseCount; i++) {
Controller::SaveData *saveData = (Controller::SaveData*)ptr;
*eCount = 0;
for (int i = 0; i < level.entitiesCount; i++) {
Controller *controller = (Controller*)level.entities[i].controller;
ASSERT(controller);
if (!controller || (controller->getEntity().isSprite() && !controller->getEntity().isPickup())) continue;
Controller::SaveData *saveData = (Controller::SaveData*)ptr;
controller->getSaveData(*saveData);
ptr += (sizeof(Controller::SaveData) - sizeof(Controller::SaveData::Extra)) + saveData->extraSize;
(*eCount)++;
}
Stream::write("savegame.dat", data, int(ptr - data));
delete[] data;
@@ -307,14 +322,6 @@ struct Level : IGame {
int index = level.entityAdd(type, room, pos, angle, -1);
if (index > -1) {
TR::Entity &e = level.entities[index];
Controller *controller = initController(index);
e.controller = controller;
if (e.isEnemy() || e.isSprite()) {
controller->flags.active = TR::ACTIVE;
controller->activate();
}
if (e.isPickup())
e.intensity = 4096;
else
@@ -324,7 +331,15 @@ struct Level : IGame {
else
e.intensity = 0x1FFF - level.rooms[room].ambient;
}
Controller *controller = initController(index);
e.controller = controller;
if (e.isEnemy() || e.isSprite()) {
controller->flags.active = TR::ACTIVE;
controller->activate();
}
return controller;
}
return NULL;
@@ -936,7 +951,7 @@ struct Level : IGame {
void renderEntity(const TR::Entity &entity) {
//if (entity.room != lara->getRoomIndex()) return;
if (entity.type == TR::Entity::NONE || !entity.modelIndex) return;
if (!entity.controller || !entity.modelIndex) return;
if (Core::pass == Core::passShadow && !entity.castShadow()) return;
ASSERT(entity.controller);
@@ -952,7 +967,7 @@ struct Level : IGame {
if (!room.flags.visible || controller->flags.invisible || controller->flags.rendered)
return;
int16 lum = entity.intensity == -1 ? room.ambient : entity.intensity;
float intensity = controller->intensity < 0.0f ? intensityf(room.ambient) : controller->intensity;
Shader::Type type = isModel ? Shader::ENTITY : Shader::SPRITE;
if (entity.type == TR::Entity::CRYSTAL)
@@ -961,9 +976,9 @@ struct Level : IGame {
if (type == Shader::SPRITE) {
float alpha = (entity.type == TR::Entity::SMOKE || entity.type == TR::Entity::WATER_SPLASH || entity.type == TR::Entity::SPARKLES) ? 0.75f : 1.0f;
float diffuse = entity.isPickup() ? 1.0f : 0.5f;
setRoomParams(roomIndex, type, diffuse, intensityf(lum), controller->specular, alpha, isModel ? !mesh->models[entity.modelIndex - 1].opaque : true);
setRoomParams(roomIndex, type, diffuse, intensity, controller->specular, alpha, isModel ? !mesh->models[entity.modelIndex - 1].opaque : true);
} else
setRoomParams(roomIndex, type, 1.0f, intensityf(lum), controller->specular, 1.0f, isModel ? !mesh->models[entity.modelIndex - 1].opaque : true);
setRoomParams(roomIndex, type, 1.0f, intensity, controller->specular, 1.0f, isModel ? !mesh->models[entity.modelIndex - 1].opaque : true);
if (isModel) { // model
vec3 pos = controller->getPos();

View File

@@ -206,7 +206,7 @@ struct TrapFlameEmitter : Controller {
#define LAVA_EMITTER_RANGE (1024 * 10)
struct LavaParticle : Sprite {
int bounces;
int bounces;
LavaParticle(IGame *game, int entity) : Sprite(game, entity, false, Sprite::FRAME_RANDOM), bounces(0) {
float speed = randf() * LAVA_H_SPEED;
@@ -235,7 +235,7 @@ struct LavaParticle : Sprite {
delete this;
return;
}
// getEntity().intensity = bounces * 2048 - 1; // TODO: updateEntity()
intensity = max(0.0f, 1.0f - bounces * 0.25f);
if (pos.y > info.floor) pos.y = info.floor;
if (pos.y < info.ceiling) pos.y = info.ceiling;
@@ -246,9 +246,7 @@ struct LavaParticle : Sprite {
};
struct TrapLavaEmitter : Controller {
float timer;
TrapLavaEmitter(IGame *game, int entity) : Controller(game, entity), timer(0.0f) {}
TrapLavaEmitter(IGame *game, int entity) : Controller(game, entity) {}
void virtual update() {
vec3 d = (game->getLara()->pos - pos).abs();
@@ -412,8 +410,9 @@ struct Block : Controller {
if (info.roomBelow != TR::NO_ROOM)
roomIndex = info.roomBelow;
velocity += Core::deltaTime * GRAVITY;
pos.y += Core::deltaTime * velocity * 30.0f;
applyGravity(velocity);
pos.y += velocity * (30.0f * Core::deltaTime);
if (pos.y >= info.floor) {
velocity = 0.0f;
pos.y = info.floor;
@@ -448,6 +447,13 @@ struct MovingBlock : Controller {
updateFloor(true);
}
virtual void setSaveData(const SaveData &data) {
updateFloor(false);
Controller::setSaveData(data);
if (flags.state == TR::Entity::asNone)
updateFloor(true);
}
void updateFloor(bool rise) {
TR::Level::FloorInfo info;
getFloorInfo(getRoomIndex(), pos, info);
@@ -614,9 +620,10 @@ struct TrapFloor : Controller {
STATE_FALL,
STATE_DOWN,
};
float speed;
TrapFloor(IGame *game, int entity) : Controller(game, entity), speed(0) {
float velocity;
TrapFloor(IGame *game, int entity) : Controller(game, entity), velocity(0) {
flags.collision = true;
}
@@ -634,8 +641,9 @@ struct TrapFloor : Controller {
updateAnimation(true);
if (state == STATE_FALL) {
flags.collision = false;
speed += GRAVITY * 30 * Core::deltaTime;
pos.y += speed * Core::deltaTime;
applyGravity(velocity);
pos.y += velocity * (30.0f * Core::deltaTime);
TR::Level::FloorInfo info;
getFloorInfo(getRoomIndex(), pos, info);
@@ -771,9 +779,9 @@ struct TrapCeiling : Controller {
STATE_DOWN,
};
float speed;
float velocity;
TrapCeiling(IGame *game, int entity) : Controller(game, entity), speed(0) {}
TrapCeiling(IGame *game, int entity) : Controller(game, entity), velocity(0) {}
virtual void update() {
updateAnimation(true);
@@ -782,8 +790,8 @@ struct TrapCeiling : Controller {
animation.setState(STATE_FALL);
if (state == STATE_FALL) {
speed += GRAVITY * 30 * Core::deltaTime;
pos.y += speed * Core::deltaTime;
applyGravity(velocity);
pos.y += velocity * (30.0f * Core::deltaTime);
TR::Level::FloorInfo info;
getFloorInfo(getRoomIndex(), pos, info);
@@ -1079,7 +1087,7 @@ struct MidasHand : Controller {
TR::Entity::Type invItem;
bool interaction;
MidasHand(IGame *game, int entity) : Controller(game, entity), invItem(TR::Entity::NONE), interaction(false) {
MidasHand(IGame *game, int entity) : Controller(game, entity), invItem(TR::Entity::LARA), interaction(false) {
activate();
}
@@ -1100,7 +1108,7 @@ struct MidasHand : Controller {
interaction = (d.x < 700.0f && d.z < 700.0f) && lara->state == 2; // 2 = Lara::STATE_STOP
if (interaction) {
if (invItem != TR::Entity::NONE) {
if (invItem != TR::Entity::LARA) {
if (invItem == TR::Entity::INV_LEADBAR) {
lara->angle.y = PI * 0.5f;
lara->pos.x = pos.x - 612.0f;
@@ -1108,7 +1116,7 @@ struct MidasHand : Controller {
game->invAdd(TR::Entity::PUZZLE_1);
} else
game->playSound(TR::SND_NO, pos, Sound::PAN); // uncompatible item
invItem = TR::Entity::NONE;
invItem = TR::Entity::LARA;
} else if (Input::state[cAction] && !game->invChooseKey(getEntity().type)) // TODO: add callback for useItem
game->playSound(TR::SND_NO, pos, Sound::PAN); // no compatible items in inventory
}
@@ -1289,12 +1297,22 @@ struct KeyHole : Controller {
virtual bool activate() {
if (!Controller::activate()) return false;
flags.active = TR::ACTIVE;
swap();
deactivate();
return true;
}
virtual void setSaveData(const SaveData &data) {
Controller::setSaveData(data);
if (flags.active == TR::ACTIVE)
swap();
}
void swap() {
if (getEntity().isPuzzleHole()) {
int doneIdx = TR::Entity::convToInv(TR::Entity::getItemForHole(getEntity().type)) - TR::Entity::INV_PUZZLE_1;
meshSwap(0, level->extra.puzzleDone[doneIdx]);
}
deactivate();
return true;
}
virtual void update() {}