Browse Source

Monster health bar

pull/1108/head
qndel 6 years ago committed by Anders Jenbo
parent
commit
be895274dc
  1. 1
      CMakeLists.txt
  2. 4
      Source/all.h
  3. 2
      Source/diablo.cpp
  4. 15
      Source/diablo.h
  5. 2
      Source/scrollrt.cpp
  6. 137
      SourceX/qol.cpp
  7. 15
      SourceX/qol.h

1
CMakeLists.txt

@ -272,6 +272,7 @@ add_library(devilution STATIC
Source/trigs.cpp)
set(devilutionx_SRCS
SourceX/qol.cpp
SourceX/dx.cpp
SourceX/controls/devices/game_controller.cpp
SourceX/controls/devices/joystick.cpp

4
Source/all.h

@ -7,6 +7,8 @@
#define __ALL_H__
#include <SDL.h>
#include <map>
#include <vector>
#ifdef USE_SDL1
#include "sdl2_to_1_2_backports.h"
@ -18,6 +20,8 @@
#include "../types.h"
#include "../SourceX/qol.h"
#include "appfat.h"
#include "automap.h"
#include "capture.h"

2
Source/diablo.cpp

@ -423,6 +423,7 @@ static void SaveOptions()
setIniInt("Game", "Cow Quest", sgOptions.bCowQuest);
setIniInt("Game", "Test Bard", sgOptions.bTestBard);
setIniInt("Game", "Test Barbarian", sgOptions.bTestBarbarian);
setIniInt("Game", "Enemy Health Bar", sgOptions.bEnemyHealthBar);
setIniValue("Network", "Bind Address", sgOptions.szBindAddress);
}
@ -464,6 +465,7 @@ static void LoadOptions()
sgOptions.bCowQuest = getIniBool("Game", "Cow Quest", false);
sgOptions.bTestBard = getIniBool("Game", "Test Bard", false);
sgOptions.bTestBarbarian = getIniBool("Game", "Test Barbarian", false);
sgOptions.bEnemyHealthBar = getIniBool("Game", "Enemy Health Bar", false);
getIniValue("Network", "Bind Address", sgOptions.szBindAddress, sizeof(sgOptions.szBindAddress), "0.0.0.0");
}

15
Source/diablo.h

@ -36,13 +36,14 @@ typedef struct Options {
Sint32 nGammaCorrection; // Gamma correction level
bool bColorCycling; // Enable color cycling animations
Sint32 nTickRate; // Game play ticks per secound
bool bJogInTown; // Enable double walk speed when in town
bool bGrabInput; // Do not let the mouse leave the application window
bool bTheoQuest; // Enable the Theo quest
bool bCowQuest; // Enable the cow quest
bool bTestBard; // Enable the bard hero class
bool bTestBarbarian; // Enable the babarian hero class
Sint32 nTickRate; // Game play ticks per secound
bool bJogInTown; // Enable double walk speed when in town
bool bGrabInput; // Do not let the mouse leave the application window
bool bTheoQuest; // Enable the Theo quest
bool bCowQuest; // Enable the cow quest
bool bTestBard; // Enable the bard hero class
bool bTestBarbarian; // Enable the babarian hero class
bool bEnemyHealthBar; // Show enemy health at the top of the screen
char szBindAddress[129]; // Optionally bind to a specific network interface
} Options;

2
Source/scrollrt.cpp

