mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-21 19:51:49 +00:00
MM: XEEN: add hp and sp bars for QoL
This commit is contained in:
parent
e3343eb810
commit
a3cfd1fabd
@ -49,6 +49,7 @@ struct MightAndMagicGameDescription {
|
||||
|
||||
#define GAMEOPTION_SHOW_ITEM_COSTS GUIO_GAMEOPTIONS1
|
||||
#define GAMEOPTION_DURABLE_ARMOR GUIO_GAMEOPTIONS2
|
||||
#define GAMEOPTION_SHOW_HP_SP_BARS GUIO_GAMEOPTIONS3
|
||||
|
||||
} // namespace MM
|
||||
|
||||
|
@ -19,8 +19,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "engines/mm/detection.h"
|
||||
|
||||
namespace MM {
|
||||
|
||||
#define GUIO_XEEN GUIO3(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR, GAMEOPTION_SHOW_HP_SP_BARS)
|
||||
|
||||
static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
#ifdef ENABLE_MM1
|
||||
{
|
||||
@ -82,7 +87,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_WorldOfXeen,
|
||||
0
|
||||
@ -98,7 +103,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_WorldOfXeen,
|
||||
0
|
||||
@ -118,7 +123,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_WorldOfXeen,
|
||||
0
|
||||
@ -134,7 +139,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_WorldOfXeen,
|
||||
0
|
||||
@ -150,7 +155,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_CD,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_WorldOfXeen,
|
||||
0
|
||||
@ -167,7 +172,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_WorldOfXeen,
|
||||
0
|
||||
@ -182,7 +187,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_Clouds,
|
||||
0
|
||||
@ -197,7 +202,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_Clouds,
|
||||
0
|
||||
@ -212,7 +217,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_Clouds,
|
||||
0
|
||||
@ -227,7 +232,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::ZH_TWN,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_Clouds,
|
||||
0
|
||||
@ -243,7 +248,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_Clouds,
|
||||
0
|
||||
@ -258,7 +263,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_DarkSide,
|
||||
0
|
||||
@ -273,7 +278,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_DarkSide,
|
||||
0
|
||||
@ -289,7 +294,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_DarkSide,
|
||||
0
|
||||
@ -304,7 +309,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::ZH_TWN,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_DarkSide,
|
||||
0
|
||||
@ -320,7 +325,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_DarkSide,
|
||||
0
|
||||
@ -335,7 +340,7 @@ static const MightAndMagicGameDescription GAME_DESCRIPTIONS[] = {
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
|
||||
GUIO_XEEN
|
||||
},
|
||||
GType_Swords,
|
||||
0
|
||||
|
@ -39,6 +39,43 @@
|
||||
#include "mm/xeen/swordsofxeen/swordsofxeen.h"
|
||||
#endif
|
||||
|
||||
static const ADExtraGuiOptionsMap optionsList[] = {
|
||||
{
|
||||
GAMEOPTION_SHOW_ITEM_COSTS,
|
||||
{
|
||||
_s("Show item costs in standard inventory mode"),
|
||||
_s("Shows item costs in standard inventory mode, allowing the value of items to be compared"),
|
||||
"ShowItemCosts",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_DURABLE_ARMOR,
|
||||
{
|
||||
_s("More durable armor"),
|
||||
_s("Armor won't break until character is at -80HP, rather than merely -10HP"),
|
||||
"DurableArmor",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_SHOW_HP_SP_BARS,
|
||||
{
|
||||
_s("Hitpoint bars"),
|
||||
_s("Replace a colored gem with bars for hit points and spell points."),
|
||||
"ShowHpSpBars",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
AD_EXTRA_GUI_OPTIONS_TERMINATOR
|
||||
};
|
||||
|
||||
class MMMetaEngine : public AdvancedMetaEngine {
|
||||
private:
|
||||
/**
|
||||
@ -60,6 +97,10 @@ public:
|
||||
SaveStateList listSaves(const char *target) const override;
|
||||
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
|
||||
Common::KeymapArray initKeymaps(const char *target) const override;
|
||||
|
||||
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
|
||||
return optionsList;
|
||||
}
|
||||
};
|
||||
|
||||
bool MMMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
|
@ -51,12 +51,124 @@ PartyDrawer::PartyDrawer(XeenEngine *vm): _vm(vm) {
|
||||
_hiliteChar = HILIGHT_CHAR_NONE;
|
||||
}
|
||||
|
||||
static inline int clipToFaceWidth(int i) {
|
||||
const int faceWidth = 32;
|
||||
return CLIP(i, 0, faceWidth);
|
||||
}
|
||||
|
||||
static inline int unzero(int i) {
|
||||
if (i) return i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void PartyDrawer::drawHitPoints(int charIndex) {
|
||||
Combat &combat = *_vm->_combat;
|
||||
Party &party = *_vm->_party;
|
||||
Windows &windows = *_vm->_windows;
|
||||
bool inCombat = _vm->_mode == MODE_COMBAT;
|
||||
Window &win = windows[0];
|
||||
Character &c = inCombat ? *combat._combatParty[charIndex] : party._activeParty[charIndex];
|
||||
|
||||
enum {
|
||||
BLACK = 0,
|
||||
STONE = 20,
|
||||
|
||||
BRIGHT_GREEN = 80,
|
||||
GREEN = 85,
|
||||
YELLOW = 55,
|
||||
RED = 185,
|
||||
DARK_BLUE = 78,
|
||||
|
||||
BRIGHT_BLUE = 70,
|
||||
BLUE = 75
|
||||
};
|
||||
|
||||
int hp = c._currentHp;
|
||||
int sp = c._currentSp;
|
||||
|
||||
int maxHp = c.getMaxHP();
|
||||
int maxSp = c.getMaxSP();
|
||||
|
||||
int gemFrame;
|
||||
int hpColor = GREEN;
|
||||
|
||||
if (hp < 1) {
|
||||
gemFrame = 4;
|
||||
} else if (hp > maxHp) {
|
||||
gemFrame = 3;
|
||||
} else if (hp == maxHp) {
|
||||
gemFrame = 0;
|
||||
} else if (hp < (maxHp / 4)) {
|
||||
gemFrame = 2;
|
||||
hpColor = RED;
|
||||
} else{
|
||||
hpColor = YELLOW;
|
||||
gemFrame = 1;
|
||||
}
|
||||
if (!g_vm->_extOptions._showHpSpBars) {
|
||||
_hpSprites.draw(0, gemFrame, Common::Point(Res.HP_BARS_X[charIndex], 182));
|
||||
} else {
|
||||
const int faceWidth = 32;
|
||||
|
||||
const int barLeft = Res.CHAR_FACES_X[charIndex];
|
||||
const int barRight = Res.CHAR_FACES_X[charIndex] + 32;
|
||||
const int barHeight = 3;
|
||||
|
||||
const int frameTop = 183;
|
||||
const int frameBottom = 190;
|
||||
const int frameColor = STONE;
|
||||
const int hpBarTop = 184;
|
||||
const int hpBarBottom = hpBarTop + barHeight;
|
||||
|
||||
const int spBarTop = 188;
|
||||
const int spBarBottom = spBarTop + barHeight;
|
||||
|
||||
int hpPart = clipToFaceWidth( (hp * faceWidth) / unzero(maxHp) );
|
||||
int boostedHpPart = 0;
|
||||
if (hp > maxHp) {
|
||||
boostedHpPart = clipToFaceWidth(faceWidth * (hp - maxHp) / unzero(hp + maxHp) );
|
||||
}
|
||||
|
||||
int spPart = clipToFaceWidth( (sp * faceWidth) / unzero(maxSp) );
|
||||
int boostedSpPart = 0;
|
||||
if (sp > maxSp) {
|
||||
boostedSpPart = clipToFaceWidth( faceWidth * (sp - maxSp) / unzero(sp + maxSp) );
|
||||
}
|
||||
|
||||
int negativeHpPart = 32;
|
||||
if (hp < 0) {
|
||||
negativeHpPart = faceWidth - clipToFaceWidth((-hp * faceWidth) / unzero(maxHp));
|
||||
}
|
||||
|
||||
win.fillRect(Common::Rect(barLeft, frameTop, barRight, frameBottom), frameColor);
|
||||
|
||||
win.fillRect(Common::Rect(barLeft, hpBarTop, barRight, hpBarBottom), BLACK);
|
||||
win.fillRect(Common::Rect(barLeft, hpBarTop, barLeft + hpPart, hpBarBottom), hpColor);
|
||||
if (boostedHpPart != 0) {
|
||||
win.fillRect(Common::Rect(barLeft, hpBarTop, barLeft + boostedHpPart, hpBarBottom), BRIGHT_GREEN);
|
||||
}
|
||||
|
||||
if (negativeHpPart != 32) {
|
||||
win.fillRect(Common::Rect(barLeft + negativeHpPart, hpBarTop, barLeft + faceWidth, hpBarBottom), DARK_BLUE);
|
||||
}
|
||||
|
||||
if (maxSp != 0) {
|
||||
win.fillRect(Common::Rect(barLeft, spBarTop, barRight, spBarBottom), BLACK);
|
||||
win.fillRect(Common::Rect(barLeft, spBarTop, barLeft + spPart, spBarBottom), BLUE);
|
||||
if (boostedSpPart) {
|
||||
win.fillRect(Common::Rect(barLeft, spBarTop, barLeft + boostedSpPart, spBarBottom), BRIGHT_BLUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PartyDrawer::drawParty(bool updateFlag) {
|
||||
Combat &combat = *_vm->_combat;
|
||||
Party &party = *_vm->_party;
|
||||
Resources &res = *_vm->_resources;
|
||||
Windows &windows = *_vm->_windows;
|
||||
bool inCombat = _vm->_mode == MODE_COMBAT;
|
||||
|
||||
_restoreSprites.draw(0, 0, Common::Point(8, 149));
|
||||
|
||||
// Handle drawing the party faces
|
||||
@ -75,23 +187,7 @@ void PartyDrawer::drawParty(bool updateFlag) {
|
||||
}
|
||||
|
||||
for (uint idx = 0; idx < partyCount; ++idx) {
|
||||
Character &c = inCombat ? *combat._combatParty[idx] : party._activeParty[idx];
|
||||
|
||||
// Draw the Hp bar
|
||||
int maxHp = c.getMaxHP();
|
||||
int frame;
|
||||
if (c._currentHp < 1)
|
||||
frame = 4;
|
||||
else if (c._currentHp > maxHp)
|
||||
frame = 3;
|
||||
else if (c._currentHp == maxHp)
|
||||
frame = 0;
|
||||
else if (c._currentHp < (maxHp / 4))
|
||||
frame = 2;
|
||||
else
|
||||
frame = 1;
|
||||
|
||||
_hpSprites.draw(0, frame, Common::Point(Res.HP_BARS_X[idx], 182));
|
||||
drawHitPoints(idx);
|
||||
}
|
||||
|
||||
if (_hiliteChar != HILIGHT_CHAR_NONE)
|
||||
@ -533,6 +629,10 @@ void Interface::perform() {
|
||||
if (CastSpell::show(_vm) != -1) {
|
||||
chargeStep();
|
||||
doStepCode();
|
||||
// update spell point bar
|
||||
if (g_vm->_extOptions._showHpSpBars) {
|
||||
drawParty(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1601,6 +1701,10 @@ void Interface::doCombat() {
|
||||
// Cast spell
|
||||
if (CastSpell::show(_vm) != -1) {
|
||||
nextChar();
|
||||
// update spell point bar
|
||||
if (g_vm->_extOptions._showHpSpBars) {
|
||||
drawParty(true);
|
||||
}
|
||||
} else {
|
||||
highlightChar(combat._whosTurn);
|
||||
}
|
||||
|
@ -86,6 +86,9 @@ public:
|
||||
void unhighlightChar();
|
||||
|
||||
void resetHighlight();
|
||||
|
||||
private:
|
||||
void drawHitPoints(int charIndex);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -125,6 +125,7 @@ void XeenEngine::loadSettings() {
|
||||
|
||||
_extOptions._showItemCosts = ConfMan.hasKey("ShowItemCosts") && ConfMan.getBool("ShowItemCosts");
|
||||
_extOptions._durableArmor = ConfMan.hasKey("DurableArmor") && ConfMan.getBool("DurableArmor");
|
||||
_extOptions._showHpSpBars = ConfMan.hasKey("ShowHpSpBars") && ConfMan.getBool("ShowHpSpBars");
|
||||
|
||||
// If requested, load a savegame instead of showing the intro
|
||||
if (ConfMan.hasKey("save_slot")) {
|
||||
|
@ -97,9 +97,13 @@ class XeenEngine : public MMEngine {
|
||||
struct ExtendedOptions {
|
||||
bool _showItemCosts;
|
||||
bool _durableArmor;
|
||||
bool _showHpSpBars;
|
||||
|
||||
ExtendedOptions() : _showItemCosts(false), _durableArmor(false) {
|
||||
}
|
||||
ExtendedOptions() :
|
||||
_showItemCosts(false),
|
||||
_durableArmor(false),
|
||||
_showHpSpBars(false)
|
||||
{}
|
||||
};
|
||||
private:
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user