diff options
Diffstat (limited to 'src/map/magic-expr.cpp')
-rw-r--r-- | src/map/magic-expr.cpp | 1332 |
1 files changed, 721 insertions, 611 deletions
diff --git a/src/map/magic-expr.cpp b/src/map/magic-expr.cpp index 42ff3a7..306126e 100644 --- a/src/map/magic-expr.cpp +++ b/src/map/magic-expr.cpp @@ -1,6 +1,4 @@ -#include "magic-expr-eval.hpp" #include "magic-expr.hpp" -#include "magic-interpreter-aux.hpp" // magic-expr.cpp - Pure functions for the old magic backend. // // Copyright © 2004-2011 The Mana World Development Team @@ -22,40 +20,49 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include <cassert> -#include <cmath> -#include "../compat/alg.hpp" +#include <algorithm> #include "../strings/mstring.hpp" #include "../strings/astring.hpp" #include "../strings/zstring.hpp" #include "../strings/vstring.hpp" +#include "../strings/literal.hpp" +#include "../generic/dumb_ptr.hpp" #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" +#include "../io/cxxstdio_enums.hpp" #include "battle.hpp" +#include "itemdb.hpp" +#include "magic-expr-eval.hpp" +#include "magic-interpreter.hpp" +#include "magic-interpreter-base.hpp" #include "npc.hpp" #include "pc.hpp" -#include "itemdb.hpp" #include "../poison.hpp" + +namespace tmwa +{ +namespace magic +{ 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_(); @@ -64,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); + } } } @@ -125,113 +188,110 @@ AString show_entity(dumb_ptr<block_list> entity) case BL::MOB: return entity->is_mob()->name; case BL::ITEM: - assert (0 && "There is no way this code did what it was supposed to do!"); + assert (0 && "There is no way this code did what it was supposed to do!"_s); /* Sorry about this one... */ - // WTF? item_data is a struct item, not a struct item_data + // WTF? item_data is a Item, not a struct item_data // return ((struct item_data *) (&entity->is_item()->item_data))->name; abort(); case BL::SPELL: - return {"%invocation(ERROR:this-should-not-be-an-entity)"}; + return "%invocation(ERROR:this-should-not-be-an-entity)"_s; default: - return {"%unknown-entity"}; + return "%unknown-entity"_s; } } static -void stringify(val_t *v, int within_op) +void stringify(val_t *v) { - static earray<ZString, DIR, DIR::COUNT> dirs //= + static earray<LString, DIR, DIR::COUNT> dirs //= {{ - {"south"}, {"south-west"}, - {"west"}, {"north-west"}, - {"north"}, {"north-east"}, - {"east"}, {"south-east"}, + "south"_s, "south-west"_s, + "west"_s, "north-west"_s, + "north"_s, "north-east"_s, + "east"_s, "south-east"_s, }}; AString buf; - switch (v->ty) + MATCH (*v) { - case TYPE::UNDEF: - buf = "UNDEF"; - break; - - case TYPE::INT: - buf = STRPRINTF("%i", v->v.v_int); - break; - - case TYPE::STRING: + default: + { + abort(); + } + CASE (const ValUndef&, x) + { + (void)x; + buf = "UNDEF"_s; + } + 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: - buf = STRPRINTF("<\"%s\", %d, %d>", - v->v.v_location.m->name_, - v->v.v_location.x, - v->v.v_location.y); - break; - - case TYPE::AREA: - buf = "%area"; - free_area(v->v.v_area); - break; - - case TYPE::SPELL: - buf = v->v.v_spell->name; + } + 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, + x.v_location.m->name_, + x.v_location.x, + x.v_location.y); + } + CASE (const ValArea&, x) + { + buf = "%area"_s; + 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(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", - 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); } /** @@ -240,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}; } } } @@ -282,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) = NULL; - ARGAREA(1) = NULL; - 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; } @@ -317,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; } @@ -333,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; } @@ -342,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; } @@ -396,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; } @@ -422,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; } @@ -462,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 = 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 = min(ARGINT(0), ARGINT(1)); + *result = ValInt{std::min(ARGINT(0), ARGINT(1))}; return 0; } @@ -528,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; @@ -590,27 +650,50 @@ void magic_area_rect(map_local **m, int *x, int *y, int *width, int *height, default: FPRINTF(stderr, - "Error: Trying to compute area of NE/SE/NW/SW-facing bar"); + "Error: Trying to compute area of NE/SE/NW/SW-facing bar"_fmt); *x = tx; *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); @@ -618,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"); - 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; } @@ -638,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) >= uint16_t(MAX_SKILL)) + || 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; } @@ -654,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; } @@ -662,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; \ } @@ -680,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; } @@ -689,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; \ } @@ -701,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; @@ -725,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 = ARGMOB(0)->mob_class; + *result = ValInt{unwrap<Species>(ARGMOB(0)->mob_class)}; return 0; } @@ -748,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; } @@ -760,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; } @@ -774,28 +858,28 @@ 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 = ARGENTITY(0)->bl_id; + *result = ValInt{static_cast<int32_t>(unwrap<BlockId>(ARGENTITY(0)->bl_id))}; return 0; } -int // ret -1: not a string, ret 1: no such item, ret 0: OK -magic_find_item(Slice<val_t> args, int index, struct item *item_, int *stackable) +// ret -1: not a string, ret 1: no such item, ret 0: OK +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) - item_data = itemdb_exists(ARGINT(index)); - else if (ARG_TYPE(index) == TYPE::STRING) + if (args[index].is<ValInt>()) + item_data = itemdb_exists(wrap<ItemNameId>(static_cast<uint16_t>(ARGINT(index)))); + else if (args[index].is<ValString>()) item_data = itemdb_searchname(ARGSTR(index)); else return -1; @@ -813,7 +897,7 @@ magic_find_item(Slice<val_t> args, int index, struct item *item_, int *stackable if (stackable) *stackable = !must_add_sequentially; - *item_ = item(); + *item_ = Item(); item_->nameid = item_data->nameid; return 0; @@ -822,25 +906,25 @@ magic_find_item(Slice<val_t> args, int index, struct item *item_, int *stackable static int fun_count_item(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - dumb_ptr<map_session_data> chr = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : NULL; + dumb_ptr<map_session_data> chr = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr; int stackable; - struct item item; + Item item; GET_ARG_ITEM(1, item, stackable); if (!chr) return 1; - RESULTINT = pc_count_all_items(chr, item.nameid); + *result = ValInt{pc_count_all_items(chr, item.nameid)}; return 0; } static int fun_is_equipped(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - dumb_ptr<map_session_data> chr = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : NULL; + dumb_ptr<map_session_data> chr = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr; int stackable; - struct item item; + Item item; bool retval = false; GET_ARG_ITEM(1, item, stackable); @@ -850,36 +934,36 @@ int fun_is_equipped(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) for (EQUIP i : EQUIPs) { - int idx = chr->equip_index_maybe[i]; - if (idx >= 0 && chr->status.inventory[idx].nameid == item.nameid) + IOff0 idx = chr->equip_index_maybe[i]; + if (idx.ok() && chr->status.inventory[idx].nameid == item.nameid) { retval = true; break; } } - 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; } @@ -888,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 @@ -911,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; } @@ -926,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 == NULL; + 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 == NULL; + 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 = 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; } @@ -953,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; } @@ -974,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; @@ -991,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); @@ -1030,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", - 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; } @@ -1056,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; } @@ -1070,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; } @@ -1080,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; } @@ -1097,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; } @@ -1126,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 = NULL != strstr(ARGSTR(0).c_str(), ARGSTR(1).c_str()); + *result = ValInt{nullptr != strstr(ARGSTR(0).c_str(), ARGSTR(1).c_str())}; return 0; } @@ -1141,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(); - return offset == NULL; + *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; } @@ -1173,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; } @@ -1181,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; } @@ -1189,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; } @@ -1199,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; } @@ -1222,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 @@ -1254,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}; } } @@ -1273,98 +1399,98 @@ int fun_dir_towards(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) static 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) : NULL; + 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; } -#define MAGIC_FUNCTION(name, args, ret, impl) {{name}, {{name}, {args}, ret, impl}} -#define MAGIC_FUNCTION1(name, args, ret) MAGIC_FUNCTION(#name, args, ret, fun_##name) -static +#define MAGIC_FUNCTION(name, args, ret, impl) {name, {name, args, ret, impl}} +#define MAGIC_FUNCTION1(name, args, ret) MAGIC_FUNCTION(#name##_s, args, ret, fun_##name) +static // should be LString, but no heterogenous lookup yet std::map<ZString, fun_t> functions = { - MAGIC_FUNCTION("+", "..", '.', fun_add), - MAGIC_FUNCTION("-", "ii", 'i', fun_sub), - MAGIC_FUNCTION("*", "ii", 'i', fun_mul), - MAGIC_FUNCTION("/", "ii", 'i', fun_div), - MAGIC_FUNCTION("%", "ii", 'i', fun_mod), - MAGIC_FUNCTION("||", "ii", 'i', fun_or), - MAGIC_FUNCTION("&&", "ii", 'i', fun_and), - MAGIC_FUNCTION("<", "..", 'i', fun_lt), - MAGIC_FUNCTION(">", "..", 'i', fun_gt), - MAGIC_FUNCTION("<=", "..", 'i', fun_lte), - MAGIC_FUNCTION(">=", "..", 'i', fun_gte), - MAGIC_FUNCTION("==", "..", 'i', fun_eq), - MAGIC_FUNCTION("!=", "..", 'i', fun_ne), - MAGIC_FUNCTION("|", "..", 'i', fun_bitor), - MAGIC_FUNCTION("&", "ii", 'i', fun_bitand), - MAGIC_FUNCTION("^", "ii", 'i', fun_bitxor), - MAGIC_FUNCTION("<<", "ii", 'i', fun_bitshl), - MAGIC_FUNCTION(">>", "ii", 'i', fun_bitshr), - MAGIC_FUNCTION1(not, "i", 'i'), - MAGIC_FUNCTION1(neg, "i", 'i'), - MAGIC_FUNCTION1(max, "ii", 'i'), - MAGIC_FUNCTION1(min, "ii", 'i'), - MAGIC_FUNCTION1(is_in, "la", 'i'), - MAGIC_FUNCTION1(if_then_else, "i__", '_'), - MAGIC_FUNCTION1(skill, "ei", 'i'), - MAGIC_FUNCTION("str", "e", 'i', fun_get_str), - MAGIC_FUNCTION("agi", "e", 'i', fun_get_agi), - MAGIC_FUNCTION("vit", "e", 'i', fun_get_vit), - MAGIC_FUNCTION("dex", "e", 'i', fun_get_dex), - MAGIC_FUNCTION("luk", "e", 'i', fun_get_luk), - MAGIC_FUNCTION("int", "e", 'i', fun_get_int), - MAGIC_FUNCTION("level", "e", 'i', fun_get_lv), - MAGIC_FUNCTION("mdef", "e", 'i', fun_get_mdef), - MAGIC_FUNCTION("def", "e", 'i', fun_get_def), - MAGIC_FUNCTION("hp", "e", 'i', fun_get_hp), - MAGIC_FUNCTION("max_hp", "e", 'i', fun_get_max_hp), - MAGIC_FUNCTION("sp", "e", 'i', fun_get_sp), - MAGIC_FUNCTION("max_sp", "e", 'i', fun_get_max_sp), - MAGIC_FUNCTION("dir", "e", 'd', fun_get_dir), - MAGIC_FUNCTION1(name_of, ".", 's'), - MAGIC_FUNCTION1(mob_id, "e", 'i'), - MAGIC_FUNCTION1(location, "e", 'l'), - MAGIC_FUNCTION1(random, "i", 'i'), - MAGIC_FUNCTION1(random_dir, "i", 'd'), - MAGIC_FUNCTION1(hash_entity, "e", 'i'), - MAGIC_FUNCTION1(is_married, "e", 'i'), - MAGIC_FUNCTION1(partner, "e", 'e'), - MAGIC_FUNCTION1(awayfrom, "ldi", 'l'), - MAGIC_FUNCTION1(failed, "_", 'i'), - MAGIC_FUNCTION1(pc, "s", 'e'), - MAGIC_FUNCTION1(npc, "s", 'e'), - MAGIC_FUNCTION1(distance, "ll", 'i'), - MAGIC_FUNCTION1(rdistance, "ll", 'i'), - MAGIC_FUNCTION1(anchor, "s", 'a'), - MAGIC_FUNCTION("random_location", "a", 'l', fun_pick_location), - MAGIC_FUNCTION("script_int", "es", 'i', fun_read_script_int), - MAGIC_FUNCTION("script_str", "es", 's', fun_read_script_str), - MAGIC_FUNCTION1(rbox, "li", 'a'), - MAGIC_FUNCTION1(count_item, "e.", 'i'), - MAGIC_FUNCTION1(line_of_sight, "ll", 'i'), - MAGIC_FUNCTION1(running_status_update, "ei", 'i'), - MAGIC_FUNCTION1(status_option, "ei", 'i'), - MAGIC_FUNCTION1(element, "e", 'i'), - MAGIC_FUNCTION1(element_level, "e", 'i'), - MAGIC_FUNCTION1(his_shroud, "e", 'i'), - MAGIC_FUNCTION1(is_equipped, "e.", 'i'), - MAGIC_FUNCTION1(is_exterior, "l", 'i'), - MAGIC_FUNCTION1(contains_string, "ss", 'i'), - MAGIC_FUNCTION1(strstr, "ss", 'i'), - MAGIC_FUNCTION1(strlen, "s", 'i'), - MAGIC_FUNCTION1(substr, "sii", 's'), - MAGIC_FUNCTION1(sqrt, "i", 'i'), - MAGIC_FUNCTION1(map_level, "l", 'i'), - MAGIC_FUNCTION1(map_nr, "l", 'i'), - MAGIC_FUNCTION1(dir_towards, "lli", 'd'), - MAGIC_FUNCTION1(is_dead, "e", 'i'), - MAGIC_FUNCTION1(is_pc, "e", 'i'), - MAGIC_FUNCTION("extract_healer_experience", "ei", 'i', fun_extract_healer_xp), + MAGIC_FUNCTION("+"_s, ".."_s, '.', fun_add), + MAGIC_FUNCTION("-"_s, "ii"_s, 'i', fun_sub), + MAGIC_FUNCTION("*"_s, "ii"_s, 'i', fun_mul), + MAGIC_FUNCTION("/"_s, "ii"_s, 'i', fun_div), + MAGIC_FUNCTION("%"_s, "ii"_s, 'i', fun_mod), + MAGIC_FUNCTION("||"_s, "ii"_s, 'i', fun_or), + MAGIC_FUNCTION("&&"_s, "ii"_s, 'i', fun_and), + MAGIC_FUNCTION("<"_s, ".."_s, 'i', fun_lt), + MAGIC_FUNCTION(">"_s, ".."_s, 'i', fun_gt), + MAGIC_FUNCTION("<="_s, ".."_s, 'i', fun_lte), + MAGIC_FUNCTION(">="_s, ".."_s, 'i', fun_gte), + MAGIC_FUNCTION("=="_s, ".."_s, 'i', fun_eq), + MAGIC_FUNCTION("!="_s, ".."_s, 'i', fun_ne), + MAGIC_FUNCTION("|"_s, ".."_s, 'i', fun_bitor), + MAGIC_FUNCTION("&"_s, "ii"_s, 'i', fun_bitand), + MAGIC_FUNCTION("^"_s, "ii"_s, 'i', fun_bitxor), + MAGIC_FUNCTION("<<"_s, "ii"_s, 'i', fun_bitshl), + MAGIC_FUNCTION(">>"_s, "ii"_s, 'i', fun_bitshr), + MAGIC_FUNCTION1(not, "i"_s, 'i'), + MAGIC_FUNCTION1(neg, "i"_s, 'i'), + MAGIC_FUNCTION1(max, "ii"_s, 'i'), + MAGIC_FUNCTION1(min, "ii"_s, 'i'), + MAGIC_FUNCTION1(is_in, "la"_s, 'i'), + MAGIC_FUNCTION1(if_then_else, "i__"_s, '_'), + MAGIC_FUNCTION1(skill, "ei"_s, 'i'), + MAGIC_FUNCTION("str"_s, "e"_s, 'i', fun_get_str), + MAGIC_FUNCTION("agi"_s, "e"_s, 'i', fun_get_agi), + MAGIC_FUNCTION("vit"_s, "e"_s, 'i', fun_get_vit), + MAGIC_FUNCTION("dex"_s, "e"_s, 'i', fun_get_dex), + MAGIC_FUNCTION("luk"_s, "e"_s, 'i', fun_get_luk), + MAGIC_FUNCTION("int"_s, "e"_s, 'i', fun_get_int), + MAGIC_FUNCTION("level"_s, "e"_s, 'i', fun_get_lv), + MAGIC_FUNCTION("mdef"_s, "e"_s, 'i', fun_get_mdef), + MAGIC_FUNCTION("def"_s, "e"_s, 'i', fun_get_def), + MAGIC_FUNCTION("hp"_s, "e"_s, 'i', fun_get_hp), + MAGIC_FUNCTION("max_hp"_s, "e"_s, 'i', fun_get_max_hp), + MAGIC_FUNCTION("sp"_s, "e"_s, 'i', fun_get_sp), + MAGIC_FUNCTION("max_sp"_s, "e"_s, 'i', fun_get_max_sp), + MAGIC_FUNCTION("dir"_s, "e"_s, 'd', fun_get_dir), + MAGIC_FUNCTION1(name_of, "."_s, 's'), + MAGIC_FUNCTION1(mob_id, "e"_s, 'i'), + MAGIC_FUNCTION1(location, "e"_s, 'l'), + MAGIC_FUNCTION1(random, "i"_s, 'i'), + MAGIC_FUNCTION1(random_dir, "i"_s, 'd'), + MAGIC_FUNCTION1(hash_entity, "e"_s, 'i'), + MAGIC_FUNCTION1(is_married, "e"_s, 'i'), + MAGIC_FUNCTION1(partner, "e"_s, 'e'), + MAGIC_FUNCTION1(awayfrom, "ldi"_s, 'l'), + MAGIC_FUNCTION1(failed, "_"_s, 'i'), + MAGIC_FUNCTION1(pc, "s"_s, 'e'), + MAGIC_FUNCTION1(npc, "s"_s, 'e'), + MAGIC_FUNCTION1(distance, "ll"_s, 'i'), + MAGIC_FUNCTION1(rdistance, "ll"_s, 'i'), + MAGIC_FUNCTION1(anchor, "s"_s, 'a'), + MAGIC_FUNCTION("random_location"_s, "a"_s, 'l', fun_pick_location), + MAGIC_FUNCTION("script_int"_s, "es"_s, 'i', fun_read_script_int), + MAGIC_FUNCTION("script_str"_s, "es"_s, 's', fun_read_script_str), + MAGIC_FUNCTION1(rbox, "li"_s, 'a'), + MAGIC_FUNCTION1(count_item, "e."_s, 'i'), + MAGIC_FUNCTION1(line_of_sight, "ll"_s, 'i'), + MAGIC_FUNCTION1(running_status_update, "ei"_s, 'i'), + MAGIC_FUNCTION1(status_option, "ei"_s, 'i'), + MAGIC_FUNCTION1(element, "e"_s, 'i'), + MAGIC_FUNCTION1(element_level, "e"_s, 'i'), + MAGIC_FUNCTION1(his_shroud, "e"_s, 'i'), + MAGIC_FUNCTION1(is_equipped, "e."_s, 'i'), + MAGIC_FUNCTION1(is_exterior, "l"_s, 'i'), + MAGIC_FUNCTION1(contains_string, "ss"_s, 'i'), + MAGIC_FUNCTION1(strstr, "ss"_s, 'i'), + MAGIC_FUNCTION1(strlen, "s"_s, 'i'), + MAGIC_FUNCTION1(substr, "sii"_s, 's'), + MAGIC_FUNCTION1(sqrt, "i"_s, 'i'), + MAGIC_FUNCTION1(map_level, "l"_s, 'i'), + MAGIC_FUNCTION1(map_nr, "l"_s, 'i'), + MAGIC_FUNCTION1(dir_towards, "lli"_s, 'd'), + MAGIC_FUNCTION1(is_dead, "e"_s, 'i'), + MAGIC_FUNCTION1(is_pc, "e"_s, 'i'), + MAGIC_FUNCTION("extract_healer_experience"_s, "ei"_s, 'i', fun_extract_healer_xp), }; fun_t *magic_get_fun(ZString name) @@ -1377,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 @@ -1407,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 NULL; + 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 NULL; + 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 NULL; + 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 NULL; + return nullptr; } } - - default: - FPRINTF(stderr, "INTERNAL ERROR: Unknown area type %d\n", - area->ty); - area.delete_(); - return NULL; } + 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; } } @@ -1552,76 +1682,66 @@ 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(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(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, - "[magic-eval]: L%d:%d: Too many arguments (%zu) to %s `%s'\n", - line, column, args.size(), opname, funname); + "[magic-eval]: L%d:%d: Too many arguments (%zu) to %s `%s'\n"_fmt, + line, column, args.size(), opname, funname); 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", - line, column, i + 1, opname, funname); + "[magic-eval]: L%d:%d: Argument #%d to %s `%s' undefined\n"_fmt, + line, column, i + 1, opname, funname); 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", - 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; } } @@ -1631,100 +1751,94 @@ 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]); - if (magic_signature_check("function", f->name, f->signature, Slice<val_t>(arguments, args_nr), - expr->e.e_funapp.line_nr, expr->e.e_funapp.column) + 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), + 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 = 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(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); } } else { FPRINTF(stderr, - "[magic] Attempt to access field %s on non-spell\n", - env->base_env->varv[id].name); - dest->ty = TYPE::FAIL; + "[magic] Attempt to access field %s on non-spell\n"_fmt, + env->base_env->varv[id].name); + *dest = ValFail(); } - break; } - - default: - FPRINTF(stderr, - "[magic] INTERNAL ERROR: Unknown expression type %d\n", - expr->ty); - break; } } @@ -1733,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) @@ -1746,17 +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) - return {"?"}; + 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 |