Get the item abilities dialog working and updated for new stuff

- Add additional treasure type for "unique" items
- Main item dialog now shows the item ability's display name, and also has more space for the item's full name
- (Game) No-ammo missiles (eg slings) are now counted as weapons by shops
- (Dialog Engine) Fix LED groups being drawn when invisible
This commit is contained in:
2015-01-21 14:04:40 -05:00
parent fb607f83c1
commit 311a3c0702
13 changed files with 713 additions and 427 deletions

View File

@@ -39,24 +39,9 @@ extern sf::RenderWindow mini_map;
extern sf::Texture pc_gworld;
extern cUniverse univ;
const std::multiset<eItemType> equippable = {
eItemType::ONE_HANDED, eItemType::TWO_HANDED, eItemType::BOW, eItemType::ARROW, eItemType::THROWN_MISSILE,
eItemType::TOOL, eItemType::SHIELD, eItemType::ARMOR, eItemType::HELM, eItemType::GLOVES,
eItemType::SHIELD_2, eItemType::BOOTS, eItemType::RING, eItemType::NECKLACE, eItemType::PANTS,
eItemType::CROSSBOW, eItemType::BOLTS, eItemType::MISSILE_NO_AMMO,
// And these are the ones that you can equip two of
eItemType::ONE_HANDED, eItemType::RING,
};
const std::multiset<eItemType> num_hands_to_use = {
eItemType::ONE_HANDED, eItemType::TWO_HANDED, eItemType::TWO_HANDED, eItemType::SHIELD, eItemType::SHIELD_2,
};
// For following, if an item of type n is equipped, no other items of type n can be equipped,
// TODO: Should SHIELD and SHIELD_2 have an entry here?
std::map<const eItemType, const short> excluding_types = {
{eItemType::BOW, 2}, {eItemType::ARROW, 1}, {eItemType::THROWN_MISSILE, 1},
{eItemType::CROSSBOW, 2}, {eItemType::BOLTS, 1}, {eItemType::MISSILE_NO_AMMO, 2}
};
extern const std::multiset<eItemType> equippable;
extern const std::multiset<eItemType> num_hands_to_use;
extern std::map<const eItemType, const short> excluding_types;
short selected,item_max = 0;

View File

