diff --git a/src/camera.h b/src/camera.h index d647a2c..dabcc34 100644 --- a/src/camera.h +++ b/src/camera.h @@ -148,7 +148,7 @@ struct Camera : ICamera { virtual void doCutscene(const vec3 &pos, float rotation) { state = Camera::STATE_CUTSCENE; level->cutMatrix.identity(); - level->cutMatrix.rotateY(angle.y); + level->cutMatrix.rotateY(rotation); level->cutMatrix.setPos(pos); timer = 0.0f; } @@ -188,7 +188,7 @@ struct Camera : ICamera { if (indexA == level->cameraFramesCount - 1) { if (level->cutEntity != -1) - game->loadLevel(TR::LevelID(level->id + 1)); + game->loadNextLevel(); else { Character *lara = (Character*)game->getLara(); if (lara->health > 0.0f) diff --git a/src/enemy.h b/src/enemy.h index 8522bd1..3811e31 100644 --- a/src/enemy.h +++ b/src/enemy.h @@ -1239,7 +1239,7 @@ struct Mummy : Enemy { struct Doppelganger : Enemy { enum { - ANIM_FALL = 32, + ANIM_FALL = 34, }; Doppelganger(IGame *game, int entity) : Enemy(game, entity, 1000, 341, 150.0f, 0.0f) { @@ -1401,9 +1401,9 @@ struct Pierre : Human { virtual void onDead() { if (level->id == TR::LEVEL_7B) { - game->addEntity(TR::Entity::MAGNUMS, getRoomIndex(), pos, 0); - game->addEntity(TR::Entity::SCION_DROP, getRoomIndex(), pos, 0); - game->addEntity(TR::Entity::KEY_ITEM_1, getRoomIndex(), pos, 0); + game->addEntity(TR::Entity::MAGNUMS, getRoomIndex(), pos, 0); + game->addEntity(TR::Entity::SCION_PICKUP_DROP, getRoomIndex(), pos, 0); + game->addEntity(TR::Entity::KEY_ITEM_1, getRoomIndex(), pos, 0); } } }; diff --git a/src/format.h b/src/format.h index 28587fc..5b8078b 100644 --- a/src/format.h +++ b/src/format.h @@ -154,10 +154,10 @@ E( KEY_HOLE_4 ) \ E( UNUSED_4 ) \ E( UNUSED_5 ) \ - E( SCION_QUALOPEC ) \ - E( SCION_DROP ) \ + E( SCION_PICKUP_QUALOPEC ) \ + E( SCION_PICKUP_DROP ) \ E( SCION_TARGET ) \ - E( SCION_NATLA ) \ + E( SCION_PICKUP_HOLDER ) \ E( SCION_HOLDER ) \ E( UNUSED_6 ) \ E( UNUSED_7 ) \ @@ -402,6 +402,10 @@ namespace TR { Limit SCION = { 640, -202, 30, {{-256, 540, -350}, {256, 740, -200}}, false, false }; + + Limit SCION_HOLDER = { + 640, -202, 10, {{-256, 206, -862}, {256, 306, -200}}, true, false + }; } struct fixed { @@ -672,10 +676,8 @@ namespace TR { return isEnemy() || isDoor() || (type == DRAWBRIDGE && flags.active != ACTIVE) || - (type == SCION_HOLDER) || ((type == HAMMER_HANDLE || type == HAMMER_BLOCK) && flags.collision) || - (type == CRYSTAL) || - (type == MOVING_OBJECT); + type == CRYSTAL || type == MOVING_OBJECT || type == SCION_HOLDER; } bool isPickup() const { @@ -683,7 +685,7 @@ namespace TR { (type >= PUZZLE_1 && type <= PUZZLE_4) || (type >= KEY_ITEM_1 && type <= KEY_ITEM_4) || (type == MEDIKIT_SMALL || type == MEDIKIT_BIG) || - (type == SCION_QUALOPEC || type == SCION_DROP || type == SCION_NATLA || type == LEADBAR); // TODO: recheck all items + (type == SCION_PICKUP_QUALOPEC || type == SCION_PICKUP_DROP || type == SCION_PICKUP_HOLDER || type == LEADBAR); // TODO: recheck all items } bool isActor() const { diff --git a/src/lara.h b/src/lara.h index 2f5f2b8..1c30129 100644 --- a/src/lara.h +++ b/src/lara.h @@ -482,6 +482,7 @@ struct Lara : Character { //reset(44, vec3(75803, -11008, 21097), 90 * DEG2RAD); // Level 10a (boat) //reset(47, vec3(50546, -13056, 53783), 270 * DEG2RAD); // Level 10b (trap door slope) //reset(59, vec3(42907, -13056, 63012), 270 * DEG2RAD); // Level 10b (doppelganger) + //reset(50, vec3(52122, -18688, 47313), 150 * DEG2RAD); // Level 10b (scion holder pickup) //reset(50, vec3(53703, -18688, 13769), PI); // Level 10c (scion holder) //reset(19, vec3(35364, -512, 40199), PI * 0.5f); // Level 10c (lava flow) //reset(9, vec3(69074, -14592, 25192), 0); // Level 10c (trap slam) @@ -1570,11 +1571,6 @@ struct Lara : Character { Controller *controller = (Controller*)entity.controller; - // set item orientation to hack limits check - if (stand == STAND_UNDERWATER) - controller->angle.x = -25 * DEG2RAD; - controller->angle.y = angle.y; - if (controller->getRoomIndex() != room || entity.flags.invisible || !canPickup(controller)) continue; @@ -1596,7 +1592,8 @@ struct Lara : Character { // get limits TR::Limits::Limit *limit; switch (entity.type) { - case TR::Entity::SCION_QUALOPEC : limit = &TR::Limits::SCION; break; + case TR::Entity::SCION_PICKUP_QUALOPEC : limit = &TR::Limits::SCION; break; + case TR::Entity::SCION_PICKUP_HOLDER : limit = &TR::Limits::SCION_HOLDER; break; default : limit = level->rooms[getRoomIndex()].flags.water ? &TR::Limits::PICKUP_UNDERWATER : &TR::Limits::PICKUP; } @@ -1608,10 +1605,18 @@ struct Lara : Character { // set new state switch (entity.type) { - case TR::Entity::SCION_QUALOPEC : + case TR::Entity::SCION_PICKUP_QUALOPEC : animation.setAnim(level->models[TR::MODEL_LARA_SPEC].animation); game->getCamera()->doCutscene(pos, angle.y); break; + case TR::Entity::SCION_PICKUP_HOLDER : + animation.setAnim(level->models[TR::MODEL_LARA_SPEC].animation); + + angle = controller->angle; + pos = controller->pos - vec3(0, -280, LARA_RADIUS + 512).rotateY(angle.y); + + game->getCamera()->doCutscene(pos, angle.y - PI * 0.5f); + break; default : ; } @@ -1656,11 +1661,18 @@ struct Lara : Character { vec3 deltaAbs = pos - targetPos; vec3 deltaRel = (controller->getMatrix().transpose() * vec4(pos - controller->pos, 0.0f)).xyz; // inverse transform + // set item orientation to hack limits check + vec3 ctrlAngle = controller->angle; + if (stand == STAND_UNDERWATER) + ctrlAngle.x = -25 * DEG2RAD; + if (!limit->alignAngle) + ctrlAngle.y = angle.y; + if (limit->box.contains(deltaRel)) { - float deltaAngY = shortAngle(angle.y, controller->angle.y); + float deltaAngY = shortAngle(angle.y, ctrlAngle.y); if (stand == STAND_UNDERWATER) { - float deltaAngX = shortAngle(angle.x, controller->angle.x); + float deltaAngX = shortAngle(angle.x, ctrlAngle.x); if (deltaAbs.length() > 64.0f || max(fabs(deltaAngX), fabs(deltaAngY)) > (10.0f * DEG2RAD)) { pos -= deltaAbs.normal() * min(deltaAbs.length(), Core::deltaTime * 512.0f); @@ -2469,6 +2481,8 @@ struct Lara : Character { int pickupFrame = stand == STAND_GROUND ? PICKUP_FRAME_GROUND : PICKUP_FRAME_UNDERWATER; if (animation.isFrameActive(pickupFrame)) { for (int i = 0; i < pickupListCount; i++) { + if (pickupList[i]->type == TR::Entity::SCION_PICKUP_HOLDER) + continue; pickupList[i]->flags.invisible = true; game->invAdd(pickupList[i]->type, 1); } @@ -2719,7 +2733,7 @@ struct Lara : Character { } else { // fast distance check for object TR::Entity &entity = getEntity(); - if (e.type != TR::Entity::HAMMER_HANDLE && e.type != TR::Entity::HAMMER_BLOCK) + if (e.type != TR::Entity::HAMMER_HANDLE && e.type != TR::Entity::HAMMER_BLOCK && e.type != TR::Entity::SCION_HOLDER) if (abs(entity.x - e.x) > 1024 || abs(entity.z - e.z) > 1024 || abs(entity.y - e.y) > 2048) continue; } @@ -2727,7 +2741,8 @@ struct Lara : Character { vec3 p = dir.rotateY(controller->angle.y); Box box = controller->getBoundingBoxLocal(); - box.expand(vec3(LARA_RADIUS, 0.0f, LARA_RADIUS)); + box.expand(vec3(LARA_RADIUS + 50.0f, 0.0f, LARA_RADIUS + 50.0f)); + box.max.y += 768; if (!box.contains(p)) // TODO: Box vs Box or check Lara's head point? (check thor hammer handle) continue;