Add a new spell pattern picker.
The picker is used in the special node dialog and also in monster abilities. Some changes were made to the game as well: * If the rotatable wall is used for a field missile or touch ability, there's no longer an option for the designer to pick an orientation. Instead, it behaves like the rotatable wall in a radiate field ability, selecting an orientation based on the creature's facing direction. * The magic values sent to place_spell_pattern for direct damage were rearranged to match the order of the eDamageType enum. This should have no effect, since the core place_spell_pattern function is only called by the various wrapper overloads. It also simplifies the code quite a bit. * The Protective Circle spell pattern is now exposed to the place patten special nodes. It can be used as just a radius 4 circle, but the effect of different layers of fields can also be obtained by specifying a field type or damage type of -1. There is also a change to the dialog engine: * Calling setText() also implicitly calls recalcRect()
This commit is contained in:
@@ -1336,7 +1336,7 @@ static bool edit_monst_abil_detail(cDialog& me, std::string hit, cMonster& monst
|
||||
abil_dlg["pick-strength"].attachClickHandler([&](cDialog& me,std::string,eKeyMod) -> bool {
|
||||
save_monst_abil_detail(me, abil, abil_params);
|
||||
int i = abil_params.gen.strength;
|
||||
i = choose_text(STRT_SPELL_PAT, i, &me, "Which spell pattern?");
|
||||
i = choose_pattern(i, &me, false);
|
||||
abil_params.gen.strength = i;
|
||||
fill_monst_abil_detail(me, monst, abil, abil_params);
|
||||
return true;
|
||||
@@ -1354,7 +1354,7 @@ static bool edit_monst_abil_detail(cDialog& me, std::string hit, cMonster& monst
|
||||
abil_dlg["pick-pat"].attachClickHandler([&](cDialog& me,std::string,eKeyMod) -> bool {
|
||||
save_monst_abil_detail(me, abil, abil_params);
|
||||
int i = abil_params.radiate.pat;
|
||||
i = choose_text(STRT_SPELL_PAT, i, &me, "Which spell pattern?");
|
||||
i = choose_pattern(i, &me, false);
|
||||
abil_params.radiate.pat = eSpellPat(i);
|
||||
fill_monst_abil_detail(me, monst, abil, abil_params);
|
||||
return true;
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include "dialogxml/dialogs/3choice.hpp"
|
||||
#include "dialogxml/dialogs/strchoice.hpp"
|
||||
#include "dialogxml/dialogs/pictchoice.hpp"
|
||||
#include "dialogxml/widgets/tilemap.hpp"
|
||||
#include "fileio/resmgr/res_dialog.hpp"
|
||||
#include "fileio/resmgr/res_strings.hpp"
|
||||
#include "spell.hpp"
|
||||
@@ -165,6 +166,129 @@ short choose_background(short cur_choice, cDialog* parent) {
|
||||
return cur_choice;
|
||||
}
|
||||
|
||||
static void set_pattern(cTilemap& map, const effect_pat_type& pat) {
|
||||
std::string id;
|
||||
map.forEach([&id](std::string ctrl_id, cControl&) {
|
||||
if(ctrl_id.size() > 4)
|
||||
id = ctrl_id.substr(0, ctrl_id.size() - 5);
|
||||
});
|
||||
for(int x = 0; x < 9; x++) {
|
||||
for(int y = 0; y < 9; y++) {
|
||||
auto& pic = map.getChild(id, x, y);
|
||||
int effect = pat[y][x];
|
||||
sf::Color clr = sf::Color::Black;
|
||||
if(effect == 0xffff) {
|
||||
clr = sf::Color::White;
|
||||
} else if(effect >= 50) {
|
||||
eDamageType type = eDamageType::MARKED;
|
||||
unsigned short dice = (effect - 50) % 40;
|
||||
if(dice <= 30 && effect <= 400) {
|
||||
type = eDamageType((effect - 50) / 40);
|
||||
}
|
||||
switch(type) {
|
||||
case eDamageType::WEAPON: clr = Colours::MAROON; break;
|
||||
case eDamageType::FIRE: clr = Colours::RED; break;
|
||||
case eDamageType::POISON: clr = Colours::GREEN; break;
|
||||
case eDamageType::MAGIC: clr = Colours::PURPLE; break;
|
||||
case eDamageType::UNBLOCKABLE: clr = Colours::LIGHT_BLUE; break;
|
||||
case eDamageType::COLD: clr = Colours::BLUE; break;
|
||||
case eDamageType::UNDEAD: clr = Colours::GREY; break;
|
||||
case eDamageType::DEMON: clr = Colours::ORANGE; break;
|
||||
case eDamageType::SPECIAL: clr = Colours::FUCHSIA; break;
|
||||
case eDamageType::MARKED: break;
|
||||
}
|
||||
} else if(effect > 0) {
|
||||
auto type = eFieldType(effect);
|
||||
switch(type) {
|
||||
case SPECIAL_EXPLORED: case SPECIAL_ROAD: case SPECIAL_SPOT:
|
||||
case SFX_SMALL_BLOOD: case SFX_MEDIUM_BLOOD: case SFX_LARGE_BLOOD:
|
||||
case SFX_SMALL_SLIME: case SFX_LARGE_SLIME: case SFX_ASH:
|
||||
case SFX_BONES: case SFX_RUBBLE: break;
|
||||
case WALL_FORCE: clr = Colours::BLUE; break;
|
||||
case WALL_FIRE: clr = Colours::RED; break;
|
||||
case FIELD_ANTIMAGIC: clr = Colours::GREEN; break;
|
||||
case CLOUD_STINK: clr = Colours::OLIVE; break;
|
||||
case WALL_ICE: clr = Colours::AQUA; break;
|
||||
case WALL_BLADES: clr = Colours::GREY; break;
|
||||
case CLOUD_SLEEP: clr = Colours::LIGHT_BLUE; break;
|
||||
case OBJECT_BLOCK: clr = Colours::MAROON; break;
|
||||
case FIELD_WEB: clr = Colours::WHITE; break;
|
||||
case OBJECT_CRATE: clr = Colours::MAROON; break;
|
||||
case OBJECT_BARREL: clr = Colours::MAROON; break;
|
||||
case BARRIER_FIRE: clr = Colours::DARK_RED; break;
|
||||
case BARRIER_FORCE: clr = Colours::DARK_BLUE; break;
|
||||
case FIELD_QUICKFIRE: clr = Colours::ORANGE; break;
|
||||
case BARRIER_CAGE: clr = Colours::LIGHT_GREEN; break;
|
||||
case FIELD_DISPEL: clr = Colours::PINK; break;
|
||||
case FIELD_SMASH: clr = Colours::YELLOW; break;
|
||||
}
|
||||
}
|
||||
pic.setColour(clr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
short choose_pattern(short cur_choice, cDialog* parent, bool expandRotatable) {
|
||||
cDialog pat_dlg(*ResMgr::dialogs.get("choose-pattern"), parent);
|
||||
pat_dlg.attachClickHandlers([](cDialog& me, std::string item_hit, eKeyMod) {
|
||||
me.toast(item_hit == "done");
|
||||
return true;
|
||||
}, {"done", "cancel"});
|
||||
static std::vector<int> all_pats;
|
||||
if(all_pats.empty()) {
|
||||
all_pats.resize(PAT_WALL + 1);
|
||||
std::iota(all_pats.begin(), all_pats.end(), 0);
|
||||
all_pats.push_back(PAT_PROT);
|
||||
}
|
||||
std::vector<int> choices;
|
||||
int i = 1;
|
||||
for(auto pat_id : all_pats) {
|
||||
std::string id = "pic" + std::to_string(i++);
|
||||
auto& pat = cPattern::get_builtin(eSpellPat(pat_id));
|
||||
std::string id2 = id;
|
||||
id2.replace(0, 3, "name");
|
||||
pat_dlg[id2].setText(pat.name);
|
||||
if(pat.rotatable) {
|
||||
if(!expandRotatable) {
|
||||
choices.push_back(pat_id);
|
||||
set_pattern(dynamic_cast<cTilemap&>(pat_dlg[id]), pat.patterns[0]);
|
||||
} else for(int j = 0; j < pat.patterns.size(); j++) {
|
||||
choices.push_back(pat_id + j);
|
||||
if(j > 0) id = "pic" + std::to_string(i++);
|
||||
set_pattern(dynamic_cast<cTilemap&>(pat_dlg[id]), pat.patterns[j]);
|
||||
}
|
||||
} else {
|
||||
choices.push_back(pat_id);
|
||||
set_pattern(dynamic_cast<cTilemap&>(pat_dlg[id]), pat.pattern);
|
||||
}
|
||||
}
|
||||
while(i <= 18) {
|
||||
std::string id = "pic" + std::to_string(i++);
|
||||
pat_dlg[id].hide();
|
||||
id.replace(0, 3, "led");
|
||||
pat_dlg[id].hide();
|
||||
id.replace(0, 3, "name");
|
||||
pat_dlg[id].hide();
|
||||
}
|
||||
pat_dlg["left"].hide();
|
||||
pat_dlg["right"].hide();
|
||||
auto& group = dynamic_cast<cLedGroup&>(pat_dlg["group"]);
|
||||
auto iter = std::lower_bound(choices.rbegin(), choices.rend(), cur_choice, std::greater<int>());
|
||||
if(iter == choices.rend()) {
|
||||
group.setSelected("led1");
|
||||
} else {
|
||||
int idx = std::distance(choices.rbegin(), iter);
|
||||
std::string id = "led" + std::to_string(9 - idx);
|
||||
group.setSelected(id);
|
||||
}
|
||||
pat_dlg.run();
|
||||
if(pat_dlg.accepted()) {
|
||||
auto selected = group.getSelected();
|
||||
return choices[std::stoi(selected.substr(3)) - 1];
|
||||
}
|
||||
return cur_choice;
|
||||
}
|
||||
|
||||
// TODO: I have two functions that do this. (The other one is pick_picture.)
|
||||
extern std::string scenario_temp_dir_name;
|
||||
pic_num_t choose_graphic(short cur_choice,ePicType g_type,cDialog* parent, bool static_only) {
|
||||
@@ -415,9 +539,6 @@ short choose_text(eStrType list, unsigned short cur_choice, cDialog* parent, std
|
||||
case STRT_STATUS:
|
||||
strings = {"Alive", "Dead", "Dust", "Petrified", "Fled Outdoor Combat", "Absent", "Deleted"};
|
||||
break;
|
||||
case STRT_SPELL_PAT:
|
||||
strings = {"Single Space", "3x3 Square", "2x2 Square", "3x3 Open Square", "Radius 2 Circle", "Radius 3 Circle", "Cross", "Rotateable 2x8 Wall"};
|
||||
break;
|
||||
case STRT_SUMMON:
|
||||
strings = {"0 - no summon (weak)", "1 - weak summoning", "2 - summoning", "3 - major summoning", "4 - no summon (unique/powerful"};
|
||||
break;
|
||||
@@ -970,7 +1091,6 @@ static bool edit_spec_enc_value(cDialog& me, std::string item_hit, node_stack_t&
|
||||
case eSpecPicker::STRING: {
|
||||
std::string title;
|
||||
switch(fcn.str_type) {
|
||||
case STRT_SPELL_PAT: title = "Which spell pattern?"; break;
|
||||
case STRT_ITEM: title = "Which item?"; break;
|
||||
case STRT_SPEC_ITEM: title = "Which special item?"; break;
|
||||
case STRT_TER: title = "Which terrain?"; break;
|
||||
@@ -1140,6 +1260,7 @@ static bool edit_spec_enc_value(cDialog& me, std::string item_hit, node_stack_t&
|
||||
store = sdf.y;
|
||||
me[otherField].setTextToNum(sdf.x);
|
||||
} break;
|
||||
case eSpecPicker::SPELL_PATTERN: store = choose_pattern(val, &me, fcn.augmented); break;
|
||||
case eSpecPicker::FIELD: store = choose_field_type(val, &me, fcn.augmented); break;
|
||||
case eSpecPicker::DAMAGE_TYPE: store = choose_damage_type(val, &me, true); break;
|
||||
case eSpecPicker::EXPLOSION: store = choose_boom_type(val, &me); break;
|
||||
|
@@ -13,6 +13,7 @@ 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,std::string title);
|
||||
short choose_text_editable(std::vector<std::string>& list, short cur_choice, cDialog* parent, std::string title);
|
||||
short choose_pattern(short cur_choice, cDialog* parent, bool expandRotatable);
|
||||
bool edit_text_str(short which_str,eStrMode mode);
|
||||
bool edit_spec_enc(short which_node,short mode,cDialog* parent);
|
||||
short get_fresh_spec(short which_mode);
|
||||
|
Reference in New Issue
Block a user