From a7f64f0b39cb7141f16608c171b20bee452fd024 Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Wed, 23 Jul 2014 23:55:41 -0700 Subject: In magic, use Variant for all the old anonymous nested unions --- src/map/magic-expr-eval.hpp | 30 +- src/map/magic-expr.cpp | 1080 ++++++++++++++++++++---------------- src/map/magic-expr.hpp | 4 +- src/map/magic-interpreter-base.cpp | 151 +++-- src/map/magic-interpreter-base.hpp | 4 +- src/map/magic-interpreter.hpp | 580 ++++++++++++------- src/map/magic-interpreter.t.hpp | 70 --- src/map/magic-stmt.cpp | 512 +++++++---------- src/map/magic-v2.cpp | 255 ++++----- src/map/magic.cpp | 9 +- 10 files changed, 1385 insertions(+), 1310 deletions(-) (limited to 'src/map') 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()->v_int +#define ARGDIR(x) args[x].get_if()->v_dir +#define ARGSTR(x) ZString(args[x].get_if()->v_string) +#define ARGENTITY(x) args[x].get_if()->v_entity +#define ARGLOCATION(x) args[x].get_if()->v_location +#define ARGAREA(x) args[x].get_if()->v_area +#define ARGSPELL(x) args[x].get_if()->v_spell +#define ARGINVOCATION(x) args[x].get_if()->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() || args[x].is()) } // 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 -bool CHECK_TYPE(T *v, TYPE t) -{ - return v->ty == t; -} - static void free_area(dumb_ptr 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) static dumb_ptr dup_area(dumb_ptr area) { - dumb_ptr retval = dumb_ptr::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::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::make(u, area->size); + } + CASE (const AreaRect&, rect) + { + return dumb_ptr::make(rect, area->size); + } + CASE (const AreaBar&, bar) + { + return dumb_ptr::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 entity) } static -void stringify(val_t *v, int within_op) +void stringify(val_t *v) { static earray 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_ = within_op - ? v->v.v_invocation - : map_id2bl(wrap(static_cast(v->v.v_int)))->is_spell(); + dumb_ptr invocation_ = + map_id2bl(x.v_iid)->is_spell(); + buf = invocation_->spell->name; + } + CASE (const ValInvocationPtr&, x) + { + dumb_ptr 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()) return; magic_clear_var(v); - v->ty = TYPE::INT; - v->v.v_int = 1; -} - -static -dumb_ptr area_new(AREA ty) -{ - auto retval = dumb_ptr::make(); - retval->ty = ty; - return retval; + *v = ValInt{1}; } static dumb_ptr area_union(dumb_ptr area, dumb_ptr other_area) { - dumb_ptr 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::make(a, size); } /** @@ -254,41 +300,43 @@ dumb_ptr area_union(dumb_ptr area, dumb_ptr other_area) static void make_area(val_t *v) { - if (v->ty == TYPE::LOCATION) + if (ValLocation *l = v->get_if()) { - auto a = dumb_ptr::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::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()) { - 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()); + if (ValInvocationPtr *p = v->get_if()) { - dumb_ptr invoc = v->v.v_invocation; - //invoc = (dumb_ptr) map_id2bl(v->v.v_int); + dumb_ptr 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, val_t *result, Slice args) { - if (ARG_TYPE(0) == TYPE::INT && ARG_TYPE(1) == TYPE::INT) + if (args[0].is() && args[1].is()) { /* 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, val_t *result, Slice args) static int fun_sub(dumb_ptr, val_t *result, Slice args) { - RESULTINT = ARGINT(0) - ARGINT(1); + *result = ValInt{ARGINT(0) - ARGINT(1)}; return 0; } static int fun_mul(dumb_ptr, val_t *result, Slice args) { - RESULTINT = ARGINT(0) * ARGINT(1); + *result = ValInt{ARGINT(0) * ARGINT(1)}; return 0; } @@ -347,7 +392,7 @@ int fun_div(dumb_ptr, val_t *result, Slice 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, val_t *result, Slice 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, val_t *result, Slice args) { - RESULTINT = ARGINT(0) || ARGINT(1); + *result = ValInt{ARGINT(0) || ARGINT(1)}; return 0; } static int fun_and(dumb_ptr, val_t *result, Slice args) { - RESULTINT = ARGINT(0) && ARGINT(1); + *result = ValInt{ARGINT(0) && ARGINT(1)}; return 0; } static int fun_not(dumb_ptr, val_t *result, Slice args) { - RESULTINT = !ARGINT(0); + *result = ValInt{!ARGINT(0)}; return 0; } static int fun_neg(dumb_ptr, val_t *result, Slice args) { - RESULTINT = ~ARGINT(0); + *result = ValInt{~ARGINT(0)}; return 0; } static int fun_gte(dumb_ptr, val_t *result, Slice args) { - if (ARG_TYPE(0) == TYPE::STRING || ARG_TYPE(1) == TYPE::STRING) + if (args[0].is() || args[1].is()) { - 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, val_t *result, Slice args) { fun_gte(env, result, args); - RESULTINT = !RESULTINT; + result->get_if()->v_int ^= 1; return 0; } static int fun_gt(dumb_ptr, val_t *result, Slice args) { - if (ARG_TYPE(0) == TYPE::STRING || ARG_TYPE(1) == TYPE::STRING) + if (args[0].is() || args[1].is()) { - 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, val_t *result, Slice args) { fun_gt(env, result, args); - RESULTINT = !RESULTINT; + result->get_if()->v_int ^= 1; return 0; } static int fun_eq(dumb_ptr, val_t *result, Slice args) { - if (ARG_TYPE(0) == TYPE::STRING || ARG_TYPE(1) == TYPE::STRING) + if (args[0].is() || args[1].is()) { - 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() && args[1].is()) + *result = ValInt{ARGDIR(0) == ARGDIR(1)}; + else if (args[0].is() && args[1].is()) + *result = ValInt{ARGENTITY(0) == ARGENTITY(1)}; + else if (args[0].is() && args[1].is()) + *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() && args[1].is()) + *result = ValInt{ARGAREA(0) == ARGAREA(1)}; /* Probably not that great an idea... */ + else if (args[0].is() && args[1].is()) + *result = ValInt{ARGSPELL(0) == ARGSPELL(1)}; + else if (args[0].is() && args[1].is()) + *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, val_t *result, Slice args) { fun_eq(env, result, args); - RESULTINT = !RESULTINT; + result->get_if()->v_int ^= 1; return 0; } static int fun_bitand(dumb_ptr, val_t *result, Slice args) { - RESULTINT = ARGINT(0) & ARGINT(1); + *result = ValInt{ARGINT(0) & ARGINT(1)}; return 0; } static int fun_bitor(dumb_ptr, val_t *result, Slice args) { - RESULTINT = ARGINT(0) | ARGINT(1); + *result = ValInt{ARGINT(0) | ARGINT(1)}; return 0; } static int fun_bitxor(dumb_ptr, val_t *result, Slice args) { - RESULTINT = ARGINT(0) ^ ARGINT(1); + *result = ValInt{ARGINT(0) ^ ARGINT(1)}; return 0; } static int fun_bitshl(dumb_ptr, val_t *result, Slice args) { - RESULTINT = ARGINT(0) << ARGINT(1); + *result = ValInt{ARGINT(0) << ARGINT(1)}; return 0; } static int fun_bitshr(dumb_ptr, val_t *result, Slice args) { - RESULTINT = ARGINT(0) >> ARGINT(1); + *result = ValInt{ARGINT(0) >> ARGINT(1)}; return 0; } static int fun_max(dumb_ptr, val_t *result, Slice args) { - RESULTINT = std::max(ARGINT(0), ARGINT(1)); + *result = ValInt{std::max(ARGINT(0), ARGINT(1))}; return 0; } static int fun_min(dumb_ptr, val_t *result, Slice 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, val_t *result, Slice 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) { - 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) && (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, val_t *result, Slice 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, val_t *result, Slice 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(MAX_SKILL)) { - RESULTINT = 0; + *result = ValInt{0}; } else { SkillID id = static_cast(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, val_t *result, Slice args) static int fun_his_shroud(dumb_ptr, val_t *result, Slice 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, val_t *result, Slice args) static \ int fun_get_##name(dumb_ptr, val_t *result, Slice 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, val_t *result, Slice 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, val_t *result, Slice 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, val_t *result, Slice args) { - if (ARG_TYPE(0) == TYPE::ENTITY) + if (args[0].is()) { - 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()) { - 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()) { - 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, val_t *result, Slice args) { if (ENTITY_TYPE(0) != BL::MOB) return 1; - RESULTINT = unwrap(ARGMOB(0)->mob_class); + *result = ValInt{unwrap(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, val_t *result, Slice 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, val_t *result, Slice 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()->v_int *= -1; return 0; } @@ -788,16 +858,16 @@ static int fun_random_dir(dumb_ptr, val_t *result, Slice 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, val_t *result, Slice args) { - RESULTINT = unwrap(ARGENTITY(0)->bl_id); + *result = ValInt{static_cast(unwrap(ARGENTITY(0)->bl_id))}; return 0; } @@ -807,9 +877,9 @@ int magic_find_item(Slice 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()) item_data = itemdb_exists(wrap(static_cast(ARGINT(index)))); - else if (ARG_TYPE(index) == TYPE::STRING) + else if (args[index].is()) item_data = itemdb_searchname(ARGSTR(index)); else return -1; @@ -845,7 +915,7 @@ int fun_count_item(dumb_ptr, val_t *result, Slice 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, val_t *result, Slice args) } } - RESULTINT = retval; + *result = ValInt{retval}; return 0; } static int fun_is_married(dumb_ptr, val_t *result, Slice 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, val_t *result, Slice 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, val_t *result, Slice 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, val_t *result, Slice 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, val_t *result, Slice args) loc->y += dy; } - RESULTLOCATION = *loc; + *result = ValLocation{*loc}; return 0; } static int fun_failed(dumb_ptr, val_t *result, Slice args) { - RESULTINT = ARG_TYPE(0) == TYPE::FAIL; + *result = ValInt{args[0].is()}; return 0; } @@ -940,26 +1010,28 @@ static int fun_npc(dumb_ptr, val_t *result, Slice args) { NpcName name = stringish(ARGSTR(0)); - RESULTENTITY = npc_name2id(name); - return RESULTENTITY == nullptr; + dumb_ptr npc = npc_name2id(name); + *result = ValEntityPtr{npc}; + return npc == nullptr; } static int fun_pc(dumb_ptr, val_t *result, Slice args) { CharName name = stringish(ARGSTR(0)); - RESULTENTITY = map_nick2sd(name); - return RESULTENTITY == nullptr; + dumb_ptr chr = map_nick2sd(name); + *result = ValEntityPtr{chr}; + return chr == nullptr; } static int fun_distance(dumb_ptr, val_t *result, Slice 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, val_t *result, Slice 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(sqrt((dx * dx) + (dy * dy))); + *result = ValInt{static_cast(sqrt((dx * dx) + (dy * dy)))}; } return 0; } @@ -988,7 +1060,7 @@ int fun_anchor(dumb_ptr env, val_t *result, Slice args) magic_eval(env, result, anchor->location); make_area(result); - if (result->ty != TYPE::AREA) + if (!result->is()) { magic_clear_var(result); return 1; @@ -1005,28 +1077,48 @@ int fun_line_of_sight(dumb_ptr, val_t *result, Slice args) COPY_LOCATION(e1, ARGLOCATION(0)); COPY_LOCATION(e2, ARGLOCATION(1)); - RESULTINT = battle_check_range(dumb_ptr(&e1), dumb_ptr(&e2), 0); + *result = ValInt{battle_check_range(dumb_ptr(&e1), dumb_ptr(&e2), 0)}; return 0; } void magic_random_location(location_t *dest, dumb_ptr 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) 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, val_t *result, Slice 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, val_t *result, Slice 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, val_t *result, Slice 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, val_t *result, Slice 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::make(a_rect, a_rect.width * a_rect.height)}; return 0; } @@ -1111,28 +1223,28 @@ int fun_running_status_update(dumb_ptr, val_t *result, Slice args) return 1; StatusChange sc = static_cast(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, val_t *result, Slice args) { - RESULTINT = (bool((ARGPC(0))->status.option & static_cast