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

@@ -2,15 +2,12 @@
<?xml-stylesheet href="dialog.xsl" type="text/xsl"?>
<!--<!DOCTYPE dialog SYSTEM "dialog.dtd">-->
<dialog skin='light' defbtn='okay' debug='true'>
<field name='str' top='88' left='183' width='77' height='16'/>
<button name='okay' type='regular' top='266' left='471'>OK</button>
<button name='cancel' type='regular' top='266' left='405' def-key='esc'>Cancel</button>
<!--
NOTE: All these LEDs have been shifted 100 pixels left to account for the labels swapping sides
-->
<button name='okay' type='regular' top='281' left='471'>OK</button>
<button name='cancel' type='regular' top='281' left='405' def-key='esc'>Cancel</button>
<text name='use-title' top='140' left='8' width='135' height='13'>Item use properties</text>
<group name='use-type'>
<led name='use0' state='off' top='143' left='164' width='100'>Help using PC</led>
<led name='use1' state='off' top='158' left='164' width='100'>Harm using PC</led>
<led name='use0' state='off' top='143' left='164' width='100'>Help single PC</led>
<led name='use1' state='off' top='158' left='164' width='100'>Harm single PC</led>
<led name='use2' state='off' top='173' left='164' width='100'>Help whole party</led>
<led name='use3' state='off' top='188' left='164' width='100'>Harm whole party</led>
</group>
@@ -18,17 +15,20 @@
<led name='magic' state='off' top='159' left='415' width='100'>Magical</led>
<led name='cursed' state='off' top='174' left='415' width='100'>Cursed</led>
<led name='conceal' state='off' top='189' left='415' width='100'>Conceal ability</led>
<led name='no-sell' state='off' top='204' left='415' width='100'>Shops won't buy</led>
<pict type='dlog' num='16' top='8' left='11'/>
<text size='large' top='6' left='50' width='158' height='16'>Edit Item Abilities</text>
<text top='8' left='222' width='111' height='14'>Item number:</text>
<text name='num' top='8' left='340' width='37' height='14'/>
<button name='weapon' type='large' top='58' left='333'>Weapon Abil.</button>
<text size='large' top='63' left='8' width='142' height='13'>Item special ability:</text>
<text name='abilname' framed='true' top='63' left='161' width='163' height='13'/>
<text top='17' left='486' width='45' height='14'/>
<text top='84' left='8' width='168' height='27'>Ability strength: (Usually 0-10, see instructions)</text>
<text top='140' left='8' width='135' height='13'>Item use properties</text>
<text top='156' left='21' width='123' height='39'>Only used for item abilities which are used (like healing).</text>
<text name='abilname' framed='true' top='63' left='161' width='250' height='13'/>
<text name='str1-title' framed='true' top='84' left='8' width='185' height='16'/>
<field name='str1' top='83' left='200' width='77' height='16'/>
<button name='str1-choose' type='large' top='80' left='290'>Create/Edit</button>
<text name='str2-title' framed='true' top='110' left='8' width='185' height='16'/>
<field name='str2' top='109' left='200' width='77' height='16'/>
<button name='str2-choose1' type='regular' top='107' left='290'>Choose</button>
<button name='str2-choose2' type='regular' top='107' left='358'>Priest</button>
<text top='140' left='292' width='121' height='13'>Other properties:</text>
<text top='209' left='10' width='155' height='42'>Item treasure class: (0 is lowest level of treasure, 4 is highest)</text>
<!--
@@ -39,15 +39,16 @@
<led name='type1' state='off' top='228' left='208' width='140'>Type 1: Lousy, 1 - 20 gp</led>
<led name='type2' state='off' top='243' left='208' width='140'>Type 2: So-so, 20-200 gp</led>
<led name='type3' state='off' top='258' left='208' width='140'>Type 2: Good, 200+ gp</led>
<led name='type4' state='off' top='273' left='208' width='140'>Type 4: Greate, 2500+ gp</led>
<led name='type4' state='off' top='273' left='208' width='140'>Type 4: Great, 2500+ gp</led>
<led name='type5' state='off' top='288' left='208' width='140'>Type 5: Unique/Rare, Not left</led>
</group>
<text top='25' left='50' width='145' height='14'>Current item name:</text>
<text name='name' top='25' left='198' width='196' height='14'/>
<text top='41' left='50' width='145' height='14'>Current item variety:</text>
<text name='variety' top='41' left='198' width='196' height='14'/>
<button name='general' type='large' top='57' left='441'>General Abil.</button>
<button name='usable' type='large' top='83' left='333'>NonSpell Use</button>
<button name='missile' type='large' top='107' left='441'>Missiles</button>
<button name='reagent' type='large' top='108' left='333'>Reagents</button>
<button name='spell' type='large' top='82' left='441'>Spell Usable</button>
<button name='clear' type='large' top='6' left='441'>Clear Abil.</button>
<button name='weapon' type='large' top='32' left='441'>Weapon Abil.</button>
<button name='general' type='large' top='58' left='441'>General Abil.</button>
<button name='usable' type='large' top='84' left='441'>Usable Abil.</button>
<button name='reagent' type='large' top='110' left='441'>Reagents</button>
</dialog>

