diff options
-rw-r--r-- | src/generic/dumb_ptr.hpp | 4 | ||||
-rw-r--r-- | src/io/cxxstdio_enums.hpp | 15 | ||||
-rw-r--r-- | src/map/magic-expr-eval.hpp | 30 | ||||
-rw-r--r-- | src/map/magic-expr.cpp | 1080 | ||||
-rw-r--r-- | src/map/magic-expr.hpp | 4 | ||||
-rw-r--r-- | src/map/magic-interpreter-base.cpp | 151 | ||||
-rw-r--r-- | src/map/magic-interpreter-base.hpp | 4 | ||||
-rw-r--r-- | src/map/magic-interpreter.hpp | 580 | ||||
-rw-r--r-- | src/map/magic-interpreter.t.hpp | 70 | ||||
-rw-r--r-- | src/map/magic-stmt.cpp | 512 | ||||
-rw-r--r-- | src/map/magic-v2.cpp | 255 | ||||
-rw-r--r-- | src/map/magic.cpp | 9 | ||||
-rw-r--r-- | src/sexpr/variant.hpp | 9 | ||||
-rw-r--r-- | src/sexpr/variant.tcc | 18 |
14 files changed, 1406 insertions, 1335 deletions
diff --git a/src/generic/dumb_ptr.hpp b/src/generic/dumb_ptr.hpp index a9d6893..da84171 100644 --- a/src/generic/dumb_ptr.hpp +++ b/src/generic/dumb_ptr.hpp @@ -42,7 +42,7 @@ class dumb_ptr T *impl; public: explicit - dumb_ptr(T *p=nullptr) + dumb_ptr(T *p=nullptr) noexcept : impl(p) {} template<class U> @@ -112,7 +112,7 @@ class dumb_ptr<T[]> T *impl; size_t sz; public: - dumb_ptr() : impl(), sz() {} + dumb_ptr() noexcept : impl(), sz() {} dumb_ptr(std::nullptr_t) : impl(nullptr), sz(0) {} dumb_ptr(T *p, size_t z) diff --git a/src/io/cxxstdio_enums.hpp b/src/io/cxxstdio_enums.hpp index 5424518..05cdcae 100644 --- a/src/io/cxxstdio_enums.hpp +++ b/src/io/cxxstdio_enums.hpp @@ -46,25 +46,10 @@ auto decay_for_printf(Option v) -> typename remove_enum<decltype(v)>::type { ret namespace magic { -enum class AREA : uint8_t; -enum class EFFECT : uint8_t; -enum class EXPR : uint8_t; enum class SPELLARG : uint8_t; -enum class SPELLGUARD : uint8_t; -enum class TYPE : uint8_t; inline -auto decay_for_printf(AREA v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } -inline -auto decay_for_printf(EFFECT v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } -inline -auto decay_for_printf(EXPR v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } -inline auto decay_for_printf(SPELLARG v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } -inline -auto decay_for_printf(SPELLGUARD v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } -inline -auto decay_for_printf(TYPE v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } } enum class BL : uint8_t; diff --git a/src/map/magic-expr-eval.hpp b/src/map/magic-expr-eval.hpp index 3cbc8f5..4529c04 100644 --- a/src/map/magic-expr-eval.hpp +++ b/src/map/magic-expr-eval.hpp @@ -31,31 +31,21 @@ namespace tmwa namespace magic { // TODO soon kill this unlike I killed VAR -#define ARGINT(x) args[x].v.v_int -#define ARGDIR(x) args[x].v.v_dir -#define ARGSTR(x) ZString(args[x].v.v_string) -#define ARGENTITY(x) args[x].v.v_entity -#define ARGLOCATION(x) args[x].v.v_location -#define ARGAREA(x) args[x].v.v_area -#define ARGSPELL(x) args[x].v.v_spell -#define ARGINVOCATION(x) args[x].v.v_invocation - -#define RESULTINT result->v.v_int -#define RESULTDIR result->v.v_dir -#define RESULTSTR result->v.v_string -#define RESULTENTITY result->v.v_entity -#define RESULTLOCATION result->v.v_location -#define RESULTAREA result->v.v_area -#define RESULTSPELL result->v.v_spell -#define RESULTINVOCATION result->v.v_invocation - -#define ARG_TYPE(x) args[x].ty +#define ARGINT(x) args[x].get_if<ValInt>()->v_int +#define ARGDIR(x) args[x].get_if<ValDir>()->v_dir +#define ARGSTR(x) ZString(args[x].get_if<ValString>()->v_string) +#define ARGENTITY(x) args[x].get_if<ValEntityPtr>()->v_entity +#define ARGLOCATION(x) args[x].get_if<ValLocation>()->v_location +#define ARGAREA(x) args[x].get_if<ValArea>()->v_area +#define ARGSPELL(x) args[x].get_if<ValSpell>()->v_spell +#define ARGINVOCATION(x) args[x].get_if<ValInvocationPtr>()->v_invocation + #define ENTITY_TYPE(x) ARGENTITY(x)->bl_type #define ARGPC(x) (ARGENTITY(x)->is_player()) #define ARGNPC(x) (ARGENTITY(x)->is_npc()) #define ARGMOB(x) (ARGENTITY(x)->is_mob()) -#define ARG_MAY_BE_AREA(x) (ARG_TYPE(x) == TYPE::AREA || ARG_TYPE(x) == TYPE::LOCATION) +#define ARG_MAY_BE_AREA(x) (args[x].is<ValArea>() || args[x].is<ValArea>()) } // namespace magic } // namespace tmwa diff --git a/src/map/magic-expr.cpp b/src/map/magic-expr.cpp index c0551d2..306126e 100644 --- a/src/map/magic-expr.cpp +++ b/src/map/magic-expr.cpp @@ -50,26 +50,19 @@ namespace tmwa { namespace magic { -template<class T> -bool CHECK_TYPE(T *v, TYPE t) -{ - return v->ty == t; -} - static void free_area(dumb_ptr<area_t> area) { if (!area) return; - switch (area->ty) + MATCH (*area) { - case AREA::UNION: - free_area(area->a.a_union[0]); - free_area(area->a.a_union[1]); - break; - default: - break; + CASE (const AreaUnion&, a) + { + free_area(a.a_union[0]); + free_area(a.a_union[1]); + } } area.delete_(); @@ -78,52 +71,108 @@ void free_area(dumb_ptr<area_t> area) static dumb_ptr<area_t> dup_area(dumb_ptr<area_t> area) { - dumb_ptr<area_t> retval = dumb_ptr<area_t>::make(); - *retval = *area; - - switch (area->ty) + MATCH (*area) { - case AREA::UNION: - retval->a.a_union[0] = dup_area(retval->a.a_union[0]); - retval->a.a_union[1] = dup_area(retval->a.a_union[1]); - break; - default: - break; + CASE (const location_t&, loc) + { + return dumb_ptr<area_t>::make(loc, area->size); + } + CASE (const AreaUnion&, a) + { + AreaUnion u; + u.a_union[0] = dup_area(a.a_union[0]); + u.a_union[1] = dup_area(a.a_union[1]); + return dumb_ptr<area_t>::make(u, area->size); + } + CASE (const AreaRect&, rect) + { + return dumb_ptr<area_t>::make(rect, area->size); + } + CASE (const AreaBar&, bar) + { + return dumb_ptr<area_t>::make(bar, area->size); + } } - return retval; + abort(); } -void magic_copy_var(val_t *dest, val_t *src) +void magic_copy_var(val_t *dest, const val_t *src) { - *dest = *src; - - switch (dest->ty) + MATCH (*src) { - case TYPE::STRING: - dest->v.v_string = dest->v.v_string.dup(); - break; - case TYPE::AREA: - dest->v.v_area = dup_area(dest->v.v_area); - break; + // mumble mumble not a public API ... default: - break; + { + abort(); + } + CASE (const ValUndef&, s) + { + *dest = s; + } + CASE (const ValInt&, s) + { + *dest = s; + } + CASE (const ValDir&, s) + { + *dest = s; + } + CASE (const ValString&, s) + { + *dest = ValString{s.v_string.dup()}; + } + CASE (const ValEntityInt&, s) + { + *dest = s; + } + CASE (const ValEntityPtr&, s) + { + *dest = s; + } + CASE (const ValLocation&, s) + { + *dest = s; + } + CASE (const ValArea&, s) + { + *dest = ValArea{dup_area(s.v_area)}; + } + CASE (const ValSpell&, s) + { + *dest = s; + } + CASE (const ValInvocationInt&, s) + { + *dest = s; + } + CASE (const ValInvocationPtr&, s) + { + *dest = s; + } + CASE (const ValFail&, s) + { + *dest = s; + } + CASE (const ValNegative1&, s) + { + *dest = s; + } } - } void magic_clear_var(val_t *v) { - switch (v->ty) + MATCH (*v) { - case TYPE::STRING: - v->v.v_string.delete_(); - break; - case TYPE::AREA: - free_area(v->v.v_area); - break; - default: - break; + CASE (ValString&, s) + { + s.v_string.delete_(); + } + CASE (const ValArea&, a) + { + free_area(a.v_area); + } } } @@ -152,7 +201,7 @@ AString show_entity(dumb_ptr<block_list> entity) } static -void stringify(val_t *v, int within_op) +void stringify(val_t *v) { static earray<LString, DIR, DIR::COUNT> dirs //= {{ @@ -163,89 +212,86 @@ void stringify(val_t *v, int within_op) }}; AString buf; - switch (v->ty) + MATCH (*v) { - case TYPE::UNDEF: + default: + { + abort(); + } + CASE (const ValUndef&, x) + { + (void)x; buf = "UNDEF"_s; - break; - - case TYPE::INT: - buf = STRPRINTF("%i"_fmt, v->v.v_int); - break; - - case TYPE::STRING: + } + CASE (const ValInt&, x) + { + buf = STRPRINTF("%i"_fmt, x.v_int); + } + CASE (const ValString&, x) + { + (void)x; return; - - case TYPE::DIR: - buf = dirs[v->v.v_dir]; - break; - - case TYPE::ENTITY: - buf = show_entity(v->v.v_entity); - break; - - case TYPE::LOCATION: + } + CASE (const ValDir&, x) + { + buf = dirs[x.v_dir]; + } + CASE (const ValEntityPtr&, x) + { + buf = show_entity(x.v_entity); + } + CASE (const ValLocation&, x) + { buf = STRPRINTF("<\"%s\", %d, %d>"_fmt, - v->v.v_location.m->name_, - v->v.v_location.x, - v->v.v_location.y); - break; - - case TYPE::AREA: + x.v_location.m->name_, + x.v_location.x, + x.v_location.y); + } + CASE (const ValArea&, x) + { buf = "%area"_s; - free_area(v->v.v_area); - break; - - case TYPE::SPELL: - buf = v->v.v_spell->name; + free_area(x.v_area); + } + CASE (const ValSpell&, x) + { + buf = x.v_spell->name; break; - - case TYPE::INVOCATION: + } + CASE (const ValInvocationInt&, x) { - dumb_ptr<invocation> invocation_ = within_op - ? v->v.v_invocation - : map_id2bl(wrap<BlockId>(static_cast<uint32_t>(v->v.v_int)))->is_spell(); + dumb_ptr<invocation> invocation_ = + map_id2bl(x.v_iid)->is_spell(); + buf = invocation_->spell->name; + } + CASE (const ValInvocationPtr&, x) + { + dumb_ptr<invocation> invocation_ = + x.v_invocation; buf = invocation_->spell->name; } - break; - - default: - FPRINTF(stderr, "[magic] INTERNAL ERROR: Cannot stringify %d\n"_fmt, - v->ty); - return; } - v->v.v_string = dumb_string::copys(buf); - v->ty = TYPE::STRING; + *v = ValString{dumb_string::copys(buf)}; } static void intify(val_t *v) { - if (v->ty == TYPE::INT) + if (v->is<ValInt>()) return; magic_clear_var(v); - v->ty = TYPE::INT; - v->v.v_int = 1; -} - -static -dumb_ptr<area_t> area_new(AREA ty) -{ - auto retval = dumb_ptr<area_t>::make(); - retval->ty = ty; - return retval; + *v = ValInt{1}; } static dumb_ptr<area_t> area_union(dumb_ptr<area_t> area, dumb_ptr<area_t> other_area) { - dumb_ptr<area_t> retval = area_new(AREA::UNION); - retval->a.a_union[0] = area; - retval->a.a_union[1] = other_area; - retval->size = area->size + other_area->size; /* Assume no overlap */ - return retval; + AreaUnion a; + a.a_union[0] = area; + a.a_union[1] = other_area; + int size = area->size + other_area->size; /* Assume no overlap */ + return dumb_ptr<area_t>::make(a, size); } /** @@ -254,41 +300,43 @@ dumb_ptr<area_t> area_union(dumb_ptr<area_t> area, dumb_ptr<area_t> other_area) static void make_area(val_t *v) { - if (v->ty == TYPE::LOCATION) + if (ValLocation *l = v->get_if<ValLocation>()) { - auto a = dumb_ptr<area_t>::make(); - v->ty = TYPE::AREA; - a->ty = AREA::LOCATION; - a->a.a_loc = v->v.v_location; - v->v.v_area = a; + auto a = dumb_ptr<area_t>::make(l->v_location, 1); + *v = ValArea{a}; } } static void make_location(val_t *v) { - if (v->ty == TYPE::AREA && v->v.v_area->ty == AREA::LOCATION) + if (ValArea *a = v->get_if<ValArea>()) { - location_t location = v->v.v_area->a.a_loc; - free_area(v->v.v_area); - v->ty = TYPE::LOCATION; - v->v.v_location = location; + MATCH (*a->v_area) + { + CASE (const location_t&, location) + { + free_area(a->v_area); + *v = ValLocation{location}; + } + } } } static void make_spell(val_t *v) { - if (v->ty == TYPE::INVOCATION) + assert(!v->is<ValInvocationInt>()); + if (ValInvocationPtr *p = v->get_if<ValInvocationPtr>()) { - dumb_ptr<invocation> invoc = v->v.v_invocation; - //invoc = (dumb_ptr<invocation>) map_id2bl(v->v.v_int); + dumb_ptr<invocation> invoc = p->v_invocation; if (!invoc) - v->ty = TYPE::FAIL; + { + *v = ValFail{}; + } else { - v->ty = TYPE::SPELL; - v->v.v_spell = invoc->spell; + *v = ValSpell{invoc->spell}; } } } @@ -296,34 +344,31 @@ void make_spell(val_t *v) static int fun_add(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - if (ARG_TYPE(0) == TYPE::INT && ARG_TYPE(1) == TYPE::INT) + if (args[0].is<ValInt>() && args[1].is<ValInt>()) { /* Integer addition */ - RESULTINT = ARGINT(0) + ARGINT(1); - result->ty = TYPE::INT; + *result = ValInt{ARGINT(0) + ARGINT(1)}; } else if (ARG_MAY_BE_AREA(0) && ARG_MAY_BE_AREA(1)) { /* Area union */ make_area(&args[0]); make_area(&args[1]); - RESULTAREA = area_union(ARGAREA(0), ARGAREA(1)); - ARGAREA(0) = nullptr; - ARGAREA(1) = nullptr; - result->ty = TYPE::AREA; + *result = ValArea{area_union(ARGAREA(0), ARGAREA(1))}; + ARGAREA(0) = nullptr; args[0] = ValUndef{}; + ARGAREA(1) = nullptr; args[1] = ValUndef{}; } else { /* Anything else -> string concatenation */ - stringify(&args[0], 1); - stringify(&args[1], 1); + stringify(&args[0]); + stringify(&args[1]); /* Yes, we could speed this up. */ // ugh MString m; m += ARGSTR(0); m += ARGSTR(1); - RESULTSTR = dumb_string::copys(AString(m)); - result->ty = TYPE::STRING; + *result = ValString{dumb_string::copys(AString(m))}; } return 0; } @@ -331,14 +376,14 @@ int fun_add(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) static int fun_sub(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) - ARGINT(1); + *result = ValInt{ARGINT(0) - ARGINT(1)}; return 0; } static int fun_mul(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) * ARGINT(1); + *result = ValInt{ARGINT(0) * ARGINT(1)}; return 0; } @@ -347,7 +392,7 @@ int fun_div(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (!ARGINT(1)) return 1; /* division by zero */ - RESULTINT = ARGINT(0) / ARGINT(1); + *result = ValInt{ARGINT(0) / ARGINT(1)}; return 0; } @@ -356,52 +401,52 @@ int fun_mod(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (!ARGINT(1)) return 1; /* division by zero */ - RESULTINT = ARGINT(0) % ARGINT(1); + *result = ValInt{ARGINT(0) % ARGINT(1)}; return 0; } static int fun_or(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) || ARGINT(1); + *result = ValInt{ARGINT(0) || ARGINT(1)}; return 0; } static int fun_and(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) && ARGINT(1); + *result = ValInt{ARGINT(0) && ARGINT(1)}; return 0; } static int fun_not(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = !ARGINT(0); + *result = ValInt{!ARGINT(0)}; return 0; } static int fun_neg(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ~ARGINT(0); + *result = ValInt{~ARGINT(0)}; return 0; } static int fun_gte(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - if (ARG_TYPE(0) == TYPE::STRING || ARG_TYPE(1) == TYPE::STRING) + if (args[0].is<ValString>() || args[1].is<ValString>()) { - stringify(&args[0], 1); - stringify(&args[1], 1); - RESULTINT = ARGSTR(0) >= ARGSTR(1); + stringify(&args[0]); + stringify(&args[1]); + *result = ValInt{ARGSTR(0) >= ARGSTR(1)}; } else { intify(&args[0]); intify(&args[1]); - RESULTINT = ARGINT(0) >= ARGINT(1); + *result = ValInt{ARGINT(0) >= ARGINT(1)}; } return 0; } @@ -410,24 +455,24 @@ static int fun_lt(dumb_ptr<env_t> env, val_t *result, Slice<val_t> args) { fun_gte(env, result, args); - RESULTINT = !RESULTINT; + result->get_if<ValInt>()->v_int ^= 1; return 0; } static int fun_gt(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - if (ARG_TYPE(0) == TYPE::STRING || ARG_TYPE(1) == TYPE::STRING) + if (args[0].is<ValString>() || args[1].is<ValString>()) { - stringify(&args[0], 1); - stringify(&args[1], 1); - RESULTINT = ARGSTR(0) > ARGSTR(1); + stringify(&args[0]); + stringify(&args[1]); + *result = ValInt{ARGSTR(0) > ARGSTR(1)}; } else { intify(&args[0]); intify(&args[1]); - RESULTINT = ARGINT(0) > ARGINT(1); + *result = ValInt{ARGINT(0) > ARGINT(1)}; } return 0; } @@ -436,38 +481,38 @@ static int fun_lte(dumb_ptr<env_t> env, val_t *result, Slice<val_t> args) { fun_gt(env, result, args); - RESULTINT = !RESULTINT; + result->get_if<ValInt>()->v_int ^= 1; return 0; } static int fun_eq(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - if (ARG_TYPE(0) == TYPE::STRING || ARG_TYPE(1) == TYPE::STRING) + if (args[0].is<ValString>() || args[1].is<ValString>()) { - stringify(&args[0], 1); - stringify(&args[1], 1); - RESULTINT = ARGSTR(0) == ARGSTR(1); + stringify(&args[0]); + stringify(&args[1]); + *result = ValInt{ARGSTR(0) == ARGSTR(1)}; } - else if (ARG_TYPE(0) == TYPE::DIR && ARG_TYPE(1) == TYPE::DIR) - RESULTINT = ARGDIR(0) == ARGDIR(1); - else if (ARG_TYPE(0) == TYPE::ENTITY && ARG_TYPE(1) == TYPE::ENTITY) - RESULTINT = ARGENTITY(0) == ARGENTITY(1); - else if (ARG_TYPE(0) == TYPE::LOCATION && ARG_TYPE(1) == TYPE::LOCATION) - RESULTINT = (ARGLOCATION(0).x == ARGLOCATION(1).x + else if (args[0].is<ValDir>() && args[1].is<ValDir>()) + *result = ValInt{ARGDIR(0) == ARGDIR(1)}; + else if (args[0].is<ValEntityPtr>() && args[1].is<ValEntityPtr>()) + *result = ValInt{ARGENTITY(0) == ARGENTITY(1)}; + else if (args[0].is<ValLocation>() && args[1].is<ValLocation>()) + *result = ValInt{(ARGLOCATION(0).x == ARGLOCATION(1).x && ARGLOCATION(0).y == ARGLOCATION(1).y - && ARGLOCATION(0).m == ARGLOCATION(1).m); - else if (ARG_TYPE(0) == TYPE::AREA && ARG_TYPE(1) == TYPE::AREA) - RESULTINT = ARGAREA(0) == ARGAREA(1); /* Probably not that great an idea... */ - else if (ARG_TYPE(0) == TYPE::SPELL && ARG_TYPE(1) == TYPE::SPELL) - RESULTINT = ARGSPELL(0) == ARGSPELL(1); - else if (ARG_TYPE(0) == TYPE::INVOCATION && ARG_TYPE(1) == TYPE::INVOCATION) - RESULTINT = ARGINVOCATION(0) == ARGINVOCATION(1); + && ARGLOCATION(0).m == ARGLOCATION(1).m)}; + else if (args[0].is<ValArea>() && args[1].is<ValArea>()) + *result = ValInt{ARGAREA(0) == ARGAREA(1)}; /* Probably not that great an idea... */ + else if (args[0].is<ValSpell>() && args[1].is<ValSpell>()) + *result = ValInt{ARGSPELL(0) == ARGSPELL(1)}; + else if (args[0].is<ValInvocationPtr>() && args[1].is<ValInvocationPtr>()) + *result = ValInt{ARGINVOCATION(0) == ARGINVOCATION(1)}; else { intify(&args[0]); intify(&args[1]); - RESULTINT = ARGINT(0) == ARGINT(1); + *result = ValInt{ARGINT(0) == ARGINT(1)}; } return 0; } @@ -476,56 +521,56 @@ static int fun_ne(dumb_ptr<env_t> env, val_t *result, Slice<val_t> args) { fun_eq(env, result, args); - RESULTINT = !RESULTINT; + result->get_if<ValInt>()->v_int ^= 1; return 0; } static int fun_bitand(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) & ARGINT(1); + *result = ValInt{ARGINT(0) & ARGINT(1)}; return 0; } static int fun_bitor(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) | ARGINT(1); + *result = ValInt{ARGINT(0) | ARGINT(1)}; return 0; } static int fun_bitxor(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) ^ ARGINT(1); + *result = ValInt{ARGINT(0) ^ ARGINT(1)}; return 0; } static int fun_bitshl(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) << ARGINT(1); + *result = ValInt{ARGINT(0) << ARGINT(1)}; return 0; } static int fun_bitshr(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) >> ARGINT(1); + *result = ValInt{ARGINT(0) >> ARGINT(1)}; return 0; } static int fun_max(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = std::max(ARGINT(0), ARGINT(1)); + *result = ValInt{std::max(ARGINT(0), ARGINT(1))}; return 0; } static int fun_min(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = std::min(ARGINT(0), ARGINT(1)); + *result = ValInt{std::min(ARGINT(0), ARGINT(1))}; return 0; } @@ -542,37 +587,38 @@ int fun_if_then_else(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) void magic_area_rect(map_local **m, int *x, int *y, int *width, int *height, area_t& area_) { - area_t *area = &area_; // diff hack - switch (area->ty) + MATCH (area_) { - case AREA::UNION: - break; - - case AREA::LOCATION: - *m = area->a.a_loc.m; - *x = area->a.a_loc.x; - *y = area->a.a_loc.y; + CASE (const AreaUnion&, a) + { + (void)a; + abort(); + } + CASE (const location_t&, a_loc) + { + *m = a_loc.m; + *x = a_loc.x; + *y = a_loc.y; *width = 1; *height = 1; - break; - - case AREA::RECT: - *m = area->a.a_rect.loc.m; - *x = area->a.a_rect.loc.x; - *y = area->a.a_rect.loc.y; - *width = area->a.a_rect.width; - *height = area->a.a_rect.height; - break; - - case AREA::BAR: + } + CASE (const AreaRect&, a_rect) + { + *m = a_rect.loc.m; + *x = a_rect.loc.x; + *y = a_rect.loc.y; + *width = a_rect.width; + *height = a_rect.height; + } + CASE (const AreaBar&, a_bar) { - int tx = area->a.a_bar.loc.x; - int ty = area->a.a_bar.loc.y; - int twidth = area->a.a_bar.width; - int tdepth = area->a.a_bar.width; - *m = area->a.a_bar.loc.m; + int tx = a_bar.loc.x; + int ty = a_bar.loc.y; + int twidth = a_bar.width; + int tdepth = a_bar.width; + *m = a_bar.loc.m; - switch (area->a.a_bar.dir) + switch (a_bar.dir) { case DIR::S: *x = tx - twidth; @@ -609,22 +655,45 @@ void magic_area_rect(map_local **m, int *x, int *y, int *width, int *height, *y = ty; *width = *height = 1; } - break; } } } int magic_location_in_area(map_local *m, int x, int y, dumb_ptr<area_t> area) { - switch (area->ty) + MATCH (*area) { - case AREA::UNION: - return magic_location_in_area(m, x, y, area->a.a_union[0]) - || magic_location_in_area(m, x, y, area->a.a_union[1]); - case AREA::LOCATION: - case AREA::RECT: - case AREA::BAR: + CASE (const AreaUnion&, a) { + return magic_location_in_area(m, x, y, a.a_union[0]) + || magic_location_in_area(m, x, y, a.a_union[1]); + } + CASE (const location_t&, a_loc) + { + (void)a_loc; + // TODO this can be simplified + map_local *am; + int ax, ay, awidth, aheight; + magic_area_rect(&am, &ax, &ay, &awidth, &aheight, *area); + return (am == m + && (x >= ax) && (y >= ay) + && (x < ax + awidth) && (y < ay + aheight)); + } + CASE (const AreaRect&, a_rect) + { + (void)a_rect; + // TODO this is too complicated + map_local *am; + int ax, ay, awidth, aheight; + magic_area_rect(&am, &ax, &ay, &awidth, &aheight, *area); + return (am == m + && (x >= ax) && (y >= ay) + && (x < ax + awidth) && (y < ay + aheight)); + } + CASE (const AreaBar&, a_bar) + { + (void)a_bar; + // TODO this is wrong map_local *am; int ax, ay, awidth, aheight; magic_area_rect(&am, &ax, &ay, &awidth, &aheight, *area); @@ -632,18 +701,16 @@ int magic_location_in_area(map_local *m, int x, int y, dumb_ptr<area_t> area) && (x >= ax) && (y >= ay) && (x < ax + awidth) && (y < ay + aheight)); } - default: - FPRINTF(stderr, "INTERNAL ERROR: Invalid area\n"_fmt); - return 0; } + abort(); } static int fun_is_in(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = magic_location_in_area(ARGLOCATION(0).m, + *result = ValInt{magic_location_in_area(ARGLOCATION(0).m, ARGLOCATION(0).x, - ARGLOCATION(0).y, ARGAREA(1)); + ARGLOCATION(0).y, ARGAREA(1))}; return 0; } @@ -652,15 +719,16 @@ int fun_skill(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (ENTITY_TYPE(0) != BL::PC // don't convert to enum until after the range check + // (actually it would be okay, I checked) || ARGINT(1) < 0 || ARGINT(1) >= static_cast<uint16_t>(MAX_SKILL)) { - RESULTINT = 0; + *result = ValInt{0}; } else { SkillID id = static_cast<SkillID>(ARGINT(1)); - RESULTINT = ARGPC(0)->status.skill[id].lv; + *result = ValInt{ARGPC(0)->status.skill[id].lv}; } return 0; } @@ -668,7 +736,7 @@ int fun_skill(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) static int fun_his_shroud(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = (ENTITY_TYPE(0) == BL::PC && ARGPC(0)->state.shroud_active); + *result = ValInt{(ENTITY_TYPE(0) == BL::PC && ARGPC(0)->state.shroud_active)}; return 0; } @@ -676,7 +744,7 @@ int fun_his_shroud(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) static \ int fun_get_##name(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) \ { \ - RESULTINT = battle_get_##name(ARGENTITY(0)); \ + *result = ValInt{battle_get_##name(ARGENTITY(0))}; \ return 0; \ } @@ -694,7 +762,7 @@ BATTLE_GETTER(max_hp) static int fun_get_dir(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTDIR = battle_get_dir(ARGENTITY(0)); + *result = ValDir{battle_get_dir(ARGENTITY(0))}; return 0; } @@ -703,9 +771,9 @@ static \ int fun_get_##name(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) \ { \ if (ENTITY_TYPE(0) == BL::PC) \ - RESULTINT = ARGPC(0)->status.name; \ + *result = ValInt{ARGPC(0)->status.name}; \ else \ - RESULTINT = 0; \ + *result = ValInt{0}; \ return 0; \ } @@ -715,19 +783,19 @@ MMO_GETTER(max_sp) static int fun_name_of(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - if (ARG_TYPE(0) == TYPE::ENTITY) + if (args[0].is<ValEntityPtr>()) { - RESULTSTR = dumb_string::copys(show_entity(ARGENTITY(0))); + *result = ValString{dumb_string::copys(show_entity(ARGENTITY(0)))}; return 0; } - else if (ARG_TYPE(0) == TYPE::SPELL) + else if (args[0].is<ValSpell>()) { - RESULTSTR = dumb_string::copys(ARGSPELL(0)->name); + *result = ValString{dumb_string::copys(ARGSPELL(0)->name)}; return 0; } - else if (ARG_TYPE(0) == TYPE::INVOCATION) + else if (args[0].is<ValInvocationPtr>()) { - RESULTSTR = dumb_string::copys(ARGINVOCATION(0)->spell->name); + *result = ValString{dumb_string::copys(ARGINVOCATION(0)->spell->name)}; return 0; } return 1; @@ -739,7 +807,7 @@ int fun_mob_id(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (ENTITY_TYPE(0) != BL::MOB) return 1; - RESULTINT = unwrap<Species>(ARGMOB(0)->mob_class); + *result = ValInt{unwrap<Species>(ARGMOB(0)->mob_class)}; return 0; } @@ -762,7 +830,9 @@ void COPY_LOCATION(location_t& dest, block_list& src) static int fun_location(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - COPY_LOCATION(RESULTLOCATION, *(ARGENTITY(0))); + location_t loc; + COPY_LOCATION(loc, *(ARGENTITY(0))); + *result = ValLocation{loc}; return 0; } @@ -774,13 +844,13 @@ int fun_random(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) delta = -delta; if (delta == 0) { - RESULTINT = 0; + *result = ValInt{0}; return 0; } - RESULTINT = random_::to(delta); + *result = ValInt{random_::to(delta)}; if (ARGINT(0) < 0) - RESULTINT = -RESULTINT; + result->get_if<ValInt>()->v_int *= -1; return 0; } @@ -788,16 +858,16 @@ static int fun_random_dir(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (ARGINT(0)) - RESULTDIR = random_::choice({DIR::S, DIR::SW, DIR::W, DIR::NW, DIR::N, DIR::NE, DIR::E, DIR::SE}); + *result = ValDir{random_::choice({DIR::S, DIR::SW, DIR::W, DIR::NW, DIR::N, DIR::NE, DIR::E, DIR::SE})}; else - RESULTDIR = random_::choice({DIR::S, DIR::W, DIR::N, DIR::E}); + *result = ValDir{random_::choice({DIR::S, DIR::W, DIR::N, DIR::E})}; return 0; } static int fun_hash_entity(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = unwrap<BlockId>(ARGENTITY(0)->bl_id); + *result = ValInt{static_cast<int32_t>(unwrap<BlockId>(ARGENTITY(0)->bl_id))}; return 0; } @@ -807,9 +877,9 @@ int magic_find_item(Slice<val_t> args, int index, Item *item_, int *stackable) struct item_data *item_data; int must_add_sequentially; - if (ARG_TYPE(index) == TYPE::INT) + if (args[index].is<ValInt>()) item_data = itemdb_exists(wrap<ItemNameId>(static_cast<uint16_t>(ARGINT(index)))); - else if (ARG_TYPE(index) == TYPE::STRING) + else if (args[index].is<ValString>()) item_data = itemdb_searchname(ARGSTR(index)); else return -1; @@ -845,7 +915,7 @@ int fun_count_item(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) if (!chr) return 1; - RESULTINT = pc_count_all_items(chr, item.nameid); + *result = ValInt{pc_count_all_items(chr, item.nameid)}; return 0; } @@ -872,28 +942,28 @@ int fun_is_equipped(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) } } - RESULTINT = retval; + *result = ValInt{retval}; return 0; } static int fun_is_married(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = (ENTITY_TYPE(0) == BL::PC && ARGPC(0)->status.partner_id); + *result = ValInt{(ENTITY_TYPE(0) == BL::PC && ARGPC(0)->status.partner_id)}; return 0; } static int fun_is_dead(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = (ENTITY_TYPE(0) == BL::PC && pc_isdead(ARGPC(0))); + *result = ValInt{(ENTITY_TYPE(0) == BL::PC && pc_isdead(ARGPC(0)))}; return 0; } static int fun_is_pc(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = (ENTITY_TYPE(0) == BL::PC); + *result = ValInt{(ENTITY_TYPE(0) == BL::PC)}; return 0; } @@ -902,8 +972,8 @@ int fun_partner(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (ENTITY_TYPE(0) == BL::PC && ARGPC(0)->status.partner_id) { - RESULTENTITY = - map_nick2sd(map_charid2nick(ARGPC(0)->status.partner_id)); + *result = + ValEntityPtr{map_nick2sd(map_charid2nick(ARGPC(0)->status.partner_id))}; return 0; } else @@ -925,14 +995,14 @@ int fun_awayfrom(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) loc->y += dy; } - RESULTLOCATION = *loc; + *result = ValLocation{*loc}; return 0; } static int fun_failed(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARG_TYPE(0) == TYPE::FAIL; + *result = ValInt{args[0].is<ValFail>()}; return 0; } @@ -940,26 +1010,28 @@ static int fun_npc(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { NpcName name = stringish<NpcName>(ARGSTR(0)); - RESULTENTITY = npc_name2id(name); - return RESULTENTITY == nullptr; + dumb_ptr<npc_data> npc = npc_name2id(name); + *result = ValEntityPtr{npc}; + return npc == nullptr; } static int fun_pc(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { CharName name = stringish<CharName>(ARGSTR(0)); - RESULTENTITY = map_nick2sd(name); - return RESULTENTITY == nullptr; + dumb_ptr<map_session_data> chr = map_nick2sd(name); + *result = ValEntityPtr{chr}; + return chr == nullptr; } static int fun_distance(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (ARGLOCATION(0).m != ARGLOCATION(1).m) - RESULTINT = 0x7fffffff; + *result = ValInt{0x7fffffff}; else - RESULTINT = std::max(abs(ARGLOCATION(0).x - ARGLOCATION(1).x), - abs(ARGLOCATION(0).y - ARGLOCATION(1).y)); + *result = ValInt{std::max(abs(ARGLOCATION(0).x - ARGLOCATION(1).x), + abs(ARGLOCATION(0).y - ARGLOCATION(1).y))}; return 0; } @@ -967,12 +1039,12 @@ static int fun_rdistance(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (ARGLOCATION(0).m != ARGLOCATION(1).m) - RESULTINT = 0x7fffffff; + *result = ValInt{0x7fffffff}; else { int dx = ARGLOCATION(0).x - ARGLOCATION(1).x; int dy = ARGLOCATION(0).y - ARGLOCATION(1).y; - RESULTINT = static_cast<int>(sqrt((dx * dx) + (dy * dy))); + *result = ValInt{static_cast<int>(sqrt((dx * dx) + (dy * dy)))}; } return 0; } @@ -988,7 +1060,7 @@ int fun_anchor(dumb_ptr<env_t> env, val_t *result, Slice<val_t> args) magic_eval(env, result, anchor->location); make_area(result); - if (result->ty != TYPE::AREA) + if (!result->is<ValArea>()) { magic_clear_var(result); return 1; @@ -1005,28 +1077,48 @@ int fun_line_of_sight(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) COPY_LOCATION(e1, ARGLOCATION(0)); COPY_LOCATION(e2, ARGLOCATION(1)); - RESULTINT = battle_check_range(dumb_ptr<block_list>(&e1), dumb_ptr<block_list>(&e2), 0); + *result = ValInt{battle_check_range(dumb_ptr<block_list>(&e1), dumb_ptr<block_list>(&e2), 0)}; return 0; } void magic_random_location(location_t *dest, dumb_ptr<area_t> area) { - switch (area->ty) + MATCH (*area) { - case AREA::UNION: + CASE (const AreaUnion&, a) { - if (random_::chance({area->a.a_union[0]->size, area->size})) - magic_random_location(dest, area->a.a_union[0]); + if (random_::chance({a.a_union[0]->size, area->size})) + magic_random_location(dest, a.a_union[0]); else - magic_random_location(dest, area->a.a_union[1]); - break; + magic_random_location(dest, a.a_union[1]); } + CASE (const location_t&, a_loc) + { + (void)a_loc; + // TODO this can be simplified + map_local *m; + int x, y, w, h; + magic_area_rect(&m, &x, &y, &w, &h, *area); + + if (w <= 1) + w = 1; - case AREA::LOCATION: - case AREA::RECT: - case AREA::BAR: + if (h <= 1) + h = 1; + + // This is not exactly the same as the old logic, + // but it's better. + auto pair = map_randfreecell(m, x, y, w, h); + + dest->m = m; + dest->x = pair.first; + dest->y = pair.second; + } + CASE (const AreaRect&, a_rect) { + (void)a_rect; + // TODO this can be simplified map_local *m; int x, y, w, h; magic_area_rect(&m, &x, &y, &w, &h, *area); @@ -1044,19 +1136,38 @@ void magic_random_location(location_t *dest, dumb_ptr<area_t> area) dest->m = m; dest->x = pair.first; dest->y = pair.second; - break; } + CASE (const AreaBar&, a_bar) + { + (void)a_bar; + // TODO this is wrong + map_local *m; + int x, y, w, h; + magic_area_rect(&m, &x, &y, &w, &h, *area); - default: - FPRINTF(stderr, "Unknown area type %d\n"_fmt, - area->ty); + if (w <= 1) + w = 1; + + if (h <= 1) + h = 1; + + // This is not exactly the same as the old logic, + // but it's better. + auto pair = map_randfreecell(m, x, y, w, h); + + dest->m = m; + dest->x = pair.first; + dest->y = pair.second; + } } } static int fun_pick_location(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - magic_random_location(&result->v.v_location, ARGAREA(0)); + location_t loc; + magic_random_location(&loc, ARGAREA(0)); + *result = ValLocation{loc}; return 0; } @@ -1070,7 +1181,7 @@ int fun_read_script_int(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) if (subject_p->bl_type != BL::PC) return 1; - RESULTINT = get_script_var_i(subject_p->is_player(), var_name, array_index); + *result = ValInt{get_script_var_i(subject_p->is_player(), var_name, array_index)}; return 0; } @@ -1084,7 +1195,7 @@ int fun_read_script_str(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) if (subject_p->bl_type != BL::PC) return 1; - RESULTSTR = dumb_string::copys(get_script_var_s(subject_p->is_player(), var_name, array_index)); + *result = ValString{dumb_string::copys(get_script_var_s(subject_p->is_player(), var_name, array_index))}; return 0; } @@ -1094,12 +1205,13 @@ int fun_rbox(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) location_t loc = ARGLOCATION(0); int radius = ARGINT(1); - RESULTAREA = area_new(AREA::RECT); - RESULTAREA->a.a_rect.loc.m = loc.m; - RESULTAREA->a.a_rect.loc.x = loc.x - radius; - RESULTAREA->a.a_rect.loc.y = loc.y - radius; - RESULTAREA->a.a_rect.width = radius * 2 + 1; - RESULTAREA->a.a_rect.height = radius * 2 + 1; + AreaRect a_rect; + a_rect.loc.m = loc.m; + a_rect.loc.x = loc.x - radius; + a_rect.loc.y = loc.y - radius; + a_rect.width = radius * 2 + 1; + a_rect.height = radius * 2 + 1; + *result = ValArea{dumb_ptr<area_t>::make(a_rect, a_rect.width * a_rect.height)}; return 0; } @@ -1111,28 +1223,28 @@ int fun_running_status_update(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) return 1; StatusChange sc = static_cast<StatusChange>(ARGINT(1)); - RESULTINT = bool(battle_get_sc_data(ARGENTITY(0))[sc].timer); + *result = ValInt{bool(battle_get_sc_data(ARGENTITY(0))[sc].timer)}; return 0; } static int fun_status_option(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = (bool((ARGPC(0))->status.option & static_cast<Option>(ARGINT(1)))); + *result = ValInt{(bool((ARGPC(0))->status.option & static_cast<Option>(ARGINT(1))))}; return 0; } static int fun_element(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = static_cast<int>(battle_get_element(ARGENTITY(0)).element); + *result = ValInt{static_cast<int>(battle_get_element(ARGENTITY(0)).element)}; return 0; } static int fun_element_level(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = battle_get_element(ARGENTITY(0)).level; + *result = ValInt{battle_get_element(ARGENTITY(0)).level}; return 0; } @@ -1140,14 +1252,14 @@ static int fun_is_exterior(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { #warning "Evil assumptions!" - RESULTINT = ARGLOCATION(0).m->name_[4] == '1'; + *result = ValInt{ARGLOCATION(0).m->name_[4] == '1'}; return 0; } static int fun_contains_string(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = nullptr != strstr(ARGSTR(0).c_str(), ARGSTR(1).c_str()); + *result = ValInt{nullptr != strstr(ARGSTR(0).c_str(), ARGSTR(1).c_str())}; return 0; } @@ -1155,14 +1267,14 @@ static int fun_strstr(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { const char *offset = strstr(ARGSTR(0).c_str(), ARGSTR(1).c_str()); - RESULTINT = offset - ARGSTR(0).c_str(); + *result = ValInt{static_cast<int32_t>(offset - ARGSTR(0).c_str())}; return offset == nullptr; } static int fun_strlen(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = strlen(ARGSTR(0).c_str()); + *result = ValInt{static_cast<int32_t>(strlen(ARGSTR(0).c_str()))}; return 0; } @@ -1187,7 +1299,7 @@ int fun_substr(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) const char *begin = src + offset; const char *end = begin + len; - RESULTSTR = dumb_string::copy(begin, end); + *result = ValString{dumb_string::copy(begin, end)}; return 0; } @@ -1195,7 +1307,7 @@ int fun_substr(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) static int fun_sqrt(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = static_cast<int>(sqrt(ARGINT(0))); + *result = ValInt{static_cast<int>(sqrt(ARGINT(0)))}; return 0; } @@ -1203,7 +1315,7 @@ static int fun_map_level(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { #warning "Evil assumptions!" - RESULTINT = ARGLOCATION(0).m->name_[4] - '0'; + *result = ValInt{ARGLOCATION(0).m->name_[4] - '0'}; return 0; } @@ -1213,8 +1325,8 @@ int fun_map_nr(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) #warning "Evil assumptions!" MapName mapname = ARGLOCATION(0).m->name_; - RESULTINT = ((mapname[0] - '0') * 100) - + ((mapname[1] - '0') * 10) + ((mapname[2] - '0')); + *result = ValInt{((mapname[0] - '0') * 100) + + ((mapname[1] - '0') * 10) + ((mapname[2] - '0'))}; return 0; } @@ -1236,30 +1348,30 @@ int fun_dir_towards(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) if (abs(dx) > abs(dy) * 2) { /* east or west */ if (dx < 0) - RESULTINT = 2 /* west */ ; + *result = ValDir{DIR::W}; else - RESULTINT = 6 /* east */ ; + *result = ValDir{DIR::E}; } else if (abs(dy) > abs(dx) * 2) { /* north or south */ if (dy > 0) - RESULTINT = 0 /* south */ ; + *result = ValDir{DIR::S}; else - RESULTINT = 4 /* north */ ; + *result = ValDir{DIR::N}; } else if (dx < 0) { /* north-west or south-west */ if (dy < 0) - RESULTINT = 3 /* north-west */ ; + *result = ValDir{DIR::NW}; else - RESULTINT = 1 /* south-west */ ; + *result = ValDir{DIR::SW}; } else { /* north-east or south-east */ if (dy < 0) - RESULTINT = 5 /* north-east */ ; + *result = ValDir{DIR::NE}; else - RESULTINT = 7 /* south-east */ ; + *result = ValDir{DIR::SE}; } } else @@ -1268,16 +1380,16 @@ int fun_dir_towards(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) if (abs(dx) > abs(dy)) { /* east or west */ if (dx < 0) - RESULTINT = 2 /* west */ ; + *result = ValDir{DIR::W}; else - RESULTINT = 6 /* east */ ; + *result = ValDir{DIR::E}; } else { /* north or south */ if (dy > 0) - RESULTINT = 0 /* south */ ; + *result = ValDir{DIR::S}; else - RESULTINT = 4 /* north */ ; + *result = ValDir{DIR::N}; } } @@ -1290,9 +1402,9 @@ int fun_extract_healer_xp(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) dumb_ptr<map_session_data> sd = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr; if (!sd) - RESULTINT = 0; + *result = ValInt{0}; else - RESULTINT = pc_extract_healer_exp(sd, ARGINT(1)); + *result = ValInt{pc_extract_healer_exp(sd, ARGINT(1))}; return 0; } @@ -1391,24 +1503,24 @@ fun_t *magic_get_fun(ZString name) // 1 on failure static -int eval_location(dumb_ptr<env_t> env, location_t *dest, e_location_t *expr) +int eval_location(dumb_ptr<env_t> env, location_t *dest, const e_location_t *expr) { val_t m, x, y; magic_eval(env, &m, expr->m); magic_eval(env, &x, expr->x); magic_eval(env, &y, expr->y); - if (CHECK_TYPE(&m, TYPE::STRING) - && CHECK_TYPE(&x, TYPE::INT) && CHECK_TYPE(&y, TYPE::INT)) + if (m.is<ValString>() + && x.is<ValInt>() && y.is<ValInt>()) { - MapName name = VString<15>(ZString(m.v.v_string)); + MapName name = VString<15>(ZString(m.get_if<ValString>()->v_string)); map_local *map_id = map_mapname2mapid(name); magic_clear_var(&m); if (!map_id) return 1; dest->m = map_id; - dest->x = x.v.v_int; - dest->y = y.v.v_int; + dest->x = x.get_if<ValInt>()->v_int; + dest->y = y.get_if<ValInt>()->v_int; return 0; } else @@ -1421,141 +1533,145 @@ int eval_location(dumb_ptr<env_t> env, location_t *dest, e_location_t *expr) } static -dumb_ptr<area_t> eval_area(dumb_ptr<env_t> env, e_area_t& expr_) +dumb_ptr<area_t> eval_area(dumb_ptr<env_t> env, const e_area_t& expr_) { - e_area_t *expr = &expr_; // temporary hack to reduce diff - auto area = dumb_ptr<area_t>::make(); - area->ty = expr->ty; - - switch (expr->ty) + MATCH (expr_) { - case AREA::LOCATION: - area->size = 1; - if (eval_location(env, &area->a.a_loc, &expr->a.a_loc)) + CASE (const e_location_t&, a_loc) + { + location_t loc; + int size = 1; + if (eval_location(env, &loc, &a_loc)) { - area.delete_(); return nullptr; } else - return area; - - case AREA::UNION: + { + return dumb_ptr<area_t>::make(loc, size); + } + } + CASE (const ExprAreaUnion&, a) { - int i, fail = 0; - for (i = 0; i < 2; i++) + AreaUnion u; + bool fail = false; + for (int i = 0; i < 2; i++) { - area->a.a_union[i] = eval_area(env, *expr->a.a_union[i]); - if (!area->a.a_union[i]) - fail = 1; + u.a_union[i] = eval_area(env, *a.a_union[i]); + if (!u.a_union[i]) + fail = true; } if (fail) { - for (i = 0; i < 2; i++) + for (int i = 0; i < 2; i++) { - if (area->a.a_union[i]) - free_area(area->a.a_union[i]); + if (u.a_union[i]) + free_area(u.a_union[i]); } - area.delete_(); return nullptr; } - area->size = area->a.a_union[0]->size + area->a.a_union[1]->size; - return area; + int size = u.a_union[0]->size + u.a_union[1]->size; + return dumb_ptr<area_t>::make(u, size); } - - case AREA::RECT: + CASE (const ExprAreaRect&, a_rect) { val_t width, height; - magic_eval(env, &width, expr->a.a_rect.width); - magic_eval(env, &height, expr->a.a_rect.height); - - area->a.a_rect.width = width.v.v_int; - area->a.a_rect.height = height.v.v_int; - - if (CHECK_TYPE(&width, TYPE::INT) - && CHECK_TYPE(&height, TYPE::INT) - && !eval_location(env, &(area->a.a_rect.loc), - &expr->a.a_rect.loc)) + magic_eval(env, &width, a_rect.width); + magic_eval(env, &height, a_rect.height); + + AreaRect a_rect_; + if (width.is<ValInt>() + && height.is<ValInt>() + && !eval_location(env, &(a_rect_.loc), + &a_rect.loc)) { - area->size = area->a.a_rect.width * area->a.a_rect.height; + a_rect_.width = width.get_if<ValInt>()->v_int; + a_rect_.height = height.get_if<ValInt>()->v_int; + + int size = a_rect_.width * a_rect_.height; magic_clear_var(&width); magic_clear_var(&height); - return area; + return dumb_ptr<area_t>::make(a_rect_, size); } else { - area.delete_(); magic_clear_var(&width); magic_clear_var(&height); return nullptr; } } - - case AREA::BAR: + CASE (const ExprAreaBar&, a_bar) { val_t width, depth, dir; - magic_eval(env, &width, expr->a.a_bar.width); - magic_eval(env, &depth, expr->a.a_bar.depth); - magic_eval(env, &dir, expr->a.a_bar.dir); - - area->a.a_bar.width = width.v.v_int; - area->a.a_bar.depth = depth.v.v_int; - area->a.a_bar.dir = dir.v.v_dir; - - if (CHECK_TYPE(&width, TYPE::INT) - && CHECK_TYPE(&depth, TYPE::INT) - && CHECK_TYPE(&dir, TYPE::DIR) - && !eval_location(env, &area->a.a_bar.loc, - &expr->a.a_bar.loc)) + magic_eval(env, &width, a_bar.width); + magic_eval(env, &depth, a_bar.depth); + magic_eval(env, &dir, a_bar.dir); + + AreaBar a_bar_; + if (width.is<ValInt>() + && depth.is<ValInt>() + && dir.is<ValDir>() + && !eval_location(env, &a_bar_.loc, + &a_bar.loc)) { - area->size = - (area->a.a_bar.width * 2 + 1) * area->a.a_bar.depth; + a_bar_.width = width.get_if<ValInt>()->v_int; + a_bar_.depth = depth.get_if<ValInt>()->v_int; + a_bar_.dir = dir.get_if<ValDir>()->v_dir; + + int size = (a_bar_.width * 2 + 1) * a_bar_.depth; magic_clear_var(&width); magic_clear_var(&depth); magic_clear_var(&dir); - return area; + return dumb_ptr<area_t>::make(a_bar_, size); } else { - area.delete_(); magic_clear_var(&width); magic_clear_var(&depth); magic_clear_var(&dir); return nullptr; } } - - default: - FPRINTF(stderr, "INTERNAL ERROR: Unknown area type %d\n"_fmt, - area->ty); - area.delete_(); - return nullptr; } + abort(); } +// This is called on arguments with begin=true, +// and on the return value with begin=false. +// In both cases, the ambiguous types are in pointer mode. static -TYPE type_key(char ty_key) +bool type_key_matches(char ty_key, val_t *arg, bool begin) { switch (ty_key) { case 'i': - return TYPE::INT; + if (begin) + intify(arg); + return arg->is<ValInt>(); case 'd': - return TYPE::DIR; + return arg->is<ValDir>(); case 's': - return TYPE::STRING; + if (begin) + stringify(arg); + return arg->is<ValString>(); case 'e': - return TYPE::ENTITY; + return arg->is<ValEntityPtr>(); case 'l': - return TYPE::LOCATION; + if (begin) + make_location(arg); + return arg->is<ValLocation>(); case 'a': - return TYPE::AREA; + if (begin) + make_area(arg); + return arg->is<ValArea>(); case 'S': - return TYPE::SPELL; + if (begin) + make_spell(arg); + return arg->is<ValSpell>(); case 'I': - return TYPE::INVOCATION; + return arg->is<ValInvocationPtr>(); default: - return TYPE::NEGATIVE_1; + return true; } } @@ -1566,24 +1682,35 @@ int magic_signature_check(ZString opname, ZString funname, ZString signature, for (i = 0; i < args.size(); i++) { val_t *arg = &args[i]; - char ty_key = signature[i]; - TYPE ty = arg->ty; - TYPE desired_ty = type_key(ty_key); - if (ty == TYPE::ENTITY) + // whoa, it turns out the second p *does* shadow this one + if (ValEntityInt *p1 = arg->get_if<ValEntityInt>()) { /* Dereference entities in preparation for calling function */ - arg->v.v_entity = map_id2bl(wrap<BlockId>(static_cast<uint32_t>(arg->v.v_int))); - if (!arg->v.v_entity) - ty = arg->ty = TYPE::FAIL; + dumb_ptr<block_list> ent = map_id2bl(p1->v_eid); + if (ent) + { + *arg = ValEntityPtr{ent}; + } + else + { + *arg = ValFail{}; + } } - else if (ty == TYPE::INVOCATION) + else if (ValInvocationInt *p2 = arg->get_if<ValInvocationInt>()) { - arg->v.v_invocation = map_id2bl(wrap<BlockId>(static_cast<uint32_t>(arg->v.v_int)))->is_spell(); - if (!arg->v.v_entity) - ty = arg->ty = TYPE::FAIL; + dumb_ptr<invocation> invoc = map_id2bl(p2->v_iid)->is_spell(); + if (invoc) + { + *arg = ValInvocationPtr{invoc}; + } + else + { + *arg = ValFail(); + } } + char ty_key = signature[i]; if (!ty_key) { FPRINTF(stderr, @@ -1592,13 +1719,14 @@ int magic_signature_check(ZString opname, ZString funname, ZString signature, return 1; } - if (ty == TYPE::FAIL && ty_key != '_') + if (arg->is<ValFail>() && ty_key != '_') return 1; /* Fail `in a sane way': This is a perfectly permissible error */ - if (ty == desired_ty || desired_ty == TYPE::NEGATIVE_1) + // this also does conversions now + if (type_key_matches(ty_key, arg, true)) continue; - if (ty == TYPE::UNDEF) + if (arg->is<ValUndef>()) { FPRINTF(stderr, "[magic-eval]: L%d:%d: Argument #%d to %s `%s' undefined\n"_fmt, @@ -1606,36 +1734,14 @@ int magic_signature_check(ZString opname, ZString funname, ZString signature, return 1; } - /* If we are here, we have a type mismatch but no failure _yet_. Try to coerce. */ - switch (desired_ty) - { - case TYPE::INT: - intify(arg); - break; /* 100% success rate */ - case TYPE::STRING: - stringify(arg, 1); - break; /* 100% success rate */ - case TYPE::AREA: - make_area(arg); - break; /* Only works for locations */ - case TYPE::LOCATION: - make_location(arg); - break; /* Only works for some areas */ - case TYPE::SPELL: - make_spell(arg); - break; /* Only works for still-active invocatoins */ - default: - break; /* We'll fail right below */ - } - ty = arg->ty; - if (ty != desired_ty) { /* Coercion failed? */ - if (ty != TYPE::FAIL) + if (!arg->is<ValFail>()) + { FPRINTF(stderr, - "[magic-eval]: L%d:%d: Argument #%d to %s `%s' of incorrect type (%d)\n"_fmt, - line, column, i + 1, opname, funname, - ty); + "[magic-eval]: L%d:%d: Argument #%d to %s `%s' of incorrect type (sorry, types aren't integers anymore)\n"_fmt, + line, column, i + 1, opname, funname); + } return 1; } } @@ -1645,82 +1751,83 @@ int magic_signature_check(ZString opname, ZString funname, ZString signature, void magic_eval(dumb_ptr<env_t> env, val_t *dest, dumb_ptr<expr_t> expr) { - switch (expr->ty) + MATCH (*expr) { - case EXPR::VAL: - magic_copy_var(dest, &expr->e.e_val); - break; + CASE (const val_t&, e_val) + { + magic_copy_var(dest, &e_val); + } - case EXPR::LOCATION: - if (eval_location(env, &dest->v.v_location, &expr->e.e_location)) - dest->ty = TYPE::FAIL; + CASE (const e_location_t&, e_location) + { + location_t loc; + if (eval_location(env, &loc, &e_location)) + *dest = ValFail(); else - dest->ty = TYPE::LOCATION; - break; - - case EXPR::AREA: - if ((dest->v.v_area = eval_area(env, expr->e.e_area))) - dest->ty = TYPE::AREA; + *dest = ValLocation{loc}; + } + CASE (const e_area_t&, e_area) + { + if (dumb_ptr<area_t> area = eval_area(env, e_area)) + *dest = ValArea{area}; else - dest->ty = TYPE::FAIL; - break; - - case EXPR::FUNAPP: + *dest = ValFail(); + } + CASE (const ExprFunApp&, e_funapp) { val_t arguments[MAX_ARGS]; - int args_nr = expr->e.e_funapp.args_nr; + int args_nr = e_funapp.args_nr; int i; - fun_t *f = expr->e.e_funapp.funp; + fun_t *f = e_funapp.funp; for (i = 0; i < args_nr; ++i) - magic_eval(env, &arguments[i], expr->e.e_funapp.args[i]); + magic_eval(env, &arguments[i], e_funapp.args[i]); if (magic_signature_check("function"_s, f->name, f->signature, Slice<val_t>(arguments, args_nr), - expr->e.e_funapp.line_nr, expr->e.e_funapp.column) + e_funapp.line_nr, e_funapp.column) || f->fun(env, dest, Slice<val_t>(arguments, args_nr))) - dest->ty = TYPE::FAIL; + *dest = ValFail(); else { - TYPE dest_ty = type_key(f->ret_ty); - if (dest_ty != TYPE::NEGATIVE_1) - dest->ty = dest_ty; + assert (!dest->is<ValInvocationPtr>()); + assert (!dest->is<ValInvocationInt>()); + assert (!dest->is<ValEntityInt>()); + assert (type_key_matches(f->ret_ty, dest, false)); /* translate entity back into persistent int */ - if (dest->ty == TYPE::ENTITY) + if (ValEntityPtr *ent = dest->get_if<ValEntityPtr>()) { - if (dest->v.v_entity) - dest->v.v_int = static_cast<int32_t>(unwrap<BlockId>(dest->v.v_entity->bl_id)); + if (ent->v_entity) + *dest = ValEntityInt{ent->v_entity->bl_id}; else - dest->ty = TYPE::FAIL; + *dest = ValFail(); } + // what about invocation? } for (i = 0; i < args_nr; ++i) magic_clear_var(&arguments[i]); - break; } - - case EXPR::ID: + CASE (const ExprId&, e) { - val_t v = env->VAR(expr->e.e_id); + val_t& v = env->VAR(e.e_id); magic_copy_var(dest, &v); - break; } - - case EXPR::SPELLFIELD: + CASE (const ExprField&, e_field) { val_t v; - int id = expr->e.e_field.id; - magic_eval(env, &v, expr->e.e_field.expr); + int id = e_field.id; + magic_eval(env, &v, e_field.expr); - if (v.ty == TYPE::INVOCATION) + assert(!v.is<ValInvocationPtr>()); + if (ValInvocationInt *ii = v.get_if<ValInvocationInt>()) { - dumb_ptr<invocation> t = map_id2bl(wrap<BlockId>(static_cast<uint32_t>(v.v.v_int)))->is_spell(); + dumb_ptr<invocation> t = map_id2bl(ii->v_iid)->is_spell(); if (!t) - dest->ty = TYPE::UNDEF; + *dest = ValUndef(); else { - val_t val = t->env->VAR(id); + val_t& val = t->env->VAR(id); magic_copy_var(dest, &val); } } @@ -1729,16 +1836,9 @@ void magic_eval(dumb_ptr<env_t> env, val_t *dest, dumb_ptr<expr_t> expr) FPRINTF(stderr, "[magic] Attempt to access field %s on non-spell\n"_fmt, env->base_env->varv[id].name); - dest->ty = TYPE::FAIL; + *dest = ValFail(); } - break; } - - default: - FPRINTF(stderr, - "[magic] INTERNAL ERROR: Unknown expression type %d\n"_fmt, - expr->ty); - break; } } @@ -1747,12 +1847,12 @@ int magic_eval_int(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr) val_t result; magic_eval(env, &result, expr); - if (result.ty == TYPE::FAIL || result.ty == TYPE::UNDEF) + if (result.is<ValFail>() || result.is<ValUndef>()) return 0; intify(&result); - return result.v.v_int; + return result.get_if<ValInt>()->v_int; } AString magic_eval_str(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr) @@ -1760,19 +1860,13 @@ AString magic_eval_str(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr) val_t result; magic_eval(env, &result, expr); - if (result.ty == TYPE::FAIL || result.ty == TYPE::UNDEF) + if (result.is<ValFail>() || result.is<ValUndef>()) return "?"_s; - stringify(&result, 0); + // is this a memory leak? + stringify(&result); - return result.v.v_string.str(); -} - -dumb_ptr<expr_t> magic_new_expr(EXPR ty) -{ - auto expr = dumb_ptr<expr_t>::make(); - expr->ty = ty; - return expr; + return result.get_if<ValString>()->v_string.str(); } } // namespace magic } // namespace tmwa diff --git a/src/map/magic-expr.hpp b/src/map/magic-expr.hpp index 4c1efe2..294e665 100644 --- a/src/map/magic-expr.hpp +++ b/src/map/magic-expr.hpp @@ -80,11 +80,9 @@ int magic_eval_int(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr); */ AString magic_eval_str(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr); -dumb_ptr<expr_t> magic_new_expr(EXPR ty); - void magic_clear_var(val_t *v); -void magic_copy_var(val_t *dest, val_t *src); +void magic_copy_var(val_t *dest, const val_t *src); void magic_random_location(location_t *dest, dumb_ptr<area_t> area); diff --git a/src/map/magic-interpreter-base.cpp b/src/map/magic-interpreter-base.cpp index cc09ed9..1ac391a 100644 --- a/src/map/magic-interpreter-base.cpp +++ b/src/map/magic-interpreter-base.cpp @@ -42,53 +42,41 @@ namespace tmwa namespace magic { static -void set_int_p(val_t *v, int i, TYPE t) +void set_int(val_t *v, int i) { - v->ty = t; - v->v.v_int = i; + *v = ValInt{i}; } -#warning "This code should die" -DIAG_PUSH(); -DIAG_I(unused_macros); - -#define set_int(v, i) set_int_p(v, i, TYPE::INT) -#define set_dir(v, i) set_int_p(v, i, TYPE::DIR) +static __attribute__((unused)) +void set_dir(val_t *v, DIR d) +{ + *v = ValDir{d}; +} -#define SETTER(tty, dyn_ty, field) (val_t *v, tty x) { v->ty = dyn_ty; v->v.field = x; } static -void set_string SETTER(dumb_string, TYPE::STRING, v_string) +void set_string(val_t *v, dumb_string x) +{ + *v = ValString{x}; +} static void set_entity(val_t *v, dumb_ptr<block_list> e) { - v->ty = TYPE::ENTITY; - v->v.v_int = static_cast<int32_t>(unwrap<BlockId>(e->bl_id)); + *v = ValEntityInt{e->bl_id}; } static void set_invocation(val_t *v, dumb_ptr<invocation> i) { - v->ty = TYPE::INVOCATION; - v->v.v_int = static_cast<int32_t>(unwrap<BlockId>(i->bl_id)); + *v = ValInvocationInt{i->bl_id}; } static -void set_spell SETTER(dumb_ptr<spell_t>, TYPE::SPELL, v_spell) - -#define setenv(f, v, x) f(&(env->varu[v]), x) - -#define set_env_int(v, x) setenv(set_int, v, x) -#define set_env_dir(v, x) setenv(set_dir, v, x) -#define set_env_string(v, x) setenv(set_string, v, x) -#define set_env_entity(v, x) setenv(set_entity, v, x) -#define set_env_location(v, x) setenv(set_location, v, x) -#define set_env_area(v, x) setenv(set_area, v, x) -#define set_env_invocation(v, x) setenv(set_invocation, v, x) -#define set_env_spell(v, x) setenv(set_spell, v, x) - -DIAG_POP(); +void set_spell(val_t *v, dumb_ptr<spell_t> x) +{ + *v = ValSpell{x}; +} magic_conf_t magic_conf; /* Global magic conf */ env_t magic_default_env = { &magic_conf, nullptr }; @@ -176,7 +164,7 @@ dumb_ptr<env_t> spell_create_env(magic_conf_t *conf, dumb_ptr<spell_t> spell, { case SPELLARG::STRING: - set_env_string(spell->arg, dumb_string::copys(param)); + set_string(&env->varu[spell->arg], dumb_string::copys(param)); break; case SPELLARG::PC: @@ -185,7 +173,7 @@ dumb_ptr<env_t> spell_create_env(magic_conf_t *conf, dumb_ptr<spell_t> spell, dumb_ptr<map_session_data> subject = map_nick2sd(name); if (!subject) subject = caster; - set_env_entity(spell->arg, subject); + set_entity(&env->varu[spell->arg], subject); break; } @@ -197,9 +185,9 @@ dumb_ptr<env_t> spell_create_env(magic_conf_t *conf, dumb_ptr<spell_t> spell, spell->spellarg_ty); } - set_env_entity(VAR_CASTER, caster); - set_env_int(VAR_SPELLPOWER, spellpower); - set_env_spell(VAR_SPELL, spell); + set_entity(&env->varu[VAR_CASTER], caster); + set_int(&env->varu[VAR_SPELLPOWER], spellpower); + set_spell(&env->varu[VAR_SPELL], spell); return env; } @@ -301,8 +289,10 @@ int spellguard_can_satisfy(spellguard_check_t *check, dumb_ptr<map_session_data> { interval_t casttime = check->casttime; - if (env->VAR(VAR_MIN_CASTTIME).ty == TYPE::INT) - casttime = std::max(casttime, static_cast<interval_t>(env->VAR(VAR_MIN_CASTTIME).v.v_int)); + if (ValInt *v = env->VAR(VAR_MIN_CASTTIME).get_if<ValInt>()) + { + casttime = std::max(casttime, static_cast<interval_t>(v->v_int)); + } caster->cast_tick = tick + casttime; /* Make sure not to cast too frequently */ @@ -314,7 +304,7 @@ int spellguard_can_satisfy(spellguard_check_t *check, dumb_ptr<map_session_data> } static -effect_set_t *spellguard_check_sub(spellguard_check_t *check, +const effect_set_t *spellguard_check_sub(spellguard_check_t *check, dumb_ptr<spellguard_t> guard, dumb_ptr<map_session_data> caster, dumb_ptr<env_t> env, @@ -323,25 +313,25 @@ effect_set_t *spellguard_check_sub(spellguard_check_t *check, if (guard == nullptr) return nullptr; - switch (guard->ty) + MATCH (*guard) { - case SPELLGUARD::CONDITION: - if (!magic_eval_int(env, guard->s.s_condition)) + CASE (const GuardCondition&, s) + { + if (!magic_eval_int(env, s.s_condition)) return nullptr; - break; - - case SPELLGUARD::COMPONENTS: - copy_components(&check->components, guard->s.s_components); - break; - - case SPELLGUARD::CATALYSTS: - copy_components(&check->catalysts, guard->s.s_catalysts); - break; - - case SPELLGUARD::CHOICE: + } + CASE (const GuardComponents&, s) + { + copy_components(&check->components, s.s_components); + } + CASE (const GuardCatalysts&, s) + { + copy_components(&check->catalysts, s.s_catalysts); + } + CASE (const GuardChoice&, s) { spellguard_check_t altcheck = *check; - effect_set_t *retval; + const effect_set_t *retval; altcheck.components = nullptr; altcheck.catalysts = nullptr; @@ -357,40 +347,36 @@ effect_set_t *spellguard_check_sub(spellguard_check_t *check, if (retval) return retval; else - return spellguard_check_sub(check, guard->s.s_alt, caster, + return spellguard_check_sub(check, s.s_alt, caster, env, near_miss); } - - case SPELLGUARD::MANA: - check->mana += magic_eval_int(env, guard->s.s_mana); - break; - - case SPELLGUARD::CASTTIME: - check->casttime += static_cast<interval_t>(magic_eval_int(env, guard->s.s_mana)); - break; - - case SPELLGUARD::EFFECT: + CASE (const GuardMana&, s) + { + check->mana += magic_eval_int(env, s.s_mana); + } + CASE (const GuardCastTime&, s) + { + check->casttime += static_cast<interval_t>(magic_eval_int(env, s.s_casttime)); + } + CASE (const effect_set_t&, s_effect) + { if (spellguard_can_satisfy(check, caster, env, near_miss)) - return &guard->s.s_effect; + return &s_effect; else return nullptr; - - default: - FPRINTF(stderr, "Unexpected spellguard type %d\n"_fmt, - guard->ty); - return nullptr; + } } return spellguard_check_sub(check, guard->next, caster, env, near_miss); } static -effect_set_t *check_spellguard(dumb_ptr<spellguard_t> guard, +const effect_set_t *check_spellguard(dumb_ptr<spellguard_t> guard, dumb_ptr<map_session_data> caster, dumb_ptr<env_t> env, int *near_miss) { spellguard_check_t check; - effect_set_t *retval; + const effect_set_t *retval; check.catalysts = nullptr; check.components = nullptr; check.mana = 0; @@ -408,7 +394,7 @@ effect_set_t *check_spellguard(dumb_ptr<spellguard_t> guard, /* Public API */ /* -------------------------------------------------------------------------------- */ -effect_set_t *spell_trigger(dumb_ptr<spell_t> spell, dumb_ptr<map_session_data> caster, +const effect_set_t *spell_trigger(dumb_ptr<spell_t> spell, dumb_ptr<map_session_data> caster, dumb_ptr<env_t> env, int *near_miss) { dumb_ptr<spellguard_t> guard = spell->spellguard; @@ -426,10 +412,11 @@ static void spell_set_location(dumb_ptr<invocation> invocation, dumb_ptr<block_list> entity) { magic_clear_var(&invocation->env->varu[VAR_LOCATION]); - invocation->env->varu[VAR_LOCATION].ty = TYPE::LOCATION; - invocation->env->varu[VAR_LOCATION].v.v_location.m = entity->bl_m; - invocation->env->varu[VAR_LOCATION].v.v_location.x = entity->bl_x; - invocation->env->varu[VAR_LOCATION].v.v_location.y = entity->bl_y; + ValLocation v; + v.v_location.m = entity->bl_m; + v.v_location.x = entity->bl_x; + v.v_location.y = entity->bl_y; + invocation->env->varu[VAR_LOCATION] = v; } void spell_update_location(dumb_ptr<invocation> invocation) @@ -447,7 +434,7 @@ void spell_update_location(dumb_ptr<invocation> invocation) } } -dumb_ptr<invocation> spell_instantiate(effect_set_t *effect_set, dumb_ptr<env_t> env) +dumb_ptr<invocation> spell_instantiate(const effect_set_t *effect_set, dumb_ptr<env_t> env) { dumb_ptr<invocation> retval; retval.new_(); @@ -455,9 +442,8 @@ dumb_ptr<invocation> spell_instantiate(effect_set_t *effect_set, dumb_ptr<env_t> retval->env = env; - retval->caster = wrap<BlockId>(static_cast<uint32_t>(env->VAR(VAR_CASTER).v.v_int)); - retval->spell = env->VAR(VAR_SPELL).v.v_spell; - retval->stack_size = 0; + retval->caster = env->VAR(VAR_CASTER).get_if<ValEntityInt>()->v_eid; + retval->spell = env->VAR(VAR_SPELL).get_if<ValSpell>()->v_spell; retval->current_effect = effect_set->effect; retval->trigger_effect = effect_set->at_trigger; retval->end_effect = effect_set->at_end; @@ -470,7 +456,7 @@ dumb_ptr<invocation> spell_instantiate(effect_set_t *effect_set, dumb_ptr<env_t> retval->bl_y = caster->bl_y; map_addblock(retval); - set_env_invocation(VAR_INVOCATION, retval); + set_invocation(&env->varu[VAR_INVOCATION], retval); return retval; } @@ -491,7 +477,6 @@ dumb_ptr<invocation> spell_clone_effect(dumb_ptr<invocation> base) retval->caster = base->caster; retval->subject = BlockId(); // retval->timer = 0; - retval->stack_size = 0; // retval->stack = undef; retval->script_pos = 0; // huh? @@ -509,7 +494,7 @@ dumb_ptr<invocation> spell_clone_effect(dumb_ptr<invocation> base) retval->bl_type = base->bl_type; retval->bl_id = map_addobject(retval); - set_env_invocation(VAR_INVOCATION, retval); + set_invocation(&env->varu[VAR_INVOCATION], retval); return retval; } diff --git a/src/map/magic-interpreter-base.hpp b/src/map/magic-interpreter-base.hpp index 8c05df0..4bb41a0 100644 --- a/src/map/magic-interpreter-base.hpp +++ b/src/map/magic-interpreter-base.hpp @@ -64,11 +64,11 @@ void magic_free_env(dumb_ptr<env_t> env); /** * near_miss is set to nonzero iff the spell only failed due to ephemereal issues (spell delay in effect, out of mana, out of components) */ -effect_set_t *spell_trigger(dumb_ptr<spell_t> spell, +const effect_set_t *spell_trigger(dumb_ptr<spell_t> spell, dumb_ptr<map_session_data> caster, dumb_ptr<env_t> env, int *near_miss); -dumb_ptr<invocation> spell_instantiate(effect_set_t *effect, dumb_ptr<env_t> env); +dumb_ptr<invocation> spell_instantiate(const effect_set_t *effect, dumb_ptr<env_t> env); /** * Bind a spell to a subject (this is a no-op for `local' spells). diff --git a/src/map/magic-interpreter.hpp b/src/map/magic-interpreter.hpp index 62ab504..01775b3 100644 --- a/src/map/magic-interpreter.hpp +++ b/src/map/magic-interpreter.hpp @@ -32,6 +32,8 @@ #include "../generic/fwd.hpp" +#include "../sexpr/variant.hpp" + #include "../net/timer.t.hpp" #include "../mmo/ids.hpp" @@ -52,55 +54,133 @@ struct location_t int x, y; }; -struct area_t +struct AreaUnion +{ + dumb_ptr<area_t> a_union[2]; +}; +struct AreaRect +{ + location_t loc; + int width, height; +}; +struct AreaBar +{ + location_t loc; + int width, depth; + DIR dir; +}; + +using AreaVariantBase = Variant< + location_t, + AreaUnion, + AreaRect, + AreaBar +>; + +struct area_t : AreaVariantBase { - union au - { - location_t a_loc; - struct - { - location_t loc; - int width, depth; - DIR dir; - } a_bar; - struct - { - location_t loc; - int width, height; - } a_rect; - dumb_ptr<area_t> a_union[2]; - - au() { really_memzero_this(this); } - ~au() = default; - au(const au&) = default; - au& operator = (const au&) = default; - } a; int size; - AREA ty; + + area_t() = delete; + area_t(area_t&&) = default; + area_t(const area_t&) = delete; + area_t& operator = (area_t&&) = default; + area_t& operator = (const area_t&) = delete; + + area_t(location_t v, int sz) : AreaVariantBase(std::move(v)), size(sz) {} + area_t(AreaUnion v, int sz) : AreaVariantBase(std::move(v)), size(sz) {} + area_t(AreaRect v, int sz) : AreaVariantBase(std::move(v)), size(sz) {} + area_t(AreaBar v, int sz) : AreaVariantBase(std::move(v)), size(sz) {} }; -struct val_t +struct ValUndef { - union vu - { - int v_int; - DIR v_dir; - dumb_string v_string; - /* Used ONLY during operation/function invocation; otherwise we use v_int */ - dumb_ptr<block_list> v_entity; - dumb_ptr<area_t> v_area; - location_t v_location; - /* Used ONLY during operation/function invocation; otherwise we use v_int */ - dumb_ptr<invocation> v_invocation; - dumb_ptr<spell_t> v_spell; - - vu() { really_memzero_this(this); } - ~vu() = default; - vu(const vu&) = default; - vu& operator = (const vu&) = default; - } v; - TYPE ty; }; +struct ValInt +{ + int v_int; +}; +struct ValDir +{ + DIR v_dir; +}; +struct ValString +{ + dumb_string v_string; +}; +struct ValEntityInt +{ + BlockId v_eid; +}; +struct ValEntityPtr +{ + dumb_ptr<block_list> v_entity; +}; +struct ValLocation +{ + location_t v_location; +}; +struct ValArea +{ + dumb_ptr<area_t> v_area; +}; +struct ValSpell +{ + dumb_ptr<spell_t> v_spell; +}; +struct ValInvocationInt +{ + BlockId v_iid; +}; +struct ValInvocationPtr +{ + dumb_ptr<invocation> v_invocation; +}; +struct ValFail +{ +}; +struct ValNegative1 +{ +}; + +using ValVariantBase = Variant< + ValUndef, + ValInt, + ValDir, + ValString, + ValEntityInt, + ValEntityPtr, + ValLocation, + ValArea, + ValSpell, + ValInvocationInt, + ValInvocationPtr, + ValFail, + ValNegative1 +>; +struct val_t : ValVariantBase +{ + val_t() noexcept : ValVariantBase(ValUndef{}) {} + val_t(val_t&&) = default; + val_t(const val_t&) = delete; + val_t& operator = (val_t&&) = default; + val_t& operator = (const val_t&) = delete; + + val_t(ValUndef v) : ValVariantBase(std::move(v)) {} + val_t(ValInt v) : ValVariantBase(std::move(v)) {} + val_t(ValDir v) : ValVariantBase(std::move(v)) {} + val_t(ValString v) : ValVariantBase(std::move(v)) {} + val_t(ValEntityInt v) : ValVariantBase(std::move(v)) {} + val_t(ValEntityPtr v) : ValVariantBase(std::move(v)) {} + val_t(ValLocation v) : ValVariantBase(std::move(v)) {} + val_t(ValArea v) : ValVariantBase(std::move(v)) {} + val_t(ValSpell v) : ValVariantBase(std::move(v)) {} + val_t(ValInvocationInt v) : ValVariantBase(std::move(v)) {} + val_t(ValInvocationPtr v) : ValVariantBase(std::move(v)) {} + val_t(ValFail v) : ValVariantBase(std::move(v)) {} + val_t(ValNegative1 v) : ValVariantBase(std::move(v)) {} +}; + /* ----------- */ /* Expressions */ @@ -108,115 +188,187 @@ struct val_t #define MAX_ARGS 7 /* Max. # of args used in builtin primitive functions */ +struct e_area_t; + struct e_location_t { dumb_ptr<expr_t> m, x, y; + + e_location_t() noexcept : m(), x(), y() {} +}; +struct ExprAreaUnion +{ + dumb_ptr<e_area_t> a_union[2]; +}; +struct ExprAreaRect +{ + e_location_t loc; + dumb_ptr<expr_t> width, height; +}; +struct ExprAreaBar +{ + e_location_t loc; + dumb_ptr<expr_t> width, depth, dir; }; -struct e_area_t +using ExprAreaVariantBase = Variant< + e_location_t, + ExprAreaUnion, + ExprAreaRect, + ExprAreaBar +>; + +struct e_area_t : ExprAreaVariantBase { - union a0 - { - e_location_t a_loc; - struct - { - e_location_t loc; - dumb_ptr<expr_t> width, depth, dir; - } a_bar; - struct - { - e_location_t loc; - dumb_ptr<expr_t> width, height; - } a_rect; - dumb_ptr<e_area_t> a_union[2]; - - a0() { really_memzero_this(this); } - ~a0() = default; - a0(const a0&) = default; - a0& operator = (const a0&) = default; - } a; - AREA ty; -}; - -struct expr_t -{ - union eu - { - val_t e_val; - e_location_t e_location; - e_area_t e_area; - struct - { - fun_t *funp; - int line_nr, column; - int args_nr; - dumb_ptr<expr_t> args[MAX_ARGS]; - } e_funapp; - int e_id; - struct - { - dumb_ptr<expr_t> expr; - int id; - } e_field; - - eu() { really_memzero_this(this); } - ~eu() = default; - eu(const eu&) = default; - eu& operator = (const eu&) = default; - } e; - EXPR ty; -}; - -struct effect_t + e_area_t() = delete; + e_area_t(e_area_t&&) = default; + e_area_t(const e_area_t&) = delete; + e_area_t& operator = (e_area_t&&) = default; + e_area_t& operator = (const e_area_t&) = delete; + + e_area_t(e_location_t v) : ExprAreaVariantBase(std::move(v)) {} + e_area_t(ExprAreaUnion v) : ExprAreaVariantBase(std::move(v)) {} + e_area_t(ExprAreaRect v) : ExprAreaVariantBase(std::move(v)) {} + e_area_t(ExprAreaBar v) : ExprAreaVariantBase(std::move(v)) {} +}; + +struct ExprFunApp +{ + fun_t *funp; + int line_nr, column; + int args_nr; + dumb_ptr<expr_t> args[MAX_ARGS]; +}; +struct ExprId +{ + int e_id; +}; +struct ExprField +{ + dumb_ptr<expr_t> expr; + int id; +}; + +using ExprVariantBase = Variant< + val_t, + e_location_t, + e_area_t, + ExprFunApp, + ExprId, + ExprField +>; +struct expr_t : ExprVariantBase +{ + expr_t() = delete; + expr_t(expr_t&&) = default; + expr_t(const expr_t&) = delete; + expr_t& operator = (expr_t&&) = default; + expr_t& operator = (const expr_t&) = delete; + + expr_t(val_t v) : ExprVariantBase(std::move(v)) {} + expr_t(e_location_t v) : ExprVariantBase(std::move(v)) {} + expr_t(e_area_t v) : ExprVariantBase(std::move(v)) {} + expr_t(ExprFunApp v) : ExprVariantBase(std::move(v)) {} + expr_t(ExprId v) : ExprVariantBase(std::move(v)) {} + expr_t(ExprField v) : ExprVariantBase(std::move(v)) {} +}; + + +struct effect_t; + +struct EffectSkip +{ +}; +struct EffectAbort +{ +}; +struct EffectAssign +{ + int id; + dumb_ptr<expr_t> expr; +}; +struct EffectForEach +{ + int id; + dumb_ptr<expr_t> area; + dumb_ptr<effect_t> body; + FOREACH_FILTER filter; +}; +struct EffectFor +{ + int id; + dumb_ptr<expr_t> start, stop; + dumb_ptr<effect_t> body; +}; +struct EffectIf +{ + dumb_ptr<expr_t> cond; + dumb_ptr<effect_t> true_branch, false_branch; +}; +struct EffectSleep +{ + dumb_ptr<expr_t> e_sleep; /* sleep time */ +}; +struct EffectScript +{ + dumb_ptr<const ScriptBuffer> e_script; +}; +struct EffectBreak +{ +}; +struct EffectOp +{ + op_t *opp; + int args_nr; + int line_nr, column; + dumb_ptr<expr_t> args[MAX_ARGS]; +}; +struct EffectEnd +{ +}; +struct EffectCall +{ + std::vector<int> *formalv; + dumb_ptr<std::vector<dumb_ptr<expr_t>>> actualvp; + dumb_ptr<effect_t> body; +}; + +using EffectVariantBase = Variant< + EffectSkip, + EffectAbort, + EffectAssign, + EffectForEach, + EffectFor, + EffectIf, + EffectSleep, + EffectScript, + EffectBreak, + EffectOp, + EffectEnd, + EffectCall +>; +struct effect_t : EffectVariantBase { dumb_ptr<effect_t> next; - union e0 - { - struct - { - int id; - dumb_ptr<expr_t> expr; - } e_assign; - struct - { - int id; - dumb_ptr<expr_t> area; - dumb_ptr<effect_t> body; - FOREACH_FILTER filter; - } e_foreach; - struct - { - int id; - dumb_ptr<expr_t> start, stop; - dumb_ptr<effect_t> body; - } e_for; - struct - { - dumb_ptr<expr_t> cond; - dumb_ptr<effect_t> true_branch, false_branch; - } e_if; - dumb_ptr<expr_t> e_sleep; /* sleep time */ - dumb_ptr<const ScriptBuffer> e_script; - struct - { - op_t *opp; - int args_nr; - int line_nr, column; - dumb_ptr<expr_t> args[MAX_ARGS]; - } e_op; - struct - { - std::vector<int> *formalv; - dumb_ptr<std::vector<dumb_ptr<expr_t>>> actualvp; - dumb_ptr<effect_t> body; - } e_call; - - e0() { really_memzero_this(this); } - ~e0() = default; - e0(const e0&) = default; - e0& operator = (const e0&) = default; - } e; - EFFECT ty; + + effect_t() = delete; + effect_t(effect_t&&) = default; + effect_t(const effect_t&) = delete; + effect_t& operator = (effect_t&&) = default; + effect_t& operator = (const effect_t&) = delete; + + effect_t(EffectSkip v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectAbort v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectAssign v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectForEach v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectFor v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectIf v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectSleep v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectScript v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectBreak v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectOp v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectEnd v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectCall v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} }; /* ---------- */ @@ -231,29 +383,62 @@ struct component_t }; +struct spellguard_t; +struct GuardCondition +{ + dumb_ptr<expr_t> s_condition; +}; +struct GuardMana +{ + dumb_ptr<expr_t> s_mana; +}; +struct GuardCastTime +{ + dumb_ptr<expr_t> s_casttime; +}; +struct GuardComponents +{ + dumb_ptr<component_t> s_components; +}; +struct GuardCatalysts +{ + dumb_ptr<component_t> s_catalysts; +}; +struct GuardChoice +{ + dumb_ptr<spellguard_t> s_alt; /* either `next' or `s.s_alt' */ +}; struct effect_set_t { dumb_ptr<effect_t> effect, at_trigger, at_end; }; -struct spellguard_t +using SpellGuardVariantBase = Variant< + GuardCondition, + GuardMana, + GuardCastTime, + GuardComponents, + GuardCatalysts, + GuardChoice, + effect_set_t +>; +struct spellguard_t : SpellGuardVariantBase { dumb_ptr<spellguard_t> next; - union su - { - dumb_ptr<expr_t> s_condition; - dumb_ptr<expr_t> s_mana; - dumb_ptr<expr_t> s_casttime; - dumb_ptr<component_t> s_components; - dumb_ptr<component_t> s_catalysts; - dumb_ptr<spellguard_t> s_alt; /* either `next' or `s.s_alt' */ - effect_set_t s_effect; - su() { really_memzero_this(this); } - ~su() = default; - su(const su&) = default; - su& operator = (const su&) = default; - } s; - SPELLGUARD ty; + + spellguard_t() = delete; + spellguard_t(spellguard_t&&) = default; + spellguard_t(const spellguard_t&) = delete; + spellguard_t& operator = (spellguard_t&&) = default; + spellguard_t& operator = (const spellguard_t&) = delete; + + spellguard_t(GuardCondition v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} + spellguard_t(GuardMana v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} + spellguard_t(GuardCastTime v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} + spellguard_t(GuardComponents v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} + spellguard_t(GuardCatalysts v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} + spellguard_t(GuardChoice v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} + spellguard_t(effect_set_t v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} }; /* ------ */ @@ -330,7 +515,7 @@ struct env_t val_t& VAR(size_t i) { assert (varu); - if (varu[i].ty == TYPE::UNDEF) + if (varu[i].is<ValUndef>()) return base_env->varv[i].val; else return varu[i]; @@ -338,41 +523,47 @@ struct env_t }; -#define MAX_STACK_SIZE 32 +struct CarForEach +{ + int id; + bool ty_is_spell_not_entity; + dumb_ptr<effect_t> body; + dumb_ptr<std::vector<BlockId>> entities_vp; + int index; +}; +struct CarFor +{ + int id; + dumb_ptr<effect_t> body; + int current; + int stop; +}; +struct CarProc +{ + int args_nr; + int *formalap; + dumb_ptr<val_t[]> old_actualpa; +}; + +using CarVariantBase = Variant< + CarForEach, + CarFor, + CarProc +>; -struct cont_activation_record_t +struct cont_activation_record_t : CarVariantBase { dumb_ptr<effect_t> return_location; - union cu - { - struct - { - int id; - TYPE ty; - dumb_ptr<effect_t> body; - dumb_ptr<std::vector<BlockId>> entities_vp; - int index; - } c_foreach; - struct - { - int id; - dumb_ptr<effect_t> body; - int current; - int stop; - } c_for; - struct - { - int args_nr; - int *formalap; - dumb_ptr<val_t[]> old_actualpa; - } c_proc; - - cu() { really_memzero_this(this); } - ~cu() = default; - cu(const cu&) = default; - cu& operator = (const cu&) = default; - } c; - CONT_STACK ty; + + cont_activation_record_t() = delete; + cont_activation_record_t(cont_activation_record_t&&) = default; + cont_activation_record_t(const cont_activation_record_t&) = delete; + cont_activation_record_t& operator = (cont_activation_record_t&&) = default; + cont_activation_record_t& operator = (const cont_activation_record_t&) = delete; + + cont_activation_record_t(CarForEach v, dumb_ptr<effect_t> rl) : CarVariantBase(std::move(v)), return_location(rl) {} + cont_activation_record_t(CarFor v, dumb_ptr<effect_t> rl) : CarVariantBase(std::move(v)), return_location(rl) {} + cont_activation_record_t(CarProc v, dumb_ptr<effect_t> rl) : CarVariantBase(std::move(v)), return_location(rl) {} }; struct status_change_ref_t @@ -393,8 +584,7 @@ struct invocation : block_list Timer timer; /* spell timer, if any */ - int stack_size; - cont_activation_record_t stack[MAX_STACK_SIZE]; + std::vector<cont_activation_record_t> stack; int script_pos; /* Script position; if nonzero, resume the script we were running. */ dumb_ptr<effect_t> current_effect; diff --git a/src/map/magic-interpreter.t.hpp b/src/map/magic-interpreter.t.hpp index 095922a..ab151fc 100644 --- a/src/map/magic-interpreter.t.hpp +++ b/src/map/magic-interpreter.t.hpp @@ -35,58 +35,6 @@ enum class SPELLARG : uint8_t STRING, }; -enum class TYPE : uint8_t -{ - UNDEF, - INT, - DIR, - STRING, - ENTITY, - LOCATION, - AREA, - SPELL, - INVOCATION, - FAIL = 127, - - NEGATIVE_1 = 255, -}; - -enum class AREA : uint8_t -{ - LOCATION, - UNION, - RECT, - BAR, -}; - -enum class EXPR : uint8_t -{ - VAL, - LOCATION, - AREA, - FUNAPP, - ID, - SPELLFIELD, -}; - -// temporary rename to avoid collision with enum value -// in magic-interpreter-parser -enum class EFFECT : uint8_t -{ - SKIP, - ABORT, - ASSIGN, - FOREACH, - FOR, - IF, - SLEEP, - SCRIPT, - BREAK, - OP, - END, - CALL, -}; - enum class FOREACH_FILTER : uint8_t { MOB, @@ -97,17 +45,6 @@ enum class FOREACH_FILTER : uint8_t NPC, }; -enum class SPELLGUARD : uint8_t -{ - CONDITION, - COMPONENTS, - CATALYSTS, - CHOICE, - MANA, - CASTTIME, - EFFECT, -}; - namespace e { enum class SPELL_FLAG : uint8_t @@ -125,13 +62,6 @@ ENUM_BITWISE_OPERATORS(SPELL_FLAG) } using e::SPELL_FLAG; -enum class CONT_STACK : uint8_t -{ - FOREACH, - FOR, - PROC, -}; - namespace e { enum class INVOCATION_FLAG : uint8_t diff --git a/src/map/magic-stmt.cpp b/src/map/magic-stmt.cpp index 28bcbe8..fd02d45 100644 --- a/src/map/magic-stmt.cpp +++ b/src/map/magic-stmt.cpp @@ -55,61 +55,19 @@ namespace magic /* used for local spell effects */ constexpr Species INVISIBLE_NPC = wrap<Species>(127); -//#define DEBUG - -#ifdef DEBUG -static -void print_val(val_t *v) -{ - switch (v->ty) - { - case TYPE::UNDEF: - FPRINTF(stderr, "UNDEF"_fmt); - break; - case TYPE::INT: - FPRINTF(stderr, "%d"_fmt, v->v.v_int); - break; - case TYPE::DIR: - FPRINTF(stderr, "dir%d"_fmt, v->v.v_int); - break; - case TYPE::STRING: - FPRINTF(stderr, "`%s'"_fmt, v->v.v_string); - break; - default: - FPRINTF(stderr, "ty%d"_fmt, v->ty); - break; - } -} - -static -void dump_env(env_t *env) -{ - int i; - for (i = 0; i < env->base_env->vars_nr; i++) - { - val_t *v = &env->vars[i]; - val_t *bv = &env->base_env->vars[i]; - - FPRINTF(stderr, "%02x %30s "_fmt, i, env->base_env->var_name[i]); - print_val(v); - FPRINTF(stderr, "\t("_fmt); - print_val(bv); - FPRINTF(stderr, ")\n"_fmt); - } -} -#endif - static void clear_activation_record(cont_activation_record_t *ar) { - switch (ar->ty) + MATCH (*ar) { - case CONT_STACK::FOREACH: - ar->c.c_foreach.entities_vp.delete_(); - break; - case CONT_STACK::PROC: - ar->c.c_proc.old_actualpa.delete_(); - break; + CASE (CarForEach&, c_foreach) + { + c_foreach.entities_vp.delete_(); + } + CASE (CarProc&, c_proc) + { + c_proc.old_actualpa.delete_(); + } } } @@ -129,10 +87,10 @@ void clear_stack(dumb_ptr<invocation> invocation_) { int i; - for (i = 0; i < invocation_->stack_size; i++) + for (i = 0; i < invocation_->stack.size(); i++) clear_activation_record(&invocation_->stack[i]); - invocation_->stack_size = 0; + invocation_->stack.clear(); } void spell_free_invocation(dumb_ptr<invocation> invocation_) @@ -254,8 +212,7 @@ BlockId trigger_spell(BlockId subject, BlockId spell) spell_bind(map_id_is_player(subject), invocation_); magic_clear_var(&invocation_->env->varu[VAR_CASTER]); - invocation_->env->varu[VAR_CASTER].ty = TYPE::ENTITY; - invocation_->env->varu[VAR_CASTER].v.v_int = static_cast<int32_t>(unwrap<BlockId>(subject)); + invocation_->env->varu[VAR_CASTER] = ValEntityInt{subject}; return invocation_->bl_id; } @@ -327,11 +284,11 @@ int op_sfx(dumb_ptr<env_t>, Slice<val_t> args) { interval_t delay = static_cast<interval_t>(ARGINT(2)); - if (ARG_TYPE(0) == TYPE::ENTITY) + if (args[0].is<ValEntityPtr>()) { entity_effect(ARGENTITY(0), ARGINT(1), delay); } - else if (ARG_TYPE(0) == TYPE::LOCATION) + else if (args[0].is<ValLocation>()) { local_spell_effect(ARGLOCATION(0).m, ARGLOCATION(0).x, @@ -346,8 +303,10 @@ int op_sfx(dumb_ptr<env_t>, Slice<val_t> args) static int op_instaheal(dumb_ptr<env_t> env, Slice<val_t> args) { - dumb_ptr<block_list> caster = (env->VAR(VAR_CASTER).ty == TYPE::ENTITY) - ? map_id2bl(wrap<BlockId>(static_cast<uint32_t>(env->VAR(VAR_CASTER).v.v_int))) : nullptr; + assert (!env->VAR(VAR_CASTER).is<ValEntityPtr>()); + ValEntityInt *caster_id = env->VAR(VAR_CASTER).get_if<ValEntityInt>(); + dumb_ptr<block_list> caster = caster_id + ? map_id2bl(caster_id->v_eid) : nullptr; dumb_ptr<block_list> subject = ARGENTITY(0); if (!caster) caster = subject; @@ -557,8 +516,10 @@ static int op_status_change(dumb_ptr<env_t> env, Slice<val_t> args) { dumb_ptr<block_list> subject = ARGENTITY(0); - BlockId invocation_id = env->VAR(VAR_INVOCATION).ty == TYPE::INVOCATION - ? wrap<BlockId>(static_cast<uint32_t>(env->VAR(VAR_INVOCATION).v.v_int)) : BlockId(); + assert (!env->VAR(VAR_INVOCATION).is<ValInvocationPtr>()); + ValInvocationInt *ii = env->VAR(VAR_INVOCATION).get_if<ValInvocationInt>(); + BlockId invocation_id = ii + ? ii->v_iid : BlockId(); dumb_ptr<invocation> invocation_ = map_id_is_spell(invocation_id); assert (!ARGINT(3)); @@ -609,8 +570,9 @@ int op_override_attack(dumb_ptr<env_t> env, Slice<val_t> args) spell_free_invocation(old_invocation); } + ValInvocationInt *ii = env->VAR(VAR_INVOCATION).get_if<ValInvocationInt>(); subject->attack_spell_override = - trigger_spell(subject->bl_id, wrap<BlockId>(static_cast<uint32_t>(env->VAR(VAR_INVOCATION).v.v_int))); + trigger_spell(subject->bl_id, ii->v_iid); subject->attack_spell_charges = charges; if (subject->attack_spell_override) @@ -778,11 +740,14 @@ int op_spawn(dumb_ptr<env_t>, Slice<val_t> args) static ZString get_invocation_name(dumb_ptr<env_t> env) { - dumb_ptr<invocation> invocation_; + assert (!env->VAR(VAR_INVOCATION).is<ValInvocationPtr>()); - if (env->VAR(VAR_INVOCATION).ty != TYPE::INVOCATION) + ValInvocationInt *ii = env->VAR(VAR_INVOCATION).get_if<ValInvocationInt>(); + if (!ii) return "?"_s; - invocation_ = map_id_is_spell(wrap<BlockId>(static_cast<uint32_t>(env->VAR(VAR_INVOCATION).v.v_int))); + + dumb_ptr<invocation> invocation_; + invocation_ = map_id_is_spell(ii->v_iid); if (invocation_) return invocation_->spell->name; @@ -945,7 +910,7 @@ int op_gain_exp(dumb_ptr<env_t>, Slice<val_t> args) return 1; pc_gainexp_reason(c, ARGINT(1), ARGINT(2), - PC_GAINEXP_REASON(ARGINT(3))); + static_cast<PC_GAINEXP_REASON>(ARGINT(3))); return 0; } @@ -1024,109 +989,84 @@ void spell_effect_report_termination(BlockId invocation_id, BlockId bl_id, static dumb_ptr<effect_t> return_to_stack(dumb_ptr<invocation> invocation_) { - if (!invocation_->stack_size) + if (invocation_->stack.empty()) return nullptr; else { cont_activation_record_t *ar = - invocation_->stack + (invocation_->stack_size - 1); - switch (ar->ty) + &invocation_->stack.back(); + MATCH (*ar) { - case CONT_STACK::PROC: + CASE (const CarProc&, c_proc) { dumb_ptr<effect_t> ret = ar->return_location; - for (int i = 0; i < ar->c.c_proc.args_nr; i++) + for (int i = 0; i < c_proc.args_nr; i++) { val_t *var = - &invocation_->env->varu[ar->c.c_proc.formalap[i]]; + &invocation_->env->varu[c_proc.formalap[i]]; magic_clear_var(var); - *var = ar->c.c_proc.old_actualpa[i]; + *var = std::move(c_proc.old_actualpa[i]); } // pop the stack clear_activation_record(ar); - --invocation_->stack_size; + invocation_->stack.pop_back(); return ret; } - - case CONT_STACK::FOREACH: + CASE (CarForEach&, c_foreach) { BlockId entity_id; - val_t *var = &invocation_->env->varu[ar->c.c_foreach.id]; + val_t *var = &invocation_->env->varu[c_foreach.id]; do { // This >= is really supposed to be a ==, but // I have no clue if it's actually safe to change it. - if (ar->c.c_foreach.index >= ar->c.c_foreach.entities_vp->size()) + if (c_foreach.index >= c_foreach.entities_vp->size()) { // pop the stack dumb_ptr<effect_t> ret = ar->return_location; clear_activation_record(ar); - --invocation_->stack_size; + invocation_->stack.pop_back(); return ret; } entity_id = - (*ar->c.c_foreach.entities_vp)[ar->c.c_foreach.index++]; + (*c_foreach.entities_vp)[c_foreach.index++]; } while (!entity_id || !map_id2bl(entity_id)); magic_clear_var(var); - var->ty = ar->c.c_foreach.ty; - var->v.v_int = static_cast<int32_t>(unwrap<BlockId>(entity_id)); + if (c_foreach.ty_is_spell_not_entity) + *var = ValInvocationInt{entity_id}; + else + *var = ValEntityInt{entity_id}; - return ar->c.c_foreach.body; + return c_foreach.body; } - - case CONT_STACK::FOR: - if (ar->c.c_for.current > ar->c.c_for.stop) + CASE (CarFor&, c_for) + { + if (c_for.current > c_for.stop) { dumb_ptr<effect_t> ret = ar->return_location; // pop the stack clear_activation_record(ar); - --invocation_->stack_size; + invocation_->stack.pop_back(); return ret; } - magic_clear_var(&invocation_->env->varu[ar->c.c_for.id]); - invocation_->env->varu[ar->c.c_for.id].ty = TYPE::INT; - invocation_->env->varu[ar->c.c_for.id].v.v_int = - ar->c.c_for.current++; + magic_clear_var(&invocation_->env->varu[c_for.id]); + invocation_->env->varu[c_for.id] = ValInt{c_for.current++}; - return ar->c.c_for.body; - - default: - FPRINTF(stderr, - "[magic] INTERNAL ERROR: While executing spell `%s': stack corruption\n"_fmt, - invocation_->spell->name); - return nullptr; + return c_for.body; + } } + abort(); } } static -cont_activation_record_t *add_stack_entry(dumb_ptr<invocation> invocation_, - CONT_STACK ty, dumb_ptr<effect_t> return_location) -{ - cont_activation_record_t *ar = - invocation_->stack + invocation_->stack_size++; - if (invocation_->stack_size >= MAX_STACK_SIZE) - { - FPRINTF(stderr, - "[magic] Execution stack size exceeded in spell `%s'; truncating effect\n"_fmt, - invocation_->spell->name); - invocation_->stack_size--; - return nullptr; - } - - ar->ty = ty; - ar->return_location = return_location; - return ar; -} - -static void find_entities_in_area_c(dumb_ptr<block_list> target, std::vector<BlockId> *entities_vp, FOREACH_FILTER filter) @@ -1193,19 +1133,46 @@ void find_entities_in_area(area_t& area_, std::vector<BlockId> *entities_vp, FOREACH_FILTER filter) { - area_t *area = &area_; // temporary hack to "keep diff small". Heh. - switch (area->ty) + MATCH (area_) { - case AREA::UNION: - find_entities_in_area(*area->a.a_union[0], entities_vp, filter); - find_entities_in_area(*area->a.a_union[1], entities_vp, filter); - break; - - default: + CASE (const AreaUnion&, a) + { + find_entities_in_area(*a.a_union[0], entities_vp, filter); + find_entities_in_area(*a.a_union[1], entities_vp, filter); + } + CASE (const location_t&, a_loc) { + (void)a_loc; + // TODO this can be simplified map_local *m; int x, y, width, height; - magic_area_rect(&m, &x, &y, &width, &height, *area); + magic_area_rect(&m, &x, &y, &width, &height, area_); + map_foreachinarea(std::bind(find_entities_in_area_c, ph::_1, entities_vp, filter), + m, + x, y, + x + width, y + height, + BL::NUL /* filter elsewhere */); + } + CASE (const AreaRect&, a_rect) + { + (void)a_rect; + // TODO this can be simplified + map_local *m; + int x, y, width, height; + magic_area_rect(&m, &x, &y, &width, &height, area_); + map_foreachinarea(std::bind(find_entities_in_area_c, ph::_1, entities_vp, filter), + m, + x, y, + x + width, y + height, + BL::NUL /* filter elsewhere */); + } + CASE (const AreaBar&, a_bar) + { + (void)a_bar; + // TODO this is wrong + map_local *m; + int x, y, width, height; + magic_area_rect(&m, &x, &y, &width, &height, area_); map_foreachinarea(std::bind(find_entities_in_area_c, ph::_1, entities_vp, filter), m, x, y, @@ -1217,17 +1184,20 @@ void find_entities_in_area(area_t& area_, static dumb_ptr<effect_t> run_foreach(dumb_ptr<invocation> invocation, - dumb_ptr<effect_t> foreach, + const EffectForEach *foreach, dumb_ptr<effect_t> return_location) { + const EffectForEach& e_foreach = *foreach; + val_t area; - FOREACH_FILTER filter = foreach->e.e_foreach.filter; - int id = foreach->e.e_foreach.id; - dumb_ptr<effect_t> body = foreach->e.e_foreach.body; + FOREACH_FILTER filter = e_foreach.filter; + int id = e_foreach.id; + dumb_ptr<effect_t> body = e_foreach.body; - magic_eval(invocation->env, &area, foreach->e.e_foreach.area); + magic_eval(invocation->env, &area, e_foreach.area); - if (area.ty != TYPE::AREA) + auto va = area.get_if<ValArea>(); + if (!va) { magic_clear_var(&area); FPRINTF(stderr, @@ -1235,27 +1205,23 @@ dumb_ptr<effect_t> run_foreach(dumb_ptr<invocation> invocation, invocation->spell->name); return return_location; } - else - { - cont_activation_record_t *ar = - add_stack_entry(invocation, CONT_STACK::FOREACH, return_location); - - if (!ar) - return return_location; + { std::vector<BlockId> entities_v; - find_entities_in_area(*area.v.v_area, + find_entities_in_area(*va->v_area, &entities_v, filter); entities_v.shrink_to_fit(); // iterator_pair will go away when this gets properly containerized. random_::shuffle(entities_v); - ar->c.c_foreach.id = id; - ar->c.c_foreach.body = body; - ar->c.c_foreach.index = 0; - ar->c.c_foreach.entities_vp.new_(std::move(entities_v)); - ar->c.c_foreach.ty = - (filter == FOREACH_FILTER::SPELL) ? TYPE::INVOCATION : TYPE::ENTITY; + CarForEach c_foreach; + c_foreach.id = id; + c_foreach.body = body; + c_foreach.index = 0; + c_foreach.entities_vp.new_(std::move(entities_v)); + c_foreach.ty_is_spell_not_entity = + (filter == FOREACH_FILTER::SPELL); + invocation->stack.emplace_back(c_foreach, return_location); magic_clear_var(&area); @@ -1265,18 +1231,19 @@ dumb_ptr<effect_t> run_foreach(dumb_ptr<invocation> invocation, static dumb_ptr<effect_t> run_for (dumb_ptr<invocation> invocation, - dumb_ptr<effect_t> for_, + const EffectFor *for_, dumb_ptr<effect_t> return_location) { - cont_activation_record_t *ar; - int id = for_->e.e_for.id; + const EffectFor& e_for = *for_; + + int id = e_for.id; val_t start; val_t stop; - magic_eval(invocation->env, &start, for_->e.e_for.start); - magic_eval(invocation->env, &stop, for_->e.e_for.stop); + magic_eval(invocation->env, &start, e_for.start); + magic_eval(invocation->env, &stop, e_for.stop); - if (start.ty != TYPE::INT || stop.ty != TYPE::INT) + if (!start.is<ValInt>() || !stop.is<ValInt>()) { magic_clear_var(&start); magic_clear_var(&stop); @@ -1286,109 +1253,44 @@ dumb_ptr<effect_t> run_for (dumb_ptr<invocation> invocation, return return_location; } - ar = add_stack_entry(invocation, CONT_STACK::FOR, return_location); - - if (!ar) - return return_location; + CarFor c_for; - ar->c.c_for.id = id; - ar->c.c_for.current = start.v.v_int; - ar->c.c_for.stop = stop.v.v_int; - ar->c.c_for.body = for_->e.e_for.body; + c_for.id = id; + c_for.current = start.get_if<ValInt>()->v_int; + c_for.stop = stop.get_if<ValInt>()->v_int; + c_for.body = e_for.body; + invocation->stack.emplace_back(c_for, return_location); return return_to_stack(invocation); } static dumb_ptr<effect_t> run_call(dumb_ptr<invocation> invocation, + const EffectCall *call, dumb_ptr<effect_t> return_location) { - dumb_ptr<effect_t> current = invocation->current_effect; - cont_activation_record_t *ar; - int args_nr = current->e.e_call.formalv->size(); - int *formals = current->e.e_call.formalv->data(); + const EffectCall& e_call = *call; + + int args_nr = e_call.formalv->size(); + int *formals = e_call.formalv->data(); auto old_actuals = dumb_ptr<val_t[]>::make(args_nr); - ar = add_stack_entry(invocation, CONT_STACK::PROC, return_location); - ar->c.c_proc.args_nr = args_nr; - ar->c.c_proc.formalap = formals; - ar->c.c_proc.old_actualpa = old_actuals; + CarProc c_proc; + c_proc.args_nr = args_nr; + c_proc.formalap = formals; + c_proc.old_actualpa = old_actuals; + invocation->stack.emplace_back(c_proc, return_location); + for (int i = 0; i < args_nr; i++) { val_t *env_val = &invocation->env->varu[formals[i]]; magic_copy_var(&old_actuals[i], env_val); - magic_eval(invocation->env, env_val, (*current->e.e_call.actualvp)[i]); + magic_eval(invocation->env, env_val, (*e_call.actualvp)[i]); } - return current->e.e_call.body; + return e_call.body; } -#ifdef DEBUG -static -void print_cfg(int i, effect_t *e) -{ - int j; - for (j = 0; j < i; j++) - PRINTF(" "_fmt); - - PRINTF("%p: "_fmt, e); - - if (!e) - { - puts(" -- end --"); - return; - } - - switch (e->ty) - { - case EFFECT::SKIP: - puts("SKIP"); - break; - case EFFECT::END: - puts("END"); - break; - case EFFECT::ABORT: - puts("ABORT"); - break; - case EFFECT::ASSIGN: - puts("ASSIGN"); - break; - case EFFECT::FOREACH: - puts("FOREACH"); - print_cfg(i + 1, e->e.e_foreach.body); - break; - case EFFECT::FOR: - puts("FOR"); - print_cfg(i + 1, e->e.e_for.body); - break; - case EFFECT::IF: - puts("IF"); - for (j = 0; j < i; j++) - PRINTF(" "_fmt); - puts("THEN"); - print_cfg(i + 1, e->e.e_if.true_branch); - for (j = 0; j < i; j++) - PRINTF(" "_fmt); - puts("ELSE"); - print_cfg(i + 1, e->e.e_if.false_branch); - break; - case EFFECT::SLEEP: - puts("SLEEP"); - break; - case EFFECT::SCRIPT: - puts("NpcSubtype::SCRIPT"); - break; - case EFFECT::BREAK: - puts("BREAK"); - break; - case EFFECT::OP: - puts("OP"); - break; - } - print_cfg(i, e->next); -} -#endif - /** * Execute a spell invocation until we abort, finish, or hit the next `sleep'. * @@ -1404,83 +1306,77 @@ interval_t spell_run(dumb_ptr<invocation> invocation_, int allow_delete) const BlockId invocation_id = invocation_->bl_id; #define REFRESH_INVOCATION invocation_ = map_id_is_spell(invocation_id); if (!invocation_) return interval_t::zero(); -#ifdef DEBUG - FPRINTF(stderr, "Resuming execution: invocation of `%s'\n"_fmt, - invocation_->spell->name); - print_cfg(1, invocation_->current_effect); -#endif while (invocation_->current_effect) { dumb_ptr<effect_t> e = invocation_->current_effect; dumb_ptr<effect_t> next = e->next; int i; -#ifdef DEBUG - FPRINTF(stderr, "Next step of type %d\n"_fmt, e->ty); - dump_env(invocation_->env); -#endif - - switch (e->ty) + MATCH (*e) { - case EFFECT::SKIP: - break; - - case EFFECT::ABORT: + CASE (const EffectSkip&, e_) + { + (void)e_; + } + CASE (const EffectAbort&, e_) + { + (void)e_; invocation_->flags |= INVOCATION_FLAG::ABORTED; invocation_->end_effect = nullptr; - FALLTHROUGH; - case EFFECT::END: clear_stack(invocation_); next = nullptr; - break; - - case EFFECT::ASSIGN: + } + CASE (const EffectEnd&, e_) + { + (void)e_; + clear_stack(invocation_); + next = nullptr; + } + CASE (const EffectAssign&, e_assign) + { magic_eval(invocation_->env, - &invocation_->env->varu[e->e.e_assign.id], - e->e.e_assign.expr); - break; - - case EFFECT::FOREACH: - next = run_foreach(invocation_, e, next); - break; - - case EFFECT::FOR: - next = run_for (invocation_, e, next); - break; - - case EFFECT::IF: - if (magic_eval_int(invocation_->env, e->e.e_if.cond)) - next = e->e.e_if.true_branch; + &invocation_->env->varu[e_assign.id], + e_assign.expr); + } + CASE (const EffectForEach&, e_foreach) + { + next = run_foreach(invocation_, &e_foreach, next); + } + CASE (const EffectFor&, e_for) + { + next = run_for (invocation_, &e_for, next); + } + CASE (const EffectIf&, e_if) + { + if (magic_eval_int(invocation_->env, e_if.cond)) + next = e_if.true_branch; else - next = e->e.e_if.false_branch; - break; - - case EFFECT::SLEEP: + next = e_if.false_branch; + } + CASE (const EffectSleep&, e_) { interval_t sleeptime = static_cast<interval_t>( - magic_eval_int(invocation_->env, e->e.e_sleep)); + magic_eval_int(invocation_->env, e_.e_sleep)); invocation_->current_effect = next; if (sleeptime > interval_t::zero()) return sleeptime; - break; } - - case EFFECT::SCRIPT: + CASE (const EffectScript&, e_) { dumb_ptr<map_session_data> caster = map_id_is_player(invocation_->caster); if (caster) { dumb_ptr<env_t> env = invocation_->env; ZString caster_name = (caster ? caster->status_key.name : CharName()).to__actual(); - argrec_t arg[3] = + argrec_t arg[1] = { - {"@target"_s, env->VAR(VAR_TARGET).ty == TYPE::ENTITY ? 0 : env->VAR(VAR_TARGET).v.v_int}, - {"@caster"_s, static_cast<int32_t>(unwrap<BlockId>(invocation_->caster))}, {"@caster_name$"_s, caster_name}, }; + assert (!env->VAR(VAR_SCRIPTTARGET).is<ValEntityPtr>()); + ValEntityInt *ei = env->VAR(VAR_SCRIPTTARGET).get_if<ValEntityInt>(); BlockId message_recipient = - env->VAR(VAR_SCRIPTTARGET).ty == TYPE::ENTITY - ? wrap<BlockId>(static_cast<uint32_t>(env->VAR(VAR_SCRIPTTARGET).v.v_int)) + ei + ? ei->v_eid : invocation_->caster; dumb_ptr<map_session_data> recipient = map_id_is_player(message_recipient); @@ -1495,7 +1391,7 @@ interval_t spell_run(dumb_ptr<invocation> invocation_, int allow_delete) // dealing with an NPC int newpos = run_script_l( - ScriptPointer(&*e->e.e_script, invocation_->script_pos), + ScriptPointer(&*e_.e_script, invocation_->script_pos), message_recipient, invocation_->bl_id, arg); /* Returns the new script position, or -1 once the script is finished */ @@ -1511,42 +1407,35 @@ interval_t spell_run(dumb_ptr<invocation> invocation_, int allow_delete) clif_clearchar_id(invocation_->bl_id, BeingRemoveWhy::DEAD, caster->sess); } REFRESH_INVOCATION; // Script may have killed the caster - break; } - - case EFFECT::BREAK: + CASE (const EffectBreak&, e_) + { + (void)e_; next = return_to_stack(invocation_); - break; - - case EFFECT::OP: + } + CASE (const EffectOp&, e_op) { - op_t *op = e->e.e_op.opp; + op_t *op = e_op.opp; val_t args[MAX_ARGS]; - for (i = 0; i < e->e.e_op.args_nr; i++) - magic_eval(invocation_->env, &args[i], e->e.e_op.args[i]); + for (i = 0; i < e_op.args_nr; i++) + magic_eval(invocation_->env, &args[i], e_op.args[i]); if (!magic_signature_check("effect"_s, op->name, op->signature, - Slice<val_t>(args, e->e.e_op.args_nr), - e->e.e_op.line_nr, - e->e.e_op.column)) - op->op(invocation_->env, Slice<val_t>(args, e->e.e_op.args_nr)); + Slice<val_t>(args, e_op.args_nr), + e_op.line_nr, + e_op.column)) + op->op(invocation_->env, Slice<val_t>(args, e_op.args_nr)); - for (i = 0; i < e->e.e_op.args_nr; i++) + for (i = 0; i < e_op.args_nr; i++) magic_clear_var(&args[i]); REFRESH_INVOCATION; // Effect may have killed the caster - break; } - - case EFFECT::CALL: - next = run_call(invocation_, next); - break; - - default: - FPRINTF(stderr, - "[magic] INTERNAL ERROR: Unknown effect %d\n"_fmt, - e->ty); + CASE (const EffectCall&, e_call) + { + next = run_call(invocation_, &e_call, next); + } } if (!next) @@ -1610,8 +1499,7 @@ int spell_attack(BlockId caster_id, BlockId target_id) if (invocation_ && caster->attack_spell_charges > 0) { magic_clear_var(&invocation_->env->varu[VAR_TARGET]); - invocation_->env->varu[VAR_TARGET].ty = TYPE::ENTITY; - invocation_->env->varu[VAR_TARGET].v.v_int = static_cast<int32_t>(unwrap<BlockId>(target_id)); + invocation_->env->varu[VAR_TARGET] = ValEntityInt{target_id}; invocation_->current_effect = invocation_->trigger_effect; invocation_->flags &= ~INVOCATION_FLAG::ABORTED; diff --git a/src/map/magic-v2.cpp b/src/map/magic-v2.cpp index fe135ea..73b7534 100644 --- a/src/map/magic-v2.cpp +++ b/src/map/magic-v2.cpp @@ -67,8 +67,8 @@ namespace magic_v2 /* Must add new */ magic_conf_t::mcvar new_var {}; new_var.name = id_name; - new_var.val.ty = TYPE::UNDEF; - magic_conf.varv.push_back(new_var); + new_var.val = ValUndef(); + magic_conf.varv.push_back(std::move(new_var)); return i; } @@ -105,9 +105,9 @@ namespace magic_v2 static - bool bind_constant(io::LineSpan span, RString name, val_t *val) + bool bind_constant(io::LineSpan span, RString name, val_t val) { - if (!const_defm.insert({name, *val}).second) + if (!const_defm.insert(std::make_pair(name, std::move(val))).second) { span.error(STRPRINTF("Redefinition of constant '%s'"_fmt, name)); return false; @@ -115,7 +115,7 @@ namespace magic_v2 return true; } static - val_t *find_constant(RString name) + const val_t *find_constant(RString name) { auto it = const_defm.find(name); if (it != const_defm.end()) @@ -124,13 +124,6 @@ namespace magic_v2 return nullptr; } static - dumb_ptr<effect_t> new_effect(EFFECT ty) - { - auto effect = dumb_ptr<effect_t>::make(); - effect->ty = ty; - return effect; - } - static dumb_ptr<effect_t> set_effect_continuation(dumb_ptr<effect_t> src, dumb_ptr<effect_t> continuation) { dumb_ptr<effect_t> retval = src; @@ -141,10 +134,13 @@ namespace magic_v2 /* For FOR and FOREACH, we use special stack handlers and thus don't have to set * the continuation. It's only IF that we need to handle in this fashion. */ - if (src->ty == EFFECT::IF) + MATCH (*src) { - set_effect_continuation(src->e.e_if.true_branch, continuation); - set_effect_continuation(src->e.e_if.false_branch, continuation); + CASE (EffectIf&, e_if) + { + set_effect_continuation(e_if.true_branch, continuation); + set_effect_continuation(e_if.false_branch, continuation); + } } if (src->next) @@ -155,13 +151,6 @@ namespace magic_v2 return retval; } static - dumb_ptr<spellguard_t> new_spellguard(SPELLGUARD ty) - { - dumb_ptr<spellguard_t> retval = dumb_ptr<spellguard_t>::make(); - retval->ty = ty; - return retval; - } - static dumb_ptr<spellguard_t> spellguard_implication(dumb_ptr<spellguard_t> a, dumb_ptr<spellguard_t> b) { dumb_ptr<spellguard_t> retval = a; @@ -183,8 +172,13 @@ namespace magic_v2 } /* If the premise is a disjunction, b is the continuation of _all_ branches */ - if (a->ty == SPELLGUARD::CHOICE) - spellguard_implication(a->s.s_alt, b); + MATCH (*a) + { + CASE(const GuardChoice&, s) + { + spellguard_implication(s.s_alt, b); + } + } if (a->next) spellguard_implication(a->next, b); @@ -265,10 +259,11 @@ namespace magic_v2 return false; } - retval = new_effect(EFFECT::CALL); - retval->e.e_call.body = p->body; - retval->e.e_call.formalv = &p->argv; - retval->e.e_call.actualvp = argvp; + EffectCall e_call; + e_call.body = p->body; + e_call.formalv = &p->argv; + e_call.actualvp = argvp; + retval = dumb_ptr<effect_t>::make(e_call, nullptr); return true; } static @@ -287,23 +282,25 @@ namespace magic_v2 return false; } - effect = new_effect(EFFECT::OP); - effect->e.e_op.line_nr = span.begin.line; - effect->e.e_op.column = span.begin.column; - effect->e.e_op.opp = op; + EffectOp e_op; + e_op.line_nr = span.begin.line; + e_op.column = span.begin.column; + e_op.opp = op; assert (argv.size() <= MAX_ARGS); - effect->e.e_op.args_nr = argv.size(); + e_op.args_nr = argv.size(); - std::copy(argv.begin(), argv.end(), effect->e.e_op.args); + std::copy(argv.begin(), argv.end(), e_op.args); + effect = dumb_ptr<effect_t>::make(e_op, nullptr); return true; } static dumb_ptr<expr_t> dot_expr(dumb_ptr<expr_t> expr, int id) { - dumb_ptr<expr_t> retval = magic_new_expr(EXPR::SPELLFIELD); - retval->e.e_field.id = id; - retval->e.e_field.expr = expr; + ExprField e_field; + e_field.id = id; + e_field.expr = expr; + dumb_ptr<expr_t> retval = dumb_ptr<expr_t>::make(e_field); return retval; } @@ -322,15 +319,16 @@ namespace magic_v2 name, fun->signature.size(), argv.size())); return false; } - expr = magic_new_expr(EXPR::FUNAPP); - expr->e.e_funapp.line_nr = span.begin.line; - expr->e.e_funapp.column = span.begin.column; - expr->e.e_funapp.funp = fun; + ExprFunApp e_funapp; + e_funapp.line_nr = span.begin.line; + e_funapp.column = span.begin.column; + e_funapp.funp = fun; assert (argv.size() <= MAX_ARGS); - expr->e.e_funapp.args_nr = argv.size(); + e_funapp.args_nr = argv.size(); - std::copy(argv.begin(), argv.end(), expr->e.e_funapp.args); + std::copy(argv.begin(), argv.end(), e_funapp.args); + expr = dumb_ptr<expr_t>::make(e_funapp); return true; } static @@ -407,23 +405,19 @@ namespace magic_v2 case sexpr::INT: { val_t val; - val.ty = TYPE::INT; - val.v.v_int = x._int; - if (val.v.v_int != x._int) + val = ValInt{static_cast<int32_t>(x._int)}; + if (val.get_if<ValInt>()->v_int != x._int) return fail(x, "integer too large"_s); - out = magic_new_expr(EXPR::VAL); - out->e.e_val = val; + out = dumb_ptr<expr_t>::make(std::move(val)); return true; } case sexpr::STRING: { val_t val; - val.ty = TYPE::STRING; - val.v.v_string = dumb_string::copys(x._str); + val = ValString{dumb_string::copys(x._str)}; - out = magic_new_expr(EXPR::VAL); - out->e.e_val = val; + out = dumb_ptr<expr_t>::make(std::move(val)); return true; } case sexpr::TOKEN: @@ -439,25 +433,25 @@ namespace magic_v2 if (it != end) { val_t val; - val.ty = TYPE::DIR; - val.v.v_dir = static_cast<DIR>(it - begin); + val = ValDir{static_cast<DIR>(it - begin)}; - out = magic_new_expr(EXPR::VAL); - out->e.e_val = val; + out = dumb_ptr<expr_t>::make(std::move(val)); return true; } } { - if (val_t *val = find_constant(x._str)) + if (const val_t *val = find_constant(x._str)) { - out = magic_new_expr(EXPR::VAL); - out->e.e_val = *val; + val_t copy; + magic_copy_var(©, val); + out = dumb_ptr<expr_t>::make(std::move(copy)); return true; } else { - out = magic_new_expr(EXPR::ID); - out->e.e_id = intern_id(x._str); + ExprId e; + e.e_id = intern_id(x._str); + out = dumb_ptr<expr_t>::make(e); return true; } } @@ -475,9 +469,7 @@ namespace magic_v2 e_location_t loc; if (!parse_loc(x, loc)) return false; - out = magic_new_expr(EXPR::AREA); - out->e.e_area.ty = AREA::LOCATION; - out->e.e_area.a.a_loc = loc; + out = dumb_ptr<expr_t>::make(loc); return true; } if (op == "@+"_s) @@ -491,11 +483,11 @@ namespace magic_v2 return false; if (!parse_expression(x._list[3], height)) return false; - out = magic_new_expr(EXPR::AREA); - out->e.e_area.ty = AREA::RECT; - out->e.e_area.a.a_rect.loc = loc; - out->e.e_area.a.a_rect.width = width; - out->e.e_area.a.a_rect.height = height; + ExprAreaRect a_rect; + a_rect.loc = loc; + a_rect.width = width; + a_rect.height = height; + out = dumb_ptr<expr_t>::make(a_rect); return true; } if (op == "TOWARDS"_s) @@ -512,12 +504,12 @@ namespace magic_v2 return false; if (!parse_expression(x._list[4], depth)) return false; - out = magic_new_expr(EXPR::AREA); - out->e.e_area.ty = AREA::BAR; - out->e.e_area.a.a_bar.loc = loc; - out->e.e_area.a.a_bar.dir = dir; - out->e.e_area.a.a_bar.width = width; - out->e.e_area.a.a_bar.depth = depth; + ExprAreaBar a_bar; + a_bar.loc = loc; + a_bar.dir = dir; + a_bar.width = width; + a_bar.depth = depth; + out = dumb_ptr<expr_t>::make(a_bar); return true; } if (op == "."_s) @@ -630,10 +622,10 @@ namespace magic_v2 dumb_ptr<spellguard_t> alt; if (!parse_spellguard(*begin, alt)) return false; - dumb_ptr<spellguard_t> choice = new_spellguard(SPELLGUARD::CHOICE); - choice->next = out; - choice->s.s_alt = alt; - out = choice; + GuardChoice choice; + auto next = out; + choice.s_alt = alt; + out = dumb_ptr<spellguard_t>::make(choice, next); } return true; } @@ -666,8 +658,9 @@ namespace magic_v2 dumb_ptr<expr_t> condition; if (!parse_expression(s._list[1], condition)) return false; - out = new_spellguard(SPELLGUARD::CONDITION); - out->s.s_condition = condition; + GuardCondition cond; + cond.s_condition = condition; + out = dumb_ptr<spellguard_t>::make(cond, nullptr); return true; } if (cmd == "MANA"_s) @@ -677,8 +670,9 @@ namespace magic_v2 dumb_ptr<expr_t> mana; if (!parse_expression(s._list[1], mana)) return false; - out = new_spellguard(SPELLGUARD::MANA); - out->s.s_mana = mana; + GuardMana sp; + sp.s_mana = mana; + out = dumb_ptr<spellguard_t>::make(sp, nullptr); return true; } if (cmd == "CASTTIME"_s) @@ -688,8 +682,9 @@ namespace magic_v2 dumb_ptr<expr_t> casttime; if (!parse_expression(s._list[1], casttime)) return false; - out = new_spellguard(SPELLGUARD::CASTTIME); - out->s.s_casttime = casttime; + GuardCastTime ct; + ct.s_casttime = casttime; + out = dumb_ptr<spellguard_t>::make(ct, nullptr); return true; } if (cmd == "CATALYSTS"_s) @@ -703,8 +698,9 @@ namespace magic_v2 return false; magic_add_component(&items, id, count); } - out = new_spellguard(SPELLGUARD::CATALYSTS); - out->s.s_catalysts = items; + GuardCatalysts cat; + cat.s_catalysts = items; + out = dumb_ptr<spellguard_t>::make(cat, nullptr); return true; } if (cmd == "COMPONENTS"_s) @@ -718,8 +714,9 @@ namespace magic_v2 return false; magic_add_component(&items, id, count); } - out = new_spellguard(SPELLGUARD::COMPONENTS); - out->s.s_components = items; + GuardComponents comp; + comp.s_components = items; + out = dumb_ptr<spellguard_t>::make(comp, nullptr); return true; } return fail(s._list[0], "unknown guard"_s); @@ -731,7 +728,7 @@ namespace magic_v2 { // these backward lists could be forward by keeping the reference // I know this is true because Linus said so - out = new_effect(EFFECT::SKIP); + out = dumb_ptr<effect_t>::make(EffectSkip{}, nullptr); while (end != begin) { const SExpr& s = *--end; @@ -772,9 +769,10 @@ namespace magic_v2 if (!parse_expression(s._list[2], expr)) return false; - out = new_effect(EFFECT::ASSIGN); - out->e.e_assign.id = intern_id(name); - out->e.e_assign.expr = expr; + EffectAssign e_assign; + e_assign.id = intern_id(name); + e_assign.expr = expr; + out = dumb_ptr<effect_t>::make(e_assign, nullptr); return true; } if (cmd == "SCRIPT"_s) @@ -787,36 +785,37 @@ namespace magic_v2 std::unique_ptr<const ScriptBuffer> script = parse_script(body, s._list[1]._span.begin.line, true); if (!script) return fail(s._list[1], "script does not compile"_s); - out = new_effect(EFFECT::SCRIPT); - out->e.e_script = dumb_ptr<const ScriptBuffer>(script.release()); + EffectScript e; + e.e_script = dumb_ptr<const ScriptBuffer>(script.release()); + out = dumb_ptr<effect_t>::make(e, nullptr); return true; } if (cmd == "SKIP"_s) { if (s._list.size() != 1) return fail(s, "not 0 arg"_s); - out = new_effect(EFFECT::SKIP); + out = dumb_ptr<effect_t>::make(EffectSkip{}, nullptr); return true; } if (cmd == "ABORT"_s) { if (s._list.size() != 1) return fail(s, "not 0 arg"_s); - out = new_effect(EFFECT::ABORT); + out = dumb_ptr<effect_t>::make(EffectAbort{}, nullptr); return true; } if (cmd == "END"_s) { if (s._list.size() != 1) return fail(s, "not 0 arg"_s); - out = new_effect(EFFECT::END); + out = dumb_ptr<effect_t>::make(EffectEnd{}, nullptr); return true; } if (cmd == "BREAK"_s) { if (s._list.size() != 1) return fail(s, "not 0 arg"_s); - out = new_effect(EFFECT::BREAK); + out = dumb_ptr<effect_t>::make(EffectBreak{}, nullptr); return true; } if (cmd == "FOREACH"_s) @@ -850,11 +849,13 @@ namespace magic_v2 return false; if (!parse_effect(s._list[4], effect)) return false; - out = new_effect(EFFECT::FOREACH); - out->e.e_foreach.id = intern_id(var); - out->e.e_foreach.area = area; - out->e.e_foreach.body = effect; - out->e.e_foreach.filter = filter; + + EffectForEach e_foreach; + e_foreach.id = intern_id(var); + e_foreach.area = area; + e_foreach.body = effect; + e_foreach.filter = filter; + out = dumb_ptr<effect_t>::make(e_foreach, nullptr); return true; } if (cmd == "FOR"_s) @@ -873,11 +874,13 @@ namespace magic_v2 return false; if (!parse_effect(s._list[4], effect)) return false; - out = new_effect(EFFECT::FOR); - out->e.e_for.id = intern_id(var); - out->e.e_for.start = low; - out->e.e_for.stop = high; - out->e.e_for.body = effect; + + EffectFor e_for; + e_for.id = intern_id(var); + e_for.start = low; + e_for.stop = high; + e_for.body = effect; + out = dumb_ptr<effect_t>::make(e_for, nullptr); return true; } if (cmd == "IF"_s) @@ -897,11 +900,13 @@ namespace magic_v2 return false; } else - if_false = new_effect(EFFECT::SKIP); - out = new_effect(EFFECT::IF); - out->e.e_if.cond = cond; - out->e.e_if.true_branch = if_true; - out->e.e_if.false_branch = if_false; + if_false = dumb_ptr<effect_t>::make(EffectSkip{}, nullptr); + + EffectIf e_if; + e_if.cond = cond; + e_if.true_branch = if_true; + e_if.false_branch = if_false; + out = dumb_ptr<effect_t>::make(e_if, nullptr); return true; } if (cmd == "WAIT"_s) @@ -911,8 +916,9 @@ namespace magic_v2 dumb_ptr<expr_t> expr; if (!parse_expression(s._list[1], expr)) return false; - out = new_effect(EFFECT::SLEEP); - out->e.e_sleep = expr; + EffectSleep e; + e.e_sleep = expr; + out = dumb_ptr<effect_t>::make(e, nullptr); return true; } if (cmd == "CALL"_s) @@ -981,9 +987,9 @@ namespace magic_v2 if (!parse_spellbody(*begin, alt)) return false; auto tmp = out; - out = new_spellguard(SPELLGUARD::CHOICE); - out->next = tmp; - out->s.s_alt = alt; + GuardChoice choice; + choice.s_alt = alt; + out = dumb_ptr<spellguard_t>::make(choice, tmp); } return true; } @@ -1031,10 +1037,11 @@ namespace magic_v2 } if (!build_effect_list(begin, end, effect)) return false; - out = new_spellguard(SPELLGUARD::EFFECT); - out->s.s_effect.effect = effect; - out->s.s_effect.at_trigger = attrig; - out->s.s_effect.at_end = atend; + effect_set_t s_effect; + s_effect.effect = effect; + s_effect.at_trigger = attrig; + s_effect.at_end = atend; + out = dumb_ptr<spellguard_t>::make(s_effect, nullptr); return true; } return fail(s._list[0], "unknown spellbody"_s); @@ -1068,7 +1075,7 @@ namespace magic_v2 return false; val_t tmp; magic_eval(dumb_ptr<env_t>(&magic_default_env), &tmp, expr); - return bind_constant(span, name, &tmp); + return bind_constant(span, name, std::move(tmp)); } static bool parse_anchor(io::LineSpan span, const std::vector<SExpr>& in) diff --git a/src/map/magic.cpp b/src/map/magic.cpp index bc46f86..a0238b5 100644 --- a/src/map/magic.cpp +++ b/src/map/magic.cpp @@ -42,8 +42,6 @@ namespace tmwa { namespace magic { -#undef DEBUG - /// Return a pair of strings, {spellname, parameter} /// Parameter may be empty. static @@ -97,18 +95,13 @@ int magic_message(dumb_ptr<map_session_data> caster, XString source_invocation) int near_miss; dumb_ptr<env_t> env = spell_create_env(&magic_conf, spell, caster, power, parameter); - effect_set_t *effects; + const effect_set_t *effects; if (bool(spell->flags & SPELL_FLAG::NONMAGIC) || (power >= 1)) effects = spell_trigger(spell, caster, env, &near_miss); else effects = nullptr; -#ifdef DEBUG - FPRINTF(stderr, "Found spell `%s', triggered = %d\n"_fmt, spell_, - effects != nullptr); -#endif - MAP_LOG_PC(caster, "CAST %s %s"_fmt, spell->name, effects ? "SUCCESS"_s : "FAILURE"_s); diff --git a/src/sexpr/variant.hpp b/src/sexpr/variant.hpp index 50ee77f..fbf9345 100644 --- a/src/sexpr/variant.hpp +++ b/src/sexpr/variant.hpp @@ -41,10 +41,11 @@ namespace sexpr #define MATCH(expr) \ WITH_VAR(auto&&, _match_var, expr) \ switch (tmwa::sexpr::VariantFriend::get_state(_match_var)) -#define CASE(ty, var) \ - break; \ - case tmwa::sexpr::VariantFriend::get_state_for<ty, decltype(_match_var)>(): \ - WITH_VAR(ty, var, tmwa::sexpr::VariantFriend::unchecked_get<ty>(_match_var)) +#define TYPED_CASE(ty, var, look) \ + break; \ + case tmwa::sexpr::VariantFriend::get_state_for<look, decltype(_match_var)>(): \ + WITH_VAR(ty, var, tmwa::sexpr::VariantFriend::unchecked_get<look>(_match_var)) +#define CASE(ty, var) TYPED_CASE(ty, var, std::remove_const<std::remove_reference<ty>::type>::type) template<class... T> class Variant diff --git a/src/sexpr/variant.tcc b/src/sexpr/variant.tcc index 424a8f1..ce820bf 100644 --- a/src/sexpr/variant.tcc +++ b/src/sexpr/variant.tcc @@ -24,6 +24,16 @@ namespace tmwa { namespace sexpr { + template<size_t v> + constexpr + size_t not_negative_one() + { + return v; + } + template<> + constexpr + size_t not_negative_one<-1>() = delete; + class VariantFriend { public: @@ -77,7 +87,7 @@ namespace sexpr template<class W, class V> constexpr static size_t get_state_for() { - return std::remove_reference<V>::type::DataType::template index<W>(); + return not_negative_one<std::remove_reference<V>::type::DataType::template index<W>()>(); } }; @@ -104,7 +114,7 @@ namespace sexpr try { data.template construct<C, A...>(std::forward<A>(a)...); - state = Union<D, T...>::template index<C>(); + state = not_negative_one<Union<D, T...>::template index<C>()>(); } catch(...) { @@ -244,7 +254,7 @@ namespace sexpr template<class E> E *Variant<D, T...>::get_if() { - if (state == Union<D, T...>::template index<E>()) + if (state == not_negative_one<Union<D, T...>::template index<E>()>()) return data.template get<E>(); return nullptr; } @@ -253,7 +263,7 @@ namespace sexpr template<class E> const E *Variant<D, T...>::get_if() const { - if (state == Union<D, T...>::template index<E>()) + if (state == not_negative_one<Union<D, T...>::template index<E>()>()) return data.template get<E>(); return nullptr; } |