From 967438ececa4d3252b5c0ec4d8c93b891484dbde Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Sun, 18 Jan 2015 12:32:47 -0500 Subject: [PATCH] Add dialog to the scenario editor to let it know what type of graphics are in the custom sheets - If you do this, it adds the graphics to all relevant select graphic dialogs, at the end, allowing you to choose custom graphics without having to remember the number schemes --- rsrc/boes/scenario.xml | 7 + rsrc/boes/scenario.xsd | 19 +- rsrc/dialogs/graphic-types.xml | 232 ++++++++++++++++++++++++ src/BoE.vsproj/ScenEdit/Scen Editor.rc | 1 + src/BoE.vsproj/ScenEdit/resource.h | 3 +- src/classes/scenario.h | 1 + src/dialogxml/pict.cpp | 11 +- src/dialogxml/pict.hpp | 4 +- src/scenedit/scen.core.cpp | 237 +++++++++++++++++++++---- src/scenedit/scen.core.h | 1 + src/scenedit/scen.fileio.cpp | 11 ++ src/scenedit/scen.keydlgs.cpp | 122 ++++++------- src/scenedit/scen.main.cpp | 4 + src/scenedit/scen.menu.xib | 17 +- src/scenedit/scen.menus.h | 1 + src/scenedit/scen.menus.mac.mm | 2 +- src/scenedit/scen.menus.win.cpp | 2 +- src/tools/graphtool.cpp | 23 +-- src/tools/graphtool.hpp | 3 +- 19 files changed, 563 insertions(+), 138 deletions(-) create mode 100644 rsrc/dialogs/graphic-types.xml diff --git a/rsrc/boes/scenario.xml b/rsrc/boes/scenario.xml index b78e9277..5cc001fc 100644 --- a/rsrc/boes/scenario.xml +++ b/rsrc/boes/scenario.xml @@ -138,5 +138,12 @@ 0 + + 7 + + + + diff --git a/rsrc/boes/scenario.xsd b/rsrc/boes/scenario.xsd index a2ed6b23..1ce80a96 100644 --- a/rsrc/boes/scenario.xsd +++ b/rsrc/boes/scenario.xsd @@ -158,6 +158,21 @@ + + + + + + + + + + + + + + + @@ -196,14 +211,14 @@ - + - + diff --git a/rsrc/dialogs/graphic-types.xml b/rsrc/dialogs/graphic-types.xml new file mode 100644 index 00000000..ab9d4666 --- /dev/null +++ b/rsrc/dialogs/graphic-types.xml @@ -0,0 +1,232 @@ + + + + + + Classify Custom Graphics: + First Graphic: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Terrain (non-animated) + Terrain (animated) + Terrain (6 map icons) + Monster (1x1 small) + Monster (2x1 wide) + Monster (1x2 tall) + Monster (2x2 large) + Dialog Icon (36x36 split) + Large Dialog Icon (72x72) + Talk Portrait (32x32 split) + Item + Boom (currently unused) + Missile + Part of another graphic + + You can use this dialog to let the scenario editor know how to interpret the contents of your + custom graphics sheets. Above you see a single line of one of your sheets. For each slot, + you can specify what type of graphic it is intended to represent; this information will be + used by the editor to offer that graphic in relevant contexts (for example, marking it as an + item graphic will cause the editor to include it in the list of item graphics to select). + This is solely for use by the editor and does not prevent you from using a graphic in more than + one way (for example, both as an item and as a monster); in that case, you would simply have + to enter the number manually. For graphics that take up more than one slot, mark only the + first slot as the required type; subsequent slots should instead be marked as "part of another graphic". + + + + \ No newline at end of file diff --git a/src/BoE.vsproj/ScenEdit/Scen Editor.rc b/src/BoE.vsproj/ScenEdit/Scen Editor.rc index 6fb7c667..e35b6e57 100644 --- a/src/BoE.vsproj/ScenEdit/Scen Editor.rc +++ b/src/BoE.vsproj/ScenEdit/Scen Editor.rc @@ -90,6 +90,7 @@ BEGIN MENUITEM "&Scenario Details", IDM_SCEN_DETAILS MENUITEM "Scenario Intr&o Text", IDM_SCEN_INTRO MENUITEM "Set Starting &Location", IDM_SCEN_START + MENUITEM "Classify Custom &Graphics" IDM_SCEN_CUSTOM_PICS MENUITEM SEPARATOR MENUITEM "Advanced:", IDM_SCEN_NEW_TOWN, GRAYED MENUITEM " Edit Special &Nodes", IDM_SCEN_ADV_SPECIALS diff --git a/src/BoE.vsproj/ScenEdit/resource.h b/src/BoE.vsproj/ScenEdit/resource.h index 48dc424e..f3451a34 100644 --- a/src/BoE.vsproj/ScenEdit/resource.h +++ b/src/BoE.vsproj/ScenEdit/resource.h @@ -66,6 +66,7 @@ #define IDM_EDIT_PASTE 160 #define IDM_EDIT_DELETE 161 #define IDM_EDIT_SELECT 162 +#define IDM_SCEN_CUSTOM_PICS 163 // Next default values for new objects // @@ -74,6 +75,6 @@ #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40014 #define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 163 +#define _APS_NEXT_SYMED_VALUE 164 #endif #endif diff --git a/src/classes/scenario.h b/src/classes/scenario.h index 34b464f4..065af689 100644 --- a/src/classes/scenario.h +++ b/src/classes/scenario.h @@ -58,6 +58,7 @@ public: short store_item_towns[3]; cSpecItem special_items[50]; short rating,uses_custom_graphics; + std::vector custom_graphics; std::array scen_monsters; cVehicle boats[30]; cVehicle horses[30]; diff --git a/src/dialogxml/pict.cpp b/src/dialogxml/pict.cpp index da5d87c0..c7201442 100644 --- a/src/dialogxml/pict.cpp +++ b/src/dialogxml/pict.cpp @@ -120,7 +120,7 @@ void cPict::setPict(pic_num_t num, ePicType type){ picType += PIC_PARTY; } else { if(picType != PIC_CUSTOM_TER_MAP) - picNum -= 1000; + picNum %= 1000; picType += PIC_CUSTOM; } } @@ -584,7 +584,6 @@ void cPict::draw(){ } void cPict::drawPresetTer(short num, rectangle to_rect){ - std::cout << "Getting terrain icon from sheet " << num / 50 << ".\n"; std::shared_ptr from_gw = getSheet(SHEET_TER, num / 50); num = num % 50; rectangle from_rect = calc_rect(num % 10, num / 10); @@ -596,7 +595,6 @@ void cPict::drawPresetTer(short num, rectangle to_rect){ void cPict::drawPresetTerAnim(short num, rectangle to_rect){ rectangle from_rect = calc_rect(4 * (num / 5) + animFrame % 4, num % 5); std::shared_ptr from_gw = getSheet(SHEET_TER_ANIM); - std::cout << "Getting animated terrain graphic " << num << " from sheet 20\n"; if(to_rect.right - to_rect.left > 28) { to_rect.inset(4,0); to_rect.right = to_rect.left + 28; @@ -832,7 +830,6 @@ void cPict::drawStatusIcon(short num, rectangle to_rect){ } void cPict::drawCustomTer(short num, rectangle to_rect){ - std::cout << "Drawing graphic " << num << " as a custom terrain pic.\n"; to_rect.right = to_rect.left + 28; to_rect.bottom = to_rect.top + 36; rectangle from_rect; @@ -842,7 +839,6 @@ void cPict::drawCustomTer(short num, rectangle to_rect){ } void cPict::drawCustomTerAnim(short num, rectangle to_rect){ - std::cout << "Drawing graphic " << num << " as a custom animated terrain pic.\n"; to_rect.right = to_rect.left + 28; to_rect.bottom = to_rect.top + 36; num += animFrame % 4; @@ -855,7 +851,6 @@ void cPict::drawCustomTerAnim(short num, rectangle to_rect){ void cPict::drawCustomMonstSm(short num, rectangle to_rect){ static const short adj[4] = {0, 2, 1, 3}; num += adj[animFrame % 4]; - std::cout << "Drawing graphic " << num << " as a custom space pic.\n"; to_rect.right = to_rect.left + 28; to_rect.bottom = to_rect.top + 36; fill_rect(*inWindow, to_rect, sf::Color::Black); @@ -976,7 +971,6 @@ void cPict::drawCustomTalk(short num, rectangle to_rect){ } void cPict::drawCustomItem(short num, rectangle to_rect){ - std::cout << "Drawing graphic " << num << " as a custom space pic." << std::endl; to_rect.right = to_rect.left + 28; to_rect.bottom = to_rect.top + 36; rectangle from_rect; @@ -1013,7 +1007,6 @@ void cPict::drawCustomTerMap(short num, rectangle to_rect){ } void cPict::drawPartyMonstSm(short num, rectangle to_rect){ - std::cout << "Drawing graphic " << num << " as a custom space pic.\n"; to_rect.right = to_rect.left + 28; to_rect.bottom = to_rect.top + 36; sf::Texture* from_gw; @@ -1093,7 +1086,6 @@ void cPict::drawPartyScen(short num, rectangle to_rect){ } void cPict::drawPartyItem(short num, rectangle to_rect){ - std::cout << "Drawing graphic " << num << " as a custom space pic.\n"; to_rect.right = to_rect.left + 28; to_rect.bottom = to_rect.top + 36; sf::Texture* from_gw; @@ -1105,7 +1097,6 @@ void cPict::drawPartyItem(short num, rectangle to_rect){ } void cPict::drawPartyPc(short num, rectangle to_rect){ - std::cout << "Drawing graphic " << num << " as a custom space pic.\n"; to_rect.right = to_rect.left + 28; to_rect.bottom = to_rect.top + 36; sf::Texture* from_gw; diff --git a/src/dialogxml/pict.hpp b/src/dialogxml/pict.hpp index 2b043883..5bd65563 100644 --- a/src/dialogxml/pict.hpp +++ b/src/dialogxml/pict.hpp @@ -43,8 +43,8 @@ public: /// /// - If type is PIC_MONST, it automatically looks up the chosen icon to determine /// whether it should apply the tall or wide modifiers. - /// - If num is 4 digits in decimal and type is not PIC_FULL, it automatically subtracts 1000 and applies the custom modifier. - /// (If type is PIC_TER_MAP, it does not subtract 1000.) + /// - If num is 4 digits in decimal and type is not PIC_FULL, it automatically takes the remainder by 1000 + /// and applies the custom modifier. (If type is PIC_TER_MAP, it does not take the remainder by 1000.) /// - If num is 10000 or greater and type is PIC_TER_MAP, it automatically subtracts 10000 and applies the party modifier. void setPict(pic_num_t num, ePicType type); /// Set the pict's icon. diff --git a/src/scenedit/scen.core.cpp b/src/scenedit/scen.core.cpp index e8ea91b7..f140c8ef 100644 --- a/src/scenedit/scen.core.cpp +++ b/src/scenedit/scen.core.cpp @@ -1,6 +1,8 @@ + #include #include #include +#include #include #include "scen.global.h" #include "classes.h" @@ -26,6 +28,7 @@ extern cOutdoors* current_terrain; extern short mode_count,to_create; extern ter_num_t template_terrain[64][64]; extern cScenario scenario; +extern cCustomGraphics spec_scen_g; extern cSpecial null_spec_node; extern cSpeech null_talk_node; extern location cur_out; @@ -130,12 +133,11 @@ bool check_range(cDialog& me,std::string id,bool losing,long min_val,long max_va } // TODO: I have two functions that do this. (The other one is choose_graphic.) -static bool pick_picture(ePicType type, cDialog& parent, std::string result_fld, std::string pic_fld, pic_num_t modifier){ +static bool pick_picture(ePicType type, cDialog& parent, std::string result_fld, std::string pic_fld){ pic_num_t cur_sel = 0; if(result_fld != ""){ cControl& fld_ctrl = parent[result_fld]; cur_sel = fld_ctrl.getTextAsNum(); - cur_sel -= modifier; }else if(pic_fld != ""){ cPict& pic_ctrl = dynamic_cast(parent[pic_fld]); if(pic_ctrl.getPicType() == type) @@ -145,10 +147,12 @@ static bool pick_picture(ePicType type, cDialog& parent, std::string result_fld, if(pic != NO_PIC){ if(result_fld != ""){ cTextField& fld_ctrl = dynamic_cast(parent[result_fld]); - fld_ctrl.setTextToNum(pic + modifier); + fld_ctrl.setTextToNum(pic); } if(pic_fld != ""){ cPict& pic_ctrl = dynamic_cast(parent[pic_fld]); + if(type == PIC_TER_ANIM && pic < 1000) + pic += 960; pic_ctrl.setPict(pic,type); } } @@ -326,8 +330,8 @@ short edit_ter_type(ter_num_t which_ter) { cDialog ter_dlg("edit-terrain"); // Attach handlers ter_dlg["pict"].attachFocusHandler(std::bind(check_range,_1,_2,_3,0,2999,"terrain graphic")); - ter_dlg["pickpict"].attachClickHandler(std::bind(pick_picture,PIC_TER,_1,"pict","graphic",0)); - ter_dlg["pickanim"].attachClickHandler(std::bind(pick_picture,PIC_TER_ANIM,_1,"pict","graphic",960)); + ter_dlg["pickpict"].attachClickHandler(std::bind(pick_picture,PIC_TER,_1,"pict","graphic")); + ter_dlg["pickanim"].attachClickHandler(std::bind(pick_picture,PIC_TER_ANIM,_1,"pict","graphic")); ter_dlg["light"].attachFocusHandler(std::bind(check_range,_1,_2,_3,0,255,"light radius")); ter_dlg["trans"].attachFocusHandler(std::bind(check_range,_1,_2,_3,0,65535,"\"transform to what?\"")); ter_dlg["ground"].attachFocusHandler(std::bind(check_range,_1,_2,_3,0,255,"ground type")); @@ -349,7 +353,7 @@ short edit_ter_type(ter_num_t which_ter) { } static void put_monst_info_in_dlog(cDialog& me, cMonster& store_monst, mon_num_t which_monst) { - char str[256]; + std::ostringstream strb; if(store_monst.picture_num < 1000) dynamic_cast(me["icon"]).setPict(store_monst.picture_num,PIC_MONST); @@ -372,10 +376,11 @@ static void put_monst_info_in_dlog(cDialog& me, cMonster& store_monst, mon_num_t me["num"].setTextToNum(which_monst); me["name"].setText(store_monst.m_name); me["pic"].setTextToNum(store_monst.picture_num); - sprintf((char *) str,"Width = %d",store_monst.x_width); - me["w"].setText(str); - sprintf((char *) str,"Height = %d",store_monst.y_width); - me["h"].setText(str); + strb << "Width = " << int(store_monst.x_width); + me["w"].setText(strb.str()); + strb.str(""); + strb << "Height = " << int(store_monst.y_width); + me["h"].setText(strb.str()); me["level"].setTextToNum(store_monst.level); me["health"].setTextToNum(store_monst.m_health); me["armor"].setTextToNum(store_monst.armor); @@ -416,33 +421,46 @@ static void put_monst_info_in_dlog(cDialog& me, cMonster& store_monst, mon_num_t static bool check_monst_pic(cDialog& me, std::string id, bool losing, cMonster& store_monst) { if(!losing) return true; + static size_t max_preset = m_pic_index.size() - 1; + static const std::string error = "Non-customized monster pic must be from 0 to " + std::to_string(max_preset) + "."; if(check_range(me, id, losing, 0, 4999, "Monster pic")) { - // later check pic num for error, and assign widths if custom - if(store_monst.picture_num >= 1000) { - if((store_monst.picture_num >= 1000) && (store_monst.picture_num < 2000)) { + pic_num_t pic = me[id].getTextAsNum(); + store_monst.picture_num = pic; + cPict& icon = dynamic_cast(me["icon"]); + switch(pic / 1000) { + case 0: + if(cre(pic,0,max_preset,error,"",&me)) return false; + store_monst.x_width = m_pic_index[store_monst.picture_num].x; + store_monst.y_width = m_pic_index[store_monst.picture_num].y; + icon.setPict(pic, PIC_MONST); + break; + case 1: store_monst.x_width = 1; store_monst.y_width = 1; - } - if((store_monst.picture_num >= 2000) && (store_monst.picture_num < 3000)) { + icon.setPict(pic, PIC_MONST); + break; + case 2: store_monst.x_width = 2; store_monst.y_width = 1; - } - if((store_monst.picture_num >= 3000) && (store_monst.picture_num < 4000)) { + icon.setPict(pic, PIC_MONST_WIDE); + break; + case 3: store_monst.x_width = 1; store_monst.y_width = 2; - } - if((store_monst.picture_num >= 4000) && (store_monst.picture_num < 5000)) { + icon.setPict(pic, PIC_MONST_TALL); + break; + case 4: store_monst.x_width = 2; store_monst.y_width = 2; - } - } - else { - // TODO: Update this with new value if more monster pictures are added later - if(cre(store_monst.picture_num,0,200,"Non-customized monster pic must be from 0 to 200.","",&me)) return false; - store_monst.x_width = m_pic_index[store_monst.picture_num].x; - store_monst.y_width = m_pic_index[store_monst.picture_num].y; - + icon.setPict(pic, PIC_MONST_LG); + break; } + std::ostringstream strb; + strb << "Width = " << int(store_monst.x_width); + me["w"].setText(strb.str()); + strb.str(""); + strb << "Height = " << int(store_monst.y_width); + me["h"].setText(strb.str()); } return true; } @@ -545,13 +563,19 @@ static bool check_monst_dice(cDialog& me, std::string fld, bool losing) { return check_range(me, fld, losing, 1, 50, "attack damage per die"); } +static bool pick_monst_picture(cDialog& me) { + bool result = pick_picture(PIC_MONST, me, "pic", "icon"); + me["pic"].triggerFocusHandler(me, "pic", true); + return result; +} + short edit_monst_type(short which_monst) { using namespace std::placeholders; cMonster store_monst = scenario.scen_monsters[which_monst]; cDialog monst_dlg("edit-monster"); - monst_dlg["pickicon"].attachClickHandler(std::bind(pick_picture,PIC_MONST,_1,"pic","icon",0)); - monst_dlg["picktalk"].attachClickHandler(std::bind(pick_picture,PIC_TALK,_1,"talk","",0)); + monst_dlg["pickicon"].attachClickHandler(std::bind(pick_monst_picture,_1)); + monst_dlg["picktalk"].attachClickHandler(std::bind(pick_picture,PIC_TALK,_1,"talk","")); monst_dlg["cancel"].attachClickHandler(std::bind(&cDialog::toast, &monst_dlg, false)); monst_dlg["pic"].attachFocusHandler(std::bind(check_monst_pic, _1, _2, _3, std::ref(store_monst))); monst_dlg["level"].attachFocusHandler(std::bind(check_range, _1, _2, _3, 0, 40, "level")); @@ -830,9 +854,9 @@ static bool edit_item_type_event_filter(cDialog& me, std::string item_hit, cItem if(store_which_item > 399) store_which_item = 0; store_item = scenario.scen_items[store_which_item]; put_item_info_in_dlog(me, store_item, store_which_item); - } else if(item_hit == "choospic") { + } else if(item_hit == "choosepic") { if(!save_item_info(me, store_item, store_which_item)) return true; - i = pick_picture(PIC_ITEM, me, "picnum", "pic", 0); + i = pick_picture(PIC_ITEM, me, "picnum", "pic"); if(i < 0) return true; store_item.graphic_num = i; } else if(item_hit == "abils") { @@ -1637,3 +1661,154 @@ void edit_scenario_events() { evt_dlg.run(); } +static void fill_custom_pics_types(cDialog& me, std::vector& pics, pic_num_t first) { + pic_num_t last = first + 9; + if(last >= pics.size()) pics.resize(last + 1, PIC_FULL); + me["num0"].setTextToNum(first); + for(pic_num_t i = first; i <= last; i++) { + std::string id = std::to_string(i - first + 1); + cLedGroup& grp = dynamic_cast(me["type" + id]); + cPict& pic = dynamic_cast(me["pic" + id]); + pic.setPict(i, PIC_CUSTOM_TER); + cControl& num = me["num" + id]; + num.setTextToNum(1000 + i); + switch(pics[i]) { + case PIC_TER: + grp.setSelected("ter" + id); + break; + case PIC_TER_ANIM: + grp.setSelected("anim" + id); + num.setTextToNum(2000 + i); + break; + case PIC_TER_MAP: + grp.setSelected("map" + id); + break; + case PIC_MONST: + grp.setSelected("monst-sm" + id); + break; + case PIC_MONST_WIDE: + grp.setSelected("monst-wide" + id); + num.setTextToNum(2000 + i); + break; + case PIC_MONST_TALL: + grp.setSelected("monst-tall" + id); + num.setTextToNum(3000 + i); + break; + case PIC_MONST_LG: + grp.setSelected("monst-lg" + id); + num.setTextToNum(4000 + i); + break; + case PIC_DLOG: + grp.setSelected("dlog" + id); + break; + case PIC_DLOG_LG: + grp.setSelected("dlog-lg" + id); + break; + case PIC_TALK: + grp.setSelected("talk" + id); + pic.setPict(i, PIC_CUSTOM_TALK); + break; + case PIC_ITEM: + grp.setSelected("item" + id); + break; + case PIC_BOOM: + grp.setSelected("boom" + id); + break; + case PIC_MISSILE: + grp.setSelected("miss" + id); + break; + case PIC_FULL: + grp.setSelected("none" + id); + break; + } + } +} + +static bool set_custom_pic_type(cDialog& me, std::string hit, std::vector& pics, pic_num_t first) { + hit = dynamic_cast(me[hit]).getSelected(); + size_t iNum = hit.find_last_not_of("0123456789"); + std::string id = hit.substr(iNum + 1); + hit = hit.substr(0, iNum + 1); + pic_num_t pic = boost::lexical_cast(id) + first - 1; + cControl& num = me["num" + id]; + num.setTextToNum(1000 + pic); + if(hit == "ter") { + pics[pic] = PIC_TER; + } else if(hit == "anim") { + pics[pic] = PIC_TER_ANIM; + num.setTextToNum(2000 + pic); + } else if(hit == "map") { + pics[pic] = PIC_TER_MAP; + } else if(hit == "monst-sm") { + pics[pic] = PIC_MONST; + } else if(hit == "monst-wide") { + pics[pic] = PIC_MONST_WIDE; + num.setTextToNum(2000 + pic); + } else if(hit == "monst-tall") { + pics[pic] = PIC_MONST_TALL; + num.setTextToNum(3000 + pic); + } else if(hit == "monst-lg") { + pics[pic] = PIC_MONST_LG; + num.setTextToNum(4000 + pic); + } else if(hit == "dlog") { + pics[pic] = PIC_DLOG; + } else if(hit == "dlog-lg") { + pics[pic] = PIC_DLOG_LG; + } else if(hit == "talk") { + pics[pic] = PIC_TALK; + } else if(hit == "item") { + pics[pic] = PIC_ITEM; + } else if(hit == "boom") { + pics[pic] = PIC_BOOM; + } else if(hit == "miss") { + pics[pic] = PIC_MISSILE; + } else if(hit == "none") { + pics[pic] = PIC_FULL; + } + return true; +} + +static bool save_pics_types(cDialog& me, const std::vector& pics) { + if(!me.toast(true)) return true; + scenario.custom_graphics = pics; + return true; +} + +static bool change_pics_page(cDialog& me, std::string hit, std::vector& pics, pic_num_t& first) { + size_t num_pics = spec_scen_g.count(); + if(hit == "left") { + if(first == 0) first = ((num_pics - 1) / 10) * 10; + else first -= 10; + } else if(hit == "right") { + if(first + 10 >= num_pics) first = 0; + else first += 10; + } else return true; + fill_custom_pics_types(me, pics, first); + return true; +} + +void edit_custom_pics_types() { + if(spec_scen_g.count() == 0) { + giveError("You don't have any custom graphics to classify!"); + return; + } + using namespace std::placeholders; + std::vector pics = scenario.custom_graphics; + pic_num_t first_pic = 0; + + cDialog pic_dlg("graphic-types"); + for(int i = 0; i < 10; i++) { + std::string id = std::to_string(i + 1); + pic_dlg["type" + id].attachFocusHandler(std::bind(set_custom_pic_type, _1, _2, std::ref(pics), std::ref(first_pic))); + } + pic_dlg["okay"].attachClickHandler(std::bind(save_pics_types, _1, std::ref(pics))); + pic_dlg["cancel"].attachClickHandler(std::bind(&cDialog::toast, _1, false)); + pic_dlg.attachClickHandlers(std::bind(change_pics_page, _1, _2, std::ref(pics), std::ref(first_pic)), {"left", "right"}); + + fill_custom_pics_types(pic_dlg, pics, first_pic); + if(spec_scen_g.count() <= 10) { + pic_dlg["left"].hide(); + pic_dlg["right"].hide(); + } + pic_dlg.run(); +} diff --git a/src/scenedit/scen.core.h b/src/scenedit/scen.core.h index f642308b..02bd97d5 100644 --- a/src/scenedit/scen.core.h +++ b/src/scenedit/scen.core.h @@ -1,6 +1,7 @@ class cDialog; +void edit_custom_pics_types(); short edit_ter_type(ter_num_t which_ter); short edit_monst_type(short which_monst); cMonster edit_monst_abil(cMonster starting_record,short parent_num); diff --git a/src/scenedit/scen.fileio.cpp b/src/scenedit/scen.fileio.cpp index d70b7028..365ab8f0 100644 --- a/src/scenedit/scen.fileio.cpp +++ b/src/scenedit/scen.fileio.cpp @@ -170,6 +170,17 @@ void save_scenario(fs::path toFile) { data.PushElement("default-ground", scenario.default_ground); data.PushElement("last-out-section", scenario.last_out_edited); data.PushElement("last-town", scenario.last_town_edited); + if(!scenario.custom_graphics.empty()) { + data.OpenElement("graphics"); + for(size_t i = 0; i < scenario.custom_graphics.size(); i++) { + if(scenario.custom_graphics[i] == PIC_FULL) continue; + data.OpenElement("pic"); + data.PushAttribute("index", i); + data.PushText(scenario.custom_graphics[i]); + data.CloseElement("pic"); + } + data.CloseElement("graphics"); + } for(int i = 0; i < 10; i++) { if(scenario.storage_shortcuts[i].ter_type >= 0) { cScenario::cItemStorage shortcut = scenario.storage_shortcuts[i]; diff --git a/src/scenedit/scen.keydlgs.cpp b/src/scenedit/scen.keydlgs.cpp index 2757c079..461ffd62 100644 --- a/src/scenedit/scen.keydlgs.cpp +++ b/src/scenedit/scen.keydlgs.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "scen.global.h" #include "classes.h" @@ -54,19 +55,27 @@ bool cre(short val,short min,short max,std::string text1,std::string text2,cDial // TODO: I have two functions that do this. (The other one is pick_picture.) pic_num_t choose_graphic(short cur_choice,ePicType g_type,cDialog* parent) { int i = 0; - std::vector> pics; + std::vector all_pics; + size_t total_pics = 0; cPictChoice* pic_dlg = nullptr; switch(g_type) { - case PIC_TER: // TODO: Increase upper limit to allow picking of the added graphics - pic_dlg = new cPictChoice(0, 252, PIC_TER, parent); - break; - case PIC_TER_ANIM: // TODO: Increase to allow picking of the added graphics - pic_dlg = new cPictChoice(0, 13, PIC_TER_ANIM, parent); - break; - case PIC_MONST: - case PIC_MONST_WIDE: - case PIC_MONST_TALL: - case PIC_MONST_LG: + case PIC_TER: total_pics = 859; break; + case PIC_TER_ANIM: total_pics = 20; break; + case PIC_DLOG: total_pics = 44; break; + case PIC_TALK: total_pics = 84; break; + case PIC_SCEN: total_pics = 30; break; + case PIC_ITEM: total_pics = 123; break; + case PIC_PC: total_pics = 36; break; + case PIC_FIELD: all_pics = field_pics; break; + case PIC_BOOM: all_pics = boom_pics; break; + case PIC_DLOG_LG: all_pics = lgdlog_pics; break; + case PIC_MISSILE: total_pics = 16; break; + case PIC_STATUS: total_pics = 27; break; + case PIC_SCEN_LG: total_pics = 4; break; + case PIC_TER_MAP: total_pics = 980; break; + case PIC_MONST: case PIC_MONST_WIDE: + case PIC_MONST_TALL: case PIC_MONST_LG: + std::vector> pics; for(m_pic_index_t m_pic : m_pic_index) { // TODO: Put the added monster graphics in m_pic_index to allow picking them ePicType type = PIC_MONST; @@ -74,64 +83,45 @@ pic_num_t choose_graphic(short cur_choice,ePicType g_type,cDialog* parent) { if(m_pic.y == 2) type += PIC_TALL; pics.push_back({i++, type}); } + for(size_t i = 0; i < scenario.custom_graphics.size(); i++) { + if(scenario.custom_graphics[i] == PIC_MONST) + pics.push_back({1000 + i, PIC_CUSTOM_MONST}); + else if(scenario.custom_graphics[i] == PIC_MONST_WIDE) + pics.push_back({2000 + i, PIC_CUSTOM_MONST_WIDE}); + else if(scenario.custom_graphics[i] == PIC_MONST_TALL) + pics.push_back({3000 + i, PIC_CUSTOM_MONST_TALL}); + else if(scenario.custom_graphics[i] == PIC_MONST_LG) + pics.push_back({4000 + i, PIC_CUSTOM_MONST_LG}); + if(cur_choice == pics.back().first) + cur_choice = pics.size() - 1; + } pic_dlg = new cPictChoice(pics, parent); break; - case PIC_DLOG: // TODO: Increase upper limit to allow picking of the added graphics - pic_dlg = new cPictChoice(0, 31, PIC_DLOG, parent); - break; - case PIC_TALK: - pic_dlg = new cPictChoice(0, 83, PIC_TALK, parent); - break; - case PIC_SCEN: - pic_dlg = new cPictChoice(0, 29, PIC_SCEN, parent); - break; - case PIC_ITEM: - pic_dlg = new cPictChoice(0, 122, PIC_ITEM, parent); - break; - case PIC_PC: - pic_dlg = new cPictChoice(0, 35, PIC_PC, parent); - break; - case PIC_FIELD: - pic_dlg = new cPictChoice(field_pics, PIC_FIELD, parent); - break; - case PIC_BOOM: - pic_dlg = new cPictChoice(boom_pics, PIC_BOOM, parent); - break; - case PIC_DLOG_LG: - pic_dlg = new cPictChoice(lgdlog_pics, PIC_DLOG_LG, parent); - break; - case PIC_FULL: - // TODO: Should this be handled at all? - break; - case PIC_MISSILE: - pic_dlg = new cPictChoice(0, 15, PIC_MISSILE, parent); - break; - case PIC_STATUS: - pic_dlg = new cPictChoice(0, 17, PIC_STATUS, parent); - break; - case PIC_SCEN_LG: - pic_dlg = new cPictChoice(0, 3, PIC_SCEN_LG, parent); - break; - case PIC_TER_MAP: - pic_dlg = new cPictChoice(0, 418, PIC_TER_MAP, parent); - break; - default: // Custom or party; assume custom, since this is the scenario editor and the party sheet isn't available - if(g_type & PIC_PARTY) break; - ePicType g_base_type = g_type - PIC_CUSTOM; - pic_num_t totalPics = spec_scen_g.count(); - pic_num_t last; - if(g_base_type == PIC_DLOG || g_base_type == PIC_TALK || g_base_type == PIC_SCEN) - last = totalPics - 2; - else if(g_base_type == PIC_TER_ANIM || g_base_type == PIC_MONST || g_base_type == PIC_PC || g_base_type == PIC_MISSILE) - last = totalPics - 4; - else if(g_base_type==PIC_DLOG_LG || g_base_type==PIC_SCEN_LG || g_base_type==PIC_MONST_WIDE || g_base_type==PIC_MONST_TALL) - last = totalPics - 8; - else if(g_base_type == PIC_MONST_LG) last = totalPics - 16; - else if(g_base_type == PIC_TER_MAP) last = totalPics * 6 - 1; // TODO: Check this formula - else last = totalPics = 1; - pic_dlg = new cPictChoice(0, last, g_type, parent); } - if(!pic_dlg) return cur_choice; + if(!pic_dlg) { + if(all_pics.size()); + else if(total_pics > 0) { + all_pics.resize(total_pics); + std::iota(all_pics.begin(), all_pics.end(), 0); + } else return cur_choice; + // Now add the custom pics + for(size_t i = 0; i < scenario.custom_graphics.size(); i++) { + if(scenario.custom_graphics[i] == g_type) { + if(g_type == PIC_TER_MAP) { + for(int j = 1; j <= 6; j++) + all_pics.push_back(j * 1000 + i); + } else if(g_type == PIC_TER_ANIM) + all_pics.push_back(2000 + i); + else all_pics.push_back(1000 + i); + } + } + if(cur_choice >= 1000) { + auto selected = std::find(all_pics.begin(), all_pics.end(), cur_choice); + if(selected == all_pics.end()) cur_choice = -1; + else cur_choice = selected - all_pics.begin(); + } + pic_dlg = new cPictChoice(all_pics, g_type, parent); + } bool made_choice = pic_dlg->show(cur_choice); pic_num_t item_hit = pic_dlg->getPicChosen(); delete pic_dlg; diff --git a/src/scenedit/scen.main.cpp b/src/scenedit/scen.main.cpp index 9ebddbbe..ef04b17c 100644 --- a/src/scenedit/scen.main.cpp +++ b/src/scenedit/scen.main.cpp @@ -263,6 +263,10 @@ void handle_menu_choice(eMenu item_hit) { set_starting_loc(); change_made = true; break; + case eMenu::SCEN_PICS: + edit_custom_pics_types(); + change_made = true; + break; case eMenu::SCEN_SPECIALS: right_sbar->setPosition(0); start_special_editing(0,0); diff --git a/src/scenedit/scen.menu.xib b/src/scenedit/scen.menu.xib index d86658f7..82920e00 100644 --- a/src/scenedit/scen.menu.xib +++ b/src/scenedit/scen.menu.xib @@ -373,6 +373,14 @@ + + + Classify Custom Graphics + + 2147483647 + + + YES @@ -1364,6 +1372,7 @@ + @@ -1838,6 +1847,11 @@ + + 887 + + + @@ -1961,12 +1975,13 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin - 886 + 887 0 diff --git a/src/scenedit/scen.menus.h b/src/scenedit/scen.menus.h index a20891ee..5794f91e 100644 --- a/src/scenedit/scen.menus.h +++ b/src/scenedit/scen.menus.h @@ -24,6 +24,7 @@ enum class eMenu { SCEN_SAVE_ITEM_RECTS, SCEN_HORSES, SCEN_BOATS, TOWN_VARYING, SCEN_TIMERS, SCEN_ITEM_SHORTCUTS, TOWN_DELETE, SCEN_DATA_DUMP, SCEN_TEXT_DUMP, + SCEN_PICS, // Town menu TOWN_DETAILS, TOWN_WANDERING, TOWN_BOUNDARIES, TOWN_AREAS, TOWN_ITEMS_RANDOM, TOWN_ITEMS_NOT_PROPERTY, TOWN_ITEMS_CLEAR, diff --git a/src/scenedit/scen.menus.mac.mm b/src/scenedit/scen.menus.mac.mm index 2cc0a05a..01336784 100644 --- a/src/scenedit/scen.menus.mac.mm +++ b/src/scenedit/scen.menus.mac.mm @@ -64,7 +64,7 @@ void init_menubar() { eMenu::EDIT_CUT, eMenu::EDIT_COPY, eMenu::EDIT_PASTE, eMenu::EDIT_DELETE, eMenu::EDIT_SELECT_ALL, }; static const eMenu scen_choices[] = { - eMenu::TOWN_CREATE, eMenu::NONE, eMenu::SCEN_DETAILS, eMenu::SCEN_INTRO, eMenu::TOWN_START, eMenu::NONE, eMenu::NONE, + eMenu::TOWN_CREATE, eMenu::NONE, eMenu::SCEN_DETAILS, eMenu::SCEN_INTRO, eMenu::TOWN_START, eMenu::SCEN_PICS, eMenu::NONE, eMenu::NONE, eMenu::SCEN_SPECIALS, eMenu::SCEN_TEXT, eMenu::SCEN_JOURNALS, eMenu::TOWN_IMPORT, eMenu::SCEN_SAVE_ITEM_RECTS, eMenu::SCEN_HORSES, eMenu::SCEN_BOATS, eMenu::TOWN_VARYING, eMenu::SCEN_TIMERS, eMenu::SCEN_ITEM_SHORTCUTS, eMenu::TOWN_DELETE, eMenu::SCEN_DATA_DUMP, eMenu::SCEN_TEXT_DUMP, diff --git a/src/scenedit/scen.menus.win.cpp b/src/scenedit/scen.menus.win.cpp index 171db0b3..8ed28797 100644 --- a/src/scenedit/scen.menus.win.cpp +++ b/src/scenedit/scen.menus.win.cpp @@ -69,7 +69,7 @@ void init_menubar() { eMenu::EDIT_CUT, eMenu::EDIT_COPY, eMenu::EDIT_PASTE, eMenu::EDIT_DELETE, eMenu::EDIT_SELECT_ALL, }; static const eMenu scen_choices[] = { - eMenu::TOWN_CREATE, eMenu::NONE, eMenu::SCEN_DETAILS, eMenu::SCEN_INTRO, eMenu::TOWN_START, eMenu::NONE, eMenu::NONE, + eMenu::TOWN_CREATE, eMenu::NONE, eMenu::SCEN_DETAILS, eMenu::SCEN_INTRO, eMenu::TOWN_START, eMenu::SCEN_PICS, eMenu::NONE, eMenu::NONE, eMenu::SCEN_SPECIALS, eMenu::SCEN_TEXT, eMenu::SCEN_JOURNALS, eMenu::TOWN_IMPORT, eMenu::SCEN_SAVE_ITEM_RECTS, eMenu::SCEN_HORSES, eMenu::SCEN_BOATS, eMenu::TOWN_VARYING, eMenu::SCEN_TIMERS, eMenu::SCEN_ITEM_SHORTCUTS, eMenu::TOWN_DELETE, eMenu::SCEN_DATA_DUMP, eMenu::SCEN_TEXT_DUMP, diff --git a/src/tools/graphtool.cpp b/src/tools/graphtool.cpp index 1065c66b..a6ae7bad 100644 --- a/src/tools/graphtool.cpp +++ b/src/tools/graphtool.cpp @@ -502,7 +502,7 @@ std::string get_str(std::string list, short j){ return strings[j - 1]; } -m_pic_index_t m_pic_index[] = { +extern const std::vector m_pic_index = { {1, 1, 1}, {2, 1, 1}, {3, 1, 1}, @@ -702,27 +702,6 @@ m_pic_index_t m_pic_index[] = { {203, 1, 1}, //180 {204, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - //190 - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - {0, 1, 1}, - //200 }; // TODO: Put these classes in a header? diff --git a/src/tools/graphtool.hpp b/src/tools/graphtool.hpp index da1b432f..42a5fc32 100644 --- a/src/tools/graphtool.hpp +++ b/src/tools/graphtool.hpp @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -138,7 +139,7 @@ short can_see(location p1,location p2,std::function get_obsc std::string get_str(std::string list, short j); #ifndef GRAPHTOOL_CPP -extern m_pic_index_t m_pic_index[200]; +extern const std::vector m_pic_index; extern tessel_ref_t bg[]; #endif