mirror of
https://github.com/XProger/OpenLara.git
synced 2025-04-22 03:51:58 +02:00
parent
8b5c17445a
commit
4b22c474c8
@ -300,11 +300,6 @@ struct Character : Controller {
|
||||
addBloodSpikes();
|
||||
}
|
||||
|
||||
void addRicochet(const vec3 &pos, bool sound) {
|
||||
game->addEntity(TR::Entity::RICOCHET, getRoomIndex(), pos);
|
||||
if (sound)
|
||||
game->playSound(TR::SND_RICOCHET, pos, Sound::PAN);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -1318,6 +1318,12 @@ struct Controller {
|
||||
mesh->renderModel(getEntity().modelIndex - 1, caustics);
|
||||
}
|
||||
}
|
||||
|
||||
void addRicochet(const vec3 &pos, bool sound) {
|
||||
game->addEntity(TR::Entity::RICOCHET, getRoomIndex(), pos);
|
||||
if (sound)
|
||||
game->playSound(TR::SND_RICOCHET, pos, Sound::PAN);
|
||||
}
|
||||
};
|
||||
|
||||
Controller *Controller::first = NULL;
|
||||
|
199
src/enemy.h
199
src/enemy.h
@ -2,6 +2,11 @@
|
||||
#define H_ENEMY
|
||||
|
||||
#include "character.h"
|
||||
#include "trigger.h"
|
||||
|
||||
#define STALK_BOX (1024 * 3)
|
||||
#define ESCAPE_BOX (1024 * 5)
|
||||
#define ATTACK_BOX STALK_BOX
|
||||
|
||||
struct Enemy : Character {
|
||||
|
||||
@ -211,6 +216,23 @@ struct Enemy : Character {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool targetIsVisible(float maxDist) {
|
||||
if (targetInView && targetDist < maxDist && target->health > 0.0f) {
|
||||
TR::Location from, to;
|
||||
from.room = getRoomIndex();
|
||||
from.pos = pos;
|
||||
to.pos = target->pos;
|
||||
|
||||
// vertical offset to ~gun/head height
|
||||
from.pos.y -= 768.0f;
|
||||
if (target->stand != STAND_UNDERWATER && target->stand != STAND_ONWATER)
|
||||
to.pos.y -= 768.0f;
|
||||
|
||||
return trace(from, to);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void lookAt(Controller *target) {
|
||||
Character::lookAt(targetInView ? target : NULL);
|
||||
}
|
||||
@ -246,16 +268,12 @@ struct Enemy : Character {
|
||||
wound = true;
|
||||
};
|
||||
|
||||
void bite(const vec3 &pos, float damage) {
|
||||
void bite(int joint, const vec3 &offset, float damage) {
|
||||
ASSERT(target);
|
||||
target->hit(damage, this);
|
||||
game->addEntity(TR::Entity::BLOOD, target->getRoomIndex(), pos);
|
||||
game->addEntity(TR::Entity::BLOOD, target->getRoomIndex(), getJoint(joint) * offset);
|
||||
}
|
||||
|
||||
#define STALK_BOX (1024 * 3)
|
||||
#define ESCAPE_BOX (1024 * 5)
|
||||
#define ATTACK_BOX STALK_BOX
|
||||
|
||||
Mood getMoodFixed() {
|
||||
bool inZone = zone == target->zone;
|
||||
|
||||
@ -463,6 +481,19 @@ struct Enemy : Character {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void shot(TR::Entity::Type type, int joint, const vec3 &offset) {
|
||||
vec3 from = getJoint(joint) * offset;
|
||||
vec3 to = target->getBoundingBox().center();
|
||||
|
||||
Bullet *bullet = (Bullet*)game->addEntity(type, getRoomIndex(), from);
|
||||
if (bullet) {
|
||||
vec3 dir = to - from;
|
||||
vec3 ang = vec3(-atan2f(dir.y, sqrtf(dir.x * dir.x + dir.z * dir.z)), atan2f(dir.x, dir.z), 0.0f);
|
||||
ang += vec3(randf() * 2.0f - 1.0f, randf() * 2.0f - 1.0f, 0.0f) * (1.5f * DEG2RAD);
|
||||
bullet->setAngle(ang);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#define WOLF_TURN_FAST (DEG2RAD * 150)
|
||||
@ -586,7 +617,7 @@ struct Wolf : Enemy {
|
||||
case STATE_ATTACK :
|
||||
case STATE_BITE :
|
||||
if (nextState == STATE_NONE && targetInView && (collide(target) & HIT_MASK)) {
|
||||
bite(getJoint(jointHead).pos, state == STATE_ATTACK ? 50.0f : 100.0f);
|
||||
bite(6, vec3(0.0f, -14.0f, 174.0f), state == STATE_ATTACK ? 50.0f : 100.0f);
|
||||
nextState = state == STATE_ATTACK ? STATE_RUN : STATE_GROWL;
|
||||
}
|
||||
return state == STATE_ATTACK ? STATE_RUN : state;
|
||||
@ -713,7 +744,7 @@ struct Lion : Enemy {
|
||||
case STATE_ATTACK :
|
||||
case STATE_BITE :
|
||||
if (nextState == STATE_NONE && (collide(target) & HIT_MASK)) {
|
||||
bite(getJoint(jointHead).pos, state == STATE_ATTACK ? 150.0f : 250.0f);
|
||||
bite(21, vec3(-2.0f, -10.0f, 132.0f), state == STATE_ATTACK ? 150.0f : 250.0f);
|
||||
nextState = STATE_STOP;
|
||||
}
|
||||
}
|
||||
@ -835,7 +866,7 @@ struct Gorilla : Enemy {
|
||||
break;
|
||||
case STATE_ATTACK :
|
||||
if (nextState == STATE_NONE && (collide(target) & HIT_MASK)) {
|
||||
bite(getJoint(jointChest).pos, 200.0f);
|
||||
bite(15, vec3(0.0f, -19.0f, 75.0f), 200.0f);
|
||||
nextState = STATE_STOP;
|
||||
}
|
||||
case STATE_LSTEP :
|
||||
@ -1002,7 +1033,7 @@ struct Rat : Enemy {
|
||||
case STATE_ATTACK :
|
||||
case STATE_BITE :
|
||||
if (nextState == STATE_NONE && targetInView && (collide(target) & HIT_MASK)) {
|
||||
bite(getJoint(jointHead).pos, RAT_DAMAGE);
|
||||
bite(3, vec3(0.0f, -11.0f, 108.0f), RAT_DAMAGE);
|
||||
nextState = state == STATE_ATTACK ? STATE_RUN : STATE_STOP;
|
||||
}
|
||||
break;
|
||||
@ -1036,7 +1067,7 @@ struct Rat : Enemy {
|
||||
case STATE_WATER_BITE :
|
||||
if (nextState == STATE_NONE && targetInView && (collide(target) & HIT_MASK)) {
|
||||
game->waterDrop(getJoint(jointHead).pos, 256.0f, 0.2f);
|
||||
bite(getJoint(jointHead).pos, RAT_DAMAGE);
|
||||
bite(3, vec3(0.0f, -11.0f, 108.0f), RAT_DAMAGE);
|
||||
nextState = STATE_WATER_SWIM;
|
||||
}
|
||||
return STATE_NONE;
|
||||
@ -1211,7 +1242,7 @@ struct Crocodile : Enemy {
|
||||
return STATE_WALK;
|
||||
case STATE_BITE :
|
||||
if (nextState == STATE_NONE) {
|
||||
bite(getJoint(jointHead).pos, CROCODILE_DAMAGE);
|
||||
bite(9, vec3(5.0f, -21.0f, 467.0f), CROCODILE_DAMAGE);
|
||||
nextState = STATE_STOP;
|
||||
}
|
||||
break;
|
||||
@ -1243,7 +1274,7 @@ struct Crocodile : Enemy {
|
||||
if (collide(target)) {
|
||||
if (nextState != STATE_NONE)
|
||||
return state;
|
||||
bite(getJoint(jointHead).pos, CROCODILE_DAMAGE);
|
||||
bite(9, vec3(5.0f, -21.0f, 467.0f), CROCODILE_DAMAGE);
|
||||
nextState = STATE_WATER_SWIM;
|
||||
}
|
||||
return STATE_WATER_SWIM;
|
||||
@ -1403,7 +1434,7 @@ struct Bear : Enemy {
|
||||
case STATE_BITE :
|
||||
case STATE_ATTACK :
|
||||
if (nextState == STATE_NONE && (collide(target) & HIT_MASK)) {
|
||||
bite(getJoint(jointHead).pos, state == STATE_BITE ? 200.0f : 400.0f);
|
||||
bite(14, vec3(0.0f, 96.0f, 335.0f), state == STATE_BITE ? 200.0f : 400.0f);
|
||||
nextState = state == STATE_BITE ? STATE_STOP : STATE_HOWL;
|
||||
}
|
||||
break;
|
||||
@ -1484,7 +1515,7 @@ struct Bat : Enemy {
|
||||
mood = MOOD_SLEEP;
|
||||
return STATE_FLY;
|
||||
} else
|
||||
bite(getJoint(jointHead).pos, 2);
|
||||
bite(4, vec3(0.0f, 16.0f, 45.0f), 2);
|
||||
break;
|
||||
case STATE_FLY :
|
||||
if (collide(target)) {
|
||||
@ -1723,7 +1754,7 @@ struct Raptor : Enemy {
|
||||
case STATE_ATTACK_2 :
|
||||
case STATE_BITE :
|
||||
if (nextState == STATE_NONE && targetInView && (mask & HIT_MASK)) {
|
||||
bite(getJoint(jointHead).pos, 100);
|
||||
bite(22, vec3(0.0f, 66.0f, 318.0f), 100);
|
||||
nextState = state == STATE_ATTACK_2 ? STATE_RUN : STATE_STOP;
|
||||
}
|
||||
break;
|
||||
@ -1876,7 +1907,7 @@ struct Mutant : Enemy {
|
||||
case STATE_ATTACK_3 :
|
||||
if (nextState == STATE_NONE && (mask & HIT_MASK)) {
|
||||
float damage = state == STATE_ATTACK_1 ? 150.0f : (state == STATE_ATTACK_2 ? 100.0f : 200.0f);
|
||||
bite(getJoint(jointHead).pos, damage);
|
||||
bite(10, vec3(-27.0f, 98.0f, 0.0f), damage);
|
||||
nextState = STATE_STOP;
|
||||
}
|
||||
break;
|
||||
@ -1899,6 +1930,7 @@ struct Mutant : Enemy {
|
||||
};
|
||||
|
||||
struct GiantMutant : Enemy {
|
||||
|
||||
enum {
|
||||
STATE_STOP = 1,
|
||||
STATE_BORN = 8,
|
||||
@ -1951,9 +1983,31 @@ struct GiantMutant : Enemy {
|
||||
}
|
||||
};
|
||||
|
||||
#define CENTAUR_TURN_FAST (DEG2RAD * 120)
|
||||
#define CENTAUR_DIST_RUN (1024 + 512)
|
||||
#define CENTAUR_DIST_SHOT (1024 * 1024)
|
||||
|
||||
struct Centaur : Enemy {
|
||||
Centaur(IGame *game, int entity) : Enemy(game, entity, 20, 341, 400.0f, 0.5f) {
|
||||
|
||||
enum {
|
||||
HIT_MASK = 0x030199,
|
||||
};
|
||||
|
||||
enum {
|
||||
ANIM_DEATH = 8,
|
||||
};
|
||||
|
||||
enum {
|
||||
STATE_NONE,
|
||||
STATE_STOP,
|
||||
STATE_FIRE,
|
||||
STATE_RUN,
|
||||
STATE_AIM,
|
||||
STATE_DEATH,
|
||||
STATE_IDLE,
|
||||
};
|
||||
|
||||
Centaur(IGame *game, int entity) : Enemy(game, entity, 120, 341, 400.0f, 1.0f) {
|
||||
jointChest = 10;
|
||||
jointHead = 17;
|
||||
}
|
||||
@ -1961,14 +2015,94 @@ struct Centaur : Enemy {
|
||||
virtual int getStateGround() {
|
||||
if (!think(true))
|
||||
return state;
|
||||
|
||||
if (nextState == state)
|
||||
nextState = STATE_NONE;
|
||||
|
||||
int mask = collide(target);
|
||||
|
||||
switch (state) {
|
||||
case STATE_STOP :
|
||||
if (nextState != STATE_NONE)
|
||||
return nextState;
|
||||
if (targetCanAttack && targetDist < CENTAUR_DIST_RUN)
|
||||
return STATE_RUN;
|
||||
if (targetIsVisible(CENTAUR_DIST_SHOT))
|
||||
return STATE_AIM;
|
||||
return STATE_RUN;
|
||||
case STATE_RUN :
|
||||
if (targetCanAttack && targetDist < CENTAUR_DIST_RUN) {
|
||||
nextState = STATE_IDLE;
|
||||
return STATE_STOP;
|
||||
}
|
||||
if (targetIsVisible(CENTAUR_DIST_SHOT)) {
|
||||
nextState = STATE_AIM;
|
||||
return STATE_STOP;
|
||||
}
|
||||
if (rand() < 96) {
|
||||
nextState = STATE_IDLE;
|
||||
return STATE_STOP;
|
||||
}
|
||||
break;
|
||||
case STATE_AIM :
|
||||
if (nextState != STATE_NONE)
|
||||
return nextState;
|
||||
if (targetIsVisible(CENTAUR_DIST_SHOT))
|
||||
return STATE_FIRE;
|
||||
return STATE_STOP;
|
||||
case STATE_FIRE :
|
||||
if (nextState != STATE_NONE)
|
||||
break;
|
||||
nextState = STATE_AIM;
|
||||
shot(TR::Entity::CENTAUR_BULLET, 13, vec3(11.0f, 415.0f, 41.0f));
|
||||
break;
|
||||
case STATE_IDLE :
|
||||
if (nextState == STATE_NONE && (collide(target) & HIT_MASK)) {
|
||||
bite(5, vec3(50.0f, 30.0f, 0.0f), 200);
|
||||
nextState = STATE_STOP;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
virtual int getStateDeath() {
|
||||
if (state == STATE_DEATH) return state;
|
||||
return animation.setAnim(ANIM_DEATH);
|
||||
}
|
||||
|
||||
virtual void updatePosition() {
|
||||
float angleY = 0.0f;
|
||||
getTargetInfo(0, NULL, NULL, &angleY, NULL);
|
||||
|
||||
if (state == STATE_RUN)
|
||||
turn(angleY, CENTAUR_TURN_FAST);
|
||||
|
||||
Enemy::updatePosition();
|
||||
setOverrides(true, jointChest, jointHead);
|
||||
lookAt(target);
|
||||
}
|
||||
|
||||
virtual void deactivate(bool removeFromList = false) {
|
||||
if (!removeFromList) {
|
||||
if (!explodeMask)
|
||||
explode(0xffffffff);
|
||||
return;
|
||||
}
|
||||
Enemy::deactivate(removeFromList);
|
||||
}
|
||||
|
||||
virtual void update() {
|
||||
bool exploded = explodeMask != 0;
|
||||
|
||||
Enemy::update();
|
||||
|
||||
if (exploded && !explodeMask) {
|
||||
deactivate(true);
|
||||
flags.invisible = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -2123,8 +2257,8 @@ struct Human : Enemy {
|
||||
STATE_FIRE
|
||||
};
|
||||
|
||||
int jointGun;
|
||||
int animDeath;
|
||||
int jointGun;
|
||||
int animDeath;
|
||||
|
||||
Human(IGame *game, int entity, float health) : Enemy(game, entity, health, 100, 375.0f, 1.0f), animDeath(-1) {
|
||||
jointGun = 0;
|
||||
@ -2166,28 +2300,11 @@ struct Human : Enemy {
|
||||
|
||||
virtual void onDead() {}
|
||||
|
||||
bool targetIsVisible() {
|
||||
if (targetInView && targetDist < HUMAN_DIST_SHOT && target->health > 0.0f) {
|
||||
TR::Location from, to;
|
||||
from.room = getRoomIndex();
|
||||
from.pos = pos;
|
||||
to.pos = target->pos;
|
||||
|
||||
// vertical offset to ~gun/head height
|
||||
from.pos.y -= 768.0f;
|
||||
if (target->stand != STAND_UNDERWATER && target->stand != STAND_ONWATER)
|
||||
to.pos.y -= 768.0f;
|
||||
|
||||
return trace(from, to);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool doShot(float damage, const vec3 &muzzleOffset) {
|
||||
game->addMuzzleFlash(this, jointGun, muzzleOffset, -1);
|
||||
|
||||
if (targetDist < HUMAN_DIST_SHOT && randf() < ((HUMAN_DIST_SHOT - targetDist) / HUMAN_DIST_SHOT - 0.25f)) {
|
||||
bite(target->getJoint(rand() % target->getModel()->mCount).pos, damage);
|
||||
bite(rand() % target->getModel()->mCount, vec3(0.0f), damage);
|
||||
game->playSound(target->stand == STAND_UNDERWATER ? TR::SND_HIT_UNDERWATER : TR::SND_HIT, target->pos, Sound::PAN);
|
||||
return true;
|
||||
}
|
||||
@ -2244,7 +2361,7 @@ struct Larson : Human {
|
||||
nextState = STATE_WAIT;
|
||||
else if (mood == MOOD_ESCAPE)
|
||||
nextState = STATE_RUN;
|
||||
else if (targetIsVisible())
|
||||
else if (targetIsVisible(HUMAN_DIST_SHOT))
|
||||
nextState = STATE_AIM;
|
||||
else if (!targetInView || targetDist > HUMAN_DIST_WALK)
|
||||
nextState = STATE_RUN;
|
||||
@ -2254,7 +2371,7 @@ struct Larson : Human {
|
||||
case STATE_RUN :
|
||||
if (mood == MOOD_SLEEP && randf() < HUMAN_WAIT)
|
||||
nextState = STATE_WAIT;
|
||||
else if (targetIsVisible())
|
||||
else if (targetIsVisible(HUMAN_DIST_SHOT))
|
||||
nextState = STATE_AIM;
|
||||
else if (targetInView && targetDist < HUMAN_DIST_WALK)
|
||||
nextState = STATE_WALK;
|
||||
@ -2264,7 +2381,7 @@ struct Larson : Human {
|
||||
case STATE_AIM :
|
||||
if (nextState != STATE_NONE)
|
||||
return nextState;
|
||||
if (targetIsVisible())
|
||||
if (targetIsVisible(HUMAN_DIST_SHOT))
|
||||
return STATE_FIRE;
|
||||
return STATE_STOP;
|
||||
case STATE_FIRE :
|
||||
|
@ -191,7 +191,7 @@
|
||||
E( WATERFALL ) \
|
||||
E( NATLA_BULLET ) \
|
||||
E( MUTANT_BULLET ) \
|
||||
E( MUTANT_GRENADE ) \
|
||||
E( CENTAUR_BULLET ) \
|
||||
E( UNUSED_16 ) \
|
||||
E( UNUSED_17 ) \
|
||||
E( LAVA_PARTICLE ) \
|
||||
@ -1790,7 +1790,7 @@ namespace TR {
|
||||
}
|
||||
|
||||
bool isDoor() const {
|
||||
return type >= DOOR_1 && type <= DOOR_6;
|
||||
return type >= DOOR_1 && type <= DOOR_8;
|
||||
}
|
||||
|
||||
bool isCollider() const {
|
||||
|
@ -476,7 +476,6 @@ struct Lara : Character {
|
||||
if (level->extra.braid > -1)
|
||||
braid = new Braid(this, (level->version & (TR::VER_TR2 | TR::VER_TR3)) ? vec3(-2.0f, -16.0f, -48.0f) : vec3(-4.0f, 24.0f, -48.0f));
|
||||
|
||||
#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)
|
||||
@ -522,6 +521,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(53, vec3(39617, -18385, 48950), 180 * DEG2RAD); // Level 10b (centaur)
|
||||
//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)
|
||||
@ -529,7 +529,6 @@ struct Lara : Character {
|
||||
//reset(21, vec3(47668, -10752, 32163), 0); // Level 10c (lava emitter)
|
||||
//reset(10, vec3(90443, 11264 - 256, 114614), PI, STAND_ONWATER); // villa mortal 2
|
||||
//dbgBoxes = NULL;
|
||||
#endif
|
||||
|
||||
if (!level->isCutsceneLevel()) {
|
||||
if (getRoom().flags.water) {
|
||||
|
20
src/level.h
20
src/level.h
@ -859,6 +859,9 @@ struct Level : IGame {
|
||||
case TR::Entity::MIDAS_HAND : return new MidasHand(this, index);
|
||||
case TR::Entity::SCION_TARGET : return new ScionTarget(this, index);
|
||||
case TR::Entity::WATERFALL : return new Waterfall(this, index);
|
||||
case TR::Entity::NATLA_BULLET :
|
||||
case TR::Entity::MUTANT_BULLET :
|
||||
case TR::Entity::CENTAUR_BULLET : return new Bullet(this, index);
|
||||
case TR::Entity::TRAP_LAVA : return new TrapLava(this, index);
|
||||
case TR::Entity::BUBBLE : return new Bubble(this, index);
|
||||
case TR::Entity::EXPLOSION : return new Explosion(this, index);
|
||||
@ -1471,10 +1474,19 @@ struct Level : IGame {
|
||||
if (isModel) { // model
|
||||
vec3 pos = controller->getPos();
|
||||
if (ambientCache) {
|
||||
AmbientCache::Cube cube;
|
||||
ambientCache->getAmbient(roomIndex, pos, cube);
|
||||
if (cube.status == AmbientCache::Cube::READY)
|
||||
memcpy(controller->ambient, cube.colors, sizeof(cube.colors)); // store last calculated ambient into controller
|
||||
if (!controller->getEntity().isDoor()) { // no advanced ambient lighting for secret (all) doors
|
||||
AmbientCache::Cube cube;
|
||||
ambientCache->getAmbient(roomIndex, pos, cube);
|
||||
if (cube.status == AmbientCache::Cube::READY)
|
||||
memcpy(controller->ambient, cube.colors, sizeof(cube.colors)); // store last calculated ambient into controller
|
||||
} else {
|
||||
controller->ambient[0] =
|
||||
controller->ambient[1] =
|
||||
controller->ambient[2] =
|
||||
controller->ambient[3] =
|
||||
controller->ambient[4] =
|
||||
controller->ambient[5] = vec4(Core::active.material.y);
|
||||
}
|
||||
Core::active.shader->setParam(uAmbient, controller->ambient[0], 6);
|
||||
}
|
||||
}
|
||||
|
@ -1547,4 +1547,76 @@ struct StoneItem : Controller {
|
||||
}
|
||||
};
|
||||
|
||||
#define CENTAUR_BULLET_DIST SQR(1024.0f)
|
||||
#define CENTAUR_BULLET_DAMAGE 100.0f
|
||||
|
||||
struct Bullet : Controller {
|
||||
vec3 velocity;
|
||||
|
||||
Bullet(IGame *game, int entity) : Controller(game, entity) {
|
||||
velocity = vec3(200.0f) * 30.0f;
|
||||
intensity = 4096;
|
||||
activate();
|
||||
}
|
||||
|
||||
void setAngle(const vec3 &ang) {
|
||||
angle = ang;
|
||||
float speed;
|
||||
switch (getEntity().type) {
|
||||
case TR::Entity::NATLA_BULLET : speed = 220.0f; break;
|
||||
case TR::Entity::MUTANT_BULLET : speed = 250.0f; break;
|
||||
case TR::Entity::CENTAUR_BULLET : speed = 220.0f; break;
|
||||
default : speed = 200.0f;
|
||||
}
|
||||
velocity = getDir() * (speed * 30.0f);
|
||||
}
|
||||
|
||||
virtual void update() {
|
||||
//getRoom().removeDynLight(entity);
|
||||
pos = pos + velocity * Core::deltaTime;
|
||||
|
||||
game->getLevel()->getSector(roomIndex, pos);
|
||||
|
||||
Controller::update();
|
||||
//getRoom().addDynLight(entity, pos, vec4(1, 1, 0, 1.0f / 1024.0f));
|
||||
|
||||
bool directHit = false;
|
||||
|
||||
Character *lara = (Character*)game->getLara(pos);
|
||||
if (!collide(lara)) {
|
||||
TR::Level::FloorInfo info;
|
||||
getFloorInfo(getRoomIndex(), pos, info);
|
||||
if (!(pos.y > info.floor || pos.y < info.ceiling || !insideRoom(pos, getRoomIndex())))
|
||||
return;
|
||||
} else
|
||||
directHit = true;
|
||||
|
||||
//getRoom().removeDynLight(entity);
|
||||
switch (getEntity().type) {
|
||||
case TR::Entity::CENTAUR_BULLET :
|
||||
if (directHit) {
|
||||
lara->hit(CENTAUR_BULLET_DAMAGE);
|
||||
game->playSound(lara->stand == Character::STAND_UNDERWATER ? TR::SND_HIT_UNDERWATER : TR::SND_HIT, lara->pos, Sound::PAN);
|
||||
} else {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Controller *lara = game->getLara(i);
|
||||
if (!lara) continue;
|
||||
|
||||
float dist = (pos - lara->pos).length2();
|
||||
if (dist < CENTAUR_BULLET_DIST)
|
||||
lara->hit(CENTAUR_BULLET_DAMAGE * (CENTAUR_BULLET_DIST - dist) / CENTAUR_BULLET_DIST);
|
||||
}
|
||||
}
|
||||
|
||||
game->addEntity(TR::Entity::EXPLOSION, getRoomIndex(), pos);
|
||||
break;
|
||||
case TR::Entity::MUTANT_BULLET :
|
||||
game->getLara()->addRicochet(pos, true);
|
||||
break;
|
||||
default : ;
|
||||
}
|
||||
game->removeEntity(this);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user