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