Implement customizable background patterns to be displayed behind the game interface based on which town/sector the player is in and whether they are in combat mode, with cascading defaults.

- All the hard-coded background changes are no longer present and not even preserved.
This commit is contained in:
2015-01-26 18:39:35 -05:00
parent a3c998eaad
commit 91c52fca77
19 changed files with 239 additions and 49 deletions

View File

@@ -609,24 +609,27 @@ void put_background() {
else if(overall_mode == MODE_RESTING)
bg_pict = bg[4];
else if(is_out()) {
if(univ.party.outdoor_corner.x >= 7)
bg_pict = bg[0];
else bg_pict = bg[10];
}
else if(is_combat()) {
if(univ.party.outdoor_corner.x >= 7)
bg_pict = bg[2];
else bg_pict = bg[4];
}
else {
if(univ.town->lighting_type > 0) {
if(univ.party.outdoor_corner.x >= 7)
bg_pict = bg[1];
else bg_pict = bg[9];
}
else if((univ.party.outdoor_corner.x >= 7) && (univ.town.num != 21)) // TODO: What's so special about town 21?
bg_pict = bg[8];
else bg_pict = bg[13];
if(univ.out->bg_out >= 0)
bg_pict = bg[univ.out->bg_out];
else bg_pict = bg[univ.scenario.bg_out];
} else if(is_combat()) {
if(which_combat_type == 1 && univ.town->bg_fight >= 0) // TODO: Verify this means town combat
bg_pict = bg[univ.town->bg_fight];
else if(univ.out->bg_fight >= 0)
bg_pict = bg[univ.out->bg_fight];
else bg_pict = bg[univ.scenario.bg_fight];
} else if(univ.town->lighting_type != LIGHT_NORMAL) {
if(univ.town->bg_town >= 0)
bg_pict = bg[univ.town->bg_town];
else if(univ.out->bg_dungeon >= 0)
bg_pict = bg[univ.out->bg_dungeon];
else bg_pict = bg[univ.scenario.bg_dungeon];
} else {
if(univ.town->bg_town >= 0)
bg_pict = bg[univ.town->bg_town];
else if(univ.out->bg_town >= 0)
bg_pict = bg[univ.out->bg_town];
else bg_pict = bg[univ.scenario.bg_town];
}
tileImage(mainPtr, rectangle(mainPtr), bg_pict);
}

View File

