You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

151 lines
4.6 KiB

/**
* @file monhealthbar.cpp
*
* Adds monster health bar QoL feature
*/
#include "DiabloUI/art_draw.h"
#include "control.h"
#include "cursor.h"
#include "options.h"
#include "utils/language.h"
namespace devilution {
namespace {
Art healthBox;
Art resistance;
Art health;
Art playerExpTags;
} // namespace
void InitMonsterHealthBar()
{
if (!*sgOptions.Gameplay.enemyHealthBar)
return;
LoadMaskedArt("data\\healthbox.pcx", &healthBox, 1, 1);
LoadArt("data\\health.pcx", &health);
LoadMaskedArt("data\\resistance.pcx", &resistance, 6, 1);
LoadMaskedArt("data\\monstertags.pcx", &playerExpTags, 5, 1);
if ((healthBox.surface == nullptr)
|| (health.surface == nullptr)
|| (resistance.surface == nullptr)) {
app_fatal("%s", _("Failed to load UI resources.\n"
"\n"
"Make sure devilutionx.mpq is in the game folder and that it is up to date.")
.c_str());
}
}
void FreeMonsterHealthBar()
{
healthBox.Unload();
health.Unload();
resistance.Unload();
}
void DrawMonsterHealthBar(const Surface &out)
{
if (!*sgOptions.Gameplay.enemyHealthBar)
return;
assert(healthBox.surface != nullptr);
assert(health.surface != nullptr);
assert(resistance.surface != nullptr);
if (currlevel == 0)
return;
if (pcursmonst == -1)
return;
const Monster &monster = Monsters[pcursmonst];
const int width = healthBox.w();
const int height = healthBox.h();
Point position = { (gnScreenWidth - width) / 2, 18 };
if (CanPanelsCoverView()) {
if (IsRightPanelOpen())
position.x -= SPANEL_WIDTH / 2;
if (IsLeftPanelOpen())
position.x += SPANEL_WIDTH / 2;
}
const int border = 3;
const int maxLife = std::max(monster._mmaxhp, monster._mhitpoints);
DrawArt(out, position, &healthBox);
DrawHalfTransparentRectTo(out, position.x + border, position.y + border, width - (border * 2), height - (border * 2));
int barProgress = (width * monster._mhitpoints) / maxLife;
if (barProgress != 0) {
DrawArt(out, position + Displacement { border + 1, border + 1 }, &health, 0, barProgress, height - (border * 2) - 2);
}
constexpr auto getBorderColor = [](MonsterClass monsterClass) {
switch (monsterClass) {
case MonsterClass::Undead:
return 248;
case MonsterClass::Demon:
return 232;
case MonsterClass::Animal:
return 150;
default:
app_fatal("Invalid monster class '%i'.", static_cast<int>(monsterClass));
}
};
if (*sgOptions.Gameplay.showMonsterType) {
Uint8 borderColor = getBorderColor(monster.MData->mMonstClass);
int borderWidth = width - (border * 2);
UnsafeDrawHorizontalLine(out, { position.x + border, position.y + border }, borderWidth, borderColor);
UnsafeDrawHorizontalLine(out, { position.x + border, position.y + height - border - 1 }, borderWidth, borderColor);
int borderHeight = height - (border * 2) - 2;
UnsafeDrawVerticalLine(out, { position.x + border, position.y + border + 1 }, borderHeight, borderColor);
UnsafeDrawVerticalLine(out, { position.x + width - border - 1, position.y + border + 1 }, borderHeight, borderColor);
}
UiFlags style = UiFlags::AlignCenter | UiFlags::VerticalCenter;
DrawString(out, monster.mName, { position + Displacement { -1, 1 }, { width, height } }, style | UiFlags::ColorBlack);
if (monster._uniqtype != 0)
style |= UiFlags::ColorWhitegold;
else if (monster.leader != 0)
style |= UiFlags::ColorBlue;
else
style |= UiFlags::ColorWhite;
DrawString(out, monster.mName, { position, { width, height } }, style);
if (monster._uniqtype != 0 || MonsterKillCounts[monster.MType->mtype] >= 15) {
monster_resistance immunes[] = { IMMUNE_MAGIC, IMMUNE_FIRE, IMMUNE_LIGHTNING };
monster_resistance resists[] = { RESIST_MAGIC, RESIST_FIRE, RESIST_LIGHTNING };
int resOffset = 5;
for (int i = 0; i < 3; i++) {
if ((monster.mMagicRes & immunes[i]) != 0) {
DrawArt(out, position + Displacement { resOffset, height - 6 }, &resistance, i * 2 + 1);
resOffset += resistance.w() + 2;
} else if ((monster.mMagicRes & resists[i]) != 0) {
DrawArt(out, position + Displacement { resOffset, height - 6 }, &resistance, i * 2);
resOffset += resistance.w() + 2;
}
}
}
int tagOffset = 5;
for (int i = 0; i < MAX_PLRS; i++) {
if (1 << i & monster.mWhoHit) {
DrawArt(out, position + Displacement { tagOffset, height - 31 }, &playerExpTags, i + 1);
} else if (Players[i].plractive) {
DrawArt(out, position + Displacement { tagOffset, height - 31 }, &playerExpTags, 0);
}
tagOffset += playerExpTags.w();
}
}
} // namespace devilution