1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-16 01:54:38 +02:00

#11 controls mapping; saving settings

This commit is contained in:
XProger
2018-02-25 07:03:28 +03:00
parent 6acb509ab4
commit 3009f2387a
14 changed files with 324 additions and 136 deletions

View File

@@ -448,7 +448,7 @@ struct Camera : ICamera {
virtual void update() { virtual void update() {
if (shake > 0.0f) { if (shake > 0.0f) {
shake = max(0.0f, shake - Core::deltaTime); shake = max(0.0f, shake - Core::deltaTime);
osJoyVibrate(Core::settings.controls[cameraIndex].joyIndex, clamp(shake, 0.0f, 1.0f), 0); Input::setJoyVibrate(cameraIndex, clamp(shake, 0.0f, 1.0f), 0);
} }
if (mode == MODE_CUTSCENE) { if (mode == MODE_CUTSCENE) {

View File

@@ -164,12 +164,6 @@
#define GENERATE_WATER_PLANE #define GENERATE_WATER_PLANE
#endif #endif
extern int osGetTime();
extern bool osSave(const char *name, const void *data, int size);
extern bool osJoyReady(int index);
extern void osJoyVibrate(int index, float L, float R);
#include "utils.h" #include "utils.h"
extern void* osMutexInit (); extern void* osMutexInit ();
@@ -177,6 +171,18 @@ extern void osMutexFree (void *obj);
extern void osMutexLock (void *obj); extern void osMutexLock (void *obj);
extern void osMutexUnlock (void *obj); extern void osMutexUnlock (void *obj);
extern int osGetTime ();
extern bool osJoyReady (int index);
extern void osJoyVibrate (int index, float L, float R);
extern bool osCacheWrite (const char *name, const char *data, int size);
extern Stream* osCacheRead (const char *name);
extern bool osSaveGame (const char *data, int size);
extern Stream* osLoadGame ();
struct Mutex { struct Mutex {
void *obj; void *obj;
@@ -254,8 +260,8 @@ enum ControlKey {
}; };
struct KeySet { struct KeySet {
InputKey key; uint8 key;
JoyKey joy; uint8 joy;
KeySet() {} KeySet() {}
KeySet(InputKey key, JoyKey joy) : key(key), joy(joy) {} KeySet(InputKey key, JoyKey joy) : key(key), joy(joy) {}
@@ -285,10 +291,14 @@ namespace Core {
#endif #endif
} support; } support;
#define SETTINGS_VERSION 1
struct Settings { struct Settings {
enum Quality { LOW, MEDIUM, HIGH }; enum Quality { LOW, MEDIUM, HIGH };
enum Stereo { STEREO_OFF, STEREO_ON, STEREO_SPLIT }; enum Stereo { STEREO_OFF, STEREO_ON, STEREO_SPLIT };
uint8 version;
struct { struct {
union { union {
struct { struct {
@@ -342,7 +352,9 @@ namespace Core {
KeySet keys[cMAX]; KeySet keys[cMAX];
} controls[2]; } controls[2];
uint8 playerIndex; // temporary, used only for setting controls // temporary, used only for setting controls
uint8 playerIndex;
uint8 ctrlIndex;
} settings; } settings;
bool resetState; bool resetState;
@@ -1021,6 +1033,8 @@ namespace Core {
whiteTex = new Texture(1, 1, Texture::RGBA, Texture::NEAREST, &data); whiteTex = new Texture(1, 1, Texture::RGBA, Texture::NEAREST, &data);
// init settings // init settings
settings.version = SETTINGS_VERSION;
settings.detail.setFilter (Core::Settings::HIGH); settings.detail.setFilter (Core::Settings::HIGH);
settings.detail.setLighting (Core::Settings::HIGH); settings.detail.setLighting (Core::Settings::HIGH);
settings.detail.setShadows (Core::Settings::HIGH); settings.detail.setShadows (Core::Settings::HIGH);
@@ -1076,7 +1090,7 @@ namespace Core {
ctrl.keys[ cDash ] = KeySet( ikNone, jkRT ); ctrl.keys[ cDash ] = KeySet( ikNone, jkRT );
ctrl.keys[ cRoll ] = KeySet( ikNone, jkB ); ctrl.keys[ cRoll ] = KeySet( ikNone, jkB );
ctrl.keys[ cInventory ] = KeySet( ikNone, jkSelect ); ctrl.keys[ cInventory ] = KeySet( ikNone, jkSelect );
ctrl.keys[ cStart ] = KeySet( ikEnter, jkStart ); ctrl.keys[ cStart ] = KeySet( ikNone, jkStart );
} }
// use D key for jump in browsers // use D key for jump in browsers

View File

@@ -34,10 +34,22 @@ namespace Game {
if (level) level->stopChannel(channel); if (level) level->stopChannel(channel);
} }
void readSettings() {
Stream *stream = osCacheRead("settings");
if (!stream) return;
uint8 version;
stream->read(version);
if (version == SETTINGS_VERSION && stream->size == sizeof(Core::Settings))
stream->raw((char*)&Core::settings + 1, stream->size - 1); // read settings data right after version number
delete stream;
}
void init(Stream *lvl) { void init(Stream *lvl) {
nextLevel = NULL; nextLevel = NULL;
Core::init(); Core::init();
readSettings();
shaderCache = new ShaderCache(); shaderCache = new ShaderCache();
UI::init(level); UI::init(level);
@@ -104,7 +116,7 @@ namespace Game {
return true; return true;
Input::update(); Input::update();
/*
if (level->camera) { if (level->camera) {
if (Input::down[ikV]) { // third <-> first person view if (Input::down[ikV]) { // third <-> first person view
level->camera->changeView(!level->camera->firstPerson); level->camera->changeView(!level->camera->firstPerson);
@@ -122,7 +134,7 @@ namespace Game {
level->loadGame(0); level->loadGame(0);
Input::down[ikL] = false; Input::down[ikL] = false;
} }
*/
if (!level->level.isTitle()) { if (!level->level.isTitle()) {
if (Input::state[0][cStart]) level->addPlayer(0); if (Input::state[0][cStart]) level->addPlayer(0);
if (Input::state[1][cStart]) level->addPlayer(1); if (Input::state[1][cStart]) level->addPlayer(1);

View File

@@ -38,8 +38,8 @@ namespace TR {
VER_TR3_PC = VER_TR3 | VER_PC, VER_TR3_PC = VER_TR3 | VER_PC,
VER_TR3_PSX = VER_TR3 | VER_PSX, VER_TR3_PSX = VER_TR3 | VER_PSX,
VER_MAX = 0xFFFFFFFF, VER_MAX = 0xFFFFFFFF,
}; };
enum LevelID { enum LevelID {
@@ -506,6 +506,9 @@ namespace TR {
if (Stream::existsContent("data/JUNGLE.TR2")) if (Stream::existsContent("data/JUNGLE.TR2"))
return VER_TR3_PC; return VER_TR3_PC;
if (Stream::existsContent("DATA/JUNGLE.PSX"))
return VER_TR3_PSX;
useEasyStart = false; useEasyStart = false;
return VER_UNKNOWN; return VER_UNKNOWN;
} }
@@ -542,6 +545,7 @@ namespace TR {
} }
case VER_TR2_PSX : sprintf(dst, "DATA/%s.PSX", LEVEL_INFO[id].name); break; case VER_TR2_PSX : sprintf(dst, "DATA/%s.PSX", LEVEL_INFO[id].name); break;
case VER_TR3_PC : sprintf(dst, isCutsceneLevel(id) ? "cuts/%s.TR2" : "data/%s.TR2", LEVEL_INFO[id].name); break; case VER_TR3_PC : sprintf(dst, isCutsceneLevel(id) ? "cuts/%s.TR2" : "data/%s.TR2", LEVEL_INFO[id].name); break;
case VER_TR3_PSX : sprintf(dst, isCutsceneLevel(id) ? "CUTS/%s.PSX" : "DATA/%s.PSX", LEVEL_INFO[id].name); break;
default : ASSERT(false); default : ASSERT(false);
} }
} else { } else {

View File

@@ -7,7 +7,7 @@
#define INPUT_JOY_COUNT 4 #define INPUT_JOY_COUNT 4
namespace Input { namespace Input {
InputKey lastKey;
bool down[ikMAX]; bool down[ikMAX];
bool state[2][cMAX]; bool state[2][cMAX];
@@ -19,9 +19,10 @@ namespace Input {
} mouse; } mouse;
struct Joystick { struct Joystick {
vec2 L, R; vec2 L, R;
float LT, RT; float LT, RT;
bool down[jkMAX]; JoyKey lastKey;
bool down[jkMAX];
} joy[INPUT_JOY_COUNT]; } joy[INPUT_JOY_COUNT];
struct Touch { struct Touch {
@@ -77,6 +78,8 @@ namespace Input {
default : ; default : ;
} }
down[key] = value; down[key] = value;
if (value && key <= ikZ) lastKey = key;
} }
void setPos(InputKey key, const vec2 &pos) { void setPos(InputKey key, const vec2 &pos) {
@@ -95,7 +98,12 @@ namespace Input {
} }
void setJoyDown(int index, JoyKey key, bool value) { void setJoyDown(int index, JoyKey key, bool value) {
if (joy[index].down[key] == value)
return;
joy[index].down[key] = value; joy[index].down[key] = value;
if (value) joy[index].lastKey = key;
} }
void setJoyPos(int index, JoyKey key, const vec2 &pos) { void setJoyPos(int index, JoyKey key, const vec2 &pos) {
@@ -109,6 +117,12 @@ namespace Input {
setJoyDown(index, key, pos.x > 0.0f); // gamepad LT, RT auto-down state setJoyDown(index, key, pos.x > 0.0f); // gamepad LT, RT auto-down state
} }
void setJoyVibrate(int playerIndex, float L, float R) {
if (!Core::settings.controls[playerIndex].vibration)
return;
osJoyVibrate(Core::settings.controls[playerIndex].joyIndex, L, R);
}
InputKey getTouch(int id) { InputKey getTouch(int id) {
for (int i = 0; i < COUNT(touch); i++) for (int i = 0; i < COUNT(touch); i++)
if (down[ikTouchA + i] && touch[i].id == id) if (down[ikTouchA + i] && touch[i].id == id)

View File

@@ -17,12 +17,15 @@
#define TITLE_LOADING 64.0f #define TITLE_LOADING 64.0f
#define LINE_HEIGHT 20.0f #define LINE_HEIGHT 20.0f
static const struct OptionItem *waitForKey = NULL;
struct OptionItem { struct OptionItem {
enum Type { enum Type {
TYPE_TITLE, TYPE_TITLE,
TYPE_EMPTY, TYPE_EMPTY,
TYPE_BUTTON, TYPE_BUTTON,
TYPE_PARAM, TYPE_PARAM,
TYPE_KEY,
} type; } type;
StringID title; StringID title;
intptr_t offset; intptr_t offset;
@@ -31,7 +34,11 @@ struct OptionItem {
uint8 maxValue; uint8 maxValue;
bool bar; bool bar;
OptionItem(Type type = TYPE_EMPTY, StringID title = STR_NOT_IMPLEMENTED, intptr_t offset = 0, uint32 color = 0xFFFFFFFF, int icon = 0, uint8 maxValue = 0, bool bar = false) : type(type), title(title), offset(offset), color(color), icon(icon), maxValue(maxValue), bar(bar) {} OptionItem(Type type = TYPE_EMPTY, int title = STR_NOT_IMPLEMENTED, intptr_t offset = 0, uint32 color = 0xFFFFFFFF, int icon = 0, uint8 maxValue = 0, bool bar = false) : type(type), title(StringID(title)), offset(offset), color(color), icon(icon), maxValue(maxValue), bar(bar) {}
void setValue(uint8 value, Core::Settings *settings) const {
*(uint8*)(intptr_t(settings) + offset) = value;
}
float drawParam(float x, float y, float w, StringID oStr, bool active, uint8 value) const { float drawParam(float x, float y, float w, StringID oStr, bool active, uint8 value) const {
if (oStr != STR_NOT_IMPLEMENTED) { if (oStr != STR_NOT_IMPLEMENTED) {
@@ -40,12 +47,22 @@ struct OptionItem {
w = w * 0.5f - 32.0f; w = w * 0.5f - 32.0f;
} }
UI::textOut(vec2(x, y), StringID(color + int(value)), UI::aCenter, w); // color as StringID StringID vStr = StringID(color + int(value));
if (active) {
uint8 alpha = 255;
if (type == TYPE_KEY && waitForKey == this) {
vStr = STR_PRESS_ANY_KEY;
float t = (Core::getTime() % 1000) / 1000.0f;
t = 0.2f + (sinf(t * PI * 2) * 0.5f + 0.5f) * 0.8f;
alpha = uint8(t * 255.0f);
}
UI::textOut(vec2(x, y), vStr, UI::aCenter, w, alpha, UI::SHADE_GRAY); // color as StringID
if (type == TYPE_PARAM && active) {
float maxWidth = UI::getTextSize(STR[color + value]).x; float maxWidth = UI::getTextSize(STR[color + value]).x;
maxWidth = maxWidth * 0.5f + 8.0f; maxWidth = maxWidth * 0.5f + 8.0f;
x += w * 0.5f; x += w * 0.5f;
if (value > 0) UI::specOut(vec2(x - maxWidth - 16.0f, y), 108); if (value > 0) UI::specOut(vec2(x - maxWidth - 16.0f, y), 108);
if (value < maxValue) UI::specOut(vec2(x + maxWidth, y), 109); if (value < maxValue) UI::specOut(vec2(x + maxWidth, y), 109);
} }
@@ -71,7 +88,7 @@ struct OptionItem {
switch (type) { switch (type) {
case TYPE_TITLE : case TYPE_TITLE :
UI::renderBar(UI::BAR_OPTION, vec2(x, y - LINE_HEIGHT + 6), vec2(w, LINE_HEIGHT - 6), 1.0f, 0x802288FF, 0, 0, 0); UI::renderBar(UI::BAR_OPTION, vec2(x, y - LINE_HEIGHT + 6), vec2(w, LINE_HEIGHT - 6), 1.0f, 0x802288FF, 0, 0, 0);
UI::textOut(vec2(x, y), title, UI::aCenter, w, UI::SHADE_GRAY); UI::textOut(vec2(x, y), title, UI::aCenter, w, 255, UI::SHADE_GRAY);
case TYPE_EMPTY : break; case TYPE_EMPTY : break;
case TYPE_BUTTON : { case TYPE_BUTTON : {
const char *caption = offset ? (char*)offset : STR[title]; const char *caption = offset ? (char*)offset : STR[title];
@@ -79,6 +96,7 @@ struct OptionItem {
break; break;
} }
case TYPE_PARAM : case TYPE_PARAM :
case TYPE_KEY :
return bar ? drawBar(x, y, w, active, value) : drawParam(x, y, w, title, active, value); return bar ? drawBar(x, y, w, active, value) : drawParam(x, y, w, title, active, value);
} }
@@ -116,11 +134,27 @@ static const OptionItem optSound[] = {
static const OptionItem optControls[] = { static const OptionItem optControls[] = {
OptionItem( OptionItem::TYPE_TITLE, STR_SET_CONTROLS ), OptionItem( OptionItem::TYPE_TITLE, STR_SET_CONTROLS ),
OptionItem( ), OptionItem( ),
OptionItem( OptionItem::TYPE_PARAM, STR_NOT_IMPLEMENTED, SETTINGS( playerIndex ), STR_PLAYER_1, 0, 1 ), OptionItem( OptionItem::TYPE_PARAM, STR_NOT_IMPLEMENTED , SETTINGS( playerIndex ), STR_PLAYER_1, 0, 1 ),
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_GAMEPAD, SETTINGS( controls[0].joyIndex ), STR_GAMEPAD_1, 0, 3 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_GAMEPAD , SETTINGS( controls[0].joyIndex ), STR_GAMEPAD_1, 0, 3 ),
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_VIBRATION, SETTINGS( controls[0].vibration ), STR_OFF, 0, 1 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_VIBRATION , SETTINGS( controls[0].vibration ), STR_OFF, 0, 1 ),
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_RETARGET, SETTINGS( controls[0].retarget ), STR_OFF, 0, 1 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_RETARGET , SETTINGS( controls[0].retarget ), STR_OFF, 0, 1 ),
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_MULTIAIM, SETTINGS( controls[0].multiaim ), STR_OFF, 0, 1 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_MULTIAIM , SETTINGS( controls[0].multiaim ), STR_OFF, 0, 1 ),
OptionItem( OptionItem::TYPE_PARAM, STR_NOT_IMPLEMENTED , SETTINGS( ctrlIndex ), STR_OPT_CONTROLS_KEYBOARD, 0, 1 ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cUp , SETTINGS( controls[0].keys[ cUp ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cDown , SETTINGS( controls[0].keys[ cDown ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cRight , SETTINGS( controls[0].keys[ cRight ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cLeft , SETTINGS( controls[0].keys[ cLeft ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cWalk , SETTINGS( controls[0].keys[ cWalk ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cJump , SETTINGS( controls[0].keys[ cJump ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cAction , SETTINGS( controls[0].keys[ cAction ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cWeapon , SETTINGS( controls[0].keys[ cWeapon ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cLook , SETTINGS( controls[0].keys[ cLook ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cDuck , SETTINGS( controls[0].keys[ cDuck ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cDash , SETTINGS( controls[0].keys[ cDash ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cRoll , SETTINGS( controls[0].keys[ cRoll ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cInventory , SETTINGS( controls[0].keys[ cInventory ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cStart , SETTINGS( controls[0].keys[ cStart ] ), STR_KEY_FIRST ),
}; };
static OptionItem optControlsPlayer[COUNT(optControls)]; static OptionItem optControlsPlayer[COUNT(optControls)];
@@ -269,9 +303,19 @@ struct Inventory {
case TR::Entity::INV_CONTROLS : case TR::Entity::INV_CONTROLS :
ASSERT(optControls[2].offset == SETTINGS( playerIndex) ); ASSERT(optControls[2].offset == SETTINGS( playerIndex) );
for (int i = 0; i < COUNT(optControls); i++) { for (int i = 0; i < COUNT(optControls); i++) {
optControlsPlayer[i] = optControls[i]; OptionItem &opt = optControlsPlayer[i];
if (i > 2) opt = optControls[i];
optControlsPlayer[i].offset += sizeof(Core::Settings::Controls) * Core::settings.playerIndex;
if (i > 2 && i != 2 && i != 7)
opt.offset += sizeof(Core::Settings::Controls) * Core::settings.playerIndex;
if (i > 7) {
if (Core::settings.ctrlIndex == 1) {
opt.offset++; // add offset to joy
opt.color = STR_JOY_FIRST;
} else
opt.color = STR_KEY_FIRST;
}
} }
optCount = COUNT(optControlsPlayer); optCount = COUNT(optControlsPlayer);
return optControlsPlayer; return optControlsPlayer;
@@ -305,7 +349,7 @@ struct Inventory {
uint8 &value = *(uint8*)(intptr_t(settings) + opt->offset); uint8 &value = *(uint8*)(intptr_t(settings) + opt->offset);
switch (key) { switch (key) {
case cAction : return (opt->type == OptionItem::TYPE_BUTTON) ? opt : NULL; case cAction : return (opt->type == OptionItem::TYPE_BUTTON || opt->type == OptionItem::TYPE_KEY) ? opt : NULL;
case cUp : nextSlot(slot, -1); break; case cUp : nextSlot(slot, -1); break;
case cDown : nextSlot(slot, +1); break; case cDown : nextSlot(slot, +1); break;
case cLeft : case cLeft :
@@ -455,6 +499,8 @@ struct Inventory {
phaseRing = phasePage = phaseChoose = phaseSelect = 0.0f; phaseRing = phasePage = phaseChoose = phaseSelect = 0.0f;
memset(pageItemIndex, 0, sizeof(pageItemIndex)); memset(pageItemIndex, 0, sizeof(pageItemIndex));
waitForKey = NULL;
} }
~Inventory() { ~Inventory() {
@@ -584,6 +630,9 @@ struct Inventory {
} }
bool toggle(int playerIndex = 0, Page curPage = PAGE_INVENTORY, TR::Entity::Type type = TR::Entity::LARA) { bool toggle(int playerIndex = 0, Page curPage = PAGE_INVENTORY, TR::Entity::Type type = TR::Entity::LARA) {
if (!game->getLara(playerIndex))
return false;
this->playerIndex = playerIndex; this->playerIndex = playerIndex;
titleTimer = 0.0f; titleTimer = 0.0f;
@@ -714,6 +763,7 @@ struct Inventory {
} }
case TR::Entity::INV_CONTROLS : case TR::Entity::INV_CONTROLS :
Core::settings.playerIndex = 0; Core::settings.playerIndex = 0;
Core::settings.ctrlIndex = 0;
break; break;
case TR::Entity::INV_DETAIL : case TR::Entity::INV_DETAIL :
settings = Core::settings; settings = Core::settings;
@@ -769,13 +819,6 @@ struct Inventory {
nextLevel = level->getHomeId(); nextLevel = level->getHomeId();
toggle(); toggle();
} }
if ((key == cInventory || key == cJump) && phaseChoose == 1.0f) {
chosen = false;
item->anim->dir = 1.0f;
item->value = 1000;
item->angle = 0.0f;
}
} }
void optionChanged(Item *item, const OptionItem *opt, Core::Settings &settings) { void optionChanged(Item *item, const OptionItem *opt, Core::Settings &settings) {
@@ -792,7 +835,17 @@ struct Inventory {
game->playSound(TR::SND_PISTOLS_SHOT); game->playSound(TR::SND_PISTOLS_SHOT);
} }
if (opt->title == STR_APPLY) { if (item->type == TR::Entity::INV_CONTROLS && opt->type == OptionItem::TYPE_KEY) {
waitForKey = opt;
Input::lastKey = ikNone;
Input::joy[Core::settings.controls[Core::settings.playerIndex].joyIndex].lastKey = jkNone;
}
if (item->type == TR::Entity::INV_SOUND || item->type == TR::Entity::INV_CONTROLS) {
game->applySettings(settings);
}
if (item->type == TR::Entity::INV_DETAIL && opt->title == STR_APPLY) {
game->applySettings(settings); game->applySettings(settings);
chosen = false; chosen = false;
} }
@@ -834,17 +887,17 @@ struct Inventory {
Input::Joystick &joy = Input::joy[Core::settings.controls[playerIndex].joyIndex]; Input::Joystick &joy = Input::joy[Core::settings.controls[playerIndex].joyIndex];
ControlKey key = cMAX; ControlKey key = cMAX;
if (Input::state[playerIndex][cAction]) if (Input::down[ikCtrl] || Input::down[ikEnter] || joy.down[jkA])
key = cAction; key = cAction;
else if (Input::state[playerIndex][cInventory] || Input::state[playerIndex][cJump]) else if (Input::down[ikAlt] || joy.down[jkB] || Input::state[playerIndex][cInventory])
key = cInventory; key = cInventory;
else if (Input::state[playerIndex][cLeft] || joy.L.x < -0.5f) else if (Input::down[ikLeft] || joy.down[jkLeft] || joy.L.x < -0.5f)
key = cLeft; key = cLeft;
else if (Input::state[playerIndex][cRight] || joy.L.x > 0.5f) else if (Input::down[ikRight] || joy.down[jkRight] || joy.L.x > 0.5f)
key = cRight; key = cRight;
else if (Input::state[playerIndex][cUp] || joy.L.y < -0.5f) else if (Input::down[ikUp] || joy.down[jkUp] || joy.L.y < -0.5f)
key = cUp; key = cUp;
else if (Input::state[playerIndex][cDown] || joy.L.y > 0.5f) else if (Input::down[ikDown] || joy.down[jkDown] || joy.L.y > 0.5f)
key = cDown; key = cDown;
Item *item = items[getGlobalIndex(page, index)]; Item *item = items[getGlobalIndex(page, index)];
@@ -876,8 +929,40 @@ struct Inventory {
} }
} }
if (key != cMAX && lastKey != key && changeTimer == 0.0f && phaseChoose == 1.0f) if (waitForKey) {
int newKey = -1;
if (Core::settings.ctrlIndex == 0 && Input::lastKey != ikNone) {
newKey = Input::lastKey;
} else {
JoyKey jk = Input::joy[Core::settings.controls[Core::settings.playerIndex].joyIndex].lastKey;
if (Core::settings.ctrlIndex == 1 && jk != jkNone)
newKey = jk;
}
if (newKey != -1) {
waitForKey->setValue(newKey, &Core::settings);
waitForKey = NULL;
lastKey = key;
game->applySettings(Core::settings);
}
}
if (key != cMAX && lastKey != key && changeTimer == 0.0f && phaseChoose == 1.0f) {
controlItem(item, key); controlItem(item, key);
}
}
if ((key == cInventory || key == cJump) && lastKey != key) {
lastKey = key;
if (chosen) {
if (phaseChoose == 1.0f) {
chosen = false;
item->anim->dir = 1.0f;
item->value = 1000;
item->angle = 0.0f;
}
} else
toggle();
} }
} }
lastKey = key; lastKey = key;
@@ -1036,7 +1121,7 @@ struct Inventory {
sprintf(buf, "%d %c", item->count, spec); sprintf(buf, "%d %c", item->count, spec);
for (int i = 0; buf[i] != ' '; i++) for (int i = 0; buf[i] != ' '; i++)
buf[i] -= 47; buf[i] -= 47;
UI::textOut(pos, buf, UI::aRight, width, UI::SHADE_NONE); UI::textOut(pos, buf, UI::aRight, width, 255, UI::SHADE_NONE);
} }
} }
@@ -1270,13 +1355,13 @@ struct Inventory {
UI::textOut(vec2(-eye, 32), pageTitle[page], UI::aCenter, UI::width); UI::textOut(vec2(-eye, 32), pageTitle[page], UI::aCenter, UI::width);
if (canFlipPage(-1)) { if (canFlipPage(-1)) {
UI::textOut(vec2(16 - eye, 32), "[", UI::aLeft, UI::width, UI::SHADE_NONE); UI::textOut(vec2(16 - eye, 32), "[", UI::aLeft, UI::width);
UI::textOut(vec2(-eye, 32), "[", UI::aRight, UI::width - 20, UI::SHADE_NONE); UI::textOut(vec2(-eye, 32), "[", UI::aRight, UI::width - 20);
} }
if (canFlipPage(1)) { if (canFlipPage(1)) {
UI::textOut(vec2(16 - eye, 480 - 16), "]", UI::aLeft, UI::width, UI::SHADE_NONE); UI::textOut(vec2(16 - eye, 480 - 16), "]", UI::aLeft, UI::width);
UI::textOut(vec2(-eye, 480 - 16), "]", UI::aRight, UI::width - 20, UI::SHADE_NONE); UI::textOut(vec2(-eye, 480 - 16), "]", UI::aRight, UI::width - 20);
} }
if (index == targetIndex) if (index == targetIndex)
@@ -1284,15 +1369,13 @@ struct Inventory {
// inventory controls help // inventory controls help
float dx = 32.0f - eye; float dx = 32.0f - eye;
UI::textOut(vec2(dx, 480 - 64), "Ctrl - Select", UI::aLeft, UI::width, UI::SHADE_NONE); char buf[64];
if (chosen) sprintf(buf, STR[STR_HELP_SELECT], STR[STR_KEY_FIRST + ikEnter] );
UI::textOut(vec2(0, 480 - 64), UI::textOut(vec2(dx, 480 - 64), buf, UI::aLeft, UI::width);
#ifdef __EMSCRIPTEN__ if (chosen) {
"D" sprintf(buf, STR[STR_HELP_BACK], STR[STR_KEY_FIRST + Core::settings.controls[playerIndex].keys[ cInventory ].key] );
#else UI::textOut(vec2(0, 480 - 64), buf, UI::aRight, UI::width - dx);
"Alt" }
#endif
" - Go Back", UI::aRight, UI::width - dx, UI::SHADE_NONE);
} }
}; };

View File

@@ -253,6 +253,7 @@ struct Lara : Character {
Camera *camera; Camera *camera;
float hitTimer; float hitTimer;
bool camChanged; // hit key detection to go first person view mode
#ifdef _DEBUG #ifdef _DEBUG
//uint16 *dbgBoxes; //uint16 *dbgBoxes;
@@ -431,7 +432,8 @@ struct Lara : Character {
Lara(IGame *game, int entity) : Character(game, entity, LARA_MAX_HEALTH), dozy(false), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), braid(NULL) { Lara(IGame *game, int entity) : Character(game, entity, LARA_MAX_HEALTH), dozy(false), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), braid(NULL) {
camera = new Camera(game, this); camera = new Camera(game, this);
hitTimer = 0.0f; hitTimer = 0.0f;
camChanged = false;
if (level->extra.laraSkin > -1) if (level->extra.laraSkin > -1)
level->entities[entity].modelIndex = level->extra.laraSkin + 1; level->entities[entity].modelIndex = level->extra.laraSkin + 1;
@@ -2652,6 +2654,14 @@ struct Lara : Character {
// analog control // analog control
rotFactor = vec2(1.0f); rotFactor = vec2(1.0f);
if ((input & LOOK) && (input & ACTION)) {
if (!camChanged) {
camera->changeView(!camera->firstPerson);
camChanged = true;
}
} else
camChanged = false;
if (input & LOOK) if (input & LOOK)
return input; return input;
@@ -2700,7 +2710,14 @@ struct Lara : Character {
|| state == STATE_USE_KEY || state == STATE_USE_KEY
|| state == STATE_USE_PUZZLE || state == STATE_USE_PUZZLE
|| state == STATE_SPECIAL || state == STATE_SPECIAL
|| state == STATE_REACH; || state == STATE_REACH
|| state == STATE_SWAN_DIVE
|| state == STATE_HANDSTAND
|| state == STATE_ROLL_1
|| state == STATE_ROLL_2
|| animation.index == ANIM_CLIMB_2
|| animation.index == ANIM_CLIMB_3
|| animation.index == ANIM_CLIMB_JUMP;
} }
virtual void doCustomCommand(int curFrame, int prevFrame) { virtual void doCustomCommand(int curFrame, int prevFrame) {
@@ -2749,9 +2766,9 @@ struct Lara : Character {
if (hitTimer > 0.0f) { if (hitTimer > 0.0f) {
hitTimer -= Core::deltaTime; hitTimer -= Core::deltaTime;
if (hitTimer > 0.0f) if (hitTimer > 0.0f)
osJoyVibrate(Core::settings.controls[camera->cameraIndex].joyIndex, 0.5f, 0.5f); Input::setJoyVibrate(camera->cameraIndex, 0.5f, 0.5f);
else else
osJoyVibrate(Core::settings.controls[camera->cameraIndex].joyIndex, 0, 0); Input::setJoyVibrate(camera->cameraIndex, 0, 0);
} }
if (level->isCutsceneLevel()) if (level->isCutsceneLevel())

View File

@@ -130,21 +130,24 @@ struct Level : IGame {
save->size = ptr - data; save->size = ptr - data;
save->version = level.version & TR::VER_VERSION; save->version = level.version & TR::VER_VERSION;
Stream::write("savegame.dat", data, int(ptr - data)); osSaveGame(data, int(ptr - data));
delete[] data; delete[] data;
LOG("Ok\n"); LOG("Ok\n");
} }
virtual void loadGame(int slot) { virtual void loadGame(int slot) {
LOG("Lave Game... "); LOG("Load Game... ");
Stream *stream = osLoadGame();
if (!stream)
return;
clearInventory(); clearInventory();
clearEntities(); clearEntities();
Stream stream("savegame.dat");
char *data; char *data;
stream.read(data, stream.size); stream->read(data, stream->size);
char *ptr = data; char *ptr = data;
TR::SaveGame *save = (TR::SaveGame*)ptr; TR::SaveGame *save = (TR::SaveGame*)ptr;
@@ -188,6 +191,7 @@ struct Level : IGame {
} }
delete[] data; delete[] data;
delete stream;
// camera->room = lara->getRoomIndex(); // camera->room = lara->getRoomIndex();
// camera->pos = camera->destPos = lara->pos; // camera->pos = camera->destPos = lara->pos;
@@ -233,6 +237,8 @@ struct Level : IGame {
Core::settings = settings; Core::settings = settings;
osCacheWrite("settings", (char*)&settings, sizeof(settings));
if (rebuildShaders) { if (rebuildShaders) {
delete shaderCache; delete shaderCache;
shaderCache = new ShaderCache(); shaderCache = new ShaderCache();
@@ -516,7 +522,7 @@ struct Level : IGame {
switch (b.flags.mode) { switch (b.flags.mode) {
case 0 : if (level.version & TR::VER_TR1) flags |= Sound::UNIQUE; break; // TODO check this case 0 : if (level.version & TR::VER_TR1) flags |= Sound::UNIQUE; break; // TODO check this
case 1 : flags |= Sound::REPLAY; break; case 1 : flags |= Sound::REPLAY; break;
case 2 : if (level.version & TR::VER_TR1) flags |= Sound::FLIPPED | Sound::UNFLIPPED | Sound::LOOP | Sound::UNIQUE; break; case 2 : if (level.version & TR::VER_TR1) flags |= Sound::FLIPPED | Sound::UNFLIPPED | Sound::LOOP; break;
case 3 : if (!(level.version & TR::VER_TR1)) flags |= Sound::FLIPPED | Sound::UNFLIPPED | Sound::LOOP | Sound::UNIQUE; break; case 3 : if (!(level.version & TR::VER_TR1)) flags |= Sound::FLIPPED | Sound::UNFLIPPED | Sound::LOOP | Sound::UNIQUE; break;
} }
} }
@@ -549,7 +555,6 @@ struct Level : IGame {
} }
level->sndSoundtrack->setVolume(1.0f, 0.2f); level->sndSoundtrack->setVolume(1.0f, 0.2f);
} }
LOG("play soundtrack - %d\n", Core::getTime());
} }
virtual void playTrack(uint8 track, bool restart = false) { virtual void playTrack(uint8 track, bool restart = false) {
@@ -1408,7 +1413,7 @@ struct Level : IGame {
} }
} }
if ((Input::state[0][cInventory] || Input::state[1][cInventory]) && !level.isTitle() && inventory.titleTimer < 1.0f) { if ((Input::state[0][cInventory] || Input::state[1][cInventory]) && !level.isTitle() && inventory.titleTimer < 1.0f && !inventory.active && inventory.lastKey == cMAX) {
int playerIndex = Input::state[0][cInventory] ? 0 : 1; int playerIndex = Input::state[0][cInventory] ? 0 : 1;
if (player->health <= 0.0f) if (player->health <= 0.0f)

View File

@@ -553,8 +553,8 @@ struct MeshBuilder {
m.geometry[1].ranges[0].iCount = 0; m.geometry[1].ranges[0].iCount = 0;
m.geometry[2].ranges[0].iCount = 0; m.geometry[2].ranges[0].iCount = 0;
// remove bottom triangles from skybox // remove bottom triangles from skybox
if (m.geometry[0].ranges[0].iCount && ((level.version & TR::VER_TR3))) //if (m.geometry[0].ranges[0].iCount && ((level.version & TR::VER_TR3)))
m.geometry[0].ranges[0].iCount -= 16 * 3; // m.geometry[0].ranges[0].iCount -= 16 * 3;
} }
} }
ASSERT(vCount - vStartModel <= 0xFFFF); ASSERT(vCount - vStartModel <= 0xFFFF);
@@ -1184,9 +1184,9 @@ struct MeshBuilder {
Vertex &v = vertices[vCount + i]; Vertex &v = vertices[vCount + i];
v.normal = short4( 0, 0, 0, 0 ); v.normal = short4( 0, 0, 0, 0 );
if (color2 != 0 && (i == 0 || i == 3)) if (color2 != 0 && (i == 0 || i == 3))
v.color = *((ubyte4*)&color2); v.light = *((ubyte4*)&color2);
else else
v.color = *((ubyte4*)&color); v.light = *((ubyte4*)&color);
short2 uv = tile.texCoord[i]; short2 uv = tile.texCoord[i];
@@ -1218,7 +1218,7 @@ struct MeshBuilder {
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
Vertex &v = vertices[vCount + i]; Vertex &v = vertices[vCount + i];
v.normal = short4( 0, 0, 0, 0 ); v.normal = short4( 0, 0, 0, 0 );
v.color = *((ubyte4*)&color1); v.light = *((ubyte4*)&color1);
v.texCoord = uv; v.texCoord = uv;
} }
@@ -1238,7 +1238,7 @@ struct MeshBuilder {
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
Vertex &v = vertices[vCount + i]; Vertex &v = vertices[vCount + i];
v.normal = short4( 0, 0, 0, 0 ); v.normal = short4( 0, 0, 0, 0 );
v.color = *((ubyte4*)&color2); v.light = *((ubyte4*)&color2);
v.texCoord = uv; v.texCoord = uv;
} }

View File

@@ -112,14 +112,34 @@ int osGetTime() {
#endif #endif
} }
bool osSave(const char *name, const void *data, int size) { bool osCacheWrite(const char *name, const char *data, int size) {
FILE *f = fopen(name, "wb"); char path[255];
strcpy(path, Stream::cacheDir);
strcat(path, name);
FILE *f = fopen(path, "wb");
if (!f) return false; if (!f) return false;
fwrite(data, size, 1, f); fwrite(data, size, 1, f);
fclose(f); fclose(f);
return true; return true;
} }
Stream* osCacheRead(const char *name) {
char path[255];
strcpy(path, Stream::cacheDir);
strcat(path, name);
if (!Stream::exists(path))
return NULL;
return new Stream(path);
}
bool osSaveGame(const char *data, int size) {
return osCacheWrite("savegame", data, size);
}
Stream* osLoadGame() {
return osCacheRead("savegame");
}
// common input functions // common input functions
InputKey keyToInputKey(int code) { InputKey keyToInputKey(int code) {
static const int codes[] = { static const int codes[] = {
@@ -168,8 +188,10 @@ typedef struct _XINPUT_VIBRATION
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689 #define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30 #define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30
DWORD (WINAPI *XInputGetState)(DWORD dwUserIndex, XINPUT_STATE* pState); DWORD (WINAPI *XInputGetState) (DWORD dwUserIndex, XINPUT_STATE* pState) = NULL;
DWORD (WINAPI *XInputSetState)(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration); DWORD (WINAPI *XInputSetState) (DWORD dwUserIndex, XINPUT_VIBRATION* pVibration) = NULL;
void (WINAPI *XInputEnable) (BOOL enable) = NULL;
#define XInputGetProc(x) (x = (decltype(x))GetProcAddress(h, #x))
#define JOY_DEAD_ZONE_STICK 0.3f #define JOY_DEAD_ZONE_STICK 0.3f
#define JOY_DEAD_ZONE_TRIGGER 0.01f #define JOY_DEAD_ZONE_TRIGGER 0.01f
@@ -193,9 +215,12 @@ void joyInit() {
memset(joyReady, 0, sizeof(joyReady)); memset(joyReady, 0, sizeof(joyReady));
HMODULE h = LoadLibrary("xinput1_3.dll"); HMODULE h = LoadLibrary("xinput1_3.dll");
if (h == NULL)
h = LoadLibrary("xinput9_1_0.dll");
XInputGetState = (decltype(XInputGetState))GetProcAddress(h, "XInputGetState"); XInputGetProc(XInputGetState);
XInputSetState = (decltype(XInputSetState))GetProcAddress(h, "XInputSetState"); XInputGetProc(XInputSetState);
XInputGetProc(XInputEnable);
for (int j = 0; j < INPUT_JOY_COUNT; j++) { for (int j = 0; j < INPUT_JOY_COUNT; j++) {
if (XInputGetState) { // XInput if (XInputGetState) { // XInput
@@ -403,6 +428,8 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara
switch (msg) { switch (msg) {
// window // window
case WM_ACTIVATE : case WM_ACTIVATE :
if (XInputEnable)
XInputEnable(wParam != WA_INACTIVE);
Input::reset(); Input::reset();
break; break;
case WM_SIZE: case WM_SIZE:

View File

@@ -80,7 +80,7 @@ struct Shader {
// generate shader file path // generate shader file path
if (Core::support.shaderBinary) { if (Core::support.shaderBinary) {
uint32 hash = fnv32(defines, strlen(defines), fnv32(source, strlen(source))); uint32 hash = fnv32(defines, strlen(defines), fnv32(source, strlen(source)));
sprintf(fileName, "%s%08X.xsh", Stream::cacheDir, hash); sprintf(fileName, "%08X.xsh", hash);
} }
ID = glCreateProgram(); ID = glCreateProgram();
@@ -94,7 +94,7 @@ struct Shader {
glGetProgramBinary(ID, size, NULL, &format, &data[8]); glGetProgramBinary(ID, size, NULL, &format, &data[8]);
*(int*)(&data[0]) = format; *(int*)(&data[0]) = format;
*(int*)(&data[4]) = size; *(int*)(&data[4]) = size;
Stream::write(fileName, data, 8 + size); osCacheWrite(fileName, data, 8 + size);
delete[] data; delete[] data;
#endif #endif
} }
@@ -145,17 +145,18 @@ struct Shader {
} }
bool linkBinary(const char *fileName) { bool linkBinary(const char *fileName) {
if (!Stream::exists(fileName)) Stream *stream = osCacheRead(fileName);
if (!stream)
return false; return false;
GLenum size, format; GLenum size, format;
Stream stream(fileName); stream->read(format);
stream.read(format); stream->read(size);
stream.read(size);
char *data = new char[size]; char *data = new char[size];
stream.raw(data, size); stream->raw(data, size);
glProgramBinary(ID, format, data, size); glProgramBinary(ID, format, data, size);
delete[] data; delete[] data;
delete stream;
return checkLink(); return checkLink();
} }

View File

@@ -14,11 +14,11 @@ varying vec4 vColor;
attribute vec4 aCoord; attribute vec4 aCoord;
attribute vec4 aTexCoord; attribute vec4 aTexCoord;
attribute vec4 aColor; attribute vec4 aLight;
void main() { void main() {
vTexCoord = aTexCoord.xy; vTexCoord = aTexCoord.xy;
vColor = aColor; vColor = aLight;
gl_Position = uViewProj * vec4(aCoord.xy * uPosScale.zw + uPosScale.xy, 0.0, 1.0); gl_Position = uViewProj * vec4(aCoord.xy * uPosScale.zw + uPosScale.xy, 0.0, 1.0);
} }
#else #else

View File

@@ -24,6 +24,9 @@ enum StringID {
, STR_NOT_READY , STR_NOT_READY
, STR_PLAYER_1 , STR_PLAYER_1
, STR_PLAYER_2 , STR_PLAYER_2
, STR_PRESS_ANY_KEY
, STR_HELP_SELECT
, STR_HELP_BACK
// inventory pages // inventory pages
, STR_OPTION , STR_OPTION
, STR_INVENTORY , STR_INVENTORY
@@ -59,10 +62,20 @@ enum StringID {
, STR_REVERBERATION , STR_REVERBERATION
// controls options // controls options
, STR_SET_CONTROLS , STR_SET_CONTROLS
, STR_OPT_CONTROLS_KEYBOARD
, STR_OPT_CONTROLS_GAMEPAD , STR_OPT_CONTROLS_GAMEPAD
, STR_OPT_CONTROLS_VIBRATION , STR_OPT_CONTROLS_VIBRATION
, STR_OPT_CONTROLS_RETARGET , STR_OPT_CONTROLS_RETARGET
, STR_OPT_CONTROLS_MULTIAIM , STR_OPT_CONTROLS_MULTIAIM
// controls
, STR_CTRL_FIRST
, STR_CTRL_LAST = STR_CTRL_FIRST + cMAX - 1
// keys
, STR_KEY_FIRST
, STR_KEY_LAST = STR_KEY_FIRST + ikZ
// gamepad
, STR_JOY_FIRST
, STR_JOY_LAST = STR_JOY_FIRST + jkMAX - 1
// inventory items // inventory items
, STR_UNKNOWN , STR_UNKNOWN
, STR_PISTOLS , STR_PISTOLS
@@ -83,32 +96,21 @@ enum StringID {
}; };
const char *helpText = const char *helpText =
"Controls gamepad, touch and keyboard:@" "Start - add second player or restore Lara@"
" Enter, Start (gamepad) - add second player or restore Lara@" "H - Show or hide this help@"
" H - Show or hide this help@" "ALT + ENTER - Fullscreen@"
" TAB - Inventory@" "C - Look@"
" LEFT - Left@" "R - Slow motion@"
" RIGHT - Right@" "T - Fast motion@"
" UP - Run@" "Roll - Up + Down@"
" DOWN - Back@" "Step Left - Walk + Left@"
" SHIFT - Walk@" "Step Right - Walk + Right@"
" SPACE - Draw Weapon@" "Out of water - Up + Action@"
" CTRL - Action@" "Handstand - Run + Walk@"
" D - Jump@" "Swan dive - Run + Walk + Jump@"
" Z - Step Left@" "First Person View - Look + Action@"
" X - Step Right@" "DOZY on - Look + Duck + Action + Jump@"
" A - Roll@" "DOZY off - Walk";
" C - Look # not implemented #@"
" V - First Person View@"
" R - slow motion@"
" T - fast motion@"
" ALT + ENTER - Fullscreen@@"
"Actions:@"
" Out of water - Run + Action@"
" Handstand - Run + Walk@"
" Swan dive - Run + Walk + jump@"
" DOZY on - Look + Step Right + Action + Jump@"
" DOZY off - Walk@";
const char *STR[STR_MAX] = { const char *STR[STR_MAX] = {
@@ -131,6 +133,9 @@ const char *STR[STR_MAX] = {
, "Not Ready" , "Not Ready"
, "Player 1" , "Player 1"
, "Player 2" , "Player 2"
, "Press Any Key"
, "%s - Select"
, "%s - Go Back"
// inventory pages // inventory pages
, "OPTION" , "OPTION"
, "INVENTORY" , "INVENTORY"
@@ -166,10 +171,20 @@ const char *STR[STR_MAX] = {
, "Reverberation" , "Reverberation"
// controls options // controls options
, "Set Controls" , "Set Controls"
, "Keyboard"
, "Gamepad" , "Gamepad"
, "Vibration" , "Vibration"
, "Retargeting" , "Retargeting"
, "Multi-aiming" , "Multi-aiming"
// controls
, "Left", "Right", "Up", "Down", "Jump", "Walk", "Action", "Draw Weapon", "Look", "Duck", "Dash", "Roll", "Inventory", "Start"
// keys
, "NONE", "LEFT", "RIGHT", "UP", "DOWN", "SPACE", "TAB", "ENTER", "ESCAPE", "SHIFT", "CTRL", "ALT"
, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"
, "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
// gamepad
, "NONE", "A", "B", "X", "Y", "L BUMPER", "R BUMPER", "SELECT", "START", "L STICK", "R STICK", "L TRIGGER", "R TRIGGER", "D-LEFT", "D-RIGHT", "D-UP", "D-DOWN"
// inventory items // inventory items
, "Unknown" , "Unknown"
, "Pistols" , "Pistols"
@@ -311,13 +326,13 @@ namespace UI {
SHADE_GRAY = 2, SHADE_GRAY = 2,
}; };
void textOut(const vec2 &pos, const char *text, Align align = aLeft, float width = 0, ShadeType shade = SHADE_ORANGE, bool isShadow = false) { void textOut(const vec2 &pos, const char *text, Align align = aLeft, float width = 0, uint8 alpha = 255, ShadeType shade = SHADE_ORANGE, bool isShadow = false) {
if (!text) return; if (!text) return;
TR::Level *level = game->getLevel(); TR::Level *level = game->getLevel();
if (shade && !isShadow && ((level->version & TR::VER_TR3))) if (shade && !isShadow && ((level->version & TR::VER_TR3)))
textOut(pos + vec2(1, 1), text, align, width, shade, true); textOut(pos + vec2(1, 1), text, align, width, alpha, shade, true);
MeshBuilder *mesh = game->getMesh(); MeshBuilder *mesh = game->getMesh();
int seq = level->extra.glyphs; int seq = level->extra.glyphs;
@@ -354,18 +369,18 @@ namespace UI {
TR::Color32 tColor, bColor; TR::Color32 tColor, bColor;
if (isShadow) { if (isShadow) {
tColor = bColor = TR::Color32(0, 0, 0, 255); tColor = bColor = TR::Color32(0, 0, 0, alpha);
} else { } else {
tColor = bColor = TR::Color32(255, 255, 255, 255); tColor = bColor = TR::Color32(255, 255, 255, alpha);
if (shade && ((level->version & TR::VER_TR3))) { if (shade && ((level->version & TR::VER_TR3))) {
if (shade == SHADE_ORANGE) { if (shade == SHADE_ORANGE) {
tColor = TR::Color32(255, 190, 90, 255); tColor = TR::Color32(255, 190, 90, alpha);
bColor = TR::Color32(140, 50, 10, 255); bColor = TR::Color32(140, 50, 10, alpha);
} }
if (shade == SHADE_GRAY) { if (shade == SHADE_GRAY) {
tColor = TR::Color32(255, 255, 255, 255); tColor = TR::Color32(255, 255, 255, alpha);
bColor = TR::Color32(128, 128, 128, 255); bColor = TR::Color32(128, 128, 128, alpha);
} }
} }
} }
@@ -389,8 +404,8 @@ namespace UI {
} }
} }
void textOut(const vec2 &pos, StringID str, Align align = aLeft, float width = 0, ShadeType shade = SHADE_ORANGE) { void textOut(const vec2 &pos, StringID str, Align align = aLeft, float width = 0, uint8 alpha = 255, ShadeType shade = SHADE_ORANGE) {
textOut(pos, STR[str], align, width, shade); textOut(pos, STR[str], align, width, alpha, shade);
} }
void specOut(const vec2 &pos, char specChar) { void specOut(const vec2 &pos, char specChar) {
@@ -508,10 +523,10 @@ namespace UI {
void renderHelp() { void renderHelp() {
// TODO: Core::eye offset // TODO: Core::eye offset
if (showHelp) if (showHelp)
textOut(vec2(0, 32), STR_HELP_TEXT, aRight, width - 32, UI::SHADE_GRAY); textOut(vec2(32, 32), STR_HELP_TEXT, aLeft, width - 32, 255, UI::SHADE_GRAY);
else else
if (helpTipTime > 0.0f) if (helpTipTime > 0.0f)
textOut(vec2(0, height - 32), STR_HELP_PRESS, aCenter, width, UI::SHADE_ORANGE); textOut(vec2(0, height - 32), STR_HELP_PRESS, aCenter, width, 255, UI::SHADE_ORANGE);
} }
}; };

View File

@@ -1211,10 +1211,6 @@ struct Stream {
return exists(fileName); return exists(fileName);
} }
static void write(const char *name, const void *data, int size) {
osSave(name, data, size);
}
void setPos(int pos) { void setPos(int pos) {
this->pos = pos; this->pos = pos;
if (f) fseek(f, pos, SEEK_SET); if (f) fseek(f, pos, SEEK_SET);