From 7084991e5544f05b9cb6ba3872361f29f745bab2 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Sun, 18 Jan 2015 17:25:08 -0500 Subject: [PATCH] Get the edit monster abilities dialog all working and updated (except for editing individual abilities) Game changes: - Remove support for playing a sound and displaying strings when a monster is first seen, since these behaviours can easily be obtained by using the special node called in the same context. Dialog engine changes: - Support for changing the font size of LEDs - When setting the page, a stack now applies a default value if the map is missing the required data - Add utility "addPage" method to stacks - If reducing the page count means the current page is deleted, a stack now switches to the last page --- rsrc/dialogs/edit-monster-abils.xml | 100 +++++++++++++++------------- src/boe.graphutil.cpp | 15 +---- src/classes/monster.cpp | 11 +-- src/classes/monster.h | 3 +- src/dialogxml/button.cpp | 8 ++- src/dialogxml/control.cpp | 1 + src/dialogxml/dialog.cpp | 2 +- src/dialogxml/field.cpp | 2 + src/dialogxml/pict.cpp | 2 + src/dialogxml/scrollbar.cpp | 1 + src/dialogxml/stack.cpp | 8 ++- src/dialogxml/stack.hpp | 4 ++ src/doxy/mainpage.md | 2 +- src/scenedit/scen.core.cpp | 78 +++++++++++++++++++++- 14 files changed, 157 insertions(+), 80 deletions(-) diff --git a/rsrc/dialogs/edit-monster-abils.xml b/rsrc/dialogs/edit-monster-abils.xml index db29c06b..73b7edd3 100644 --- a/rsrc/dialogs/edit-monster-abils.xml +++ b/rsrc/dialogs/edit-monster-abils.xml @@ -5,31 +5,18 @@ - - - - - - - - - - Fire - Cold - Electricity - Darkness - - Resist Magic - Resist Fire - Resist Cold - Resist Poison - Immune To Magic - Immune To Fire - Immune To Cold - Immune To Poison + + + Magic: + + Fire: + + Cold: + + Poison: + + Mindless + Invulnerable Edit Monster Abilities Monster number: @@ -38,29 +25,46 @@ Enter properties for this monster type. For a detailed description of the fields, see the documentation. - Monster Poison: (0 - 8) - Monster Breath Weapon strength (0 - 40): - Breath weapon type: - Special ability: - - - Create monsters/fields: - - - - - Special treasure: - Item to drop when killed: - Chance of dropping: (0-100) - Monster resistances: - + Special abilities: + + + + + + + + + + + + Monster vocalization sound + + + + \ No newline at end of file diff --git a/src/boe.graphutil.cpp b/src/boe.graphutil.cpp index 3761785f..c21cc803 100644 --- a/src/boe.graphutil.cpp +++ b/src/boe.graphutil.cpp @@ -229,24 +229,11 @@ void draw_monsters() { } void play_see_monster_str(unsigned short m, location monst_loc) { - short str1, str2, pic, snd, spec; + short pic, spec; ePicType type; - str1 = univ.scenario.scen_monsters[m].see_str1; - str2 = univ.scenario.scen_monsters[m].see_str2; pic = univ.scenario.scen_monsters[m].picture_num; type = get_monst_pictype(m); - snd = univ.scenario.scen_monsters[m].see_sound; spec = univ.scenario.scen_monsters[m].see_spec; - // First display strings, if any - if((str1 >= 0 && str1 < 100) || (str2 >= 0 && str2 < 100)) { - short where1 = is_out() ? univ.party.outdoor_corner.x + univ.party.i_w_c.x : univ.town.num; - short where2 = is_out() ? univ.party.outdoor_corner.y + univ.party.i_w_c.y : univ.town.num; - std::string placename = is_out() ? univ.out->out_name : univ.town->town_name; - cStrDlog display_strings(str1 < 100 ? univ.scenario.spec_strs[str1] : "", str2 < 100 ? univ.scenario.spec_strs[str2] : "", "", pic, type, NULL); - display_strings.setSound(snd); - display_strings.setRecordHandler(cStringRecorder(NOTE_SCEN).string1(str1).string2(str2).from(where1,where2).at(placename)); - display_strings.show(); - } // Then run the special, if any if(spec > -1){ queue_special(eSpecCtx::SEE_MONST, 0, spec, monst_loc); diff --git a/src/classes/monster.cpp b/src/classes/monster.cpp index 36a7ce6a..e2d89916 100644 --- a/src/classes/monster.cpp +++ b/src/classes/monster.cpp @@ -132,8 +132,6 @@ void cMonster::append(legacy::monster_record_type& old){ picture_num = old.picture_num; if(picture_num == 122) picture_num = 119; see_spec = -1; - see_str1 = see_str2 = -1; - see_sound = 0; ambient_sound = 0; } @@ -371,8 +369,6 @@ void cMonster::addAbil(eMonstAbilTemplate what, int param) { cMonster::cMonster(){ magic_res = poison_res = fire_res = cold_res = 100; // TODO: Fill in - see_str1 = -1; - see_str2 = -1; see_spec = -1; } @@ -792,17 +788,14 @@ void cMonster::writeTo(std::ostream& file) const { } void cMonster::readFrom(std::istream& file) { - // On-see event is not exported, so make sure the fields are not filled with garbage data - see_sound = 0; - see_str1 = -1; - see_str2 = -1; + // On-see event is not exported, so make sure the field ise not filled with garbage data see_spec = -1; std::istringstream bin; std::string cur; getline(file, cur, '\f'); bin.str(cur); while(bin) { - int temp1, temp2, temp3; + int temp1, temp2; getline(bin, cur); std::istringstream line(cur); line >> cur; diff --git a/src/classes/monster.h b/src/classes/monster.h index 5f97f1ad..7e67f25c 100644 --- a/src/classes/monster.h +++ b/src/classes/monster.h @@ -140,8 +140,7 @@ public: unsigned char summon_type; pic_num_t default_facial_pic; pic_num_t picture_num; - str_num_t see_str1, see_str2; - snd_num_t see_sound, ambient_sound; // ambient_sound has a chance of being played every move + snd_num_t ambient_sound; // has a chance of being played every move spec_num_t see_spec; public: diff --git a/src/dialogxml/button.cpp b/src/dialogxml/button.cpp index 904d81ad..56e9611d 100644 --- a/src/dialogxml/button.cpp +++ b/src/dialogxml/button.cpp @@ -225,11 +225,13 @@ bool cLed::triggerClickHandler(cDialog& me, std::string id, eKeyMod mods){ void cLed::setFormat(eFormat prop, short val) throw(xUnsupportedProp){ if(prop == TXT_FONT) textFont = (eFont) val; + else if(prop == TXT_SIZE) textSize = val; else throw xUnsupportedProp(prop); } short cLed::getFormat(eFormat prop) throw(xUnsupportedProp){ if(prop == TXT_FONT) return textFont; + else if(prop == TXT_SIZE) return textSize; else throw xUnsupportedProp(prop); } @@ -240,8 +242,8 @@ void cLed::draw(){ if(visible){ TextStyle style; - style.pointSize = 9; - style.lineHeight = 8; + style.pointSize = textSize; + style.lineHeight = textSize - 1; from_rect = ledRects[state][depressed]; to_rect = frame; to_rect.right = to_rect.left + 14; @@ -265,6 +267,7 @@ void cLed::restore(storage_t to) { cButton::restore(to); if(to.find("led-state") != to.end()) setState(boost::any_cast(to["led-state"])); + else setState(led_off); } cLedGroup::cLedGroup(cDialog* parent) : @@ -501,4 +504,5 @@ void cLedGroup::restore(storage_t to) { cControl::restore(to); if(to.find("led-select") != to.end()) setSelected(boost::any_cast(to["led-select"])); + else setSelected(""); } diff --git a/src/dialogxml/control.cpp b/src/dialogxml/control.cpp index 595e8612..0b18acf6 100644 --- a/src/dialogxml/control.cpp +++ b/src/dialogxml/control.cpp @@ -326,4 +326,5 @@ cControl::storage_t cControl::store() { void cControl::restore(storage_t to) { if(to.find("text") != to.end()) lbl = boost::any_cast(to["text"]); + else lbl = ""; } diff --git a/src/dialogxml/dialog.cpp b/src/dialogxml/dialog.cpp index d4ba2224..b7a2d062 100644 --- a/src/dialogxml/dialog.cpp +++ b/src/dialogxml/dialog.cpp @@ -583,7 +583,7 @@ template<> pair cDialog::parse(Element& who /*LED*/){ p.second->setFormat(TXT_SIZE, 12); else if(val == "small") p.second->setFormat(TXT_SIZE, 10); - if(val == "title") + else if(val == "title") p.second->setFormat(TXT_SIZE, 18); else throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname); }else if(name == "color" || name == "colour"){ diff --git a/src/dialogxml/field.cpp b/src/dialogxml/field.cpp index 2b20d3d2..8760963b 100644 --- a/src/dialogxml/field.cpp +++ b/src/dialogxml/field.cpp @@ -493,6 +493,8 @@ void cTextField::restore(storage_t to) { cControl::restore(to); if(to.find("fld-ip") != to.end()) insertionPoint = boost::any_cast(to["fld-ip"]); + else insertionPoint = getText().length(); if(to.find("fld-sp") != to.end()) selectionPoint = boost::any_cast(to["fld-sp"]); + else selectionPoint = 0; } diff --git a/src/dialogxml/pict.cpp b/src/dialogxml/pict.cpp index c7201442..06c2c471 100644 --- a/src/dialogxml/pict.cpp +++ b/src/dialogxml/pict.cpp @@ -1128,6 +1128,8 @@ void cPict::restore(storage_t to) { cControl::restore(to); if(to.find("pic-num") != to.end()) picNum = boost::any_cast(to["pic-num"]); + else picNum = -1; if(to.find("pic-type") != to.end()) picType = boost::any_cast(to["pic-type"]); + else picNum = PIC_DLOG; } diff --git a/src/dialogxml/scrollbar.cpp b/src/dialogxml/scrollbar.cpp index 2e1a7869..309dbef7 100644 --- a/src/dialogxml/scrollbar.cpp +++ b/src/dialogxml/scrollbar.cpp @@ -199,4 +199,5 @@ void cScrollbar::restore(storage_t to) { cControl::restore(to); if(to.find("scroll-pos") != to.end()) pos = boost::any_cast(to["scroll-pos"]); + else pos = 0; } diff --git a/src/dialogxml/stack.cpp b/src/dialogxml/stack.cpp index 83aaef65..861be464 100644 --- a/src/dialogxml/stack.cpp +++ b/src/dialogxml/stack.cpp @@ -96,10 +96,16 @@ size_t cStack::getPage() { } void cStack::setPageCount(size_t n) { + if(curPage >= n && n > 0) + setPage(nPages - 1); nPages = n; storage.resize(nPages); } +void cStack::addPage() { + setPageCount(getPageCount() + 1); +} + size_t cStack::getPageCount() { return nPages; } @@ -142,5 +148,5 @@ void cStack::fillTabOrder(std::vector& specificTabs, std::vector& reve } } -cStack::cStack(cDialog& parent) : cControl(CTRL_STACK, parent) {} +cStack::cStack(cDialog& parent) : cControl(CTRL_STACK, parent), curPage(0), nPages(0) {} diff --git a/src/dialogxml/stack.hpp b/src/dialogxml/stack.hpp index fb264fa9..c1972ef8 100644 --- a/src/dialogxml/stack.hpp +++ b/src/dialogxml/stack.hpp @@ -63,7 +63,11 @@ public: /// Set the number of pages in the stack. /// @param n The new number of pages /// @note If you reduce the number of pages, some data will be destroyed. + /// @note If the current page is deleted by this function, the last page will be shown, if there are any left. void setPageCount(size_t n); + /// Add a new page to the end of the stack. + /// This is equivalent to calling setPageCount(getPageCount() + 1). + void addPage(); // Get the number of pages in the stack. /// @return The number of pages size_t getPageCount(); diff --git a/src/doxy/mainpage.md b/src/doxy/mainpage.md index a5c06e27..90fd2f14 100644 --- a/src/doxy/mainpage.md +++ b/src/doxy/mainpage.md @@ -127,7 +127,7 @@ The `` tag accepts the following attributes: Attributes** above. * `state` - Specifies the starting state of the LED. Can be one of `red`, `green`, or `off`; defaults to `off`. -* `font`, `size`, `color`, `colour` - See **Common Attributes** above. +* `font`, `size`, `color`, `colour` - See **Common Attributes** above. Note that, for an LED, omitting the size attribute gives a different result than any of the possible values. The `` tag ----------------- diff --git a/src/scenedit/scen.core.cpp b/src/scenedit/scen.core.cpp index f140c8ef..ea40d1ed 100644 --- a/src/scenedit/scen.core.cpp +++ b/src/scenedit/scen.core.cpp @@ -19,6 +19,7 @@ #include "fileio.hpp" #include "field.hpp" #include "restypes.hpp" +#include "stack.hpp" extern short cen_x, cen_y,cur_town; extern bool mouse_button_held; @@ -600,8 +601,46 @@ static void put_monst_abils_in_dlog(cDialog& me, cMonster& store_monst, short wh me["loot-item"].setTextToNum(store_monst.corpse_item); me["loot-chance"].setTextToNum(store_monst.corpse_item_chance); + me["magic-res"].setTextToNum(store_monst.magic_res); + me["fire-res"].setTextToNum(store_monst.fire_res); + me["cold-res"].setTextToNum(store_monst.cold_res); + me["poison-res"].setTextToNum(store_monst.poison_res); + me["onsee"].setTextToNum(store_monst.see_spec); + me["snd"].setTextToNum(store_monst.ambient_sound); + + if(store_monst.mindless) + dynamic_cast(me["mindless"]).setState(led_red); + if(store_monst.invuln) + dynamic_cast(me["invuln"]).setState(led_red); + if(store_monst.invisible) + dynamic_cast(me["invis"]).setState(led_red); + if(store_monst.guard) + dynamic_cast(me["guard"]).setState(led_red); dynamic_cast(me["summon"]).setSelected("s" + boost::lexical_cast(store_monst.summon_type)); + + cStack& abils = dynamic_cast(me["abils"]); + abils.setPageCount(0); // This clears out any data still in the stack + abils.setPageCount(1); + int i = 0; + for(auto& abil : store_monst.abil) { + if(!abil.second.active) continue; + std::string id = std::to_string((i % 4) + 1); + if(i % 4 == 0) abils.setPage(i / 4); + else if(i % 4 == 3) abils.addPage(); + me["abil-name" + id].setText(abil.second.to_string(abil.first)); + me["abil-edit" + id].setText("Edit"); + i++; + } + abils.setPage(0); + + if(abils.getPageCount() <= 1) { + me["abil-up"].hide(); + me["abil-down"].hide(); + } else { + me["abil-up"].show(); + me["abil-down"].show(); + } } static bool save_monst_abils(cDialog& me, cMonster& store_monst) { @@ -609,10 +648,21 @@ static bool save_monst_abils(cDialog& me, cMonster& store_monst) { store_monst.corpse_item = me["loot-item"].getTextAsNum(); store_monst.corpse_item_chance = me["loot-chance"].getTextAsNum(); + store_monst.magic_res = me["magic-res"].getTextAsNum(); + store_monst.fire_res = me["fire-res"].getTextAsNum(); + store_monst.cold_res = me["cold-res"].getTextAsNum(); + store_monst.poison_res = me["poison-res"].getTextAsNum(); + store_monst.see_spec = me["onsee"].getTextAsNum(); + store_monst.ambient_sound = me["snd"].getTextAsNum(); + + store_monst.mindless = dynamic_cast(me["mindless"]).getState() != led_off; + store_monst.invuln = dynamic_cast(me["invuln"]).getState() != led_off; + store_monst.invisible = dynamic_cast(me["invis"]).getState() != led_off; + store_monst.guard = dynamic_cast(me["guard"]).getState() != led_off; return true; } -static bool edit_monst_abil_event_filter(cDialog& me,std::string item_hit,cMonster& store_monst,short which_monst) { +static bool edit_monst_abil_event_filter(cDialog& me,std::string item_hit,cMonster& store_monst) { using namespace std::placeholders; if(item_hit == "cancel") { @@ -621,6 +671,30 @@ static bool edit_monst_abil_event_filter(cDialog& me,std::string item_hit,cMonst } else if(item_hit == "okay") { if(save_monst_abils(me, store_monst)) me.toast(true); + } else if(item_hit == "abil-up") { + cStack& abils = dynamic_cast(me["abils"]); + if(abils.getPage() == 0) abils.setPage(abils.getPageCount() - 1); + else abils.setPage(abils.getPage() - 1); + } else if(item_hit == "abil-down") { + cStack& abils = dynamic_cast(me["abils"]); + if(abils.getPage() >= abils.getPageCount() - 1) abils.setPage(0); + else abils.setPage(abils.getPage() + 1); + } else if(item_hit == "edit-see") { + short spec = me["onsee"].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)) + me["onsee"].setTextToNum(spec); + } else if(item_hit == "pick-snd") { + int i = me["snd"].getTextAsNum(); + i = choose_text(STRT_SND, i, &me, "Select monster vocalization sound:"); + me["snd"].setTextToNum(i); } return true; } @@ -632,7 +706,7 @@ cMonster edit_monst_abil(cMonster starting_record,short which_monst) { cDialog monst_dlg("edit-monster-abils"); monst_dlg["loot-item"].attachFocusHandler(std::bind(check_range_msg, _1, _2, _3, -1, 399, "Item To Drop", "-1 for no item")); monst_dlg["loot-chance"].attachFocusHandler(std::bind(check_range_msg, _1, _2, _3, -1, 100, "Dropping Chance", "-1 for no item")); - monst_dlg.attachClickHandlers(std::bind(edit_monst_abil_event_filter, _1, _2, std::ref(store_monst),which_monst), {"okay", "cancel", "abils", "radiate"}); + monst_dlg.attachClickHandlers(std::bind(edit_monst_abil_event_filter, _1, _2, std::ref(store_monst)), {"okay", "cancel", "abil-up", "abil-down", "edit-see", "pick-snd"}); put_monst_abils_in_dlog(monst_dlg, store_monst, which_monst);