1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-02-26 08:23:27 +01:00

#3 burning Lara; #22 add fire traps, lava death; #23 filter sounds by distance;

This commit is contained in:
XProger 2017-09-30 06:05:24 +03:00
parent 9ac30862c7
commit fab5d8b301
8 changed files with 230 additions and 84 deletions

View File

@ -402,6 +402,10 @@ struct Controller {
return mask; return mask;
} }
bool collide(const Sphere &sphere) {
return getBoundingBoxLocal().intersect(Sphere(getMatrix().inverse() * sphere.center, sphere.radius));
}
vec3 trace(int fromRoom, const vec3 &from, const vec3 &to, int &room, bool isCamera) { // TODO: use Bresenham vec3 trace(int fromRoom, const vec3 &from, const vec3 &to, int &room, bool isCamera) { // TODO: use Bresenham
room = fromRoom; room = fromRoom;

View File

@ -669,8 +669,11 @@ namespace Debug {
sprintf(buf, "floor = %d, roomBelow = %d, roomAbove = %d, height = %d", info.floorIndex, info.roomBelow, info.roomAbove, info.floor - info.ceiling); sprintf(buf, "floor = %d, roomBelow = %d, roomAbove = %d, height = %d", info.floorIndex, info.roomBelow, info.roomAbove, info.floor - info.ceiling);
Debug::Draw::text(vec2(16, y += 16), vec4(1.0f), buf); Debug::Draw::text(vec2(16, y += 16), vec4(1.0f), buf);
y += 16;
if (info.lava)
Debug::Draw::text(vec2(16, y += 16), vec4(1.0f, 0.5f, 0.3f, 1.0f), "LAVA");
if (info.trigCmdCount > 0) { if (info.trigCmdCount > 0) {
y += 16;
sprintf(buf, "trigger: %s%s mask: %d timer: %d", getTriggerType(level, info.trigger), info.trigInfo.once ? " (once)" : "", info.trigInfo.mask, info.trigInfo.timer); sprintf(buf, "trigger: %s%s mask: %d timer: %d", getTriggerType(level, info.trigger), info.trigInfo.once ? " (once)" : "", info.trigInfo.mask, info.trigInfo.timer);
Debug::Draw::text(vec2(16, y += 16), vec4(0.5f, 0.8f, 0.5f, 1.0f), buf); Debug::Draw::text(vec2(16, y += 16), vec4(0.5f, 0.8f, 0.5f, 1.0f), buf);

View File

@ -51,7 +51,7 @@
E( TRAP_SPIKES ) \ E( TRAP_SPIKES ) \
E( TRAP_BOULDER ) \ E( TRAP_BOULDER ) \
E( TRAP_DART ) \ E( TRAP_DART ) \
E( TRAP_DARTGUN ) \ E( TRAP_DART_EMITTER ) \
E( DRAWBRIDGE ) \ E( DRAWBRIDGE ) \
E( TRAP_SLAM ) \ E( TRAP_SLAM ) \
E( TRAP_SWORD ) \ E( TRAP_SWORD ) \
@ -187,10 +187,10 @@
E( MUTANT_GRENADE ) \ E( MUTANT_GRENADE ) \
E( UNUSED_16 ) \ E( UNUSED_16 ) \
E( UNUSED_17 ) \ E( UNUSED_17 ) \
E( LAVA_PARTICLE ) \ E( TRAP_LAVA_PARTICLE ) \
E( LAVA_EMITTER ) \ E( TRAP_LAVA_EMITTER ) \
E( FLAME ) \ E( TRAP_FLAME ) \
E( FLAME_EMITTER ) \ E( TRAP_FLAME_EMITTER ) \
E( TRAP_LAVA ) \ E( TRAP_LAVA ) \
E( MUTANT_EGG_BIG ) \ E( MUTANT_EGG_BIG ) \
E( BOAT ) \ E( BOAT ) \
@ -268,12 +268,16 @@ namespace TR {
SND_UNDERWATER = 60, SND_UNDERWATER = 60,
SND_BOULDER = 70,
SND_FLOOD = 81, SND_FLOOD = 81,
SND_HIT_LION = 85, SND_HIT_LION = 85,
SND_HIT_RAT = 95, SND_HIT_RAT = 95,
SND_ROCK = 99,
SND_EXPLOSION = 104, SND_EXPLOSION = 104,
SND_INV_SPIN = 108, SND_INV_SPIN = 108,
@ -291,7 +295,9 @@ namespace TR {
SND_HIT_SKATEBOY = 132, SND_HIT_SKATEBOY = 132,
SND_HIT_MUTANT = 142, SND_HIT_MUTANT = 142,
SND_STOMP = 147,
SND_FLAME = 150,
SND_DART = 151, SND_DART = 151,
SND_TNT = 170, SND_TNT = 170,
@ -327,7 +333,7 @@ namespace TR {
HIT_BLADE, HIT_BLADE,
HIT_BOULDER, HIT_BOULDER,
HIT_SPIKES, HIT_SPIKES,
HIT_FLAME, HIT_LAVA,
HIT_SLAM, HIT_SLAM,
HIT_REX, HIT_REX,
}; };
@ -578,7 +584,7 @@ namespace TR {
FLOOR , FLOOR ,
CEILING , CEILING ,
TRIGGER , TRIGGER ,
KILL , LAVA ,
}; };
}; };
@ -663,7 +669,7 @@ namespace TR {
return (type >= PISTOLS && type <= AMMO_UZIS) || return (type >= PISTOLS && type <= AMMO_UZIS) ||
(type >= PUZZLE_1 && type <= PUZZLE_4) || (type >= PUZZLE_1 && type <= PUZZLE_4) ||
(type >= KEY_ITEM_1 && type <= KEY_ITEM_4) || (type >= KEY_ITEM_1 && type <= KEY_ITEM_4) ||
(type == MEDIKIT_SMALL || type == MEDIKIT_BIG || type == SCION_1); // TODO: recheck all items (type == MEDIKIT_SMALL || type == MEDIKIT_BIG || type == SCION_1 || type == LEADBAR); // TODO: recheck all items
} }
bool isActor() const { bool isActor() const {
@ -1140,7 +1146,7 @@ namespace TR {
int slantX, slantZ; int slantX, slantZ;
int floorIndex; int floorIndex;
int boxIndex; int boxIndex;
int kill; int lava;
int trigCmdCount; int trigCmdCount;
Trigger trigger; Trigger trigger;
FloorData::TriggerInfo trigInfo; FloorData::TriggerInfo trigInfo;
@ -2172,7 +2178,7 @@ namespace TR {
info.roomAbove = s.roomAbove; info.roomAbove = s.roomAbove;
info.floorIndex = s.floorIndex; info.floorIndex = s.floorIndex;
info.boxIndex = s.boxIndex; info.boxIndex = s.boxIndex;
info.kill = 0; info.lava = false;
info.trigger = Trigger::ACTIVATE; info.trigger = Trigger::ACTIVATE;
info.trigCmdCount = 0; info.trigCmdCount = 0;
@ -2344,8 +2350,8 @@ namespace TR {
break; break;
} }
case FloorData::KILL : case FloorData::LAVA :
info.kill = 1; info.lava = true;
break; break;
default : LOG("unknown func: %d\n", cmd.func); default : LOG("unknown func: %d\n", cmd.func);

View File

@ -400,14 +400,6 @@ struct Lara : Character {
} *braid; } *braid;
Lara(IGame *game, int entity) : Character(game, entity, LARA_MAX_HEALTH), dozy(false), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos), braid(NULL) { Lara(IGame *game, int entity) : Character(game, entity, LARA_MAX_HEALTH), dozy(false), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos), braid(NULL) {
if (getEntity().type == TR::Entity::LARA) {
if (getRoom().flags.water)
animation.setAnim(ANIM_UNDERWATER);
else
animation.setAnim(ANIM_STAND);
}
jointChest = 7; jointChest = 7;
jointHead = 14; jointHead = 14;
rangeChest = vec4(-0.40f, 0.40f, -0.90f, 0.90f) * PI; rangeChest = vec4(-0.40f, 0.40f, -0.90f, 0.90f) * PI;
@ -465,6 +457,9 @@ struct Lara : Character {
//reset(18, vec3(34914, 11008, 41315), 90 * DEG2RAD); // level 4 (main hall) //reset(18, vec3(34914, 11008, 41315), 90 * DEG2RAD); // level 4 (main hall)
//reset(19, vec3(33368, 19968, 45643), 270 * DEG2RAD); // level 4 (damocles) //reset(19, vec3(33368, 19968, 45643), 270 * DEG2RAD); // level 4 (damocles)
//reset(24, vec3(45609, 18176, 41500), 90 * DEG2RAD); // level 4 (thor) //reset(24, vec3(45609, 18176, 41500), 90 * DEG2RAD); // level 4 (thor)
//reset(21, vec3(24106, -4352, 52089), 0); // level 6 (flame traps)
//reset(73, vec3(73372, -122, 51687), PI * 0.5f); // level 6 (midas hand)
//reset(64, vec3(36839, -2560, 48769), 270 * DEG2RAD); // level 6 (flipmap effect)
//reset(99, vec3(45562, -3328, 63366), 225 * DEG2RAD); // level 7a (flipmap) //reset(99, vec3(45562, -3328, 63366), 225 * DEG2RAD); // level 7a (flipmap)
//reset(90, vec3(19438, 3840, 78341), 90 * DEG2RAD); // level 7a (statues) //reset(90, vec3(19438, 3840, 78341), 90 * DEG2RAD); // level 7a (statues)
//reset(57, vec3(54844, -3328, 53145), 0); // level 8b (bridge switch) //reset(57, vec3(54844, -3328, 53145), 0); // level 8b (bridge switch)
@ -473,12 +468,20 @@ struct Lara : Character {
//reset(30, vec3(69689, -8448, 34922), 330 * DEG2RAD); // Level 10a (cabin) //reset(30, vec3(69689, -8448, 34922), 330 * DEG2RAD); // Level 10a (cabin)
//reset(27, vec3(52631, -4352, 57893), 270 * DEG2RAD); // Level 10a (drill) //reset(27, vec3(52631, -4352, 57893), 270 * DEG2RAD); // Level 10a (drill)
//reset(44, vec3(75803, -11008, 21097), 90 * DEG2RAD); // Level 10a (boat) //reset(44, vec3(75803, -11008, 21097), 90 * DEG2RAD); // Level 10a (boat)
//reset(50, vec3(53703, -18688, 13769), PI); // Level 10c (scion holder) //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(19, vec3(35364, -512, 40199), PI * 0.5f); // Level 10c (lava flow)
//reset(9, vec3(69074, -14592, 25192), 0); // Level 10c (trap slam) //reset(9, vec3(69074, -14592, 25192), 0); // Level 10c (trap slam)
//reset(10, vec3(90443, 11264 - 256, 114614), PI, STAND_ONWATER); // villa mortal 2 //reset(10, vec3(90443, 11264 - 256, 114614), PI, STAND_ONWATER); // villa mortal 2
#endif #endif
chestOffset = animation.getJoints(getMatrix(), 7).pos;
if (getEntity().type == TR::Entity::LARA) {
if (getRoom().flags.water)
animation.setAnim(ANIM_UNDERWATER);
else
animation.setAnim(ANIM_STAND);
}
chestOffset = animation.getJoints(getMatrix(), jointChest).pos;
} }
virtual ~Lara() { virtual ~Lara() {
@ -983,8 +986,8 @@ struct Lara : Character {
// head & chest // head & chest
overrideMask |= BODY_CHEST | BODY_HEAD; overrideMask |= BODY_CHEST | BODY_HEAD;
animation.overrides[ 7] = animation.getJointRot( 7); animation.overrides[jointChest] = animation.getJointRot(jointChest);
animation.overrides[14] = animation.getJointRot(14); animation.overrides[jointHead] = animation.getJointRot(jointHead);
/* TODO: shotgun full body animation /* TODO: shotgun full body animation
if (wpnCurrent == Weapon::SHOTGUN) { if (wpnCurrent == Weapon::SHOTGUN) {
@ -1396,6 +1399,20 @@ struct Lara : Character {
} }
default : ; default : ;
} }
if (hitType != TR::HIT_LAVA) {
TR::Entity &e = getEntity();
TR::Level::FloorInfo info;
level->getFloorInfo(e.room, e.x, e.y, e.z, info);
if (info.lava && info.floor == e.y)
hitType = TR::HIT_LAVA;
}
if (hitType == TR::HIT_LAVA) {
for (int i = 0; i < 10; i++)
Flame::add(game, this, int(randf() * 24.0f));
}
}; };
bool useItem(TR::Entity::Type item) { bool useItem(TR::Entity::Type item) {
@ -1578,6 +1595,11 @@ struct Lara : Character {
TR::Level::FloorInfo info; TR::Level::FloorInfo info;
level->getFloorInfo(e.room, e.x, e.y, e.z, info); level->getFloorInfo(e.room, e.x, e.y, e.z, info);
if (info.lava && info.floor == e.y) {
hit(LARA_MAX_HEALTH + 1, NULL, TR::HIT_LAVA);
return;
}
if (!info.trigCmdCount) return; // has no trigger if (!info.trigCmdCount) return; // has no trigger
TR::Limits::Limit *limit = NULL; TR::Limits::Limit *limit = NULL;
@ -2218,10 +2240,10 @@ struct Lara : Character {
if (state == STATE_SURF_TREAD) { if (state == STATE_SURF_TREAD) {
if (animation.isFrameActive(0)) if (animation.isFrameActive(0))
game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 96.0f, 0.03f); game->waterDrop(animation.getJoints(getMatrix(), jointHead).pos, 96.0f, 0.03f);
} else { } else {
if (animation.frameIndex % 4 == 0) if (animation.frameIndex % 4 == 0)
game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 96.0f, 0.02f); game->waterDrop(animation.getJoints(getMatrix(), jointHead).pos, 96.0f, 0.02f);
} }
if (input & FORTH) { if (input & FORTH) {
@ -2779,7 +2801,7 @@ struct Lara : Character {
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) { virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
Controller::render(frustum, mesh, type, caustics); Controller::render(frustum, mesh, type, caustics);
chestOffset = animation.getJoints(getMatrix(), 7).pos; // TODO: move to update func chestOffset = animation.getJoints(getMatrix(), jointChest).pos; // TODO: move to update func
if (braid) if (braid)
braid->render(mesh); braid->render(mesh);

View File

@ -283,7 +283,7 @@ struct Level : IGame {
switch (b.flags.mode) { switch (b.flags.mode) {
case 0 : flags |= Sound::UNIQUE; break; case 0 : flags |= Sound::UNIQUE; break;
case 1 : flags |= Sound::REPLAY; break; case 1 : flags |= Sound::REPLAY; break;
case 2 : flags |= Sound::STATIC | Sound::LOOP; break; case 2 : flags |= Sound::FLIPPED | Sound::UNFLIPPED | Sound::LOOP; break;
} }
} }
if (b.flags.gain) volume = max(0.0f, volume - randf() * 0.25f); if (b.flags.gain) volume = max(0.0f, volume - randf() * 0.25f);
@ -447,8 +447,8 @@ struct Level : IGame {
case TR::Entity::TRAP_BOULDER : case TR::Entity::TRAP_BOULDER :
entity.controller = new TrapBoulder(this, i); entity.controller = new TrapBoulder(this, i);
break; break;
case TR::Entity::TRAP_DARTGUN : case TR::Entity::TRAP_DART_EMITTER :
entity.controller = new TrapDartgun(this, i); entity.controller = new TrapDartEmitter(this, i);
break; break;
case TR::Entity::DRAWBRIDGE : case TR::Entity::DRAWBRIDGE :
entity.controller = new Drawbridge(this, i); entity.controller = new Drawbridge(this, i);
@ -498,6 +498,9 @@ struct Level : IGame {
case TR::Entity::CABIN : case TR::Entity::CABIN :
entity.controller = new Cabin(this, i); entity.controller = new Cabin(this, i);
break; break;
case TR::Entity::TRAP_FLAME_EMITTER :
entity.controller = new TrapFlameEmitter(this, i);
break;
case TR::Entity::BOAT : case TR::Entity::BOAT :
entity.controller = new Boat(this, i); entity.controller = new Boat(this, i);
break; break;

View File

@ -412,10 +412,9 @@ namespace Sound {
PAN = 2, PAN = 2,
UNIQUE = 4, UNIQUE = 4,
REPLAY = 8, REPLAY = 8,
STATIC = 16, MUSIC = 16,
MUSIC = 32, FLIPPED = 32,
FLIPPED = 64, UNFLIPPED = 64,
UNFLIPPED = 128,
}; };
bool flipped; bool flipped;
@ -607,7 +606,7 @@ namespace Sound {
if (music != ((channels[i]->flags & MUSIC) != 0)) if (music != ((channels[i]->flags & MUSIC) != 0))
continue; continue;
if (channels[i]->flags & STATIC) { if (channels[i]->flags & (FLIPPED | UNFLIPPED)) {
if (!(channels[i]->flags & (flipped ? FLIPPED : UNFLIPPED))) if (!(channels[i]->flags & (flipped ? FLIPPED : UNFLIPPED)))
continue; continue;
@ -704,7 +703,7 @@ namespace Sound {
Sample* play(Stream *stream, const vec3 &pos, float volume = 1.0f, float pitch = 0.0f, int flags = 0, int id = - 1) { Sample* play(Stream *stream, const vec3 &pos, float volume = 1.0f, float pitch = 0.0f, int flags = 0, int id = - 1) {
if (!stream) return NULL; if (!stream) return NULL;
if (volume > 0.001f) { if (volume > 0.001f) {
if (!(flags & (STATIC | MUSIC)) && (flags & PAN)) { if (!(flags & (FLIPPED | UNFLIPPED | MUSIC)) && (flags & PAN)) {
vec3 d = pos - listener.matrix.getPos(); vec3 d = pos - listener.matrix.getPos();
if (fabsf(d.x) > SND_FADEOFF_DIST || fabsf(d.y) > SND_FADEOFF_DIST || fabsf(d.z) > SND_FADEOFF_DIST) { if (fabsf(d.x) > SND_FADEOFF_DIST || fabsf(d.y) > SND_FADEOFF_DIST || fabsf(d.z) > SND_FADEOFF_DIST) {
delete stream; delete stream;
@ -712,17 +711,23 @@ namespace Sound {
} }
} }
if (flags & (UNIQUE | REPLAY)) if (flags & (UNIQUE | REPLAY)) {
for (int i = 0; i < channelsCount; i++) for (int i = 0; i < channelsCount; i++)
if (channels[i]->id == id) { if (channels[i]->id == id) {
if (!(flags & UNIQUE)) { vec3 p = listener.matrix.getPos();
channels[i]->pos = pos;
if ((p - channels[i]->pos).length2() > (p - pos).length2()) {
channels[i]->pos = pos;
channels[i]->pitch = pitch; channels[i]->pitch = pitch;
channels[i]->replay();
} }
if (flags & REPLAY)
channels[i]->replay();
delete stream; delete stream;
return channels[i]; return channels[i];
} }
}
if (channelsCount < SND_CHANNELS_MAX) if (channelsCount < SND_CHANNELS_MAX)
return channels[channelsCount++] = new Sample(stream, pos, volume, pitch, flags, id); return channels[channelsCount++] = new Sample(stream, pos, volume, pitch, flags, id);

View File

@ -56,6 +56,8 @@ struct Gear : Controller {
} }
}; };
#define DART_DAMAGE 50
struct Dart : Controller { struct Dart : Controller {
vec3 velocity; vec3 velocity;
vec3 dir; vec3 dir;
@ -74,7 +76,7 @@ struct Dart : Controller {
Controller *lara = (Controller*)level->laraController; Controller *lara = (Controller*)level->laraController;
if (armed && collide(lara)) { if (armed && collide(lara)) {
Sprite::add(game, TR::Entity::BLOOD, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z, Sprite::FRAME_ANIMATED); Sprite::add(game, TR::Entity::BLOOD, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z, Sprite::FRAME_ANIMATED);
lara->hit(50.0f, this); lara->hit(DART_DAMAGE, this);
armed = false; armed = false;
} }
@ -95,13 +97,13 @@ struct Dart : Controller {
} }
}; };
struct TrapDartgun : Controller { struct TrapDartEmitter : Controller {
enum { enum {
STATE_IDLE, STATE_IDLE,
STATE_FIRE STATE_FIRE
}; };
TrapDartgun(IGame *game, int entity) : Controller(game, entity) {} TrapDartEmitter(IGame *game, int entity) : Controller(game, entity) {}
virtual bool activate() { virtual bool activate() {
if (!Controller::activate()) if (!Controller::activate())
@ -114,11 +116,11 @@ struct TrapDartgun : Controller {
vec3 p = pos + vec3(0.0f, -512.0f, 256.0f).rotateY(PI - entity.rotation); vec3 p = pos + vec3(0.0f, -512.0f, 256.0f).rotateY(PI - entity.rotation);
int dartIndex = level->entityAdd(TR::Entity::TRAP_DART, entity.room, (int)p.x, (int)p.y, (int)p.z, entity.rotation, entity.intensity); int index = level->entityAdd(TR::Entity::TRAP_DART, getRoomIndex(), int(pos.x), int(pos.y), int(pos.z), entity.rotation, entity.intensity);
if (dartIndex > -1) { if (index > -1) {
Dart *dart = new Dart(game, dartIndex); Dart *dart = new Dart(game, index);
dart->activate(); dart->activate();
level->entities[dartIndex].controller = dart; level->entities[index].controller = dart;
} }
Sprite::add(game, TR::Entity::SMOKE, entity.room, (int)p.x, (int)p.y, (int)p.z); Sprite::add(game, TR::Entity::SMOKE, entity.room, (int)p.x, (int)p.y, (int)p.z);
@ -137,6 +139,91 @@ struct TrapDartgun : Controller {
} }
}; };
#define FLAME_HEAT_DAMAGE 90
#define FLAME_BURN_DAMAGE 150
struct Flame : Sprite {
static Flame* add(IGame *game, Controller *controller, int jointIndex) {
Flame *flame = NULL;
TR::Level *level = game->getLevel();
int roomIndex = controller->getRoomIndex();
vec3 pos = controller->pos;
int index = level->entityAdd(TR::Entity::TRAP_FLAME, roomIndex, int(pos.x), int(pos.y), int(pos.z), 0, 0);
if (index > -1) {
flame = new Flame(game, index, jointIndex);
level->entities[index].controller = flame;
}
return flame;
}
int jointIndex;
float sleep;
Flame(IGame *game, int entity, int jointIndex) : Sprite(game, entity, false, Sprite::FRAME_ANIMATED), jointIndex(jointIndex), sleep(0.0f) {
time = randf() * 3.0f;
activate();
}
virtual void update() {
Sprite::update();
game->playSound(TR::SND_FLAME, pos, Sound::PAN);
Character *lara = (Character*)level->laraController;
if (jointIndex > -1) {
if (lara->stand == Character::STAND_UNDERWATER) {
level->entityRemove(entity);
delete this;
return;
}
pos = lara->animation.getJoints(lara->getMatrix(), jointIndex).pos;
if (jointIndex == 0)
pos.y += 100.0f;
lara->hit(FLAME_BURN_DAMAGE * Core::deltaTime, this);
} else
if (lara->health > 0.0f) {
if (sleep > 0.0f)
sleep = max(0.0f, sleep - Core::deltaTime);
if (sleep == 0.0f && lara->collide(Sphere(pos, 600.0f))) {
lara->hit(FLAME_HEAT_DAMAGE * Core::deltaTime, this);
if (lara->collide(Sphere(pos, 300.0f))) {
Flame::add(game, lara, 0);
sleep = 3.0f; // stay inactive for 3 seconds
}
}
}
}
};
struct TrapFlameEmitter : Controller {
Flame *flame;
TrapFlameEmitter(IGame *game, int entity) : Controller(game, entity), flame(NULL) {}
void virtual update() {
if (!isActive()) {
if (flame) {
level->entityRemove(flame->entity);
delete flame;
flame = NULL;
Sound::stop(TR::SND_FLAME);
}
return;
}
if (flame) return;
flame = Flame::add(game, this, -1);
}
};
#define BOULDER_DAMAGE_GROUND 1000 #define BOULDER_DAMAGE_GROUND 1000
#define BOULDER_DAMAGE_AIR 100 #define BOULDER_DAMAGE_AIR 100
@ -694,7 +781,7 @@ struct TrapLava : Controller {
virtual void update() { virtual void update() {
Character *lara = (Character*)level->laraController; Character *lara = (Character*)level->laraController;
if (lara->health > 0.0f && collide(lara)) if (lara->health > 0.0f && collide(lara))
lara->hit(1000.0f, this, TR::HIT_FLAME); lara->hit(1001.0f, this, TR::HIT_LAVA);
if (done) { if (done) {
deactivate(); deactivate();

View File

@ -773,6 +773,41 @@ vec3 boxNormal(int x, int z) {
return x < z ? vec3(-1, 0, 0) : vec3(0, 0, -1); return x < z ? vec3(-1, 0, 0) : vec3(0, 0, -1);
} }
struct Sphere {
vec3 center;
float radius;
Sphere() {}
Sphere(const vec3 &center, float radius) : center(center), radius(radius) {}
bool intersect(const Sphere &s) const {
float d = (center - s.center).length2();
float r = (radius + s.radius);
return d < r * r;
}
bool intersect(const vec3 &rayPos, const vec3 &rayDir, float &t) const {
vec3 v = rayPos - center;
float h = -v.dot(rayDir);
float d = h * h + radius * radius - v.length2();
if (d > 0.0f) {
d = sqrtf(d);
float tMin = h - d;
float tMax = h + d;
if (tMax > 0.0f) {
if (tMin < 0.0f)
tMin = 0.0f;
t = tMin;
return true;
}
}
return false;
}
};
struct Box { struct Box {
vec3 min, max; vec3 min, max;
@ -872,6 +907,12 @@ struct Box {
max += offset; max += offset;
} }
vec3 closestPoint(const vec3 &p) const {
return vec3(clamp(p.x, min.x, max.x),
clamp(p.y, min.y, max.y),
clamp(p.z, min.z, max.z));
}
bool contains(const vec3 &v) const { bool contains(const vec3 &v) const {
return v.x >= min.x && v.x <= max.x && v.y >= min.y && v.y <= max.y && v.z >= min.z && v.z <= max.z; return v.x >= min.x && v.x <= max.x && v.y >= min.y && v.y <= max.y && v.z >= min.z && v.z <= max.z;
} }
@ -918,6 +959,13 @@ struct Box {
return !((max.x < box.min.x || min.x > box.max.x) || (max.y < box.min.y || min.y > box.max.y) || (max.z < box.min.z || min.z > box.max.z)); return !((max.x < box.min.x || min.x > box.max.x) || (max.y < box.min.y || min.y > box.max.y) || (max.z < box.min.z || min.z > box.max.z));
} }
bool intersect(const Sphere &sphere) const {
if (contains(sphere.center))
return true;
vec3 dir = sphere.center - closestPoint(sphere.center);
return (dir.length2() < sphere.radius * sphere.radius);
}
bool intersect(const vec3 &rayPos, const vec3 &rayDir, float &t) const { bool intersect(const vec3 &rayPos, const vec3 &rayDir, float &t) const {
float tMax = INF, tMin = -tMax; float tMax = INF, tMin = -tMax;
@ -940,38 +988,6 @@ struct Box {
} }
}; };
struct Sphere {
vec3 center;
float radius;
Sphere() {}
Sphere(const vec3 &center, float radius) : center(center), radius(radius) {}
bool intersect(const Sphere &s) const {
float d = (center - s.center).length2();
float r = (radius + s.radius);
return d < r * r;
}
bool intersect(const vec3 &rayPos, const vec3 &rayDir, float &t) const {
vec3 v = rayPos - center;
float h = -v.dot(rayDir);
float d = h * h + radius * radius - v.length2();
if (d > 0.0f) {
d = sqrtf(d);
float tMin = h - d;
float tMax = h + d;
if (tMax > 0.0f) {
if (tMin < 0.0f)
tMin = 0.0f;
t = tMin;
return true;
}
}
return false;
}
};
struct Stream { struct Stream {
static char cacheDir[255]; static char cacheDir[255];