1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-13 16:44:50 +02:00

fix multi-line text centering, level stats screen (debug on 0 key)

This commit is contained in:
XProger
2018-10-17 10:37:18 +03:00
parent 92a9f9e941
commit ccc270ee2b
8 changed files with 113 additions and 42 deletions

View File

@@ -128,7 +128,7 @@ struct Character : Controller {
virtual void hit(float damage, Controller *enemy = NULL, TR::HitType hitType = TR::HIT_DEFAULT) {
if (getEntity().isEnemy() && health > 0.0f && health <= damage)
level->levelStats.kills++;
level->stats.kills++;
health = max(0.0f, health - damage);
}

View File

@@ -711,7 +711,7 @@ namespace Debug {
sprintf(buf, "floor = %d, roomBelow = %d, roomAbove = %d, roomNext = %d, height = %d", info.floorIndex, info.roomBelow, info.roomAbove, info.roomNext, int(info.floor - info.ceiling));
Debug::Draw::text(vec2(16, y += 16), vec4(1.0f), buf);
const SaveProgress &stats = game->getLevel()->levelStats;
const SaveProgress &stats = game->getLevel()->stats;
sprintf(buf, "stats: time = %d, distance = %d, secrets = %c%c%c, pickups = %d, mediUsed = %d, ammoUsed = %d, kills = %d", stats.time, stats.distance,
(stats.secrets & 4) ? '1' : '0',
(stats.secrets & 2) ? '1' : '0',

View File

@@ -2344,8 +2344,7 @@ namespace TR {
}
};
SaveProgress gameStats;
SaveProgress levelStats;
SaveProgress stats;
SaveState state;
int cutEntity;
@@ -2839,9 +2838,8 @@ namespace TR {
initRoomMeshes();
initAnimTex();
memset(&gameStats, 0, sizeof(gameStats));
memset(&levelStats, 0, sizeof(levelStats));
memset(&state, 0, sizeof(state));
memset(&stats, 0, sizeof(stats));
memset(&state, 0, sizeof(state));
initExtra();
initCutscene();

View File

@@ -186,6 +186,11 @@ namespace Game {
if (level->isEnded)
return true;
if (Input::down[ik0] && !level->inventory->isActive()) {
level->inventory->toggle(0, Inventory::PAGE_LEVEL_STATS);
Input::down[ik0] = false;
}
if (Input::down[ik5] && !level->inventory->isActive()) {
if (level->players[0]->canSaveGame())
level->saveGame(true, false);

View File

@@ -75,8 +75,8 @@ struct OptionItem {
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;
maxWidth = maxWidth * 0.5f + 8.0f;
int maxWidth = UI::getTextSize(STR[color + value]).x;
maxWidth = maxWidth / 2 + 8;
x += w * 0.5f;
if (checkValue(value - 1)) UI::specOut(vec2(x - maxWidth - 16.0f, y), 108);
if (checkValue(value + 1)) UI::specOut(vec2(x + maxWidth, y), 109);
@@ -191,6 +191,7 @@ struct Inventory {
PAGE_INVENTORY,
PAGE_ITEMS,
PAGE_SAVEGAME,
PAGE_LEVEL_STATS,
PAGE_MAX
};
@@ -787,7 +788,8 @@ struct Inventory {
phaseRing = active ? 1.0f : 0.0f;
slot = 1;
} else {
game->playSound(active ? TR::SND_INV_SHOW : TR::SND_INV_HIDE, p);
if (curPage != PAGE_LEVEL_STATS)
game->playSound(active ? TR::SND_INV_SHOW : TR::SND_INV_HIDE, p);
}
chosen = false;
@@ -1085,7 +1087,11 @@ struct Inventory {
Item *item = items[getGlobalIndex(page, index)];
if (page == PAGE_SAVEGAME) {
if (page == PAGE_LEVEL_STATS) {
if (Input::lastState[playerIndex] != cMAX) {
toggle(playerIndex, targetPage);
}
} else if (page == PAGE_SAVEGAME) {
if (Input::lastState[playerIndex] == cLeft || Input::lastState[playerIndex] == cRight)
slot ^= 1;
@@ -1345,7 +1351,7 @@ struct Inventory {
}
UI::textOut(vec2(0, 480 - 32), str, UI::aCenter, UI::width);
float tw = UI::getTextSize(STR[str]).x;
int tw = UI::getTextSize(STR[str]).x;
if (item->value > 0) UI::specOut(vec2((UI::width - tw) * 0.5f - 32.0f, 480 - 32), 108);
if (item->value < 2) UI::specOut(vec2((UI::width + tw) * 0.5f + 16.0f, 480 - 32), 109);
@@ -1716,10 +1722,39 @@ struct Inventory {
renderPage(targetPage);
}
void showLevelStats(const vec2 &pos) {
char buf[256];
char time[16];
TR::Level *level = game->getLevel();
SaveProgress &stats = level->stats;
int secretsMax = 3;
int secrets = ((stats.secrets & 1) != 0) +
((stats.secrets & 2) != 0) +
((stats.secrets & 4) != 0);
int s = stats.time % 60;
int m = stats.time / 60 % 60;
int h = stats.time / 3600;
if (h)
sprintf(time, "%d:%02d:%02d", h, m, s);
else
sprintf(time, "%d:%02d", m, s);
sprintf(buf, STR[STR_LEVEL_STATS],
TR::LEVEL_INFO[level->id].title,
stats.kills,
stats.pickups,
secrets, secretsMax, time);
UI::textOut(pos, buf, UI::aCenter, UI::width);
}
void renderUI() {
if (!active || phaseRing < 1.0f) return;
static const StringID pageTitle[PAGE_MAX] = { STR_OPTION, STR_INVENTORY, STR_ITEMS, STR_SAVEGAME };
static const StringID pageTitle[PAGE_MAX] = { STR_OPTION, STR_INVENTORY, STR_ITEMS, STR_SAVEGAME, STR_LEVEL_STATS };
float eye = UI::width * Core::eye * 0.01f;
@@ -1738,6 +1773,11 @@ struct Inventory {
return;
}
if (page == PAGE_LEVEL_STATS) {
showLevelStats(vec2(-eye, 180));
return;
}
if (!game->getLevel()->isTitle())
UI::textOut(vec2(-eye, 32), pageTitle[page], UI::aCenter, UI::width);

View File

@@ -1020,7 +1020,7 @@ struct Lara : Character {
}
if (shots) {
level->levelStats.ammoUsed += ((wpnCurrent == TR::Entity::SHOTGUN) ? 1 : 2);
level->stats.ammoUsed += ((wpnCurrent == TR::Entity::SHOTGUN) ? 1 : 2);
game->playSound(wpnGetSound(), pos, Sound::PAN);
game->playSound(TR::SND_RICOCHET, nearPos, Sound::PAN);
@@ -1635,7 +1635,7 @@ struct Lara : Character {
case TR::Entity::INV_UZIS : wpnChange(TR::Entity::UZIS); break;
case TR::Entity::INV_MEDIKIT_SMALL :
case TR::Entity::INV_MEDIKIT_BIG :
level->levelStats.mediUsed += (item == TR::Entity::INV_MEDIKIT_SMALL) ? 1 : 2;
level->stats.mediUsed += (item == TR::Entity::INV_MEDIKIT_SMALL) ? 1 : 2;
damageTime = LARA_DAMAGE_TIME;
health = min(LARA_MAX_HEALTH, health + (item == TR::Entity::INV_MEDIKIT_SMALL ? LARA_MAX_HEALTH / 2 : LARA_MAX_HEALTH));
game->playSound(TR::SND_HEALTH, pos, Sound::PAN);
@@ -2107,8 +2107,8 @@ struct Lara : Character {
effect = TR::Effect::Type(cmd.args);
break;
case TR::Action::SECRET :
if (!(level->levelStats.secrets & (1 << cmd.args))) {
level->levelStats.secrets |= 1 << cmd.args;
if (!(level->stats.secrets & (1 << cmd.args))) {
level->stats.secrets |= 1 << cmd.args;
if (!game->playSound(TR::SND_SECRET, pos))
game->playTrack(TR::TRACK_TR1_SECRET, true);
}
@@ -2839,7 +2839,7 @@ struct Lara : Character {
pickupList[i]->deactivate();
pickupList[i]->flags.invisible = true;
game->invAdd(pickupList[i]->getEntity().type, 1);
level->levelStats.pickups++;
level->stats.pickups++;
}
pickupListCount = 0;
}
@@ -3123,7 +3123,7 @@ struct Lara : Character {
statsDistDelta += (pos - oldPos).length();
while (statsDistDelta >= UNITS_PER_METER) {
statsDistDelta -= UNITS_PER_METER;
level->levelStats.distance++;
level->stats.distance++;
}
}
}

View File

@@ -82,7 +82,7 @@ struct Level : IGame {
// save next level
level.id = TR::getNextSaveLevel(level.id); // get next not cutscene level
if (level.id != TR::LVL_MAX && !level.isTitle()) {
memset(&level.levelStats, 0, sizeof(level.levelStats));
memset(&level.stats, 0, sizeof(level.stats));
saveGame(false, false);
loadSlot = getSaveSlot(level.id, false);
}
@@ -123,7 +123,7 @@ struct Level : IGame {
if (dummy)
memset(levelStats, 0, sizeof(*levelStats));
else
*levelStats = level.levelStats;
*levelStats = level.stats;
// inventory items
int32 *itemsCount = (int32*)ptr;
@@ -191,8 +191,8 @@ struct Level : IGame {
uint8 *ptr = data;
// level progress stats
level.levelStats = *(SaveProgress*)ptr;
ptr += sizeof(level.levelStats);
level.stats = *(SaveProgress*)ptr;
ptr += sizeof(level.stats);
// inventory items
int32 itemsCount = *(int32*)ptr;
@@ -247,7 +247,7 @@ struct Level : IGame {
level.state.flags.track = 0;
playTrack(track);
} else
memset(&level.levelStats, 0, sizeof(level.levelStats));
memset(&level.stats, 0, sizeof(level.stats));
statsTimeDelta = 0.0f;
}
@@ -284,7 +284,7 @@ struct Level : IGame {
} else
slot = saveSlots[index];
SaveProgress *levelStats = (SaveProgress*)slot.data;
*levelStats = level.levelStats;
*levelStats = level.stats;
} else {
removeSaveSlot(id, checkpoint); // remove checkpoints and level saves
saveSlots.push(createSaveSlot(id, checkpoint));
@@ -1771,7 +1771,7 @@ struct Level : IGame {
statsTimeDelta += Core::deltaTime;
while (statsTimeDelta >= 1.0f) {
statsTimeDelta -= 1.0f;
level.levelStats.time++;
level.stats.time++;
}
params->time += Core::deltaTime;

View File

@@ -11,6 +11,7 @@ enum StringID {
, STR_LOADING
, STR_HELP_PRESS
, STR_HELP_TEXT
, STR_LEVEL_STATS
, STR_HINT_SAVING
, STR_HINT_SAVING_DONE
, STR_HINT_SAVING_ERROR
@@ -122,6 +123,12 @@ const char *helpText =
"DOZY on - Look + Duck + Action + Jump@"
"DOZY off - Walk";
const char *levelStats =
"%s@@@"
"KILLS %d@@"
"PICKUPS %d@@"
"SECRETS %d of %d@@"
"TIME TAKEN %s";
const char *STR[STR_MAX] = {
"Not implemented yet!"
@@ -129,6 +136,7 @@ const char *STR[STR_MAX] = {
, "Loading..."
, "Press H for help"
, helpText
, levelStats
, "Saving game..."
, "Saving done!"
, "SAVING ERROR!"
@@ -256,7 +264,21 @@ namespace UI {
return char_map[c - 32];
}
vec2 getTextSize(const char *text) {
short2 getLineSize(const char *text) {
int x = 0;
while (char c = *text++) {
if (c == ' ' || c == '_') {
x += 6;
} else if (c == '@') {
break;
} else
x += char_width[charRemap(c)] + 1;
}
return short2(x, 16);
}
short2 getTextSize(const char *text) {
int x = 0, w = 0, h = 16;
while (char c = *text++) {
@@ -271,7 +293,7 @@ namespace UI {
}
w = max(w, x);
return vec2(float(w), float(h));
return short2(w, h);
}
#define MAX_CHARS DYN_MESH_QUADS
@@ -347,6 +369,19 @@ namespace UI {
SHADE_GRAY = 2,
};
int getLeftOffset(const char *text, Align align, int width) {
if (align != aLeft) {
int lineWidth = getLineSize(text).x;
if (align == aCenter)
return (width - lineWidth) / 2;
if (align == aRight)
return width - lineWidth;
}
return 0;
}
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;
@@ -358,26 +393,19 @@ namespace UI {
MeshBuilder *mesh = game->getMesh();
int seq = level->extra.glyphs;
int x = int(pos.x);
int x = int(pos.x) + getLeftOffset(text, align, width);
int y = int(pos.y);
if (align == aCenter)
x += int((width - getTextSize(text).x) / 2);
if (align == aRight)
x += int(width - getTextSize(text).x);
int left = x;
while (char c = *text++) {
if (c == ' ' || c == '_') {
x += 6;
if (c == '@') {
x = int(pos.x) + getLeftOffset(text, align, width);
y += 16;
continue;
}
if (c == '@') {
x = left;
y += 16;
if (c == ' ' || c == '_') {
x += 6;
continue;
}