The special node dictionary now supports specifying different labels or pickers based on the value of another field.

This commit is contained in:
2025-03-06 00:14:52 -05:00
committed by Celtic Minstrel
parent 246aec3253
commit b86ef8ae39
20 changed files with 416 additions and 75 deletions

View File

@@ -346,6 +346,7 @@
<ClInclude Include="..\..\..\src\scenario\scenario.hpp" />
<ClInclude Include="..\..\..\src\scenario\shop.hpp" />
<ClInclude Include="..\..\..\src\scenario\special.hpp" />
<ClInclude Include="..\..\..\src\scenario\special-conditions.hpp" />
<ClInclude Include="..\..\..\src\scenario\talking.hpp" />
<ClInclude Include="..\..\..\src\scenario\terrain.hpp" />
<ClInclude Include="..\..\..\src\scenario\terrain_abilities.hpp" />

View File

@@ -901,6 +901,9 @@
<ClInclude Include="..\..\..\src\scenario\special.hpp">
<Filter>Scenario</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\scenario\special-conditions.hpp">
<Filter>Scenario</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\scenario\shop.hpp">
<Filter>Scenario</Filter>
</ClInclude>

View File

@@ -505,6 +505,7 @@
<ClInclude Include="..\..\..\src\scenario\scenario.hpp" />
<ClInclude Include="..\..\..\src\scenario\shop.hpp" />
<ClInclude Include="..\..\..\src\scenario\special.hpp" />
<ClInclude Include="..\..\..\src\scenario\special-conditions.hpp" />
<ClInclude Include="..\..\..\src\scenario\talking.hpp" />
<ClInclude Include="..\..\..\src\scenario\terrain.hpp" />
<ClInclude Include="..\..\..\src\scenario\terrain_abilities.hpp" />

View File

@@ -925,6 +925,9 @@
<ClInclude Include="..\..\..\src\scenario\special.hpp">
<Filter>Scenario</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\scenario\special-conditions.hpp">
<Filter>Scenario</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\scenario\talking.hpp">
<Filter>Scenario</Filter>
</ClInclude>

View File

@@ -744,6 +744,7 @@
9170C5262D74237A009B6E7C /* scen.sdfpicker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = scen.sdfpicker.hpp; sourceTree = "<group>"; };
9170C5962D75EE42009B6E7C /* pattern.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = pattern.cpp; sourceTree = "<group>"; };
9170C5972D75EE42009B6E7C /* pattern.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = pattern.hpp; sourceTree = "<group>"; };
9170C5A32D79659A009B6E7C /* special-conditions.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "special-conditions.hpp"; sourceTree = "<group>"; };
9176FEC01D550EFC006EF694 /* out_legacy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = out_legacy.cpp; sourceTree = "<group>"; };
9176FEC11D550EFC006EF694 /* scen_legacy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scen_legacy.cpp; sourceTree = "<group>"; };
9176FEC41D550EFD006EF694 /* talk_legacy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = talk_legacy.cpp; sourceTree = "<group>"; };
@@ -1301,6 +1302,7 @@
91279C570F9D1253007B0D52 /* scenario.hpp */,
91FDB5771A4E71A900DE5983 /* shop.hpp */,
91279CC50F9D1A02007B0D52 /* special.hpp */,
9170C5A32D79659A009B6E7C /* special-conditions.hpp */,
91E5C7B60F9F619D00C21460 /* talking.hpp */,
91279C650F9D12D6007B0D52 /* terrain.hpp */,
9185BD9C1EA02BA20027C346 /* terrain_abilities.hpp */,

View File

@@ -10,7 +10,7 @@ Restrictions
Special if Cancel button pressed
Unused
Selection Mode
0..6 - PC, 100+ - monster (if above = 2)
Unused|0..6 - PC, 100+ - monster
Unused
Special to Jump To

View File