View File

@@ -5,87 +5,89 @@
<!--
TODO: Assign numeric types (type = 'int' or 'uint') to fields as appropriate
-->
<field name='full' top='30' left='163' width='126' height='16'/>
<field name="short" top='30' left='458' width='125' height='16'/>
<field name='picnum' top='62' left='140' width='52' height='16'/>
<field name='level' top='199' left='161' width='52' height='16'/>
<field name='awkward' top='223' left='161' width='52' height='16'/>
<field name='bonus' top='247' left='161' width='52' height='16'/>
<field name='prot' top='271' left='161' width='52' height='16'/>
<field name='charges' top='295' left='161' width='52' height='16'/>
<field name='flag' top='199' left='366' width='52' height='16'/>
<field name='value' top='223' left='366' width='52' height='16'/>
<field name='weight' top='247' left='366' width='52' height='16'/>
<field name='class' top='271' left='366' width='52' height='16'/>
<button name='okay' type='regular' top='337' left='509'>OK</button>
<button name='cancel' type='regular' top='337' left='434' def-key='esc'>Cancel</button>
<button name='prev' type='left' top='337' left='13'/>
<button name='next' type='right' top='337' left='76'/>
<field name='full' top='30' left='163' width='226' height='16'/>
<field name="short" top='54' left='163' width='125' height='16'/>
<field name='picnum' top='82' left='140' width='52' height='16'/>
<field name='level' top='219' left='161' width='52' height='16'/>
<field name='awkward' top='243' left='161' width='52' height='16'/>
<field name='bonus' top='267' left='161' width='52' height='16'/>
<field name='prot' top='291' left='161' width='52' height='16'/>
<field name='charges' top='315' left='161' width='52' height='16'/>
<field name='flag' top='219' left='366' width='52' height='16'/>
<field name='value' top='243' left='366' width='52' height='16'/>
<field name='weight' top='267' left='366' width='52' height='16'/>
<field name='class' top='291' left='366' width='52' height='16'/>
<button name='okay' type='regular' top='357' left='509'>OK</button>
<button name='cancel' type='regular' top='357' left='434' def-key='esc'>Cancel</button>
<button name='prev' type='left' top='357' left='13'/>
<button name='next' type='right' top='357' left='76'/>
<!--
NOTE: All these LEDs have been shifted 100 pixels left to account for the labels swapping sides
-->
<group name='variety'>
<led name='none' state='off' top='89' left='106' width='90'>No Item</led>
<led name='weap1' state='off' top='104' left='106' width='90'>1-Hand weapon</led>
<led name='weap2' state='off' top='119' left='106' width='90'>2-Hand weapon</led>
<led name='gold' state='off' top='134' left='106' width='90'>Gold</led>
<led name='bow' state='off' top='149' left='106' width='90'>Bow</led>
<led name='arrow' state='off' top='164' left='106' width='90'>Arrows</led>
<led name='thrown' state='off' top='179' left='106' width='90'>Thrown missile</led>
<led name='potion' state='off' top='89' left='218' width='90'>Potion/Magic Item</led>
<led name='scroll' state='off' top='104' left='218' width='90'>Scroll/Magic Item</led>
<led name='wand' state='off' top='119' left='218' width='90'>Wand</led>
<led name='tool' state='off' top='134' left='218' width='90'>Tool</led>
<led name='food' state='off' top='149' left='218' width='90'>Food</led>
<led name='shield' state='off' top='164' left='218' width='90'>Shield</led>
<led name='armor' state='off' top='179' left='218' width='90'>Armor</led>
<led name='helm' state='off' top='89' left='336' width='90'>Helm</led>
<led name='gloves' state='off' top='104' left='336' width='90'>Gloves</led>
<led name='none' state='off' top='109' left='106' width='90'>No Item</led>
<led name='weap1' state='off' top='124' left='106' width='90'>1-Hand weapon</led>
<led name='weap2' state='off' top='139' left='106' width='90'>2-Hand weapon</led>
<led name='gold' state='off' top='154' left='106' width='90'>Gold</led>
<led name='bow' state='off' top='169' left='106' width='90'>Bow</led>
<led name='arrow' state='off' top='184' left='106' width='90'>Arrows</led>
<led name='thrown' state='off' top='199' left='106' width='90'>Thrown missile</led>
<led name='potion' state='off' top='109' left='218' width='90'>Potion/Magic Item</led>
<led name='scroll' state='off' top='124' left='218' width='90'>Scroll/Magic Item</led>
<led name='wand' state='off' top='139' left='218' width='90'>Wand</led>
<led name='tool' state='off' top='154' left='218' width='90'>Tool</led>
<led name='food' state='off' top='169' left='218' width='90'>Food</led>
<led name='shield' state='off' top='184' left='218' width='90'>Shield</led>
<led name='armor' state='off' top='199' left='218' width='90'>Armor</led>
<led name='helm' state='off' top='109' left='336' width='90'>Helm</led>
<led name='gloves' state='off' top='124' left='336' width='90'>Gloves</led>
<!--
TODO: Why are there two shields?
-->
<led name='shield2' state='off' top='119' left='336' width='90'>Shield 2</led>
<led name='boots' state='off' top='134' left='336' width='90'>Boots</led>
<led name='ring' state='off' top='149' left='336' width='90'>Ring</led>
<led name='necklace' state='off' top='164' left='336' width='90'>Necklace</led>
<led name='poison' state='off' top='179' left='336' width='90'>Weapon Poison</led>
<led name='nonuse' state='off' top='89' left='448' width='90'>Non-Use Object</led>
<led name='pants' state='off' top='104' left='448' width='90'>Pants</led>
<led name='xbow' state='off' top='119' left='448' width='90'>Crossbow</led>
<led name='bolt' state='off' top='134' left='448' width='90'>Bolts</led>
<led name='missile' state='off' top='149' left='448' width='90'>Missile (no ammo)</led>
<led name='special' state='off' top='164' left='448' width='90'>Special Item</led>
<led name='unused2' state='off' top='179' left='448' width='80'>Unused</led>
<led name='shield2' state='off' top='139' left='336' width='90'>Shield 2</led>
<led name='boots' state='off' top='154' left='336' width='90'>Boots</led>
<led name='ring' state='off' top='169' left='336' width='90'>Ring</led>
<led name='necklace' state='off' top='184' left='336' width='90'>Necklace</led>
<led name='poison' state='off' top='199' left='336' width='90'>Weapon Poison</led>
<led name='nonuse' state='off' top='109' left='448' width='90'>Non-Use Object</led>
<led name='pants' state='off' top='124' left='448' width='90'>Pants</led>
<led name='xbow' state='off' top='139' left='448' width='90'>Crossbow</led>
<led name='bolt' state='off' top='154' left='448' width='90'>Bolts</led>
<led name='missile' state='off' top='169' left='448' width='90'>Missile (no ammo)</led>
<led name='special' state='off' top='184' left='448' width='90'>Special Item</led>
<led name='unused2' state='off' top='199' left='448' width='80'>Unused</led>
</group>
<pict name="pic" type='dlog' num='16' top='8' left='11'/>
<text size='large' top='6' left='50' width='158' height='16'>Edit an Item Type</text>
<text top='8' left='222' width='111' height='14'>Item number:</text>
<text name='num' top='8' left='340' width='37' height='14'/>
<text top='31' left='50' width='107' height='14'>Item Full Name:</text>
<text top='31' left='298' width='155' height='14'>Item Unidentified Name:</text>
<text top='63' left='8' width='120' height='14'>Item picture:</text>
<button name="choosepic" type='large' top='58' left='201'>Select Icon</button>
<text size='large' top='87' left='8' width='86' height='16'>Item type:</text>
<text top='200' left='8' width='148' height='14'>Item level: (0 - 50)</text>
<text top='224' left='8' width='148' height='14'>Awkwardness: (0-20)</text>
<text top='248' left='8' width='148' height='14'>Bonus: (0-10)</text>
<text top='272' left='8' width='148' height='14'>Protection: (-10 - 20)</text>
<text top='296' left='8' width='148' height='14'>Charges: (0-100)</text>
<text top='200' left='220' width='137' height='13'>Type flag: (0-1000)</text>
<text top='224' left='220' width='141' height='13'>Value: (0-10000)</text>
<text top='248' left='220' width='141' height='13'>Weight: (0-250)</text>
<text top='272' left='220' width='141' height='13'>Special class: (0-100)</text>
<text name='missile-title' top='200' left='440' width='140' height='16'>Missile type:</text>
<field name='missile' top='223' left='463' width='50' height='16'/>
<pict name='missile-pic' type='missile' num='3' top='223' left='440'/>
<button name='choosemiss' type='regular' top='220' left='521'>Choose</button>
<text name='skill-title' top='250' left='440' width='140' height='16'>Weapon key skill:</text>
<field name='weap-type' top='271' left='440' width='73' height='16'/>
<button name='choosetp' type='regular' top='268' left='521'>Choose</button>
<text top='293' left='221' width='363' height='40'>
<text top='55' left='2' width='155' height='14'>Item Unidentified Name:</text>
<text top='56' left='298' width='80' height='14'>Item Ability:</text>
<text name='abilname' framed='true' top='55' left='387' width='185' height='14'/>
<text top='83' left='8' width='120' height='14'>Item picture:</text>
<button name="choosepic" type='large' top='78' left='201'>Select Icon</button>
<text size='large' top='97' left='8' width='96' height='16'>Item type:</text>
<text top='220' left='8' width='148' height='14'>Item level: (0 - 50)</text>
<text top='244' left='8' width='148' height='14'>Awkwardness: (0-20)</text>
<text top='268' left='8' width='148' height='14'>Bonus: (0-10)</text>
<text top='292' left='8' width='148' height='14'>Protection: (-10 - 20)</text>
<text top='316' left='8' width='148' height='14'>Charges: (0-100)</text>
<text top='220' left='220' width='137' height='13'>Type flag: (0-1000)</text>
<text top='244' left='220' width='141' height='13'>Value: (0-10000)</text>
<text top='268' left='220' width='141' height='13'>Weight: (0-250)</text>
<text top='292' left='220' width='141' height='13'>Special class: (0-100)</text>
<text name='missile-title' top='220' left='440' width='140' height='16'>Missile type:</text>
<field name='missile' top='243' left='463' width='50' height='16'/>
<pict name='missile-pic' type='missile' num='3' top='243' left='440'/>
<button name='choosemiss' type='regular' top='240' left='521'>Choose</button>
<text name='skill-title' top='270' left='440' width='140' height='16'>Weapon key skill:</text>
<field name='weap-type' top='291' left='440' width='73' height='16'/>
<button name='choosetp' type='regular' top='288' left='521'>Choose</button>
<text top='313' left='221' width='363' height='40'>
Enter properties for this item type.
For a detailed description of the fields, see the documentation.
Click Edit Abilities to edit item abilities.
</text>
<button name="abils" type='large' top='337' left='155'>Abilities</button>
<button name="abils" type='large' top='357' left='155'>Abilities</button>
</dialog>

