diff --git a/proj/vs2017/Common/Common.vcxproj b/proj/vs2017/Common/Common.vcxproj
index 2d87ee8e..f172b3d7 100644
--- a/proj/vs2017/Common/Common.vcxproj
+++ b/proj/vs2017/Common/Common.vcxproj
@@ -387,6 +387,7 @@
+
diff --git a/proj/vs2017/Common/Common.vcxproj.filters b/proj/vs2017/Common/Common.vcxproj.filters
index 50afff6a..2f45390d 100644
--- a/proj/vs2017/Common/Common.vcxproj.filters
+++ b/proj/vs2017/Common/Common.vcxproj.filters
@@ -716,6 +716,7 @@
Universe
+
diff --git a/proj/xc12/BoE.xcodeproj/project.pbxproj b/proj/xc12/BoE.xcodeproj/project.pbxproj
index 821a2243..8ad5013f 100755
--- a/proj/xc12/BoE.xcodeproj/project.pbxproj
+++ b/proj/xc12/BoE.xcodeproj/project.pbxproj
@@ -104,6 +104,7 @@
9153C79E1A994A0D00D7F8A7 /* SFML.framework in Copy Libraries and Frameworks */ = {isa = PBXBuildFile; fileRef = 91F6F8E218F87F3700E3EA15 /* SFML.framework */; };
9153C79F1A994A1300D7F8A7 /* SFML.framework in Copy Libraries and Frameworks */ = {isa = PBXBuildFile; fileRef = 91F6F8E218F87F3700E3EA15 /* SFML.framework */; };
9153C7A01A994A1700D7F8A7 /* SFML.framework in Copy Libraries and Frameworks */ = {isa = PBXBuildFile; fileRef = 91F6F8E218F87F3700E3EA15 /* SFML.framework */; };
+ 915473BF2C7E11B900EB1C94 /* damage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 915473BE2C7E11B900EB1C94 /* damage.cpp */; };
915AF9E81BBF8B5C008AEF49 /* scrollpane.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 919B13A81BBE2B54009905A4 /* scrollpane.cpp */; };
9176FEC71D550EFE006EF694 /* out_legacy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9176FEC01D550EFC006EF694 /* out_legacy.cpp */; };
9176FEC81D550EFE006EF694 /* scen_legacy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9176FEC11D550EFC006EF694 /* scen_legacy.cpp */; };
@@ -690,6 +691,7 @@
914F412E23EBD27500DB53BD /* town.xsd */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = town.xsd; sourceTree = ""; };
915325161A2E1DA8000A9A1C /* oldstructs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = oldstructs.cpp; sourceTree = ""; };
915325181A2E37EE000A9A1C /* special_parse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = special_parse.cpp; sourceTree = ""; };
+ 915473BE2C7E11B900EB1C94 /* damage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = damage.cpp; sourceTree = ""; };
91574CC323CB97C5004766F8 /* enum_map.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = enum_map.hpp; sourceTree = ""; };
91597A6C1A3BED2D00BE7BF9 /* spell.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = spell.hpp; sourceTree = ""; };
91597A6E1A3BEDC700BE7BF9 /* spell.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spell.cpp; sourceTree = ""; };
@@ -1329,6 +1331,7 @@
9185BDA41EA053E00027C346 /* misc */ = {
isa = PBXGroup;
children = (
+ 915473BE2C7E11B900EB1C94 /* damage.cpp */,
91279BE10F9D0F73007B0D52 /* location.cpp */,
91B3F11E0F97801F00BF5B67 /* mathutil.cpp */,
915325161A2E1DA8000A9A1C /* oldstructs.cpp */,
@@ -2095,6 +2098,7 @@
9149924B25913E3F00B5BE97 /* container.cpp in Sources */,
9149924D25913E3F00B5BE97 /* led.cpp in Sources */,
9149924F25913E3F00B5BE97 /* ledgroup.cpp in Sources */,
+ 915473BF2C7E11B900EB1C94 /* damage.cpp in Sources */,
91499253259140FF00B5BE97 /* keycodes.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
diff --git a/src/damage.cpp b/src/damage.cpp
new file mode 100644
index 00000000..3331ade1
--- /dev/null
+++ b/src/damage.cpp
@@ -0,0 +1,46 @@
+//
+// damage.cpp
+// BoE
+//
+// Created by Celtic Minstrel on 2023-08-27.
+//
+//
+
+#include "damage.hpp"
+
+static status_info_t status_info[int(eStatus::CHARM) + 1] = {
+ {false, 4}, // POISONED_WEAPON
+ {false, 2, 3}, // BLESS_CURSE
+ {true, 0, -1, {1, 4}}, // POISON
+ {false, 6, 8, {7, 0, 0}}, // HASTE_SLOW
+ {false, 5}, // INVULNERABLE
+ {false, 9, 19}, // MAGIC_RESISTANCE
+ {true, 10}, // WEBS
+ {true, 11}, // DISEASE
+ {false, 12}, // INVISIBLE
+ {true, 13, 18}, // DUMB
+ {false, 14}, // MARTYRS_SHIELD
+ {true, 15, 21}, // ASLEEP
+ {true, 16}, // PARALYZED
+ {true, 17}, // ACIDS
+ {true, 20}, // FORCECAGE
+ {true, 22}, // CHARM
+};
+
+static status_info_t party_status_info[int(ePartyStatus::FIREWALK) + 1] = {
+ {false, 26}, // STEALTH
+ {false, 23}, // FLIGHT
+ {false, 24}, // DETECT_LIFE
+ {false, 25}, // FIREWALK
+};
+
+status_info_t dummy_main_info{};
+
+const status_info_t& operator* (eStatus status) {
+ if(status == eStatus::MAIN) return dummy_main_info;
+ return status_info[int(status)];
+}
+
+const status_info_t& operator* (ePartyStatus status) {
+ return party_status_info[int(status)];
+}
diff --git a/src/damage.hpp b/src/damage.hpp
index efaf94a5..71f4a010 100644
--- a/src/damage.hpp
+++ b/src/damage.hpp
@@ -9,6 +9,9 @@
#ifndef BoE_DATA_DAMAGE_HPP
#define BoE_DATA_DAMAGE_HPP
+#include
+#include
+
enum class eDamageType {
WEAPON = 0,
FIRE = 1,
@@ -45,29 +48,6 @@ enum class eStatus {
CHARM = 15,
};
-inline bool isStatusNegative(eStatus stat) {
- switch(stat) {
- case eStatus::MAIN: return false;
- case eStatus::POISONED_WEAPON: return false;
- case eStatus::BLESS_CURSE: return false;
- case eStatus::POISON: return true;
- case eStatus::HASTE_SLOW: return false;
- case eStatus::INVULNERABLE: return false;
- case eStatus::MAGIC_RESISTANCE: return false;
- case eStatus::WEBS: return true;
- case eStatus::DISEASE: return true;
- case eStatus::INVISIBLE: return false;
- case eStatus::DUMB: return true;
- case eStatus::MARTYRS_SHIELD: return false;
- case eStatus::ASLEEP: return true;
- case eStatus::PARALYZED: return true;
- case eStatus::ACID: return true;
- case eStatus::FORCECAGE: return true;
- case eStatus::CHARM: return true;
- }
- return false;
-}
-
enum class ePartyStatus {
STEALTH,
FLIGHT,
@@ -75,6 +55,22 @@ enum class ePartyStatus {
FIREWALK,
};
+struct status_info_t {
+ bool isNegative = false;
+ int icon = -1, negIcon = -1;
+ struct special_icon_t {
+ int icon, lo, hi;
+ special_icon_t(int p, int m, int M = std::numeric_limits::max()) : icon(p), lo(m), hi(M) {}
+ };
+ boost::optional special;
+ status_info_t() = default;
+ status_info_t(bool neg, int p1, int p2 = -1) : isNegative(neg), icon(p1), negIcon(p2) {}
+ status_info_t(bool neg, int p1, int p2, special_icon_t spec) : isNegative(neg), icon(p1), negIcon(p2), special(spec) {}
+};
+
+const status_info_t& operator* (eStatus status);
+const status_info_t& operator* (ePartyStatus status);
+
enum class eMainStatus {
ABSENT = 0, // absent, empty slot
ALIVE = 1,
diff --git a/src/game/boe.actions.cpp b/src/game/boe.actions.cpp
index abb6a990..91b0ef67 100644
--- a/src/game/boe.actions.cpp
+++ b/src/game/boe.actions.cpp
@@ -2310,7 +2310,7 @@ void do_rest(long length, int hp_restore, int mp_restore) {
if(get_ran(1,0,5) != 3) continue;
int how_much = item.abil_strength;
if(item.abil_harms()) how_much *= -1;
- if(isStatusNegative(item.abil_data.status))
+ if((*item.abil_data.status).isNegative)
how_much *= -1;
univ.party.apply_status(item.abil_data.status, how_much);
}
@@ -2429,7 +2429,7 @@ void increase_age() {
int how_much = item.abil_strength;
if(item.abil_harms()) how_much *= -1;
eStatus status = item.abil_data.status;
- if(isStatusNegative(status))
+ if((*status).isNegative)
how_much *= -1;
univ.party.apply_status(status, how_much);
}
diff --git a/src/game/boe.combat.cpp b/src/game/boe.combat.cpp
index 0dd913e1..ec1a4470 100644
--- a/src/game/boe.combat.cpp
+++ b/src/game/boe.combat.cpp
@@ -2097,7 +2097,7 @@ void combat_run_monst() {
int how_much = item.abil_strength;
if(item.abil_harms()) how_much *= -1;
eStatus status = item.abil_data.status;
- if(isStatusNegative(status))
+ if((*status).isNegative)
how_much *= -1;
switch(status) {
case eStatus::MAIN: case eStatus::CHARM:
diff --git a/src/game/boe.graphics.cpp b/src/game/boe.graphics.cpp
index 36429023..c862fadb 100644
--- a/src/game/boe.graphics.cpp
+++ b/src/game/boe.graphics.cpp
@@ -643,21 +643,12 @@ void put_text_bar(std::string str) {
to_rect.left = to_rect.right - 15;
to_rect.width() = 12;
to_rect.height() = 12;
- if(univ.party.status[ePartyStatus::STEALTH] > 0) {
- rect_draw_some_item(status_gworld, get_stat_effect_rect(26), text_bar_gworld, to_rect, sf::BlendAlpha);
- to_rect.offset(-15, 0);
- }
- if(univ.party.status[ePartyStatus::FLIGHT] > 0) {
- rect_draw_some_item(status_gworld, get_stat_effect_rect(23), text_bar_gworld, to_rect, sf::BlendAlpha);
- to_rect.offset(-15, 0);
- }
- if(univ.party.status[ePartyStatus::DETECT_LIFE] > 0) {
- rect_draw_some_item(status_gworld, get_stat_effect_rect(24), text_bar_gworld, to_rect, sf::BlendAlpha);
- to_rect.offset(-15, 0);
- }
- if(univ.party.status[ePartyStatus::FIREWALK] > 0) {
- rect_draw_some_item(status_gworld, get_stat_effect_rect(25), text_bar_gworld, to_rect, sf::BlendAlpha);
- to_rect.offset(-15, 0);
+ for(auto next : univ.party.status) {
+ const auto& statInfo = *next.first;
+ if(next.second > 0) {
+ rect_draw_some_item(status_gworld, get_stat_effect_rect(statInfo.icon), text_bar_gworld, to_rect, sf::BlendAlpha);
+ to_rect.offset(-15, 0);
+ }
}
}
diff --git a/src/game/boe.party.cpp b/src/game/boe.party.cpp
index 4d879b56..d15e27c6 100644
--- a/src/game/boe.party.cpp
+++ b/src/game/boe.party.cpp
@@ -83,16 +83,6 @@ extern cUniverse univ;
extern sf::Texture pc_gworld;
extern std::queue special_queue;
-// First icon is displayed for positive values, second for negative, if -1 no negative icon.
-// This omits two special cases - major poison, and normal speed; they are hard-coded.
-std::map> statIcons = {
- {eStatus::POISONED_WEAPON, {4,-1}}, {eStatus::BLESS_CURSE, {2,3}}, {eStatus::POISON, {0,-1}},
- {eStatus::HASTE_SLOW, {6,8}}, {eStatus::INVULNERABLE, {5,-1}}, {eStatus::MAGIC_RESISTANCE, {9,19}},
- {eStatus::WEBS, {10,-1}}, {eStatus::DISEASE, {11,-1}}, {eStatus::INVISIBLE, {12,-1}},
- {eStatus::DUMB, {13,18}}, {eStatus::MARTYRS_SHIELD, {14,-1}}, {eStatus::ASLEEP, {15,21}},
- {eStatus::PARALYZED, {16,-1}}, {eStatus::ACID, {17,-1}}, {eStatus::FORCECAGE, {20,-1}},
-};
-
// Variables for spell selection
short on_which_spell_page = 0;
short store_last_cast_mage = 6,store_last_cast_priest = 6;
@@ -1635,10 +1625,12 @@ static void put_target_status_graphics(cDialog& me, short for_pc) {
pic.setFormat(TXT_FRAME, FRM_NONE);
if(isAlive) {
short placedIcon = -1;
- if(next.first == eStatus::POISON && next.second > 4) placedIcon = 1;
- else if(next.second > 0) placedIcon = statIcons[next.first].first;
- else if(next.second < 0) placedIcon = statIcons[next.first].second;
- else if(next.first == eStatus::HASTE_SLOW) placedIcon = 7;
+ const auto& statInfo = *next.first;
+ if(statInfo.special && next.second >= statInfo.special->lo && next.second <= statInfo.special->hi) {
+ placedIcon = statInfo.special->icon;
+ }
+ else if(next.second > 0) placedIcon = statInfo.icon;
+ else if(next.second < 0) placedIcon = statInfo.negIcon;
if(placedIcon >= 0) {
pic.show();
pic.setPict(placedIcon);
diff --git a/src/game/boe.text.cpp b/src/game/boe.text.cpp
index b3ad55fc..5c449fad 100644
--- a/src/game/boe.text.cpp
+++ b/src/game/boe.text.cpp
@@ -82,7 +82,6 @@ extern short store_selling_values[8];
extern short combat_posing_monster, current_working_monster; // 0-5 PC 100 + x - monster x
extern bool supressing_some_spaces;
extern location ok_space[4];
-extern std::map> statIcons;
// Draws the pc area in upper right
void put_pc_screen() {
@@ -642,9 +641,12 @@ void draw_pc_effects(short pc) {
sf::Texture& status_gworld = *ResMgr::graphics.get("staticons");
for(auto next : univ.party[pc].status) {
short placedIcon = -1;
- if(next.first == eStatus::POISON && next.second > 4) placedIcon = 1;
- else if(next.second > 0) placedIcon = statIcons[next.first].first;
- else if(next.second < 0) placedIcon = statIcons[next.first].second;
+ const auto& statInfo = *next.first;
+ if(statInfo.special && next.second >= statInfo.special->lo && next.second <= statInfo.special->hi) {
+ placedIcon = statInfo.special->icon;
+ }
+ else if(next.second > 0) placedIcon = statInfo.icon;
+ else if(next.second < 0) placedIcon = statInfo.negIcon;
if(placedIcon >= 0) {
rect_draw_some_item(status_gworld, get_stat_effect_rect(placedIcon), pc_stats_gworld, dest_rect, sf::BlendAlpha);
dest_rect.offset(13, 0);
diff --git a/src/tools/SConscript b/src/tools/SConscript
index 7ec445aa..d0a174cb 100644
--- a/src/tools/SConscript
+++ b/src/tools/SConscript
@@ -7,6 +7,7 @@ tools = Split("""
drawable_manager.cpp
keymods.cpp
replay.cpp
+ ../damage.cpp
../location.cpp
../mathutil.cpp
../porting.cpp
diff --git a/src/universe/living.cpp b/src/universe/living.cpp
index 2f3f13a9..e8ab1401 100644
--- a/src/universe/living.cpp
+++ b/src/universe/living.cpp
@@ -50,7 +50,7 @@ void iLiving::clear_bad_status() {
std::map old;
status.swap(old);
std::remove_copy_if(old.begin(), old.end(), std::inserter(status, status.begin()), [](std::pair kv) {
- return isStatusNegative(kv.first) ? kv.second > 0 : kv.second < 0;
+ return (*kv.first).isNegative ? kv.second > 0 : kv.second < 0;
});
}