Files
oboe/osx/scenedit/scen.keydlgs.cpp
Celtic Minstrel 41c3396aa3 Tear out most of the legacy code in the scenario editor - see below for details
- All Carbon code is gone
- Many dialogs converted; some are still left unimplemented since they still need to be converted
- Menus converted to a xib file
- The giant arrays specifying the configuration of the special node dialog for each special node type have been replaced with maps and sets.

Changes to dialogs:
- pict choice dialog can now show picts of differing types; this was required for picking a monster graphic, as monsters of all sizes need to be shown in the same dialog
- string choice dialog can set the title, and properly shows the currently selected string
- LEDs now accept font format
- Fixed LED group's calculation of its rect
- Fixed LED group crashing if it has no selection
- Tabbing between text fields now works
- Fix display of larger monster graphics in dialogs
- Fix the script element content showing in the browser preview
2014-07-12 22:13:27 -04:00

1101 lines
34 KiB
C++

#include <stack>
#include <set>
#include <map>
#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 std::string get_str(std::string list, short j);
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<short> last_node;
cSpecial store_spec_node;
short num_specs[3] = {256,60,100};
std::set<short> ex1a_choose = {19,50,55,56,57,58,59,60,182,229,-1,-1};
std::set<short> ex2a_choose = {55,56,57,-1,-1, -1,135,136,171,172, 181,192,226,-1,-1, -1,-1,-1};
std::set<short> ex1b_choose = {
13, 20, 55, 56, 57, 24, -1, -1, 80, 130,
131,132,133,137,138,140,141,142,143,145,
146,147,148,149,150,151,152,153,154,184,
188,195,186,-1, -1, -1, -1, -1, -1, 155
};
std::set<short> ex2b_choose = {
19, 50, 55, 56, 57, 58, 59, 60, 130,134,
135,136,139,144,154,-1, -1, -1, -1, -1
};
// These are maps from special node type to indices
// Those that map to index 0 are omitted, because if a key doesn't exist when fetched, it defaults to 0.
// TODO: Actually use the special node enum type here
std::map<short,short> edit_spec_stuff_done_mess = {
{1,1}, {2,1}, {6,1}, {22,3}, {23,1},
{50,1}, {51,1}, {52,1}, {53,1}, {54,1},
{55,1}, {56,1}, {57,1}, {58,1}, {59,1},
{60,1}, {61,1}, {62,1}, {63,1},
{130,1}, {134,1}, {155,1},
{200,2}, {201,2}, {202,2}, {203,2}, {204,2},
{205,2}, {206,2}, {207,2}, {208,2}, {209,2},
{210,7}, {211,8}, {212,4}, {214,5}, {215,6},
};
std::map<short,short> edit_spec_mess_mess = {
{1,1}, {2,1}, {3,1}, {5,1}, {6,1},
{11,1}, {12,1}, {17,1}, {18,1}, {19,1},
{20,1}, {25,1},
{50,1}, {51,1}, {54,1}, {55,4}, {56,4}, {57,4}, {58,5}, {59,5}, {60,5},
{61,1}, {62,1}, {63,1},
{80,1}, {81,1}, {82,1}, {83,1}, {84,1},
{85,1}, {86,1}, {87,1}, {88,1}, {89,1},
{90,1}, {91,1}, {92,1}, {93,1}, {94,1},
{95,1}, {96,1}, {97,1}, {98,1}, {99,1},
{100,1}, {101,1}, {102,1}, {103,1}, {104,1},
{105,1}, {106,1},
{170,1}, {171,1}, {172,1}, {173,1}, {174,1},
{175,1}, {176,1}, {177,1}, {178,1}, {179,1},
{180,1}, {181,1}, {182,1}, {183,1}, {188,2}, {189,2},
{190,2}, {191,1}, {192,1}, {193,1}, {194,1}, {195,1},
{200,1}, {201,1}, {202,1}, {203,1}, {204,1},
{205,1}, {206,1}, {207,1}, {208,1}, {209,1},
{210,1}, {211,1}, {212,1}, {213,1}, {214,1},
{215,1}, {216,1}, {217,1}, {218,1},
{226,1}, {227,1}, {228,1}, {229,3},
};
std::map<short,short> edit_pict_mess = {
{55,1}, {56,2}, {57,3}, {58,1}, {59,2}, {60,3},
{98,4}, {154,5}, {176,6}, {188,2}, {189,1},
};
std::map<short,short> edit_jumpto_mess = {
{7,1}, {8,1}, {9,1}, {10,1},
{55,4}, {56,4}, {57,4}, {63,2},
{130,3}, {131,3}, {132,3}, {133,3}, {134,3},
{135,3}, {136,3}, {137,3}, {138,3}, {139,3},
{140,3}, {141,3}, {142,3}, {143,3}, {144,3},
{145,3}, {146,3}, {147,3}, {148,3}, {149,3},
{150,3}, {151,3}, {152,3}, {153,3}, {154,3},
};
std::vector<pic_num_t> 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<pic_num_t> boom_pics = {0,1,2,3,4,8,16,24,32};
std::vector<pic_num_t> 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;
}
pic_num_t choose_graphic(short cur_choice,ePicType g_type,cDialog* parent) {
pic_num_t item_hit = 0;
std::vector<std::pair<pic_num_t,ePicType>> pics;
switch(g_type) {
case PIC_TER: // TODO: Increase upper limit to allow picking of the added graphics
item_hit = cPictChoice(0, 252, PIC_TER, parent).show(NO_PIC, cur_choice);
break;
case PIC_TER_ANIM: // TODO: Increase to allow picking of the added graphics
item_hit = cPictChoice(0, 13, PIC_TER_ANIM, parent).show(NO_PIC, cur_choice);
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({item_hit++, type});
}
item_hit = cPictChoice(pics, parent).show(NO_PIC, cur_choice);
break;
case PIC_DLOG: // TODO: Increase upper limit to allow picking of the added graphics
item_hit = cPictChoice(0, 31, PIC_DLOG, parent).show(NO_PIC, cur_choice);
break;
case PIC_TALK:
item_hit = cPictChoice(0, 83, PIC_TALK, parent).show(NO_PIC, cur_choice);
break;
case PIC_SCEN:
item_hit = cPictChoice(0, 29, PIC_SCEN, parent).show(NO_PIC, cur_choice);
break;
case PIC_ITEM:
item_hit = cPictChoice(0, 122, PIC_ITEM, parent).show(NO_PIC, cur_choice);
break;
case PIC_PC:
item_hit = cPictChoice(0, 35, PIC_PC, parent).show(NO_PIC, cur_choice);
break;
case PIC_FIELD:
item_hit = cPictChoice(field_pics, PIC_FIELD, parent).show(NO_PIC, cur_choice);
break;
case PIC_BOOM:
item_hit = cPictChoice(boom_pics, PIC_BOOM, parent).show(NO_PIC, cur_choice);
break;
case PIC_DLOG_LG:
item_hit = cPictChoice(lgdlog_pics, PIC_DLOG_LG, parent).show(NO_PIC, cur_choice);
break;
case PIC_FULL:
// TODO: Should this be handled at all?
break;
case PIC_MISSILE:
item_hit = cPictChoice(0, 15, PIC_MISSILE, parent).show(NO_PIC, cur_choice);
break;
case PIC_STATUS:
item_hit = cPictChoice(0, 17, PIC_STATUS, parent).show(NO_PIC, cur_choice);
break;
case PIC_SCEN_LG:
item_hit = cPictChoice(0, 3, PIC_SCEN_LG, parent).show(NO_PIC, cur_choice);
break;
case PIC_TER_MAP:
item_hit = cPictChoice(0, 418, PIC_TER_MAP, parent).show(NO_PIC, cur_choice);
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) return NO_PIC;
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;
item_hit = cPictChoice(0, last, g_type, parent).show(NO_PIC, cur_choice);
}
return item_hit;
}
short choose_text_res(std::string res_list,short first_t,short last_t,short cur_choice,cDialog* parent,const char *title) {
short item_hit;
location view_loc;
if((cur_choice < first_t) || (cur_choice > last_t))
cur_choice = first_t;
StringRsrc strings = *ResMgr::get<StringRsrc>(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, short cur_choice, cDialog* parent, const char* title) {
short item_hit;
location view_loc;
std::vector<std::string> 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);
}
bool edit_text_event_filter(cDialog& me, std::string item_hit, eKeyMod mods, 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();
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;
// ignore parent in Mac version
short item_hit;
cDialog dlog("edit-text.xml");
dlog.attachClickHandlers(std::bind(edit_text_event_filter, _1, _2, _3, 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();
}
bool edit_area_rect_event_filter(cDialog& me, std::string item_hit, eKeyMod mods, short which_str, short str_mode) {
if(item_hit == "okay") {
me.setResult(true);
me.toast();
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();
}
return true;
}
// mode 0 - out 1 - town
bool edit_area_rect_str(short which_str,short mode) {
// ignore parent in Mac version
short item_hit;
cDialog dlog("set-area-desc.xml");
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<bool>();
}
// MARK: Special node dialog
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 (edit_spec_stuff_done_mess[store_spec_node.type] == 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;
short i;
me["num"].setTextToNum(which_node);
str = get_str("special-node-names",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 (edit_spec_stuff_done_mess[store_spec_node.type]) {
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 (edit_spec_mess_mess[store_spec_node.type]) {
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 (edit_pict_mess[store_spec_node.type]) {
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",store_spec_node.type + 1);
me["x1a-lbl"].setText(str);
if(ex1a_choose.count(store_spec_node.type) == 1)
me["x1a-edit"].show();
else me["x1a-edit"].hide();
me["x1b"].setTextToNum(store_spec_node.ex1b);
str = get_str("special-x1b",store_spec_node.type + 1);
me["x1b-lbl"].setText(str);
if(ex1b_choose.count(store_spec_node.type) == 1)
me["x1b-edit"].show();
else me["x1b-edit"].hide();
me["x2a"].setTextToNum(store_spec_node.ex2a);
str = get_str("special-x2a",store_spec_node.type + 1);
me["x2a-lbl"].setText(str);
if(ex2a_choose.count(store_spec_node.type) == 1)
me["x2a-edit"].show();
else me["x2a-edit"].hide();
me["x2b"].setTextToNum(store_spec_node.ex2b);
str = get_str("special-x2b",store_spec_node.type + 1);
me["x2b-lbl"].setText(str);
if(ex2b_choose.count(store_spec_node.type) == 1)
me["x2b-edit"].show();
else me["x2b-edit"].hide();
me["jump"].setTextToNum(store_spec_node.jumpto);
switch (edit_jumpto_mess[store_spec_node.type]) {
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, eKeyMod mods, 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();
} 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();
} 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 == 13))
spec = get_fresh_spec(0);
else if((item_hit == "jump-edit") && (store_spec_node.type == 21))
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 == 13))
node_to_change_to = spec;
else if((item_hit == "jump-edit") && (store_spec_node.type == 21))
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 19: case 50: case 58: case 59: case 60:
i = choose_text(STRT_ITEM,store_spec_node.ex1a,&me,"Give which item?");
break;
case 229:
i = choose_text(STRT_ITEM,store_spec_node.ex1a,&me,"First item in store?");
break;
case 55: case 56: case 57:
i = choose_text(STRT_BUTTON,store_spec_node.ex1a,&me,"Which button label?");
break;
case 182:
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 19: case 50: case 192: case 229:
i = choose_text(STRT_ITEM,store_spec_node.ex2a,&me,"Give which item?");
break;
case 55: case 56: case 57: case 58: case 59: case 60:
i = choose_text(STRT_BUTTON,store_spec_node.ex2a,&me,"Which button label?");
break;
case 181:
i = choose_text(STRT_MONST,store_spec_node.ex2a,&me,"Choose Which Monster:");
break;
case 135: case 136: case 171: case 172: case 226:
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))
me.toast();
if ((edit_spec_mess_mess[store_spec_node.type] == 2) ||
(edit_spec_mess_mess[store_spec_node.type] == 4) ||
(edit_spec_mess_mess[store_spec_node.type] == 5)) {
edit_dialog_text(which_mode,&store_spec_node.m1,&me);
put_spec_enc_in_dlog(me, which_node);
}
else if ((edit_spec_mess_mess[store_spec_node.type] == 1) ||
(edit_spec_mess_mess[store_spec_node.type] == 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))
me.toast();
i = -1;
switch (edit_pict_mess[store_spec_node.type]) {
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)
me.toast();
i = choose_text_res("special-node-names",1,28,store_spec_node.type + 1,&me,"Choose General Use Special:");
if (i >= 0) {
store_spec_node.type = i - 1;
}
put_spec_enc_in_dlog(me, which_node);
} else if(item_hit == "oneshot") {
if(save_spec_enc(me, which_mode, which_node))
me.toast();
i = choose_text_res("special-node-names",51,64,store_spec_node.type + 1,&me,"Choose One-Shot Special:");
if (i >= 0) {
store_spec_node.type = i - 1;
store_spec_node.sd1 = -1;
store_spec_node.sd2 = -1;
if ((store_spec_node.type >= 55) && (store_spec_node.type <= 57))
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))
me.toast();
i = choose_text_res("special-node-names",81,107,store_spec_node.type + 1,&me,"Choose Affect Party Special:");
if (i >= 0) store_spec_node.type = i - 1;
put_spec_enc_in_dlog(me, which_node);
} else if(item_hit == "ifthen") {
if(save_spec_enc(me, which_mode, which_node))
me.toast();
i = choose_text_res("special-node-names",131,156,store_spec_node.type + 1,&me,"Choose If-Then Special:");
if (i >= 0) {
store_spec_node.type = i - 1;
}
put_spec_enc_in_dlog(me, which_node);
} else if(item_hit == "town") {
if(save_spec_enc(me, which_mode, which_node))
me.toast();
i = choose_text_res("special-node-names",171,219,store_spec_node.type + 1,&me,"Choose Town Special:");
if (i >= 0) store_spec_node.type = i - 1;
put_spec_enc_in_dlog(me, which_node);
} else if(item_hit == "out") {
if(save_spec_enc(me, which_mode, which_node))
me.toast();
i = choose_text_res("special-node-names",226,230,store_spec_node.type + 1,&me,"Choose Outdoor Special:");
if (i >= 0) store_spec_node.type = 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,cDialog* parent) {
// ignore parent in Mac version
using namespace std::placeholders;
short spec_enc_hit,i;
// 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, _3, 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 == 0) && (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, eKeyMod mods, short spec_str_mode, short* str1, short* str2) {
std::string str;
short i;
me.toast();
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;
}
}
}
}
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 item_hit;
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, _3, 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, eKeyMod mods, short spec_str_mode, short* str1){
std::string str;
short i;
me.toast();
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;
}
}
}
return true;
}
// mode 0 - scen 1 - out 2 - town
void edit_dialog_text(short mode,short *str1,cDialog* parent) {
short i,j,item_hit;
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, _3, 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, eKeyMod mods, short spec_mode) {
short i;
me.toast();
if(item_hit == "cancel") me.setResult<short>(-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);
}
return true;
}
short edit_special_num(short mode,short what_start) {
using namespace std::placeholders;
short item_hit;
cDialog edit("edit-special-assign.xml");
edit.attachClickHandlers(std::bind(edit_special_num_event_filter, _1, _2, _3, mode), {"okay", "cancel"});
edit["num"].setTextToNum(what_start);
edit.run();
return edit.getResult<short>();
}
static bool edit_scen_intro_event_filter(cDialog& me, std::string item_hit, eKeyMod mods) {
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();
} else if(item_hit == "cancel") {
me.toast();
} else if(item_hit == "choose") {
i = me["picnum"].getTextAsNum();
i = choose_graphic(i,PIC_SCEN,&me);
if(i < NO_PIC) {
me["picnum"].setTextToNum(i);
dynamic_cast<cPict&>(me["pic"]).setPict(i);
}
}
return true;
}
void edit_scen_intro() {
short i,item_hit;
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<cPict&>(edit["pic"]).setPict(scenario.intro_pic);
edit.run();
}
void make_cursor_sword() {
set_cursor(wand_curs);
}