mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-15 09:34:18 +02:00
#22 add midas hand logic and death; #3 multiple pickups, fix surfacing for flipmaps; #11 fix inventory after death; #23 mipmap generation for cubemap textures
This commit is contained in:
@@ -166,8 +166,11 @@ struct Camera : ICamera {
|
|||||||
if (indexA == level->cameraFramesCount - 1) {
|
if (indexA == level->cameraFramesCount - 1) {
|
||||||
if (level->cutEntity != -1)
|
if (level->cutEntity != -1)
|
||||||
game->loadLevel(TR::LevelID(level->id + 1));
|
game->loadLevel(TR::LevelID(level->id + 1));
|
||||||
else
|
else {
|
||||||
state = STATE_FOLLOW;
|
Character *lara = (Character*)game->getLara();
|
||||||
|
if (lara->health > 0.0f)
|
||||||
|
state = STATE_FOLLOW;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TR::CameraFrame *frameA = &level->cameraFrames[indexA];
|
TR::CameraFrame *frameA = &level->cameraFrames[indexA];
|
||||||
|
@@ -97,7 +97,11 @@ struct Character : Controller {
|
|||||||
e.room = info.roomBelow;
|
e.room = info.roomBelow;
|
||||||
|
|
||||||
if (info.roomAbove != TR::NO_ROOM && e.y <= info.roomCeiling) {
|
if (info.roomAbove != TR::NO_ROOM && e.y <= info.roomCeiling) {
|
||||||
if (stand == STAND_UNDERWATER && !level->rooms[info.roomAbove].flags.water) {
|
TR::Room *room = &level->rooms[info.roomAbove];
|
||||||
|
if (level->isFlipped && room->alternateRoom > -1)
|
||||||
|
room = &level->rooms[room->alternateRoom];
|
||||||
|
|
||||||
|
if (stand == STAND_UNDERWATER && !room->flags.water) {
|
||||||
stand = STAND_ONWATER;
|
stand = STAND_ONWATER;
|
||||||
velocity.y = 0;
|
velocity.y = 0;
|
||||||
pos.y = float(info.roomCeiling);
|
pos.y = float(info.roomCeiling);
|
||||||
|
@@ -25,6 +25,7 @@ struct ICamera {
|
|||||||
|
|
||||||
virtual void setup(bool calcMatrices) {}
|
virtual void setup(bool calcMatrices) {}
|
||||||
virtual int getRoomIndex() const { return TR::NO_ROOM; }
|
virtual int getRoomIndex() const { return TR::NO_ROOM; }
|
||||||
|
virtual void doCutscene(const vec3 &pos, float rotation) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IGame {
|
struct IGame {
|
||||||
@@ -45,6 +46,7 @@ struct IGame {
|
|||||||
virtual void setWaterParams(float height) {}
|
virtual void setWaterParams(float height) {}
|
||||||
virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
|
virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
|
||||||
virtual void setShader(Core::Pass pass, Shader::Type type, bool underwater = false, bool alphaTest = false) {}
|
virtual void setShader(Core::Pass pass, Shader::Type type, bool underwater = false, bool alphaTest = false) {}
|
||||||
|
virtual void setRoomParams(int roomIndex, Shader::Type type, float diffuse, float ambient, float specular, float alpha, bool alphaTest = false) {}
|
||||||
virtual void setupBinding() {}
|
virtual void setupBinding() {}
|
||||||
virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {}
|
virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {}
|
||||||
virtual void renderCompose(int roomIndex) {}
|
virtual void renderCompose(int roomIndex) {}
|
||||||
@@ -98,6 +100,7 @@ struct Controller {
|
|||||||
uint32 mask;
|
uint32 mask;
|
||||||
} *layers;
|
} *layers;
|
||||||
|
|
||||||
|
uint32 visibleMask;
|
||||||
uint32 explodeMask;
|
uint32 explodeMask;
|
||||||
struct ExplodePart {
|
struct ExplodePart {
|
||||||
Basis basis;
|
Basis basis;
|
||||||
@@ -120,6 +123,7 @@ struct Controller {
|
|||||||
ambient[0] = ambient[1] = ambient[2] = ambient[3] = ambient[4] = ambient[5] = vec3(intensityf(getRoom().ambient));
|
ambient[0] = ambient[1] = ambient[2] = ambient[3] = ambient[4] = ambient[5] = vec3(intensityf(getRoom().ambient));
|
||||||
targetLight = NULL;
|
targetLight = NULL;
|
||||||
updateLights(false);
|
updateLights(false);
|
||||||
|
visibleMask = 0xFFFFFFFF;
|
||||||
|
|
||||||
if (e.flags.once) {
|
if (e.flags.once) {
|
||||||
e.flags.invisible = true;
|
e.flags.invisible = true;
|
||||||
@@ -762,6 +766,7 @@ struct Controller {
|
|||||||
|
|
||||||
for (int i = MAX_LAYERS - 1; i >= 0; i--) {
|
for (int i = MAX_LAYERS - 1; i >= 0; i--) {
|
||||||
uint32 vmask = (layers[i].mask & ~mask) | (!i ? explodeMask : 0);
|
uint32 vmask = (layers[i].mask & ~mask) | (!i ? explodeMask : 0);
|
||||||
|
vmask &= visibleMask;
|
||||||
if (!vmask) continue;
|
if (!vmask) continue;
|
||||||
mask |= layers[i].mask;
|
mask |= layers[i].mask;
|
||||||
// set meshes visibility
|
// set meshes visibility
|
||||||
@@ -769,6 +774,7 @@ struct Controller {
|
|||||||
joints[j].w = (vmask & (1 << j)) ? 1.0f : -1.0f; // AHAHA
|
joints[j].w = (vmask & (1 << j)) ? 1.0f : -1.0f; // AHAHA
|
||||||
|
|
||||||
if (explodeMask) {
|
if (explodeMask) {
|
||||||
|
ASSERT(explodeParts);
|
||||||
TR::Model *model = getModel();
|
TR::Model *model = getModel();
|
||||||
for (int i = 0; i < model->mCount; i++)
|
for (int i = 0; i < model->mCount; i++)
|
||||||
if (explodeMask & (1 << i))
|
if (explodeMask & (1 << i))
|
||||||
|
@@ -668,6 +668,7 @@ namespace Core {
|
|||||||
|
|
||||||
memset(rtCache, 0, sizeof(rtCache));
|
memset(rtCache, 0, sizeof(rtCache));
|
||||||
defaultTarget = NULL;
|
defaultTarget = NULL;
|
||||||
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
|
||||||
Sound::init();
|
Sound::init();
|
||||||
|
|
||||||
|
22
src/format.h
22
src/format.h
@@ -139,7 +139,7 @@
|
|||||||
E( PUZZLE_DONE_4 ) \
|
E( PUZZLE_DONE_4 ) \
|
||||||
E( LEADBAR ) \
|
E( LEADBAR ) \
|
||||||
E( INV_LEADBAR ) \
|
E( INV_LEADBAR ) \
|
||||||
E( MIDAS_TOUCH ) \
|
E( MIDAS_HAND ) \
|
||||||
E( KEY_ITEM_1 ) \
|
E( KEY_ITEM_1 ) \
|
||||||
E( KEY_ITEM_2 ) \
|
E( KEY_ITEM_2 ) \
|
||||||
E( KEY_ITEM_3 ) \
|
E( KEY_ITEM_3 ) \
|
||||||
@@ -340,6 +340,7 @@ namespace TR {
|
|||||||
HIT_SLAM,
|
HIT_SLAM,
|
||||||
HIT_REX,
|
HIT_REX,
|
||||||
HIT_LIGHTNING,
|
HIT_LIGHTNING,
|
||||||
|
HIT_MIDAS,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Action : uint16 {
|
enum Action : uint16 {
|
||||||
@@ -393,8 +394,12 @@ namespace TR {
|
|||||||
0, -612, 30, {{-300, 0, -692}, {300, 0, -512}}, true, false
|
0, -612, 30, {{-300, 0, -692}, {300, 0, -512}}, true, false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Limit MIDAS = {
|
||||||
|
512, -612, 30, {{-700, 284, -700}, {700, 996, 700}}, true, false
|
||||||
|
};
|
||||||
|
|
||||||
Limit SCION = {
|
Limit SCION = {
|
||||||
640, -202, 30, {{-256, 540, -350}, {256, 740, -200}}, false, false
|
640, -202, 30, {{-256, 540, -350}, {256, 740, -200}}, false, false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -667,14 +672,16 @@ namespace TR {
|
|||||||
isDoor() ||
|
isDoor() ||
|
||||||
(type == DRAWBRIDGE && flags.active != ACTIVE) ||
|
(type == DRAWBRIDGE && flags.active != ACTIVE) ||
|
||||||
(type == SCION_HOLDER) ||
|
(type == SCION_HOLDER) ||
|
||||||
((type == HAMMER_HANDLE || type == HAMMER_BLOCK) && flags.collision);
|
((type == HAMMER_HANDLE || type == HAMMER_BLOCK) && flags.collision) ||
|
||||||
|
(type == CRYSTAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isItem() const {
|
bool isPickup() const {
|
||||||
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_QUALOPEC || type == SCION_DROP || type == SCION_NATLA || 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 {
|
bool isActor() const {
|
||||||
@@ -748,6 +755,7 @@ namespace TR {
|
|||||||
case KEY_HOLE_2 : return KEY_ITEM_2; break;
|
case KEY_HOLE_2 : return KEY_ITEM_2; break;
|
||||||
case KEY_HOLE_3 : return KEY_ITEM_3; break;
|
case KEY_HOLE_3 : return KEY_ITEM_3; break;
|
||||||
case KEY_HOLE_4 : return KEY_ITEM_4; break;
|
case KEY_HOLE_4 : return KEY_ITEM_4; break;
|
||||||
|
case MIDAS_HAND : return LEADBAR; break;
|
||||||
default : return NONE;
|
default : return NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1668,6 +1676,10 @@ namespace TR {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isCutsceneLevel() {
|
||||||
|
return cutEntity > -1;
|
||||||
|
}
|
||||||
|
|
||||||
void readMeshes(Stream &stream) {
|
void readMeshes(Stream &stream) {
|
||||||
uint32 meshDataSize;
|
uint32 meshDataSize;
|
||||||
stream.read(meshDataSize);
|
stream.read(meshDataSize);
|
||||||
|
@@ -190,6 +190,8 @@ struct Inventory {
|
|||||||
add(TR::Entity::INV_PUZZLE_2, 3);
|
add(TR::Entity::INV_PUZZLE_2, 3);
|
||||||
add(TR::Entity::INV_PUZZLE_3, 3);
|
add(TR::Entity::INV_PUZZLE_3, 3);
|
||||||
add(TR::Entity::INV_PUZZLE_4, 3);
|
add(TR::Entity::INV_PUZZLE_4, 3);
|
||||||
|
|
||||||
|
add(TR::Entity::INV_LEADBAR, 3);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,6 +353,9 @@ struct Inventory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
index = targetIndex = pageItemIndex[page];
|
index = targetIndex = pageItemIndex[page];
|
||||||
|
|
||||||
|
//if (type == TR::Entity::INV_PASSPORT) // toggle after death
|
||||||
|
// chooseItem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return active;
|
return active;
|
||||||
@@ -563,8 +568,8 @@ struct Inventory {
|
|||||||
|
|
||||||
if (index == targetIndex && targetPage == page && ready) {
|
if (index == targetIndex && targetPage == page && ready) {
|
||||||
if (!chosen) {
|
if (!chosen) {
|
||||||
if (key == cUp && !(page < PAGE_ITEMS && getItemsCount(page + 1))) key = cMAX;
|
if ((key == cUp && !canFlipPage(-1)) || (key == cDown && !canFlipPage( 1)))
|
||||||
if (key == cDown && !(page > PAGE_OPTION && getItemsCount(page - 1))) key = cMAX;
|
key = cMAX;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case cLeft : { phaseSelect = 0.0f; targetIndex = (targetIndex - 1 + count) % count; } break;
|
case cLeft : { phaseSelect = 0.0f; targetIndex = (targetIndex - 1 + count) % count; } break;
|
||||||
@@ -577,21 +582,8 @@ struct Inventory {
|
|||||||
if (index != targetIndex)
|
if (index != targetIndex)
|
||||||
game->playSound(TR::SND_INV_SPIN);
|
game->playSound(TR::SND_INV_SPIN);
|
||||||
|
|
||||||
if (lastKey != key && key == cAction && phaseChoose == 0.0f) {
|
if (lastKey != key && key == cAction && phaseChoose == 0.0f)
|
||||||
vec3 p;
|
chooseItem();
|
||||||
chosen = true;
|
|
||||||
switch (item->type) {
|
|
||||||
case TR::Entity::INV_COMPASS : game->playSound(TR::SND_INV_COMPASS); break;
|
|
||||||
case TR::Entity::INV_HOME : game->playSound(TR::SND_INV_HOME); break;
|
|
||||||
case TR::Entity::INV_CONTROLS : game->playSound(TR::SND_INV_CONTROLS); break;
|
|
||||||
case TR::Entity::INV_PISTOLS :
|
|
||||||
case TR::Entity::INV_SHOTGUN :
|
|
||||||
case TR::Entity::INV_MAGNUMS :
|
|
||||||
case TR::Entity::INV_UZIS : game->playSound(TR::SND_INV_WEAPON); break;
|
|
||||||
default : game->playSound(TR::SND_INV_SHOW); break;
|
|
||||||
}
|
|
||||||
item->choose();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (changeTimer > 0.0f) {
|
if (changeTimer > 0.0f) {
|
||||||
changeTimer -= Core::deltaTime;
|
changeTimer -= Core::deltaTime;
|
||||||
@@ -662,6 +654,32 @@ struct Inventory {
|
|||||||
game->loadLevel(nextLevel);
|
game->loadLevel(nextLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void chooseItem() {
|
||||||
|
Item *item = items[getGlobalIndex(page, index)];
|
||||||
|
|
||||||
|
vec3 p;
|
||||||
|
chosen = true;
|
||||||
|
switch (item->type) {
|
||||||
|
case TR::Entity::INV_COMPASS : game->playSound(TR::SND_INV_COMPASS); break;
|
||||||
|
case TR::Entity::INV_HOME : game->playSound(TR::SND_INV_HOME); break;
|
||||||
|
case TR::Entity::INV_CONTROLS : game->playSound(TR::SND_INV_CONTROLS); break;
|
||||||
|
case TR::Entity::INV_PISTOLS :
|
||||||
|
case TR::Entity::INV_SHOTGUN :
|
||||||
|
case TR::Entity::INV_MAGNUMS :
|
||||||
|
case TR::Entity::INV_UZIS : game->playSound(TR::SND_INV_WEAPON); break;
|
||||||
|
default : game->playSound(TR::SND_INV_SHOW); break;
|
||||||
|
}
|
||||||
|
item->choose();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canFlipPage(int dir) {
|
||||||
|
if (((Character*)game->getLara())->health <= 0.0f)
|
||||||
|
return false;
|
||||||
|
if (dir == -1) return page < PAGE_ITEMS && getItemsCount(page + 1);
|
||||||
|
if (dir == 1) return page > PAGE_OPTION && getItemsCount(page - 1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void prepareBackground() {
|
void prepareBackground() {
|
||||||
Core::setDepthTest(false);
|
Core::setDepthTest(false);
|
||||||
|
|
||||||
@@ -952,7 +970,7 @@ struct Inventory {
|
|||||||
Core::setDepthTest(true);
|
Core::setDepthTest(true);
|
||||||
Core::setBlending(bmAlpha);
|
Core::setBlending(bmAlpha);
|
||||||
|
|
||||||
if (game->isCutscene())
|
if (game->getLevel()->isCutsceneLevel())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// items
|
// items
|
||||||
@@ -1002,12 +1020,12 @@ struct Inventory {
|
|||||||
if (game->getLevel()->id != TR::TITLE)
|
if (game->getLevel()->id != TR::TITLE)
|
||||||
UI::textOut(vec2( 0, 32), pageTitle[page], UI::aCenter, UI::width);
|
UI::textOut(vec2( 0, 32), pageTitle[page], UI::aCenter, UI::width);
|
||||||
|
|
||||||
if (page < PAGE_ITEMS && getItemsCount(page + 1)) {
|
if (canFlipPage(-1)) {
|
||||||
UI::textOut(vec2(16, 32), "[", UI::aLeft, UI::width);
|
UI::textOut(vec2(16, 32), "[", UI::aLeft, UI::width);
|
||||||
UI::textOut(vec2( 0, 32), "[", UI::aRight, UI::width - 20);
|
UI::textOut(vec2( 0, 32), "[", UI::aRight, UI::width - 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page > PAGE_OPTION && getItemsCount(page - 1)) {
|
if (canFlipPage(1)) {
|
||||||
UI::textOut(vec2(16, 480 - 16), "]", UI::aLeft, UI::width);
|
UI::textOut(vec2(16, 480 - 16), "]", UI::aLeft, UI::width);
|
||||||
UI::textOut(vec2(0, 480 - 16), "]", UI::aRight, UI::width - 20);
|
UI::textOut(vec2(0, 480 - 16), "]", UI::aRight, UI::width - 20);
|
||||||
}
|
}
|
||||||
|
186
src/lara.h
186
src/lara.h
@@ -226,9 +226,11 @@ struct Lara : Character {
|
|||||||
} arms[2];
|
} arms[2];
|
||||||
|
|
||||||
TR::Entity::Type usedKey;
|
TR::Entity::Type usedKey;
|
||||||
TR::Entity *pickupEntity;
|
int pickupListCount;
|
||||||
|
TR::Entity *pickupList[32];
|
||||||
KeyHole *keyHole;
|
KeyHole *keyHole;
|
||||||
Lightning *lightning;
|
Lightning *lightning;
|
||||||
|
Texture *environment;
|
||||||
|
|
||||||
int roomPrev; // water out from room
|
int roomPrev; // water out from room
|
||||||
vec2 rotFactor;
|
vec2 rotFactor;
|
||||||
@@ -411,8 +413,9 @@ struct Lara : Character {
|
|||||||
damageTime = LARA_DAMAGE_TIME;
|
damageTime = LARA_DAMAGE_TIME;
|
||||||
hitTime = 0.0f;
|
hitTime = 0.0f;
|
||||||
|
|
||||||
keyHole = NULL;
|
keyHole = NULL;
|
||||||
lightning = NULL;
|
lightning = NULL;
|
||||||
|
environment = NULL;
|
||||||
|
|
||||||
getEntity().flags.active = 1;
|
getEntity().flags.active = 1;
|
||||||
initMeshOverrides();
|
initMeshOverrides();
|
||||||
@@ -460,11 +463,12 @@ struct Lara : Character {
|
|||||||
//reset(24, vec3(45609, 18176, 41500), 90 * DEG2RAD); // level 4 (thor)
|
//reset(24, vec3(45609, 18176, 41500), 90 * DEG2RAD); // level 4 (thor)
|
||||||
//reset(19, vec3(41418, -3707, 58863), 270 * DEG2RAD); // level 5 (triangle)
|
//reset(19, vec3(41418, -3707, 58863), 270 * DEG2RAD); // level 5 (triangle)
|
||||||
//reset(21, vec3(24106, -4352, 52089), 0); // level 6 (flame traps)
|
//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(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(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(77, vec3(36943, -4096, 62821), 270 * DEG2RAD); // level 7b (heavy trigger)
|
||||||
|
//reset(57, vec3(54844, -3328, 53145), 0); // level 8b (bridge switch
|
||||||
//reset(12, vec3(34236, -2415, 14974), 0); // level 8b (sphinx)
|
//reset(12, vec3(34236, -2415, 14974), 0); // level 8b (sphinx)
|
||||||
//reset(0, vec3(40913, -1012, 42252), PI); // level 8c
|
//reset(0, vec3(40913, -1012, 42252), PI); // level 8c
|
||||||
//reset(30, vec3(69689, -8448, 34922), 330 * DEG2RAD); // Level 10a (cabin)
|
//reset(30, vec3(69689, -8448, 34922), 330 * DEG2RAD); // Level 10a (cabin)
|
||||||
@@ -488,6 +492,7 @@ struct Lara : Character {
|
|||||||
|
|
||||||
virtual ~Lara() {
|
virtual ~Lara() {
|
||||||
delete braid;
|
delete braid;
|
||||||
|
delete environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getRoomByPos(const vec3 &pos) {
|
int getRoomByPos(const vec3 &pos) {
|
||||||
@@ -517,6 +522,9 @@ struct Lara : Character {
|
|||||||
if (level->rooms[room].flags.water) {
|
if (level->rooms[room].flags.water) {
|
||||||
stand = STAND_UNDERWATER;
|
stand = STAND_UNDERWATER;
|
||||||
animation.setAnim(ANIM_UNDERWATER);
|
animation.setAnim(ANIM_UNDERWATER);
|
||||||
|
} else {
|
||||||
|
stand = STAND_GROUND;
|
||||||
|
animation.setAnim(ANIM_STAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
velocity = vec3(0.0f);
|
velocity = vec3(0.0f);
|
||||||
@@ -1408,6 +1416,19 @@ struct Lara : Character {
|
|||||||
animation.setAnim(level->models[TR::MODEL_LARA_SPEC].animation + 1);
|
animation.setAnim(level->models[TR::MODEL_LARA_SPEC].animation + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case TR::HIT_MIDAS : {
|
||||||
|
// generate environment map for reflections
|
||||||
|
if (!environment)
|
||||||
|
environment = new Texture(256, 256, Texture::RGBA, true, NULL, true, true);
|
||||||
|
Core::beginFrame();
|
||||||
|
game->renderEnvironment(73, pos - vec3(0.0f, 384.0f, 0.0f), &environment);
|
||||||
|
environment->generateMipMap();
|
||||||
|
Core::endFrame();
|
||||||
|
// set death animation
|
||||||
|
animation.setAnim(level->models[TR::MODEL_LARA_SPEC].animation + 1);
|
||||||
|
game->getCamera()->doCutscene(pos, angle.y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default : ;
|
default : ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1427,6 +1448,8 @@ struct Lara : Character {
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool useItem(TR::Entity::Type item) {
|
bool useItem(TR::Entity::Type item) {
|
||||||
|
if (game->isCutscene()) return false;
|
||||||
|
|
||||||
switch (item) {
|
switch (item) {
|
||||||
case TR::Entity::INV_PISTOLS : wpnChange(Lara::Weapon::PISTOLS); break;
|
case TR::Entity::INV_PISTOLS : wpnChange(Lara::Weapon::PISTOLS); break;
|
||||||
case TR::Entity::INV_SHOTGUN : wpnChange(Lara::Weapon::SHOTGUN); break;
|
case TR::Entity::INV_SHOTGUN : wpnChange(Lara::Weapon::SHOTGUN); break;
|
||||||
@@ -1451,6 +1474,17 @@ struct Lara : Character {
|
|||||||
return false;
|
return false;
|
||||||
usedKey = item;
|
usedKey = item;
|
||||||
break;
|
break;
|
||||||
|
case TR::Entity::INV_LEADBAR :
|
||||||
|
for (int i = 0; i < level->entitiesCount; i++)
|
||||||
|
if (level->entities[i].type == TR::Entity::MIDAS_HAND) {
|
||||||
|
MidasHand *controller = (MidasHand*)level->entities[i].controller;
|
||||||
|
if (controller->interaction) {
|
||||||
|
controller->invItem = item;
|
||||||
|
return false; // remove item from inventory
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
default : return false;
|
default : return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -1488,46 +1522,68 @@ struct Lara : Character {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool doPickUp() {
|
bool doPickUp() {
|
||||||
if ((state != STATE_STOP && state != STATE_TREAD) || !animation.canSetState(STATE_PICK_UP))
|
if (!animation.canSetState(STATE_PICK_UP))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int room = getRoomIndex();
|
int room = getRoomIndex();
|
||||||
TR::Limits::Limit limit = state == STATE_STOP ? TR::Limits::PICKUP : TR::Limits::PICKUP_UNDERWATER;
|
|
||||||
|
pickupListCount = 0;
|
||||||
|
|
||||||
for (int i = 0; i < level->entitiesCount; i++) {
|
for (int i = 0; i < level->entitiesCount; i++) {
|
||||||
TR::Entity &item = level->entities[i];
|
TR::Entity &entity = level->entities[i];
|
||||||
if (!item.isItem())
|
if (!entity.isPickup())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Controller *controller = (Controller*)item.controller;
|
Controller *controller = (Controller*)entity.controller;
|
||||||
if (controller->getRoomIndex() == room && !item.flags.invisible) {
|
|
||||||
if (stand == STAND_UNDERWATER)
|
|
||||||
controller->angle.x = -25 * DEG2RAD;
|
|
||||||
controller->angle.y = angle.y;
|
|
||||||
|
|
||||||
if (item.type == TR::Entity::SCION_QUALOPEC)
|
// set item orientation to hack limits check
|
||||||
limit = TR::Limits::SCION;
|
if (stand == STAND_UNDERWATER)
|
||||||
|
controller->angle.x = -25 * DEG2RAD;
|
||||||
|
controller->angle.y = angle.y;
|
||||||
|
|
||||||
if (!checkInteraction(controller, limit, (input & ACTION) != 0))
|
if (controller->getRoomIndex() != room || entity.flags.invisible || !canPickup(controller))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (stand == STAND_UNDERWATER)
|
ASSERT(pickupListCount < COUNT(pickupList));
|
||||||
angle.x = -25 * DEG2RAD;
|
pickupList[pickupListCount++] = &entity;
|
||||||
|
|
||||||
pickupEntity = &item;
|
|
||||||
|
|
||||||
if (item.type == TR::Entity::SCION_QUALOPEC) {
|
|
||||||
animation.setAnim(level->models[TR::MODEL_LARA_SPEC].animation);
|
|
||||||
((Camera*)level->cameraController)->doCutscene(pos, angle.y);
|
|
||||||
} else
|
|
||||||
state = STATE_PICK_UP;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pickupListCount > 0) {
|
||||||
|
state = STATE_PICK_UP;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool canPickup(Controller *controller) {
|
||||||
|
TR::Entity &entity = controller->getEntity();
|
||||||
|
|
||||||
|
// get limits
|
||||||
|
TR::Limits::Limit *limit;
|
||||||
|
switch (entity.type) {
|
||||||
|
case TR::Entity::SCION_QUALOPEC : limit = &TR::Limits::SCION; break;
|
||||||
|
default : limit = level->rooms[getRoomIndex()].flags.water ? &TR::Limits::PICKUP_UNDERWATER : &TR::Limits::PICKUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkInteraction(controller, limit, true))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (stand == Character::STAND_UNDERWATER)
|
||||||
|
angle.x = -25 * DEG2RAD;
|
||||||
|
|
||||||
|
// set new state
|
||||||
|
switch (entity.type) {
|
||||||
|
case TR::Entity::SCION_QUALOPEC :
|
||||||
|
animation.setAnim(level->models[TR::MODEL_LARA_SPEC].animation);
|
||||||
|
game->getCamera()->doCutscene(pos, angle.y);
|
||||||
|
break;
|
||||||
|
default : ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int doTutorial(int track) {
|
int doTutorial(int track) {
|
||||||
switch (track) { // GYM tutorial routine
|
switch (track) { // GYM tutorial routine
|
||||||
case 28 : if (level->tracks[track].once && state == STATE_UP_JUMP) track = 29; break;
|
case 28 : if (level->tracks[track].once && state == STATE_UP_JUMP) track = 29; break;
|
||||||
@@ -1551,22 +1607,22 @@ struct Lara : Character {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool checkInteraction(Controller *controller, const TR::Limits::Limit &limit, bool action) {
|
bool checkInteraction(Controller *controller, const TR::Limits::Limit *limit, bool action) {
|
||||||
if ((state != STATE_STOP && state != STATE_TREAD && state != STATE_PUSH_PULL_READY) || !action || !emptyHands())
|
if ((state != STATE_STOP && state != STATE_TREAD && state != STATE_PUSH_PULL_READY) || !action || !emptyHands())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
mat4 m = controller->getMatrix();
|
mat4 m = controller->getMatrix();
|
||||||
|
|
||||||
float fx = 0.0f;
|
float fx = 0.0f;
|
||||||
if (!limit.alignHoriz)
|
if (!limit->alignHoriz)
|
||||||
fx = (m.transpose() * vec4(pos - controller->pos, 0.0f)).x;
|
fx = (m.transpose() * vec4(pos - controller->pos, 0.0f)).x;
|
||||||
|
|
||||||
vec3 targetPos = controller->pos + (m * vec4(fx, limit.dy, limit.dz, 0.0f)).xyz;
|
vec3 targetPos = controller->pos + (m * vec4(fx, limit->dy, limit->dz, 0.0f)).xyz;
|
||||||
|
|
||||||
vec3 deltaAbs = pos - targetPos;
|
vec3 deltaAbs = pos - targetPos;
|
||||||
vec3 deltaRel = (controller->getMatrix().transpose() * vec4(pos - controller->pos, 0.0f)).xyz; // inverse transform
|
vec3 deltaRel = (controller->getMatrix().transpose() * vec4(pos - controller->pos, 0.0f)).xyz; // inverse transform
|
||||||
|
|
||||||
if (limit.box.contains(deltaRel)) {
|
if (limit->box.contains(deltaRel)) {
|
||||||
float deltaAngY = shortAngle(angle.y, controller->angle.y);
|
float deltaAngY = shortAngle(angle.y, controller->angle.y);
|
||||||
|
|
||||||
if (stand == STAND_UNDERWATER) {
|
if (stand == STAND_UNDERWATER) {
|
||||||
@@ -1580,9 +1636,9 @@ struct Lara : Character {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fabsf(deltaAngY) <= limit.ay * DEG2RAD) {
|
if (fabsf(deltaAngY) <= limit->ay * DEG2RAD) {
|
||||||
// align
|
// align
|
||||||
if (limit.alignAngle)
|
if (limit->alignAngle)
|
||||||
angle = controller->angle;
|
angle = controller->angle;
|
||||||
else
|
else
|
||||||
angle.x = angle.z = 0.0f;
|
angle.x = angle.z = 0.0f;
|
||||||
@@ -1624,7 +1680,7 @@ struct Lara : Character {
|
|||||||
|
|
||||||
if (controller->activeState == asNone) {
|
if (controller->activeState == asNone) {
|
||||||
limit = state == STATE_STOP ? &TR::Limits::SWITCH : &TR::Limits::SWITCH_UNDERWATER;
|
limit = state == STATE_STOP ? &TR::Limits::SWITCH : &TR::Limits::SWITCH_UNDERWATER;
|
||||||
if (checkInteraction(controller, *limit, Input::state[cAction])) {
|
if (checkInteraction(controller, limit, Input::state[cAction])) {
|
||||||
actionState = (controller->state == Switch::STATE_DOWN && stand == STAND_GROUND) ? STATE_SWITCH_UP : STATE_SWITCH_DOWN;
|
actionState = (controller->state == Switch::STATE_DOWN && stand == STAND_GROUND) ? STATE_SWITCH_UP : STATE_SWITCH_DOWN;
|
||||||
if (animation.setState(actionState))
|
if (animation.setState(actionState))
|
||||||
controller->activate();
|
controller->activate();
|
||||||
@@ -1651,7 +1707,7 @@ struct Lara : Character {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
limit = actionState == STATE_USE_PUZZLE ? &TR::Limits::PUZZLE_HOLE : &TR::Limits::KEY_HOLE;
|
limit = actionState == STATE_USE_PUZZLE ? &TR::Limits::PUZZLE_HOLE : &TR::Limits::KEY_HOLE;
|
||||||
if (!checkInteraction(controller, *limit, isPressed(ACTION) || usedKey != TR::Entity::NONE))
|
if (!checkInteraction(controller, limit, isPressed(ACTION) || usedKey != TR::Entity::NONE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (usedKey == TR::Entity::NONE) {
|
if (usedKey == TR::Entity::NONE) {
|
||||||
@@ -2010,7 +2066,7 @@ struct Lara : Character {
|
|||||||
float oldAngle = block->angle.y;
|
float oldAngle = block->angle.y;
|
||||||
block->angle.y = angleQuadrant(angle.y) * (PI * 0.5f);
|
block->angle.y = angleQuadrant(angle.y) * (PI * 0.5f);
|
||||||
|
|
||||||
if (!checkInteraction(block, TR::Limits::BLOCK, (input & ACTION) != 0)) {
|
if (!checkInteraction(block, &TR::Limits::BLOCK, (input & ACTION) != 0)) {
|
||||||
block->angle.y = oldAngle;
|
block->angle.y = oldAngle;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2024,7 +2080,7 @@ struct Lara : Character {
|
|||||||
int res = STATE_STOP;
|
int res = STATE_STOP;
|
||||||
angle.x = 0.0f;
|
angle.x = 0.0f;
|
||||||
|
|
||||||
if ((state == STATE_STOP || state == STATE_TREAD) && (input & ACTION) && emptyHands() && doPickUp())
|
if ((input == ACTION) && (state == STATE_STOP) && emptyHands() && doPickUp())
|
||||||
return state;
|
return state;
|
||||||
|
|
||||||
if ((input & (FORTH | ACTION)) == (FORTH | ACTION) && (animation.index == ANIM_STAND || animation.index == ANIM_STAND_NORMAL) && emptyHands() && collision.side == Collision::FRONT) { // TODO: get rid of animation.index
|
if ((input & (FORTH | ACTION)) == (FORTH | ACTION) && (animation.index == ANIM_STAND || animation.index == ANIM_STAND_NORMAL) && emptyHands() && collision.side == Collision::FRONT) { // TODO: get rid of animation.index
|
||||||
@@ -2209,7 +2265,7 @@ struct Lara : Character {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual int getStateUnderwater() {
|
virtual int getStateUnderwater() {
|
||||||
if (input == ACTION && doPickUp())
|
if ((input == ACTION) && (state == STATE_TREAD) && emptyHands() && doPickUp())
|
||||||
return state;
|
return state;
|
||||||
|
|
||||||
if (state == STATE_FORWARD_JUMP || state == STATE_UP_JUMP || state == STATE_BACK_JUMP || state == STATE_LEFT_JUMP || state == STATE_RIGHT_JUMP || state == STATE_FALL || state == STATE_REACH || state == STATE_SLIDE || state == STATE_SLIDE_BACK) {
|
if (state == STATE_FORWARD_JUMP || state == STATE_UP_JUMP || state == STATE_BACK_JUMP || state == STATE_LEFT_JUMP || state == STATE_RIGHT_JUMP || state == STATE_FALL || state == STATE_REACH || state == STATE_SLIDE || state == STATE_SLIDE_BACK) {
|
||||||
@@ -2335,6 +2391,12 @@ struct Lara : Character {
|
|||||||
case TR::LEVEL_4 :
|
case TR::LEVEL_4 :
|
||||||
reset(18, vec3(34914, 11008, 41315), 90 * DEG2RAD); // main hall
|
reset(18, vec3(34914, 11008, 41315), 90 * DEG2RAD); // main hall
|
||||||
break;
|
break;
|
||||||
|
case TR::LEVEL_6 :
|
||||||
|
reset(73, vec3(73372, 122, 51687), PI * 0.5f); // level 6 (midas hand)
|
||||||
|
break;
|
||||||
|
case TR::LEVEL_7B :
|
||||||
|
reset(77, vec3(36943, -4096, 62821), 270 * DEG2RAD); // level 7b (heavy trigger)
|
||||||
|
break;
|
||||||
default : game->playSound(TR::SND_NO, pos, Sound::PAN);
|
default : game->playSound(TR::SND_NO, pos, Sound::PAN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2372,13 +2434,13 @@ struct Lara : Character {
|
|||||||
virtual void doCustomCommand(int curFrame, int prevFrame) {
|
virtual void doCustomCommand(int curFrame, int prevFrame) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case STATE_PICK_UP : {
|
case STATE_PICK_UP : {
|
||||||
if (pickupEntity && !pickupEntity->flags.invisible) {
|
int pickupFrame = stand == STAND_GROUND ? PICKUP_FRAME_GROUND : PICKUP_FRAME_UNDERWATER;
|
||||||
int pickupFrame = stand == STAND_GROUND ? PICKUP_FRAME_GROUND : PICKUP_FRAME_UNDERWATER;
|
if (animation.isFrameActive(pickupFrame)) {
|
||||||
if (animation.isFrameActive(pickupFrame)) {
|
for (int i = 0; i < pickupListCount; i++) {
|
||||||
pickupEntity->flags.invisible = true;
|
pickupList[i]->flags.invisible = true;
|
||||||
game->invAdd(pickupEntity->type, 1);
|
game->invAdd(pickupList[i]->type, 1);
|
||||||
pickupEntity = NULL;
|
|
||||||
}
|
}
|
||||||
|
pickupListCount = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2814,6 +2876,24 @@ struct Lara : Character {
|
|||||||
velocity = v * (sink.speed * 8.0f);
|
velocity = v * (sink.speed * 8.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 getMidasDeathMask() {
|
||||||
|
uint32 mask = 0;
|
||||||
|
int frame = animation.frameIndex;
|
||||||
|
if (frame > 4 ) mask |= BODY_LEG_L3 | BODY_LEG_R3;
|
||||||
|
if (frame > 69 ) mask |= BODY_LEG_L2;
|
||||||
|
if (frame > 79 ) mask |= BODY_LEG_L1;
|
||||||
|
if (frame > 99 ) mask |= BODY_LEG_R2;
|
||||||
|
if (frame > 119) mask |= BODY_LEG_R1 | BODY_HIP;
|
||||||
|
if (frame > 134) mask |= BODY_CHEST;
|
||||||
|
if (frame > 149) mask |= BODY_ARM_L1;
|
||||||
|
if (frame > 162) mask |= BODY_ARM_L2;
|
||||||
|
if (frame > 173) mask |= BODY_ARM_L3;
|
||||||
|
if (frame > 185) mask |= BODY_ARM_R1;
|
||||||
|
if (frame > 194) mask |= BODY_ARM_R2;
|
||||||
|
if (frame > 217) mask |= BODY_ARM_R3;
|
||||||
|
if (frame > 224) mask |= BODY_HEAD;
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
void renderMuzzleFlash(MeshBuilder *mesh, const Basis &basis, const vec3 &offset, float time) {
|
void renderMuzzleFlash(MeshBuilder *mesh, const Basis &basis, const vec3 &offset, float time) {
|
||||||
ASSERT(level->extra.muzzleFlash);
|
ASSERT(level->extra.muzzleFlash);
|
||||||
@@ -2843,6 +2923,16 @@ struct Lara : Character {
|
|||||||
renderMuzzleFlash(mesh, animation.getJoints(matrix, 13, true), vec3( 10, -50, 150), arms[1].shotTimer);
|
renderMuzzleFlash(mesh, animation.getJoints(matrix, 13, true), vec3( 10, -50, 150), arms[1].shotTimer);
|
||||||
Core::setBlending(bmNone);
|
Core::setBlending(bmNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state == STATE_DIE_MIDAS) {
|
||||||
|
game->setRoomParams(getRoomIndex(), Shader::MIRROR, 1.2f, 1.0f, 0.2f, 1.0f, false);
|
||||||
|
environment->bind(sEnvironment);
|
||||||
|
Core::setBlending(bmAlpha);
|
||||||
|
visibleMask = getMidasDeathMask();
|
||||||
|
Controller::render(frustum, mesh, type, caustics);
|
||||||
|
visibleMask = 0xFFFFFFFF;
|
||||||
|
Core::setBlending(bmNone);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
71
src/level.h
71
src/level.h
@@ -163,6 +163,34 @@ struct Level : IGame {
|
|||||||
shaderCache->bind(pass, type, (underwater ? ShaderCache::FX_UNDERWATER : 0) | (alphaTest ? ShaderCache::FX_ALPHA_TEST : 0) | ((params->clipHeight != NO_CLIP_PLANE && pass == Core::passCompose) ? ShaderCache::FX_CLIP_PLANE : 0), this);
|
shaderCache->bind(pass, type, (underwater ? ShaderCache::FX_UNDERWATER : 0) | (alphaTest ? ShaderCache::FX_ALPHA_TEST : 0) | ((params->clipHeight != NO_CLIP_PLANE && pass == Core::passCompose) ? ShaderCache::FX_CLIP_PLANE : 0), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void setRoomParams(int roomIndex, Shader::Type type, float diffuse, float ambient, float specular, float alpha, bool alphaTest = false) {
|
||||||
|
if (Core::pass == Core::passShadow) {
|
||||||
|
setShader(Core::pass, type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TR::Room &room = level.rooms[roomIndex];
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::active.shader->setParam(uParam, Core::params);
|
||||||
|
Core::active.shader->setParam(uMaterial, vec4(diffuse, ambient, specular, alpha));
|
||||||
|
|
||||||
|
if (Core::settings.detail.shadows > Core::Settings::MEDIUM)
|
||||||
|
Core::active.shader->setParam(uContacts, Core::contacts[0], MAX_CONTACTS);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void setupBinding() {
|
virtual void setupBinding() {
|
||||||
atlas->bind(sDiffuse);
|
atlas->bind(sDiffuse);
|
||||||
Core::whiteTex->bind(sNormal);
|
Core::whiteTex->bind(sNormal);
|
||||||
@@ -489,6 +517,7 @@ struct Level : IGame {
|
|||||||
case TR::Entity::KEY_HOLE_2 :
|
case TR::Entity::KEY_HOLE_2 :
|
||||||
case TR::Entity::KEY_HOLE_3 :
|
case TR::Entity::KEY_HOLE_3 :
|
||||||
case TR::Entity::KEY_HOLE_4 : return new KeyHole(this, index);
|
case TR::Entity::KEY_HOLE_4 : return new KeyHole(this, index);
|
||||||
|
case TR::Entity::MIDAS_HAND : return new MidasHand(this, index);
|
||||||
case TR::Entity::SCION_TARGET : return new ScionTarget(this, index);
|
case TR::Entity::SCION_TARGET : return new ScionTarget(this, index);
|
||||||
case TR::Entity::WATERFALL : return new Waterfall(this, index);
|
case TR::Entity::WATERFALL : return new Waterfall(this, index);
|
||||||
case TR::Entity::TRAP_LAVA : return new TrapLava(this, index);
|
case TR::Entity::TRAP_LAVA : return new TrapLava(this, index);
|
||||||
@@ -729,38 +758,12 @@ struct Level : IGame {
|
|||||||
if (e.type == TR::Entity::CRYSTAL) {
|
if (e.type == TR::Entity::CRYSTAL) {
|
||||||
Crystal *c = (Crystal*)e.controller;
|
Crystal *c = (Crystal*)e.controller;
|
||||||
renderEnvironment(c->getRoomIndex(), c->pos - vec3(0, 512, 0), &c->environment);
|
renderEnvironment(c->getRoomIndex(), c->pos - vec3(0, 512, 0), &c->environment);
|
||||||
|
c->environment->generateMipMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Core::endFrame();
|
Core::endFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setRoomParams(int roomIndex, Shader::Type type, float diffuse, float ambient, float specular, float alpha, bool alphaTest = false) {
|
|
||||||
if (Core::pass == Core::passShadow) {
|
|
||||||
setShader(Core::pass, type);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TR::Room &room = level.rooms[roomIndex];
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
Core::active.shader->setParam(uParam, Core::params);
|
|
||||||
Core::active.shader->setParam(uMaterial, vec4(diffuse, ambient, specular, alpha));
|
|
||||||
if (Core::settings.detail.shadows > Core::Settings::MEDIUM)
|
|
||||||
Core::active.shader->setParam(uContacts, Core::contacts[0], MAX_CONTACTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMainLight(Controller *controller) {
|
void setMainLight(Controller *controller) {
|
||||||
Core::lightPos[0] = controller->mainLightPos;
|
Core::lightPos[0] = controller->mainLightPos;
|
||||||
Core::lightColor[0] = vec4(controller->mainLightColor.xyz, 1.0f / controller->mainLightColor.w);
|
Core::lightColor[0] = vec4(controller->mainLightColor.xyz, 1.0f / controller->mainLightColor.w);
|
||||||
@@ -874,7 +877,7 @@ struct Level : IGame {
|
|||||||
|
|
||||||
if (type == Shader::SPRITE) {
|
if (type == Shader::SPRITE) {
|
||||||
float alpha = (entity.type == TR::Entity::SMOKE || entity.type == TR::Entity::WATER_SPLASH) ? 0.75f : 1.0f;
|
float alpha = (entity.type == TR::Entity::SMOKE || entity.type == TR::Entity::WATER_SPLASH) ? 0.75f : 1.0f;
|
||||||
float diffuse = entity.isItem() ? 1.0f : 0.5f;
|
float diffuse = entity.isPickup() ? 1.0f : 0.5f;
|
||||||
setRoomParams(roomIndex, type, diffuse, intensityf(lum), controller->specular, alpha, isModel ? !mesh->models[entity.modelIndex - 1].opaque : true);
|
setRoomParams(roomIndex, type, diffuse, intensityf(lum), controller->specular, alpha, isModel ? !mesh->models[entity.modelIndex - 1].opaque : true);
|
||||||
} else
|
} else
|
||||||
setRoomParams(roomIndex, type, 1.0f, intensityf(lum), controller->specular, 1.0f, isModel ? !mesh->models[entity.modelIndex - 1].opaque : true);
|
setRoomParams(roomIndex, type, 1.0f, intensityf(lum), controller->specular, 1.0f, isModel ? !mesh->models[entity.modelIndex - 1].opaque : true);
|
||||||
@@ -904,11 +907,15 @@ struct Level : IGame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void update() {
|
void update() {
|
||||||
if (isCutscene() && !sndSoundtrack)
|
if (isCutscene() && (lara->health > 0.0f && !sndSoundtrack))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Input::state[cInventory] && level.id != TR::TITLE)
|
if (Input::state[cInventory] && level.id != TR::TITLE) {
|
||||||
inventory.toggle();
|
if (lara->health <= 0.0f)
|
||||||
|
inventory.toggle(Inventory::PAGE_OPTION, TR::Entity::INV_PASSPORT);
|
||||||
|
else
|
||||||
|
inventory.toggle();
|
||||||
|
}
|
||||||
|
|
||||||
Sound::Sample *sndChanged = sndCurrent;
|
Sound::Sample *sndChanged = sndCurrent;
|
||||||
|
|
||||||
@@ -1477,7 +1484,7 @@ struct Level : IGame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void renderUI() {
|
void renderUI() {
|
||||||
if (isCutscene()) return;
|
if (level.isCutsceneLevel()) return;
|
||||||
|
|
||||||
UI::begin();
|
UI::begin();
|
||||||
|
|
||||||
|
@@ -45,7 +45,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
|||||||
|
|
||||||
#ifdef VERTEX
|
#ifdef VERTEX
|
||||||
|
|
||||||
#ifdef TYPE_ENTITY
|
#if defined(TYPE_ENTITY) || defined(TYPE_MIRROR)
|
||||||
uniform vec4 uBasis[32 * 2];
|
uniform vec4 uBasis[32 * 2];
|
||||||
#else
|
#else
|
||||||
uniform vec4 uBasis[2];
|
uniform vec4 uBasis[2];
|
||||||
@@ -89,7 +89,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
|||||||
}
|
}
|
||||||
|
|
||||||
vec4 _transform() {
|
vec4 _transform() {
|
||||||
#ifdef TYPE_ENTITY
|
#if defined(TYPE_ENTITY) || defined(TYPE_MIRROR)
|
||||||
int index = int(aCoord.w * 2.0);
|
int index = int(aCoord.w * 2.0);
|
||||||
vec4 rBasisRot = uBasis[index];
|
vec4 rBasisRot = uBasis[index];
|
||||||
vec4 rBasisPos = uBasis[index + 1];
|
vec4 rBasisPos = uBasis[index + 1];
|
||||||
@@ -147,7 +147,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TYPE_MIRROR
|
#ifdef TYPE_MIRROR
|
||||||
vDiffuse.xyz = vec3(0.5, 0.5, 2.0); // blue color dodge for crystal
|
vDiffuse.xyz = uMaterial.xyz;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TYPE_FLASH
|
#ifdef TYPE_FLASH
|
||||||
|
@@ -10,8 +10,9 @@ struct Texture {
|
|||||||
int width, height;
|
int width, height;
|
||||||
Format format;
|
Format format;
|
||||||
bool cube;
|
bool cube;
|
||||||
|
bool filter;
|
||||||
|
|
||||||
Texture(int width, int height, Format format, bool cube = false, void *data = NULL, bool filter = true, bool mips = false) : cube(cube) {
|
Texture(int width, int height, Format format, bool cube = false, void *data = NULL, bool filter = true, bool mips = false) : cube(cube), filter(filter) {
|
||||||
if (!Core::support.texNPOT) {
|
if (!Core::support.texNPOT) {
|
||||||
width = nextPow2(width);
|
width = nextPow2(width);
|
||||||
height = nextPow2(height);
|
height = nextPow2(height);
|
||||||
@@ -117,12 +118,20 @@ struct Texture {
|
|||||||
if (!cube) break;
|
if (!cube) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mips) {
|
if (mips)
|
||||||
glGenerateMipmap(target);
|
generateMipMap();
|
||||||
if (!cube && filter && (Core::support.maxAniso > 0))
|
|
||||||
glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, min(int(Core::support.maxAniso), 8));
|
this->filter = filter;
|
||||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);
|
}
|
||||||
}
|
|
||||||
|
void generateMipMap() {
|
||||||
|
bind(0);
|
||||||
|
GLenum target = cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
|
||||||
|
|
||||||
|
glGenerateMipmap(target);
|
||||||
|
if (!cube && filter && (Core::support.maxAniso > 0))
|
||||||
|
glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, min(int(Core::support.maxAniso), 8));
|
||||||
|
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Texture() {
|
virtual ~Texture() {
|
||||||
|
@@ -621,7 +621,7 @@ struct Crystal : Controller {
|
|||||||
Texture *environment;
|
Texture *environment;
|
||||||
|
|
||||||
Crystal(IGame *game, int entity) : Controller(game, entity) {
|
Crystal(IGame *game, int entity) : Controller(game, entity) {
|
||||||
environment = new Texture(64, 64, Texture::RGBA, true);
|
environment = new Texture(64, 64, Texture::RGBA, true, NULL, true, true);
|
||||||
activate();
|
activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,8 +634,7 @@ struct Crystal : Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
|
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
|
||||||
Shader *sh = Core::active.shader;
|
Core::active.shader->setParam(uMaterial, vec4(0.5, 0.5, 2.0, 1.0f)); // blue color dodge for crystal
|
||||||
sh->setParam(uMaterial, vec4(1.0f));
|
|
||||||
environment->bind(sEnvironment);
|
environment->bind(sEnvironment);
|
||||||
Controller::render(frustum, mesh, type, caustics);
|
Controller::render(frustum, mesh, type, caustics);
|
||||||
}
|
}
|
||||||
@@ -803,8 +802,8 @@ struct TrapSword : Controller {
|
|||||||
angle.y += rot * Core::deltaTime;
|
angle.y += rot * Core::deltaTime;
|
||||||
applyGravity(dir.y);
|
applyGravity(dir.y);
|
||||||
pos += dir * (30.0f * Core::deltaTime);
|
pos += dir * (30.0f * Core::deltaTime);
|
||||||
if (pos.y > info.floor) {
|
if (pos.y > float(info.floor)) {
|
||||||
pos.y = info.floor;
|
pos.y = float(info.floor);
|
||||||
game->playSound(TR::SND_SWORD, pos, Sound::PAN);
|
game->playSound(TR::SND_SWORD, pos, Sound::PAN);
|
||||||
deactivate(true);
|
deactivate(true);
|
||||||
}
|
}
|
||||||
@@ -1017,6 +1016,46 @@ struct Lightning : Controller {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MidasHand : Controller {
|
||||||
|
TR::Entity::Type invItem;
|
||||||
|
bool interaction;
|
||||||
|
|
||||||
|
MidasHand(IGame *game, int entity) : Controller(game, entity), invItem(TR::Entity::NONE), interaction(false) {
|
||||||
|
activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void update() {
|
||||||
|
Character *lara = (Character*)level->laraController;
|
||||||
|
|
||||||
|
if (lara->health <= 0.0f || lara->stand != Character::STAND_GROUND || lara->getRoomIndex() != getRoomIndex())
|
||||||
|
return;
|
||||||
|
|
||||||
|
vec3 d = (pos - lara->pos).abs();
|
||||||
|
|
||||||
|
if (d.x < 512.0f && d.z < 512.0f) { // check for same sector
|
||||||
|
lara->hit(1001.0f, this, TR::HIT_MIDAS);
|
||||||
|
deactivate(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
interaction = (d.x < 700.0f && d.z < 700.0f) && lara->state == 2; // 2 = Lara::STATE_STOP
|
||||||
|
|
||||||
|
if (interaction) {
|
||||||
|
if (invItem != TR::Entity::NONE) {
|
||||||
|
if (invItem == TR::Entity::INV_LEADBAR) {
|
||||||
|
lara->angle.y = PI * 0.5f;
|
||||||
|
lara->pos.x = pos.x - 612.0f;
|
||||||
|
lara->animation.setAnim(level->models[TR::MODEL_LARA_SPEC].animation);
|
||||||
|
game->invAdd(TR::Entity::PUZZLE_1);
|
||||||
|
} else
|
||||||
|
game->playSound(TR::SND_NO, pos, Sound::PAN); // uncompatible item
|
||||||
|
invItem = TR::Entity::NONE;
|
||||||
|
} else if (Input::state[cAction] && !game->invChooseKey(getEntity().type)) // TODO: add callback for useItem
|
||||||
|
game->playSound(TR::SND_NO, pos, Sound::PAN); // no compatible items in inventory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct TrapLava : Controller {
|
struct TrapLava : Controller {
|
||||||
bool done;
|
bool done;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user