#include #include #include #include "scen.global.h" #include "classes.h" #include "graphtool.h" #include "scen.graphics.h" #include "scen.keydlgs.h" #include "scen.core.h" #include "dlogutil.h" #include "restypes.hpp" extern short cen_x, cen_y/*, overall_mode*/; extern bool mouse_button_held; extern short cur_viewing_mode; extern cTown* town; //extern big_tr_type t_d; extern short town_type; // 0 - big 1 - ave 2 - small extern short /*max_dim[3],*/mode_count,to_create; extern ter_num_t template_terrain[64][64]; extern cItemRec item_list[400]; extern cScenario scenario; extern cSpecial null_spec_node; extern cSpeech null_talk_node; //extern piles_of_stuff_dumping_type *data_store; extern cOutdoors current_terrain; extern cCustomGraphics spec_scen_g; std::stack last_node; cSpecial store_spec_node; short num_specs[3] = {256,60,100}; std::vector field_pics = {2,3,5,6,7,8,9,10,11,12,13,14,15,16,24,25,26,27,28,29,30,31}; std::vector boom_pics = {0,1,2,3,4,8,16,24,32}; std::vector lgdlog_pics = {0,72}; //cre = check range error bool cre(short val,short min,short max,const char *text1,const char *text2,cDialog* parent) { if ((val < min) || (val > max)) { giveError(text1,text2,parent); return true; } return false; } // 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; 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: 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; if(m_pic.x == 2) type += PIC_WIDE; if(m_pic.y == 2) type += PIC_TALL; pics.push_back({i++, type}); } 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; bool made_choice = pic_dlg->show(cur_choice); pic_num_t item_hit = pic_dlg->getPicChosen(); delete pic_dlg; return made_choice ? item_hit : NO_PIC; } 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; StringRsrc strings = *ResMgr::get(res_list); cStringChoice dlog(strings.begin() + first_t, strings.begin() + last_t + 1, title, parent); return dlog.show(cur_choice); } short choose_text(eStrType list, unsigned short cur_choice, cDialog* parent, const char* title) { location view_loc; std::vector strings; switch(list) { case STRT_MONST: for(cMonster& monst : scenario.scen_monsters) { strings.push_back(monst.m_name); } break; case STRT_ITEM: for(cItemRec& item : scenario.scen_items) { strings.push_back(item.full_name); } break; case STRT_TER: for(cTerrain& ter : scenario.ter_types) { strings.push_back(ter.name); } break; case STRT_BUTTON: for(int btn : available_btns) { strings.push_back(basic_buttons[btn].label); } } if(cur_choice < 0 || cur_choice >= strings.size()) cur_choice = 0; cStringChoice dlog(strings, title, parent); return dlog.show(cur_choice); } static bool edit_text_event_filter(cDialog& me, std::string item_hit, short& which_str, short str_mode) { short num_strs[3] = {260,108,140}; std::string newVal = me["text"].getText(); if (str_mode == 0) strcpy(scenario.scen_strs(which_str), newVal.c_str()); if (str_mode == 1) strcpy(current_terrain.out_strs(which_str), newVal.c_str()); if (str_mode == 2) strcpy(town->town_strs(which_str), newVal.c_str()); if(item_hit == "okay") me.toast(true); else if(item_hit == "left" || item_hit == "right") { if(item_hit[0] == 'l') which_str--; else which_str++; if (which_str < 0) which_str = num_strs[str_mode] - 1; if (which_str >= num_strs[str_mode]) which_str = 0; } me["num"].setTextToNum(which_str); if (str_mode == 0) me["text"].setText(scenario.scen_strs(which_str)); if (str_mode) me["text"].setText(current_terrain.out_strs(which_str)); if (str_mode == 2) me["text"].setText(town->town_strs(which_str)); return true; } // mode 0 - scen 1 - out 2 - town void edit_text_str(short which_str,short mode) { using namespace std::placeholders; cDialog dlog("edit-text.xml"); dlog.attachClickHandlers(std::bind(edit_text_event_filter, _1, _2, std::ref(which_str), mode), {"okay", "left", "right"}); dlog["num"].setTextToNum(which_str); if(mode == 0) dlog["text"].setText(scenario.scen_strs(which_str)); if(mode) dlog["text"].setText(current_terrain.out_strs(which_str)); if(mode == 2) dlog["text"].setText(town->town_strs(which_str)); dlog.run(); } static bool edit_area_rect_event_filter(cDialog& me, std::string item_hit, short which_str, short str_mode) { if(item_hit == "okay") { me.setResult(true); me.toast(true); std::string str = me["area"].getText(); if(str_mode == 0) sprintf(current_terrain.out_strs(which_str + 1),"%-29.29s",str.c_str()); else sprintf(town->town_strs(which_str + 1),"%-29.29s",str.c_str()); } else if(item_hit == "cancel") { me.setResult(false); me.toast(false); } return true; } // mode 0 - out 1 - town bool edit_area_rect_str(short which_str,short mode) { using namespace std::placeholders; cDialog dlog("set-area-desc.xml"); dlog.attachClickHandlers(std::bind(edit_area_rect_event_filter, _1, _2, which_str, mode), {"okay", "cancel"}); if(mode == 0) dlog["area"].setText(current_terrain.out_strs(which_str + 1)); else dlog["area"].setText(town->town_strs(which_str + 1)); dlog.run(); return dlog.getResult(); } // MARK: Special node dialog static bool save_spec_enc(cDialog& me, short which_mode, short which_node) { store_spec_node.sd1 = me["sdf1"].getTextAsNum(); store_spec_node.sd2 = me["sdf2"].getTextAsNum(); store_spec_node.m1 = me["msg1"].getTextAsNum(); store_spec_node.m2 = me["msg2"].getTextAsNum(); store_spec_node.pic = me["pict"].getTextAsNum(); if (store_spec_node.pic < 0) store_spec_node.pic = 0; store_spec_node.ex1a = me["x1a"].getTextAsNum(); store_spec_node.ex1b = me["x1b"].getTextAsNum(); store_spec_node.ex2a = me["x2a"].getTextAsNum(); store_spec_node.ex2b = me["x2b"].getTextAsNum(); store_spec_node.jumpto = me["jump"].getTextAsNum(); if((*store_spec_node.type).sdf_label == 1) { if (cre(store_spec_node.sd1,-1,299,"The first part of a Stuff Done flag must be from 0 to 299 (or -1 if the Stuff Done flag is ignored.", "",&me) > 0) return false; if (cre(store_spec_node.sd2,-1,9,"The second part of a Stuff Done flag must be from 0 to 9 (or -1 if the Stuff Done flag is ignored.", "",&me) > 0) return false; } if(which_mode == 0) scenario.scen_specials[which_node] = store_spec_node; if(which_mode == 1) current_terrain.specials[which_node] = store_spec_node; if(which_mode == 2) town->specials[which_node] = store_spec_node; return true; } static void put_spec_enc_in_dlog(cDialog& me, short which_node) { std::string str; me["num"].setTextToNum(which_node); str = get_str("special-node-names",int(store_spec_node.type) + 1); me["type"].setText(str); if(last_node.empty()) me["back"].hide(); else me["back"].show(); me["sdf1"].setTextToNum(store_spec_node.sd1); me["sdf2"].setTextToNum(store_spec_node.sd2); switch((*store_spec_node.type).sdf_label) { case 0: me["sdf1-lbl"].setText("Unused."); me["sdf2-lbl"].setText("Unused."); break; case 1: me["sdf1-lbl"].setText("Stuff Done Flag Part A"); me["sdf2-lbl"].setText("Stuff Done Flag Part B"); break; case 2: me["sdf1-lbl"].setText("Chance of placing (0 - 100)"); me["sdf2-lbl"].setText("Unused"); break; case 3: me["sdf1-lbl"].setText("Stuff Done Flag Part A"); me["sdf2-lbl"].setText("Unused"); break; case 4: me["sdf1-lbl"].setText("X of space to move to"); me["sdf2-lbl"].setText("Y of space to move to"); break; case 5: me["sdf1-lbl"].setText("Terrain to change to"); me["sdf2-lbl"].setText("Chance of changing (0 - 100)"); break; case 6: me["sdf1-lbl"].setText("Switch this ter. type"); me["sdf2-lbl"].setText("with this ter. type"); break; case 7: me["sdf1-lbl"].setText("Chance of placing (0 - 100)"); me["sdf2-lbl"].setText("What to place (see docs.)"); break; case 8: me["sdf1-lbl"].setText("Chance of placing (0 - 100)"); me["sdf2-lbl"].setText("0 - web, 1 - barrel, 2 - crate"); break; } me["msg1"].setTextToNum(store_spec_node.m1); me["msg2"].setTextToNum(store_spec_node.m2); switch((*store_spec_node.type).msg_label) { case 0: me["msg1-lbl"].setText("Unused."); me["msg2-lbl"].setText("Unused."); me["msg1-edit"].hide(); me["msg2-edit"].hide(); break; case 1: me["msg1-lbl"].setText("First part of message"); me["msg2-lbl"].setText("Second part of message"); me["msg1-edit"].hide(); me["msg2-edit"].show(); break; case 2: me["msg1-lbl"].setText("Number of first message in dialog"); me["msg2-lbl"].setText("Unused"); me["msg1-edit"].hide(); me["msg2-edit"].show(); break; case 3: me["msg1-lbl"].setText("Name of Store"); me["msg2-lbl"].setText("Unused"); me["msg1-edit"].hide(); me["msg2-edit"].show(); break; case 4: me["msg1-lbl"].setText("Number of first message in dialog"); me["msg2-lbl"].setText("1 - add 'Leave'/'OK' button, else no"); me["msg1-edit"].hide(); me["msg2-edit"].show(); break; case 5: me["msg1-lbl"].setText("Number of first message in dialog"); me["msg2-lbl"].setText("Num. of spec. item to give (-1 none)"); me["msg1-edit"].hide(); me["msg2-edit"].show(); break; } me["pict"].setTextToNum(store_spec_node.pic); switch((*store_spec_node.type).pic_label) { case 0: me["pict-lbl"].setText("Unused."); me["pict-edit"].hide(); break; case 1: me["pict-lbl"].setText("Dialog Picture number"); me["pict-edit"].show(); break; case 2: me["pict-lbl"].setText("Terrain Picture number"); me["pict-edit"].show(); break; case 3: me["pict-lbl"].setText("Monster Picture number"); me["pict-edit"].show(); break; case 4: me["pict-lbl"].setText("Chance of changing (0 - 100)"); me["pict-edit"].hide(); break; case 5: me["pict-lbl"].setText("Number of letters to match"); me["pict-edit"].hide(); break; case 6: me["pict-lbl"].setText("Radius of explosion"); me["pict-edit"].hide(); break; } me["x1a"].setTextToNum(store_spec_node.ex1a); str = get_str("special-x1a",int(store_spec_node.type) + 1); me["x1a-lbl"].setText(str); if((*store_spec_node.type).ex1a_choose == 1) me["x1a-edit"].show(); else me["x1a-edit"].hide(); me["x1b"].setTextToNum(store_spec_node.ex1b); str = get_str("special-x1b",int(store_spec_node.type) + 1); me["x1b-lbl"].setText(str); if((*store_spec_node.type).ex1b_choose == 1) me["x1b-edit"].show(); else me["x1b-edit"].hide(); me["x2a"].setTextToNum(store_spec_node.ex2a); str = get_str("special-x2a",int(store_spec_node.type) + 1); me["x2a-lbl"].setText(str); if((*store_spec_node.type).ex2a_choose == 1) me["x2a-edit"].show(); else me["x2a-edit"].hide(); me["x2b"].setTextToNum(store_spec_node.ex2b); str = get_str("special-x2b",int(store_spec_node.type) + 1); me["x2b-lbl"].setText(str); if((*store_spec_node.type).ex2b_choose == 1) me["x2b-edit"].show(); else me["x2b-edit"].hide(); me["jump"].setTextToNum(store_spec_node.jumpto); switch ((*store_spec_node.type).jmp_label) { case 0: me["jump-lbl"].setText("Special to Jump To"); break; case 1: me["jump-lbl"].setText("Special node if not blocked"); break; case 2: me["jump-lbl"].setText("Special after trap finished"); break; case 3: me["jump-lbl"].setText("Otherwise call this special"); break; case 4: me["jump-lbl"].setText("Special if OK/Leave picked"); break; } } static bool edit_spec_enc_event_filter(cDialog& me, std::string item_hit, short& which_mode, short& which_node) { short i,node_to_change_to = -1,spec; if(item_hit == "okay") { if(save_spec_enc(me, which_mode, which_node)) me.toast(true); } else if(item_hit == "back") { if(!save_spec_enc(me, which_mode, which_node)) return true; if(!last_node.empty()) { node_to_change_to = last_node.top(); last_node.pop(); } } else if(item_hit == "cancel") { if(!last_node.empty()) { giveError("You can't cancel out of making a special until you're back at the beginning of the special chain.", "Press the Go Back button until it disappears.",&me); return true; } me.toast(false); } else if(me[item_hit].getText() == "Create/Edit") { if(!save_spec_enc(me, which_mode, which_node)) return true; if(item_hit == "x1b-edit") spec = me["x1b"].getTextAsNum(); else if(item_hit == "x2b-edit") spec = me["x2b"].getTextAsNum(); else if(item_hit == "jump-edit") spec = me["jump"].getTextAsNum(); if ((spec < 0) || (spec >= num_specs[which_mode])) { spec = -1; //CDSN(822,8,-1) // TODO: Generalize this situation of a node jumping to a scenario node if(item_hit == "x1b-edit" && store_spec_node.type == eSpecType::SCEN_TIMER_START) spec = get_fresh_spec(0); else if(item_hit == "jump-edit" && store_spec_node.type == eSpecType::CALL_GLOBAL) spec = get_fresh_spec(0); else spec = get_fresh_spec(which_mode); if (spec < 0) { giveError("You can't create a new 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(item_hit == "x1b-edit") me["x1b"].setTextToNum(spec); else if(item_hit == "x2b-edit") me["x2b"].setTextToNum(spec); else if(item_hit == "jump-edit") me["jump"].setTextToNum(spec); /* if (item_hit == 43) store_spec_node.ex1b = spec; if (item_hit == 44) store_spec_node.ex2b = spec; if (item_hit == 45) store_spec_node.jumpto = spec; */ } if(!save_spec_enc(me, which_mode, which_node)) return true; if(item_hit == "x1b-edit" && store_spec_node.type == eSpecType::SCEN_TIMER_START) node_to_change_to = spec; else if(item_hit == "jump-edit" && store_spec_node.type == eSpecType::CALL_GLOBAL) node_to_change_to = spec; else node_to_change_to = which_mode * 1000 + spec; last_node.push(which_mode * 1000 + which_node); } else if(item_hit == "x1a-edit") { switch (store_spec_node.type) { case eSpecType::FORCED_GIVE: case eSpecType::ONCE_GIVE_ITEM: case eSpecType::ONCE_GIVE_ITEM_DIALOG: case eSpecType::ONCE_GIVE_ITEM_TERRAIN: case eSpecType::ONCE_GIVE_ITEM_MONSTER: i = choose_text(STRT_ITEM,store_spec_node.ex1a,&me,"Give which item?"); break; case eSpecType::OUT_STORE: i = choose_text(STRT_ITEM,store_spec_node.ex1a,&me,"First item in store?"); break; case eSpecType::ONCE_DIALOG: case eSpecType::ONCE_DIALOG_TERRAIN: case eSpecType::ONCE_DIALOG_MONSTER: i = choose_text(STRT_BUTTON,store_spec_node.ex1a,&me,"Which button label?"); break; case eSpecType::TOWN_DESTROY_MONST: i = choose_text(STRT_MONST,store_spec_node.ex1a,&me,"Choose Which Monster:"); break; } store_spec_node.ex1a = i; me["x1a"].setTextToNum(store_spec_node.ex1a); } else if(item_hit == "x2a-edit") { switch (store_spec_node.type) { case eSpecType::FORCED_GIVE: case eSpecType::ONCE_GIVE_ITEM: case eSpecType::TOWN_PLACE_ITEM: case eSpecType::OUT_STORE: // TODO: This isn't right - it should be "number of items" or some such i = choose_text(STRT_ITEM,store_spec_node.ex2a,&me,"Give which item?"); break; case eSpecType::ONCE_DIALOG: case eSpecType::ONCE_DIALOG_TERRAIN: case eSpecType::ONCE_DIALOG_MONSTER: case eSpecType::ONCE_GIVE_ITEM_DIALOG: case eSpecType::ONCE_GIVE_ITEM_TERRAIN: case eSpecType::ONCE_GIVE_ITEM_MONSTER: i = choose_text(STRT_BUTTON,store_spec_node.ex2a,&me,"Which button label?"); break; case eSpecType::TOWN_PLACE_MONST: i = choose_text(STRT_MONST,store_spec_node.ex2a,&me,"Choose Which Monster:"); break; case eSpecType::IF_TOWN_TER_TYPE: case eSpecType::IF_OUT_TER_TYPE: case eSpecType::TOWN_CHANGE_TER: case eSpecType::TOWN_SWAP_TER: case eSpecType::OUT_CHANGE_TER: i = choose_text(STRT_TER,store_spec_node.ex2a,&me,"Which Terrain?"); break; } store_spec_node.ex2a = i; me["x2a"].setTextToNum(store_spec_node.ex2a); } else if(item_hit == "msg2-edit") { // TODO: What about msg1-edit? if(save_spec_enc(me, which_mode, which_node)) return true; if (((*store_spec_node.type).msg_label == 2) || ((*store_spec_node.type).msg_label == 4) || ((*store_spec_node.type).msg_label == 5)) { edit_dialog_text(which_mode,&store_spec_node.m1,&me); put_spec_enc_in_dlog(me, which_node); } else if (((*store_spec_node.type).msg_label == 1) || ((*store_spec_node.type).msg_label == 3)) { edit_spec_text(which_mode,&store_spec_node.m1, &store_spec_node.m2,&me); put_spec_enc_in_dlog(me, which_node); } } else if(item_hit == "pict-edit") { if(save_spec_enc(me, which_mode, which_node)) return true; i = -1; switch ((*store_spec_node.type).pic_label) { case 1: i = choose_graphic(store_spec_node.pic,PIC_DLOG,&me); break; case 2: i = choose_graphic(store_spec_node.pic,PIC_TER,&me); break; case 3: i = choose_graphic(store_spec_node.pic,PIC_MONST,&me); break; } if(i != NO_PIC) { store_spec_node.pic = i; put_spec_enc_in_dlog(me, which_node); } } else if(item_hit == "general") { if(save_spec_enc(me, which_mode, which_node) == true) return true; // TODO: I wonder if this can all be achieved without casts... if not, at least check getNodeCategory to ensure validity. i = choose_text_res("special-node-names",1,28,int(store_spec_node.type) + 1,&me,"Choose General Use Special:"); if (i >= 0) { store_spec_node.type = eSpecType(i - 1); } put_spec_enc_in_dlog(me, which_node); } else if(item_hit == "oneshot") { if(save_spec_enc(me, which_mode, which_node)) return true; i = choose_text_res("special-node-names",51,64,int(store_spec_node.type) + 1,&me,"Choose One-Shot Special:"); if (i >= 0) { store_spec_node.type = eSpecType(i - 1); store_spec_node.sd1 = -1; store_spec_node.sd2 = -1; if(store_spec_node.type == eSpecType::ONCE_DIALOG || store_spec_node.type == eSpecType::ONCE_DIALOG_TERRAIN || store_spec_node.type == eSpecType::ONCE_DIALOG_MONSTER) store_spec_node.m2 = 1; } put_spec_enc_in_dlog(me, which_node); } else if(item_hit == "affectpc") { if(save_spec_enc(me, which_mode, which_node)) return true; i = choose_text_res("special-node-names",81,107,int(store_spec_node.type) + 1,&me,"Choose Affect Party Special:"); if (i >= 0) store_spec_node.type = eSpecType(i - 1); put_spec_enc_in_dlog(me, which_node); } else if(item_hit == "ifthen") { if(save_spec_enc(me, which_mode, which_node)) return true; i = choose_text_res("special-node-names",131,156,int(store_spec_node.type) + 1,&me,"Choose If-Then Special:"); if (i >= 0) { store_spec_node.type = eSpecType(i - 1); } put_spec_enc_in_dlog(me, which_node); } else if(item_hit == "town") { if(save_spec_enc(me, which_mode, which_node)) return true; i = choose_text_res("special-node-names",171,219,int(store_spec_node.type) + 1,&me,"Choose Town Special:"); if (i >= 0) store_spec_node.type = eSpecType(i - 1); put_spec_enc_in_dlog(me, which_node); } else if(item_hit == "out") { if(save_spec_enc(me, which_mode, which_node)) return true; i = choose_text_res("special-node-names",226,230,int(store_spec_node.type) + 1,&me,"Choose Outdoor Special:"); if (i >= 0) store_spec_node.type = eSpecType(i - 1); put_spec_enc_in_dlog(me, which_node); } /*if ((item_hit >= 37) && (item_hit <= 42)) { if (cd_get_active(822,43) == 0) CDSN(822,8,0); if (cd_get_active(822,44) == 0) CDSN(822,10,0); }*/ // Might be useful, but I forget what I was thinking when I added it. if (node_to_change_to >= 0) { which_mode = node_to_change_to / 1000; which_node = node_to_change_to % 1000; if (which_mode == 0) store_spec_node = scenario.scen_specials[which_node]; if (which_mode == 1) store_spec_node = current_terrain.specials[which_node]; if (which_mode == 2) store_spec_node = town->specials[which_node]; if (store_spec_node.pic < 0) store_spec_node.pic = 0; put_spec_enc_in_dlog(me, which_node); } return true; } // mode - 0 scen 1 - out 2 - town void edit_spec_enc(short which_node,short mode) { // ignore parent in Mac version using namespace std::placeholders; // Clear the "nodes edited" stack; should already be clear, but just make sure while(!last_node.empty()) last_node.pop(); //last_node[0] = store_which_mode * 1000 + store_which_node; if (mode == 0) store_spec_node = scenario.scen_specials[which_node]; if (mode == 1) store_spec_node = current_terrain.specials[which_node]; if (mode == 2) store_spec_node = town->specials[which_node]; if (store_spec_node.pic < 0) store_spec_node.pic = 0; cDialog special("edit-special-node.xml"); auto callback = std::bind(edit_spec_enc_event_filter, _1, _2, std::ref(mode), std::ref(which_node)); special.attachClickHandlers(callback, {"okay", "cancel", "back"}); special.attachClickHandlers(callback, {"general", "oneshot", "affectpc", "ifthen", "town", "out"}); special.attachClickHandlers(callback, {"x1a-edit", "x1b-edit", "x2a-edit", "x2b-edit"}); special.attachClickHandlers(callback, {"msg1-edit", "msg2-edit", "pict-edit", "jump-edit"}); special["back"].hide(); put_spec_enc_in_dlog(special, which_node); special.run(); } short get_fresh_spec(short which_mode) { short i; cSpecial store_node; for (i = 0; i < num_specs[which_mode]; i++) { if (which_mode == 0) store_node = scenario.scen_specials[i]; if (which_mode == 1) store_node = current_terrain.specials[i]; if (which_mode == 2) store_node = town->specials[i]; if(store_node.type == eSpecType::NONE && store_node.jumpto == -1 && store_node.pic == -1) return i; } return -1; } static bool edit_spec_text_event_filter(cDialog& me, std::string item_hit, short spec_str_mode, short* str1, short* str2) { std::string str; short i; if(item_hit == "okay") { str = me["str1"].getText(); if(!str.empty()) { if(*str1 < 0) { switch(spec_str_mode) { case 0: for (i = 160; i < 260; i++) // TODO: This could overwrite a string if it's unlucky enough to start with * if (scenario.scen_strs(i)[0] == '*') { *str1 = i - 160; i = 500; } break; case 1: for (i = 10; i < 100; i++) if (current_terrain.out_strs(i)[0] == '*') { *str1 = i - 10; i = 500; } break; case 2: for (i = 20; i < 120; i++) if (town->town_strs(i)[0] == '*') { *str1 = i - 20; i = 500; } break; } if (i < 500) { giveError("There are no more free message slots.", "To free up some slots, go into Edit Town/Out/Scenario Text to clear some messages.", &me); return true; } } if(*str1 >= 0) { switch(spec_str_mode) { case 0: strcpy(scenario.scen_strs(*str1 + 160),str.c_str()); break; case 1: strcpy(current_terrain.out_strs(*str1 + 10),str.c_str()); break; case 2: strcpy(town->town_strs(*str1 + 20),str.c_str()); break; } } } str = me["str2"].getText(); if(!str.empty()) { if(*str2 < 0) { switch(spec_str_mode) { case 0: for (i = 160; i < 260; i++) if (scenario.scen_strs(i)[0] == '*') { *str2 = i - 160; i = 500; } break; case 1: for (i = 10; i < 100; i++) if (current_terrain.out_strs(i)[0] == '*') { *str2 = i - 10; i = 500; } break; case 2: for (i = 20; i < 120; i++) if (town->town_strs(i)[0] == '*') { *str2 = i - 20; i = 500; } break; } if (i < 500) { giveError("There are no more free message slots.", "To free up some slots, go into Edit Town/Out/Scenario Text to clear some messages.", &me); return true; } } if(*str2 >= 0) { switch(spec_str_mode) { case 0: strcpy(scenario.scen_strs(*str2 + 160),str.c_str()); break; case 1: strcpy(current_terrain.out_strs(*str2 + 10),str.c_str()); break; case 2: strcpy(town->town_strs(*str2 + 20),str.c_str()); break; } } } me.toast(true); } else me.toast(false); return true; } // mode 0 - scen 1 - out 2 - town void edit_spec_text(short mode,short *str1,short *str2,cDialog* parent) { using namespace std::placeholders; short num_s_strs[3] = {100,90,100}; cDialog edit("edit-special-text.xml", parent); edit.attachClickHandlers(std::bind(edit_spec_text_event_filter, _1, _2, mode, str1, str1), {"okay", "cancel"}); if (*str1 >= num_s_strs[mode]) *str1 = -1; if (*str1 >= 0){ if (mode == 0) edit["str1"].setText(scenario.scen_strs(*str1 + 160)); if (mode == 1) edit["str1"].setText(current_terrain.out_strs(*str1 + 10)); if (mode == 2) edit["str1"].setText(town->town_strs(*str1 + 20)); } if (*str2 >= num_s_strs[mode]) *str2 = -1; if (*str2 >= 0){ if (mode == 0) edit["str2"].setText(scenario.scen_strs(*str2 + 160)); if (mode == 1) edit["str2"].setText(current_terrain.out_strs(*str2 + 10)); if (mode == 2) edit["str2"].setText(town->town_strs(*str2 + 20)); } edit.run(); } static bool edit_dialog_text_event_filter(cDialog& me, std::string item_hit, short spec_str_mode, short* str1){ std::string str; short i; if(item_hit == "okay") { for (i = 0; i < 6; i++) { std::string id = "str" + std::to_string(i + 1); str = me[id].getText(); if(i == 0 && str.empty()) break; switch (spec_str_mode) { case 0: strcpy(scenario.scen_strs(*str1 + 160 + i),str.c_str()); break; case 1: strcpy(current_terrain.out_strs(*str1 + 10 + i),str.c_str()); break; case 2: strcpy(town->town_strs(*str1 + 20 + i),str.c_str()); break; } } me.toast(true); } else me.toast(false); return true; } // mode 0 - scen 1 - out 2 - town void edit_dialog_text(short mode,short *str1,cDialog* parent) { short i,j; short num_s_strs[3] = {100,90,100}; if (*str1 >= num_s_strs[mode] - 6) *str1 = -1; // first, assign the 6 strs for the dialog. if (*str1 < 0) { switch(mode) { case 0: for (i = 160; i < 260 - 6; i++) { for (j = i; j < i + 6; j++) if (scenario.scen_strs(j)[0] != '*') { j = 500; } if (j < 500) { *str1 = i - 160; i = 500; } } break; case 1: for (i = 10; i < 100 - 6; i++) { for (j = i; j < i + 6; j++) if (current_terrain.out_strs(j)[0] != '*') { j = 500; } if (j < 500) { *str1 = i - 10; i = 500; } } break; case 2: for (i = 20; i < 120 - 6; i++) { for (j = i; j < i + 6; j++) if (town->town_strs(j)[0] != '*') { j = 500; } if (j < 500) { *str1 = i - 20; i = 500; } } break; } if (*str1 >= 0) for (i = *str1; i < *str1 + 6; i++) { switch(mode) { case 0: strcpy(scenario.scen_strs(160 + i),""); break; case 1: strcpy(current_terrain.out_strs(10 + i),""); break; case 2: strcpy(town->town_strs(20 + i),""); break; } } } if (*str1 < 0) { giveError("To create a dialog, you need 6 consecutive unused messages. To free up 6 messages, select Edit Out/Town/Scenario Text from the menus.","",parent); return; } using namespace std::placeholders; cDialog edit("edit-dialog-text.xml",parent); edit.attachClickHandlers(std::bind(edit_dialog_text_event_filter, _1, _2, mode, str1), {"okay", "cancel"}); if (*str1 >= 0){ for (i = 0; i < 6; i++) { std::string id = "str" + std::to_string(i + 1); if (mode == 0) edit[id].setText(scenario.scen_strs(*str1 + 160 + i)); if (mode == 1) edit[id].setText(current_terrain.out_strs(*str1 + 10 + i)); if (mode == 2) edit[id].setText(town->town_strs(*str1 + 20 + i)); } } edit.run(); } static bool edit_special_num_event_filter(cDialog& me, std::string item_hit, short spec_mode) { short i; if(item_hit == "cancel") me.setResult(-1); else if(item_hit == "okay") { i = me["num"].getTextAsNum(); if((i < 0) || (i >= num_specs[spec_mode])) { giveError("There is no special node with that number. Legal ranges are 0 to 255 for scenario specials, 0 to 59 for outdoor specials, and 0 to 99 for town specials.","",&me); } me.setResult(i); me.toast(true); } me.toast(false); return true; } short edit_special_num(short mode,short what_start) { using namespace std::placeholders; cDialog edit("edit-special-assign.xml"); edit.attachClickHandlers(std::bind(edit_special_num_event_filter, _1, _2, mode), {"okay", "cancel"}); edit["num"].setTextToNum(what_start); edit.run(); return edit.getResult(); } static bool edit_scen_intro_event_filter(cDialog& me, std::string item_hit, eKeyMod) { short i; if(item_hit == "okay") { scenario.intro_pic = me["picnum"].getTextAsNum(); if (scenario.intro_pic > 29) { giveError("Intro picture number is out of range.","",&me); return true; } for(i = 0; i < 6; i++) { std::string id = "str" + std::to_string(i + 1); strcpy(scenario.scen_strs(4 + i), me[id].getText().c_str()); } me.toast(true); } else if(item_hit == "cancel") { me.toast(false); } else if(item_hit == "choose") { pic_num_t pic = me["picnum"].getTextAsNum(); i = choose_graphic(pic,PIC_SCEN,&me); if(i != NO_PIC) { me["picnum"].setTextToNum(i); dynamic_cast(me["pic"]).setPict(i); } } return true; } void edit_scen_intro() { short i; cDialog edit("edit-intro.xml"); edit.attachClickHandlers(edit_scen_intro_event_filter, {"okay", "cancel", "choose"}); edit["picnum"].setTextToNum(scenario.intro_pic); for(i = 0; i < 6; i++) { std::string id = "str" + std::to_string(i + 1); edit[id].setText(scenario.scen_strs(4 + i)); } dynamic_cast(edit["pic"]).setPict(scenario.intro_pic); edit.run(); } void make_cursor_sword() { set_cursor(wand_curs); }