@@ -196,7 +196,7 @@ Unused
0 - allow, 1 - prevent
Unused
Unused
Force allow if blocked?
Unused|Force allow if blocked?
Unused
Unused
Special to Jump To
@@ -509,16 +509,16 @@ Special to Jump To
--------------------
Debug Print Numbers
Stuff Done Flag Part A
Stuff Done Flag Part B
Unused|Stuff Done Flag Part A
Unused|Stuff Done Flag Part B
Unused
Unused
Unused
Specify what to print
Unused
Number of monster, or value to print
Value to print (could be a pointer)
Value to print (could be a pointer)
Unused|Value to print (could be a pointer)|Number of monster
Unused|Value to print (could be a pointer)
Unused|Value to print (could be a pointer)
Unused
Unused
Unused
@@ -774,7 +774,7 @@ Unused
Which quest?
New Quest Status
Unused
Job Board Source / Anger (see docs)
Unused|Job Board Source|Job Board Anger
Unused
Unused
Special to Jump To

View File

@@ -465,11 +465,11 @@ Minimum allowed response
Maximum allowed response
Comparison Mode
If tests 1 and 2 both pass, call this special ...
Range lower bound (or value to compare to)
Range upper bound (or comparison method -2 .. 2)
Range lower bound|Value to compare to
Range upper bound|Comparison method
If test 1 passes but test 2 fails, call this special ...
Range lower bound (or value to compare to)
Range upper bound (or comparison method -2 .. 2)
Range lower bound|Value to compare to
Range upper bound|Comparison method
If test 2 passes but test 1 fails, call this special ...
Otherwise call this special

View File

@@ -231,7 +231,7 @@ Type of trap
Trap severity (0 .. 3)
Animation Loops (-2 for infinite)
Penalty (0 .. 100, higher is harder)
(Custom only) Special node for effect
Unused|Special node for effect
Animation FPS (-1 for default 2)
Special after trap finished

View File