@@ -149,6 +149,7 @@ cOutdoors::cOutdoors(cScenario& scenario, bool init_strings) : scenario(scenario
short i,j;
location d_loc(100,0);;
location locs[4] = {loc(8,8),loc(32,8),loc(8,32),loc(32,32)};
bg_out = bg_fight = bg_town = bg_dungeon = -1;
for(i = 0; i < 48; i++)
for(j = 0; j < 48; j++) {

View File

@@ -78,6 +78,7 @@ public:
bool special_spot[48][48];
eAmbientSound ambient_sound;
snd_num_t out_sound;
int bg_out, bg_fight, bg_town, bg_dungeon;
explicit cOutdoors(cScenario& scenario, bool init_strings = false);
void append(legacy::outdoor_record_type& old);

View File

@@ -60,6 +60,10 @@ cScenario::cScenario(bool init_strings) {
where_start.x = 24;
where_start.y = 24;
out_start = where_start;
bg_out = 10;
bg_fight = 4;
bg_town = 13;
bg_dungeon = 9;
for(i = 0; i < 10; i++) {
town_to_add_to[i] = -1;
}

View File

@@ -49,6 +49,7 @@ public:
void destroy_terrain();
public:
unsigned short difficulty,intro_pic,default_ground;
int bg_out, bg_fight, bg_town, bg_dungeon;
short intro_mess_pic;
location where_start,out_sec_start,out_start;
size_t which_town_start;

View File

@@ -107,6 +107,7 @@ cTown::cTown(cScenario& scenario, bool init_strings) : scenario(scenario) {
specials[i] = cSpecial();
}
difficulty = 0;
bg_town = bg_fight = -1;
strong_barriers = defy_scrying = defy_mapping = is_hidden = false;
for(i = 0; i < 60; i++) {
talking.talk_nodes[i].personality = -1;

View File

@@ -70,6 +70,7 @@ public:
cField() : type(FIELD_DISPEL) {}
};
short town_chop_time,town_chop_key;
int bg_town, bg_fight;
cWandering wandering[4];
location wandering_locs[4];
location special_locs[50];

View File

@@ -39,6 +39,7 @@ cButton::cButton(cDialog* parent) :
cControl(CTRL_BTN,*parent),
wrapLabel(false),
type(BTN_REG),
textClr(parent->getDefTextClr()),
fromList("none") {}
cButton::cButton(cDialog* parent,eControlType t) :
@@ -73,6 +74,7 @@ void cButton::draw(){
if(type == BTN_TINY) {
textMode = eTextMode::LEFT_TOP;
to_rect.left += 18;
style.colour = textClr;
} else if(type == BTN_PUSH) {
to_rect.top += 34;
}
@@ -100,13 +102,12 @@ short cButton::getFormat(eFormat prop) throw(xUnsupportedProp){
else throw xUnsupportedProp(prop);
}
void cButton::setColour(sf::Color) throw(xUnsupportedProp) {
// TODO: Colour is not supported
void cButton::setColour(sf::Color clr) throw(xUnsupportedProp) {
textClr = clr;
}
sf::Color cButton::getColour() throw(xUnsupportedProp) {
// TODO: Colour is not supported
return sf::Color();
return textClr;
}
// Indices within the buttons array.
@@ -187,8 +188,7 @@ cLed::cLed(cDialog* parent) :
cButton(parent,CTRL_LED),
state(led_off),
textFont(FONT_BOLD),
textSize(10),
color(parent->getDefTextClr()) {
textSize(10) {
type = BTN_LED;
}
@@ -254,7 +254,7 @@ void cLed::draw(){
to_rect.right = to_rect.left + 14;
to_rect.bottom = to_rect.top + 10;
rect_draw_some_item(buttons[btnGW[BTN_LED]],from_rect,*inWindow,to_rect);
style.colour = parent->getDefTextClr();
style.colour = textClr;
to_rect.right = frame.right;
to_rect.left = frame.left + 18; // Possibly could be 20
win_draw_string(*inWindow,to_rect,lbl,eTextMode::LEFT_TOP,style);

View File

@@ -87,6 +87,8 @@ private:
std::string fromList;
static rectangle btnRects[13][2];
protected:
/// The button's text colour; only used by LED and tiny buttons
sf::Color textClr;
/// The index in buttons of the texture for each button type.
static size_t btnGW[14];
/// The textures that hold the graphics for the buttons.
@@ -129,7 +131,6 @@ public:
private:
eLedState state;
eFont textFont;
sf::Color color;
short textSize;
static rectangle ledRects[3][2];
focus_callback_t onFocus;

View File

@@ -294,9 +294,15 @@ sf::Color cDialog::parseColor(string what){
sf::Color clr;
if(what[0] == '#'){
unsigned int r,g,b;
if(sscanf(what.c_str(),"#%2x%2x%2x",&r,&g,&b) < 3)
if(sscanf(what.c_str(),"#%2x%2x%2x",&r,&g,&b) < 3) {
if(sscanf(what.c_str(),"#%1x%1x%1x",&r,&g,&b) < 3)
throw -1;
else {
r *= 0x11;
g *= 0x11;
b *= 0x11;
}
}
clr.r = r, clr.g = g, clr.b = b;
}else if(what == "black")
clr.r = 0x00, clr.g = 0x00, clr.b = 0x00;
@@ -384,6 +390,16 @@ template<> pair<string,cButton*> cDialog::parse(Element& who /*button*/){
p.second->setBtnType(BTN_TRAIT);
else if(val == "push")
p.second->setBtnType(BTN_PUSH);
}else if(name == "color" || name == "colour"){
std::string val;
attr->GetValue(&val);
sf::Color clr;
try{
clr = parseColor(val);
}catch(int){
throw xBadVal("button",name,val,attr->Row(),attr->Column(),fname);
}
p.second->setColour(clr);
}else if(name == "def-key"){
attr->GetValue(&keyMain);
foundKey = true;
@@ -424,11 +440,7 @@ template<> pair<string,cButton*> cDialog::parse(Element& who /*button*/){
}
p.second->attachKey(theKey);
}
if(width > 0 || height > 0) {
// TODO: What if width is set but height isn't?
frame.right = frame.left + width;
frame.bottom = frame.top + height;
}else switch(p.second->getBtnType()){
switch(p.second->getBtnType()){
case BTN_SM:
frame.right = frame.left + 23;
frame.bottom = frame.top + 23;
@@ -459,6 +471,10 @@ template<> pair<string,cButton*> cDialog::parse(Element& who /*button*/){
frame.right = frame.left + 63;
frame.bottom = frame.top + 23;
}
if(width > 0)
frame.right = frame.left + width;
if(height > 0)
frame.bottom = frame.top + height;
p.second->setBounds(frame);
string content;
for(node = node.begin(&who); node != node.end(); node++){
@@ -575,7 +591,7 @@ template<> pair<string,cLed*> cDialog::parse(Element& who /*LED*/){
p.second->setFormat(TXT_FONT, FONT_BOLD);
else if(val == "maidenword")
p.second->setFormat(TXT_FONT, FONT_MAIDWORD);
else throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname);
else throw xBadVal("led",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "size"){
std::string val;
attr->GetValue(&val);
@@ -585,7 +601,7 @@ template<> pair<string,cLed*> cDialog::parse(Element& who /*LED*/){
p.second->setFormat(TXT_SIZE, 10);
else if(val == "title")
p.second->setFormat(TXT_SIZE, 18);
else throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname);
else throw xBadVal("led",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "color" || name == "colour"){
std::string val;
attr->GetValue(&val);
@@ -593,7 +609,7 @@ template<> pair<string,cLed*> cDialog::parse(Element& who /*LED*/){
try{
clr = parseColor(val);
}catch(int){
throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname);
throw xBadVal("led",name,val,attr->Row(),attr->Column(),fname);
}
p.second->setColour(clr);
}else if(name == "top"){

View File

@@ -2148,8 +2148,9 @@ void edit_item_placement() {
shortcut_dlg.run();
}
static bool save_scen_details(cDialog& me) {
static bool save_scen_details(cDialog& me, std::string, eKeyMod) {
short i;
if(!me.toast(true)) return true;
{
cLedGroup& difficulty = dynamic_cast<cLedGroup&>(me["difficulty"]);
@@ -2165,6 +2166,10 @@ static bool save_scen_details(cDialog& me) {
scenario.who_wrote[1] = me["who2"].getText().substr(0, 60);
scenario.contact_info = me["contact"].getText().substr(0, 256);
scenario.campaign_id = me["cpnid"].getText();
scenario.bg_out = boost::lexical_cast<int>(me["bg-out"].getText().substr(10));
scenario.bg_town = boost::lexical_cast<int>(me["bg-town"].getText().substr(10));
scenario.bg_dungeon = boost::lexical_cast<int>(me["bg-dungeon"].getText().substr(13));
scenario.bg_fight = boost::lexical_cast<int>(me["bg-fight"].getText().substr(11));
return true;
}
@@ -2178,17 +2183,40 @@ static void put_scen_details_in_dlog(cDialog& me) {
me["who2"].setText(scenario.who_wrote[1]);
me["contact"].setText(scenario.contact_info);
me["cpnid"].setText(scenario.campaign_id);
me["bg-out"].setText("Outdoors: " + std::to_string(scenario.bg_out));
me["bg-town"].setText("In towns: " + std::to_string(scenario.bg_town));
me["bg-dungeon"].setText("In dungeons: " + std::to_string(scenario.bg_dungeon));
me["bg-fight"].setText("In combat: " + std::to_string(scenario.bg_fight));
}
static bool edit_scen_details_event_filter(cDialog& me, std::string, eKeyMod) {
if(save_scen_details(me))
me.toast(true);
static bool edit_scen_default_bgs(cDialog& me, std::string which, eKeyMod) {
int bg_i = 0, idx_i = 0;
if(which == "bg-out" || which == "bg-town")
idx_i = 10;
else if(which == "bg-dungeon")
idx_i = 13;
else if(which == "bg-fight")
idx_i = 11;
else return true;
bg_i = boost::lexical_cast<int>(me[which].getText().substr(idx_i));
bg_i = choose_background(bg_i, &me);
std::string lbl;
if(which == "bg-out")
lbl = "Outdoors";
else if(which == "bg-town")
lbl = "In towns";
else if(which == "bg-dungeon")
lbl = "In dungeons";
else if(which == "bg-fight")
lbl = "In combat";
me[which].setText(lbl + ": " + std::to_string(bg_i));
return true;
}
void edit_scen_details() {
cDialog info_dlg("edit-scenario-details");
info_dlg["okay"].attachClickHandler(edit_scen_details_event_filter);
info_dlg["okay"].attachClickHandler(save_scen_details);
info_dlg.attachClickHandlers(edit_scen_default_bgs, {"bg-out", "bg-town", "bg-dungeon", "bg-fight"});
put_scen_details_in_dlog(info_dlg);

View File

@@ -50,6 +50,46 @@ bool cre(short val,short min,short max,std::string text1,std::string text2,cDial
return false;
}
short choose_background(short cur_choice, cDialog* parent) {
cDialog bg_dlg("choose-bg",parent);
auto get_selected = [&]() -> short {
std::string sel = dynamic_cast<cLedGroup&>(bg_dlg["group"]).getSelected();
if(sel.empty()) return -1;
return boost::lexical_cast<int>(sel.substr(3)) - 1;
};
auto set_colour_for = [&](int which) {
sf::Color to = sf::Color::Black;
if(which == 2)
to = sf::Color::Red;
else if(which == 3)
to = {0x00, 0x00, 0x80};
else if(which == 11)
to = {0xC0, 0x40, 0xFF};
else if(which <= 5 || which == 7 || which == 9 || which == 15)
to = sf::Color::White;
bg_dlg["title"].setColour(to);
for(int i = 0; i < 21; i++)
bg_dlg["led" + std::to_string(i + 1)].setColour(to);
};
bg_dlg["done"].attachClickHandler(std::bind(&cDialog::toast, &bg_dlg, true));
bg_dlg["cancel"].attachClickHandler(std::bind(&cDialog::toast, &bg_dlg, false));
bg_dlg["group"].attachFocusHandler([&](cDialog&, std::string, bool) -> bool {
int which = get_selected();
bg_dlg.setBg(which);
set_colour_for(which);
return true;
});
int sel = cur_choice;
if(sel < 0 || sel >= 21) sel = bg_dlg.getBg();
dynamic_cast<cLedGroup&>(bg_dlg["group"]).setSelected("led" + std::to_string(sel + 1));
bg_dlg.setBg(sel);
set_colour_for(sel);
bg_dlg.run();
if(bg_dlg.accepted())
return get_selected();
return cur_choice;
}
// 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;

View File

@@ -19,6 +19,7 @@ void display_strings(char *text1, char *text2,
char *title,short sound_num,short graphic_num,short graphic_type,cDialog* parent);
void put_choice_pics(short g_type);
pic_num_t choose_graphic(short cur_choice,ePicType g_type,cDialog* parent);
short choose_background(short cur_choice, cDialog* parent);
short choose_text_res(std::string res_list,short first_t,short last_t,unsigned short cur_choice,cDialog* parent,const char *title);
short choose_text(eStrType list, unsigned short cur_choice, cDialog* parent,const char* title);
void edit_text_str(short which_str,short mode);

View File

@@ -507,6 +507,10 @@ static bool outdoor_details_event_filter(cDialog& me, std::string, eKeyMod) {
if(!me.toast(true)) return true;
current_terrain->out_name = me["name"].getText();
current_terrain->comment = me["comment"].getText();
current_terrain->bg_out = me["bg-out"].getTextAsNum();
current_terrain->bg_fight = me["bg-fight"].getTextAsNum();
current_terrain->bg_town = me["bg-town"].getTextAsNum();
current_terrain->bg_dungeon = me["bg-dungeon"].getTextAsNum();
return true;
}
@@ -518,6 +522,10 @@ void outdoor_details() {
out_dlg["loc"].setText(str_out.str());
out_dlg["comment"].setText(current_terrain->comment);
out_dlg["name"].setText(current_terrain->out_name);
out_dlg["bg-out"].setTextToNum(current_terrain->bg_out);
out_dlg["bg-fight"].setTextToNum(current_terrain->bg_fight);
out_dlg["bg-town"].setTextToNum(current_terrain->bg_town);
out_dlg["bg-dungeon"].setTextToNum(current_terrain->bg_dungeon);
dynamic_cast<cLedGroup&>(out_dlg["ambient"]).setSelected("snd" + std::to_string(int(current_terrain->ambient_sound) + 1));
out_dlg["ambient"].attachFocusHandler([](cDialog& me, std::string, bool) -> bool {
cLedGroup& lg = dynamic_cast<cLedGroup&>(me["ambient"]);
@@ -536,6 +544,19 @@ void outdoor_details() {
current_terrain->ambient_sound = choice;
return true;
});
out_dlg.attachClickHandlers([](cDialog& me, std::string which, eKeyMod) -> bool {
std::string fld = which.replace(0, 4, "bg");
int bg_i = me[fld].getTextAsNum();
bg_i = choose_background(bg_i, &me);
me[fld].setTextToNum(bg_i);
return true;
}, {"pick-out", "pick-fight", "pick-town", "pick-dungeon"});
using namespace std::placeholders;
auto focus_handler = std::bind(check_range_msg, _1, _2, _3, -1, 21, _4, "-1 to use scenario default");
out_dlg["bg-out"].attachFocusHandler(std::bind(focus_handler, _1, _2, _3, "Outdoors Background"));
out_dlg["bg-fight"].attachFocusHandler(std::bind(focus_handler, _1, _2, _3, "Combat Background"));
out_dlg["bg-town"].attachFocusHandler(std::bind(focus_handler, _1, _2, _3, "Default Town Background"));
out_dlg["bg-dungeon"].attachFocusHandler(std::bind(focus_handler, _1, _2, _3, "Default Dungeon Background"));
out_dlg.run();
}
@@ -787,6 +808,8 @@ static bool save_advanced_town(cDialog& me, std::string, eKeyMod) {
town->spec_on_entry = me["onenter"].getTextAsNum();
town->spec_on_entry_if_dead = me["onenterdead"].getTextAsNum();
town->spec_on_hostile = me["onhostile"].getTextAsNum();
town->bg_town = me["bg-town"].getTextAsNum();
town->bg_fight = me["bg-fight"].getTextAsNum();
town->is_hidden = dynamic_cast<cLed&>(me["hidden"]).getState() != led_off;
town->defy_mapping = dynamic_cast<cLed&>(me["nomap"]).getState() != led_off;
town->defy_scrying = dynamic_cast<cLed&>(me["noscry"]).getState() != led_off;
@@ -805,6 +828,8 @@ static void put_advanced_town_in_dlog(cDialog& me) {
me["onenter"].setTextToNum(town->spec_on_entry);
me["onenterdead"].setTextToNum(town->spec_on_entry_if_dead);
me["onhostile"].setTextToNum(town->spec_on_hostile);
me["bg-town"].setTextToNum(town->bg_town);
me["bg-fight"].setTextToNum(town->bg_fight);
dynamic_cast<cLed&>(me["hidden"]).setState(town->is_hidden ? led_red : led_off);
dynamic_cast<cLed&>(me["nomap"]).setState(town->defy_mapping ? led_red : led_off);
dynamic_cast<cLed&>(me["noscry"]).setState(town->defy_scrying ? led_red : led_off);
@@ -842,6 +867,17 @@ void edit_advanced_town() {
town_dlg.attachFocusHandlers(loc_check, {"exit1-x", "exit2-x", "exit3-x", "exit4-x"});
town_dlg.attachFocusHandlers(loc_check, {"exit1-y", "exit2-y", "exit3-y", "exit4-y"});
town_dlg.attachClickHandlers(edit_advanced_town_special, {"edit-onexit1", "edit-onexit2", "edit-onexit3", "edit-onexit4", "edit-onenter", "edit-onenterdead", "edit-onhostile"});
town_dlg.attachClickHandlers([](cDialog& me, std::string which, eKeyMod) -> bool {
std::string fld = which.replace(0, 4, "bg");
int bg_i = me[fld].getTextAsNum();
bg_i = choose_background(bg_i, &me);
me[fld].setTextToNum(bg_i);
return true;
}, {"pick-fight", "pick-town"});
using namespace std::placeholders;
auto focus_handler = std::bind(check_range_msg, _1, _2, _3, -1, 21, _4, "-1 to use scenario default");
town_dlg["bg-fight"].attachFocusHandler(std::bind(focus_handler, _1, _2, _3, "Combat Background"));
town_dlg["bg-town"].attachFocusHandler(std::bind(focus_handler, _1, _2, _3, "Town Background"));
put_advanced_town_in_dlog(town_dlg);

View File

@@ -101,10 +101,10 @@ void init_graph_tool(){
bg_rects[0] = bg_rects[1] = bg_rects[18] = map_pat_rects[7] = tmp_rect;
bg_rects[0].right -= 32;
bg_rects[0].bottom -= 32;
bg_rects[1].left -= 32;
bg_rects[1].left += 32;
bg_rects[1].bottom -= 32;
bg_rects[18].right -= 32;
bg_rects[18].top -= 32;
bg_rects[18].top += 32;
map_pat_rects[7].left += 32;
map_pat_rects[7].top += 32;
tmp_rect.offset(0, 64);