diff --git a/src/camera.h b/src/camera.h index 698d247..d647a2c 100644 --- a/src/camera.h +++ b/src/camera.h @@ -258,13 +258,22 @@ struct Camera : ICamera { Controller *lookAt = viewTarget; + lookAt = NULL; + if (state != STATE_STATIC) { - if (owner->viewTarget) - owner->lookAt(lookAt = owner->viewTarget); - else - owner->lookAt(lookAt = viewTarget); - } else - owner->lookAt(NULL); + if (!owner->viewTarget) { + + if (viewTarget && !viewTarget->getEntity().flags.invisible) { + vec3 targetVec = (viewTarget->pos - owner->pos).normal(); + if (targetVec.dot(owner->getDir()) > 0.5f) + lookAt = viewTarget; + } + + } else + lookAt = owner->viewTarget; + } + + owner->lookAt(lookAt); vec3 viewPoint = getViewPoint(); diff --git a/src/enemy.h b/src/enemy.h index 4cdaf3d..8522bd1 100644 --- a/src/enemy.h +++ b/src/enemy.h @@ -139,7 +139,7 @@ struct Enemy : Character { if (!getEntity().flags.active) return; vec3 p = pos; - pos += velocity * Core::deltaTime * 30.0f; + pos += velocity * (30.0f * Core::deltaTime); clipByBox(pos); @@ -1235,14 +1235,61 @@ struct Mummy : Enemy { }; +#define DOPPELGANGER_ROOM_CENTER (vec3(36, 0, 60) * 1024.0f) + struct Doppelganger : Enemy { + enum { + ANIM_FALL = 32, + }; + Doppelganger(IGame *game, int entity) : Enemy(game, entity, 1000, 341, 150.0f, 0.0f) { - jointChest = 1; - jointHead = 2; + jointChest = 7; + jointHead = 14; } + virtual void hit(float damage, Controller *enemy = NULL, TR::HitType hitType = TR::HIT_DEFAULT) { + Character *lara = (Character*)game->getLara(); + lara->hit(damage * 10, this); + }; + virtual void update() { - Enemy::update(); + Character *lara = (Character*)game->getLara(); + + if (stand != STAND_AIR) { + pos = DOPPELGANGER_ROOM_CENTER * 2.0f - lara->pos; + pos.y = lara->pos.y; + angle = lara->angle; + angle.y -= PI; + } + + updateEntity(); + Enemy::checkRoom(); + + TR::Level::FloorInfo info; + level->getFloorInfo(getRoomIndex(), int(pos.x), int(pos.y), int(pos.z), info); + + if (stand != STAND_AIR && lara->stand == Character::STAND_GROUND && pos.y < info.floor - 1024) { + animation = Animation(level, lara->getModel()); + animation.setAnim(ANIM_FALL, 1); + stand = STAND_AIR; + velocity.x = velocity.y = 0.0f; + } + + if (stand == STAND_AIR) { + if (pos.y > info.floor) { + game->checkTrigger(this, true); + getEntity().flags.invisible = true; + deactivate(true); + } else { + updateAnimation(true); + applyGravity(velocity.y); + pos += velocity * (30.0f * Core::deltaTime); + } + } else { + animation.frameA = lara->animation.frameA; + animation.frameB = lara->animation.frameB; + animation.delta = lara->animation.delta; + } } virtual int getStateGround() { diff --git a/src/format.h b/src/format.h index a3ab2e4..28587fc 100644 --- a/src/format.h +++ b/src/format.h @@ -2270,8 +2270,11 @@ namespace TR { int ex = e.x / 1024; int ez = e.z / 1024; if ((ex == sx && ez == sz) || (ex + dirX == sx && ez + dirZ == sz)) { - if (e.y >= y - 128 && e.y < info.floor) + if (e.y >= y - 128 && e.y < info.floor) { info.floor = e.y; + info.slantX = info.slantZ = 0; + info.lava = false; + } if (e.y < y - 128 && e.y > info.ceiling) info.ceiling = e.y + 256; } @@ -2281,8 +2284,11 @@ namespace TR { if (sx != e.x / 1024 || sz != e.z / 1024) break; int ey = e.y - 512; - if (ey >= y - 128 && ey < info.floor) + if (ey >= y - 128 && ey < info.floor) { info.floor = ey; + info.slantX = info.slantZ = 0; + info.lava = false; + } if (ey < y - 128 && ey > info.ceiling) info.ceiling = ey; break; @@ -2297,8 +2303,11 @@ namespace TR { if ((ex - dirX * 1 == sx && ez - dirZ * 1 == sz) || (ex - dirX * 2 == sx && ez - dirZ * 2 == sz)) { int ey = e.y; - if (ey >= y - 128 && ey < info.floor) + if (ey >= y - 128 && ey < info.floor) { info.floor = ey; + info.slantX = info.slantZ = 0; + info.lava = false; + } if (ey < y - 128 && ey > info.ceiling) info.ceiling = ey + 256; } @@ -2338,6 +2347,7 @@ namespace TR { info.floor = ey; info.slantX = sx; info.slantZ = sz; + info.lava = false; } if (ey < y - 128) info.ceiling = ey + 64; diff --git a/src/lara.h b/src/lara.h index 4384b1e..2f5f2b8 100644 --- a/src/lara.h +++ b/src/lara.h @@ -480,6 +480,8 @@ struct Lara : Character { //reset(27, vec3(52631, -4352, 57893), 270 * DEG2RAD); // Level 10a (TNT / Cowboy) //reset(68, vec3(52458, -9984, 93724), 270 * DEG2RAD); // Level 10a (MrT) //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(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) @@ -860,9 +862,10 @@ struct Lara : Character { int room; vec3 hit = trace(getRoomIndex(), p, t, room, false); if (arm->target && checkHit(arm->target, p, hit, hit)) { + TR::Entity::Type type = arm->target->getEntity().type; ((Character*)arm->target)->hit(wpnGetDamage()); hit -= d * 64.0f; - if (arm->target->getEntity().type != TR::Entity::SCION_TARGET) + if (type != TR::Entity::SCION_TARGET) Sprite::add(game, TR::Entity::BLOOD, room, (int)hit.x, (int)hit.y, (int)hit.z, Sprite::FRAME_ANIMATED); } else { hit -= d * 64.0f;