@@ -14,6 +14,27 @@
#include "classes.h"
#include "boe.consts.h" // TODO: If this is needed here, maybe it shouldn't be in the "boe" namespace
#include "oldstructs.h"
#include "spell.hpp"
extern const std::multiset<eItemType> equippable = {
eItemType::ONE_HANDED, eItemType::TWO_HANDED, eItemType::BOW, eItemType::ARROW, eItemType::THROWN_MISSILE,
eItemType::TOOL, eItemType::SHIELD, eItemType::ARMOR, eItemType::HELM, eItemType::GLOVES,
eItemType::SHIELD_2, eItemType::BOOTS, eItemType::RING, eItemType::NECKLACE, eItemType::PANTS,
eItemType::CROSSBOW, eItemType::BOLTS, eItemType::MISSILE_NO_AMMO,
// And these are the ones that you can equip two of
eItemType::ONE_HANDED, eItemType::RING,
};
extern const std::multiset<eItemType> num_hands_to_use = {
eItemType::ONE_HANDED, eItemType::TWO_HANDED, eItemType::TWO_HANDED, eItemType::SHIELD, eItemType::SHIELD_2,
};
// For following, if an item of type n is equipped, no other items of type n can be equipped,
// TODO: Should SHIELD and SHIELD_2 have an entry here?
std::map<const eItemType, const short> excluding_types = {
{eItemType::BOW, 2}, {eItemType::ARROW, 1}, {eItemType::THROWN_MISSILE, 1},
{eItemType::CROSSBOW, 2}, {eItemType::BOLTS, 1}, {eItemType::MISSILE_NO_AMMO, 2}
};
unsigned char cItem::rec_treas_class() const {
short tmp = value;
@@ -911,6 +932,295 @@ void cItem::append(legacy::item_record_type& old){
}
}
std::string cItem::getAbilName() {
bool harmful = magic_use_type % 2;
bool party = magic_use_type >= 2;
std::ostringstream sout;
switch(ability) {
case eItemAbil::NONE: sout << "No ability"; break;
case eItemAbil::HEALING_WEAPON: sout << "Heals target"; break;
case eItemAbil::RETURNING_MISSILE: sout << "Returning missile"; break;
case eItemAbil::DISTANCE_MISSILE: sout << "Farflight missile"; break;
case eItemAbil::SEEKING_MISSILE: sout << "Seeking missile"; break;
case eItemAbil::ANTIMAGIC_WEAPON: sout << "Manasucker"; break;
case eItemAbil::SOULSUCKER: sout << "Soulsucker"; break;
case eItemAbil::DRAIN_MISSILES: sout << "Drain Missiles"; break;
case eItemAbil::WEAK_WEAPON: sout << "Weak Weapon"; break;
case eItemAbil::CAUSES_FEAR: sout << "Causes Fear"; break;
case eItemAbil::WEAPON_CALL_SPECIAL: sout << "Unusual Attack Effect"; break;
case eItemAbil::FULL_PROTECTION: sout << "Full Protection"; break;
case eItemAbil::MELEE_PROTECTION: sout << "Melee Protection"; break;
case eItemAbil::EVASION: sout << "Evasion"; break;
case eItemAbil::MARTYRS_SHIELD: sout << "Martyr's Shield"; break;
case eItemAbil::ENCUMBERING: sout << "Awkward Weapon"; break;
case eItemAbil::SKILL: sout << "Skill"; break;
case eItemAbil::BOOST_WAR: sout << "Warrior's Mantle"; break;
case eItemAbil::BOOST_MAGIC: sout << "Mage's Mantle"; break;
case eItemAbil::ACCURACY: sout << "Accuracy"; break;
case eItemAbil::THIEVING: sout << "Thieving"; break;
case eItemAbil::GIANT_STRENGTH: sout << "Giant Strength"; break;
case eItemAbil::LIGHTER_OBJECT: sout << "Lighter Object"; break;
case eItemAbil::HEAVIER_OBJECT: sout << "Heavier Object"; break;
case eItemAbil::HIT_CALL_SPECIAL: sout << "Unusual Defense Effect"; break;
case eItemAbil::LIFE_SAVING: sout << "Life Saving"; break;
case eItemAbil::PROTECT_FROM_PETRIFY: sout << "Protect from Petrify"; break;
case eItemAbil::REGENERATE: sout << "Regenerate"; break;
case eItemAbil::POISON_AUGMENT: sout << "Poison Augment"; break;
case eItemAbil::RADIANT: sout << "Radiance"; break;
case eItemAbil::WILL: sout << "Will"; break;
case eItemAbil::FREE_ACTION: sout << "Free Action"; break;
case eItemAbil::SPEED: sout << "Speed"; break;
case eItemAbil::SLOW_WEARER: sout << "Slow Wearer"; break;
case eItemAbil::LOCKPICKS: sout << "Lockpicks"; break;
case eItemAbil::POISON_WEAPON: sout << "Poison Weapon"; break;
case eItemAbil::CALL_SPECIAL: sout << "Unusual Ability"; break;
case eItemAbil::QUICKFIRE: sout << "Quickfire"; break;
case eItemAbil::HOLLY: sout << "Holly/Toadstool"; break;
case eItemAbil::COMFREY: sout << "Comfrey Root"; break;
case eItemAbil::NETTLE: sout << "Glowing Nettle"; break;
case eItemAbil::WORMGRASS: sout << "Crypt Shroom/Wormgrass"; break;
case eItemAbil::ASPTONGUE: sout << "Asptongue Mold"; break;
case eItemAbil::EMBERF: sout << "Ember Flower"; break;
case eItemAbil::GRAYMOLD: sout << "Graymold"; break;
case eItemAbil::MANDRAKE: sout << "Mandrake Root"; break;
case eItemAbil::SAPPHIRE: sout << "Sapphire"; break;
case eItemAbil::SMOKY_CRYSTAL: sout << "Smoky Crystal"; break;
case eItemAbil::RESURRECTION_BALM: sout << "Resurrection Balm"; break;
case eItemAbil::DAMAGING_WEAPON:
switch(eDamageType(abil_data[1])) {
case eDamageType::FIRE: sout << "Flaming"; break;
case eDamageType::MAGIC: sout << "Shocking"; break;
case eDamageType::COLD: sout << "Frosty"; break;
case eDamageType::POISON: sout << "Slimy"; break;
case eDamageType::WEAPON: sout << "Enhanced"; break;
case eDamageType::UNDEAD: sout << "Necrotic"; break;
case eDamageType::DEMON: sout << "Unholy"; break;
case eDamageType::UNBLOCKABLE: sout << "Dark"; break;
case eDamageType::MARKED: break; // Invalid
}
sout << " Weapon";
break;
case eItemAbil::SLAYER_WEAPON:
switch(eRace(abil_data[1])) {
case eRace::UNKNOWN: break; // Invalid
case eRace::DEMON: sout << "Demon"; break;
case eRace::UNDEAD: sout << "Undead"; break;
case eRace::REPTILE: sout << "Lizard"; break;
case eRace::GIANT: sout << "Giant"; break;
case eRace::MAGE: sout << "Mage"; break;
case eRace::PRIEST: sout << "Priest"; break;
case eRace::BUG: sout << "Bug"; break;
case eRace::HUMAN: sout << "Human"; break;
case eRace::NEPHIL: sout << "Nephil"; break;
case eRace::SLITH: sout << "Slith"; break;
case eRace::VAHNATAI: sout << "Vahnatai"; break;
case eRace::HUMANOID: sout << "Humanoid"; break;
case eRace::BEAST: sout << "Beast"; break;
case eRace::IMPORTANT: sout << "VIP"; break; // TODO: This one should probably not exist
case eRace::SLIME: sout << "Slime"; break;
case eRace::STONE: sout << "Golem"; break;
case eRace::DRAGON: sout << "Dragon"; break;
case eRace::MAGICAL: sout << "Magical Beast"; break;
case eRace::PLANT: sout << "Plant"; break;
case eRace::BIRD: sout << "Bird"; break;
}
sout << " Slayer";
break;
case eItemAbil::EXPLODING_WEAPON:
sout << "Explodes ";
switch(eDamageType(abil_data[1])) {
case eDamageType::FIRE: sout << "in flames"; break;
case eDamageType::COLD: sout << "into frost"; break;
case eDamageType::MAGIC: sout << "in sparks"; break;
case eDamageType::POISON: sout << "into slime"; break;
case eDamageType::WEAPON: sout << "in shrapnel"; break;
case eDamageType::UNBLOCKABLE: sout << "in darkness"; break;
case eDamageType::UNDEAD: sout.str("Implodes"); break;
case eDamageType::DEMON: sout << "into corruption"; break;
case eDamageType::MARKED: break; // Invalid
}
break;
case eItemAbil::STATUS_WEAPON:
switch(eStatus(abil_data[1])) {
case eStatus::MAIN: break; // Invalid
case eStatus::POISONED_WEAPON:
case eStatus::INVULNERABLE:
case eStatus::MAGIC_RESISTANCE:
case eStatus::INVISIBLE:
break; // TODO: Not implemented?
case eStatus::ACID: sout << "Acidic"; break;
case eStatus::POISON: sout << "Poisoned"; break;
case eStatus::BLESS_CURSE: sout << "Cursing"; break;
case eStatus::HASTE_SLOW: sout << "Slowing"; break;
case eStatus::WEBS: sout << "Webbing"; break;
case eStatus::DISEASE: sout << "Infectious"; break;
case eStatus::DUMB: sout << "Dumbfounding"; break;
case eStatus::MARTYRS_SHIELD: sout << "Martyr Draining"; break;
case eStatus::ASLEEP: sout << "Soporific"; break;
case eStatus::PARALYZED: sout << "Paralytic"; break;
case eStatus::FORCECAGE: sout << "Entrapping"; break;
case eStatus::CHARM: sout << "Charming"; break;
}
sout << " Weapon";
break;
case eItemAbil::DAMAGE_PROTECTION:
switch(eDamageType(abil_data[1])) {
case eDamageType::WEAPON: break;
case eDamageType::FIRE: sout << "Fire"; break;
case eDamageType::COLD: sout << "Cold"; break;
case eDamageType::MAGIC: sout << "Magic"; break;
case eDamageType::DEMON: sout << "Demon"; break;
case eDamageType::UNDEAD: sout << "Undead"; break;
case eDamageType::POISON: sout << "Poison"; break;
case eDamageType::UNBLOCKABLE: sout << "Darkness"; break;
case eDamageType::MARKED: break; // Invalid
}
sout << " Protection";
break;
case eItemAbil::STATUS_PROTECTION:
sout << "Protect From ";
switch(eStatus(abil_data[1])) {
case eStatus::MAIN: break; // Invalid;
case eStatus::POISONED_WEAPON:
case eStatus::INVULNERABLE:
case eStatus::MARTYRS_SHIELD:
case eStatus::FORCECAGE:
case eStatus::CHARM:
case eStatus::INVISIBLE:
break; // TODO: Not implemented:
case eStatus::POISON: sout << "Poison"; break;
case eStatus::ACID: sout << "Acid"; break;
case eStatus::DISEASE: sout << "Disease"; break;
case eStatus::BLESS_CURSE: sout << "Curses"; break;
case eStatus::HASTE_SLOW: sout << "Slowing"; break;
case eStatus::MAGIC_RESISTANCE: sout << "Magic Vulnerability"; break;
case eStatus::WEBS: sout << "Webbing"; break;
case eStatus::DUMB: sout << "Dumbfounding"; break;
case eStatus::ASLEEP: sout << "Sleep"; break;
case eStatus::PARALYZED: sout << "Paralysis"; break;
}
break;
case eItemAbil::BOOST_STAT:
sout << get_str("skills", abil_data[1] * 2 + 1);
break;
case eItemAbil::OCCASIONAL_STATUS:
sout << "Occasional ";
switch(eStatus(abil_data[1])) {
case eStatus::MAIN: break; // Invalid;
case eStatus::FORCECAGE:
case eStatus::CHARM:
break; // TODO: Not implemented?
case eStatus::DISEASE: sout << (harmful ? "Disease" : "Cure Disease"); break;
case eStatus::HASTE_SLOW: sout << (harmful ? "Slow" : "Haste"); break;
case eStatus::BLESS_CURSE: sout << (harmful ? "Curse" : "Bless"); break;
case eStatus::POISON: sout << (harmful ? "Poison" : "Cure"); break;
case eStatus::WEBS: sout << (harmful ? "Webbing" : "Cleansing"); break;
case eStatus::DUMB: sout << (harmful ? "Dumbfounding" : "Enlightening"); break;
case eStatus::MARTYRS_SHIELD: sout << (harmful ? "Lose" : "Gain") << " Martyr's Shield"; break;
case eStatus::INVULNERABLE: sout << (harmful ? "Lose" : "Gain") << " Invulnerability"; break;
case eStatus::MAGIC_RESISTANCE: sout << "Magic " << (harmful ? "Vulnerability" : "Resistance"); break;
case eStatus::INVISIBLE: sout << (harmful ? "Lose" : "Gain") << " Sanctuary"; break;
case eStatus::POISONED_WEAPON: sout << (harmful ? "Lose" : "Gain") << " Weapon Poison"; break;
case eStatus::ASLEEP: sout << (harmful ? "Sleep" : "Hyperactivity"); break;
case eStatus::PARALYZED: sout << (harmful ? "Gain" : "Lose") << " Paralysis"; break;
case eStatus::ACID: sout << (harmful ? "Gain" : "Neutralize") << " Acid"; break;
}
sout << (party ? " Party" : " Wearer");
break;
case eItemAbil::PROTECT_FROM_SPECIES:
sout << "Protection from ";
switch(eRace(abil_data[1])) {
case eRace::UNKNOWN: break; // Invalid
case eRace::UNDEAD: sout << "Undead"; break;
case eRace::DEMON: sout << "Demons"; break;
case eRace::HUMANOID: sout << "Humanoids"; break;
case eRace::REPTILE: sout << "Reptiles"; break;
case eRace::GIANT: sout << "Giants"; break;
case eRace::HUMAN: sout << "Humans"; break;
case eRace::NEPHIL: sout << "Nephilim"; break;
case eRace::SLITH: sout << "Sliths"; break;
case eRace::VAHNATAI: sout << "Vahnatai"; break;
case eRace::BEAST: sout << "Beasts"; break;
case eRace::IMPORTANT: sout << "VIPs"; break;
case eRace::MAGE: sout << "Mages"; break;
case eRace::PRIEST: sout << "Priests"; break;
case eRace::SLIME: sout << "Slimes"; break;
case eRace::STONE: sout << "Golems"; break;
case eRace::BUG: sout << "Bugs"; break;
case eRace::DRAGON: sout << "Dragons"; break;
case eRace::MAGICAL: sout << "Magical Beasts"; break;
case eRace::PLANT: sout << "Plants"; break;
case eRace::BIRD: sout << "Birds"; break;
}
break;
case eItemAbil::AFFECT_STATUS:
switch(eStatus(abil_data[1])) {
case eStatus::MAIN: break; // Invalid;
case eStatus::FORCECAGE: break;
case eStatus::CHARM: break;
case eStatus::POISONED_WEAPON: sout << (harmful ? "Increase" : "Decrease") << " Weapon Poison"; break;
case eStatus::BLESS_CURSE: sout << (harmful ? "Curse" : "Bless"); break;
case eStatus::POISON: sout << (harmful ? "Cause" : "Cure") << " Poison"; break;
case eStatus::HASTE_SLOW: sout << (harmful ? "Slow" : "Haste"); break;
case eStatus::INVULNERABLE: sout << (harmful ? "Lose" : "Add") << " Invulnerability"; break;
case eStatus::MAGIC_RESISTANCE: sout << (harmful ? "Lose" : "Add") << " Magic Resistance"; break;
case eStatus::WEBS: sout << (harmful ? "Lose" : "Add") << "Webs"; break;
case eStatus::DISEASE: sout << (harmful ? "Cause" : "Cure") << " Disease"; break;
case eStatus::INVISIBLE: sout << (harmful ? "Lose" : "Add") << " Sanctuary"; break;
case eStatus::DUMB: sout << (harmful ? "Add" : "Lose") << " Dumbfounding"; break;
case eStatus::MARTYRS_SHIELD: sout << (harmful ? "Lose" : "Add") << " Martyr's Shield"; break;
case eStatus::ASLEEP: sout << (harmful ? "Cause" : "Cure") << " Sleep"; break;
case eStatus::PARALYZED: sout << (harmful ? "Cause" : "Cure") << " Paralysis"; break;
case eStatus::ACID: sout << (harmful ? "Cause" : "Cure") << " Acid"; break;
}
break;
case eItemAbil::CAST_SPELL:
sout << "Spell: " << (*cSpell::fromNum(abil_data[1])).name();
break;
case eItemAbil::BLISS_DOOM:
if(magic_use_type >= 2)
sout << "Party ";
sout << (harmful ? "Doom" : "Bliss");
break;
case eItemAbil::AFFECT_EXPERIENCE:
sout << (harmful ? "Drain" : "Gain") << " Experience";
break;
case eItemAbil::AFFECT_SKILL_POINTS:
sout << (harmful ? "Drain" : "Gain") << " Skill Points";
break;
case eItemAbil::AFFECT_HEALTH:
sout << (harmful ? "Drain Health" : "Heal");
break;
case eItemAbil::AFFECT_SPELL_POINTS:
sout << (harmful ? "Drain" : "Restore") << " Spell Points";
break;
case eItemAbil::LIGHT:
sout << (harmful ? "Drain" : "Increase") << " Light";
break;
case eItemAbil::AFFECT_PARTY_STATUS:
sout << (harmful ? "Lose " : "Gain ");
switch(ePartyStatus(abil_data[1])) {
case ePartyStatus::STEALTH: sout << "Stealth"; break;
case ePartyStatus::FLIGHT: sout << "Flight"; break;
case ePartyStatus::DETECT_LIFE: sout << "Life Detection"; break;
case ePartyStatus::FIREWALK: sout << "Firewalk"; break;
}
break;
case eItemAbil::HEALTH_POISON:
sout << "Major " << (harmful ? "Poison" : "Healing");
if(party) sout << " All";
break;
case eItemAbil::SUMMONING:
// TODO: Figure out a way to wedge the monster name in here.
sout << "Summons " << "monst-names";
break;
case eItemAbil::MASS_SUMMONING:
sout << "Mass summon " << "monst-names";
break;
}
return sout.str();
}
void cItem::writeTo(std::ostream& file, std::string prefix) const {
file << prefix << "VARIETY " << variety << '\n';
file << prefix << "LEVEL " << item_level << '\n';

View File

@@ -53,6 +53,8 @@ public:
unsigned char rec_treas_class() const;
short item_weight() const;
std::string getAbilName();
cItem();
explicit cItem(long preset);
explicit cItem(eAlchemy recipe);

View File

@@ -309,10 +309,8 @@ inline bool isArmourType(eItemType type) {
}
inline bool isWeaponType(eItemType type) {
if(type == eItemType::CROSSBOW || type == eItemType::BOLTS)
return true;
int code = (int) type;
return code >= 1 && code <= 6 && code != 3;
return (code >= 1 && code <= 6 && code != 3) || (code >= 23 && code <= 25);
}
/* items[i].ability */
@@ -329,7 +327,7 @@ enum class eItemAbil {
ANTIMAGIC_WEAPON = 8,
STATUS_WEAPON = 9,
SOULSUCKER = 10,
DRAIN_MISSILES = 11,
UNUSED = 11,
WEAK_WEAPON = 12,
CAUSES_FEAR = 13,
WEAPON_CALL_SPECIAL = 14,
@@ -362,8 +360,10 @@ enum class eItemAbil {
SPEED = 55,
SLOW_WEARER = 56,
PROTECT_FROM_SPECIES = 57,
LOCKPICKS = 58,
DRAIN_MISSILES = 59,
// Usable
POISON_WEAPON = 70, //put poison on weapon
POISON_WEAPON = 70,
AFFECT_STATUS = 71,
CAST_SPELL = 72,
BLISS_DOOM = 73,
@@ -390,7 +390,6 @@ enum class eItemAbil {
SAPPHIRE = 158,
SMOKY_CRYSTAL = 159,
RESURRECTION_BALM = 160,
LOCKPICKS = 161,
};
enum class eItemAbilCat {
@@ -535,7 +534,7 @@ enum class eSpecType {
DISPLAY_PICTURE = 24,
REST = 25,
WANDERING_WILL_FIGHT = 26,
END_SCENARIO = 27,
END_SCENARIO = 27, // add "win/lose" option
SET_POINTER = 28,
SET_CAMP_FLAG = 29,
PRINT_NUMS = 30, // For debugging
@@ -666,7 +665,7 @@ enum class eSpecType {
OUT_MAKE_WANDER = 225,
UNUSED20 = 226,
OUT_PLACE_ENCOUNTER = 227,
OUT_MOVE_PARTY = 228,
OUT_MOVE_PARTY = 228, // allow change sector
};
enum class eSpecCat {

View File

@@ -56,6 +56,7 @@ const cSpell& cSpell::finish() {
}
std::string cSpell::name() const {
if(num == eSpell::NONE) return "INVALID SPELL";
return get_str("magic-names", int(num) + 1);
}
@@ -77,6 +78,13 @@ eSpell cSpell::fromNum(eSkill type, int num) {
return eSpell::NONE;
}
eSpell cSpell::fromNum(int num) {
eSpell check = eSpell(num);
if(dictionary.find(check) == dictionary.end())
return eSpell::NONE;
return check;
}
// Mage Spells
cSpell M_LIGHT = cSpell(eSpell::LIGHT).asType(eSkill::MAGE_SPELLS).asLevel(1)
.withCost(1).when(WHEN_COMBAT).when(WHEN_TOWN).when(WHEN_OUTDOORS).finish();

View File

@@ -42,6 +42,7 @@ public:
std::string name() const;
bool is_priest() const;
static eSpell fromNum(eSkill type, int num);
static eSpell fromNum(int num);
};
// Need to declare this a second time in order for it to be in scope where it's needed

View File

@@ -478,6 +478,7 @@ std::string cLedGroup::getPrevSelection(){
}
void cLedGroup::draw(){
if(!visible) return;
ledIter iter = choices.begin();
while(iter != choices.end()){
iter->second->draw();

View File

@@ -34,6 +34,13 @@ extern cSpecial null_spec_node;
extern cSpeech null_talk_node;
extern location cur_out;
extern short start_volume, start_dir;
extern const std::multiset<eItemType> equippable;
const std::set<eItemAbil> items_no_strength = {
eItemAbil::NONE, eItemAbil::HEALING_WEAPON, eItemAbil::RETURNING_MISSILE, eItemAbil::SEEKING_MISSILE, eItemAbil::DRAIN_MISSILES,
eItemAbil::LIGHTER_OBJECT, eItemAbil::HEAVIER_OBJECT, eItemAbil::LIFE_SAVING, eItemAbil::POISON_AUGMENT,
eItemAbil::QUICKFIRE,
};
static bool save_ter_info(cDialog& me, cTerrain& store_ter) {
@@ -879,6 +886,7 @@ static bool edit_monst_abil_detail(cDialog& me, std::string hit, cMonster& monst
std::map<eMonstAbil,uAbility>::iterator iter;
if(me[hit].getText() == "Add") {
int i = choose_text_res("monster-abilities", 1, 70, 0, &me, "Select an ability to add.");
if(i < 0) return true;
eMonstAbilTemplate tmpl = eMonstAbilTemplate(i);
int param = 0;
switch(tmpl) {
@@ -982,13 +990,14 @@ static bool edit_monst_abil_detail(cDialog& me, std::string hit, cMonster& monst
if(cat == eMonstAbilCat::MISSILE) first = 110, last = 117;
else if(cat == eMonstAbilCat::GENERAL) first = 120, last = 124;
else if(cat == eMonstAbilCat::SUMMON) first = 150, last = 152;
abil_dlg["pick-subtype"].attachClickHandler([&,cat](cDialog& me,std::string,eKeyMod) -> bool {
abil_dlg["pick-subtype"].attachClickHandler([&,cat,first,last](cDialog& me,std::string,eKeyMod) -> bool {
save_monst_abil_detail(me, abil, abil_params);
int i = 0;
if(cat == eMonstAbilCat::MISSILE) i = int(abil_params.missile.type);
else if(cat == eMonstAbilCat::GENERAL) i = int(abil_params.gen.type);
else if(cat == eMonstAbilCat::SUMMON) i = int(abil_params.summon.type);
i = choose_text_res("monster-abilities", first, last, i + first, &me, "Select ability subtype:");
if(i < 0) return true;
if(cat == eMonstAbilCat::MISSILE) abil_params.missile.type = eMonstMissile(i);
else if(cat == eMonstAbilCat::GENERAL) abil_params.gen.type = eMonstGen(i);
else if(cat == eMonstAbilCat::SUMMON) abil_params.summon.type = eMonstSummon(i);
@@ -1250,6 +1259,7 @@ static void put_item_info_in_dlog(cDialog& me, cItem& store_item, short which_it
me["value"].setTextToNum(store_item.value);
me["weight"].setTextToNum(store_item.weight);
me["class"].setTextToNum(store_item.special_class);
me["abilname"].setText(store_item.getAbilName());
}
static void save_item_info(cDialog& me, cItem& store_item, short which_item) {
@@ -1359,6 +1369,7 @@ static bool edit_item_type_event_filter(cDialog& me, std::string item_hit, cItem
if(i < 0) return true;
store_item.missile = i;
} else if(item_hit == "abils") {
save_item_info(me, store_item, store_which_item);
if(store_item.variety == eItemType::NO_ITEM) {
giveError("You must give the item a type (weapon, armor, etc.) before you can choose its abilities.","",&me);
return true;
@@ -1367,7 +1378,7 @@ static bool edit_item_type_event_filter(cDialog& me, std::string item_hit, cItem
giveError("Gold, Food, and Special Items cannot be given special abilities.","",&me);
return true;
}
temp_item = edit_item_abil(store_item,store_which_item);
temp_item = edit_item_abil(store_item,store_which_item,me);
if(temp_item.variety != eItemType::NO_ITEM)
store_item = temp_item;
}
@@ -1433,129 +1444,226 @@ static void put_item_abils_in_dlog(cDialog& me, cItem& store_item, short which_i
me["num"].setTextToNum(which_item);
me["name"].setText(store_item.full_name.c_str());
me["variety"].setText(get_str("item-types", (int)store_item.variety));
me["abilname"].setText(get_str("item-abilities", int(store_item.ability) + 1));
me["variety"].setText(get_str("item-types", int(store_item.variety) + 1));
if(store_item.ability == eItemAbil::NONE)
me["abilname"].setText("No ability");
else me["abilname"].setText(get_str("item-abilities", int(store_item.ability)));
dynamic_cast<cLedGroup&>(me["use-type"]).setSelected("use" + std::to_string(store_item.magic_use_type));
dynamic_cast<cLedGroup&>(me["treasure"]).setSelected("type" + std::to_string(store_item.treas_class));
me["str"].setTextToNum(store_item.abil_data[0]);
me["str1"].setTextToNum(store_item.abil_data[0]);
me["str2"].setTextToNum(store_item.abil_data[1]);
if(store_item.ability == eItemAbil::CALL_SPECIAL || store_item.ability == eItemAbil::WEAPON_CALL_SPECIAL || store_item.ability == eItemAbil::HIT_CALL_SPECIAL) {
me["str1-choose"].show();
me["str1-title"].setText("Special to call");
} else {
me["str1-choose"].hide();
if(getItemAbilCategory(store_item.ability) == eItemAbilCat::REAGENT || items_no_strength.count(store_item.ability) > 0)
me["str1-title"].setText("Unused");
else me["str1-title"].setText("Ability strength");
}
me["str2-choose1"].show();
me["str2-choose1"].setText("Choose");
me["str2-choose2"].hide();
switch(store_item.ability) {
case eItemAbil::DAMAGING_WEAPON:
case eItemAbil::EXPLODING_WEAPON:
case eItemAbil::DAMAGE_PROTECTION:
me["str2-title"].setText("Type of damage");
break;
case eItemAbil::STATUS_WEAPON:
case eItemAbil::STATUS_PROTECTION:
case eItemAbil::OCCASIONAL_STATUS:
case eItemAbil::AFFECT_STATUS:
case eItemAbil::AFFECT_PARTY_STATUS:
me["str2-title"].setText("Which status effect");
break;
case eItemAbil::SLAYER_WEAPON:
case eItemAbil::PROTECT_FROM_SPECIES:
me["str2-title"].setText("Which species");
break;
case eItemAbil::BOOST_STAT:
me["str2-title"].setText("Which statistic");
break;
case eItemAbil::CAST_SPELL:
me["str2-title"].setText("Which spell");
me["str2-choose1"].setText("Mage");
me["str2-choose2"].show();
break;
case eItemAbil::SUMMONING:
case eItemAbil::MASS_SUMMONING:
me["str2-title"].setText("Which monster");
break;
default:
me["str2-title"].setText("Unused");
me["str2-choose1"].hide();
break;
}
if((store_item.ability >= eItemAbil::BLISS_DOOM && store_item.ability <= eItemAbil::HEALTH_POISON) || store_item.ability == eItemAbil::AFFECT_STATUS || store_item.ability == eItemAbil::OCCASIONAL_STATUS) {
me["use-title"].show();
me["use-type"].show();
} else {
me["use-title"].hide();
me["use-type"].hide();
}
dynamic_cast<cLed&>(me["always-id"]).setState(store_item.ident ? led_red : led_off);
dynamic_cast<cLed&>(me["magic"]).setState(store_item.magic ? led_red : led_off);
dynamic_cast<cLed&>(me["cursed"]).setState(store_item.cursed ? led_red : led_off);
dynamic_cast<cLed&>(me["conceal"]).setState(store_item.concealed ? led_red : led_off);
dynamic_cast<cLed&>(me["no-sell"]).setState(store_item.unsellable ? led_red : led_off);
}
static bool save_item_abils(cDialog& me, cItem& store_item) {
static void save_item_abils(cDialog& me, cItem& store_item) {
store_item.magic_use_type = boost::lexical_cast<short>(dynamic_cast<cLedGroup&>(me["use-type"]).getSelected().substr(3));
store_item.treas_class = boost::lexical_cast<short>(dynamic_cast<cLedGroup&>(me["treasure"]).getSelected().substr(4));
store_item.abil_data[0] = me["str"].getTextAsNum();
store_item.abil_data[0] = me["str1"].getTextAsNum();
store_item.abil_data[1] = me["str2"].getTextAsNum();
store_item.property = store_item.enchanted = store_item.contained = false;
store_item.ident = dynamic_cast<cLed&>(me["always-id"]).getState() != led_off;
store_item.magic = dynamic_cast<cLed&>(me["magic"]).getState() != led_off;
store_item.cursed = store_item.unsellable = dynamic_cast<cLed&>(me["cursed"]).getState() != led_off;
store_item.cursed = dynamic_cast<cLed&>(me["cursed"]).getState() != led_off;
store_item.unsellable = dynamic_cast<cLed&>(me["no-sell"]).getState() != led_off;
store_item.concealed = dynamic_cast<cLed&>(me["conceal"]).getState() != led_off;
return true;
}
static bool edit_item_abil_event_filter(cDialog& me, std::string item_hit, cItem& store_item, short which_item) {
short i;
if(item_hit == "cancel") {
store_item.ability = eItemAbil::NONE;
store_item.variety = eItemType::NO_ITEM;
me.toast(false);
return true;
} else if(item_hit == "okay") {
if(save_item_abils(me, store_item)) {
me.toast(true);
return true;
save_item_abils(me, store_item);
me.toast(true);
} else if(item_hit == "str1-choose") {
save_item_abils(me, store_item);
short spec = me["str1"].getTextAsNum();
if(spec < 0 || spec > 255) {
spec = get_fresh_spec(0);
if(spec < 0) {
giveError("You can't create a new scenario special encounter because there are no more free special nodes.",
"To free a special node, set its type to No Special and set its Jump To special to -1.", &me);
return true;
}
}
if(edit_spec_enc(spec,0,&me)) {
store_item.abil_data[0] = spec;
me["str1"].setTextToNum(spec);
}
} else if(item_hit == "str2-choose1") {
save_item_abils(me, store_item);
i = store_item.abil_data[1];
switch(store_item.ability) {
case eItemAbil::DAMAGING_WEAPON:
case eItemAbil::EXPLODING_WEAPON:
case eItemAbil::DAMAGE_PROTECTION:
i = choose_damage_type(i, &me);
break;
case eItemAbil::STATUS_WEAPON:
case eItemAbil::STATUS_PROTECTION:
case eItemAbil::OCCASIONAL_STATUS:
case eItemAbil::AFFECT_STATUS:
case eItemAbil::AFFECT_PARTY_STATUS:
i = choose_status_effect(i, store_item.ability == eItemAbil::AFFECT_PARTY_STATUS, &me);
break;
case eItemAbil::SLAYER_WEAPON:
case eItemAbil::PROTECT_FROM_SPECIES:
i = choose_text(STRT_RACE, i, &me, "Which species?");
break;
case eItemAbil::BOOST_STAT:
i = choose_text(STRT_SKILL, i, &me, "Boost which skill?");
break;
case eItemAbil::CAST_SPELL:
i = choose_text_res("magic-names", 1, 73, i + 1, &me, "Which mage spell?");
if(i < 0) return true;
break;
case eItemAbil::SUMMONING:
case eItemAbil::MASS_SUMMONING:
i = choose_text(STRT_MONST, i, &me, "Summon which monster type?");
break;
default: return true;
}
store_item.abil_data[1] = i;
me["str2"].setTextToNum(i);
} else if(item_hit == "str2-choose2") {
save_item_abils(me, store_item);
i = 100 + choose_text_res("magic-names", 101, 166, store_item.abil_data[1] + 1, &me, "Which priest spell?");
if(i < 100) return true;
store_item.abil_data[1] = i;
me["str2"].setTextToNum(i);
} else if(item_hit == "clear") {
save_item_abils(me, store_item);
store_item.ability = eItemAbil::NONE;
put_item_abils_in_dlog(me, store_item, which_item);
} else if(item_hit == "weapon") {
if(!save_item_abils(me, store_item)) return true;
if(store_item.variety != eItemType::ONE_HANDED && store_item.variety != eItemType::TWO_HANDED) {
giveError("You can only give an ability of this sort to a melee weapon.","",&me);
save_item_abils(me, store_item);
if(!isWeaponType(store_item.variety)) {
giveError("You can only give an ability of this sort to a weapon.","",&me);
return true;
}
i = choose_text_res("item-abilities", 0, 14, int(store_item.ability), &me, "Choose Weapon Ability (inherent)");
if(i >= 0) store_item.ability = eItemAbil(i);
else store_item.ability = eItemAbil::NONE;
i = choose_text_res("item-abilities", 1, 14, int(store_item.ability), &me, "Choose Weapon Ability (inherent)");
if(i < 0) return true;
eItemAbil abil = eItemAbil(i + 1);
if(abil >= eItemAbil::RETURNING_MISSILE && abil <= eItemAbil::SEEKING_MISSILE) {
if(store_item.variety != eItemType::THROWN_MISSILE && store_item.variety != eItemType::ARROW &&
store_item.variety != eItemType::BOLTS && store_item.variety != eItemType::MISSILE_NO_AMMO) {
giveError("You can only give this ability to a missile.",&me);
return true;
}
}
store_item.ability = abil;
put_item_abils_in_dlog(me, store_item, which_item);
} else if(item_hit == "general") {
if(!save_item_abils(me, store_item)) return true;
if((store_item.variety == eItemType::ARROW) || (store_item.variety == eItemType::THROWN_MISSILE)|| (store_item.variety == eItemType::POTION) || (store_item.variety == eItemType::SCROLL) ||
(store_item.variety == eItemType::WAND) || (store_item.variety == eItemType::TOOL) || (store_item.variety == eItemType::WEAPON_POISON) ||
(store_item.variety == eItemType::NON_USE_OBJECT) || (store_item.variety == eItemType::BOLTS)){
giveError("You can only give an ability of this sort to an non-missile item which can be equipped (like armor, or a ring).","",&me);
save_item_abils(me, store_item);
if(equippable.count(store_item.variety) == 0 || store_item.variety == eItemType::ARROW || store_item.variety == eItemType::THROWN_MISSILE || store_item.variety == eItemType::BOLTS){
giveError("You can only give an ability of this sort to an non-missile item which can be equipped (like armor, or a ring).",&me);
return true;
}
i = choose_text_res("item-abilities", 30, 62, int(store_item.ability), &me, "Choose General Ability (inherent)");
if(i >= 0) store_item.ability = eItemAbil(i + 30);
else store_item.ability = eItemAbil::NONE;
i = choose_text_res("item-abilities", 30, 58, int(store_item.ability), &me, "Choose General Ability (inherent)");
if(i < 0) return true;
store_item.ability = eItemAbil(i + 30);
put_item_abils_in_dlog(me, store_item, which_item);
} else if(item_hit == "usable") {
if(!save_item_abils(me, store_item)) return true;
save_item_abils(me, store_item);
if((store_item.variety == eItemType::ARROW) || (store_item.variety == eItemType::THROWN_MISSILE) || (store_item.variety == eItemType::BOLTS)){
giveError("You can only give an ability of this sort to an item which isn't a missile.","",&me);
giveError("You can't give an ability of this sort to a missile.",&me);
return true;
}
i = choose_text_res("item-abilities", 70, 94, int(store_item.ability), &me, "Choose Usable Ability (Not spell)");
if(i >= 0) store_item.ability = eItemAbil(i + 70);
else store_item.ability = eItemAbil::NONE;
put_item_abils_in_dlog(me, store_item, which_item);
} else if(item_hit == "spell") {
if(!save_item_abils(me,store_item)) return true;
if((store_item.variety == eItemType::ARROW) || (store_item.variety == eItemType::THROWN_MISSILE) || (store_item.variety == eItemType::BOLTS)){
giveError("You can only give an ability of this sort to an item which isn't a missile.","",&me);
return true;
}
i = choose_text_res("item-abilities", 110, 135, int(store_item.ability), &me, "Choose Usable Ability (Spell)");
if(i >= 0) store_item.ability = eItemAbil(i + 110);
else store_item.ability = eItemAbil::NONE;
i = choose_text_res("item-abilities", 70, 84, int(store_item.ability), &me, "Choose Usable Ability");
if(i < 0) return true;
store_item.ability = eItemAbil(i + 70);
put_item_abils_in_dlog(me, store_item, which_item);
} else if(item_hit == "reagent") {
if(!save_item_abils(me, store_item)) return true;
// TODO: Some of these should also be applicable to tools, as I recall?
save_item_abils(me, store_item);
if(store_item.variety != eItemType::NON_USE_OBJECT){
giveError("You can only give an ability of this sort to an item of type Non-Use Object.","",&me);
giveError("You can only give an ability of this sort to an item of type Non-Use Object.",&me);
return true;
}
i = choose_text_res("item-abilities", 150, 161, int(store_item.ability), &me, "Choose Reagent Ability");
if(i >= 0) store_item.ability = eItemAbil(i + 150);
else store_item.ability = eItemAbil::NONE;
i = choose_text_res("item-abilities", 150, 160, int(store_item.ability), &me, "Choose Reagent Ability");
if(i < 0) return true;
store_item.ability = eItemAbil(i + 150);
put_item_abils_in_dlog(me, store_item, which_item);
} else if(item_hit == "missile") {
if(!save_item_abils(me,store_item)) return true;
if((store_item.variety == eItemType::ARROW) || (store_item.variety == eItemType::THROWN_MISSILE) || (store_item.variety == eItemType::BOLTS)){
giveError("You can only give an ability of this sort to an item which isn't a missile.","",&me);
return true;
}
i = choose_text_res("item-abilities", 170, 176, int(store_item.ability), &me, "Choose Missile Ability");
if(i >= 0) store_item.ability = eItemAbil(i + 170);
else store_item.ability = eItemAbil::NONE;
put_item_abils_in_dlog(me, store_item, which_item);
}
using namespace std::placeholders;
if(store_item.ability != eItemAbil::SUMMONING && store_item.ability != eItemAbil::MASS_SUMMONING) {
me["str"].attachFocusHandler(std::bind(check_range, _1, _2, _3, 0, 10, "Ability Strength"));
} else {
me["str"].attachFocusHandler(std::bind(check_range_msg, _1,_2,_3, 0,255, "Ability Strength","the number of the monster to summon"));
}
return true;
}
cItem edit_item_abil(cItem starting_record,short which_item) {
cItem edit_item_abil(cItem starting_record,short which_item,cDialog& parent) {
using namespace std::placeholders;
cItem store_item = starting_record;
cDialog item_dlg("edit-item-abils");
if(store_item.ability != eItemAbil::SUMMONING && store_item.ability != eItemAbil::MASS_SUMMONING) {
item_dlg["str"].attachFocusHandler(std::bind(check_range, _1, _2, _3, 0, 10, "Ability Strength"));
} else {
item_dlg["str"].attachFocusHandler(std::bind(check_range_msg,_1,_2,_3, 0,255, "Ability Strength","the number of the monster to summon"));
}
item_dlg.attachClickHandlers(std::bind(edit_item_abil_event_filter, _1, _2, std::ref(store_item), which_item), {"okay", "cancel", "weapon", "general", "usable", "missile", "reagent", "spell"});
cDialog item_dlg("edit-item-abils",&parent);
item_dlg.attachClickHandlers(std::bind(edit_item_abil_event_filter, _1, _2, std::ref(store_item), which_item), {
"okay", "cancel",
"clear", "weapon", "general", "usable", "reagent",
"str1-choose", "str2-choose1", "str2-choose2",
});
put_item_abils_in_dlog(item_dlg, store_item, which_item);

View File

@@ -6,7 +6,7 @@ short edit_ter_type(ter_num_t which_ter);
short edit_monst_type(short which_monst);
cMonster edit_monst_abil(cMonster starting_record,short which_monst,cDialog& parent);
short edit_item_type(short which_item);
cItem edit_item_abil(cItem starting_record,short parent_num);
cItem edit_item_abil(cItem starting_record,short which_item,cDialog& parent);
void edit_spec_item(short which_item);
void edit_save_rects();
void edit_horses();

View File

@@ -131,8 +131,8 @@ pic_num_t choose_graphic(short cur_choice,ePicType g_type,cDialog* parent) {
short choose_text_res(std::string res_list,short first_t,short last_t,unsigned short cur_choice,cDialog* parent,const char *title) {
location view_loc;
if((cur_choice < first_t) || (cur_choice > last_t))
cur_choice = first_t;
cur_choice -= first_t;
cur_choice = -1;
else cur_choice -= first_t;
StringRsrc strings = *ResMgr::get<StringRsrc>(res_list);
cStringChoice dlog(strings.begin() + first_t - 1, strings.begin() + last_t, title, parent);