1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-17 18:36:43 +02:00

#23 fix water; #14 crocodile basic logic

This commit is contained in:
XProger
2018-03-13 10:14:52 +03:00
parent c0ef6c1ce9
commit 64438c3ec1
8 changed files with 273 additions and 36 deletions

View File

@@ -328,7 +328,7 @@ struct AmbientCache {
bool needFlip = task.flip != level->state.flags.flipped;
if (needFlip) game->flipMap();
if (needFlip) game->flipMap(false);
int sector = task.sector;
if (task.flip) {
@@ -337,7 +337,7 @@ struct AmbientCache {
}
renderAmbient(task.room, sector, &task.cube->colors[0]);
if (needFlip) game->flipMap();
if (needFlip) game->flipMap(false);
task.cube->status = Cube::READY;
}
@@ -628,7 +628,7 @@ struct WaterCache {
vec3 p;
p.x = (drop.pos.x - (item.pos.x - item.size.x)) * DETAIL;
p.z = (drop.pos.z - (item.pos.z - item.size.z)) * DETAIL;
Core::active.shader->setParam(uParam, vec4(p.x, p.z, drop.radius * DETAIL, drop.strength));
Core::active.shader->setParam(uParam, vec4(p.x, p.z, drop.radius * DETAIL, -drop.strength));
item.data[0]->bind(sDiffuse);
Core::setTarget(item.data[1], CLEAR_ALL);

View File

@@ -83,6 +83,16 @@ struct Character : Controller {
return index;
}
virtual TR::Room& getLightRoom() {
if (stand == STAND_ONWATER) {
int16 rIndex = getRoomIndex();
TR::Room::Sector *sector = level->getSector(rIndex, pos);
if (sector && sector->roomAbove != TR::NO_ROOM)
return level->rooms[sector->roomAbove];
}
return Controller::getLightRoom();
}
bool updateZone() {
if (level->isCutsceneLevel())
return false;

View File

@@ -64,7 +64,7 @@ struct IGame {
virtual bool isCutscene() { return false; }
virtual uint16 getRandomBox(uint16 zone, uint16 *zones) { return 0; }
virtual uint16 findPath(int ascend, int descend, bool big, int boxStart, int boxEnd, uint16 *zones, uint16 **boxes) { return 0; }
virtual void flipMap() {}
virtual void flipMap(bool water = true) {}
virtual void setClipParams(float clipSign, float clipHeight) {}
virtual void setWaterParams(float height) {}
virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
@@ -1085,13 +1085,17 @@ struct Controller {
updateExplosion();
updateLights(true);
}
virtual TR::Room& getLightRoom() {
return getRoom();
}
void updateLights(bool lerp = true) {
TR::Room::Light sunLight;
if (getModel()) {
const TR::Room &room = getRoom();
const TR::Room &room = getLightRoom();
if (getModel()) {
vec3 center = getBoundingBox().center();
float maxAtt = 0.0f;
/*
@@ -1131,7 +1135,7 @@ struct Controller {
vec4 tcolor = vec4(vec3(targetLight->color.r, targetLight->color.g, targetLight->color.b) * (1.0f / 255.0f), float(targetLight->radius));
if (mainLightFlip != level->state.flags.flipped) {
if (getRoom().alternateRoom > -1)
if (room.alternateRoom > -1)
lerp = false;
mainLightFlip = level->state.flags.flipped;
}

View File

@@ -648,7 +648,7 @@ struct Lion : Enemy {
STATE_BITE ,
};
Lion(IGame *game, int entity) : Enemy(game, entity, 6, 341, 375.0f, 0.25f) {
Lion(IGame *game, int entity) : Enemy(game, entity, 6, 341, 400.0f, 0.25f) {
dropHeight = -1024;
jointChest = 19;
jointHead = 20;
@@ -756,15 +756,16 @@ struct Lion : Enemy {
struct Rat : Enemy {
enum {
HIT_MASK = 0x300018F,
HIT_MASK = 0x0300018F,
};
enum {
ANIM_GROUND_DEATH = 8,
ANIM_WATER_DEATH = 2,
ANIM_DEATH_LAND = 8,
ANIM_DEATH_WATER = 2,
};
enum {
// land
STATE_NONE ,
STATE_STOP ,
STATE_ATTACK ,
@@ -772,8 +773,9 @@ struct Rat : Enemy {
STATE_BITE ,
STATE_DEATH ,
STATE_WAIT ,
// water
STATE_WATER_SWIM = 1,
STATE_WATER_ATTACK ,
STATE_WATER_BITE ,
STATE_WATER_DEATH ,
};
@@ -889,9 +891,9 @@ struct Rat : Enemy {
switch (state) {
case STATE_WATER_SWIM :
if (targetInView && (collide(target) & HIT_MASK))
return STATE_WATER_ATTACK;
return STATE_WATER_BITE;
break;
case STATE_WATER_ATTACK :
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);
@@ -926,10 +928,224 @@ struct Rat : Enemy {
bool water = getRoom().flags.water;
if ((water && state == STATE_WATER_DEATH) || (!water && state == STATE_DEATH))
return state;
return animation.setAnim(water ? ANIM_WATER_DEATH : ANIM_GROUND_DEATH);
return animation.setAnim(water ? ANIM_DEATH_WATER : ANIM_DEATH_LAND);
}
};
#define CROCODILE_TURN_SLOW (DEG2RAD * 90)
#define CROCODILE_TURN_FAST (DEG2RAD * 180)
#define CROCODILE_DIST_BITE 435.0f
#define CROCODILE_DIST_TURN (1024 * 3)
#define CROCODILE_LIFT_SPEED 960.0f
#define CROCODILE_DAMAGE 25
struct Crocodile : Enemy {
enum {
HIT_MASK = 0x000003FC,
};
enum {
ANIM_DEATH_LAND = 11,
ANIM_DEATH_WATER = 4,
};
enum {
// land
STATE_NONE ,
STATE_STOP ,
STATE_RUN ,
STATE_WALK ,
STATE_TURN ,
STATE_BITE ,
STATE_UNUSED ,
STATE_DEATH ,
// water
STATE_WATER_SWIM = 1,
STATE_WATER_BITE ,
STATE_WATER_DEATH ,
};
int modelLand, modelWater;
Crocodile(IGame *game, int entity) : Enemy(game, entity, 20, 341, 600.0f, 0.25f) {
jointChest = 1;
jointHead = 8;
modelLand = level->getModelIndex(TR::Entity::ENEMY_CROCODILE_LAND) - 1;
modelWater = level->getModelIndex(TR::Entity::ENEMY_CROCODILE_WATER) - 1;
bool water = getRoom().flags.water;
flying = water;
stand = water ? STAND_UNDERWATER : STAND_GROUND;
}
const virtual TR::Model* getModel() {
bool water = getRoom().flags.water;
int modelIndex = water ? modelWater : modelLand;
ASSERT(modelIndex > -1);
const TR::Model *model = &level->models[modelIndex];
if (animation.model != model) {
targetBox = -1;
animation.setModel(model);
stand = water ? STAND_UNDERWATER : STAND_GROUND;
flying = water;
int16 rIndex = getRoomIndex();
if (water) {
TR::Room::Sector *sector = level->getWaterLevelSector(rIndex, pos);
if (sector) {
pos.y = float(sector->ceiling * 256);
roomIndex = rIndex;
}
} else {
int16 rIndex = getRoomIndex();
TR::Room::Sector *sector = level->getSector(rIndex, pos);
if (sector) {
pos.y = float(sector->floor * 256);
roomIndex = rIndex;
}
}
nextState = STATE_NONE;
state = STATE_NONE;
if (health <= 0.0f) {
getStateDeath();
animation.goEnd(false);
}
updateZone();
}
return animation.model;
}
virtual int getStateGround() {
if (!think(true))
return state;
float angle;
getTargetInfo(0, NULL, NULL, &angle, NULL);
if (nextState == state)
nextState = STATE_NONE;
bool isBite = targetInView && fabsf(target->pos.y - pos.y) < 256.0f;
switch (state) {
case STATE_STOP :
if (isBite && targetDist < CROCODILE_DIST_BITE)
return STATE_BITE;
switch (mood) {
case MOOD_ESCAPE : return STATE_RUN;
case MOOD_ATTACK : return STATE_RUN; // TODO: turn
case MOOD_STALK : return STATE_WALK;
default : return state;
}
case STATE_RUN :
if (targetInView && (collide(target) & HIT_MASK))
return STATE_STOP;
switch (mood) {
case MOOD_SLEEP : return STATE_STOP;
case MOOD_STALK : return STATE_WALK;
case MOOD_ATTACK : if (targetDist < CROCODILE_DIST_TURN) return STATE_STOP; // TODO: check turn angles
default : return state;
}
case STATE_WALK :
if (targetInView && (collide(target) & HIT_MASK))
return STATE_STOP;
switch (mood) {
case MOOD_SLEEP : return STATE_STOP;
case MOOD_ATTACK :
case MOOD_ESCAPE : return STATE_RUN;
default : return state;
}
case STATE_TURN : // TODO turn
return STATE_WALK;
case STATE_BITE :
if (nextState == STATE_NONE) {
bite(getJoint(jointHead).pos, CROCODILE_DAMAGE);
nextState = STATE_STOP;
}
break;
default : ;
}
return state;
}
virtual int getStateUnderwater() {
if (!think(false))
return state;
float angle;
getTargetInfo(0, NULL, NULL, &angle, NULL);
if (nextState == state)
nextState = STATE_NONE;
if (animation.frameIndex % 4 == 0)
game->waterDrop(getJoint(jointHead).pos, 96.0f, 0.02f);
switch (state) {
case STATE_WATER_SWIM :
if (targetInView && collide(target))
return STATE_WATER_BITE;
break;
case STATE_WATER_BITE :
if (collide(target)) {
if (nextState != STATE_NONE)
return state;
bite(getJoint(jointHead).pos, CROCODILE_DAMAGE);
nextState = STATE_WATER_SWIM;
}
return STATE_WATER_SWIM;
default : ;
}
return state;
}
virtual void updatePosition() {
float angleY = 0.0f;
if ((stand == STAND_GROUND && (state == STATE_RUN || state == STATE_WALK)) || (stand == STAND_UNDERWATER && state == STATE_WATER_SWIM))
getTargetInfo(0, NULL, NULL, &angleY, NULL);
turn(angleY, RAT_TURN_FAST);
if (state == STATE_DEATH) {
animation.overrideMask = 0;
return;
}
if (flying) {
lift(waypoint.y - pos.y, CROCODILE_LIFT_SPEED);
int16 rIndex = getRoomIndex();
TR::Room::Sector *sector = level->getWaterLevelSector(rIndex, pos);
if (sector) {
float waterLevel = float(sector->ceiling * 256) + 256;
if (pos.y < waterLevel)
pos.y = waterLevel;
}
}
Enemy::updatePosition();
setOverrides(state != STATE_DEATH, jointChest, jointHead);
lookAt(target);
}
virtual int getStateDeath() {
bool water = getRoom().flags.water;
if ((water && state == STATE_WATER_DEATH) || (!water && state == STATE_DEATH))
return state;
return animation.setAnim(water ? ANIM_DEATH_WATER : ANIM_DEATH_LAND);
}
};
#define BEAR_DIST_EAT 768
#define BEAR_DIST_HOWL 2048
#define BEAR_DIST_BITE 1024

View File

@@ -3762,7 +3762,6 @@ namespace TR {
if (type == spriteSequences[i].type)
return -(i + 1);
ASSERT(false);
return 0;
}

View File

@@ -2590,6 +2590,9 @@ struct Lara : Character {
// scion debug (TODO: remove)
if (Input::down[ikP]) {
switch (level->id) {
case TR::LVL_TR1_GYM :
reset(14, vec3(40448, 3584, 60928), PI * 0.5f, STAND_ONWATER); // gym (pool)
break;
case TR::LVL_TR1_2 :
reset(61, vec3(21987, -1024, 29144), PI * 3.0f * 0.5f); // level 2 (trap door)
break;

View File

@@ -330,9 +330,9 @@ struct Level : IGame {
}
}
virtual void flipMap() {
virtual void flipMap(bool water = true) {
updateBlocks(false);
if (waterCache) waterCache->flipMap();
if (water && waterCache) waterCache->flipMap();
mesh->flipMap();
level.flipMap();
updateBlocks(true);
@@ -372,18 +372,24 @@ struct Level : IGame {
Core::lightColor[3] = vec4(0, 0, 0, 1);
}
if (room.flags.water)
setWaterParams(float(room.info.yTop));
else
setWaterParams(NO_CLIP_PLANE);
setShader(Core::pass, type, room.flags.water, alphaTest);
if (room.flags.water) {
if (waterCache)
waterCache->bindCaustics(roomIndex);
setWaterParams(float(room.info.yTop));
}
if (room.waterLevel == -1) { // TODO: precalculate
int16 rIndex = roomIndex;
TR::Room::Sector *sector = level.getWaterLevelSector(rIndex, room.getOffset() + vec3(512, 0, 512));
if (sector)
setWaterParams(float(sector->ceiling * 256));
else
setWaterParams(float(room.info.yTop));
} else
setWaterParams(float(room.waterLevel));
} else
setWaterParams(NO_CLIP_PLANE);
Core::active.shader->setParam(uParam, Core::params);
Core::setMaterial(diffuse, ambient, specular, alpha);
@@ -760,7 +766,7 @@ struct Level : IGame {
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_CROCODILE_WATER : return new Crocodile(this, index);
case TR::Entity::ENEMY_GORILLA : return new Enemy(this, index, 100, 10, 0.0f, 0.0f);
case TR::Entity::ENEMY_LARSON : return new Larson(this, index);
case TR::Entity::ENEMY_PIERRE : return new Pierre(this, index);

View File

@@ -83,9 +83,9 @@ uniform sampler2D sNormal;
#define PI 3.141592653589793
float calcFresnel(float NdotL, float fbias, float fpow) {
float f = 1.0 - abs(NdotL);
return clamp(fbias + (1.0 - fbias) * pow(f, fpow), 0.0, 1.0);
float calcFresnel(float NdotL, float fbias) {
float f = 1.0 - NdotL;
return clamp(fbias + (1.0 - fbias) * (f * f), 0.0, 1.0);
}
vec3 applyFog(vec3 color, vec3 fogColor, float factor) {
@@ -132,7 +132,7 @@ uniform sampler2D sNormal;
}
float h(vec2 tc) {
return simplex_noise(vec3(tc * 16.0, uParam.w)) * 0.001;
return simplex_noise(vec3(tc * 16.0, uParam.w)) * 0.0005;
}
vec4 calc() {
@@ -149,7 +149,7 @@ uniform sampler2D sNormal;
float average = dot(f, vec4(0.25));
// normal
v.zw = normalize( vec3(f.x - f.z, 64.0 / (1024.0 * 2.0), f.y - f.w) ).xz;
v.zw = normalize( vec3(f.x - f.z, 64.0 / (1024.0 * 4.0), f.y - f.w) ).xz;
// integrate
const float vel = 1.4;
@@ -176,13 +176,12 @@ uniform sampler2D sNormal;
}
vec4 compose() {
vec3 viewVec = normalize(vViewVec);
vec4 value = texture2D(sNormal, vTexCoord);
vec3 normal = vec3(value.z, -sqrt(1.0 - dot(value.zw, value.zw)), value.w);
vec3 normal = vec3(value.z, sqrt(1.0 - dot(value.zw, value.zw)) * sign(viewVec.y), value.w);
vec2 dudv = (uViewProj * vec4(normal.x, 0.0, normal.z, 0.0)).xy;
vec3 viewVec = normalize(vViewVec);
vec3 rv = reflect(-viewVec, normal);
vec3 lv = normalize(vLightVec);
@@ -195,7 +194,7 @@ uniform sampler2D sNormal;
vec4 refr = vec4(mix(refrA.xyz, refrB.xyz, refrA.w), 1.0);
vec4 refl = texture2D(sReflect, vec2(tc.x, 1.0 - tc.y) + dudv * uParam.w);
float fresnel = calcFresnel(dot(normal, viewVec), 0.1, 2.0);
float fresnel = calcFresnel(dot(normal, viewVec), 0.04);
vec4 color = mix(refr, refl, fresnel) + spec * 1.5;