mirror of
https://github.com/XProger/OpenLara.git
synced 2025-01-17 21:09:00 +01:00
parent
0ea27ca3d8
commit
4364f6d651
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
@ -33,9 +33,10 @@ struct IGame {
|
||||
virtual void renderCompose(int roomIndex, bool genShadowMask = false) {}
|
||||
virtual void fxQuake(float time) {}
|
||||
|
||||
virtual bool invUse(TR::Entity::Type item, TR::Entity::Type slot) { return false; }
|
||||
virtual bool invUse(TR::Entity::Type type) { return false; }
|
||||
virtual void invAdd(TR::Entity::Type type, int count = 1) {}
|
||||
virtual int* invCount(TR::Entity::Type type) { return NULL; }
|
||||
virtual bool invChooseKey(TR::Entity::Type hole) { return false; }
|
||||
|
||||
virtual Sound::Sample* playSound(int id, const vec3 &pos, int flags, int group = -1) const { return NULL; }
|
||||
};
|
||||
|
58
src/format.h
58
src/format.h
@ -630,17 +630,66 @@ namespace TR {
|
||||
return (type >= DOOR_1 && type <= DOOR_6) || type == DOOR_LIFT;
|
||||
}
|
||||
|
||||
int isItem() {
|
||||
bool isItem() {
|
||||
return (type >= PISTOLS && type <= AMMO_UZIS) ||
|
||||
(type >= PUZZLE_1 && type <= PUZZLE_4) ||
|
||||
(type >= KEY_1 && type <= KEY_4) ||
|
||||
(type == MEDIKIT_SMALL || type == MEDIKIT_BIG || type == SCION_1); // TODO: recheck all items
|
||||
}
|
||||
|
||||
bool isKeyHole() {
|
||||
return type >= KEY_HOLE_1 && type <= KEY_HOLE_2;
|
||||
}
|
||||
|
||||
bool isBlock() {
|
||||
return type >= TR::Entity::BLOCK_1 && type <= TR::Entity::BLOCK_2;
|
||||
}
|
||||
|
||||
static Type convToInv(Type type) {
|
||||
switch (type) {
|
||||
case PISTOLS : return INV_PISTOLS;
|
||||
case SHOTGUN : return INV_SHOTGUN;
|
||||
case MAGNUMS : return INV_MAGNUMS;
|
||||
case UZIS : return INV_UZIS;
|
||||
|
||||
case AMMO_PISTOLS : return INV_AMMO_PISTOLS;
|
||||
case AMMO_SHOTGUN : return INV_AMMO_SHOTGUN;
|
||||
case AMMO_MAGNUMS : return INV_AMMO_MAGNUMS;
|
||||
case AMMO_UZIS : return INV_AMMO_UZIS;
|
||||
|
||||
case MEDIKIT_SMALL : return INV_MEDIKIT_SMALL;
|
||||
case MEDIKIT_BIG : return INV_MEDIKIT_BIG;
|
||||
|
||||
case PUZZLE_1 : return INV_PUZZLE_1;
|
||||
case PUZZLE_2 : return INV_PUZZLE_2;
|
||||
case PUZZLE_3 : return INV_PUZZLE_3;
|
||||
case PUZZLE_4 : return INV_PUZZLE_4;
|
||||
|
||||
case KEY_1 : return INV_KEY_1;
|
||||
case KEY_2 : return INV_KEY_2;
|
||||
case KEY_3 : return INV_KEY_3;
|
||||
case KEY_4 : return INV_KEY_4;
|
||||
|
||||
case LEADBAR : return INV_LEADBAR;
|
||||
//case TR::Entity::SCION : return TR::Entity::INV_SCION;
|
||||
default : return type;
|
||||
}
|
||||
}
|
||||
|
||||
static Type getKeyForHole(Type hole) {
|
||||
switch (hole) {
|
||||
case PUZZLE_HOLE_1 : return PUZZLE_1; break;
|
||||
case PUZZLE_HOLE_2 : return PUZZLE_2; break;
|
||||
case PUZZLE_HOLE_3 : return PUZZLE_3; break;
|
||||
case PUZZLE_HOLE_4 : return PUZZLE_4; break;
|
||||
case KEY_HOLE_1 : return KEY_1; break;
|
||||
case KEY_HOLE_2 : return KEY_2; break;
|
||||
case KEY_HOLE_3 : return KEY_3; break;
|
||||
case KEY_HOLE_4 : return KEY_4; break;
|
||||
default : return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static void fixOpaque(Type type, bool &opaque) {
|
||||
if (type >= LARA && type <= ENEMY_GIANT_MUTANT
|
||||
&& type != ENEMY_REX
|
||||
@ -985,7 +1034,7 @@ namespace TR {
|
||||
|
||||
struct {
|
||||
int16 muzzleFlash;
|
||||
int16 puzzleSet;
|
||||
int16 puzzleDone[4];
|
||||
int16 weapons[4];
|
||||
int16 braid;
|
||||
|
||||
@ -1230,7 +1279,10 @@ namespace TR {
|
||||
for (int i = 0; i < modelsCount; i++)
|
||||
switch (models[i].type) {
|
||||
case Entity::MUZZLE_FLASH : extra.muzzleFlash = i; break;
|
||||
case Entity::PUZZLE_DONE_1 : extra.puzzleSet = i; break;
|
||||
case Entity::PUZZLE_DONE_1 : extra.puzzleDone[0] = i; break;
|
||||
case Entity::PUZZLE_DONE_2 : extra.puzzleDone[1] = i; break;
|
||||
case Entity::PUZZLE_DONE_3 : extra.puzzleDone[2] = i; break;
|
||||
case Entity::PUZZLE_DONE_4 : extra.puzzleDone[3] = i; break;
|
||||
case Entity::LARA_PISTOLS : extra.weapons[0] = i; break;
|
||||
case Entity::LARA_SHOTGUN : extra.weapons[1] = i; break;
|
||||
case Entity::LARA_MAGNUMS : extra.weapons[2] = i; break;
|
||||
|
215
src/inventory.h
215
src/inventory.h
@ -37,7 +37,7 @@ struct Inventory {
|
||||
|
||||
struct Desc {
|
||||
const char *name;
|
||||
int page;
|
||||
Page page;
|
||||
int model;
|
||||
} desc;
|
||||
|
||||
@ -45,42 +45,42 @@ struct Inventory {
|
||||
|
||||
Item(TR::Level *level, TR::Entity::Type type, int count = 1) : type(type), count(count), angle(0.0f) {
|
||||
switch (type) {
|
||||
case TR::Entity::INV_PASSPORT : desc = { "Game", 0, level->extra.inv.passport }; break;
|
||||
case TR::Entity::INV_PASSPORT_CLOSED : desc = { "Game", 0, level->extra.inv.passport_closed }; break;
|
||||
case TR::Entity::INV_MAP : desc = { "Map", 1, level->extra.inv.map }; break;
|
||||
case TR::Entity::INV_COMPASS : desc = { "Compass", 1, level->extra.inv.compass }; break;
|
||||
case TR::Entity::INV_HOME : desc = { "Lara's Home", 0, level->extra.inv.home }; break;
|
||||
case TR::Entity::INV_DETAIL : desc = { "Detail Levels", 0, level->extra.inv.detail }; break;
|
||||
case TR::Entity::INV_SOUND : desc = { "Sound", 0, level->extra.inv.sound }; break;
|
||||
case TR::Entity::INV_CONTROLS : desc = { "Controls", 0, level->extra.inv.controls }; break;
|
||||
case TR::Entity::INV_GAMMA : desc = { "Gamma", 0, level->extra.inv.gamma }; break;
|
||||
case TR::Entity::INV_PASSPORT : desc = { "Game", PAGE_OPTION, level->extra.inv.passport }; break;
|
||||
case TR::Entity::INV_PASSPORT_CLOSED : desc = { "Game", PAGE_OPTION, level->extra.inv.passport_closed }; break;
|
||||
case TR::Entity::INV_MAP : desc = { "Map", PAGE_INVENTORY, level->extra.inv.map }; break;
|
||||
case TR::Entity::INV_COMPASS : desc = { "Compass", PAGE_INVENTORY, level->extra.inv.compass }; break;
|
||||
case TR::Entity::INV_HOME : desc = { "Lara's Home", PAGE_OPTION, level->extra.inv.home }; break;
|
||||
case TR::Entity::INV_DETAIL : desc = { "Detail Levels", PAGE_OPTION, level->extra.inv.detail }; break;
|
||||
case TR::Entity::INV_SOUND : desc = { "Sound", PAGE_OPTION, level->extra.inv.sound }; break;
|
||||
case TR::Entity::INV_CONTROLS : desc = { "Controls", PAGE_OPTION, level->extra.inv.controls }; break;
|
||||
case TR::Entity::INV_GAMMA : desc = { "Gamma", PAGE_OPTION, level->extra.inv.gamma }; break;
|
||||
|
||||
case TR::Entity::INV_PISTOLS : desc = { "Pistols", 1, level->extra.inv.weapon[0] }; break;
|
||||
case TR::Entity::INV_SHOTGUN : desc = { "Shotgun", 1, level->extra.inv.weapon[1] }; break;
|
||||
case TR::Entity::INV_MAGNUMS : desc = { "Magnums", 1, level->extra.inv.weapon[2] }; break;
|
||||
case TR::Entity::INV_UZIS : desc = { "Uzis", 1, level->extra.inv.weapon[3] }; break;
|
||||
case TR::Entity::INV_PISTOLS : desc = { "Pistols", PAGE_INVENTORY, level->extra.inv.weapon[0] }; break;
|
||||
case TR::Entity::INV_SHOTGUN : desc = { "Shotgun", PAGE_INVENTORY, level->extra.inv.weapon[1] }; break;
|
||||
case TR::Entity::INV_MAGNUMS : desc = { "Magnums", PAGE_INVENTORY, level->extra.inv.weapon[2] }; break;
|
||||
case TR::Entity::INV_UZIS : desc = { "Uzis", PAGE_INVENTORY, level->extra.inv.weapon[3] }; break;
|
||||
|
||||
case TR::Entity::INV_AMMO_PISTOLS : desc = { "Pistol Clips", 1, level->extra.inv.ammo[0] }; break;
|
||||
case TR::Entity::INV_AMMO_SHOTGUN : desc = { "Shotgun Shells", 1, level->extra.inv.ammo[1] }; break;
|
||||
case TR::Entity::INV_AMMO_MAGNUMS : desc = { "Magnum Clips", 1, level->extra.inv.ammo[2] }; break;
|
||||
case TR::Entity::INV_AMMO_UZIS : desc = { "Uzi Clips", 1, level->extra.inv.ammo[3] }; break;
|
||||
case TR::Entity::INV_AMMO_PISTOLS : desc = { "Pistol Clips", PAGE_INVENTORY, level->extra.inv.ammo[0] }; break;
|
||||
case TR::Entity::INV_AMMO_SHOTGUN : desc = { "Shotgun Shells", PAGE_INVENTORY, level->extra.inv.ammo[1] }; break;
|
||||
case TR::Entity::INV_AMMO_MAGNUMS : desc = { "Magnum Clips", PAGE_INVENTORY, level->extra.inv.ammo[2] }; break;
|
||||
case TR::Entity::INV_AMMO_UZIS : desc = { "Uzi Clips", PAGE_INVENTORY, level->extra.inv.ammo[3] }; break;
|
||||
|
||||
case TR::Entity::INV_MEDIKIT_SMALL : desc = { "Small Medi Pack", 1, level->extra.inv.medikit[0] }; break;
|
||||
case TR::Entity::INV_MEDIKIT_BIG : desc = { "Large Medi Pack", 1, level->extra.inv.medikit[1] }; break;
|
||||
case TR::Entity::INV_MEDIKIT_SMALL : desc = { "Small Medi Pack", PAGE_INVENTORY, level->extra.inv.medikit[0] }; break;
|
||||
case TR::Entity::INV_MEDIKIT_BIG : desc = { "Large Medi Pack", PAGE_INVENTORY, level->extra.inv.medikit[1] }; break;
|
||||
|
||||
case TR::Entity::INV_PUZZLE_1 : desc = { "Puzzle", 2, level->extra.inv.puzzle[0] }; break;
|
||||
case TR::Entity::INV_PUZZLE_2 : desc = { "Puzzle", 2, level->extra.inv.puzzle[1] }; break;
|
||||
case TR::Entity::INV_PUZZLE_3 : desc = { "Puzzle", 2, level->extra.inv.puzzle[2] }; break;
|
||||
case TR::Entity::INV_PUZZLE_4 : desc = { "Puzzle", 2, level->extra.inv.puzzle[3] }; break;
|
||||
|
||||
case TR::Entity::INV_KEY_1 : desc = { "Key", 2, level->extra.inv.key[0] }; break;
|
||||
case TR::Entity::INV_KEY_2 : desc = { "Key", 2, level->extra.inv.key[1] }; break;
|
||||
case TR::Entity::INV_KEY_3 : desc = { "Key", 2, level->extra.inv.key[2] }; break;
|
||||
case TR::Entity::INV_KEY_4 : desc = { "Key", 2, level->extra.inv.key[3] }; break;
|
||||
|
||||
case TR::Entity::INV_LEADBAR : desc = { "Lead Bar", 2, level->extra.inv.leadbar }; break;
|
||||
case TR::Entity::INV_SCION : desc = { "Scion", 2, level->extra.inv.scion }; break;
|
||||
default : desc = { "unknown", 2, -1 }; break;
|
||||
case TR::Entity::INV_PUZZLE_1 : desc = { "Puzzle", PAGE_ITEMS, level->extra.inv.puzzle[0] }; break;
|
||||
case TR::Entity::INV_PUZZLE_2 : desc = { "Puzzle", PAGE_ITEMS, level->extra.inv.puzzle[1] }; break;
|
||||
case TR::Entity::INV_PUZZLE_3 : desc = { "Puzzle", PAGE_ITEMS, level->extra.inv.puzzle[2] }; break;
|
||||
case TR::Entity::INV_PUZZLE_4 : desc = { "Puzzle", PAGE_ITEMS, level->extra.inv.puzzle[3] }; break;
|
||||
|
||||
case TR::Entity::INV_KEY_1 : desc = { "Key", PAGE_ITEMS, level->extra.inv.key[0] }; break;
|
||||
case TR::Entity::INV_KEY_2 : desc = { "Key", PAGE_ITEMS, level->extra.inv.key[1] }; break;
|
||||
case TR::Entity::INV_KEY_3 : desc = { "Key", PAGE_ITEMS, level->extra.inv.key[2] }; break;
|
||||
case TR::Entity::INV_KEY_4 : desc = { "Key", PAGE_ITEMS, level->extra.inv.key[3] }; break;
|
||||
|
||||
case TR::Entity::INV_LEADBAR : desc = { "Lead Bar", PAGE_ITEMS, level->extra.inv.leadbar }; break;
|
||||
case TR::Entity::INV_SCION : desc = { "Scion", PAGE_ITEMS, level->extra.inv.scion }; break;
|
||||
default : desc = { "unknown", PAGE_ITEMS, -1 }; break;
|
||||
}
|
||||
|
||||
if (desc.model > -1) {
|
||||
@ -132,8 +132,6 @@ struct Inventory {
|
||||
} *items[INVENTORY_MAX_ITEMS];
|
||||
|
||||
Inventory(IGame *game) : game(game), active(false), chosen(false), index(0), targetIndex(0), page(PAGE_OPTION), targetPage(PAGE_OPTION), itemsCount(0) {
|
||||
TR::Level *level = game->getLevel();
|
||||
|
||||
add(TR::Entity::INV_PASSPORT);
|
||||
add(TR::Entity::INV_DETAIL);
|
||||
add(TR::Entity::INV_SOUND);
|
||||
@ -175,39 +173,8 @@ struct Inventory {
|
||||
return active || phaseRing > 0.0f;
|
||||
}
|
||||
|
||||
TR::Entity::Type convToInv(TR::Entity::Type type) {
|
||||
switch (type) {
|
||||
case TR::Entity::PISTOLS : return TR::Entity::INV_PISTOLS;
|
||||
case TR::Entity::SHOTGUN : return TR::Entity::INV_SHOTGUN;
|
||||
case TR::Entity::MAGNUMS : return TR::Entity::INV_MAGNUMS;
|
||||
case TR::Entity::UZIS : return TR::Entity::INV_UZIS;
|
||||
|
||||
case TR::Entity::AMMO_PISTOLS : return TR::Entity::INV_AMMO_PISTOLS;
|
||||
case TR::Entity::AMMO_SHOTGUN : return TR::Entity::INV_AMMO_SHOTGUN;
|
||||
case TR::Entity::AMMO_MAGNUMS : return TR::Entity::INV_AMMO_MAGNUMS;
|
||||
case TR::Entity::AMMO_UZIS : return TR::Entity::INV_AMMO_UZIS;
|
||||
|
||||
case TR::Entity::MEDIKIT_SMALL : return TR::Entity::INV_MEDIKIT_SMALL;
|
||||
case TR::Entity::MEDIKIT_BIG : return TR::Entity::INV_MEDIKIT_BIG;
|
||||
|
||||
case TR::Entity::PUZZLE_1 : return TR::Entity::INV_PUZZLE_1;
|
||||
case TR::Entity::PUZZLE_2 : return TR::Entity::INV_PUZZLE_2;
|
||||
case TR::Entity::PUZZLE_3 : return TR::Entity::INV_PUZZLE_3;
|
||||
case TR::Entity::PUZZLE_4 : return TR::Entity::INV_PUZZLE_4;
|
||||
|
||||
case TR::Entity::KEY_1 : return TR::Entity::INV_KEY_1;
|
||||
case TR::Entity::KEY_2 : return TR::Entity::INV_KEY_2;
|
||||
case TR::Entity::KEY_3 : return TR::Entity::INV_KEY_3;
|
||||
case TR::Entity::KEY_4 : return TR::Entity::INV_KEY_4;
|
||||
|
||||
case TR::Entity::LEADBAR : return TR::Entity::INV_LEADBAR;
|
||||
//case TR::Entity::SCION : return TR::Entity::INV_SCION;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
int contains(TR::Entity::Type type) {
|
||||
type = convToInv(type);
|
||||
type = TR::Entity::convToInv(type);
|
||||
for (int i = 0; i < itemsCount; i++)
|
||||
if (items[i]->type == type)
|
||||
return i;
|
||||
@ -215,35 +182,38 @@ struct Inventory {
|
||||
}
|
||||
|
||||
void addAmmo(TR::Entity::Type &type, int &count, int clip, TR::Entity::Type wpnType, TR::Entity::Type ammoType) {
|
||||
count *= clip;
|
||||
if (type == wpnType) {
|
||||
count *= clip;
|
||||
int index = contains(ammoType);
|
||||
if (index > -1) {
|
||||
count += items[index]->count;
|
||||
count += items[index]->count * clip;
|
||||
remove(index);
|
||||
}
|
||||
} else {
|
||||
if (contains(wpnType) > -1)
|
||||
if (contains(wpnType) > -1) {
|
||||
type = wpnType;
|
||||
count *= clip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add(TR::Entity::Type type, int count = 1) {
|
||||
type = convToInv(type);
|
||||
type = TR::Entity::convToInv(type);
|
||||
|
||||
switch (type) {
|
||||
case TR::Entity::INV_SHOTGUN :
|
||||
case TR::Entity::INV_AMMO_SHOTGUN :
|
||||
addAmmo(type, count, 12, TR::Entity::INV_SHOTGUN, TR::Entity::INV_AMMO_SHOTGUN);
|
||||
addAmmo(type, count, 2, TR::Entity::INV_SHOTGUN, TR::Entity::INV_AMMO_SHOTGUN);
|
||||
break;
|
||||
case TR::Entity::INV_MAGNUMS :
|
||||
case TR::Entity::INV_AMMO_MAGNUMS :
|
||||
addAmmo(type, count, 50, TR::Entity::INV_MAGNUMS, TR::Entity::INV_AMMO_MAGNUMS);
|
||||
addAmmo(type, count, 25, TR::Entity::INV_MAGNUMS, TR::Entity::INV_AMMO_MAGNUMS);
|
||||
break;
|
||||
case TR::Entity::INV_UZIS :
|
||||
case TR::Entity::INV_AMMO_UZIS :
|
||||
addAmmo(type, count, 100, TR::Entity::INV_UZIS, TR::Entity::INV_AMMO_UZIS);
|
||||
addAmmo(type, count, 50, TR::Entity::INV_UZIS, TR::Entity::INV_AMMO_UZIS);
|
||||
break;
|
||||
default : ;
|
||||
}
|
||||
|
||||
int i = contains(type);
|
||||
@ -289,33 +259,27 @@ struct Inventory {
|
||||
items[i] = items[i + 1];
|
||||
itemsCount--;
|
||||
}
|
||||
|
||||
bool chooseKey(TR::Entity::Type hole) {
|
||||
TR::Entity::Type type = TR::Entity::getKeyForHole(hole);
|
||||
if (type == TR::Entity::NONE)
|
||||
return false;
|
||||
int index = contains(type);
|
||||
if (index < 0)
|
||||
return false;
|
||||
toggle(items[index]->desc.page, type);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool use(TR::Entity::Type item, TR::Entity::Type slot) {
|
||||
switch (slot) {
|
||||
case TR::Entity::PUZZLE_HOLE_1 : item = TR::Entity::INV_PUZZLE_1; break;
|
||||
case TR::Entity::PUZZLE_HOLE_2 : item = TR::Entity::INV_PUZZLE_2; break;
|
||||
case TR::Entity::PUZZLE_HOLE_3 : item = TR::Entity::INV_PUZZLE_3; break;
|
||||
case TR::Entity::PUZZLE_HOLE_4 : item = TR::Entity::INV_PUZZLE_4; break;
|
||||
case TR::Entity::KEY_HOLE_1 : item = TR::Entity::INV_KEY_1; break;
|
||||
case TR::Entity::KEY_HOLE_2 : item = TR::Entity::INV_KEY_2; break;
|
||||
case TR::Entity::KEY_HOLE_3 : item = TR::Entity::INV_KEY_3; break;
|
||||
case TR::Entity::KEY_HOLE_4 : item = TR::Entity::INV_KEY_4; break;
|
||||
case TR::Entity::INV_PISTOLS :
|
||||
case TR::Entity::INV_SHOTGUN :
|
||||
case TR::Entity::INV_MAGNUMS :
|
||||
case TR::Entity::INV_UZIS : return false;
|
||||
default : return false;
|
||||
}
|
||||
|
||||
if (getCountPtr(item)) {
|
||||
remove(item);
|
||||
bool use(TR::Entity::Type type) {
|
||||
if (contains(type) > -1) {
|
||||
remove(type);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool toggle(Page curPage = PAGE_INVENTORY) {
|
||||
bool toggle(Page curPage = PAGE_INVENTORY, TR::Entity::Type type = TR::Entity::NONE) {
|
||||
if (phaseRing == 0.0f || phaseRing == 1.0f) {
|
||||
active = !active;
|
||||
vec3 p;
|
||||
@ -329,6 +293,13 @@ struct Inventory {
|
||||
phasePage = 1.0f;
|
||||
phaseSelect = 1.0f;
|
||||
page = targetPage = curPage;
|
||||
|
||||
if (type != TR::Entity::NONE) {
|
||||
int i = contains(type);
|
||||
if (i >= 0)
|
||||
pageItemIndex[page] = getItemIndex(page, i);
|
||||
}
|
||||
|
||||
index = targetIndex = pageItemIndex[page];
|
||||
}
|
||||
}
|
||||
@ -382,7 +353,8 @@ struct Inventory {
|
||||
}
|
||||
|
||||
void update() {
|
||||
doPhase(active, 2.0f, phaseRing);
|
||||
if (phaseChoose == 0.0f)
|
||||
doPhase(active, 2.0f, phaseRing);
|
||||
doPhase(true, 1.6f, phasePage);
|
||||
doPhase(chosen, 4.0f, phaseChoose);
|
||||
doPhase(true, 2.5f, phaseSelect);
|
||||
@ -465,13 +437,24 @@ struct Inventory {
|
||||
if (ready && chosen && phaseChoose == 1.0f && item->anim->isEnded) {
|
||||
TR::Entity::Type type = item->type;
|
||||
|
||||
if (type == TR::Entity::INV_PISTOLS || type == TR::Entity::INV_SHOTGUN || type == TR::Entity::INV_MAGNUMS || type == TR::Entity::INV_UZIS ||
|
||||
type == TR::Entity::INV_MEDIKIT_SMALL || type == TR::Entity::INV_MEDIKIT_BIG) {
|
||||
|
||||
game->invUse(type, TR::Entity::NONE);
|
||||
toggle();
|
||||
switch (type) {
|
||||
case TR::Entity::INV_PASSPORT :
|
||||
case TR::Entity::INV_PASSPORT_CLOSED :
|
||||
case TR::Entity::INV_MAP :
|
||||
case TR::Entity::INV_COMPASS :
|
||||
case TR::Entity::INV_HOME :
|
||||
case TR::Entity::INV_DETAIL :
|
||||
case TR::Entity::INV_SOUND :
|
||||
case TR::Entity::INV_CONTROLS :
|
||||
case TR::Entity::INV_GAMMA :
|
||||
case TR::Entity::INV_AMMO_PISTOLS :
|
||||
case TR::Entity::INV_AMMO_SHOTGUN :
|
||||
case TR::Entity::INV_AMMO_MAGNUMS :
|
||||
case TR::Entity::INV_AMMO_UZIS : break;
|
||||
default :
|
||||
game->invUse(type);
|
||||
toggle();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -518,13 +501,27 @@ struct Inventory {
|
||||
sprintf(buf, "%d %c", item->count, spec);
|
||||
for (int i = 0; buf[i] != ' '; i++)
|
||||
buf[i] -= 47;
|
||||
UI::textOut(game, pos, buf, UI::aRight, width);
|
||||
UI::textOut(pos, buf, UI::aRight, width);
|
||||
}
|
||||
}
|
||||
|
||||
void renderItemText(const Item *item, float width) {
|
||||
UI::textOut(game, vec2(0, 480 - 16), item->desc.name, UI::aCenter, width);
|
||||
UI::textOut(vec2(0, 480 - 16), item->desc.name, UI::aCenter, width);
|
||||
renderItemCount(item, vec2(width / 2 - 160, 480 - 96), 320);
|
||||
|
||||
if (phaseChoose == 1.0f) {
|
||||
if (item->type == TR::Entity::INV_PASSPORT ||
|
||||
item->type == TR::Entity::INV_MAP ||
|
||||
item->type == TR::Entity::INV_COMPASS ||
|
||||
item->type == TR::Entity::INV_HOME ||
|
||||
item->type == TR::Entity::INV_DETAIL ||
|
||||
item->type == TR::Entity::INV_SOUND ||
|
||||
item->type == TR::Entity::INV_CONTROLS ||
|
||||
item->type == TR::Entity::INV_GAMMA)
|
||||
{
|
||||
UI::textOut(vec2(0, 240), "Not implemented yet!", UI::aCenter, width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void renderPage(int page) {
|
||||
@ -632,16 +629,16 @@ struct Inventory {
|
||||
|
||||
static const char* pageTitle[PAGE_MAX] = { "OPTION", "INVENTORY", "ITEMS" };
|
||||
|
||||
UI::textOut(game, 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)) {
|
||||
UI::textOut(game, vec2(16, 32), "\x5B", UI::aLeft, UI::width);
|
||||
UI::textOut(game, vec2( 0, 32), "\x5B", UI::aRight, UI::width - 20);
|
||||
UI::textOut(vec2(16, 32), "[", UI::aLeft, UI::width);
|
||||
UI::textOut(vec2( 0, 32), "[", UI::aRight, UI::width - 20);
|
||||
}
|
||||
|
||||
if (page > PAGE_OPTION && getItemsCount(page - 1)) {
|
||||
UI::textOut(game, vec2(16, 480 - 16), "\x5D", UI::aLeft, UI::width);
|
||||
UI::textOut(game, vec2(0, 480 - 16), "\x5D", UI::aRight, UI::width - 20);
|
||||
UI::textOut(vec2(16, 480 - 16), "]", UI::aLeft, UI::width);
|
||||
UI::textOut(vec2(0, 480 - 16), "]", UI::aRight, UI::width - 20);
|
||||
}
|
||||
|
||||
if (index == targetIndex)
|
||||
|
114
src/lara.h
114
src/lara.h
@ -192,6 +192,7 @@ struct Lara : Character {
|
||||
};
|
||||
|
||||
bool home;
|
||||
bool dozy;
|
||||
|
||||
struct Weapon {
|
||||
enum Type { EMPTY = -1, PISTOLS, SHOTGUN, MAGNUMS, UZIS, MAX };
|
||||
@ -216,7 +217,10 @@ struct Lara : Character {
|
||||
|
||||
ActionCommand actionList[MAX_TRIGGER_ACTIONS];
|
||||
|
||||
int lastPickUp;
|
||||
TR::Entity::Type usedKey;
|
||||
TR::Entity *puzzleEntity;
|
||||
TR::Entity *pickupEntity;
|
||||
|
||||
int viewTarget;
|
||||
int roomPrev; // water out from room
|
||||
vec2 rotFactor;
|
||||
@ -388,7 +392,7 @@ struct Lara : Character {
|
||||
|
||||
} *braid;
|
||||
|
||||
Lara(IGame *game, int entity, bool home) : Character(game, entity, LARA_MAX_HEALTH), home(home), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos), viewTarget(-1), braid(NULL) {
|
||||
Lara(IGame *game, int entity, bool home) : Character(game, entity, LARA_MAX_HEALTH), home(home), dozy(false), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos), viewTarget(-1), braid(NULL) {
|
||||
|
||||
if (getEntity().type == TR::Entity::LARA) {
|
||||
if (getRoom().flags.water)
|
||||
@ -437,7 +441,7 @@ struct Lara : Character {
|
||||
//reset(5, vec3(38643, -3072, 92370), PI * 0.5f); // level 3a (gears)
|
||||
//reset(43, vec3(64037, 6656, 48229), PI); // level 3b (movingblock)
|
||||
//reset(0, vec3(40913, -1012, 42252), PI); // level 8c
|
||||
//reset(10, vec3(90443, 11264 - 256, 114614), PI, true); // villa mortal 2
|
||||
//reset(10, vec3(90443, 11264 - 256, 114614), PI, STAND_ONWATER); // villa mortal 2
|
||||
#endif
|
||||
chestOffset = animation.getJoints(getMatrix(), 7).pos;
|
||||
}
|
||||
@ -461,7 +465,7 @@ struct Lara : Character {
|
||||
return TR::NO_ROOM;
|
||||
}
|
||||
|
||||
void reset(int room, const vec3 &pos, float angle, bool onwater = false) {
|
||||
void reset(int room, const vec3 &pos, float angle, Stand forceStand = STAND_GROUND) {
|
||||
if (room == TR::NO_ROOM) {
|
||||
stand = STAND_AIR;
|
||||
room = getRoomByPos(pos);
|
||||
@ -480,10 +484,16 @@ struct Lara : Character {
|
||||
getEntity().room = room;
|
||||
this->pos = pos;
|
||||
this->angle = vec3(0.0f, angle, 0.0f);
|
||||
if (onwater) {
|
||||
stand = STAND_ONWATER;
|
||||
animation.setAnim(ANIM_TO_ONWATER);
|
||||
|
||||
if (forceStand != STAND_GROUND) {
|
||||
stand = forceStand;
|
||||
switch (stand) {
|
||||
case STAND_ONWATER : animation.setAnim(ANIM_TO_ONWATER); break;
|
||||
case STAND_UNDERWATER : animation.setAnim(ANIM_UNDERWATER); break;
|
||||
default : ;
|
||||
}
|
||||
}
|
||||
|
||||
updateEntity();
|
||||
updateLights(false);
|
||||
}
|
||||
@ -605,6 +615,8 @@ struct Lara : Character {
|
||||
}
|
||||
|
||||
bool canDrawWeapon() {
|
||||
if (dozy) return true;
|
||||
|
||||
return wpnCurrent != Weapon::EMPTY
|
||||
&& emptyHands()
|
||||
&& animation.index != ANIM_CLIMB_3
|
||||
@ -1255,6 +1267,8 @@ struct Lara : Character {
|
||||
}
|
||||
|
||||
virtual void hit(float damage, Controller *enemy = NULL) {
|
||||
if (dozy) return;
|
||||
|
||||
damageTime = LARA_DAMAGE_TIME;
|
||||
|
||||
Character::hit(damage, enemy);
|
||||
@ -1273,7 +1287,7 @@ struct Lara : Character {
|
||||
Core::lightColor[1 + 0] = Core::lightColor[1 + 1] = vec4(0, 0, 0, 1);
|
||||
};
|
||||
|
||||
void useItem(TR::Entity::Type item) {
|
||||
bool useItem(TR::Entity::Type item) {
|
||||
switch (item) {
|
||||
case TR::Entity::INV_PISTOLS : wpnChange(Lara::Weapon::PISTOLS); break;
|
||||
case TR::Entity::INV_SHOTGUN : wpnChange(Lara::Weapon::SHOTGUN); break;
|
||||
@ -1285,8 +1299,21 @@ struct Lara : Character {
|
||||
health = min(LARA_MAX_HEALTH, health + (item == TR::Entity::INV_MEDIKIT_SMALL ? LARA_MAX_HEALTH / 2 : LARA_MAX_HEALTH));
|
||||
playSound(TR::SND_HEALTH, pos, Sound::PAN);
|
||||
break;
|
||||
default : ;
|
||||
case TR::Entity::INV_PUZZLE_1 :
|
||||
case TR::Entity::INV_PUZZLE_2 :
|
||||
case TR::Entity::INV_PUZZLE_3 :
|
||||
case TR::Entity::INV_PUZZLE_4 :
|
||||
case TR::Entity::INV_KEY_1 :
|
||||
case TR::Entity::INV_KEY_2 :
|
||||
case TR::Entity::INV_KEY_3 :
|
||||
case TR::Entity::INV_KEY_4 :
|
||||
if (usedKey == item)
|
||||
return false;
|
||||
usedKey = item;
|
||||
break;
|
||||
default : return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool waterOut() {
|
||||
@ -1347,7 +1374,7 @@ struct Lara : Character {
|
||||
if (stand == STAND_UNDERWATER)
|
||||
angle.x = -25 * DEG2RAD;
|
||||
|
||||
lastPickUp = i;
|
||||
pickupEntity = &item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1422,19 +1449,33 @@ struct Lara : Character {
|
||||
}
|
||||
break;
|
||||
case TR::Level::Trigger::KEY :
|
||||
if (level->entities[info.trigCmd[0].args].flags.active)
|
||||
if (level->entities[info.trigCmd[0].args].flags.active || state != STATE_STOP)
|
||||
return;
|
||||
actionState = level->entities[info.trigCmd[0].args].type == TR::Entity::KEY_HOLE_1 ? STATE_USE_KEY : STATE_USE_PUZZLE;
|
||||
|
||||
actionState = level->entities[info.trigCmd[0].args].isKeyHole() ? STATE_USE_KEY : STATE_USE_PUZZLE;
|
||||
if (!animation.canSetState(actionState))
|
||||
return;
|
||||
limit = actionState == STATE_USE_KEY ? &TR::Limits::KEY_HOLE : &TR::Limits::PUZZLE_HOLE;
|
||||
if (!checkInteraction((Controller*)level->entities[info.trigCmd[0].args].controller, *limit, isPressed(ACTION)))
|
||||
return;
|
||||
if (!game->invUse(TR::Entity::NONE, level->entities[info.trigCmd[0].args].type)) {
|
||||
playSound(TR::SND_NO, pos, Sound::PAN);
|
||||
|
||||
limit = actionState == STATE_USE_PUZZLE ? &TR::Limits::PUZZLE_HOLE : &TR::Limits::KEY_HOLE;
|
||||
if (!checkInteraction((Controller*)level->entities[info.trigCmd[0].args].controller, *limit, isPressed(ACTION) || usedKey != TR::Entity::NONE))
|
||||
return;
|
||||
|
||||
if (!animation.canSetState(actionState))
|
||||
return;
|
||||
|
||||
if (usedKey == TR::Entity::NONE) {
|
||||
if (isPressed(ACTION) && !game->invChooseKey(level->entities[info.trigCmd[0].args].type))
|
||||
playSound(TR::SND_NO, pos, Sound::PAN); // no compatible items in inventory
|
||||
return;
|
||||
}
|
||||
lastPickUp = info.trigCmd[0].args; // TODO: it's not pickup, it's key/puzzle hole
|
||||
|
||||
if (TR::Entity::convToInv(TR::Entity::getKeyForHole(level->entities[info.trigCmd[0].args].type)) != usedKey) { // check compatibility if user select other
|
||||
playSound(TR::SND_NO, pos, Sound::PAN); // uncompatible item
|
||||
return;
|
||||
}
|
||||
|
||||
puzzleEntity = actionState == STATE_USE_PUZZLE ? &level->entities[info.trigCmd[0].args] : NULL;
|
||||
game->invUse(usedKey);
|
||||
break;
|
||||
case TR::Level::Trigger::PICKUP :
|
||||
if (!isActive) // check if item is not picked up
|
||||
@ -1498,6 +1539,8 @@ struct Lara : Character {
|
||||
}
|
||||
|
||||
virtual Stand getStand() {
|
||||
if (dozy) return STAND_UNDERWATER;
|
||||
|
||||
if (state == STATE_HANG || state == STATE_HANG_LEFT || state == STATE_HANG_RIGHT) {
|
||||
if (input & ACTION)
|
||||
return STAND_HANG;
|
||||
@ -1921,6 +1964,19 @@ struct Lara : Character {
|
||||
|
||||
virtual int getInput() { // TODO: updateInput
|
||||
if (level->cutEntity > -1) return 0;
|
||||
input = 0;
|
||||
|
||||
if (!dozy && Input::state[cAction] && Input::state[cJump] && Input::state[cLook] && Input::state[cStepRight]) {
|
||||
dozy = true;
|
||||
reset(getRoomIndex(), pos - vec3(0, 512, 0), angle.y, STAND_UNDERWATER);
|
||||
return input;
|
||||
}
|
||||
|
||||
if (dozy && Input::state[cWalk]) {
|
||||
dozy = false;
|
||||
return input;
|
||||
}
|
||||
|
||||
input = Character::getInput();
|
||||
if (input & DEATH) return input;
|
||||
|
||||
@ -1969,20 +2025,22 @@ struct Lara : Character {
|
||||
virtual void doCustomCommand(int curFrame, int prevFrame) {
|
||||
switch (state) {
|
||||
case STATE_PICK_UP : {
|
||||
TR::Entity &item = level->entities[lastPickUp];
|
||||
if (!item.flags.invisible) {
|
||||
if (pickupEntity && !pickupEntity->flags.invisible) {
|
||||
int pickupFrame = stand == STAND_GROUND ? PICKUP_FRAME_GROUND : PICKUP_FRAME_UNDERWATER;
|
||||
if (animation.isFrameActive(pickupFrame)) {
|
||||
item.flags.invisible = true;
|
||||
game->invAdd(item.type, 1);
|
||||
pickupEntity->flags.invisible = true;
|
||||
game->invAdd(pickupEntity->type, 1);
|
||||
pickupEntity = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_USE_PUZZLE : {
|
||||
TR::Entity &item = level->entities[lastPickUp];
|
||||
if (animation.isFrameActive(PUZZLE_FRAME))
|
||||
((Controller*)item.controller)->meshSwap(0, level->extra.puzzleSet);
|
||||
if (puzzleEntity && animation.isFrameActive(PUZZLE_FRAME)) {
|
||||
int doneIdx = TR::Entity::convToInv(TR::Entity::getKeyForHole(puzzleEntity->type)) - TR::Entity::INV_PUZZLE_1;
|
||||
((Controller*)puzzleEntity->controller)->meshSwap(0, level->extra.puzzleDone[doneIdx]);
|
||||
puzzleEntity = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1994,7 +2052,7 @@ struct Lara : Character {
|
||||
if (damageTime > 0.0f)
|
||||
damageTime = max(0.0f, damageTime - Core::deltaTime);
|
||||
|
||||
if (stand == STAND_UNDERWATER) {
|
||||
if (stand == STAND_UNDERWATER && !dozy) {
|
||||
if (oxygen > 0.0f)
|
||||
oxygen -= Core::deltaTime;
|
||||
else
|
||||
@ -2002,6 +2060,8 @@ struct Lara : Character {
|
||||
} else
|
||||
if (oxygen < LARA_MAX_OXYGEN)
|
||||
oxygen = min(LARA_MAX_OXYGEN, oxygen += Core::deltaTime * 10.0f);
|
||||
|
||||
usedKey = TR::Entity::NONE;
|
||||
}
|
||||
|
||||
virtual void updateAnimation(bool commands) {
|
||||
@ -2367,7 +2427,9 @@ struct Lara : Character {
|
||||
}
|
||||
|
||||
updateEntity();
|
||||
if (dozy) stand = STAND_GROUND;
|
||||
checkRoom();
|
||||
if (dozy) stand = STAND_UNDERWATER;
|
||||
}
|
||||
|
||||
virtual void applyFlow(TR::Camera &sink) {
|
||||
|
19
src/level.h
19
src/level.h
@ -127,9 +127,10 @@ struct Level : IGame {
|
||||
camera->shake = time;
|
||||
}
|
||||
|
||||
virtual bool invUse(TR::Entity::Type item, TR::Entity::Type slot) {
|
||||
lara->useItem(item);
|
||||
return inventory.use(item, slot);
|
||||
virtual bool invUse(TR::Entity::Type type) {
|
||||
if (!lara->useItem(type))
|
||||
return inventory.use(type);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void invAdd(TR::Entity::Type type, int count) {
|
||||
@ -140,6 +141,10 @@ struct Level : IGame {
|
||||
return inventory.getCountPtr(type);
|
||||
}
|
||||
|
||||
virtual bool invChooseKey(TR::Entity::Type hole) {
|
||||
return inventory.chooseKey(hole);
|
||||
}
|
||||
|
||||
virtual Sound::Sample* playSound(int id, const vec3 &pos, int flags, int group = -1) const {
|
||||
if (level.version == TR::Level::VER_TR1_PSX && id == TR::SND_SECRET)
|
||||
return NULL;
|
||||
@ -636,8 +641,8 @@ struct Level : IGame {
|
||||
|
||||
void update() {
|
||||
#ifdef LEVEL_EDITOR
|
||||
if (Input::down[ikCtrl]) {
|
||||
Input::down[ikCtrl] = false;
|
||||
if (Input::down[ik0]) {
|
||||
Input::down[ik0] = false;
|
||||
lara->reset(TR::NO_ROOM, camera->pos, camera->angle.y, false);
|
||||
}
|
||||
#endif
|
||||
@ -993,11 +998,13 @@ struct Level : IGame {
|
||||
}
|
||||
}
|
||||
|
||||
if (lara->stand == Lara::STAND_ONWATER || lara->stand == Character::STAND_UNDERWATER)
|
||||
if (!lara->dozy && (lara->stand == Lara::STAND_ONWATER || lara->stand == Character::STAND_UNDERWATER))
|
||||
UI::renderBar(1, vec2(32, 32), size, oxygen);
|
||||
|
||||
inventory.renderUI();
|
||||
|
||||
UI::renderHelp();
|
||||
|
||||
UI::end();
|
||||
}
|
||||
|
||||
|
50
src/ui.h
50
src/ui.h
@ -7,6 +7,8 @@
|
||||
namespace UI {
|
||||
IGame *game;
|
||||
float width;
|
||||
float helpTipTime;
|
||||
bool showHelp;
|
||||
|
||||
const static uint8 char_width[110] = {
|
||||
14, 11, 11, 11, 11, 11, 11, 13, 8, 11, 12, 11, 13, 13, 12, 11, 12, 12, 11, 12, 13, 13, 13, 12,
|
||||
@ -84,7 +86,7 @@ namespace UI {
|
||||
Core::setDepthTest(true);
|
||||
}
|
||||
|
||||
void textOut(IGame *game, const vec2 &pos, const char *text, Align align = aLeft, float width = 0) {
|
||||
void textOut(const vec2 &pos, const char *text, Align align = aLeft, float width = 0) {
|
||||
if (!text) return;
|
||||
|
||||
TR::Level *level = game->getLevel();
|
||||
@ -101,6 +103,8 @@ namespace UI {
|
||||
if (align == aRight)
|
||||
x += int(width - getTextSize(text).x);
|
||||
|
||||
int left = x;
|
||||
|
||||
while (char c = *text++) {
|
||||
if (c == ' ' || c == '_') {
|
||||
x += 6;
|
||||
@ -108,7 +112,7 @@ namespace UI {
|
||||
}
|
||||
|
||||
if (c == '@') {
|
||||
x = int(pos.x);
|
||||
x = left;
|
||||
y += 16;
|
||||
continue;
|
||||
}
|
||||
@ -130,10 +134,18 @@ namespace UI {
|
||||
|
||||
void init(IGame *game) {
|
||||
UI::game = game;
|
||||
showHelp = false;
|
||||
helpTipTime = 5.0f;
|
||||
}
|
||||
|
||||
void update() {
|
||||
//
|
||||
if (Input::down[ikH]) {
|
||||
Input::down[ikH] = false;
|
||||
showHelp = !showHelp;
|
||||
helpTipTime = 0.0f;
|
||||
}
|
||||
if (helpTipTime > 0.0f)
|
||||
helpTipTime -= Core::deltaTime;
|
||||
}
|
||||
|
||||
void renderControl(const vec2 &pos, float size, bool active) {
|
||||
@ -181,6 +193,38 @@ namespace UI {
|
||||
if (value > 0.0f)
|
||||
mesh->addBar(buffer.indices, buffer.vertices, buffer.iCount, buffer.vCount, type, pos, vec2(size.x * value, size.y), 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
const char *helpText = \
|
||||
"Controls gamepad, touch and keyboard:@"\
|
||||
" H - Show or hide this help@"\
|
||||
" TAB - Inventory@"\
|
||||
" LEFT - Left@"\
|
||||
" RIGHT - Right@"\
|
||||
" UP - Run@"\
|
||||
" DOWN - Back@"\
|
||||
" SHIFT - Walk@"\
|
||||
" SPACE - Draw Weapon@"\
|
||||
" CTRL - Action@"\
|
||||
" ALT - Jump@"\
|
||||
" Z - Step Left@"\
|
||||
" X - Step Right@"\
|
||||
" A - Roll@"\
|
||||
" C - Look # not implemented #@"\
|
||||
" V - First Person View@@"
|
||||
"Actions:@"\
|
||||
" Out of water - Run + Action@"\
|
||||
" Handstand - Run + Walk@"\
|
||||
" Swan dive - Run + Walk + jump@"\
|
||||
" DOZY on - Look + Step Right + Action + Jump@"\
|
||||
" DOZY off - Walk@";
|
||||
|
||||
void renderHelp() {
|
||||
if (showHelp)
|
||||
textOut(vec2(0, 64), helpText, aRight, width - 32);
|
||||
else
|
||||
if (helpTipTime > 0.0f)
|
||||
textOut(vec2(0, 480 - 32), "Press H for help", aCenter, width);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user