mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-16 10:04:28 +02:00
#22 fix dart emitters with timers, add scion & earthquake entity for LEVEL10C; #14 disable activation for dead enemies, fix hit sounds, add mummy entity for LEVEL3B
This commit is contained in:
@@ -363,7 +363,7 @@ struct Controller {
|
||||
void getSpheres(Sphere *spheres, int &count) {
|
||||
TR::Model *m = getModel();
|
||||
Basis basis(getMatrix());
|
||||
|
||||
// TODO: optimize (check frame index for animation updates, use joints array)
|
||||
count = 0;
|
||||
for (int i = 0; i < m->mCount; i++) {
|
||||
TR::Mesh &aMesh = level->meshes[level->meshOffsets[m->mStart + i]];
|
||||
@@ -556,9 +556,36 @@ struct Controller {
|
||||
part.basis = Basis(part.basis.rot * q, part.basis.pos + explodeParts[i].velocity * (Core::deltaTime * 30.0f));
|
||||
|
||||
vec3 p = part.basis.pos;
|
||||
TR::Room::Sector *s = level->getSector(part.roomIndex, int(p.x), int(p.y), int(p.z));
|
||||
//TR::Room::Sector *s = level->getSector(part.roomIndex, int(p.x), int(p.y), int(p.z));
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(part.roomIndex, int(p.x), int(p.y), int(p.z), info);
|
||||
|
||||
if (s && s->floor * 256.0f < p.y) {
|
||||
if (info.roomNext != TR::NO_ROOM)
|
||||
part.roomIndex = info.roomNext;
|
||||
|
||||
bool explode = false;
|
||||
|
||||
if (p.y < info.roomCeiling) {
|
||||
if (info.roomAbove != TR::NO_ROOM)
|
||||
part.roomIndex = info.roomAbove;
|
||||
else {
|
||||
if (info.roomCeiling != 0xffff8100)
|
||||
p.y = (float)info.roomCeiling;
|
||||
explode = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (p.y > info.roomFloor) {
|
||||
if (info.roomBelow != TR::NO_ROOM)
|
||||
part.roomIndex = info.roomBelow;
|
||||
else {
|
||||
if (info.roomFloor != 0xffff8100)
|
||||
p.y = (float)info.roomFloor;
|
||||
explode = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (explode) {
|
||||
explodeMask &= ~(1 << i);
|
||||
|
||||
game->addSprite(TR::Entity::EXPLOSION, part.roomIndex, int(p.x), int(p.y), int(p.z));
|
||||
|
76
src/enemy.h
76
src/enemy.h
@@ -68,7 +68,7 @@ struct Enemy : Character {
|
||||
bool targetFromView; // enemy in target view zone
|
||||
bool targetCanAttack;
|
||||
|
||||
Enemy(IGame *game, int entity, float health, int radius, float length, float aggression) : Character(game, entity, health), ai(AI_RANDOM), mood(MOOD_SLEEP), wound(false), nextState(0), targetBox(-1), thinkTime(1.0f / 30.0f), length(length), aggression(aggression), radius(radius), target(NULL), path(NULL) {
|
||||
Enemy(IGame *game, int entity, float health, int radius, float length, float aggression) : Character(game, entity, health), ai(AI_RANDOM), mood(MOOD_SLEEP), wound(false), nextState(0), targetBox(-1), thinkTime(1.0f / 30.0f), length(length), aggression(aggression), radius(radius), hitSound(-1), target(NULL), path(NULL) {
|
||||
targetDist = +INF;
|
||||
targetInView = targetFromView = targetCanAttack = false;
|
||||
}
|
||||
@@ -78,7 +78,7 @@ struct Enemy : Character {
|
||||
}
|
||||
|
||||
virtual bool activate() {
|
||||
if (Character::activate()) {
|
||||
if (health > 0.0f && Character::activate()) {
|
||||
target = (Character*)game->getLara();
|
||||
return true;
|
||||
}
|
||||
@@ -1202,4 +1202,76 @@ struct Centaur : Enemy {
|
||||
};
|
||||
|
||||
|
||||
struct Mummy : Enemy {
|
||||
enum {
|
||||
STATE_NONE,
|
||||
STATE_IDLE,
|
||||
STATE_FALL,
|
||||
};
|
||||
|
||||
Mummy(IGame *game, int entity) : Enemy(game, entity, 18, 341, 150.0f, 0.0f) {
|
||||
jointHead = 2;
|
||||
}
|
||||
|
||||
virtual void update() {
|
||||
if (state == STATE_IDLE && (health <= 0.0f || collide((Controller*)level->laraController))) {
|
||||
animation.setState(STATE_FALL);
|
||||
health = 0.0f;
|
||||
}
|
||||
Enemy::update();
|
||||
}
|
||||
|
||||
virtual int getStateGround() {
|
||||
if (!think(true))
|
||||
return state;
|
||||
return state;
|
||||
}
|
||||
|
||||
virtual void updatePosition() {
|
||||
Enemy::updatePosition();
|
||||
setOverrides(true, jointChest, jointHead);
|
||||
lookAt(target);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Doppelganger : Enemy {
|
||||
Doppelganger(IGame *game, int entity) : Enemy(game, entity, 1000, 341, 150.0f, 0.0f) {
|
||||
jointChest = 1;
|
||||
jointHead = 2;
|
||||
}
|
||||
|
||||
virtual void update() {
|
||||
Enemy::update();
|
||||
}
|
||||
|
||||
virtual int getStateGround() {
|
||||
if (!think(true))
|
||||
return state;
|
||||
return state;
|
||||
}
|
||||
|
||||
virtual void updatePosition() {
|
||||
Enemy::updatePosition();
|
||||
setOverrides(true, jointChest, jointHead);
|
||||
lookAt(target);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ScionTarget : Enemy {
|
||||
ScionTarget(IGame *game, int entity) : Enemy(game, entity, 5, 0, 0, 0) {}
|
||||
|
||||
virtual void update() {
|
||||
Controller::update();
|
||||
|
||||
if (health <= 0.0f) {
|
||||
getEntity().flags.invisible = true;
|
||||
game->checkTrigger(this, true);
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
12
src/format.h
12
src/format.h
@@ -17,7 +17,7 @@
|
||||
E( LARA_MAGNUMS ) \
|
||||
E( LARA_UZIS ) \
|
||||
E( LARA_SPEC ) \
|
||||
E( ENEMY_TWIN ) \
|
||||
E( ENEMY_DOPPELGANGER ) \
|
||||
E( ENEMY_WOLF ) \
|
||||
E( ENEMY_BEAR ) \
|
||||
E( ENEMY_BAT ) \
|
||||
@@ -154,10 +154,10 @@
|
||||
E( KEY_HOLE_4 ) \
|
||||
E( UNUSED_4 ) \
|
||||
E( UNUSED_5 ) \
|
||||
E( SCION_1 ) \
|
||||
E( SCION_2 ) \
|
||||
E( SCION_3 ) \
|
||||
E( SCION_QUALOPEC ) \
|
||||
E( SCION_DROP ) \
|
||||
E( SCION_TARGET ) \
|
||||
E( SCION_NATLA ) \
|
||||
E( SCION_HOLDER ) \
|
||||
E( UNUSED_6 ) \
|
||||
E( UNUSED_7 ) \
|
||||
@@ -647,7 +647,7 @@ namespace TR {
|
||||
void *controller; // Controller implementation or NULL
|
||||
|
||||
bool isEnemy() const {
|
||||
return type >= ENEMY_TWIN && type <= ENEMY_GIANT_MUTANT;
|
||||
return (type >= ENEMY_DOPPELGANGER && type <= ENEMY_GIANT_MUTANT) || type == SCION_TARGET;
|
||||
}
|
||||
|
||||
bool isBigEnemy() const {
|
||||
@@ -669,7 +669,7 @@ namespace TR {
|
||||
return (type >= PISTOLS && type <= AMMO_UZIS) ||
|
||||
(type >= PUZZLE_1 && type <= PUZZLE_4) ||
|
||||
(type >= KEY_ITEM_1 && type <= KEY_ITEM_4) ||
|
||||
(type == MEDIKIT_SMALL || type == MEDIKIT_BIG || type == SCION_1 || type == LEADBAR); // TODO: recheck all items
|
||||
(type == MEDIKIT_SMALL || type == MEDIKIT_BIG || type == SCION_QUALOPEC || type == SCION_DROP || type == SCION_NATLA || type == LEADBAR); // TODO: recheck all items
|
||||
}
|
||||
|
||||
bool isActor() const {
|
||||
|
15
src/lara.h
15
src/lara.h
@@ -426,17 +426,14 @@ struct Lara : Character {
|
||||
|
||||
if (level->extra.braid > -1)
|
||||
braid = new Braid(this, vec3(-4.0f, 24.0f, -48.0f));
|
||||
//reset(19, vec3(41418, -3707, 58863), 270 * DEG2RAD); // level 5 (triangle)
|
||||
//reset(9, vec3(63008, 0, 37787), 0); // level 2 (switch)
|
||||
//reset(5, vec3(38643, -3072, 92370), PI * 0.5f); // level 3a (gears)
|
||||
//reset(15, vec3(70067, -256, 29104), -0.68f); // level 2 (pool)
|
||||
//reset(26, vec3(24475, 6912, 83505), 90 * DEG2RAD); // level 1 (switch timer)
|
||||
#ifdef _DEBUG
|
||||
//reset(14, vec3(40448, 3584, 60928), PI * 0.5f, STAND_ONWATER); // gym (pool)
|
||||
//reset(0, vec3(74858, 3072, 20795), 0); // level 1 (dart)
|
||||
//reset(14, vec3(20215, 6656, 52942), PI); // level 1 (bridge)
|
||||
//reset(20, vec3(8952, 3840, 68071), PI); // level 1 (crystal)
|
||||
//reset(26, vec3(24475, 6912, 83505), 90 * DEG2RAD); // level 1 (switch timer)
|
||||
//reset(33, vec3(48229, 4608, 78420), 270 * DEG2RAD); // level 1 (end)
|
||||
//reset(9, vec3(63008, 0, 37787), 0); // level 2 (switch)
|
||||
//reset(15, vec3(70067, -256, 29104), -0.68f); // level 2 (pool)
|
||||
//reset(26, vec3(71980, 1546, 19000), 270 * DEG2RAD); // level 2 (underwater switch)
|
||||
//reset(61, vec3(27221, -1024, 29205), -PI * 0.5f); // level 2 (blade)
|
||||
@@ -457,6 +454,7 @@ struct Lara : Character {
|
||||
//reset(18, vec3(34914, 11008, 41315), 90 * DEG2RAD); // level 4 (main hall)
|
||||
//reset(19, vec3(33368, 19968, 45643), 270 * DEG2RAD); // level 4 (damocles)
|
||||
//reset(24, vec3(45609, 18176, 41500), 90 * DEG2RAD); // level 4 (thor)
|
||||
//reset(19, vec3(41418, -3707, 58863), 270 * DEG2RAD); // level 5 (triangle)
|
||||
//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)
|
||||
@@ -842,7 +840,8 @@ struct Lara : Character {
|
||||
if (arm->target && checkHit(arm->target, p, hit, hit)) {
|
||||
((Character*)arm->target)->hit(wpnGetDamage());
|
||||
hit -= d * 64.0f;
|
||||
Sprite::add(game, TR::Entity::BLOOD, room, (int)hit.x, (int)hit.y, (int)hit.z, Sprite::FRAME_ANIMATED);
|
||||
if (arm->target->getEntity().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;
|
||||
Sprite::add(game, TR::Entity::RICOCHET, room, (int)hit.x, (int)hit.y, (int)hit.z, Sprite::FRAME_RANDOM);
|
||||
@@ -1494,7 +1493,7 @@ struct Lara : Character {
|
||||
controller->angle.x = -25 * DEG2RAD;
|
||||
controller->angle.y = angle.y;
|
||||
|
||||
if (item.type == TR::Entity::SCION_1)
|
||||
if (item.type == TR::Entity::SCION_QUALOPEC)
|
||||
limit = TR::Limits::SCION;
|
||||
|
||||
if (!checkInteraction(controller, limit, (input & ACTION) != 0))
|
||||
@@ -1505,7 +1504,7 @@ struct Lara : Character {
|
||||
|
||||
pickupEntity = &item;
|
||||
|
||||
if (item.type == TR::Entity::SCION_1) {
|
||||
if (item.type == TR::Entity::SCION_QUALOPEC) {
|
||||
animation.setAnim(level->models[TR::MODEL_LARA_SPEC].animation);
|
||||
((Camera*)level->cameraController)->state = Camera::STATE_CUTSCENE;
|
||||
level->cutMatrix.identity();
|
||||
|
265
src/level.h
265
src/level.h
@@ -225,23 +225,7 @@ struct Level : IGame {
|
||||
int index = level.entityAdd(type, room, int(pos.x), int(pos.y), int(pos.z), TR::angle(angle), -1);
|
||||
if (index > -1) {
|
||||
TR::Entity &e = level.entities[index];
|
||||
Enemy *enemy = NULL;
|
||||
switch (type) {
|
||||
case TR::Entity::ENEMY_MUTANT_1 :
|
||||
case TR::Entity::ENEMY_MUTANT_2 :
|
||||
case TR::Entity::ENEMY_MUTANT_3 :
|
||||
enemy = new Mutant(this, index);
|
||||
break;
|
||||
case TR::Entity::ENEMY_CENTAUR :
|
||||
enemy = new Centaur(this, index);
|
||||
break;
|
||||
case TR::Entity::ENEMY_GIANT_MUTANT :
|
||||
enemy = new GiantMutant(this, index);
|
||||
break;
|
||||
default : ;
|
||||
}
|
||||
|
||||
ASSERT(enemy);
|
||||
Controller *enemy = initController(index);
|
||||
e.controller = enemy;
|
||||
e.flags.active = TR::ACTIVE;
|
||||
enemy->activate();
|
||||
@@ -357,163 +341,10 @@ struct Level : IGame {
|
||||
initOverrides();
|
||||
|
||||
for (int i = 0; i < level.entitiesBaseCount; i++) {
|
||||
TR::Entity &entity = level.entities[i];
|
||||
switch (entity.type) {
|
||||
case TR::Entity::LARA :
|
||||
case TR::Entity::CUT_1 :
|
||||
entity.controller = (lara = new Lara(this, i));
|
||||
break;
|
||||
case TR::Entity::ENEMY_WOLF :
|
||||
entity.controller = new Wolf(this, i);
|
||||
break;
|
||||
case TR::Entity::ENEMY_BEAR :
|
||||
entity.controller = new Bear(this, i);
|
||||
break;
|
||||
case TR::Entity::ENEMY_BAT :
|
||||
entity.controller = new Bat(this, i);
|
||||
break;
|
||||
case TR::Entity::ENEMY_LION_MALE :
|
||||
case TR::Entity::ENEMY_LION_FEMALE :
|
||||
entity.controller = new Lion(this, i);
|
||||
break;
|
||||
case TR::Entity::ENEMY_RAT_LAND :
|
||||
case TR::Entity::ENEMY_RAT_WATER :
|
||||
entity.controller = new Rat(this, i);
|
||||
break;
|
||||
case TR::Entity::ENEMY_REX :
|
||||
entity.controller = new Rex(this, i);
|
||||
break;
|
||||
case TR::Entity::ENEMY_RAPTOR :
|
||||
entity.controller = new Raptor(this, i);
|
||||
break;
|
||||
case TR::Entity::ENEMY_MUTANT_1 :
|
||||
case TR::Entity::ENEMY_MUTANT_2 :
|
||||
case TR::Entity::ENEMY_MUTANT_3 :
|
||||
entity.controller = new Mutant(this, i);
|
||||
break;
|
||||
case TR::Entity::ENEMY_CENTAUR :
|
||||
entity.controller = new Centaur(this, i);
|
||||
break;
|
||||
case TR::Entity::ENEMY_MUMMY :
|
||||
case TR::Entity::ENEMY_TWIN :
|
||||
case TR::Entity::ENEMY_CROCODILE_LAND :
|
||||
case TR::Entity::ENEMY_CROCODILE_WATER :
|
||||
case TR::Entity::ENEMY_PUMA :
|
||||
case TR::Entity::ENEMY_GORILLA :
|
||||
case TR::Entity::ENEMY_LARSON :
|
||||
case TR::Entity::ENEMY_PIERRE :
|
||||
case TR::Entity::ENEMY_SKATEBOY :
|
||||
case TR::Entity::ENEMY_COWBOY :
|
||||
case TR::Entity::ENEMY_MR_T :
|
||||
case TR::Entity::ENEMY_NATLA :
|
||||
entity.controller = new Enemy(this, i, 100, 10, 0.0f, 0.0f);
|
||||
break;
|
||||
case TR::Entity::DOOR_1 :
|
||||
case TR::Entity::DOOR_2 :
|
||||
case TR::Entity::DOOR_3 :
|
||||
case TR::Entity::DOOR_4 :
|
||||
case TR::Entity::DOOR_5 :
|
||||
case TR::Entity::DOOR_6 :
|
||||
case TR::Entity::DOOR_BIG_1 :
|
||||
case TR::Entity::DOOR_BIG_2 :
|
||||
entity.controller = new Door(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_DOOR_1 :
|
||||
case TR::Entity::TRAP_DOOR_2 :
|
||||
entity.controller = new TrapDoor(this, i);
|
||||
break;
|
||||
case TR::Entity::BRIDGE_0 :
|
||||
case TR::Entity::BRIDGE_1 :
|
||||
case TR::Entity::BRIDGE_2 :
|
||||
entity.controller = new Bridge(this, i);
|
||||
break;
|
||||
case TR::Entity::GEARS_1 :
|
||||
case TR::Entity::GEARS_2 :
|
||||
case TR::Entity::GEARS_3 :
|
||||
entity.controller = new Gear(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_FLOOR :
|
||||
entity.controller = new TrapFloor(this, i);
|
||||
break;
|
||||
case TR::Entity::CRYSTAL :
|
||||
entity.controller = new Crystal(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_BLADE :
|
||||
entity.controller = new TrapBlade(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_SPIKES :
|
||||
entity.controller = new TrapSpikes(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_BOULDER :
|
||||
entity.controller = new TrapBoulder(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_DART_EMITTER :
|
||||
entity.controller = new TrapDartEmitter(this, i);
|
||||
break;
|
||||
case TR::Entity::DRAWBRIDGE :
|
||||
entity.controller = new Drawbridge(this, i);
|
||||
break;
|
||||
case TR::Entity::BLOCK_1 :
|
||||
case TR::Entity::BLOCK_2 :
|
||||
case TR::Entity::BLOCK_3 :
|
||||
case TR::Entity::BLOCK_4 :
|
||||
entity.controller = new Block(this, i);
|
||||
break;
|
||||
case TR::Entity::MOVING_BLOCK :
|
||||
entity.controller = new MovingBlock(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_CEILING_1 :
|
||||
case TR::Entity::TRAP_CEILING_2 :
|
||||
entity.controller = new TrapCeiling(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_SLAM :
|
||||
entity.controller = new TrapSlam(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_SWORD :
|
||||
entity.controller = new TrapSword(this, i);
|
||||
break;
|
||||
case TR::Entity::DOOR_LATCH :
|
||||
entity.controller = new DoorLatch(this, i);
|
||||
break;
|
||||
case TR::Entity::SWITCH :
|
||||
case TR::Entity::SWITCH_WATER :
|
||||
entity.controller = new Switch(this, i);
|
||||
break;
|
||||
case TR::Entity::PUZZLE_HOLE_1 :
|
||||
case TR::Entity::PUZZLE_HOLE_2 :
|
||||
case TR::Entity::PUZZLE_HOLE_3 :
|
||||
case TR::Entity::PUZZLE_HOLE_4 :
|
||||
case TR::Entity::KEY_HOLE_1 :
|
||||
case TR::Entity::KEY_HOLE_2 :
|
||||
case TR::Entity::KEY_HOLE_3 :
|
||||
case TR::Entity::KEY_HOLE_4 :
|
||||
entity.controller = new KeyHole(this, i);
|
||||
break;
|
||||
case TR::Entity::WATERFALL :
|
||||
entity.controller = new Waterfall(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_LAVA :
|
||||
entity.controller = new TrapLava(this, i);
|
||||
break;
|
||||
case TR::Entity::CABIN :
|
||||
entity.controller = new Cabin(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_FLAME_EMITTER :
|
||||
entity.controller = new TrapFlameEmitter(this, i);
|
||||
break;
|
||||
case TR::Entity::BOAT :
|
||||
entity.controller = new Boat(this, i);
|
||||
break;
|
||||
case TR::Entity::MUTANT_EGG_SMALL :
|
||||
case TR::Entity::MUTANT_EGG_BIG :
|
||||
entity.controller = new MutantEgg(this, i);
|
||||
break;
|
||||
default :
|
||||
if (entity.modelIndex > 0)
|
||||
entity.controller = new Controller(this, i);
|
||||
else
|
||||
entity.controller = new Sprite(this, i, 0);
|
||||
}
|
||||
TR::Entity &e = level.entities[i];
|
||||
e.controller = initController(i);
|
||||
if (e.type == TR::Entity::LARA || e.type == TR::Entity::CUT_1)
|
||||
lara = (Lara*)e.controller;
|
||||
}
|
||||
|
||||
if (level.id != TR::TITLE) {
|
||||
@@ -583,6 +414,92 @@ struct Level : IGame {
|
||||
Sound::stopAll();
|
||||
}
|
||||
|
||||
Controller* initController(int index) {
|
||||
switch (level.entities[index].type) {
|
||||
case TR::Entity::LARA :
|
||||
case TR::Entity::CUT_1 : return new Lara(this, index);
|
||||
case TR::Entity::ENEMY_DOPPELGANGER : return new Doppelganger(this, index);
|
||||
case TR::Entity::ENEMY_WOLF : return new Wolf(this, index);
|
||||
case TR::Entity::ENEMY_BEAR : return new Bear(this, index);
|
||||
case TR::Entity::ENEMY_BAT : return new Bat(this, index);
|
||||
case TR::Entity::ENEMY_LION_MALE :
|
||||
case TR::Entity::ENEMY_LION_FEMALE : return new Lion(this, index);
|
||||
case TR::Entity::ENEMY_RAT_LAND :
|
||||
case TR::Entity::ENEMY_RAT_WATER : return new Rat(this, index);
|
||||
case TR::Entity::ENEMY_REX : return new Rex(this, index);
|
||||
case TR::Entity::ENEMY_RAPTOR : return new Raptor(this, index);
|
||||
case TR::Entity::ENEMY_MUTANT_1 :
|
||||
case TR::Entity::ENEMY_MUTANT_2 :
|
||||
case TR::Entity::ENEMY_MUTANT_3 : return new Mutant(this, index);
|
||||
case TR::Entity::ENEMY_CENTAUR : return new Centaur(this, index);
|
||||
case TR::Entity::ENEMY_MUMMY : return new Mummy(this, index);
|
||||
case TR::Entity::ENEMY_CROCODILE_LAND :
|
||||
case TR::Entity::ENEMY_CROCODILE_WATER :
|
||||
case TR::Entity::ENEMY_PUMA :
|
||||
case TR::Entity::ENEMY_GORILLA :
|
||||
case TR::Entity::ENEMY_LARSON :
|
||||
case TR::Entity::ENEMY_PIERRE :
|
||||
case TR::Entity::ENEMY_SKATEBOY :
|
||||
case TR::Entity::ENEMY_COWBOY :
|
||||
case TR::Entity::ENEMY_MR_T :
|
||||
case TR::Entity::ENEMY_NATLA : return new Enemy(this, index, 100, 10, 0.0f, 0.0f);
|
||||
case TR::Entity::ENEMY_GIANT_MUTANT : return new GiantMutant(this, index);
|
||||
case TR::Entity::DOOR_1 :
|
||||
case TR::Entity::DOOR_2 :
|
||||
case TR::Entity::DOOR_3 :
|
||||
case TR::Entity::DOOR_4 :
|
||||
case TR::Entity::DOOR_5 :
|
||||
case TR::Entity::DOOR_6 :
|
||||
case TR::Entity::DOOR_BIG_1 :
|
||||
case TR::Entity::DOOR_BIG_2 : return new Door(this, index);
|
||||
case TR::Entity::TRAP_DOOR_1 :
|
||||
case TR::Entity::TRAP_DOOR_2 : return new TrapDoor(this, index);
|
||||
case TR::Entity::BRIDGE_0 :
|
||||
case TR::Entity::BRIDGE_1 :
|
||||
case TR::Entity::BRIDGE_2 : return new Bridge(this, index);
|
||||
case TR::Entity::GEARS_1 :
|
||||
case TR::Entity::GEARS_2 :
|
||||
case TR::Entity::GEARS_3 : return new Gear(this, index);
|
||||
case TR::Entity::TRAP_FLOOR : return new TrapFloor(this, index);
|
||||
case TR::Entity::CRYSTAL : return new Crystal(this, index);
|
||||
case TR::Entity::TRAP_BLADE : return new TrapBlade(this, index);
|
||||
case TR::Entity::TRAP_SPIKES : return new TrapSpikes(this, index);
|
||||
case TR::Entity::TRAP_BOULDER : return new TrapBoulder(this, index);
|
||||
case TR::Entity::TRAP_DART_EMITTER : return new TrapDartEmitter(this, index);
|
||||
case TR::Entity::DRAWBRIDGE : return new Drawbridge(this, index);
|
||||
case TR::Entity::BLOCK_1 :
|
||||
case TR::Entity::BLOCK_2 :
|
||||
case TR::Entity::BLOCK_3 :
|
||||
case TR::Entity::BLOCK_4 : return new Block(this, index);
|
||||
case TR::Entity::MOVING_BLOCK : return new MovingBlock(this, index);
|
||||
case TR::Entity::TRAP_CEILING_1 :
|
||||
case TR::Entity::TRAP_CEILING_2 : return new TrapCeiling(this, index);
|
||||
case TR::Entity::TRAP_SLAM : return new TrapSlam(this, index);
|
||||
case TR::Entity::TRAP_SWORD : return new TrapSword(this, index);
|
||||
case TR::Entity::DOOR_LATCH : return new DoorLatch(this, index);
|
||||
case TR::Entity::SWITCH :
|
||||
case TR::Entity::SWITCH_WATER : return new Switch(this, index);
|
||||
case TR::Entity::PUZZLE_HOLE_1 :
|
||||
case TR::Entity::PUZZLE_HOLE_2 :
|
||||
case TR::Entity::PUZZLE_HOLE_3 :
|
||||
case TR::Entity::PUZZLE_HOLE_4 :
|
||||
case TR::Entity::KEY_HOLE_1 :
|
||||
case TR::Entity::KEY_HOLE_2 :
|
||||
case TR::Entity::KEY_HOLE_3 :
|
||||
case TR::Entity::KEY_HOLE_4 : return new KeyHole(this, index);
|
||||
case TR::Entity::SCION_TARGET : return new ScionTarget(this, index);
|
||||
case TR::Entity::WATERFALL : return new Waterfall(this, index);
|
||||
case TR::Entity::TRAP_LAVA : return new TrapLava(this, index);
|
||||
case TR::Entity::CABIN : return new Cabin(this, index);
|
||||
case TR::Entity::TRAP_FLAME_EMITTER : return new TrapFlameEmitter(this, index);
|
||||
case TR::Entity::BOAT : return new Boat(this, index);
|
||||
case TR::Entity::EARTHQUAKE : return new Earthquake(this, index);
|
||||
case TR::Entity::MUTANT_EGG_SMALL :
|
||||
case TR::Entity::MUTANT_EGG_BIG : return new MutantEgg(this, index);
|
||||
default : return (level.entities[index].modelIndex > 0) ? new Controller(this, index) : new Sprite(this, index, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void fillCallback(int id, int width, int height, int tileX, int tileY, void *userData, void *data) {
|
||||
static const uint32 barColor[UI::BAR_MAX][25] = {
|
||||
// health bar
|
||||
|
@@ -61,10 +61,9 @@ struct Gear : Controller {
|
||||
struct Dart : Controller {
|
||||
vec3 velocity;
|
||||
vec3 dir;
|
||||
bool inWall; // dart starts from wall
|
||||
bool armed;
|
||||
|
||||
Dart(IGame *game, int entity) : Controller(game, entity), inWall(true), armed(true) {
|
||||
Dart(IGame *game, int entity) : Controller(game, entity), armed(true) {
|
||||
dir = vec3(sinf(angle.y), 0, cosf(angle.y));
|
||||
}
|
||||
|
||||
@@ -83,17 +82,14 @@ struct Dart : Controller {
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z, info);
|
||||
if (pos.y > info.floor || pos.y < info.ceiling || !insideRoom(pos, getRoomIndex())) {
|
||||
if (!inWall) {
|
||||
TR::Entity &e = getEntity();
|
||||
TR::Entity &e = getEntity();
|
||||
|
||||
vec3 p = pos - dir * 64.0f; // wall offset = 64
|
||||
Sprite::add(game, TR::Entity::RICOCHET, e.room, (int)p.x, (int)p.y, (int)p.z, Sprite::FRAME_RANDOM);
|
||||
vec3 p = pos - dir * 64.0f; // wall offset = 64
|
||||
Sprite::add(game, TR::Entity::RICOCHET, e.room, (int)p.x, (int)p.y, (int)p.z, Sprite::FRAME_RANDOM);
|
||||
|
||||
level->entityRemove(entity);
|
||||
delete this;
|
||||
}
|
||||
} else
|
||||
inWall = false;
|
||||
level->entityRemove(entity);
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,37 +101,30 @@ struct TrapDartEmitter : Controller {
|
||||
|
||||
TrapDartEmitter(IGame *game, int entity) : Controller(game, entity) {}
|
||||
|
||||
virtual bool activate() {
|
||||
if (!Controller::activate())
|
||||
return false;
|
||||
|
||||
animation.setState(STATE_FIRE);
|
||||
|
||||
// add dart (bullet)
|
||||
TR::Entity &entity = getEntity();
|
||||
|
||||
vec3 p = pos + vec3(0.0f, -512.0f, 256.0f).rotateY(PI - entity.rotation);
|
||||
|
||||
int index = level->entityAdd(TR::Entity::TRAP_DART, getRoomIndex(), int(pos.x), int(pos.y), int(pos.z), entity.rotation, entity.intensity);
|
||||
if (index > -1) {
|
||||
Dart *dart = new Dart(game, index);
|
||||
dart->activate();
|
||||
level->entities[index].controller = dart;
|
||||
}
|
||||
|
||||
Sprite::add(game, TR::Entity::SMOKE, entity.room, (int)p.x, (int)p.y, (int)p.z);
|
||||
|
||||
game->playSound(TR::SND_DART, pos, Sound::Flags::PAN);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void virtual update() {
|
||||
updateAnimation(true);
|
||||
if (animation.canSetState(STATE_IDLE)) {
|
||||
animation.setState(STATE_IDLE);
|
||||
deactivate();
|
||||
if (state == STATE_IDLE || state == STATE_FIRE)
|
||||
animation.setState(isActive() ? STATE_FIRE : STATE_IDLE);
|
||||
else
|
||||
ASSERT(false);
|
||||
|
||||
if (state == STATE_FIRE && animation.framePrev == -1) {
|
||||
TR::Entity &entity = getEntity();
|
||||
|
||||
vec3 p = pos + vec3(0.0f, -512.0f, 256.0f).rotateY(PI - entity.rotation);
|
||||
|
||||
int index = level->entityAdd(TR::Entity::TRAP_DART, getRoomIndex(), int(p.x), int(p.y), int(p.z), entity.rotation, -1);
|
||||
if (index > -1) {
|
||||
Dart *dart = new Dart(game, index);
|
||||
dart->activate();
|
||||
level->entities[index].controller = dart;
|
||||
}
|
||||
|
||||
Sprite::add(game, TR::Entity::SMOKE, entity.room, (int)p.x, (int)p.y, (int)p.z);
|
||||
|
||||
game->playSound(TR::SND_DART, p, Sound::Flags::PAN);
|
||||
}
|
||||
|
||||
updateAnimation(true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -909,6 +898,7 @@ struct MutantEgg : Controller {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct KeyHole : Controller {
|
||||
KeyHole(IGame *game, int entity) : Controller(game, entity) {}
|
||||
|
||||
@@ -927,6 +917,33 @@ struct KeyHole : Controller {
|
||||
};
|
||||
|
||||
|
||||
struct Earthquake : Controller {
|
||||
float timer;
|
||||
|
||||
Earthquake(IGame *game, int entity) : Controller(game, entity), timer(0.0f) {}
|
||||
|
||||
virtual void update() {
|
||||
if (!isActive()) return;
|
||||
|
||||
if (timer < (1.0f / 30.0f)){
|
||||
timer += Core::deltaTime;
|
||||
return;
|
||||
}
|
||||
|
||||
float p = randf();
|
||||
if (p < 0.001f) {
|
||||
game->playSound(TR::SND_STOMP);
|
||||
game->getCamera()->shake = 1.0f;
|
||||
} else if (p < 0.04f) {
|
||||
game->playSound(TR::SND_BOULDER);
|
||||
game->getCamera()->shake = 0.3f;
|
||||
}
|
||||
|
||||
timer = 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Waterfall : Controller {
|
||||
#define SPLASH_TIMESTEP (1.0f / 30.0f)
|
||||
|
||||
|
Reference in New Issue
Block a user