@@ -6,6 +6,7 @@
//
#include "special.hpp"
#include "special-conditions.hpp"
// Note: If adding a new node type below, be sure to adjust the end point here too.
node_category_info_t CAT_AFFECT{eSpecType::SELECT_TARGET, eSpecType::UNSTORE_PC};
@@ -15,7 +16,10 @@ namespace {
.msg()
.ex1a(STRT_TARG_TYPE)
.ex1b(eSpecPicker::NODE)
.ex2a(STRT_TARG_MODE);
.ex2a(STRT_TARG_MODE)
.when(eSpecField::EX2A == 2, 1)
.ex2b()
.end();
node_properties_t S_DAMAGE = node_builder_t(eSpecType::DAMAGE)
.msg()
.ex2b(eSpecPicker::DAMAGE_TYPE)

View File

@@ -6,6 +6,7 @@
//
#include "special.hpp"
#include "special-conditions.hpp"
// Note: If adding a new node type below, be sure to adjust the end point here too.
node_category_info_t CAT_COND{eSpecType::IF_SDF, eSpecType::IF_QUEST};
@@ -111,10 +112,14 @@ namespace {
.msg1(+eSpecPicker::MSG_SINGLE)
.pict(STRT_CMP_MODE)
.ptyp(eSpecPicker::NODE)
.ex1b(STRT_CMP)
.ex1c(eSpecPicker::NODE)
.ex2b(STRT_CMP)
.ex2c(eSpecPicker::NODE);
.ex2c(eSpecPicker::NODE)
.when(eSpecField::PICT == 2, 1)
.ex1a()
.ex1b(STRT_CMP)
.ex2a()
.ex2b(STRT_CMP)
.end();
node_properties_t S_BOAT = node_builder_t(eSpecType::IF_IN_BOAT)
.ex1b(STRT_BOAT)
.ex1c(eSpecPicker::NODE);

View File

@@ -0,0 +1,98 @@
//
// special-conditions.hpp
// BoE
//
// Created by Celtic Minstrel on 2025-03-06.
//
#ifndef BOE_DATA_SPECIAL_COND_H
#define BOE_DATA_SPECIAL_COND_H
struct node_literal_t {
using value_type = short;
short operator()(const cSpecial&) const { return value; }
node_literal_t(short v) : value(v) {}
private:
short value;
};
struct node_value_t {
using value_type = eSpecField;
short operator()(const cSpecial& spec) const { return spec->*field; }
node_value_t(eSpecField fld) : field(fld) {}
private:
eSpecField field;
};
template<template<class> class P, typename A, typename B>
struct node_comparison_t {
static const bool node_expr = true;
bool operator()(const cSpecial& spec) const {
short a = lhs(spec), b = rhs(spec);
return pred(a, b);
}
node_comparison_t(A a, B b, P<short> p) : lhs(a), rhs(b), pred(p) {}
private:
A lhs;
B rhs;
P<short> pred;
};
template<typename A, typename B>
struct node_logic_t {
static const bool node_expr = true;
bool operator()(const cSpecial& spec) const {
return conjunct ? (a(spec) && b(spec)) : (a(spec) || b(spec));
}
node_logic_t(A a, B b, bool conj) : a(a), b(b), conjunct(conj) {}
private:
A a;
B b;
bool conjunct;
};
template<typename T>
struct node_negate_t {
static const bool node_expr = true;
bool operator()(const cSpecial& spec) const {
return !pred(spec);
}
node_negate_t(T p) : pred(p) {}
private:
T pred;
};
#define DEFINE_CMP(LHS, RHS, OP, OP_NAME) \
inline node_comparison_t<std::OP_NAME, LHS, RHS> operator OP(LHS::value_type a, RHS::value_type b) { \
return node_comparison_t<std::OP_NAME, LHS, RHS>{ \
LHS{a}, \
RHS{b}, \
std::OP_NAME<short>() \
}; \
}
#define DEFINE_CMPS(OP, OP_NAME) \
DEFINE_CMP(node_value_t, node_literal_t, OP, OP_NAME); \
DEFINE_CMP(node_literal_t, node_value_t, OP, OP_NAME);
DEFINE_CMPS(==, equal_to);
DEFINE_CMPS(<=, less_equal);
DEFINE_CMPS(>=, greater_equal);
DEFINE_CMPS(!=, not_equal_to);
DEFINE_CMPS(<, less);
DEFINE_CMPS(>, greater);
#undef DEFINE_CMP
#undef DEFINE_CMPS
template<typename A, typename B>
inline node_logic_t<A, B> operator&&(typename std::enable_if<A::node_expr, A>::type a, typename std::enable_if<B::node_expr, B>::type b) {
return node_logic_t<A, B>{a, b, true};
}
template<typename A, typename B>
inline node_logic_t<A, B> operator||(typename std::enable_if<A::node_expr, A>::type a, typename std::enable_if<B::node_expr, B>::type b) {
return node_logic_t<A, B>{a, b, false};
}
template<typename T>
inline node_negate_t<T> operator!(typename std::enable_if<T::node_expr, T>::type v) {
return node_negate_t<T>{v};
};
#endif

View File

@@ -6,6 +6,7 @@
//
#include "special.hpp"
#include "special-conditions.hpp"
// Note: If adding a new node type below, be sure to adjust the end point here too.
node_category_info_t CAT_GENERAL{eSpecType::NONE, eSpecType::STR_BUF_TO_SIGN};
@@ -47,7 +48,9 @@ namespace{
node_properties_t S_PREVENT = node_builder_t(eSpecType::CANT_ENTER)
.msg()
.ex1a(eSpecPicker::TOGGLE)
.ex2a(eSpecPicker::TOGGLE);
.when(eSpecField::EX1A < 1, 1)
.ex2a(eSpecPicker::TOGGLE)
.end();
node_properties_t S_TIME = node_builder_t(eSpecType::CHANGE_TIME)
.msg();
node_properties_t S_TIMER = node_builder_t(eSpecType::SCEN_TIMER_START)
@@ -103,8 +106,18 @@ namespace{
.msg1(+eSpecPicker::MSG_SINGLE)
.ex2a(eSpecPicker::TOGGLE);
node_properties_t S_DEBUG = node_builder_t(eSpecType::PRINT_NUMS)
.sdf()
.pict(STRT_DEBUG_PRINT);
.pict(STRT_DEBUG_PRINT)
.when(eSpecField::PICT == 0, 1)
.sdf()
.end()
.when(eSpecField::PICT == 1, 1)
.ex1a()
.ex1b()
.ex1c()
.end()
.when(eSpecField::PICT == 2, 2)
.ex1a()
.end();
node_properties_t S_MULFLAG = node_builder_t(eSpecType::SDF_TIMES)
.sdf()
.msg();
@@ -151,7 +164,13 @@ namespace{
node_properties_t S_QUEST = node_builder_t(eSpecType::UPDATE_QUEST)
.msg()
.ex1a(STRT_QUEST)
.ex1b(STRT_QUEST_STATUS);
.ex1b(STRT_QUEST_STATUS)
.when(eSpecField::EX1B == 1, 1)
.ex2a(eSpecPicker::JOB_BOARD)
.end()
.when(eSpecField::EX1B == 3, 2)
.ex2a()
.end();
node_properties_t S_BUF_SWAP = node_builder_t(eSpecType::SWAP_STR_BUF)
.msg();
node_properties_t S_ALTER_SIGN = node_builder_t(eSpecType::STR_BUF_TO_SIGN)

View File

@@ -6,6 +6,7 @@
//
#include "special.hpp"
#include "special-conditions.hpp"
// Note: If adding a new node type below, be sure to adjust the end point here too.
node_category_info_t CAT_ONCE{eSpecType::ONCE_GIVE_ITEM, eSpecType::ONCE_TRAP};
@@ -55,5 +56,7 @@ namespace {
.msg()
.pic()
.ex1a(STRT_TRAP)
.ex2b(+eSpecPicker::NODE);
.when(eSpecField::EX1A == 13, 1)
.ex2b(+eSpecPicker::NODE)
.end();
}

View File

@@ -6,6 +6,7 @@
//
#include "special.hpp"
#include "special-conditions.hpp"
// Note: If adding a new node type below, be sure to adjust the end point here too.
node_category_info_t CAT_OUTD{eSpecType::OUT_MAKE_WANDER, eSpecType::OUT_MOVE_PARTY};

View File

@@ -6,6 +6,7 @@
//
#include "special.hpp"
#include "special-conditions.hpp"
// Note: If adding a new node type below, be sure to adjust the end point here too.
node_category_info_t CAT_RECT{eSpecType::RECT_PLACE_FIELD, eSpecType::RECT_UNLOCK};

View File

@@ -6,6 +6,7 @@
//
#include "special.hpp"
#include "special-conditions.hpp"
// Note: If adding a new node type below, be sure to adjust the end point here too.
node_category_info_t CAT_TOWN{eSpecType::MAKE_TOWN_HOSTILE, eSpecType::TOWN_PLACE_LABEL};

View File

@@ -584,37 +584,36 @@ std::string node_properties_t::opcode() const {
return get_str("specials-opcodes", int(self));
}
static std::string get_node_string(std::string base, eSpecType type, int which) {
static std::string get_node_string(std::string base, eSpecType type, int which, int sect) {
eSpecCat cat = getNodeCategory(type);
int offset = int((*cat).first), i = int(type);
int strnum = (i - offset) * 17 + which + 1;
switch(cat) {
case eSpecCat::GENERAL:
return get_str(base + "-general", strnum);
case eSpecCat::ONCE:
return get_str(base + "-once", strnum);
case eSpecCat::AFFECT:
return get_str(base + "-affect", strnum);
case eSpecCat::IF_THEN:
return get_str(base + "-ifthen", strnum);
case eSpecCat::TOWN:
return get_str(base + "-town", strnum);
case eSpecCat::RECT:
return get_str(base + "-rect", strnum);
case eSpecCat::OUTDOOR:
return get_str(base + "-outdoor", strnum);
case eSpecCat::INVALID:
return "error";
case eSpecCat::GENERAL: base += "-general"; break;
case eSpecCat::ONCE: base += "-once"; break;
case eSpecCat::AFFECT: base += "-affect"; break;
case eSpecCat::IF_THEN: base += "-ifthen"; break;
case eSpecCat::TOWN: base += "-town"; break;
case eSpecCat::RECT: base += "-rect"; break;
case eSpecCat::OUTDOOR: base += "-outdoor"; break;
case eSpecCat::INVALID: return "error";
}
return "";
std::string str = get_str(base, strnum);
if(sect < 0) return str;
size_t start = 0, end = str.find_first_of('|');
while(sect --> 0 && end != std::string::npos) {
start = end + 1;
end = str.find_first_of('|', end + 1);
}
return str.substr(start, end - start);
}
std::string node_properties_t::name() const {
return get_node_string("specials-text", self, 0);
return get_node_string("specials-text", self, 0, -1);
}
std::string node_properties_t::descr() const {
return get_node_string("specials-text", self, 15);
return get_node_string("specials-text", self, 15, -1);
}
node_function_t::node_function_t() {}
@@ -670,10 +669,16 @@ node_function_t operator+(eSpecPicker picker) {
}
std::string node_function_t::label() const {
return get_node_string("specials-text", self, lbl_idx);
return get_node_string("specials-text", self, lbl_idx, sub_idx);
}
node_function_t node_properties_t::get(eSpecField fld) const {
node_function_t node_properties_t::get(const cSpecial& spec, eSpecField fld) const {
for(const auto& cond : conditions) {
if(cond.first(spec)) {
auto iter = cond.second.fields.find(fld);
if(iter != cond.second.fields.end()) return iter->second;
}
}
auto iter = fields.find(fld);
if(iter != fields.end()) return iter->second;
static node_function_t nil_fcn;
@@ -688,60 +693,60 @@ void node_properties_t::set(eSpecField fld, node_function_t fcn) {
fields[fld] = fcn;
}
node_function_t node_properties_t::sdf1(const cSpecial&) const {
return get(eSpecField::SDF1);
node_function_t node_properties_t::sdf1(const cSpecial& spec) const {
return get(spec, eSpecField::SDF1);
}
node_function_t node_properties_t::sdf2(const cSpecial&) const {
return get(eSpecField::SDF2);
node_function_t node_properties_t::sdf2(const cSpecial& spec) const {
return get(spec, eSpecField::SDF2);
}
node_function_t node_properties_t::msg1(const cSpecial&) const {
return get(eSpecField::MSG1);
node_function_t node_properties_t::msg1(const cSpecial& spec) const {
return get(spec, eSpecField::MSG1);
}
node_function_t node_properties_t::msg2(const cSpecial&) const {
return get(eSpecField::MSG2);
node_function_t node_properties_t::msg2(const cSpecial& spec) const {
return get(spec, eSpecField::MSG2);
}
node_function_t node_properties_t::msg3(const cSpecial&) const {
return get(eSpecField::MSG3);
node_function_t node_properties_t::msg3(const cSpecial& spec) const {
return get(spec, eSpecField::MSG3);
}
node_function_t node_properties_t::pic(const cSpecial&) const {
return get(eSpecField::PICT);
node_function_t node_properties_t::pic(const cSpecial& spec) const {
return get(spec, eSpecField::PICT);
}
node_function_t node_properties_t::pictype(const cSpecial&) const {
return get(eSpecField::PTYP);
node_function_t node_properties_t::pictype(const cSpecial& spec) const {
return get(spec, eSpecField::PTYP);
}
node_function_t node_properties_t::ex1a(const cSpecial&) const {
return get(eSpecField::EX1A);
node_function_t node_properties_t::ex1a(const cSpecial& spec) const {
return get(spec, eSpecField::EX1A);
}
node_function_t node_properties_t::ex1b(const cSpecial&) const {
return get(eSpecField::EX1B);
node_function_t node_properties_t::ex1b(const cSpecial& spec) const {
return get(spec, eSpecField::EX1B);
}
node_function_t node_properties_t::ex1c(const cSpecial&) const {
return get(eSpecField::EX1C);
node_function_t node_properties_t::ex1c(const cSpecial& spec) const {
return get(spec, eSpecField::EX1C);
}
node_function_t node_properties_t::ex2a(const cSpecial&) const {
return get(eSpecField::EX2A);
node_function_t node_properties_t::ex2a(const cSpecial& spec) const {
return get(spec, eSpecField::EX2A);
}
node_function_t node_properties_t::ex2b(const cSpecial&) const {
return get(eSpecField::EX2B);
node_function_t node_properties_t::ex2b(const cSpecial& spec) const {
return get(spec, eSpecField::EX2B);
}
node_function_t node_properties_t::ex2c(const cSpecial&) const {
return get(eSpecField::EX2C);
node_function_t node_properties_t::ex2c(const cSpecial& spec) const {
return get(spec, eSpecField::EX2C);
}
node_function_t node_properties_t::jump(const cSpecial&) const {
return get(eSpecField::JUMP);
node_function_t node_properties_t::jump(const cSpecial& spec) const {
return get(spec, eSpecField::JUMP);
}
struct field_map {
@@ -763,9 +768,9 @@ struct field_map {
};
};
static field_map& fields() {
short operator->*(const cSpecial& spec, eSpecField fld) {
static field_map map;
return map;
return spec.*map.map[fld];
}
node_builder_t& node_builder_t::sdf() {
@@ -872,3 +877,139 @@ node_builder_t::operator node_properties_t() {
allNodeProps.emplace(node.self, node);
return node;
}
node_condition_builder_t node_builder_t::when(node_condition_t cond, int lbl_sub) {
return node_condition_builder_t(*this, cond, lbl_sub);
}
node_condition_builder_t::node_condition_builder_t(node_builder_t& parent, node_condition_t cond, int sub)
: cond(cond)
, self(parent.node.self)
, parent(parent)
, sub(sub)
{
self.node.fields.clear();
}
node_builder_t& node_condition_builder_t::end() {
for(auto& field : self.node.fields) {
field.second.sub_idx = sub;
}
parent.node.conditions.emplace_back(cond, self.node);
return parent;
}
node_condition_builder_t& node_condition_builder_t::field(eSpecField field, node_function_t picker) {
self.field(field, picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::field_pair(eSpecField main, eSpecField extra, node_function_t picker) {
self.field_pair(main, extra, picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::sdf1(node_function_t picker) {
self.sdf1(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::sdf2(node_function_t picker) {
self.sdf2(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::jump(node_function_t picker) {
self.jump(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::msg1(node_function_t picker) {
self.msg1(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::msg2(node_function_t picker) {
self.msg2(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::msg3(node_function_t picker) {
self.msg3(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::pict(node_function_t picker) {
self.pict(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::ptyp(node_function_t picker) {
self.ptyp(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::ex1a(node_function_t picker) {
self.ex1a(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::ex1b(node_function_t picker) {
self.ex1b(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::ex1c(node_function_t picker) {
self.ex1c(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::ex2a(node_function_t picker) {
self.ex2a(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::ex2b(node_function_t picker) {
self.ex2b(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::ex2c(node_function_t picker) {
self.ex2c(picker);
return *this;
}
node_condition_builder_t& node_condition_builder_t::sdf() {
self.sdf();
return *this;
}
node_condition_builder_t& node_condition_builder_t::msg() {
self.msg();
return *this;
}
node_condition_builder_t& node_condition_builder_t::pic() {
self.pic();
return *this;
}
node_condition_builder_t& node_condition_builder_t::rect(eLocType type) {
self.rect(type);
return *this;
}
node_condition_builder_t& node_condition_builder_t::sdf(eSpecField a, eSpecField b) {
self.sdf(a, b);
return *this;
}
node_condition_builder_t& node_condition_builder_t::loc(eSpecField a, eSpecField b, eLocType type) {
self.loc(a, b, type);
return *this;
}
node_condition_builder_t& node_condition_builder_t::loc(eSpecField a, eSpecField b, eLocType type, eSpecField where) {
self.loc(a, b, type, where);
return *this;
}

View File

@@ -167,6 +167,7 @@ enum class eLocType {
};
enum class eSpecField { NONE, SDF1, SDF2, MSG1, MSG2, MSG3, PICT, PTYP, EX1A, EX1B, EX1C, EX2A, EX2B, EX2C, JUMP };
short operator->*(const cSpecial& spec, eSpecField fld);
struct node_function_t {
eSpecPicker button = eSpecPicker::NONE;
@@ -194,10 +195,13 @@ private:
bool needs_split = false;
friend struct node_builder_t;
friend struct node_properties_t;
friend struct node_condition_builder_t;
};
node_function_t operator+(eSpecPicker);
using node_condition_t = std::function<bool(const cSpecial&)>;
struct node_properties_t {
eSpecType self;
eSpecCat cat;
@@ -211,16 +215,20 @@ struct node_properties_t {
node_properties_t() : node_properties_t(eSpecType::INVALID) {}
private:
node_properties_t(eSpecType type);
node_function_t get(eSpecField fld) const;
node_function_t get(const cSpecial& spec, eSpecField fld) const;
void set(eSpecField fld, node_function_t fcn);
std::map<eSpecField, node_function_t> fields;
std::vector<std::pair<node_condition_t, node_properties_t>> conditions;
friend struct node_builder_t;
friend struct node_condition_builder_t;
friend struct field_map;
};
const node_properties_t& operator* (eSpecType t);
const node_category_info_t& operator* (eSpecCat t);
struct node_condition_builder_t;
// Builds the information needed to display the correct buttons when editing a special node.
struct node_builder_t {
node_builder_t(eSpecType type) : node(type) {}
@@ -259,9 +267,45 @@ struct node_builder_t {
node_builder_t& loc(eSpecField a, eSpecField b, eLocType type);
// As above, but also notes that the area the location is in will be specified by the indicated field.
node_builder_t& loc(eSpecField a, eSpecField b, eLocType type, eSpecField where);
node_condition_builder_t when(node_condition_t cond, int lbl_sub);
operator node_properties_t();
private:
node_properties_t node;
friend struct node_condition_builder_t;
};
struct node_condition_builder_t {
node_builder_t& end();
node_condition_builder_t& field(eSpecField field, node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& field_pair(eSpecField main, eSpecField extra, node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& sdf1(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& sdf2(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& jump(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& msg1(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& msg2(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& msg3(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& pict(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& ptyp(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& ex1a(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& ex1b(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& ex1c(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& ex2a(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& ex2b(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& ex2c(node_function_t picker = eSpecPicker::NONE);
node_condition_builder_t& sdf();
node_condition_builder_t& msg();
node_condition_builder_t& pic();
node_condition_builder_t& rect(eLocType type);
node_condition_builder_t& sdf(eSpecField a, eSpecField b);
node_condition_builder_t& loc(eSpecField a, eSpecField b, eLocType type);
node_condition_builder_t& loc(eSpecField a, eSpecField b, eLocType type, eSpecField where);
private:
node_condition_builder_t(node_builder_t& parent, node_condition_t cond, int sub);
node_condition_t cond;
node_builder_t self;
node_builder_t& parent;
int sub;
friend class node_builder_t;
};
// An overview of how the builder works.

View File

@@ -1273,6 +1273,9 @@ static bool edit_spec_enc_value(cDialog& me, std::string item_hit, node_stack_t&
case eSpecPicker::NONE: return false;
}
me[field].setTextToNum(store);
// Field labels might need to change, so refresh them
save_spec_enc(me, edit_stack);
put_spec_enc_in_dlog(me, edit_stack);
return true;
}
@@ -1321,6 +1324,17 @@ bool edit_spec_enc(short which_node,short mode,cDialog* parent) {
"x1a-toggle", "x1b-toggle", "x1c-toggle", "x2a-toggle", "x2b-toggle", "x2c-toggle",
"sdf1-toggle", "sdf2-toggle",
});
special.attachFocusHandlers([&edit_stack](cDialog& me, std::string, bool losing) {
if(losing) {
save_spec_enc(me, edit_stack);
put_spec_enc_in_dlog(me, edit_stack);
}
return true;
}, {
"msg1", "msg2", "msg3", "pict", "pictype", "jump",
"x1a", "x1b", "x1c", "x2a", "x2b", "x2c",
"sdf1", "sdf2",
});
special["cancel"].attachClickHandler(std::bind(discard_spec_enc, _1, std::ref(edit_stack)));
special["node-help"].attachClickHandler([&edit_stack](cDialog& me, std::string item_hit, eKeyMod mods) {
eSpecType type = edit_stack.top().node.type;