summaryrefslogtreecommitdiff
path: root/src/files.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/files.cc')
-rw-r--r--src/files.cc926
1 files changed, 476 insertions, 450 deletions
diff --git a/src/files.cc b/src/files.cc
index e375e7b0..9ebc18ab 100644
--- a/src/files.cc
+++ b/src/files.cc
@@ -23,6 +23,7 @@
#include "loadsave.h"
#include "loadsave.hpp"
#include "mimic.hpp"
+#include "monoid.hpp"
#include "monster2.hpp"
#include "monster3.hpp"
#include "monster_ego.hpp"
@@ -32,6 +33,8 @@
#include "notes.hpp"
#include "object1.hpp"
#include "object2.hpp"
+#include "object_flag.hpp"
+#include "object_flag_meta.hpp"
#include "object_kind.hpp"
#include "options.hpp"
#include "player_class.hpp"
@@ -56,9 +59,10 @@
#include "z-rand.hpp"
#include <boost/filesystem.hpp>
-#include <memory>
#include <iostream>
#include <fstream>
+#include <limits>
+#include <memory>
#include <unordered_set>
/*
@@ -1546,620 +1550,642 @@ static void display_player_various(void)
* Obtain the "flags" of the wielded symbiote
*/
-void wield_monster_flags(u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp)
+static object_flag_set wield_monster_flags()
{
- object_type *o_ptr;
- monster_race *r_ptr;
-
- /* Clear */
- (*f1) = (*f2) = (*f3) = (*f4) = (*f5) = (*esp) = 0L;
+ object_flag_set flags;
/* Get the carried monster */
- o_ptr = &p_ptr->inventory[INVEN_CARRY];
-
+ auto o_ptr = &p_ptr->inventory[INVEN_CARRY];
if (o_ptr->k_idx)
{
- r_ptr = &r_info[o_ptr->pval];
+ auto r_ptr = &r_info[o_ptr->pval];
if (r_ptr->flags & RF_INVISIBLE)
- (*f2) |= TR2_INVIS;
+ flags |= TR_INVIS;
if (r_ptr->flags & RF_REFLECTING)
- (*f2) |= TR2_REFLECT;
+ flags |= TR_REFLECT;
if (r_ptr->flags & RF_CAN_FLY)
- (*f3) |= TR3_FEATHER;
+ flags |= TR_FEATHER;
if (r_ptr->flags & RF_AQUATIC)
- (*f5) |= TR5_WATER_BREATH;
+ flags |= TR_WATER_BREATH;
}
+
+ return flags;
}
/*
* Obtain the "flags" for the player as if he was an item
*/
-void player_flags(u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp)
+object_flag_set player_flags()
{
- int i;
-
/* Clear */
- (*f1) = (*f2) = (*f3) = (*f4) = (*f5) = (*esp) = 0L;
+ object_flag_set f;
/* Astral chars */
if (p_ptr->astral)
{
- (*f3) |= TR3_WRAITH;
+ f |= TR_WRAITH;
}
/* Skills */
- if (get_skill(SKILL_DAEMON) > 20) (*f2) |= TR2_RES_CONF;
- if (get_skill(SKILL_DAEMON) > 30) (*f2) |= TR2_RES_FEAR;
- if (get_skill(SKILL_MINDCRAFT) >= 40) (*esp) |= ESP_ALL;
+ if (get_skill(SKILL_DAEMON) > 20) f |= TR_RES_CONF;
+ if (get_skill(SKILL_DAEMON) > 30) f |= TR_RES_FEAR;
+ if (get_skill(SKILL_MINDCRAFT) >= 40) f |= ESP_ALL;
if (p_ptr->melee_style == SKILL_HAND && get_skill(SKILL_HAND) > 24 && !monk_heavy_armor())
- (*f2) |= TR2_FREE_ACT;
-/* Hack - from Lua */
- if (get_skill(SKILL_MANA) >= 35) (*f1) |= TR1_MANA;
- if (get_skill(SKILL_AIR) >= 50) (*f5) |= (TR5_MAGIC_BREATH | TR5_WATER_BREATH);
- if (get_skill(SKILL_WATER) >= 30) (*f5) |= TR5_WATER_BREATH;
+ {
+ f |= TR_FREE_ACT;
+ }
+ if (get_skill(SKILL_MANA) >= 35) f |= TR_MANA;
+ if (get_skill(SKILL_AIR) >= 50) f |= (TR_MAGIC_BREATH | TR_WATER_BREATH);
+ if (get_skill(SKILL_WATER) >= 30) f |= TR_WATER_BREATH;
/* Gods */
if (p_ptr->pgod == GOD_ERU)
{
- if ((p_ptr->grace >= 100) || (p_ptr->grace <= -100)) (*f1) |= TR1_MANA;
- if (p_ptr->grace > 10000) (*f1) |= TR1_WIS;
+ if ((p_ptr->grace >= 100) || (p_ptr->grace <= -100)) f |= TR_MANA;
+ if (p_ptr->grace > 10000) f |= TR_WIS;
}
if (p_ptr->pgod == GOD_MELKOR)
{
- (*f2) |= TR2_RES_FIRE;
- if (p_ptr->melkor_sacrifice > 0) (*f2) |= TR2_LIFE;
- if (p_ptr->grace > 10000) (*f1) |= (TR1_STR | TR1_CON | TR1_INT | TR1_WIS | TR1_CHR);
+ f |= TR_RES_FIRE;
+ if (p_ptr->melkor_sacrifice > 0) f |= TR_LIFE;
+ if (p_ptr->grace > 10000) f |= (TR_STR | TR_CON | TR_INT | TR_WIS | TR_CHR);
if (p_ptr->praying)
{
- if (p_ptr->grace > 5000) (*f2) |= TR2_INVIS;
- if (p_ptr->grace > 15000) (*f2) |= TR2_IM_FIRE;
+ if (p_ptr->grace > 5000) f |= TR_INVIS;
+ if (p_ptr->grace > 15000) f |= TR_IM_FIRE;
}
}
if (p_ptr->pgod == GOD_MANWE)
{
- if (p_ptr->grace >= 2000) (*f3) |= TR3_FEATHER;
+ if (p_ptr->grace >= 2000) f |= TR_FEATHER;
if (p_ptr->praying)
{
- if (p_ptr->grace >= 7000) (*f2) |= TR2_FREE_ACT;
- if (p_ptr->grace >= 15000) (*f4) |= TR4_FLY;
- if ((p_ptr->grace >= 5000) || (p_ptr->grace <= -5000)) (*f1) |= TR1_SPEED;
+ if (p_ptr->grace >= 7000) f |= TR_FREE_ACT;
+ if (p_ptr->grace >= 15000) f |= TR_FLY;
+ if ((p_ptr->grace >= 5000) || (p_ptr->grace <= -5000)) f |= TR_SPEED;
}
}
if (p_ptr->pgod == GOD_TULKAS)
{
- if (p_ptr->grace > 5000) (*f1) |= TR1_CON;
- if (p_ptr->grace > 10000) (*f1) |= TR1_STR;
+ if (p_ptr->grace > 5000) f |= TR_CON;
+ if (p_ptr->grace > 10000) f |= TR_STR;
}
if (p_ptr->pgod == GOD_AULE)
{
if (p_ptr->grace > 5000)
{
- (*f2) |= TR2_RES_FIRE;
+ f |= TR_RES_FIRE;
}
}
if (p_ptr->pgod == GOD_MANDOS)
{
- (*f2) |= TR2_RES_NETHER;
+ f |= TR_RES_NETHER;
if ((p_ptr->grace > 10000) &&
(p_ptr->praying == TRUE))
{
- (*f3) |= TR3_NO_TELE;
+ f |= TR_NO_TELE;
}
if ((p_ptr->grace > 20000) &&
(p_ptr->praying == TRUE))
{
- (*f4) |= TR4_IM_NETHER;
+ f |= TR_IM_NETHER;
}
}
if (p_ptr->pgod == GOD_ULMO)
{
- (*f5) |= TR5_WATER_BREATH;
+ f |= TR_WATER_BREATH;
if ((p_ptr->grace > 1000) &&
(p_ptr->praying == TRUE))
{
- (*f2) |= TR2_RES_POIS;
+ f |= TR_RES_POIS;
}
if ((p_ptr->grace > 15000) &&
(p_ptr->praying == TRUE))
{
- (*f5) |= TR5_MAGIC_BREATH;
+ f |= TR_MAGIC_BREATH;
}
}
/* Classes */
- for (i = 1; i <= p_ptr->lev; i++)
+ for (int i = 1; i <= p_ptr->lev; i++)
{
- (*f1) |= cp_ptr->oflags1[i];
- (*f2) |= cp_ptr->oflags2[i];
- (*f3) |= cp_ptr->oflags3[i];
- (*f4) |= cp_ptr->oflags4[i];
- (*f5) |= cp_ptr->oflags5[i];
- (*esp) |= cp_ptr->oesp[i];
+ f |= cp_ptr->oflags[i];
}
/* Races */
if ((!p_ptr->mimic_form) && (!p_ptr->body_monster))
{
- for (i = 1; i <= p_ptr->lev; i++)
+ for (int i = 1; i <= p_ptr->lev; i++)
{
- (*f1) |= rp_ptr->oflags1[i];
- (*f2) |= rp_ptr->oflags2[i];
- (*f3) |= rp_ptr->oflags3[i];
- (*f4) |= rp_ptr->oflags4[i];
- (*f5) |= rp_ptr->oflags5[i];
- (*esp) |= rp_ptr->oesp[i];
+ f |= rp_ptr->oflags[i];
- (*f1) |= rmp_ptr->oflags1[i];
- (*f2) |= rmp_ptr->oflags2[i];
- (*f3) |= rmp_ptr->oflags3[i];
- (*f4) |= rmp_ptr->oflags4[i];
- (*f5) |= rmp_ptr->oflags5[i];
- (*esp) |= rmp_ptr->oesp[i];
+ f |= rmp_ptr->oflags[i];
}
}
else
{
monster_race *r_ptr = &r_info[p_ptr->body_monster];
- if (r_ptr->flags & RF_REFLECTING) (*f2) |= TR2_REFLECT;
- if (r_ptr->flags & RF_REGENERATE) (*f3) |= TR3_REGEN;
- if (r_ptr->flags & RF_AURA_FIRE) (*f3) |= TR3_SH_FIRE;
- if (r_ptr->flags & RF_AURA_ELEC) (*f3) |= TR3_SH_ELEC;
- if (r_ptr->flags & RF_PASS_WALL) (*f3) |= TR3_WRAITH;
- if (r_ptr->flags & RF_SUSCEP_FIRE) (*f2) |= TR2_SENS_FIRE;
- if (r_ptr->flags & RF_IM_ACID) (*f2) |= TR2_RES_ACID;
- if (r_ptr->flags & RF_IM_ELEC) (*f2) |= TR2_RES_ELEC;
- if (r_ptr->flags & RF_IM_FIRE) (*f2) |= TR2_RES_FIRE;
- if (r_ptr->flags & RF_IM_POIS) (*f2) |= TR2_RES_POIS;
- if (r_ptr->flags & RF_IM_COLD) (*f2) |= TR2_RES_COLD;
- if (r_ptr->flags & RF_RES_NETH) (*f2) |= TR2_RES_NETHER;
- if (r_ptr->flags & RF_RES_NEXU) (*f2) |= TR2_RES_NEXUS;
- if (r_ptr->flags & RF_RES_DISE) (*f2) |= TR2_RES_DISEN;
- if (r_ptr->flags & RF_NO_FEAR) (*f2) |= TR2_RES_FEAR;
- if (r_ptr->flags & RF_NO_SLEEP) (*f2) |= TR2_FREE_ACT;
- if (r_ptr->flags & RF_NO_CONF) (*f2) |= TR2_RES_CONF;
- if (r_ptr->flags & RF_CAN_FLY) (*f3) |= TR3_FEATHER;
- }
-
- (*f1) |= p_ptr->xtra_f1;
- (*f2) |= p_ptr->xtra_f2;
- (*f3) |= p_ptr->xtra_f3;
- (*f4) |= p_ptr->xtra_f4;
- (*f5) |= p_ptr->xtra_f5;
- (*esp) |= p_ptr->xtra_esp;
+ if (r_ptr->flags & RF_REFLECTING) f |= TR_REFLECT;
+ if (r_ptr->flags & RF_REGENERATE) f |= TR_REGEN;
+ if (r_ptr->flags & RF_AURA_FIRE) f |= TR_SH_FIRE;
+ if (r_ptr->flags & RF_AURA_ELEC) f |= TR_SH_ELEC;
+ if (r_ptr->flags & RF_PASS_WALL) f |= TR_WRAITH;
+ if (r_ptr->flags & RF_SUSCEP_FIRE) f |= TR_SENS_FIRE;
+ if (r_ptr->flags & RF_IM_ACID) f |= TR_RES_ACID;
+ if (r_ptr->flags & RF_IM_ELEC) f |= TR_RES_ELEC;
+ if (r_ptr->flags & RF_IM_FIRE) f |= TR_RES_FIRE;
+ if (r_ptr->flags & RF_IM_POIS) f |= TR_RES_POIS;
+ if (r_ptr->flags & RF_IM_COLD) f |= TR_RES_COLD;
+ if (r_ptr->flags & RF_RES_NETH) f |= TR_RES_NETHER;
+ if (r_ptr->flags & RF_RES_NEXU) f |= TR_RES_NEXUS;
+ if (r_ptr->flags & RF_RES_DISE) f |= TR_RES_DISEN;
+ if (r_ptr->flags & RF_NO_FEAR) f |= TR_RES_FEAR;
+ if (r_ptr->flags & RF_NO_SLEEP) f |= TR_FREE_ACT;
+ if (r_ptr->flags & RF_NO_CONF) f |= TR_RES_CONF;
+ if (r_ptr->flags & RF_CAN_FLY) f |= TR_FEATHER;
+ }
+
+ f |= p_ptr->xtra_flags;
if (p_ptr->black_breath)
{
- (*f4) |= TR4_BLACK_BREATH;
+ f |= TR_BLACK_BREATH;
}
if (p_ptr->hp_mod != 0)
{
- (*f2) |= TR2_LIFE;
+ f |= TR_LIFE;
}
+
+ return f;
}
+namespace { // <anonymous>
+
/*
- * Object flag names
+ * Build an return a (static) index of all the object_flag_meta
+ * information indexed by page->column->row.
*/
-static cptr object_flag_names[192] =
+static std::vector<object_flag_meta const *> const &object_flag_metas_by_pcr(int page, int column, int row)
{
- "Add Str",
- "Add Int",
- "Add Wis",
- "Add Dex",
- "Add Con",
- "Add Chr",
- "Mul Mana",
- "Mul SPower",
- "Add Stea.",
- "Add Sear.",
- "Add Infra",
- "Add Tun..",
- "Add Speed",
- "Add Blows",
- "Chaotic",
- "Vampiric",
- "Slay Anim.",
- "Slay Evil",
- "Slay Und.",
- "Slay Demon",
- "Slay Orc",
- "Slay Troll",
- "Slay Giant",
- "Slay Drag.",
- "Kill Drag.",
- "Sharpness",
- "Impact",
- "Poison Brd",
- "Acid Brand",
- "Elec Brand",
- "Fire Brand",
- "Cold Brand",
-
- "Sust Str",
- "Sust Int",
- "Sust Wis",
- "Sust Dex",
- "Sust Con",
- "Sust Chr",
- "Invisible",
- "Mul life",
- "Imm Acid",
- "Imm Elec",
- "Imm Fire",
- "Imm Cold",
- "Sens Fire",
- "Reflect",
- "Free Act",
- "Hold Life",
- "Res Acid",
- "Res Elec",
- "Res Fire",
- "Res Cold",
- "Res Pois",
- "Res Fear",
- "Res Light",
- "Res Dark",
- "Res Blind",
- "Res Conf",
- "Res Sound",
- "Res Shard",
- "Res Neth",
- "Res Nexus",
- "Res Chaos",
- "Res Disen",
-
-
-
- "Aura Fire",
- "Aura Elec",
- "Auto Curse",
- NULL,
- "NoTeleport",
- "AntiMagic",
- "WraithForm",
- "EvilCurse",
- NULL,
- NULL,
- NULL,
- NULL,
- "Levitate",
- "Lite",
- "See Invis",
- NULL,
- "Digestion",
- "Regen",
- "Xtra Might",
- "Xtra Shots",
- NULL,
- NULL,
- NULL,
- NULL,
- "Activate",
- "Drain Exp",
- "Teleport",
- "Aggravate",
- "Blessed",
- "Cursed",
- "Hvy Curse",
- "Prm Curse",
-
- "No blows",
- "Precogn.",
- "B.Breath",
- "Recharge",
- "Fly",
- "Mrg.Curse",
- NULL,
- NULL,
- "Sentient",
- "Clone",
- NULL,
- "Climb",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "Imm Neth",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
-
- "Orc.ESP",
- "Troll.ESP",
- "Dragon.ESP",
- "Giant.ESP",
- "Demon.ESP",
- "Undead.ESP",
- "Evil.ESP",
- "Animal.ESP",
- "TLord.ESP",
- "Good.ESP",
- "Nlive.ESP",
- "Unique.ESP",
- "Spider ESP",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "Full ESP",
+ static std::vector<std::vector<std::vector<std::vector<object_flag_meta const *>>>> instance;
+
+ if (instance.empty())
+ {
+ // Find number of pages, columns and rows.
+ std::size_t n_pages = 0;
+ std::size_t n_columns = 0;
+ std::size_t n_rows = 0;
+
+ for (auto const &object_flag_meta: object_flags_meta())
+ {
+ n_pages = std::max<std::size_t>(n_pages, object_flag_meta->c_page + 1);
+ n_columns = std::max<std::size_t>(n_columns, object_flag_meta->c_column + 1);
+ n_rows = std::max<std::size_t>(n_rows, object_flag_meta->c_row + 1);
+ }
+
+ // Sanity check; we should always have enough data.
+ assert(n_pages > 0);
+ assert(n_columns > 0);
+ assert(n_rows > 0);
+
+ // Build the scaffolding structure without the actual data.
+ instance.reserve(n_pages);
+ for (std::size_t i = 0; i < n_pages; i++)
+ {
+ std::vector<std::vector<std::vector<object_flag_meta const *>>> page;
+ page.reserve(n_columns);
+
+ for (std::size_t j = 0; j < n_columns; j++)
+ {
+ std::vector<std::vector<object_flag_meta const *>> column;
+ column.reserve(n_rows);
+
+ for (std::size_t k = 0; k < n_rows; k++)
+ {
+ std::vector<object_flag_meta const *> row;
+ column.push_back(row);
+ }
+
+ page.push_back(column);
+ }
+
+ instance.push_back(page);
+ }
+
+ // Insert all the data.
+ for (auto const object_flag_meta: object_flags_meta())
+ {
+ // Ignore if not mapped to any page.
+ if (!object_flag_meta->c_name)
+ {
+ continue;
+ }
+
+ // Find the row
+ auto &row = instance
+ .at(object_flag_meta->c_page)
+ .at(object_flag_meta->c_column)
+ .at(object_flag_meta->c_row);
+
+ // Insert
+ row.push_back(object_flag_meta);
+ }
+ }
+
+ return instance.at(page).at(column).at(row);
+}
+
+
+/**
+ * Convert a number to a digit, capping at '9'. Ignores the sign of the number.
+ */
+static char number_to_digit(int n) {
+ // Throw away sign.
+ n = std::abs(n);
+ // Convert to digit or '*'
+ return (n > 9 ? '*' : I2D(n));
};
-/*
- * Summarize resistances
+
+/**
+ * Check that two object_flag types are compatible.
*/
-static void display_player_ben_one(int mode)
+static bool object_flag_types_are_compatible(char type_a, char type_b)
{
- int i, n, x, y, z, dispx, modetemp, xtemp;
+ switch (type_a)
+ {
+ case 'n':
+ return (type_b == 'n');
+ case 'b':
+ return (type_b == 'b');
+ case '+':
+ case '*':
+ return (type_b == '+') || (type_b == '*');
+ case 'f':
+ return (type_b == 'f');
+ case '\0':
+ return true;
+ default:
+ abort();
+ }
+}
- object_type *o_ptr;
+/**
+ * Object flag data for calculating cells on the character sheet.
+ */
+struct object_flag_cell {
+ /**
+ * Type designator for the cell, if any.
+ */
+ char type;
+
+ /**
+ * Associated PVAL, if any.
+ */
+ int pval;
- char dummy[80], c;
+ /**
+ * Label for the cell, given its current contents.
+ */
+ const char *label;
- u32b f1, f2, f3, f4, f5, esp;
+ /**
+ * Create object_flag_cell from object_flag_meta.
+ */
+ static object_flag_cell from_object_flag_meta(object_flag_meta const &object_flag_meta, int pval)
+ {
+ // The FIXED type flags require special handling.
+ if ((object_flag_meta.c_type == '1') || (object_flag_meta.c_type == '2') || (object_flag_meta.c_type == '3'))
+ {
+ return object_flag_cell {
+ 'f',
+ D2I(object_flag_meta.c_type),
+ object_flag_meta.c_name
+ };
+ }
+ else
+ {
+ return object_flag_cell {
+ object_flag_meta.c_type,
+ pval,
+ object_flag_meta.c_name
+ };
+ }
+ }
- u16b b[INVEN_TOTAL - INVEN_WIELD + 1][10];
+};
- int d[INVEN_TOTAL - INVEN_WIELD + 1];
+namespace detail { // "hide" from surrounding scope; should only be accessed through the monoid
- bool_ got;
+static object_flag_cell object_flag_cell_append(object_flag_cell const &a, object_flag_cell const &b)
+{
+ // The "empty" value automatically gets swallowed, whatever
+ // "side" of the append it's on.
+ if (a.type == '\0')
+ {
+ return b;
+ }
- byte a;
+ if (b.type == '\0')
+ {
+ return a;
+ }
- cptr name;
+ // The rest of the code assumes compatible types, so we
+ // assert this to a) avoid over-complicated logic, and
+ // b) breaking under 'unexpected' changes to the object
+ // flag list.
+ if (!object_flag_types_are_compatible(a.type, b.type))
+ {
+ abort();
+ }
- /* Scan equipment */
- for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ // Any boolean flag which is "set" overrides the previous
+ // flag. (If the flag was already set we won't lose any
+ // information.)
+ if (b.type == 'b')
{
- /* Index */
- n = (i - INVEN_WIELD);
+ return b;
+ }
- /* Object */
- o_ptr = &p_ptr->inventory[i];
+ // Flags with a numerical value get added together.
+ if (b.type == 'n') // (a.type == 'n') by symmetry and object_flag_types_are_compatible()
+ {
+ // Arbitrary choice of label -- the labels *should* be the same, by definition
+ return object_flag_cell { 'n', a.pval + b.pval, a.label };
+ }
- /* Known object flags */
- object_flags_known(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ // Fixed-value flags.
+ if (a.type == 'f') // (b.type == 'f') by symmetry and object_flag_types_are_compatible()
+ {
+ // Arbitrary choice of label -- the labels *should* be the same, by definition
+ return object_flag_cell { 'f', a.pval + b.pval, a.label };
+ }
- /* Incorporate */
- b[n][0] = (u16b)(f1 & 0xFFFF);
- b[n][1] = (u16b)(f1 >> 16);
- b[n][2] = (u16b)(f2 & 0xFFFF);
- b[n][3] = (u16b)(f2 >> 16);
- b[n][4] = (u16b)(f3 & 0xFFFF);
- b[n][5] = (u16b)(f3 >> 16);
- b[n][6] = (u16b)(f4 & 0xFFFF);
- b[n][7] = (u16b)(f4 >> 16);
- b[n][8] = (u16b)(esp & 0xFFFF);
- b[n][9] = (u16b)(esp >> 16);
- d[n] = o_ptr->pval;
+ // Flags of the TERNARY variety have a "supercedes" rule
+ // where immunity supercedes resistance.
+ if (a.type == '*')
+ {
+ return object_flag_cell { '*', 0, a.label };
+ }
+ else if (b.type == '*')
+ {
+ return object_flag_cell { '*', 0, b.label };
+ }
+ else // Both must be '+'
+ {
+ // Arbitrary choice of label -- the labels *should* be the same, by definition
+ return object_flag_cell { '+', 0, a.label };
}
+}
- /* Carried symbiote */
- n = INVEN_CARRY - INVEN_WIELD;
+constexpr object_flag_cell object_flag_cell_empty { '\0', 0, nullptr };
- /* Player flags */
- wield_monster_flags(&f1, &f2, &f3, &f4, &f5, &esp);
+} // namespace "detail"
- /* Incorporate */
- b[n][0] = (u16b)(f1 & 0xFFFF);
- b[n][1] = (u16b)(f1 >> 16);
- b[n][2] = (u16b)(f2 & 0xFFFF);
- b[n][3] = (u16b)(f2 >> 16);
- b[n][4] = (u16b)(f3 & 0xFFFF);
- b[n][5] = (u16b)(f3 >> 16);
- b[n][6] = (u16b)(f4 & 0xFFFF);
- b[n][7] = (u16b)(f4 >> 16);
- b[n][8] = (u16b)(esp & 0xFFFF);
- b[n][9] = (u16b)(esp >> 16);
+using object_flag_cell_monoid = monoid<object_flag_cell, detail::object_flag_cell_append, detail::object_flag_cell_empty>;
- /* Index */
- n = INVEN_TOTAL - INVEN_WIELD;
+} // namespace <anonymous>
- /* Player flags */
- player_flags(&f1, &f2, &f3, &f4, &f5, &esp);
+namespace { // <anonymous>
- /* Incorporate */
- b[n][0] = (u16b)(f1 & 0xFFFF);
- b[n][1] = (u16b)(f1 >> 16);
- b[n][2] = (u16b)(f2 & 0xFFFF);
- b[n][3] = (u16b)(f2 >> 16);
- b[n][4] = (u16b)(f3 & 0xFFFF);
- b[n][5] = (u16b)(f3 >> 16);
- b[n][6] = (u16b)(f4 & 0xFFFF);
- b[n][7] = (u16b)(f4 >> 16);
- b[n][8] = (u16b)(esp & 0xFFFF);
- b[n][9] = (u16b)(esp >> 16);
+static object_flag_meta const *get_lowest_priority_object_flag_meta(std::vector<object_flag_meta const *> const &object_flag_metas)
+{
+ object_flag_meta const *found = nullptr;
- /* Generate the equip chars */
- sprintf(dummy, " ");
- for (i = 0; i < INVEN_TOTAL - INVEN_WIELD; i++)
+ for (auto object_flag_meta: object_flag_metas)
{
- /* If you have that body part then show it */
- if (p_ptr->body_parts[i])
+ if ((!found) || (found->c_priority > object_flag_meta->c_priority))
{
- strcat(dummy, format("%c", i + 'a'));
+ found = object_flag_meta;
}
}
- strcat(dummy, "@");
- /* Scan cols */
- for (x = 1; x > -1; x--)
+ return found;
+}
+
+
+static std::tuple<char, int> object_flag_cell_to_char(object_flag_cell const &object_flag_cell)
+{
+ switch (object_flag_cell.type)
{
- /* Label */
- Term_putstr(x * 40 + 11, 3, -1, TERM_WHITE, dummy);
+ case 'n':
+ case 'f':
+ // If we have no pval, we use a simple '+'. This applies
+ // to the 'player' slot.
+ if (object_flag_cell.pval == 0)
+ {
+ return std::make_tuple('+', 1);
+ }
+ else
+ {
+ return std::make_tuple(
+ number_to_digit(object_flag_cell.pval),
+ (object_flag_cell.pval >= 0) ? 1 : -1);
+ }
+ break;
+
+ case 'b':
+ case '+':
+ return std::make_tuple('+', 1);
+ break;
+
+ case '*':
+ return std::make_tuple('*', 1);
+ break;
+
+ default:
+ return std::make_tuple('.', 0);
+ break;
+ }
+
+ abort();
+}
+
- /* Scan rows */
- for (y = 0; y < 16; y++)
+/*
+ * Output a slot
+ */
+static void display_flag_row(
+ int y,
+ int x0,
+ std::vector<std::tuple<char, int, object_flag_set>> const &slots,
+ std::vector<object_flag_meta const *> const &object_flag_metas_at_pcr)
+{
+ assert(!object_flag_metas_at_pcr.empty());
+
+ // Accumulated value of all of the slots
+ auto acc = object_flag_cell_monoid::empty;
+
+ // Go through each slot
+ for (std::size_t i = 0; i < slots.size(); i++)
+ {
+ object_flag_cell combined = object_flag_cell_monoid::empty;
+
+ // Go through all flags that are actually set for this 'cell'.
{
- if (mode == 3 && x == 1)
- {
- modetemp = 4;
- xtemp = 0;
- }
- else
+ auto const &slot = slots[i];
+ auto const pval = std::get<1>(slot);
+ auto const flags = std::get<2>(slot);
+
+ for (auto const object_flag_meta: object_flag_metas_at_pcr)
{
- modetemp = mode;
- xtemp = x;
+ if (object_flag_meta->flag_set & flags)
+ {
+ combined = object_flag_cell_monoid::append(
+ combined,
+ object_flag_cell::from_object_flag_meta(*object_flag_meta, pval));
+ }
}
+ }
- for (z = mode; z <= modetemp; z++)
- {
- if (mode == 3 && x == 1 && z == modetemp) xtemp = 1;
- name = object_flag_names[32 * modetemp + 16 * xtemp + y];
- got = FALSE;
+ // Accumulate into the global accumulator
+ acc = object_flag_cell_monoid::append(acc, combined);
- /* No name */
- if (!name) continue;
+ // Write the cell's value.
+ auto const char_and_rating = object_flag_cell_to_char(combined);
+ auto const ch = std::get<0>(char_and_rating);
+ auto const rating = std::get<1>(char_and_rating);
- /* Dump colon */
- if (!(modetemp == 1 && x == 0 && y > 7 && y < 12))
- {
- Term_putch(x * 40 + 10, y + 4, TERM_WHITE, ':');
- }
+ // Convert good flag into a color.
+ byte a;
+ if (rating == 0)
+ {
+ a = (i & 0x02) ? TERM_GREEN : TERM_SLATE;
+ }
+ else if (rating < 0)
+ {
+ a = TERM_RED;
+ }
+ else
+ {
+ a = TERM_L_GREEN;
+ }
- /* Check flags */
- dispx = 0;
- for (n = 0; n < INVEN_TOTAL - INVEN_WIELD + 1; n++)
- {
- /* Change colour every two columns */
- bool_ is_green = (dispx & 0x02);
- a = (is_green ? TERM_GREEN : TERM_SLATE);
- c = '.';
+ // Output the flag
+ Term_putch(x0 + 11 + i, y, a, ch);
+ }
- /* If the body part doesn't exists then skip it :) */
- if ((n < INVEN_TOTAL - INVEN_WIELD) && (!p_ptr->body_parts[n])) continue;
+ // Extract the label. If the flag isn't set at all then we don't have
+ // an actual label, so we'll use the one from the meta-level object
+ // flag definition. Note that the prioritization is crucial for the
+ // labeling to work properly; e.g. IMM_FIRE comes *before* the
+ // RES_FIRE flag in the object flag list, but we don't want the *label*
+ // from IMM_FIRE to be used when the flag is not set at all.
+ auto const label = (acc.label != nullptr)
+ ? acc.label
+ : get_lowest_priority_object_flag_meta(object_flag_metas_at_pcr)->c_name;
- /* Increment the drawing coordinates */
- dispx++;
+ // Get the "rating" for the label.
+ auto const rating = std::get<1>(object_flag_cell_to_char(acc));
- /* Check flag */
- if (b[n][2 * modetemp + xtemp] & (1 << y))
- {
- a = (is_green ? TERM_L_GREEN : TERM_WHITE);
- if (modetemp == 1 && x == 0 && y > 7 && y < 12)
- {
- c = '*';
- }
- else if (modetemp == 0 && x == 0 && y < 14 && (y < 6 || y > 7))
- {
- if (n == INVEN_TOTAL - INVEN_WIELD)
- {
- c = '+';
- }
- else
- {
- c = d[n];
- if (c < 0)
- {
- c = -c;
- a = TERM_RED;
- }
- c = (c > 9 ? '*' : I2D(c));
- }
- }
- else
- {
- c = '+';
- }
- got = TRUE;
- }
+ byte label_attr;
+ if (rating == 0) {
+ label_attr = TERM_WHITE;
+ } else if (rating < 0) {
+ label_attr = TERM_RED;
+ } else {
+ label_attr = TERM_L_GREEN;
+ }
- /* HACK - Check for nether immunity and
- apply to Res Neth line */
- if (modetemp == 1 && x == 1 && y == 12)
- {
- if (b[n][7] & (1 << 6))
- {
- a = (is_green ? TERM_L_GREEN : TERM_WHITE);
- c = '*';
- got = TRUE;
- }
- }
+ Term_putch(x0 + 10, y, TERM_WHITE, ':');
+ Term_putstr(x0, y, -1, label_attr, label);
+}
- /* Dump flag */
- if (modetemp == 1 && x == 0 && y > 7 && y < 12)
- {
- if (c == '*') Term_putch(40 + 11 + dispx, y - 4, a, c);
- }
- else
- {
- Term_putch(x * 40 + 11 + dispx, y + 4, a, c);
- }
- }
+/*
+ * Summarize resistances
+ */
+static void display_player_ben_one(int page)
+{
+ // Slots of flags to show.
+ std::vector<std::tuple<char, int, object_flag_set>> slots;
+ slots.reserve(INVEN_TOTAL - INVEN_WIELD + 1);
- a = TERM_WHITE;
- if (got)
- {
- if (modetemp == 1 && x == 0 && y > 7 && y < 12)
- {
- a = TERM_L_GREEN;
- }
- else if (modetemp != 0)
- {
- a = TERM_GREEN;
- }
- }
+ // Scan equipment
+ for (std::size_t i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ // Skip inventory slots that don't exist on the body.
+ auto n = i - INVEN_WIELD;
+ if ((n < INVEN_TOTAL - INVEN_WIELD) && (!p_ptr->body_parts[n])) continue;
- /* HACK - Check for nether immunity and change "Res Neth" */
- if (modetemp == 1 && x == 1 && y == 12 && p_ptr->immune_neth)
- {
- name = "Imm Neth";
- a = TERM_L_GREEN;
- }
+ // Extract object flags
+ auto const o_ptr = &p_ptr->inventory[i];
+ auto const flags = object_flags_known(o_ptr);
+ // Add slot
+ slots.emplace_back(
+ std::make_tuple('a' + i - INVEN_WIELD, o_ptr->pval, flags));
+ }
- /* Dump name */
- if (modetemp == 1 && x == 0 && y > 7 && y < 12)
- {
- if (got) Term_putstr(40, y - 4, -1, a, name);
- }
- else
- {
- Term_putstr(x * 40, y + 4, -1, a, name);
- }
+ // Carried symbiote
+ {
+ // Extract flags
+ auto const flags = wield_monster_flags();
+ // Add slot
+ slots.emplace_back(
+ std::make_tuple('z', 0, flags));
+ }
+
+ // Player
+ slots.emplace_back(
+ std::make_tuple('@', 0, player_flags()));
+
+ // Go through each column
+ for (int col = 0; col < 2; col++)
+ {
+ // Base coordinate for output
+ const auto x0 = col * 40;
+ const auto y0 = 3;
+
+ // Add slot headings.
+ {
+ std::string buf;
+ buf.reserve(slots.size());
+
+ for (auto const &slot: slots)
+ {
+ buf += std::get<0>(slot);
+ }
+
+ Term_putstr(x0 + 11, y0, -1, TERM_WHITE, buf.c_str());
+ }
+
+ // Scan rows
+ for (int row = 0; row < 16; row++)
+ {
+ // Extract the flag metadata for the current page/col/row
+ auto const object_flag_metas_at_pcr =
+ object_flag_metas_by_pcr(page, col, row);
+
+ // Ignore flags which we don't actually map to anything.
+ if (object_flag_metas_at_pcr.empty())
+ {
+ continue;
}
+
+ // Y coordinate for the row
+ auto const y = y0 + 1 + row;
+
+ // Show the row
+ display_flag_row(y, x0, slots, object_flag_metas_at_pcr);
}
}
}
+} // namespace <anonymous>
/*
* Display the character on the screen (various modes)
@@ -4030,7 +4056,7 @@ static long total_points(void)
object_kind *k_ptr = &k_info[k];
/* Hack -- skip artifacts */
- if (k_ptr->flags3 & (TR3_INSTA_ART)) continue;
+ if (k_ptr->flags & TR_INSTA_ART) continue;
/* List known flavored objects */
if (k_ptr->flavor && k_ptr->aware)