@ -1232,6 +1232,8 @@ void DrawView(int StartX, int StartY)
if (automapflag) {
DrawAutomap(out.subregion(0, 0, out.line_width, SCREEN_Y + VIEWPORT_HEIGHT));
}
DrawMonsterHealthBar();
if (stextflag && !qtextflag)
DrawSText(out);
if (invflag) {

137
SourceX/qol.cpp

@ -0,0 +1,137 @@
/**
* @file qol.cpp
*
* Quality of life features
*/
#include "all.h"
#include "../3rdParty/Storm/Source/storm.h"
DEVILUTION_BEGIN_NAMESPACE
int GetTextWidth(const char *s)
{
int l = 0;
while (*s) {
l += fontkern[fontframe[gbFontTransTbl[(BYTE)*s++]]] + 1;
}
return l;
}
inline void FastDrawHorizLine(int x, int y, int width, BYTE col)
{
memset(&gpBuffer[SCREENXY(x, y)], col, width);
}
inline void FastDrawVertLine(int x, int y, int height, BYTE col)
{
BYTE *p = &gpBuffer[SCREENXY(x, y)];
for (int j = 0; j < height; j++) {
*p = col;
p += BUFFER_WIDTH;
}
}
inline void FillRect(int x, int y, int width, int height, BYTE col)
{
for (int j = 0; j < height; j++) {
FastDrawHorizLine(x, y + j, width, col);
}
}
inline void FillSquare(int x, int y, int size, BYTE col)
{
FillRect(x, y, size, size, col);
}
void DrawMonsterHealthBar()
{
if (!sgOptions.bEnemyHealthBar)
return;
if (currlevel == 0)
return;
if (pcursmonst == -1)
return;
int width = 250;
int height = 25;
int x = 0; // x offset from the center of the screen
int y = 20; // y position
int xOffset = 0; // empty space between left/right borders and health bar
int yOffset = 1; // empty space between top/bottom borders and health bar
int borderSize = 2; // size of the border around health bar
BYTE borderColors[] = { 242 /*undead*/, 232 /*demon*/, 182 /*beast*/ };
BYTE filledColor = 142; // filled health bar color
bool fillCorners = false; // true to fill border corners, false to cut them off
int square = 10; // resistance / immunity / vulnerability square size
const char *immuText = "IMMU: ", *resText = "RES: ", *vulnText = ":VULN"; // text displayed for immunities / resistances / vulnerabilities
int resSize = 3; // how many damage types
BYTE resistColors[] = { 148, 140, 129 }; // colors for these damage types
WORD immunes[] = { IMMUNE_MAGIC, IMMUNE_FIRE, IMMUNE_LIGHTNING }; // immunity flags for damage types
WORD resists[] = { RESIST_MAGIC, RESIST_FIRE, RESIST_LIGHTNING }; // resistance flags for damage types
MonsterStruct *mon = &monster[pcursmonst];
BYTE borderColor = borderColors[(BYTE)mon->MData->mMonstClass];
WORD mres = mon->mMagicRes;
bool drawImmu = false;
int xPos = (SCREEN_WIDTH - width) / 2 + x;
int xPos2 = xPos + width / 2;
int yPos = y;
int immuOffset = GetTextWidth(immuText) - 5;
int resOffset = GetTextWidth(resText);
int vulOffset = width - square - GetTextWidth(vulnText) - 4;
int corners = (fillCorners ? borderSize : 0);
int currentLife = mon->_mhitpoints, maxLife = mon->_mmaxhp;
if (currentLife > maxLife)
maxLife = currentLife;
if (mon->_uniqtype != 0)
borderSize <<= 1;
FillRect(xPos, yPos, (width * currentLife) / maxLife, height, filledColor);
for (int j = 0; j < borderSize; j++) {
FastDrawHorizLine(xPos - xOffset - corners, yPos - borderSize - yOffset + j, (xOffset + corners) * 2 + width, borderColor);
FastDrawHorizLine(xPos - xOffset, yPos + height + yOffset + j, width + corners + xOffset * 2, borderColor);
}
for (int j = -yOffset; j < yOffset + height + corners; ++j) {
FastDrawHorizLine(xPos - xOffset - borderSize, yPos + j, borderSize, borderColor);
FastDrawHorizLine(xPos + xOffset + width, yPos + j, borderSize, borderColor);
}
for (int k = 0; k < resSize; ++k) {
if (mres & immunes[k]) {
drawImmu = true;
FillSquare(xPos + immuOffset, yPos + height - square, square, resistColors[k]);
immuOffset += square + 2;
} else if ((mres & resists[k])) {
FillSquare(xPos + resOffset, yPos + yOffset + height + borderSize + 2, square, resistColors[k]);
resOffset += square + 2;
} else {
FillSquare(xPos + vulOffset, yPos + yOffset + height + borderSize + 2, square, resistColors[k]);
vulOffset -= square + 2;
}
}
char text[64];
strcpy(text, mon->mName);
if (mon->leader > 0)
strcat(text, " (minion)");
CelOutputBuffer out = GlobalBackBuffer();
PrintGameStr(out, xPos2 - GetTextWidth(text) / 2, yPos + 10, text, (mon->_uniqtype != 0 ? COL_GOLD : COL_WHITE));
sprintf(text, "%d", (maxLife >> 6));
PrintGameStr(out, xPos2 + GetTextWidth("/"), yPos + 23, text, COL_WHITE);
sprintf(text, "%d", (currentLife >> 6));
PrintGameStr(out, xPos2 - GetTextWidth(text) - GetTextWidth("/"), yPos + 23, text, COL_WHITE);
PrintGameStr(out, xPos2 - GetTextWidth("/") / 2, yPos + 23, "/", COL_WHITE);
sprintf(text, "kills: %d", monstkills[mon->MType->mtype]);
PrintGameStr(out, xPos2 - GetTextWidth("kills:") / 2 - 30, yPos + yOffset + height + borderSize + 12, text, COL_WHITE);
if (drawImmu)
PrintGameStr(out, xPos2 - width / 2, yPos + height, immuText, COL_GOLD);
PrintGameStr(out, xPos2 - width / 2, yPos + yOffset + height + borderSize + 12, resText, COL_GOLD);
PrintGameStr(out, xPos2 + width / 2 - GetTextWidth(vulnText), yPos + yOffset + height + borderSize + 12, vulnText, COL_RED);
}
DEVILUTION_END_NAMESPACE

15
SourceX/qol.h

@ -0,0 +1,15 @@
/**
* @file qol.h
*
* Quality of life features
*/
#ifndef __QOL_H__
#define __QOL_H__
DEVILUTION_BEGIN_NAMESPACE
void DrawMonsterHealthBar();
DEVILUTION_END_NAMESPACE
#endif /* __QOL_H__ */
Loading…
Cancel
Save