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:
2025-03-04 21:46:29 -05:00
committed by Celtic Minstrel
parent 4c4c70648c
commit 628b0ee677
25 changed files with 747 additions and 450 deletions

View File

@@ -613,7 +613,7 @@ std::string uAbility::to_string(eMonstAbil key) const {
} else if(key == eMonstAbil::FIELD && gen.strength != PAT_SINGLE) {
sout << " (";
switch(eSpellPat(gen.strength)) {
case PAT_SINGLE: break;
case PAT_CURRENT: case PAT_SINGLE: break;
case PAT_SMSQ: sout << "small "; BOOST_FALLTHROUGH;
case PAT_SQ: sout << "square"; break;
case PAT_OPENSQ: sout << "open square"; break;
@@ -621,6 +621,7 @@ std::string uAbility::to_string(eMonstAbil key) const {
case PAT_RAD2: sout << "small circle"; break;
case PAT_RAD3: sout << "big circle"; break;
case PAT_WALL: sout << "line"; break;
case PAT_PROT: sout << "protective circle"; break;
}
sout << ")";
} else if(key == eMonstAbil::KILL) {

View File

@@ -11,6 +11,7 @@
#include "damage.hpp"
#include "fields.hpp"
#include "pattern.hpp"
#include "spell.hpp"
class cTagFile_Page;

View File

@@ -128,19 +128,19 @@ namespace {
.ex1a(eSpecPicker::TOGGLE);
node_properties_t S_TARGET = node_builder_t(eSpecType::TOWN_START_TARGETING)
.msg()
.ex1a(STRT_SPELL_PAT)
.ex1a(eSpecPicker::SPELL_PATTERN)
.ex2a(eSpecPicker::NODE)
.ex2b(eSpecPicker::TOGGLE)
.ex2c(eSpecPicker::TOGGLE);
node_properties_t S_FIELDS = node_builder_t(eSpecType::TOWN_SPELL_PAT_FIELD)
.msg()
.loc(eSpecField::EX1A, eSpecField::EX1B, eLocType::ACTIVE_TOWN)
.ex1c(+STRT_SPELL_PAT)
.ex1c(+eSpecPicker::SPELL_PATTERN)
.ex2a(+eSpecPicker::FIELD);
node_properties_t S_PATTERN = node_builder_t(eSpecType::TOWN_SPELL_PAT_BOOM)
.msg()
.loc(eSpecField::EX1A, eSpecField::EX1B, eLocType::ACTIVE_TOWN)
.ex1c(+STRT_SPELL_PAT)
.ex1c(+eSpecPicker::SPELL_PATTERN)
.ex2a(eSpecPicker::DAMAGE_TYPE)
.ex2c(STRT_SPELL_PAT_MODE);
node_properties_t S_WARP = node_builder_t(eSpecType::TOWN_RELOCATE_CREATURE)

View File

@@ -662,15 +662,7 @@ node_function_t operator+(eSpecPicker picker) {
if(picker == eSpecPicker::NODE || picker == eSpecPicker::MSG_PAIR || picker == eSpecPicker::MSG_SINGLE || picker == eSpecPicker::MSG_SEQUENCE) {
n.force_global = true;
}
if(picker == eSpecPicker::FIELD) {
n.augmented = true;
}
return n;
}
node_function_t operator+(eStrType str) {
node_function_t n(str);
if(str == STRT_SPELL_PAT) {
if(picker == eSpecPicker::FIELD || picker == eSpecPicker::SPELL_PATTERN) {
n.augmented = true;
}
return n;

View File

@@ -141,7 +141,7 @@ enum eStrType {
STRT_PICT, STRT_CMP, STRT_ACCUM, STRT_TRAP,
STRT_ATTITUDE, STRT_STAIR, STRT_LIGHT, STRT_CONTEXT,
STRT_SHOP, STRT_COST_ADJ, STRT_STAIR_MODE, STRT_TALK_NODE,
STRT_STATUS, STRT_SPELL_PAT, STRT_SUMMON, STRT_TALK, STRT_TALK_NODE_PERSON,
STRT_STATUS, STRT_SUMMON, STRT_TALK, STRT_TALK_NODE_PERSON,
STRT_ENCHANT, STRT_DIR, STRT_QUEST, STRT_QUEST_STATUS,
STRT_HEALING, STRT_TREASURE, STRT_MONST_STAT, STRT_POS_MODE,
STRT_DEBUG_PRINT, STRT_TARG_TYPE, STRT_TARG_MODE,
@@ -158,7 +158,7 @@ enum class eSpecPicker {
STATUS, STATUS_PARTY,
SDF, LOCATION, RECTANGLE, TOGGLE,
EVENT, ITEM_CLASS, QUEST, JOB_BOARD,
POINTER,
POINTER, SPELL_PATTERN,
};
enum class eLocType {
@@ -177,7 +177,7 @@ struct node_function_t {
bool force_global; // for eSpecPicker::NODE and eSpecPicker::MSG_*
// other pickers don't put anything in here
};
bool augmented = false; // only for eSpecPicker::FIELD and eSpecPicker::STRING with certain string types
bool augmented = false; // only for eSpecPicker::FIELD and eSpecPicker::SPELL_PATTERN
int adjust = 0; // only for eSpecPicker::STRING
eSpecField continuation = eSpecField::NONE;
std::string label() const;
@@ -197,7 +197,6 @@ private:
};
node_function_t operator+(eSpecPicker);
node_function_t operator+(eStrType);
struct node_properties_t {
eSpecType self;
@@ -280,8 +279,7 @@ private:
// +eSpecPicker::NODE means always edit a scenario node, even if the caller is a town or outdoor node.
// +eSpecPicker::MSG_* is similar always edit a scenario string, never a town or outdoor string.
// +eSpecPicker::FIELD adds the pseudo-fields Move Mountains and Dispel to the list.
// +STRT_SKILL adds read-only pseudo-skills such as "current HP" to the list
// +STRT_SPELL_PAT expands the "rotateable wall" into all its possible orientations
// +eSpecPicker::SPELL_PATTERN expands the "rotateable wall" into all its possible orientations
// More cases may be added.
#endif