summaryrefslogtreecommitdiff
path: root/src/map/magic-expr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/magic-expr.cpp')
-rw-r--r--src/map/magic-expr.cpp1332
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