From 1292a88e4f3f33b37b4c998d2105974dbeb447ad Mon Sep 17 00:00:00 2001 From: XProger Date: Tue, 7 Nov 2017 09:04:26 +0300 Subject: [PATCH] #22 refactoring --- src/controller.h | 65 +++++++++++++++++++++++++++++---------------- src/debug.h | 4 +-- src/enemy.h | 2 +- src/format.h | 35 +++++++++++------------- src/inventory.h | 6 ++--- src/lara.h | 25 +++++++++--------- src/level.h | 69 +++++++++++++++++++++++++++++------------------- src/trigger.h | 58 ++++++++++++++++++++++++++-------------- 8 files changed, 156 insertions(+), 108 deletions(-) diff --git a/src/controller.h b/src/controller.h index f565aba..241f830 100644 --- a/src/controller.h +++ b/src/controller.h @@ -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)); diff --git a/src/debug.h b/src/debug.h index 5ac3132..42698ad 100644 --- a/src/debug.h +++ b/src/debug.h @@ -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]; } diff --git a/src/enemy.h b/src/enemy.h index a30f8da..61eaeec 100644 --- a/src/enemy.h +++ b/src/enemy.h @@ -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(); diff --git a/src/format.h b/src/format.h index 28d5e0f..d70ea6c 100644 --- a/src/format.h +++ b/src/format.h @@ -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; } diff --git a/src/inventory.h b/src/inventory.h index b1601ef..f70422f 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -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); diff --git a/src/lara.h b/src/lara.h index b830616..badb208 100644 --- a/src/lara.h +++ b/src/lara.h @@ -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; diff --git a/src/level.h b/src/level.h index 8387af1..5025dc5 100644 --- a/src/level.h +++ b/src/level.h @@ -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(); diff --git a/src/trigger.h b/src/trigger.h index 327ce5e..906d448 100644 --- a/src/trigger.h +++ b/src/trigger.h @@ -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() {}