View File

@@ -1,18 +1,17 @@
No ability
Flaming Weapon
Demon Slayer
Undead Slayer
Lizard Slayer
Giant Slayer
Mage Slayer
Priest Slayer
Bug Slayer
Acidic Weapon
Soulsucker
Drain Missiles
Weak Weapon
Causes Fear
Poisoned Weapon
Bonus damage of type
Bonus damage against race
Heal target
Explodes
Returning missile
Farflight missile
Seeking missile
Drain magic from target
Afflict status on target
Drain life from target
Unused
Weak weapon
Cause fear
Call special when attacking
@@ -28,71 +27,36 @@ Poisoned Weapon
Protection
Full Protection
Fire Protection
Cold Protection
Poison Protection
Magic Protection
Acid Protection
Skill
Strength
Dexterity
Intelligence
Accuracy
Thieving
Giant Strength
Lighter Object
Heavier Object
Occasional Bless
Occasional Haste
Life Saving
Prot. From Petrify
Protection from damage type
Full protection
Protection from melee damage
Evasion
Martyr's shield
Awkward weapon
Protection from status effect
Boost attack skill
Boost statistic
Boost combat statistics
Boost magic statistics
Boost missile accuracy
Boost thieving skills
Giant strength
Lighter object
Heavier object
Occasional status effect
Call special when attacked
Life saving
Protect from petrification
Regenerate
Poison Augment
Disease Party
Will
Free Action
Speed
Slow Wearer
Protection from Undead
Protection from Demons
Prot. from Humanoids
Prot. from Reptiles
Prot. from Giants
Prot. from Disease
Poison Weapon
Curse/Bless User
Cure/Cause Poison
Speed/Slow User
Add/Lose Invulnerability
Add/Lose Magic Res.
Add/Lose Web
Cause/Cure Disease
Add/Lose Sanctuary
Cure/Cause Dumbfound
Add/Lose Martyr's Shield
Cure/Cause Sleep
Cure/Cause Paralysis
Cure/Cause Acid
Bliss
Add/Lose Experience
Add/Lose Skill Pts.
Add/Lose Health
Add/Lose Spell Points
Doom
Light
Stealth
Firewalk
Flying
Major Healing
Augment weapon poison
Radiance
Boost willpower
Free action
Boost speed
Slow wearer
Protect from race
Lockpicks
Drain missiles
@@ -103,37 +67,72 @@ Major Healing
Flame
Fireball
Firestorm
Kill
Ice Bolt
Slow
Shockwave
Dispel Undead
Dispel Spirit
Weapon poison
Affect status effect
Cast spell
Bliss/Doom
Affect experience
Affect skill points
Affect health
Affect spell points
Affect light level
Affect party status
Affect health and poison
Call special when used
Summoning
Mass Summoning
Acid Spray
Stinking Cloud
Sleep Field
Venom
Shockstorm
Paralysis
Web Spell
Strengthen Target
Mass summoning
Quickfire
Mass Charm
Magic Map
Dispel Barrier
Make Ice Wall
Charm Spell
Antimagic Cloud
@@ -151,144 +150,14 @@ Antimagic Cloud
Holly/Toadstool
Comfrey Root
Glowing Nettle
Crypt Shroom/Wormgr.
Crypt Shroom/Wormgrass
Asptongue Mold
Ember Flowers
Graymold
Mandrake
Sapphire
Smoky Crystal
Ressurection Balm
Lockpicks
Returning
Lightning
Exploding
Acid
Slay Undead
Slay Demon
Heal Target
Resurrection Balm

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);