summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwushin <pasekei@gmail.com>2015-06-09 01:06:22 -0500
committermekolat <mekolat@users.noreply.github.com>2016-04-15 11:44:49 -0400
commit506a41d6926405b2753894f0b40130b4077828b3 (patch)
tree401fd473a23d80dcdcbd56d0c89f6587a46f878c
parenta8640e1df61c06faf6edb89c5c4b9f025c0dff33 (diff)
downloadtmwa-506a41d6926405b2753894f0b40130b4077828b3.tar.gz
tmwa-506a41d6926405b2753894f0b40130b4077828b3.tar.bz2
tmwa-506a41d6926405b2753894f0b40130b4077828b3.tar.xz
tmwa-506a41d6926405b2753894f0b40130b4077828b3.zip
Remove old Magic
-rw-r--r--src/map/clif.cpp13
-rw-r--r--src/map/fwd.hpp18
-rw-r--r--src/map/globals.cpp19
-rw-r--r--src/map/globals.hpp14
-rw-r--r--src/map/magic-expr-eval.hpp54
-rw-r--r--src/map/magic-expr.cpp1874
-rw-r--r--src/map/magic-expr.hpp107
-rw-r--r--src/map/magic-expr.py38
-rw-r--r--src/map/magic-interpreter-base.cpp553
-rw-r--r--src/map/magic-interpreter-base.hpp84
-rw-r--r--src/map/magic-interpreter.hpp630
-rw-r--r--src/map/magic-interpreter.py215
-rw-r--r--src/map/magic-interpreter.t.hpp85
-rw-r--r--src/map/magic-stmt.cpp1547
-rw-r--r--src/map/magic-stmt.hpp93
-rw-r--r--src/map/magic-stmt.py37
-rw-r--r--src/map/magic-v2.cpp1295
-rw-r--r--src/map/magic-v2.hpp37
-rw-r--r--src/map/magic.cpp130
-rw-r--r--src/map/magic.hpp48
-rw-r--r--src/map/map.cpp20
-rw-r--r--src/map/map.hpp15
-rw-r--r--src/map/map.t.hpp1
-rw-r--r--src/map/npc.cpp58
-rw-r--r--src/map/pc.cpp9
-rw-r--r--src/map/script-fun.cpp38
-rw-r--r--src/map/skill.cpp13
-rw-r--r--src/mmo/cxxstdio_enums.hpp7
-rw-r--r--src/mmo/skill.t.hpp4
29 files changed, 61 insertions, 6995 deletions
diff --git a/src/map/clif.cpp b/src/map/clif.cpp
index a2a2a33..33de3e6 100644
--- a/src/map/clif.cpp
+++ b/src/map/clif.cpp
@@ -62,8 +62,6 @@
#include "globals.hpp"
#include "intif.hpp"
#include "itemdb.hpp"
-#include "magic.hpp"
-#include "magic-stmt.hpp"
#include "map.hpp"
#include "map_conf.hpp"
#include "npc.hpp"
@@ -2641,12 +2639,6 @@ void clif_getareachar(dumb_ptr<block_list> bl, dumb_ptr<map_session_data> sd)
case BL::ITEM:
clif_getareachar_item(sd, bl->is_item());
break;
- case BL::SPELL:
- // spell objects are not visible
- // (at least, I *think* that's what this code is for)
- // in any case, this is not a behavior change, just silencing
- // the below warning
- break;
default:
if (battle_config.error_log)
PRINTF("get area char ??? %d\n"_fmt,
@@ -3792,7 +3784,6 @@ RecvResult clif_parse_GetCharNameRequest(Session *s, dumb_ptr<map_session_data>
send_fpacket<0x0095, 30>(s, fixed_95);
}
break;
- // case BL::SPELL
default:
if (battle_config.error_log)
PRINTF("clif_parse_GetCharNameRequest : bad type %d (%d)\n"_fmt,
@@ -4273,8 +4264,8 @@ RecvResult clif_parse_TakeItem(Session *s, dumb_ptr<map_session_data> sd)
|| abs(sd->bl_y - fitem->bl_y) >= 2)
return rv; // too far away to pick up
- if (sd->state.shroud_active && sd->state.shroud_disappears_on_pickup)
- magic::magic_unshroud(sd);
+// if (sd->state.shroud_active && sd->state.shroud_disappears_on_pickup)
+// magic_unshroud(sd);
pc_takeitem(sd, fitem);
diff --git a/src/map/fwd.hpp b/src/map/fwd.hpp
index 911d566..de65216 100644
--- a/src/map/fwd.hpp
+++ b/src/map/fwd.hpp
@@ -57,7 +57,6 @@ struct map_session_data;
struct npc_data;
struct mob_data;
struct flooritem_data;
-//struct magic::invocation;
struct map_local;
class npc_data_script;
class npc_data_shop;
@@ -71,22 +70,5 @@ struct ScriptState;
struct str_data_t;
class SIR;
-namespace magic
-{
-struct fun_t;
-struct op_t;
-struct expr_t;
-struct val_t;
-struct location_t;
-struct area_t;
-struct spell_t;
-struct invocation;
-struct teleport_anchor_t;
-struct env_t;
-struct magic_conf_t;
-struct component_t;
-struct effect_set_t;
-struct proc_t;
-} // namespace magic
} // namespace map
} // namespace tmwa
diff --git a/src/map/globals.cpp b/src/map/globals.cpp
index 4a54843..c96037e 100644
--- a/src/map/globals.cpp
+++ b/src/map/globals.cpp
@@ -27,7 +27,6 @@
#include "battle_conf.hpp"
#include "itemdb.hpp"
#include "quest.hpp"
-#include "magic-interpreter.hpp"
#include "map_conf.hpp"
#include "mob.hpp"
#include "npc-internal.hpp"
@@ -51,17 +50,6 @@ namespace tmwa
std::map<MapName, RString> resnametable;
Map<ItemNameId, item_data> item_db;
Map<QuestId, quest_data> quest_db;
- namespace magic
- {
- // Global magic conf
- magic_conf_t magic_conf;
- env_t magic_default_env = { &magic_conf, nullptr };
- namespace magic_v2
- {
- std::map<RString, proc_t> procs;
- std::map<RString, val_t> const_defm;
- } // namespace magic_v2
- } // namespace magic
DMap<BlockId, dumb_ptr<block_list>> id_db;
UPMap<MapName, map_abstract> maps_db;
@@ -85,7 +73,8 @@ namespace tmwa
BlockId npc_id = START_NPC_NUM;
Map<NpcEvent, struct event_data> ev_db;
DMap<NpcName, dumb_ptr<npc_data>> npcs_by_name;
- DMap<RString, NpcEvent> spells_by_name;
+ DMap<RString, NpcName> spells_by_name;
+ DMap<RString, NpcEvent> spells_by_events;
// used for clock-based event triggers
// only tm_min, tm_hour, and tm_mday are used
tm ev_tm_b =
@@ -142,9 +131,5 @@ namespace tmwa
// BuiltinFunction builtin_functions[];
// src/map/clif.cpp:
// func_table clif_parse_func_table[0x0220];
- // src/map/magic-expr.cpp:
- // std::map<ZString, fun_t> functions;
- // src/map/magic-stmt.cpp:
- // std::map<ZString, op_t> operations;
} // namespace map
} // namespace tmwa
diff --git a/src/map/globals.hpp b/src/map/globals.hpp
index 5a4ec82..84e4765 100644
--- a/src/map/globals.hpp
+++ b/src/map/globals.hpp
@@ -49,17 +49,6 @@ namespace tmwa
extern std::map<MapName, RString> resnametable;
extern Map<ItemNameId, item_data> item_db;
extern Map<QuestId, quest_data> quest_db;
- namespace magic
- {
- // Global magic conf
- extern magic_conf_t magic_conf;
- extern env_t magic_default_env;
- namespace magic_v2
- {
- extern std::map<RString, proc_t> procs;
- extern std::map<RString, val_t> const_defm;
- } // namespace magic_v2
- } // namespace magic
extern DMap<BlockId, dumb_ptr<block_list>> id_db;
extern UPMap<MapName, map_abstract> maps_db;
extern DMap<CharName, dumb_ptr<map_session_data>> nick_db;
@@ -79,7 +68,8 @@ namespace tmwa
extern BlockId npc_id;
extern Map<NpcEvent, event_data> ev_db;
extern DMap<NpcName, dumb_ptr<npc_data>> npcs_by_name;
- extern DMap<RString, NpcEvent> spells_by_name;
+ extern DMap<RString, NpcName> spells_by_name;
+ extern DMap<RString, NpcEvent> spells_by_events;
extern tm ev_tm_b;
extern Map<PartyId, PartyMost> party_db;
extern std::map<AccountId, GmLevel> gm_accountm;
diff --git a/src/map/magic-expr-eval.hpp b/src/map/magic-expr-eval.hpp
deleted file mode 100644
index e8ed4aa..0000000
--- a/src/map/magic-expr-eval.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#pragma once
-// magic-expr-eval.hpp - Utilities for evaluating magic.
-//
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include "fwd.hpp"
-
-#include "../strings/zstring.hpp"
-
-#include "magic-interpreter.t.hpp"
-
-
-namespace tmwa
-{
-namespace map
-{
-namespace magic
-{
-// TODO soon kill this unlike I killed VAR
-#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) (args[x].is<ValArea>() || args[x].is<ValArea>())
-} // namespace magic
-} // namespace map
-} // namespace tmwa
diff --git a/src/map/magic-expr.cpp b/src/map/magic-expr.cpp
deleted file mode 100644
index 197727e..0000000
--- a/src/map/magic-expr.cpp
+++ /dev/null
@@ -1,1874 +0,0 @@
-#include "magic-expr.hpp"
-// magic-expr.cpp - Pure functions for the old magic backend.
-//
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include <cassert>
-
-#include <algorithm>
-
-#include "../strings/mstring.hpp"
-#include "../strings/astring.hpp"
-#include "../strings/zstring.hpp"
-#include "../strings/vstring.hpp"
-#include "../strings/literal.hpp"
-
-#include "../generic/dumb_ptr.hpp"
-#include "../generic/random.hpp"
-
-#include "../io/cxxstdio.hpp"
-
-#include "../mmo/cxxstdio_enums.hpp"
-
-#include "battle.hpp"
-#include "itemdb.hpp"
-#include "magic-expr-eval.hpp"
-#include "magic-interpreter.hpp"
-#include "magic-interpreter-base.hpp"
-#include "npc.hpp"
-#include "pc.hpp"
-#include "script-call.hpp"
-
-#include "../poison.hpp"
-
-
-namespace tmwa
-{
-namespace map
-{
-namespace magic
-{
-static
-void free_area(dumb_ptr<area_t> area)
-{
- if (!area)
- return;
-
- MATCH_BEGIN (*area)
- {
- MATCH_CASE (const AreaUnion&, a)
- {
- free_area(a.a_union[0]);
- free_area(a.a_union[1]);
- }
- }
- MATCH_END ();
-
- area.delete_();
-}
-
-static
-dumb_ptr<area_t> dup_area(dumb_ptr<area_t> area)
-{
- MATCH_BEGIN (*area)
- {
- MATCH_CASE (const location_t&, loc)
- {
- return dumb_ptr<area_t>::make(loc);
- }
- MATCH_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);
- }
- MATCH_CASE (const AreaRect&, rect)
- {
- return dumb_ptr<area_t>::make(rect);
- }
- MATCH_CASE (const AreaBar&, bar)
- {
- return dumb_ptr<area_t>::make(bar);
- }
- }
- MATCH_END ();
-
- abort();
-}
-
-void magic_copy_var(val_t *dest, const val_t *src)
-{
- MATCH_BEGIN (*src)
- {
- MATCH_DEFAULT ()
- {
- abort();
- }
- MATCH_CASE (const ValUndef&, s)
- {
- *dest = s;
- }
- MATCH_CASE (const ValInt&, s)
- {
- *dest = s;
- }
- MATCH_CASE (const ValDir&, s)
- {
- *dest = s;
- }
- MATCH_CASE (const ValString&, s)
- {
- *dest = ValString{s.v_string};
- }
- MATCH_CASE (const ValEntityInt&, s)
- {
- *dest = s;
- }
- MATCH_CASE (const ValEntityPtr&, s)
- {
- *dest = s;
- }
- MATCH_CASE (const ValLocation&, s)
- {
- *dest = s;
- }
- MATCH_CASE (const ValArea&, s)
- {
- *dest = ValArea{dup_area(s.v_area)};
- }
- MATCH_CASE (const ValSpell&, s)
- {
- *dest = s;
- }
- MATCH_CASE (const ValInvocationInt&, s)
- {
- *dest = s;
- }
- MATCH_CASE (const ValInvocationPtr&, s)
- {
- *dest = s;
- }
- MATCH_CASE (const ValFail&, s)
- {
- *dest = s;
- }
- MATCH_CASE (const ValNegative1&, s)
- {
- *dest = s;
- }
- }
- MATCH_END ();
-}
-
-void magic_clear_var(val_t *v)
-{
- MATCH_BEGIN (*v)
- {
- MATCH_CASE (ValString&, s)
- {
- (void)s;
- }
- MATCH_CASE (const ValArea&, a)
- {
- free_area(a.v_area);
- }
- }
- MATCH_END ();
-}
-
-static
-AString show_entity(dumb_ptr<block_list> entity)
-{
- switch (entity->bl_type)
- {
- case BL::PC:
- return entity->is_player()->status_key.name.to__actual();
- case BL::NPC:
- return entity->is_npc()->name;
- case BL::MOB:
- return entity->is_mob()->name;
- case BL::ITEM:
- assert (0 && "There is no way this code did what it was supposed to do!"_s);
- /* Sorry about this one... */
- // WTF? item_data is a Item, not a struct item_data
- // return ((struct item_data *) (&entity->is_item()->item_data))->name;
- abort();
- case BL::SPELL:
- return "%invocation(ERROR:this-should-not-be-an-entity)"_s;
- default:
- return "%unknown-entity"_s;
- }
-}
-
-static
-void stringify(val_t *v)
-{
- static earray<LString, DIR, DIR::COUNT> dirs //=
- {{
- "south"_s, "south-west"_s,
- "west"_s, "north-west"_s,
- "north"_s, "north-east"_s,
- "east"_s, "south-east"_s,
- }};
- AString buf;
-
- MATCH_BEGIN (*v)
- {
- MATCH_DEFAULT ()
- {
- abort();
- }
- MATCH_CASE (const ValUndef&, x)
- {
- (void)x;
- buf = "UNDEF"_s;
- }
- MATCH_CASE (const ValInt&, x)
- {
- buf = STRPRINTF("%i"_fmt, x.v_int);
- }
- MATCH_CASE (const ValString&, x)
- {
- (void)x;
- return;
- }
- MATCH_CASE (const ValDir&, x)
- {
- buf = dirs[x.v_dir];
- }
- MATCH_CASE (const ValEntityPtr&, x)
- {
- buf = show_entity(x.v_entity);
- }
- MATCH_CASE (const ValLocation&, x)
- {
- buf = STRPRINTF("<\"%s\", %d, %d>"_fmt,
- x.v_location.m->name_,
- x.v_location.x,
- x.v_location.y);
- }
- MATCH_CASE (const ValArea&, x)
- {
- buf = "%area"_s;
- free_area(x.v_area);
- }
- MATCH_CASE (const ValSpell&, x)
- {
- buf = x.v_spell->name;
- }
- MATCH_CASE (const ValInvocationInt&, x)
- {
- dumb_ptr<invocation> invocation_ =
- map_id2bl(x.v_iid)->is_spell();
- buf = invocation_->spell->name;
- }
- MATCH_CASE (const ValInvocationPtr&, x)
- {
- dumb_ptr<invocation> invocation_ =
- x.v_invocation;
- buf = invocation_->spell->name;
- }
- }
- MATCH_END ();
-
- *v = ValString{buf};
-}
-
-static
-void intify(val_t *v)
-{
- if (v->is<ValInt>())
- return;
-
- magic_clear_var(v);
- *v = ValInt{1};
-}
-
-static
-dumb_ptr<area_t> area_union(dumb_ptr<area_t> area, dumb_ptr<area_t> other_area)
-{
- AreaUnion a;
- a.a_union[0] = area;
- a.a_union[1] = other_area;
- return dumb_ptr<area_t>::make(a);
-}
-
-/**
- * Turns location into area, leaves other types untouched
- */
-static
-void make_area(val_t *v)
-{
- if (ValLocation *l = v->get_if<ValLocation>())
- {
- auto a = dumb_ptr<area_t>::make(l->v_location);
- *v = ValArea{a};
- }
-}
-
-static
-void make_location(val_t *v)
-{
- if (ValArea *a = v->get_if<ValArea>())
- {
- MATCH_BEGIN (*a->v_area)
- {
- MATCH_CASE (const location_t&, location)
- {
- free_area(a->v_area);
- *v = ValLocation{location};
- }
- }
- MATCH_END ();
- }
-}
-
-static
-void make_spell(val_t *v)
-{
- assert(!v->is<ValInvocationInt>());
- if (ValInvocationPtr *p = v->get_if<ValInvocationPtr>())
- {
- dumb_ptr<invocation> invoc = p->v_invocation;
- if (!invoc)
- {
- *v = ValFail{};
- }
- else
- {
- *v = ValSpell{invoc->spell};
- }
- }
-}
-
-static
-int fun_add(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- if (args[0].is<ValInt>() && args[1].is<ValInt>())
- {
- /* Integer addition */
- *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]);
- *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]);
- stringify(&args[1]);
- /* Yes, we could speed this up. */
- // ugh
- MString m;
- m += ARGSTR(0);
- m += ARGSTR(1);
- *result = ValString{AString(m)};
- }
- return 0;
-}
-
-static
-int fun_sub(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{ARGINT(0) - ARGINT(1)};
- return 0;
-}
-
-static
-int fun_mul(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{ARGINT(0) * ARGINT(1)};
- return 0;
-}
-
-static
-int fun_div(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- if (!ARGINT(1))
- return 1; /* division by zero */
- *result = ValInt{ARGINT(0) / ARGINT(1)};
- return 0;
-}
-
-static
-int fun_mod(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- if (!ARGINT(1))
- return 1; /* division by zero */
- *result = ValInt{ARGINT(0) % ARGINT(1)};
- return 0;
-}
-
-static
-int fun_or(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{ARGINT(0) || ARGINT(1)};
- return 0;
-}
-
-static
-int fun_and(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{ARGINT(0) && ARGINT(1)};
- return 0;
-}
-
-static
-int fun_not(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{!ARGINT(0)};
- return 0;
-}
-
-static
-int fun_neg(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{~ARGINT(0)};
- return 0;
-}
-
-static
-int fun_gte(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- if (args[0].is<ValString>() || args[1].is<ValString>())
- {
- stringify(&args[0]);
- stringify(&args[1]);
- *result = ValInt{ARGSTR(0) >= ARGSTR(1)};
- }
- else
- {
- intify(&args[0]);
- intify(&args[1]);
- *result = ValInt{ARGINT(0) >= ARGINT(1)};
- }
- return 0;
-}
-
-static
-int fun_lt(dumb_ptr<env_t> env, val_t *result, Slice<val_t> args)
-{
- fun_gte(env, result, args);
- 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 (args[0].is<ValString>() || args[1].is<ValString>())
- {
- stringify(&args[0]);
- stringify(&args[1]);
- *result = ValInt{ARGSTR(0) > ARGSTR(1)};
- }
- else
- {
- intify(&args[0]);
- intify(&args[1]);
- *result = ValInt{ARGINT(0) > ARGINT(1)};
- }
- return 0;
-}
-
-static
-int fun_lte(dumb_ptr<env_t> env, val_t *result, Slice<val_t> args)
-{
- fun_gt(env, result, args);
- 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 (args[0].is<ValString>() || args[1].is<ValString>())
- {
- stringify(&args[0]);
- stringify(&args[1]);
- *result = ValInt{ARGSTR(0) == ARGSTR(1)};
- }
- 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 (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]);
- *result = ValInt{ARGINT(0) == ARGINT(1)};
- }
- return 0;
-}
-
-static
-int fun_ne(dumb_ptr<env_t> env, val_t *result, Slice<val_t> args)
-{
- fun_eq(env, result, args);
- result->get_if<ValInt>()->v_int ^= 1;
- return 0;
-}
-
-static
-int fun_bitand(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{ARGINT(0) & ARGINT(1)};
- return 0;
-}
-
-static
-int fun_bitor(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{ARGINT(0) | ARGINT(1)};
- return 0;
-}
-
-static
-int fun_bitxor(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{ARGINT(0) ^ ARGINT(1)};
- return 0;
-}
-
-static
-int fun_bitshl(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{ARGINT(0) << ARGINT(1)};
- return 0;
-}
-
-static
-int fun_bitshr(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{ARGINT(0) >> ARGINT(1)};
- return 0;
-}
-
-static
-int fun_max(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *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)
-{
- *result = ValInt{std::min(ARGINT(0), ARGINT(1))};
- return 0;
-}
-
-static
-int fun_if_then_else(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- if (ARGINT(0))
- magic_copy_var(result, &args[1]);
- else
- magic_copy_var(result, &args[2]);
- return 0;
-}
-
-Borrowed<map_local> magic_area_rect(int *x, int *y, int *width, int *height,
- area_t& area_)
-{
- MATCH_BEGIN (area_)
- {
- MATCH_CASE (const AreaUnion&, a)
- {
- (void)a;
- abort();
- }
- MATCH_CASE (const location_t&, a_loc)
- {
- P<map_local> m = a_loc.m;
- *x = a_loc.x;
- *y = a_loc.y;
- *width = 1;
- *height = 1;
- return m;
- }
- MATCH_CASE (const AreaRect&, a_rect)
- {
- P<map_local> m = a_rect.loc.m;
- *x = a_rect.loc.x;
- *y = a_rect.loc.y;
- *width = a_rect.width;
- *height = a_rect.height;
- return m;
- }
- MATCH_CASE (const AreaBar&, a_bar)
- {
- int tx = a_bar.loc.x;
- int ty = a_bar.loc.y;
- int twidth = a_bar.width;
- int tdepth = a_bar.width;
- P<map_local> m = a_bar.loc.m;
-
- switch (a_bar.dir)
- {
- case DIR::S:
- *x = tx - twidth;
- *y = ty;
- *width = twidth * 2 + 1;
- *height = tdepth;
- break;
-
- case DIR::W:
- *x = tx - tdepth;
- *y = ty - twidth;
- *width = tdepth;
- *height = twidth * 2 + 1;
- break;
-
- case DIR::N:
- *x = tx - twidth;
- *y = ty - tdepth;
- *width = twidth * 2 + 1;
- *height = tdepth;
- break;
-
- case DIR::E:
- *x = tx;
- *y = ty - twidth;
- *width = tdepth;
- *height = twidth * 2 + 1;
- break;
-
- default:
- FPRINTF(stderr,
- "Error: Trying to compute area of NE/SE/NW/SW-facing bar"_fmt);
- *x = tx;
- *y = ty;
- *width = *height = 1;
- }
- return m;
- }
- }
- MATCH_END ();
- abort();
-}
-
-int magic_location_in_area(Borrowed<map_local> m, int x, int y, dumb_ptr<area_t> area)
-{
- MATCH_BEGIN (*area)
- {
- MATCH_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]);
- }
- MATCH_CASE (const location_t&, a_loc)
- {
- (void)a_loc;
- // TODO this can be simplified
- int ax, ay, awidth, aheight;
- P<map_local> am = magic_area_rect(&ax, &ay, &awidth, &aheight, *area);
- return (am == m
- && (x >= ax) && (y >= ay)
- && (x < ax + awidth) && (y < ay + aheight));
- }
- MATCH_CASE (const AreaRect&, a_rect)
- {
- (void)a_rect;
- // TODO this is too complicated
- int ax, ay, awidth, aheight;
- P<map_local> am = magic_area_rect(&ax, &ay, &awidth, &aheight, *area);
- return (am == m
- && (x >= ax) && (y >= ay)
- && (x < ax + awidth) && (y < ay + aheight));
- }
- MATCH_CASE (const AreaBar&, a_bar)
- {
- (void)a_bar;
- // TODO this is wrong
- int ax, ay, awidth, aheight;
- P<map_local> am = magic_area_rect(&ax, &ay, &awidth, &aheight, *area);
- return (am == m
- && (x >= ax) && (y >= ay)
- && (x < ax + awidth) && (y < ay + aheight));
- }
- }
- MATCH_END ();
- abort();
-}
-
-static
-int fun_is_in(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{magic_location_in_area(ARGLOCATION(0).m,
- ARGLOCATION(0).x,
- ARGLOCATION(0).y, ARGAREA(1))};
- return 0;
-}
-
-static
-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))
- {
- *result = ValInt{0};
- }
- else
- {
- SkillID id = static_cast<SkillID>(ARGINT(1));
- *result = ValInt{ARGPC(0)->status.skill[id].lv};
- }
- return 0;
-}
-
-static
-int fun_his_shroud(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{(ENTITY_TYPE(0) == BL::PC && ARGPC(0)->state.shroud_active)};
- return 0;
-}
-
-#define BATTLE_GETTER(name) \
-static \
-int fun_get_##name(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) \
-{ \
- *result = ValInt{battle_get_##name(ARGENTITY(0))}; \
- return 0; \
-}
-
-BATTLE_GETTER(str)
-BATTLE_GETTER(agi)
-BATTLE_GETTER(vit)
-BATTLE_GETTER(dex)
-BATTLE_GETTER(luk)
-BATTLE_GETTER(int)
-BATTLE_GETTER(lv)
-BATTLE_GETTER(hp)
-BATTLE_GETTER(mdef)
-BATTLE_GETTER(def)
-BATTLE_GETTER(max_hp)
-static
-int fun_get_dir(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValDir{battle_get_dir(ARGENTITY(0))};
- return 0;
-}
-
-#define MMO_GETTER(name) \
-static \
-int fun_get_##name(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) \
-{ \
- if (ENTITY_TYPE(0) == BL::PC) \
- *result = ValInt{ARGPC(0)->status.name}; \
- else \
- *result = ValInt{0}; \
- return 0; \
-}
-
-MMO_GETTER(sp)
-MMO_GETTER(max_sp)
-
-static
-int fun_name_of(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- if (args[0].is<ValEntityPtr>())
- {
- *result = ValString{show_entity(ARGENTITY(0))};
- return 0;
- }
- else if (args[0].is<ValSpell>())
- {
- *result = ValString{ARGSPELL(0)->name};
- return 0;
- }
- else if (args[0].is<ValInvocationPtr>())
- {
- *result = ValString{ARGINVOCATION(0)->spell->name};
- return 0;
- }
- return 1;
-}
-
-/* [Freeyorp] I'm putting this one in as name_of seems to have issues with summoned or spawned mobs. */
-static
-int fun_mob_id(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- if (ENTITY_TYPE(0) != BL::MOB)
- return 1;
- *result = ValInt{unwrap<Species>(ARGMOB(0)->mob_class)};
- return 0;
-}
-
-inline
-void COPY_LOCATION(block_list& dest, location_t& src)
-{
- dest.bl_x = src.x;
- dest.bl_y = src.y;
- dest.bl_m = src.m;
-}
-
-inline
-void COPY_LOCATION(location_t& dest, block_list& src)
-{
- dest.x = src.bl_x;
- dest.y = src.bl_y;
- dest.m = src.bl_m;
-}
-
-static
-int fun_location(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- location_t loc;
- COPY_LOCATION(loc, *(ARGENTITY(0)));
- *result = ValLocation{loc};
- return 0;
-}
-
-static
-int fun_random(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- int delta = ARGINT(0);
- if (delta < 0)
- delta = -delta;
- if (delta == 0)
- {
- *result = ValInt{0};
- return 0;
- }
- *result = ValInt{random_::to(delta)};
-
- if (ARGINT(0) < 0)
- result->get_if<ValInt>()->v_int *= -1;
- return 0;
-}
-
-static
-int fun_random_dir(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- if (ARGINT(0))
- *result = ValDir{random_::choice({DIR::S, DIR::SW, DIR::W, DIR::NW, DIR::N, DIR::NE, DIR::E, DIR::SE})};
- else
- *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)
-{
- *result = ValInt{static_cast<int32_t>(unwrap<BlockId>(ARGENTITY(0)->bl_id))};
- return 0;
-}
-
-// ret -1: not a string, ret 1: no such item, ret 0: OK
-int magic_find_item(Slice<val_t> args, int index, Item *item_, int *stackable)
-{
- Option<P<struct item_data>> item_data_ = None;
- int must_add_sequentially;
-
- if (args[index].is<ValInt>())
- item_data_ = itemdb_exists(wrap<ItemNameId>(static_cast<uint16_t>(ARGINT(index))));
- else if (args[index].is<ValString>())
- item_data_ = itemdb_searchname(ARGSTR(index));
- else
- return -1;
-
- P<struct item_data> item_data = TRY_UNWRAP(item_data_, return 1);
-
- // Very elegant.
- must_add_sequentially = (
- item_data->type == ItemType::WEAPON
- || item_data->type == ItemType::ARMOR
- || item_data->type == ItemType::_7
- || item_data->type == ItemType::_8);
-
- if (stackable)
- *stackable = !must_add_sequentially;
-
- *item_ = Item();
- item_->nameid = item_data->nameid;
-
- return 0;
-}
-
-static
-int fun_count_item(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- dumb_ptr<map_session_data> chr = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr;
- int stackable;
- Item item;
-
- GET_ARG_ITEM(1, item, stackable);
-
- if (!chr)
- return 1;
-
- *result = ValInt{pc_count_all_items(chr, item.nameid)};
- return 0;
-}
-
-static
-int fun_is_equipped(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- dumb_ptr<map_session_data> chr = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr;
- int stackable;
- Item item;
- bool retval = false;
-
- GET_ARG_ITEM(1, item, stackable);
-
- if (!chr)
- return 1;
-
- for (EQUIP i : EQUIPs)
- {
- IOff0 idx = chr->equip_index_maybe[i];
- if (idx.ok() && chr->status.inventory[idx].nameid == item.nameid)
- {
- retval = true;
- break;
- }
- }
-
- *result = ValInt{retval};
- return 0;
-}
-
-static
-int fun_is_married(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *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)
-{
- *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)
-{
- *result = ValInt{(ENTITY_TYPE(0) == BL::PC)};
- return 0;
-}
-
-static
-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)
- {
- *result =
- ValEntityPtr{map_nick2sd(map_charid2nick(ARGPC(0)->status.partner_id))};
- return 0;
- }
- else
- return 1;
-}
-
-static
-int fun_awayfrom(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- location_t *loc = &ARGLOCATION(0);
- int dx = dirx[ARGDIR(1)];
- int dy = diry[ARGDIR(1)];
- int distance = ARGINT(2);
- while (distance--
- && !bool(read_gatp(loc->m, loc->x + dx, loc->y + dy)
- & MapCell::UNWALKABLE))
- {
- loc->x += dx;
- loc->y += dy;
- }
-
- *result = ValLocation{*loc};
- return 0;
-}
-
-static
-int fun_failed(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{args[0].is<ValFail>()};
- return 0;
-}
-
-static
-int fun_npc(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- NpcName name = stringish<NpcName>(ARGSTR(0));
- 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));
- 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)
- *result = ValInt{0x7fffffff};
- else
- *result = ValInt{std::max(abs(ARGLOCATION(0).x - ARGLOCATION(1).x),
- abs(ARGLOCATION(0).y - ARGLOCATION(1).y))};
- return 0;
-}
-
-static
-int fun_rdistance(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- if (ARGLOCATION(0).m != ARGLOCATION(1).m)
- *result = ValInt{0x7fffffff};
- else
- {
- int dx = ARGLOCATION(0).x - ARGLOCATION(1).x;
- int dy = ARGLOCATION(0).y - ARGLOCATION(1).y;
- *result = ValInt{static_cast<int>(sqrt((dx * dx) + (dy * dy)))};
- }
- return 0;
-}
-
-static
-int fun_anchor(dumb_ptr<env_t> env, val_t *result, Slice<val_t> args)
-{
- dumb_ptr<teleport_anchor_t> anchor = magic_find_anchor(ARGSTR(0));
-
- if (!anchor)
- return 1;
-
- magic_eval(env, result, anchor->location);
-
- make_area(result);
- if (!result->is<ValArea>())
- {
- magic_clear_var(result);
- return 1;
- }
-
- return 0;
-}
-
-static
-int fun_line_of_sight(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- block_list e1, e2;
-
- COPY_LOCATION(e1, ARGLOCATION(0));
- COPY_LOCATION(e2, ARGLOCATION(1));
-
- *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)
-{
- MATCH_BEGIN (*area)
- {
- MATCH_CASE (const AreaUnion&, a)
- {
- if (random_::chance({a.a_union[0]->size, area->size}))
- magic_random_location(dest, a.a_union[0]);
- else
- magic_random_location(dest, a.a_union[1]);
- }
- MATCH_CASE (const location_t&, a_loc)
- {
- (void)a_loc;
- // TODO this can be simplified
- int x, y, w, h;
- P<map_local> m = magic_area_rect(&x, &y, &w, &h, *area);
-
- 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;
- }
- MATCH_CASE (const AreaRect&, a_rect)
- {
- (void)a_rect;
- // TODO this can be simplified
- int x, y, w, h;
- P<map_local> m = magic_area_rect(&x, &y, &w, &h, *area);
-
- 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;
- }
- MATCH_CASE (const AreaBar&, a_bar)
- {
- (void)a_bar;
- // TODO this is wrong
- int x, y, w, h;
- P<map_local> m = magic_area_rect(&x, &y, &w, &h, *area);
-
- 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;
- }
- }
- MATCH_END ();
-}
-
-static
-int fun_pick_location(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- location_t loc;
- magic_random_location(&loc, ARGAREA(0));
- *result = ValLocation{loc};
- return 0;
-}
-
-static
-int fun_read_script_int(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- dumb_ptr<block_list> subject_p = ARGENTITY(0);
- VarName var_name = stringish<VarName>(ARGSTR(1));
- int array_index = 0;
-
- if (subject_p->bl_type != BL::PC)
- return 1;
-
- *result = ValInt{get_script_var_i(subject_p->is_player(), var_name, array_index)};
- return 0;
-}
-
-static
-int fun_read_script_str(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- dumb_ptr<block_list> subject_p = ARGENTITY(0);
- VarName var_name = stringish<VarName>(ARGSTR(1));
- int array_index = 0;
-
- if (subject_p->bl_type != BL::PC)
- return 1;
-
- *result = ValString{get_script_var_s(subject_p->is_player(), var_name, array_index)};
- return 0;
-}
-
-static
-int fun_rbox(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- location_t loc = ARGLOCATION(0);
- int radius = ARGINT(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)};
-
- return 0;
-}
-
-static
-int fun_running_status_update(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- if (ENTITY_TYPE(0) != BL::PC && ENTITY_TYPE(0) != BL::MOB)
- return 1;
-
- StatusChange sc = static_cast<StatusChange>(ARGINT(1));
- *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)
-{
- *result = ValInt{(bool((ARGPC(0))->status.option & static_cast<Opt0>(ARGINT(1))))};
- return 0;
-}
-
-static
-int fun_element(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *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)
-{
- *result = ValInt{battle_get_element(ARGENTITY(0)).level};
- return 0;
-}
-
-static
-int fun_is_exterior(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
-#warning "Evil assumptions!"
- *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)
-{
- *result = ValInt{nullptr != strstr(ARGSTR(0).c_str(), ARGSTR(1).c_str())};
- return 0;
-}
-
-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());
- *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)
-{
- *result = ValInt{static_cast<int32_t>(strlen(ARGSTR(0).c_str()))};
- return 0;
-}
-
-static
-int fun_substr(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- RString src = ARGSTR(0);
- int offset = ARGINT(1);
- int len = ARGINT(2);
-
- if (len < 0)
- len = 0;
- if (offset < 0)
- offset = 0;
-
- if (offset > src.size())
- offset = src.size();
-
- if (offset + len > src.size())
- len = src.size() - offset;
-
- auto begin = src.begin() + offset;
- auto end = begin + len;
- *result = ValString{RString(begin, end)};
-
- return 0;
-}
-
-static
-int fun_sqrt(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- *result = ValInt{static_cast<int>(sqrt(ARGINT(0)))};
- return 0;
-}
-
-static
-int fun_map_level(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
-#warning "Evil assumptions!"
- *result = ValInt{ARGLOCATION(0).m->name_[4] - '0'};
- return 0;
-}
-
-static
-int fun_map_nr(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
-#warning "Evil assumptions!"
- MapName mapname = ARGLOCATION(0).m->name_;
-
- *result = ValInt{((mapname[0] - '0') * 100)
- + ((mapname[1] - '0') * 10) + ((mapname[2] - '0'))};
- return 0;
-}
-
-static
-int fun_dir_towards(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- int dx;
- int dy;
-
- if (ARGLOCATION(0).m != ARGLOCATION(1).m)
- return 1;
-
- dx = ARGLOCATION(1).x - ARGLOCATION(0).x;
- dy = ARGLOCATION(1).y - ARGLOCATION(0).y;
-
- if (ARGINT(2))
- {
- /* 8-direction mode */
- if (abs(dx) > abs(dy) * 2)
- { /* east or west */
- if (dx < 0)
- *result = ValDir{DIR::W};
- else
- *result = ValDir{DIR::E};
- }
- else if (abs(dy) > abs(dx) * 2)
- { /* north or south */
- if (dy > 0)
- *result = ValDir{DIR::S};
- else
- *result = ValDir{DIR::N};
- }
- else if (dx < 0)
- { /* north-west or south-west */
- if (dy < 0)
- *result = ValDir{DIR::NW};
- else
- *result = ValDir{DIR::SW};
- }
- else
- { /* north-east or south-east */
- if (dy < 0)
- *result = ValDir{DIR::NE};
- else
- *result = ValDir{DIR::SE};
- }
- }
- else
- {
- /* 4-direction mode */
- if (abs(dx) > abs(dy))
- { /* east or west */
- if (dx < 0)
- *result = ValDir{DIR::W};
- else
- *result = ValDir{DIR::E};
- }
- else
- { /* north or south */
- if (dy > 0)
- *result = ValDir{DIR::S};
- else
- *result = ValDir{DIR::N};
- }
- }
-
- return 0;
-}
-
-static
-int fun_extract_healer_xp(dumb_ptr<env_t>, val_t *result, Slice<val_t> args)
-{
- dumb_ptr<map_session_data> sd = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr;
-
- if (!sd)
- *result = ValInt{0};
- else
- *result = ValInt{pc_extract_healer_exp(sd, ARGINT(1))};
- return 0;
-}
-
-#define MAGIC_FUNCTION(name, args, ret, impl) {name, {name, args, ret, impl}}
-#define MAGIC_FUNCTION1(name, args, ret) MAGIC_FUNCTION(#name##_s, args, ret, fun_##name)
-static // should be LString, but no heterogenous lookup yet
-std::map<ZString, fun_t> functions =
-{
- MAGIC_FUNCTION("+"_s, ".."_s, '.', fun_add),
- MAGIC_FUNCTION("-"_s, "ii"_s, 'i', fun_sub),
- MAGIC_FUNCTION("*"_s, "ii"_s, 'i', fun_mul),
- MAGIC_FUNCTION("/"_s, "ii"_s, 'i', fun_div),
- MAGIC_FUNCTION("%"_s, "ii"_s, 'i', fun_mod),
- MAGIC_FUNCTION("||"_s, "ii"_s, 'i', fun_or),
- MAGIC_FUNCTION("&&"_s, "ii"_s, 'i', fun_and),
- MAGIC_FUNCTION("<"_s, ".."_s, 'i', fun_lt),
- MAGIC_FUNCTION(">"_s, ".."_s, 'i', fun_gt),
- MAGIC_FUNCTION("<="_s, ".."_s, 'i', fun_lte),
- MAGIC_FUNCTION(">="_s, ".."_s, 'i', fun_gte),
- MAGIC_FUNCTION("=="_s, ".."_s, 'i', fun_eq),
- MAGIC_FUNCTION("!="_s, ".."_s, 'i', fun_ne),
- MAGIC_FUNCTION("|"_s, ".."_s, 'i', fun_bitor),
- MAGIC_FUNCTION("&"_s, "ii"_s, 'i', fun_bitand),
- MAGIC_FUNCTION("^"_s, "ii"_s, 'i', fun_bitxor),
- MAGIC_FUNCTION("<<"_s, "ii"_s, 'i', fun_bitshl),
- MAGIC_FUNCTION(">>"_s, "ii"_s, 'i', fun_bitshr),
- MAGIC_FUNCTION1(not, "i"_s, 'i'),
- MAGIC_FUNCTION1(neg, "i"_s, 'i'),
- MAGIC_FUNCTION1(max, "ii"_s, 'i'),
- MAGIC_FUNCTION1(min, "ii"_s, 'i'),
- MAGIC_FUNCTION1(is_in, "la"_s, 'i'),
- MAGIC_FUNCTION1(if_then_else, "i__"_s, '_'),
- MAGIC_FUNCTION1(skill, "ei"_s, 'i'),
- MAGIC_FUNCTION("str"_s, "e"_s, 'i', fun_get_str),
- MAGIC_FUNCTION("agi"_s, "e"_s, 'i', fun_get_agi),
- MAGIC_FUNCTION("vit"_s, "e"_s, 'i', fun_get_vit),
- MAGIC_FUNCTION("dex"_s, "e"_s, 'i', fun_get_dex),
- MAGIC_FUNCTION("luk"_s, "e"_s, 'i', fun_get_luk),
- MAGIC_FUNCTION("int"_s, "e"_s, 'i', fun_get_int),
- MAGIC_FUNCTION("level"_s, "e"_s, 'i', fun_get_lv),
- MAGIC_FUNCTION("mdef"_s, "e"_s, 'i', fun_get_mdef),
- MAGIC_FUNCTION("def"_s, "e"_s, 'i', fun_get_def),
- MAGIC_FUNCTION("hp"_s, "e"_s, 'i', fun_get_hp),
- MAGIC_FUNCTION("max_hp"_s, "e"_s, 'i', fun_get_max_hp),
- MAGIC_FUNCTION("sp"_s, "e"_s, 'i', fun_get_sp),
- MAGIC_FUNCTION("max_sp"_s, "e"_s, 'i', fun_get_max_sp),
- MAGIC_FUNCTION("dir"_s, "e"_s, 'd', fun_get_dir),
- MAGIC_FUNCTION1(name_of, "."_s, 's'),
- MAGIC_FUNCTION1(mob_id, "e"_s, 'i'),
- MAGIC_FUNCTION1(location, "e"_s, 'l'),
- MAGIC_FUNCTION1(random, "i"_s, 'i'),
- MAGIC_FUNCTION1(random_dir, "i"_s, 'd'),
- MAGIC_FUNCTION1(hash_entity, "e"_s, 'i'),
- MAGIC_FUNCTION1(is_married, "e"_s, 'i'),
- MAGIC_FUNCTION1(partner, "e"_s, 'e'),
- MAGIC_FUNCTION1(awayfrom, "ldi"_s, 'l'),
- MAGIC_FUNCTION1(failed, "_"_s, 'i'),
- MAGIC_FUNCTION1(pc, "s"_s, 'e'),
- MAGIC_FUNCTION1(npc, "s"_s, 'e'),
- MAGIC_FUNCTION1(distance, "ll"_s, 'i'),
- MAGIC_FUNCTION1(rdistance, "ll"_s, 'i'),
- MAGIC_FUNCTION1(anchor, "s"_s, 'a'),
- MAGIC_FUNCTION("random_location"_s, "a"_s, 'l', fun_pick_location),
- MAGIC_FUNCTION("script_int"_s, "es"_s, 'i', fun_read_script_int),
- MAGIC_FUNCTION("script_str"_s, "es"_s, 's', fun_read_script_str),
- MAGIC_FUNCTION1(rbox, "li"_s, 'a'),
- MAGIC_FUNCTION1(count_item, "e."_s, 'i'),
- MAGIC_FUNCTION1(line_of_sight, "ll"_s, 'i'),
- MAGIC_FUNCTION1(running_status_update, "ei"_s, 'i'),
- MAGIC_FUNCTION1(status_option, "ei"_s, 'i'),
- MAGIC_FUNCTION1(element, "e"_s, 'i'),
- MAGIC_FUNCTION1(element_level, "e"_s, 'i'),
- MAGIC_FUNCTION1(his_shroud, "e"_s, 'i'),
- MAGIC_FUNCTION1(is_equipped, "e."_s, 'i'),
- MAGIC_FUNCTION1(is_exterior, "l"_s, 'i'),
- MAGIC_FUNCTION1(contains_string, "ss"_s, 'i'),
- MAGIC_FUNCTION1(strstr, "ss"_s, 'i'),
- MAGIC_FUNCTION1(strlen, "s"_s, 'i'),
- MAGIC_FUNCTION1(substr, "sii"_s, 's'),
- MAGIC_FUNCTION1(sqrt, "i"_s, 'i'),
- MAGIC_FUNCTION1(map_level, "l"_s, 'i'),
- MAGIC_FUNCTION1(map_nr, "l"_s, 'i'),
- MAGIC_FUNCTION1(dir_towards, "lli"_s, 'd'),
- MAGIC_FUNCTION1(is_dead, "e"_s, 'i'),
- MAGIC_FUNCTION1(is_pc, "e"_s, 'i'),
- MAGIC_FUNCTION("extract_healer_experience"_s, "ei"_s, 'i', fun_extract_healer_xp),
-};
-
-fun_t *magic_get_fun(ZString name)
-{
- auto it = functions.find(name);
- if (it == functions.end())
- return nullptr;
- return &it->second;
-}
-
-// 1 on failure
-static
-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 (m.is<ValString>()
- && x.is<ValInt>() && y.is<ValInt>())
- {
- MapName name = VString<15>(ZString(m.get_if<ValString>()->v_string));
- magic_clear_var(&m);
- P<map_local> map_id = TRY_UNWRAP(map_mapname2mapid(name), return 1);
- dest->m = map_id;
- dest->x = x.get_if<ValInt>()->v_int;
- dest->y = y.get_if<ValInt>()->v_int;
- return 0;
- }
- else
- {
- magic_clear_var(&m);
- magic_clear_var(&x);
- magic_clear_var(&y);
- return 1;
- }
-}
-
-static
-dumb_ptr<area_t> eval_area(dumb_ptr<env_t> env, const e_area_t& expr_)
-{
- MATCH_BEGIN (expr_)
- {
- MATCH_CASE (const e_location_t&, a_loc)
- {
- location_t loc;
- if (eval_location(env, &loc, &a_loc))
- {
- return nullptr;
- }
- else
- {
- return dumb_ptr<area_t>::make(loc);
- }
- }
- MATCH_CASE (const ExprAreaUnion&, a)
- {
- AreaUnion u;
- bool fail = false;
- for (int i = 0; i < 2; i++)
- {
- u.a_union[i] = eval_area(env, *a.a_union[i]);
- if (!u.a_union[i])
- fail = true;
- }
-
- if (fail)
- {
- for (int i = 0; i < 2; i++)
- {
- if (u.a_union[i])
- free_area(u.a_union[i]);
- }
- return nullptr;
- }
- return dumb_ptr<area_t>::make(u);
- }
- MATCH_CASE (const ExprAreaRect&, a_rect)
- {
- val_t width, height;
- 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))
- {
- a_rect_.width = width.get_if<ValInt>()->v_int;
- a_rect_.height = height.get_if<ValInt>()->v_int;
-
- magic_clear_var(&width);
- magic_clear_var(&height);
- return dumb_ptr<area_t>::make(a_rect_);
- }
- else
- {
- magic_clear_var(&width);
- magic_clear_var(&height);
- return nullptr;
- }
- }
- MATCH_CASE (const ExprAreaBar&, a_bar)
- {
- val_t width, depth, dir;
- 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))
- {
- 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;
-
- magic_clear_var(&width);
- magic_clear_var(&depth);
- magic_clear_var(&dir);
- return dumb_ptr<area_t>::make(a_bar_);
- }
- else
- {
- magic_clear_var(&width);
- magic_clear_var(&depth);
- magic_clear_var(&dir);
- return nullptr;
- }
- }
- }
- MATCH_END ();
- 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
-bool type_key_matches(char ty_key, val_t *arg, bool begin)
-{
- switch (ty_key)
- {
- case 'i':
- if (begin)
- intify(arg);
- return arg->is<ValInt>();
- case 'd':
- return arg->is<ValDir>();
- case 's':
- if (begin)
- stringify(arg);
- return arg->is<ValString>();
- case 'e':
- return arg->is<ValEntityPtr>();
- case 'l':
- if (begin)
- make_location(arg);
- return arg->is<ValLocation>();
- case 'a':
- if (begin)
- make_area(arg);
- return arg->is<ValArea>();
- case 'S':
- if (begin)
- make_spell(arg);
- return arg->is<ValSpell>();
- case 'I':
- return arg->is<ValInvocationPtr>();
- default:
- return true;
- }
-}
-
-int magic_signature_check(ZString opname, ZString funname, ZString signature,
- Slice<val_t> args, int line, int column)
-{
- int i;
- for (i = 0; i < args.size(); i++)
- {
- val_t *arg = &args[i];
-
- // 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 */
- dumb_ptr<block_list> ent = map_id2bl(p1->v_eid);
- if (ent)
- {
- *arg = ValEntityPtr{ent};
- }
- else
- {
- *arg = ValFail{};
- }
- }
- else if (ValInvocationInt *p2 = arg->get_if<ValInvocationInt>())
- {
- dumb_ptr<invocation> invoc = map_id2bl(p2->v_iid)->is_spell();
- if (invoc)
- {
- *arg = ValInvocationPtr{invoc};
- }
- else
- {
- *arg = ValFail();
- }
- }
-
- char ty_key = signature[i];
- if (!ty_key)
- {
- FPRINTF(stderr,
- "[magic-eval]: L%d:%d: Too many arguments (%zu) to %s `%s'\n"_fmt,
- line, column, args.size(), opname, funname);
- return 1;
- }
-
- if (arg->is<ValFail>() && ty_key != '_')
- return 1; /* Fail `in a sane way': This is a perfectly permissible error */
-
- // this also does conversions now
- if (type_key_matches(ty_key, arg, true))
- continue;
-
- if (arg->is<ValUndef>())
- {
- FPRINTF(stderr,
- "[magic-eval]: L%d:%d: Argument #%d to %s `%s' undefined\n"_fmt,
- line, column, i + 1, opname, funname);
- return 1;
- }
-
-
- { /* Coercion failed? */
- if (!arg->is<ValFail>())
- {
- FPRINTF(stderr,
- "[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;
- }
- }
-
- return 0;
-}
-
-void magic_eval(dumb_ptr<env_t> env, val_t *dest, dumb_ptr<expr_t> expr)
-{
- MATCH_BEGIN (*expr)
- {
- MATCH_CASE (const val_t&, e_val)
- {
- magic_copy_var(dest, &e_val);
- }
-
- MATCH_CASE (const e_location_t&, e_location)
- {
- location_t loc;
- if (eval_location(env, &loc, &e_location))
- *dest = ValFail();
- else
- *dest = ValLocation{loc};
- }
- MATCH_CASE (const e_area_t&, e_area)
- {
- if (dumb_ptr<area_t> area = eval_area(env, e_area))
- *dest = ValArea{area};
- else
- *dest = ValFail();
- }
- MATCH_CASE (const ExprFunApp&, e_funapp)
- {
- val_t arguments[MAX_ARGS];
- int args_nr = e_funapp.args_nr;
- int i;
- fun_t *f = e_funapp.funp;
-
- for (i = 0; i < args_nr; ++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),
- e_funapp.line_nr, e_funapp.column)
- || f->fun(env, dest, Slice<val_t>(arguments, args_nr)))
- *dest = ValFail();
- else
- {
- 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 (ValEntityPtr *ent = dest->get_if<ValEntityPtr>())
- {
- if (ent->v_entity)
- *dest = ValEntityInt{ent->v_entity->bl_id};
- else
- *dest = ValFail();
- }
- // what about invocation?
- }
-
- for (i = 0; i < args_nr; ++i)
- magic_clear_var(&arguments[i]);
- }
- MATCH_CASE (const ExprId&, e)
- {
- val_t& v = env->VAR(e.e_id);
- magic_copy_var(dest, &v);
- }
- MATCH_CASE (const ExprField&, e_field)
- {
- val_t v;
- int id = e_field.id;
- magic_eval(env, &v, e_field.expr);
-
- assert(!v.is<ValInvocationPtr>());
- if (ValInvocationInt *ii = v.get_if<ValInvocationInt>())
- {
- dumb_ptr<invocation> t = map_id2bl(ii->v_iid)->is_spell();
-
- if (!t)
- *dest = ValUndef();
- else
- {
- val_t& val = t->env->VAR(id);
- magic_copy_var(dest, &val);
- }
- }
- else
- {
- FPRINTF(stderr,
- "[magic] Attempt to access field %s on non-spell\n"_fmt,
- env->base_env->varv[id].name);
- *dest = ValFail();
- }
- }
- }
- MATCH_END ();
-}
-
-int magic_eval_int(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr)
-{
- val_t result;
- magic_eval(env, &result, expr);
-
- if (result.is<ValFail>() || result.is<ValUndef>())
- return 0;
-
- intify(&result);
-
- return result.get_if<ValInt>()->v_int;
-}
-
-AString magic_eval_str(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr)
-{
- val_t result;
- magic_eval(env, &result, expr);
-
- if (result.is<ValFail>() || result.is<ValUndef>())
- return "?"_s;
-
- stringify(&result);
-
- return result.get_if<ValString>()->v_string;
-}
-} // namespace magic
-} // namespace map
-} // namespace tmwa
diff --git a/src/map/magic-expr.hpp b/src/map/magic-expr.hpp
deleted file mode 100644
index 055f37b..0000000
--- a/src/map/magic-expr.hpp
+++ /dev/null
@@ -1,107 +0,0 @@
-#pragma once
-// magic-expr.hpp - Pure functions for the old magic backend.
-//
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include "fwd.hpp"
-
-#include "../strings/zstring.hpp"
-#include "../strings/literal.hpp"
-
-#include "magic-interpreter.t.hpp"
-
-
-namespace tmwa
-{
-namespace map
-{
-namespace magic
-{
-/*
- * Argument types:
- * i : int
- * d : dir
- * s : string
- * e : entity
- * l : location
- * a : area
- * S : spell
- * I : invocation
- * . : any, except for fail/undef
- * _ : any, including fail, but not undef
- */
-struct fun_t
-{
- LString name;
- LString signature;
- char ret_ty;
- int (*fun)(dumb_ptr<env_t> env, val_t *result, Slice<val_t> arga);
-};
-
-/**
- * Retrieves a function by name
- * @param name The name to look up
- * @return A function of that name, or nullptr.
- */
-fun_t *magic_get_fun(ZString name);
-
-/**
- * Evaluates an expression and stores the result in `dest'
- */
-void magic_eval(dumb_ptr<env_t> env, val_t *dest, dumb_ptr<expr_t> expr);
-
-/**
- * Evaluates an expression and coerces the result into an integer
- */
-int magic_eval_int(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr);
-
-/**
- * Evaluates an expression and coerces the result into a string
- */
-AString magic_eval_str(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr);
-
-void magic_clear_var(val_t *v);
-
-void magic_copy_var(val_t *dest, const val_t *src);
-
-void magic_random_location(location_t *dest, dumb_ptr<area_t> area);
-
-// ret -1: not a string, ret 1: no such item, ret 0: OK
-int magic_find_item(Slice<val_t> args, int index, Item *item, int *stackable);
-
-#define GET_ARG_ITEM(index, dest, stackable) \
- switch (magic_find_item(args, index, &dest, &stackable)) \
- { \
- case -1: return 1; \
- case 1: return 0; \
- default: break; \
- }
-
-int magic_location_in_area(Borrowed<map_local> m, int x, int y, dumb_ptr<area_t> area);
-
-/* Helper definitions for dealing with functions and operations */
-
-int magic_signature_check(ZString opname, ZString funname, ZString signature,
- Slice<val_t> args, int line, int column);
-
-Borrowed<map_local> magic_area_rect(int *x, int *y, int *width, int *height,
- area_t& area);
-} // namespace magic
-} // namespace map
-} // namespace tmwa
diff --git a/src/map/magic-expr.py b/src/map/magic-expr.py
deleted file mode 100644
index f53ddc8..0000000
--- a/src/map/magic-expr.py
+++ /dev/null
@@ -1,38 +0,0 @@
-class fun_t(object):
- __slots__ = ('_value')
-
- name = 'tmwa::map::magic::fun_t'
- depth = 1
- enabled = True
-
- def __init__(self, value):
- if not value:
- value = None
- self._value = value
-
- def to_string(self):
- value = self._value
- if value is None:
- return '(fun_t *) nullptr'
- return '(fun_t *)'
-
- def children(self):
- value = self._value
- if value is None:
- return
- value = value.dereference()
- yield '->name', value['name']
- yield '->signature', value['signature']
- yield '->ret_ty', value['ret_ty']
- yield '->fun', value['fun']
-
- test_extra = '''
- using tmwa::operator "" _s;
- '''
-
- tests = [
- ('static_cast<tmwa::map::magic::fun_t *>(nullptr)',
- '(fun_t *) nullptr'),
- ('new tmwa::map::magic::fun_t{"name"_s, "sig"_s, \'\\0\', nullptr}',
- '(fun_t *) = {->name = "name", ->signature = "sig", ->ret_ty = 0 \'\\000\', ->fun = nullptr}'),
- ]
diff --git a/src/map/magic-interpreter-base.cpp b/src/map/magic-interpreter-base.cpp
deleted file mode 100644
index c2be363..0000000
--- a/src/map/magic-interpreter-base.cpp
+++ /dev/null
@@ -1,553 +0,0 @@
-#include "magic-interpreter-base.hpp"
-// magic-interpreter-base.cpp - Core of the old magic system.
-//
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include <algorithm>
-
-#include "../strings/astring.hpp"
-#include "../strings/xstring.hpp"
-
-#include "../io/cxxstdio.hpp"
-
-#include "../mmo/cxxstdio_enums.hpp"
-
-#include "../net/timer.hpp"
-
-#include "globals.hpp"
-#include "magic.hpp"
-#include "magic-expr.hpp"
-#include "magic-interpreter.hpp"
-#include "pc.hpp"
-
-#include "../poison.hpp"
-
-
-namespace tmwa
-{
-namespace map
-{
-namespace magic
-{
-static
-void set_int(val_t *v, int i)
-{
- *v = ValInt{i};
-}
-
-static __attribute__((unused))
-void set_dir(val_t *v, DIR d)
-{
- *v = ValDir{d};
-}
-
-
-static
-void set_string(val_t *v, RString x)
-{
- *v = ValString{x};
-}
-
-static
-void set_entity(val_t *v, dumb_ptr<block_list> e)
-{
- *v = ValEntityInt{e->bl_id};
-}
-
-static
-void set_invocation(val_t *v, dumb_ptr<invocation> i)
-{
- *v = ValInvocationInt{i->bl_id};
-}
-
-static
-void set_spell(val_t *v, dumb_ptr<spell_t> x)
-{
- *v = ValSpell{x};
-}
-
-AString magic_find_invocation(XString spellname)
-{
- auto it = magic_conf.spells_by_name.find(spellname);
- if (it != magic_conf.spells_by_name.end())
- return it->second->invocation;
-
- return AString();
-}
-
-dumb_ptr<spell_t> magic_find_spell(XString invocation)
-{
- auto it = magic_conf.spells_by_invocation.find(invocation);
- if (it != magic_conf.spells_by_invocation.end())
- return it->second;
-
- return nullptr;
-}
-
-/* -------------------------------------------------------------------------------- */
-/* Spell anchors */
-/* -------------------------------------------------------------------------------- */
-
-AString magic_find_anchor_invocation(XString anchor_name)
-{
- auto it = magic_conf.anchors_by_name.find(anchor_name);
-
- if (it != magic_conf.anchors_by_name.end())
- return it->second->invocation;
-
- return AString();
-}
-
-dumb_ptr<teleport_anchor_t> magic_find_anchor(XString name)
-{
- auto it = magic_conf.anchors_by_invocation.find(name);
- if (it != magic_conf.anchors_by_invocation.end())
- return it->second;
-
- return nullptr;
-}
-
-/* -------------------------------------------------------------------------------- */
-/* Spell guard checks */
-/* -------------------------------------------------------------------------------- */
-
-static
-dumb_ptr<env_t> alloc_env(magic_conf_t *conf)
-{
- auto env = dumb_ptr<env_t>::make();
- env->varu = make_unique<val_t[]>(conf->varv.size());
- env->base_env = conf;
- return env;
-}
-
-static
-dumb_ptr<env_t> clone_env(dumb_ptr<env_t> src)
-{
- dumb_ptr<env_t> retval = alloc_env(src->base_env);
-
- for (int i = 0; i < src->base_env->varv.size(); i++)
- magic_copy_var(&retval->varu[i], &src->varu[i]);
-
- return retval;
-}
-
-void magic_free_env(dumb_ptr<env_t> env)
-{
- for (int i = 0; i < env->base_env->varv.size(); i++)
- magic_clear_var(&env->varu[i]);
- // handled by std::unique_ptr now. Was a memory leak before.
- // delete[] env->vars;
- env.delete_();
-}
-
-dumb_ptr<env_t> spell_create_env(magic_conf_t *conf, dumb_ptr<spell_t> spell,
- dumb_ptr<map_session_data> caster, int spellpower, XString param)
-{
- dumb_ptr<env_t> env = alloc_env(conf);
-
- switch (spell->spellarg_ty)
- {
-
- case SPELLARG::STRING:
- set_string(&env->varu[spell->arg], param);
- break;
-
- case SPELLARG::PC:
- {
- CharName name = stringish<CharName>(param);
- dumb_ptr<map_session_data> subject = map_nick2sd(name);
- if (!subject)
- subject = caster;
- set_entity(&env->varu[spell->arg], subject);
- break;
- }
-
- case SPELLARG::NONE:
- break;
-
- default:
- FPRINTF(stderr, "Unexpected spellarg type %d\n"_fmt,
- spell->spellarg_ty);
- }
-
- set_entity(&env->varu[VAR_CASTER], caster);
- set_int(&env->varu[VAR_SPELLPOWER], spellpower);
- set_spell(&env->varu[VAR_SPELL], spell);
-
- return env;
-}
-
-static
-void free_components(dumb_ptr<component_t> *component_holder)
-{
- if (*component_holder == nullptr)
- return;
- free_components(&(*component_holder)->next);
- (*component_holder).delete_();
- *component_holder = nullptr;
-}
-
-void magic_add_component(dumb_ptr<component_t> *component_holder, ItemNameId id, int count)
-{
- if (count <= 0)
- return;
-
- if (*component_holder == nullptr)
- {
- auto component = dumb_ptr<component_t>::make();
- component->next = nullptr;
- component->item_id = id;
- component->count = count;
- *component_holder = component;
- }
- else
- {
- dumb_ptr<component_t> component = *component_holder;
- if (component->item_id == id)
- {
- component->count += count;
- return;
- }
- else
- magic_add_component(&component->next, id, count);
- /* Tail-recurse; gcc can optimise this. Not that it matters. */
- }
-}
-
-static
-void copy_components(dumb_ptr<component_t> *component_holder, dumb_ptr<component_t> component)
-{
- if (component == nullptr)
- return;
-
- magic_add_component(component_holder, component->item_id, component->count);
- copy_components(component_holder, component->next);
-}
-
-typedef struct spellguard_check
-{
- dumb_ptr<component_t> catalysts, components;
- int mana;
- interval_t casttime;
-} spellguard_check_t;
-
-static
-int check_prerequisites(dumb_ptr<map_session_data> caster, dumb_ptr<component_t> component)
-{
- while (component)
- {
- if (pc_count_all_items(caster, component->item_id) < component->count)
- return 0; /* insufficient */
-
- component = component->next;
- }
-
- return 1;
-}
-
-static
-void consume_components(dumb_ptr<map_session_data> caster, dumb_ptr<component_t> component)
-{
- while (component)
- {
- pc_remove_items(caster, component->item_id, component->count);
- component = component->next;
- }
-}
-
-static
-int spellguard_can_satisfy(spellguard_check_t *check, dumb_ptr<map_session_data> caster,
- dumb_ptr<env_t> env, int *near_miss)
-{
- tick_t tick = gettick();
-
- int retval = check_prerequisites(caster, check->catalysts);
-
- if (retval && near_miss)
- *near_miss = 1; // close enough!
-
- retval = retval && caster->cast_tick <= tick /* Hasn't cast a spell too recently */
- && check->mana <= caster->status.sp
- && check_prerequisites(caster, check->components);
-
- if (retval)
- {
- interval_t casttime = check->casttime;
-
- 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 */
-
- consume_components(caster, check->components);
- pc_heal(caster, 0, -check->mana);
- }
-
- return retval;
-}
-
-static
-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,
- int *near_miss)
-{
- if (guard == nullptr)
- return nullptr;
-
- MATCH_BEGIN (*guard)
- {
- MATCH_CASE (const GuardCondition&, s)
- {
- if (!magic_eval_int(env, s.s_condition))
- return nullptr;
- }
- MATCH_CASE (const GuardComponents&, s)
- {
- copy_components(&check->components, s.s_components);
- }
- MATCH_CASE (const GuardCatalysts&, s)
- {
- copy_components(&check->catalysts, s.s_catalysts);
- }
- MATCH_CASE (const GuardChoice&, s)
- {
- spellguard_check_t altcheck = *check;
- const effect_set_t *retval;
-
- altcheck.components = nullptr;
- altcheck.catalysts = nullptr;
-
- copy_components(&altcheck.catalysts, check->catalysts);
- copy_components(&altcheck.components, check->components);
-
- retval =
- spellguard_check_sub(&altcheck, guard->next, caster, env,
- near_miss);
- free_components(&altcheck.catalysts);
- free_components(&altcheck.components);
- if (retval)
- return retval;
- else
- return spellguard_check_sub(check, s.s_alt, caster,
- env, near_miss);
- }
- MATCH_CASE (const GuardMana&, s)
- {
- check->mana += magic_eval_int(env, s.s_mana);
- }
- MATCH_CASE (const GuardCastTime&, s)
- {
- check->casttime += static_cast<interval_t>(magic_eval_int(env, s.s_casttime));
- }
- MATCH_CASE (const effect_set_t&, s_effect)
- {
- if (spellguard_can_satisfy(check, caster, env, near_miss))
- return &s_effect;
- else
- return nullptr;
- }
- }
- MATCH_END ();
-
- return spellguard_check_sub(check, guard->next, caster, env, near_miss);
-}
-
-static
-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;
- const effect_set_t *retval;
- check.catalysts = nullptr;
- check.components = nullptr;
- check.mana = 0;
- check.casttime = interval_t::zero();
-
- retval = spellguard_check_sub(&check, guard, caster, env, near_miss);
-
- free_components(&check.catalysts);
- free_components(&check.components);
-
- return retval;
-}
-
-/* -------------------------------------------------------------------------------- */
-/* Public API */
-/* -------------------------------------------------------------------------------- */
-
-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;
-
- if (near_miss)
- *near_miss = 0;
-
- for (letdef_t& ld : spell->letdefv)
- magic_eval(env, &env->varu[ld.id], ld.expr);
-
- return check_spellguard(guard, caster, env, near_miss);
-}
-
-static
-void spell_set_location(dumb_ptr<invocation> invocation, dumb_ptr<block_list> entity)
-{
- magic_clear_var(&invocation->env->varu[VAR_LOCATION]);
- 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)
-{
- if (bool(invocation->spell->flags & SPELL_FLAG::LOCAL))
- return;
- else
- {
- dumb_ptr<block_list> owner_bl = map_id2bl(invocation->subject);
- if (!owner_bl)
- return;
- dumb_ptr<map_session_data> owner = owner_bl->is_player();
-
- spell_set_location(invocation, owner);
- }
-}
-
-dumb_ptr<invocation> spell_instantiate(const effect_set_t *effect_set, dumb_ptr<env_t> env)
-{
- dumb_ptr<invocation> retval;
- retval.new_();
- dumb_ptr<block_list> caster;
-
- retval->env = env;
-
- 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;
-
- caster = map_id2bl(retval->caster); // must still exist
- retval->bl_id = map_addobject(retval);
- retval->bl_type = BL::SPELL;
- retval->bl_m = caster->bl_m;
- retval->bl_x = caster->bl_x;
- retval->bl_y = caster->bl_y;
-
- map_addblock(retval);
- set_invocation(&env->varu[VAR_INVOCATION], retval);
-
- return retval;
-}
-
-dumb_ptr<invocation> spell_clone_effect(dumb_ptr<invocation> base)
-{
- dumb_ptr<invocation> retval;
- retval.new_();
-
- // block_list in general is not copyable
- // since this is the only call site, it is expanded here
- //*retval = *base;
-
- retval->next_invocation = nullptr;
- retval->flags = INVOCATION_FLAG::ZERO;
- dumb_ptr<env_t> env = retval->env = clone_env(base->env);
- retval->spell = base->spell;
- retval->caster = base->caster;
- retval->subject = BlockId();
- // retval->timer = 0;
- // retval->stack = undef;
- retval->script_pos = 0;
- // huh?
- retval->current_effect = base->trigger_effect;
- retval->trigger_effect = base->trigger_effect;
- retval->end_effect = nullptr;
- // retval->status_change_refs = nullptr;
-
- retval->bl_id = BlockId();
- retval->bl_prev = nullptr;
- retval->bl_next = nullptr;
- retval->bl_m = base->bl_m;
- retval->bl_x = base->bl_x;
- retval->bl_y = base->bl_y;
- retval->bl_type = base->bl_type;
-
- retval->bl_id = map_addobject(retval);
- set_invocation(&env->varu[VAR_INVOCATION], retval);
-
- return retval;
-}
-
-void spell_bind(dumb_ptr<map_session_data> subject, dumb_ptr<invocation> invocation)
-{
- /* Only bind nonlocal spells */
-
- if (!bool(invocation->spell->flags & SPELL_FLAG::LOCAL))
- {
- if (bool(invocation->flags & INVOCATION_FLAG::BOUND)
- || invocation->subject || invocation->next_invocation)
- {
- int *i = nullptr;
- FPRINTF(stderr,
- "[magic] INTERNAL ERROR: Attempt to re-bind spell invocation `%s'\n"_fmt,
- invocation->spell->name);
- *i = 1;
- return;
- }
-
- invocation->next_invocation = subject->active_spells;
- subject->active_spells = invocation;
- invocation->flags |= INVOCATION_FLAG::BOUND;
- invocation->subject = subject->bl_id;
- }
-
- spell_set_location(invocation, subject);
-}
-
-int spell_unbind(dumb_ptr<map_session_data> subject, dumb_ptr<invocation> invocation_)
-{
- dumb_ptr<invocation> *seeker = &subject->active_spells;
-
- while (*seeker)
- {
- if (*seeker == invocation_)
- {
- *seeker = invocation_->next_invocation;
-
- invocation_->flags &= ~INVOCATION_FLAG::BOUND;
- invocation_->next_invocation = nullptr;
- invocation_->subject = BlockId();
-
- return 0;
- }
- seeker = &((*seeker)->next_invocation);
- }
-
- return 1;
-}
-} // namespace magic
-} // namespace map
-} // namespace tmwa
diff --git a/src/map/magic-interpreter-base.hpp b/src/map/magic-interpreter-base.hpp
deleted file mode 100644
index 7c00db0..0000000
--- a/src/map/magic-interpreter-base.hpp
+++ /dev/null
@@ -1,84 +0,0 @@
-#pragma once
-// magic-interpreter-base.hpp - Core of the old magic system.
-//
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include "fwd.hpp"
-
-
-namespace tmwa
-{
-namespace map
-{
-namespace magic
-{
-/**
- * Adds a component selection to a component holder (which may initially be nullptr)
- */
-void magic_add_component(dumb_ptr<component_t> *component_holder, ItemNameId id, int count);
-
-/**
- * Identifies the invocation used to trigger a spell
- *
- * Returns empty string if not found
- */
-AString magic_find_invocation(XString spellname);
-
-/**
- * Identifies the invocation used to denote a teleport location
- *
- * Returns empty string if not found
- */
-AString magic_find_anchor_invocation(XString teleport_location);
-
-dumb_ptr<teleport_anchor_t> magic_find_anchor(XString name);
-
-dumb_ptr<env_t> spell_create_env(magic_conf_t *conf, dumb_ptr<spell_t> spell,
- dumb_ptr<map_session_data> caster, int spellpower, XString param);
-
-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)
- */
-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(const effect_set_t *effect, dumb_ptr<env_t> env);
-
-/**
- * Bind a spell to a subject (this is a no-op for `local' spells).
- */
-void spell_bind(dumb_ptr<map_session_data> subject, dumb_ptr<invocation> invocation);
-
-// 1 on failure
-int spell_unbind(dumb_ptr<map_session_data> subject, dumb_ptr<invocation> invocation);
-
-/**
- * Clones a spell to run the at_effect field
- */
-dumb_ptr<invocation> spell_clone_effect(dumb_ptr<invocation> source);
-
-dumb_ptr<spell_t> magic_find_spell(XString invocation);
-
-void spell_update_location(dumb_ptr<invocation> invocation);
-} // namespace magic
-} // namespace map
-} // namespace tmwa
diff --git a/src/map/magic-interpreter.hpp b/src/map/magic-interpreter.hpp
deleted file mode 100644
index cbd92a9..0000000
--- a/src/map/magic-interpreter.hpp
+++ /dev/null
@@ -1,630 +0,0 @@
-#pragma once
-// magic-interpreter.hpp - Old magic.
-//
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include "magic-interpreter.t.hpp"
-
-#include "fwd.hpp"
-
-#include <cassert>
-
-#include <memory>
-
-#include "../strings/rstring.hpp"
-
-#include "../sexpr/variant.hpp"
-
-#include "../net/timer.t.hpp"
-
-#include "../mmo/ids.hpp"
-
-#include "map.hpp"
-#include "script-buffer.hpp"
-#include "../mmo/skill.t.hpp"
-
-
-namespace tmwa
-{
-namespace map
-{
-namespace magic
-{
-struct location_t
-{
- Borrowed<map_local> m;
- int x, y;
-
- // This constructor exists solely to work around the design constraints
- // of sexpr::Variant<>. See comments in variant.tcc for future plans.
- __attribute__((deprecated))
- location_t() noexcept : m(borrow(undefined_gat)), x(), y() {}
- location_t(Borrowed<map_local> m_, int x_, int y_) : m(m_), x(x_), y(y_) {}
-};
-
-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
-{
- int size;
-
- 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) : AreaVariantBase(std::move(v)), size(1) {}
- area_t(AreaUnion v) : AreaVariantBase(std::move(v)), size(v.a_union[0]->size + v.a_union[1]->size) {}
- area_t(AreaRect v) : AreaVariantBase(std::move(v)), size(v.width * v.height) {}
- area_t(AreaBar v) : AreaVariantBase(std::move(v)), size((v.width * 2 + 1) * v.depth) {}
-};
-
-struct ValUndef
-{
-};
-struct ValInt
-{
- int v_int;
-};
-struct ValDir
-{
- DIR v_dir;
-};
-struct ValString
-{
- RString 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 */
-/* ----------- */
-
-#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;
-};
-
-using ExprAreaVariantBase = Variant<
- e_location_t,
- ExprAreaUnion,
- ExprAreaRect,
- ExprAreaBar
->;
-
-struct e_area_t : ExprAreaVariantBase
-{
- 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;
-
- 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) {}
-};
-
-/* ---------- */
-/* Components */
-/* ---------- */
-
-struct component_t
-{
- dumb_ptr<component_t> next;
- ItemNameId item_id;
- int count;
-};
-
-
-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;
-};
-
-using SpellGuardVariantBase = Variant<
- GuardCondition,
- GuardMana,
- GuardCastTime,
- GuardComponents,
- GuardCatalysts,
- GuardChoice,
- effect_set_t
->;
-struct spellguard_t : SpellGuardVariantBase
-{
- dumb_ptr<spellguard_t> next;
-
- 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) {}
-};
-
-/* ------ */
-/* Spells */
-/* ------ */
-
-struct letdef_t
-{
- int id;
- dumb_ptr<expr_t> expr;
-};
-
-struct spell_t
-{
- RString name;
- RString invocation;
- SPELL_FLAG flags;
- int arg;
- SPELLARG spellarg_ty;
-
- std::vector<letdef_t> letdefv;
-
- dumb_ptr<spellguard_t> spellguard;
-};
-
-/* ------- */
-/* Anchors */
-/* ------- */
-
-struct teleport_anchor_t
-{
- RString name;
- RString invocation;
- dumb_ptr<expr_t> location;
-};
-
-/* ------------------- */
-/* The big config blob */
-/* ------------------- */
-
-struct magic_conf_t
-{
- struct mcvar
- {
- RString name;
- val_t val;
- };
- // This should probably be done by a dedicated "intern pool" class
- std::vector<mcvar> varv;
-
- std::map<RString, dumb_ptr<spell_t>> spells_by_name, spells_by_invocation;
-
- std::map<RString, dumb_ptr<teleport_anchor_t>> anchors_by_name, anchors_by_invocation;
-};
-
-/* Execution environment */
-
-// these are not an enum they're a nasty intern hack
-#define VAR_MIN_CASTTIME 0
-#define VAR_OBSCURE_CHANCE 1
-#define VAR_CASTER 2
-#define VAR_SPELLPOWER 3
-#define VAR_SPELL 4
-#define VAR_INVOCATION 5
-#define VAR_TARGET 6
-#define VAR_SCRIPTTARGET 7
-#define VAR_LOCATION 8
-
-struct env_t
-{
- magic_conf_t *base_env;
- std::unique_ptr<val_t[]> varu;
-
- val_t& VAR(size_t i)
- {
- assert (varu);
- if (varu[i].is<ValUndef>())
- return base_env->varv[i].val;
- else
- return varu[i];
- }
-
-};
-
-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 : CarVariantBase
-{
- dumb_ptr<effect_t> return_location;
-
- 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
-{
- StatusChange sc_type;
- BlockId bl_id;
-};
-
-struct invocation : block_list
-{
- dumb_ptr<invocation> next_invocation; /* used for spells directly associated with a caster: they form a singly-linked list */
- INVOCATION_FLAG flags;
-
- dumb_ptr<env_t> env;
- dumb_ptr<spell_t> spell;
- BlockId caster; /* this is the person who originally invoked the spell */
- BlockId subject; /* when this person dies, the spell dies with it */
-
- Timer timer; /* spell timer, if any */
-
- 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;
- dumb_ptr<effect_t> trigger_effect; /* If non-nullptr, this is used to spawn a cloned effect based on the same environment */
- dumb_ptr<effect_t> end_effect; /* If non-nullptr, this is executed when the spell terminates naturally, e.g. when all status changes have run out or all delays are over. */
-
- /* Status change references: for status change updates, keep track of whom we updated where */
- std::vector<status_change_ref_t> status_change_refv;
-
-};
-} // namespace magic
-
-// inlines for map.hpp
-inline dumb_ptr<magic::invocation> block_list::as_spell() { return dumb_ptr<magic::invocation>(static_cast<magic::invocation *>(this)); }
-inline dumb_ptr<magic::invocation> block_list::is_spell() { return bl_type == BL::SPELL ? as_spell() : nullptr; }
-
-namespace magic
-{
-/* The following is used only by the parser: */
-struct args_rec_t
-{
- dumb_ptr<std::vector<dumb_ptr<expr_t>>> argvp;
-};
-
-struct proc_t
-{
- RString name;
- std::vector<int> argv;
- dumb_ptr<effect_t> body;
-
- proc_t()
- : name()
- , argv()
- , body()
- {}
-};
-} // namespace magic
-} // namespace map
-} // namespace tmwa
diff --git a/src/map/magic-interpreter.py b/src/map/magic-interpreter.py
deleted file mode 100644
index 520ab37..0000000
--- a/src/map/magic-interpreter.py
+++ /dev/null
@@ -1,215 +0,0 @@
-class AreaUnion(object):
- __slots__ = ('_value')
- name = 'tmwa::map::magic::AreaUnion'
- enabled = True
-
- def __init__(self, value):
- self._value = value
-
- def display_hint(self):
- return 'array'
-
- def to_string(self):
- return None
-
- def children(self):
- v = self._value
- for i in [0, 1]:
- yield '[%d]', v['a_union'][i]['impl'].dereference()
-
- tests = []
-
-class area_t(object):
- enabled = True
-
- test_extra = '''
- #include "../strings/fwd.hpp"
- using tmwa::operator "" _s;
-
- inline
- tmwa::Borrowed<tmwa::map::map_local> fake_map_local_x_dup_for_area_t(tmwa::ZString name)
- {
- auto *p = new tmwa::map::map_local{};
- p->name_ = tmwa::stringish<tmwa::MapName>(name);
- return tmwa::borrow(*p);
- }
- '''
-
- tests = [
- ('tmwa::map::magic::area_t(tmwa::map::magic::location_t{fake_map_local_x_dup_for_area_t("map"_s), 123, 456})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::location_t, tmwa::map::magic::AreaUnion, tmwa::map::magic::AreaRect, tmwa::map::magic::AreaBar>> = {(tmwa::map::magic::location_t) = {m = (map_local *) = {->name = "map", ->xs = 0, ->ys = 0}, x = 123, y = 456}}, size = 1}'),
- ('tmwa::map::magic::area_t(tmwa::map::magic::AreaUnion{{tmwa::dumb_ptr<tmwa::map::magic::area_t>::make(tmwa::map::magic::location_t{fake_map_local_x_dup_for_area_t("map"_s), 123, 456}), tmwa::dumb_ptr<tmwa::map::magic::area_t>::make(tmwa::map::magic::location_t{fake_map_local_x_dup_for_area_t("map"_s), 321, 654})}})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::location_t, tmwa::map::magic::AreaUnion, tmwa::map::magic::AreaRect, tmwa::map::magic::AreaBar>> = {(tmwa::map::magic::AreaUnion) = {{<tmwa::sexpr::Variant<tmwa::map::magic::location_t, tmwa::map::magic::AreaUnion, tmwa::map::magic::AreaRect, tmwa::map::magic::AreaBar>> = {(tmwa::map::magic::location_t) = {m = (map_local *) = {->name = "map", ->xs = 0, ->ys = 0}, x = 123, y = 456}}, size = 1}, {<tmwa::sexpr::Variant<tmwa::map::magic::location_t, tmwa::map::magic::AreaUnion, tmwa::map::magic::AreaRect, tmwa::map::magic::AreaBar>> = {(tmwa::map::magic::location_t) = {m = (map_local *) = {->name = "map", ->xs = 0, ->ys = 0}, x = 321, y = 654}}, size = 1}}}, size = 2}'),
- ('tmwa::map::magic::area_t(tmwa::map::magic::AreaRect{tmwa::map::magic::location_t{fake_map_local_x_dup_for_area_t("map"_s), 123, 456}, 789, 102})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::location_t, tmwa::map::magic::AreaUnion, tmwa::map::magic::AreaRect, tmwa::map::magic::AreaBar>> = {(tmwa::map::magic::AreaRect) = {loc = {m = (map_local *) = {->name = "map", ->xs = 0, ->ys = 0}, x = 123, y = 456}, width = 789, height = 102}}, size = 80478}'),
- ('tmwa::map::magic::area_t(tmwa::map::magic::AreaBar{tmwa::map::magic::location_t{fake_map_local_x_dup_for_area_t("map"_s), 42, 43}, 123, 456, tmwa::DIR::NW})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::location_t, tmwa::map::magic::AreaUnion, tmwa::map::magic::AreaRect, tmwa::map::magic::AreaBar>> = {(tmwa::map::magic::AreaBar) = {loc = {m = (map_local *) = {->name = "map", ->xs = 0, ->ys = 0}, x = 42, y = 43}, width = 123, depth = 456, dir = tmwa::DIR::NW}}, size = 112632}'),
- ]
-
-
-class val_t(object):
- enabled = True
-
- test_extra = '''
- #include "../strings/fwd.hpp"
- using tmwa::operator "" _s;
-
- inline
- tmwa::Borrowed<tmwa::map::map_local> fake_map_local_x_dup_for_val_t(tmwa::ZString name)
- {
- auto *p = new tmwa::map::map_local{};
- p->name_ = tmwa::stringish<tmwa::MapName>(name);
- return tmwa::borrow(*p);
- }
- '''
-
- tests = [
- ('tmwa::map::magic::val_t(tmwa::map::magic::ValUndef{})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValUndef) = {<No data fields>}}, <No data fields>}'),
- ('tmwa::map::magic::val_t(tmwa::map::magic::ValInt{42})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValInt) = {v_int = 42}}, <No data fields>}'),
- ('tmwa::map::magic::val_t(tmwa::map::magic::ValDir{tmwa::DIR::NW})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValDir) = {v_dir = tmwa::DIR::NW}}, <No data fields>}'),
- ('tmwa::map::magic::val_t(tmwa::map::magic::ValString{"Hello"_s})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValString) = {v_string = "Hello"}}, <No data fields>}'),
- ('tmwa::map::magic::val_t(tmwa::map::magic::ValEntityInt{tmwa::wrap<tmwa::BlockId>(123)})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValEntityInt) = {v_eid = 123}}, <No data fields>}'),
- ('tmwa::map::magic::val_t(tmwa::map::magic::ValEntityPtr{tmwa::dumb_ptr<tmwa::map::block_list>()})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValEntityPtr) = {v_entity = 0x0}}, <No data fields>}'),
- ('tmwa::map::magic::val_t(tmwa::map::magic::ValLocation{tmwa::map::magic::location_t{fake_map_local_x_dup_for_val_t("map"_s), 42, 123}})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValLocation) = {v_location = {m = (map_local *) = {->name = "map", ->xs = 0, ->ys = 0}, x = 42, y = 123}}}, <No data fields>}'),
- ('tmwa::map::magic::val_t(tmwa::map::magic::ValArea{tmwa::dumb_ptr<tmwa::map::magic::area_t>()})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValArea) = {v_area = 0x0}}, <No data fields>}'),
- ('tmwa::map::magic::val_t(tmwa::map::magic::ValSpell{tmwa::dumb_ptr<tmwa::map::magic::spell_t>()})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValSpell) = {v_spell = 0x0}}, <No data fields>}'),
- ('tmwa::map::magic::val_t(tmwa::map::magic::ValInvocationInt{tmwa::wrap<tmwa::BlockId>(123)})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValInvocationInt) = {v_iid = 123}}, <No data fields>}'),
- ('tmwa::map::magic::val_t(tmwa::map::magic::ValInvocationPtr{})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValInvocationPtr) = {v_invocation = 0x0}}, <No data fields>}'),
- ('tmwa::map::magic::val_t(tmwa::map::magic::ValFail{})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValFail) = {<No data fields>}}, <No data fields>}'),
- ('tmwa::map::magic::val_t(tmwa::map::magic::ValNegative1{})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValNegative1) = {<No data fields>}}, <No data fields>}'),
- ]
-
-
-class ExprAreaUnion(object):
- __slots__ = ('_value')
- name = 'tmwa::map::magic::ExprAreaUnion'
- enabled = True
-
- def __init__(self, value):
- self._value = value
-
- def display_hint(self):
- return 'array'
-
- def to_string(self):
- return None
-
- def children(self):
- v = self._value
- for i in [0, 1]:
- yield '[%d]', v['a_union'][i]['impl'].dereference()
-
- tests = []
-
-
-class e_area_t(object):
- enabled = True
-
- tests = [
- ('tmwa::map::magic::e_area_t(tmwa::map::magic::e_location_t())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::e_location_t, tmwa::map::magic::ExprAreaUnion, tmwa::map::magic::ExprAreaRect, tmwa::map::magic::ExprAreaBar>> = {(tmwa::map::magic::e_location_t) = {m = 0x0, x = 0x0, y = 0x0}}, <No data fields>}'),
- ('tmwa::map::magic::e_area_t(tmwa::map::magic::ExprAreaUnion{{tmwa::dumb_ptr<tmwa::map::magic::e_area_t>::make(tmwa::map::magic::e_location_t()), tmwa::dumb_ptr<tmwa::map::magic::e_area_t>::make(tmwa::map::magic::e_location_t())}})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::e_location_t, tmwa::map::magic::ExprAreaUnion, tmwa::map::magic::ExprAreaRect, tmwa::map::magic::ExprAreaBar>> = {(tmwa::map::magic::ExprAreaUnion) = {{<tmwa::sexpr::Variant<tmwa::map::magic::e_location_t, tmwa::map::magic::ExprAreaUnion, tmwa::map::magic::ExprAreaRect, tmwa::map::magic::ExprAreaBar>> = {(tmwa::map::magic::e_location_t) = {m = 0x0, x = 0x0, y = 0x0}}, <No data fields>}, {<tmwa::sexpr::Variant<tmwa::map::magic::e_location_t, tmwa::map::magic::ExprAreaUnion, tmwa::map::magic::ExprAreaRect, tmwa::map::magic::ExprAreaBar>> = {(tmwa::map::magic::e_location_t) = {m = 0x0, x = 0x0, y = 0x0}}, <No data fields>}}}, <No data fields>}'),
- ('tmwa::map::magic::e_area_t(tmwa::map::magic::ExprAreaRect{tmwa::map::magic::e_location_t(), tmwa::dumb_ptr<tmwa::map::magic::expr_t>(), tmwa::dumb_ptr<tmwa::map::magic::expr_t>()})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::e_location_t, tmwa::map::magic::ExprAreaUnion, tmwa::map::magic::ExprAreaRect, tmwa::map::magic::ExprAreaBar>> = {(tmwa::map::magic::ExprAreaRect) = {loc = {m = 0x0, x = 0x0, y = 0x0}, width = 0x0, height = 0x0}}, <No data fields>}'),
- ('tmwa::map::magic::e_area_t(tmwa::map::magic::ExprAreaBar{tmwa::map::magic::e_location_t(), tmwa::dumb_ptr<tmwa::map::magic::expr_t>(), tmwa::dumb_ptr<tmwa::map::magic::expr_t>(), tmwa::dumb_ptr<tmwa::map::magic::expr_t>()})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::e_location_t, tmwa::map::magic::ExprAreaUnion, tmwa::map::magic::ExprAreaRect, tmwa::map::magic::ExprAreaBar>> = {(tmwa::map::magic::ExprAreaBar) = {loc = {m = 0x0, x = 0x0, y = 0x0}, width = 0x0, depth = 0x0, dir = 0x0}}, <No data fields>}'),
- ]
-
-
-
-class expr_t(object):
- enabled = True
-
- tests = [
- ('tmwa::map::magic::expr_t(tmwa::map::magic::val_t(tmwa::map::magic::ValUndef()))',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::val_t, tmwa::map::magic::e_location_t, tmwa::map::magic::e_area_t, tmwa::map::magic::ExprFunApp, tmwa::map::magic::ExprId, tmwa::map::magic::ExprField>> = {(tmwa::map::magic::val_t) = {<tmwa::sexpr::Variant<tmwa::map::magic::ValUndef, tmwa::map::magic::ValInt, tmwa::map::magic::ValDir, tmwa::map::magic::ValString, tmwa::map::magic::ValEntityInt, tmwa::map::magic::ValEntityPtr, tmwa::map::magic::ValLocation, tmwa::map::magic::ValArea, tmwa::map::magic::ValSpell, tmwa::map::magic::ValInvocationInt, tmwa::map::magic::ValInvocationPtr, tmwa::map::magic::ValFail, tmwa::map::magic::ValNegative1>> = {(tmwa::map::magic::ValUndef) = {<No data fields>}}, <No data fields>}}, <No data fields>}'),
- ('tmwa::map::magic::expr_t(tmwa::map::magic::e_location_t())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::val_t, tmwa::map::magic::e_location_t, tmwa::map::magic::e_area_t, tmwa::map::magic::ExprFunApp, tmwa::map::magic::ExprId, tmwa::map::magic::ExprField>> = {(tmwa::map::magic::e_location_t) = {m = 0x0, x = 0x0, y = 0x0}}, <No data fields>}'),
- ('tmwa::map::magic::expr_t(tmwa::map::magic::e_area_t(tmwa::map::magic::e_location_t()))',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::val_t, tmwa::map::magic::e_location_t, tmwa::map::magic::e_area_t, tmwa::map::magic::ExprFunApp, tmwa::map::magic::ExprId, tmwa::map::magic::ExprField>> = {(tmwa::map::magic::e_area_t) = {<tmwa::sexpr::Variant<tmwa::map::magic::e_location_t, tmwa::map::magic::ExprAreaUnion, tmwa::map::magic::ExprAreaRect, tmwa::map::magic::ExprAreaBar>> = {(tmwa::map::magic::e_location_t) = {m = 0x0, x = 0x0, y = 0x0}}, <No data fields>}}, <No data fields>}'),
- ('tmwa::map::magic::expr_t(tmwa::map::magic::ExprFunApp())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::val_t, tmwa::map::magic::e_location_t, tmwa::map::magic::e_area_t, tmwa::map::magic::ExprFunApp, tmwa::map::magic::ExprId, tmwa::map::magic::ExprField>> = {(tmwa::map::magic::ExprFunApp) = {funp = (fun_t *) nullptr, line_nr = 0, column = 0, args_nr = 0, args = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}}, <No data fields>}'),
- ('tmwa::map::magic::expr_t(tmwa::map::magic::ExprId{123})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::val_t, tmwa::map::magic::e_location_t, tmwa::map::magic::e_area_t, tmwa::map::magic::ExprFunApp, tmwa::map::magic::ExprId, tmwa::map::magic::ExprField>> = {(tmwa::map::magic::ExprId) = {e_id = 123}}, <No data fields>}'),
- ('tmwa::map::magic::expr_t(tmwa::map::magic::ExprField{tmwa::dumb_ptr<tmwa::map::magic::expr_t>(), 42})',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::val_t, tmwa::map::magic::e_location_t, tmwa::map::magic::e_area_t, tmwa::map::magic::ExprFunApp, tmwa::map::magic::ExprId, tmwa::map::magic::ExprField>> = {(tmwa::map::magic::ExprField) = {expr = 0x0, id = 42}}, <No data fields>}'),
- ]
-
-
-class effect_t(object):
- enabled = True
-
- tests = [
- ('tmwa::map::magic::effect_t(tmwa::map::magic::EffectSkip{}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::EffectSkip, tmwa::map::magic::EffectAbort, tmwa::map::magic::EffectAssign, tmwa::map::magic::EffectForEach, tmwa::map::magic::EffectFor, tmwa::map::magic::EffectIf, tmwa::map::magic::EffectSleep, tmwa::map::magic::EffectScript, tmwa::map::magic::EffectBreak, tmwa::map::magic::EffectOp, tmwa::map::magic::EffectEnd, tmwa::map::magic::EffectCall>> = {(tmwa::map::magic::EffectSkip) = {<No data fields>}}, next = 0x0}'),
- ('tmwa::map::magic::effect_t(tmwa::map::magic::EffectAbort{}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::EffectSkip, tmwa::map::magic::EffectAbort, tmwa::map::magic::EffectAssign, tmwa::map::magic::EffectForEach, tmwa::map::magic::EffectFor, tmwa::map::magic::EffectIf, tmwa::map::magic::EffectSleep, tmwa::map::magic::EffectScript, tmwa::map::magic::EffectBreak, tmwa::map::magic::EffectOp, tmwa::map::magic::EffectEnd, tmwa::map::magic::EffectCall>> = {(tmwa::map::magic::EffectAbort) = {<No data fields>}}, next = 0x0}'),
- ('tmwa::map::magic::effect_t(tmwa::map::magic::EffectAssign{42, tmwa::dumb_ptr<tmwa::map::magic::expr_t>()}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::EffectSkip, tmwa::map::magic::EffectAbort, tmwa::map::magic::EffectAssign, tmwa::map::magic::EffectForEach, tmwa::map::magic::EffectFor, tmwa::map::magic::EffectIf, tmwa::map::magic::EffectSleep, tmwa::map::magic::EffectScript, tmwa::map::magic::EffectBreak, tmwa::map::magic::EffectOp, tmwa::map::magic::EffectEnd, tmwa::map::magic::EffectCall>> = {(tmwa::map::magic::EffectAssign) = {id = 42, expr = 0x0}}, next = 0x0}'),
- ('tmwa::map::magic::effect_t(tmwa::map::magic::EffectForEach{123, tmwa::dumb_ptr<tmwa::map::magic::expr_t>(), tmwa::dumb_ptr<tmwa::map::magic::effect_t>(), tmwa::map::magic::FOREACH_FILTER::PC}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::EffectSkip, tmwa::map::magic::EffectAbort, tmwa::map::magic::EffectAssign, tmwa::map::magic::EffectForEach, tmwa::map::magic::EffectFor, tmwa::map::magic::EffectIf, tmwa::map::magic::EffectSleep, tmwa::map::magic::EffectScript, tmwa::map::magic::EffectBreak, tmwa::map::magic::EffectOp, tmwa::map::magic::EffectEnd, tmwa::map::magic::EffectCall>> = {(tmwa::map::magic::EffectForEach) = {id = 123, area = 0x0, body = 0x0, filter = tmwa::map::magic::FOREACH_FILTER::PC}}, next = 0x0}'),
- ('tmwa::map::magic::effect_t(tmwa::map::magic::EffectFor{42, tmwa::dumb_ptr<tmwa::map::magic::expr_t>(), tmwa::dumb_ptr<tmwa::map::magic::expr_t>(), tmwa::dumb_ptr<tmwa::map::magic::effect_t>()}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::EffectSkip, tmwa::map::magic::EffectAbort, tmwa::map::magic::EffectAssign, tmwa::map::magic::EffectForEach, tmwa::map::magic::EffectFor, tmwa::map::magic::EffectIf, tmwa::map::magic::EffectSleep, tmwa::map::magic::EffectScript, tmwa::map::magic::EffectBreak, tmwa::map::magic::EffectOp, tmwa::map::magic::EffectEnd, tmwa::map::magic::EffectCall>> = {(tmwa::map::magic::EffectFor) = {id = 42, start = 0x0, stop = 0x0, body = 0x0}}, next = 0x0}'),
- ('tmwa::map::magic::effect_t(tmwa::map::magic::EffectIf{tmwa::dumb_ptr<tmwa::map::magic::expr_t>(), tmwa::dumb_ptr<tmwa::map::magic::effect_t>(), tmwa::dumb_ptr<tmwa::map::magic::effect_t>()}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::EffectSkip, tmwa::map::magic::EffectAbort, tmwa::map::magic::EffectAssign, tmwa::map::magic::EffectForEach, tmwa::map::magic::EffectFor, tmwa::map::magic::EffectIf, tmwa::map::magic::EffectSleep, tmwa::map::magic::EffectScript, tmwa::map::magic::EffectBreak, tmwa::map::magic::EffectOp, tmwa::map::magic::EffectEnd, tmwa::map::magic::EffectCall>> = {(tmwa::map::magic::EffectIf) = {cond = 0x0, true_branch = 0x0, false_branch = 0x0}}, next = 0x0}'),
- ('tmwa::map::magic::effect_t(tmwa::map::magic::EffectSleep{tmwa::dumb_ptr<tmwa::map::magic::expr_t>()}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::EffectSkip, tmwa::map::magic::EffectAbort, tmwa::map::magic::EffectAssign, tmwa::map::magic::EffectForEach, tmwa::map::magic::EffectFor, tmwa::map::magic::EffectIf, tmwa::map::magic::EffectSleep, tmwa::map::magic::EffectScript, tmwa::map::magic::EffectBreak, tmwa::map::magic::EffectOp, tmwa::map::magic::EffectEnd, tmwa::map::magic::EffectCall>> = {(tmwa::map::magic::EffectSleep) = {e_sleep = 0x0}}, next = 0x0}'),
- ('tmwa::map::magic::effect_t(tmwa::map::magic::EffectScript{tmwa::dumb_ptr<const tmwa::map::ScriptBuffer>()}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::EffectSkip, tmwa::map::magic::EffectAbort, tmwa::map::magic::EffectAssign, tmwa::map::magic::EffectForEach, tmwa::map::magic::EffectFor, tmwa::map::magic::EffectIf, tmwa::map::magic::EffectSleep, tmwa::map::magic::EffectScript, tmwa::map::magic::EffectBreak, tmwa::map::magic::EffectOp, tmwa::map::magic::EffectEnd, tmwa::map::magic::EffectCall>> = {(tmwa::map::magic::EffectScript) = {e_script = 0x0}}, next = 0x0}'),
- ('tmwa::map::magic::effect_t(tmwa::map::magic::EffectBreak{}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::EffectSkip, tmwa::map::magic::EffectAbort, tmwa::map::magic::EffectAssign, tmwa::map::magic::EffectForEach, tmwa::map::magic::EffectFor, tmwa::map::magic::EffectIf, tmwa::map::magic::EffectSleep, tmwa::map::magic::EffectScript, tmwa::map::magic::EffectBreak, tmwa::map::magic::EffectOp, tmwa::map::magic::EffectEnd, tmwa::map::magic::EffectCall>> = {(tmwa::map::magic::EffectBreak) = {<No data fields>}}, next = 0x0}'),
- ('tmwa::map::magic::effect_t(tmwa::map::magic::EffectOp(), tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::EffectSkip, tmwa::map::magic::EffectAbort, tmwa::map::magic::EffectAssign, tmwa::map::magic::EffectForEach, tmwa::map::magic::EffectFor, tmwa::map::magic::EffectIf, tmwa::map::magic::EffectSleep, tmwa::map::magic::EffectScript, tmwa::map::magic::EffectBreak, tmwa::map::magic::EffectOp, tmwa::map::magic::EffectEnd, tmwa::map::magic::EffectCall>> = {(tmwa::map::magic::EffectOp) = {opp = (op_t *) nullptr, args_nr = 0, line_nr = 0, column = 0, args = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}}, next = 0x0}'),
- ('tmwa::map::magic::effect_t(tmwa::map::magic::EffectEnd{}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::EffectSkip, tmwa::map::magic::EffectAbort, tmwa::map::magic::EffectAssign, tmwa::map::magic::EffectForEach, tmwa::map::magic::EffectFor, tmwa::map::magic::EffectIf, tmwa::map::magic::EffectSleep, tmwa::map::magic::EffectScript, tmwa::map::magic::EffectBreak, tmwa::map::magic::EffectOp, tmwa::map::magic::EffectEnd, tmwa::map::magic::EffectCall>> = {(tmwa::map::magic::EffectEnd) = {<No data fields>}}, next = 0x0}'),
- ('tmwa::map::magic::effect_t(tmwa::map::magic::EffectCall{nullptr, tmwa::dumb_ptr<std::vector<tmwa::dumb_ptr<tmwa::map::magic::expr_t>>>(), tmwa::dumb_ptr<tmwa::map::magic::effect_t>()}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::EffectSkip, tmwa::map::magic::EffectAbort, tmwa::map::magic::EffectAssign, tmwa::map::magic::EffectForEach, tmwa::map::magic::EffectFor, tmwa::map::magic::EffectIf, tmwa::map::magic::EffectSleep, tmwa::map::magic::EffectScript, tmwa::map::magic::EffectBreak, tmwa::map::magic::EffectOp, tmwa::map::magic::EffectEnd, tmwa::map::magic::EffectCall>> = {(tmwa::map::magic::EffectCall) = {formalv = nullptr, actualvp = 0x0, body = 0x0}}, next = 0x0}'),
- ]
-
-
-class spellguard_t(object):
- enabled = True
-
- tests = [
- ('tmwa::map::magic::spellguard_t(tmwa::map::magic::GuardCondition{tmwa::dumb_ptr<tmwa::map::magic::expr_t>()}, tmwa::dumb_ptr<tmwa::map::magic::spellguard_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::GuardCondition, tmwa::map::magic::GuardMana, tmwa::map::magic::GuardCastTime, tmwa::map::magic::GuardComponents, tmwa::map::magic::GuardCatalysts, tmwa::map::magic::GuardChoice, tmwa::map::magic::effect_set_t>> = {(tmwa::map::magic::GuardCondition) = {s_condition = 0x0}}, next = 0x0}'),
- ('tmwa::map::magic::spellguard_t(tmwa::map::magic::GuardMana{tmwa::dumb_ptr<tmwa::map::magic::expr_t>()}, tmwa::dumb_ptr<tmwa::map::magic::spellguard_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::GuardCondition, tmwa::map::magic::GuardMana, tmwa::map::magic::GuardCastTime, tmwa::map::magic::GuardComponents, tmwa::map::magic::GuardCatalysts, tmwa::map::magic::GuardChoice, tmwa::map::magic::effect_set_t>> = {(tmwa::map::magic::GuardMana) = {s_mana = 0x0}}, next = 0x0}'),
- ('tmwa::map::magic::spellguard_t(tmwa::map::magic::GuardCastTime{tmwa::dumb_ptr<tmwa::map::magic::expr_t>()}, tmwa::dumb_ptr<tmwa::map::magic::spellguard_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::GuardCondition, tmwa::map::magic::GuardMana, tmwa::map::magic::GuardCastTime, tmwa::map::magic::GuardComponents, tmwa::map::magic::GuardCatalysts, tmwa::map::magic::GuardChoice, tmwa::map::magic::effect_set_t>> = {(tmwa::map::magic::GuardCastTime) = {s_casttime = 0x0}}, next = 0x0}'),
- ('tmwa::map::magic::spellguard_t(tmwa::map::magic::GuardComponents{tmwa::dumb_ptr<tmwa::map::magic::component_t>()}, tmwa::dumb_ptr<tmwa::map::magic::spellguard_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::GuardCondition, tmwa::map::magic::GuardMana, tmwa::map::magic::GuardCastTime, tmwa::map::magic::GuardComponents, tmwa::map::magic::GuardCatalysts, tmwa::map::magic::GuardChoice, tmwa::map::magic::effect_set_t>> = {(tmwa::map::magic::GuardComponents) = {s_components = 0x0}}, next = 0x0}'),
- ('tmwa::map::magic::spellguard_t(tmwa::map::magic::GuardCatalysts{tmwa::dumb_ptr<tmwa::map::magic::component_t>()}, tmwa::dumb_ptr<tmwa::map::magic::spellguard_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::GuardCondition, tmwa::map::magic::GuardMana, tmwa::map::magic::GuardCastTime, tmwa::map::magic::GuardComponents, tmwa::map::magic::GuardCatalysts, tmwa::map::magic::GuardChoice, tmwa::map::magic::effect_set_t>> = {(tmwa::map::magic::GuardCatalysts) = {s_catalysts = 0x0}}, next = 0x0}'),
- ('tmwa::map::magic::spellguard_t(tmwa::map::magic::GuardChoice{tmwa::dumb_ptr<tmwa::map::magic::spellguard_t>()}, tmwa::dumb_ptr<tmwa::map::magic::spellguard_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::GuardCondition, tmwa::map::magic::GuardMana, tmwa::map::magic::GuardCastTime, tmwa::map::magic::GuardComponents, tmwa::map::magic::GuardCatalysts, tmwa::map::magic::GuardChoice, tmwa::map::magic::effect_set_t>> = {(tmwa::map::magic::GuardChoice) = {s_alt = 0x0}}, next = 0x0}'),
- ('tmwa::map::magic::spellguard_t(tmwa::map::magic::effect_set_t{tmwa::dumb_ptr<tmwa::map::magic::effect_t>(), tmwa::dumb_ptr<tmwa::map::magic::effect_t>(), tmwa::dumb_ptr<tmwa::map::magic::effect_t>()}, tmwa::dumb_ptr<tmwa::map::magic::spellguard_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::GuardCondition, tmwa::map::magic::GuardMana, tmwa::map::magic::GuardCastTime, tmwa::map::magic::GuardComponents, tmwa::map::magic::GuardCatalysts, tmwa::map::magic::GuardChoice, tmwa::map::magic::effect_set_t>> = {(tmwa::map::magic::effect_set_t) = {effect = 0x0, at_trigger = 0x0, at_end = 0x0}}, next = 0x0}'),
- ]
-
-
-class cont_activation_record_t(object):
- enabled = True
-
- tests = [
- ('tmwa::map::magic::cont_activation_record_t(tmwa::map::magic::CarForEach{42, true, tmwa::dumb_ptr<tmwa::map::magic::effect_t>(), tmwa::dumb_ptr<std::vector<tmwa::BlockId>>(), 123}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::CarForEach, tmwa::map::magic::CarFor, tmwa::map::magic::CarProc>> = {(tmwa::map::magic::CarForEach) = {id = 42, ty_is_spell_not_entity = true, body = 0x0, entities_vp = 0x0, index = 123}}, return_location = 0x0}'),
- ('tmwa::map::magic::cont_activation_record_t(tmwa::map::magic::CarFor{42, tmwa::dumb_ptr<tmwa::map::magic::effect_t>(), 123, 456}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::CarForEach, tmwa::map::magic::CarFor, tmwa::map::magic::CarProc>> = {(tmwa::map::magic::CarFor) = {id = 42, body = 0x0, current = 123, stop = 456}}, return_location = 0x0}'),
- ('tmwa::map::magic::cont_activation_record_t(tmwa::map::magic::CarProc{123, nullptr, tmwa::dumb_ptr<tmwa::map::magic::val_t[]>()}, tmwa::dumb_ptr<tmwa::map::magic::effect_t>())',
- '{<tmwa::sexpr::Variant<tmwa::map::magic::CarForEach, tmwa::map::magic::CarFor, tmwa::map::magic::CarProc>> = {(tmwa::map::magic::CarProc) = {args_nr = 123, formalap = nullptr, old_actualpa = 0x0 = {sz = 0}}}, return_location = 0x0}'),
- ]
diff --git a/src/map/magic-interpreter.t.hpp b/src/map/magic-interpreter.t.hpp
deleted file mode 100644
index e302354..0000000
--- a/src/map/magic-interpreter.t.hpp
+++ /dev/null
@@ -1,85 +0,0 @@
-#pragma once
-// magic-interpreter.t.hpp - Old magic.
-//
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include "fwd.hpp"
-
-#include "../generic/enum.hpp"
-
-
-namespace tmwa
-{
-namespace map
-{
-namespace magic
-{
-enum class SPELLARG : uint8_t
-{
- NONE,
- PC,
- STRING,
-};
-
-enum class FOREACH_FILTER : uint8_t
-{
- MOB,
- PC,
- ENTITY,
- TARGET,
- SPELL,
- NPC,
-};
-
-namespace e
-{
-enum class SPELL_FLAG : uint8_t
-{
- ZERO = 0,
-
- // spell associated not with caster but with place
- LOCAL = 1 << 0,
- // spell invocation never uttered
- SILENT = 1 << 1,
- // `magic word' only: don't require spellcasting ability
- NONMAGIC = 1 << 2,
-};
-ENUM_BITWISE_OPERATORS(SPELL_FLAG)
-}
-using e::SPELL_FLAG;
-
-namespace e
-{
-enum class INVOCATION_FLAG : uint8_t
-{
- ZERO = 0,
-
- // Bound directly to the caster (i.e., ignore its location)
- BOUND = 1 << 0,
- // Used `abort' to terminate
- ABORTED = 1 << 1,
- // On magical attacks: if we run out of steam, stop attacking altogether
- STOPATTACK = 1 << 2,
-};
-ENUM_BITWISE_OPERATORS(INVOCATION_FLAG)
-}
-using e::INVOCATION_FLAG;
-} // namespace magic
-} // namespace map
-} // namespace tmwa
diff --git a/src/map/magic-stmt.cpp b/src/map/magic-stmt.cpp
deleted file mode 100644
index 1a8085b..0000000
--- a/src/map/magic-stmt.cpp
+++ /dev/null
@@ -1,1547 +0,0 @@
-#include "magic-stmt.hpp"
-// magic-stmt.cpp - Imperative commands for the magic backend.
-//
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include <cassert>
-
-#include "../compat/attr.hpp"
-#include "../compat/fun.hpp"
-
-#include "../strings/zstring.hpp"
-
-#include "../generic/random2.hpp"
-
-#include "../io/cxxstdio.hpp"
-
-#include "../mmo/cxxstdio_enums.hpp"
-
-#include "../net/timer.hpp"
-
-#include "battle.hpp"
-#include "clif.hpp"
-#include "magic.hpp"
-#include "magic-expr.hpp"
-#include "magic-expr-eval.hpp"
-#include "magic-interpreter.hpp"
-#include "magic-interpreter-base.hpp"
-#include "mob.hpp"
-#include "npc.hpp"
-#include "npc-parse.hpp"
-#include "pc.hpp"
-#include "script-call.hpp"
-#include "skill.hpp"
-
-#include "../poison.hpp"
-
-
-namespace tmwa
-{
-namespace map
-{
-namespace magic
-{
-/* used for local spell effects */
-constexpr Species INVISIBLE_NPC = wrap<Species>(127);
-
-static
-void clear_activation_record(cont_activation_record_t *ar)
-{
- MATCH_BEGIN (*ar)
- {
- MATCH_CASE (CarForEach&, c_foreach)
- {
- c_foreach.entities_vp.delete_();
- }
- MATCH_CASE (CarProc&, c_proc)
- {
- c_proc.old_actualpa.delete_();
- }
- }
- MATCH_END ();
-}
-
-static
-void invocation_timer_callback(TimerData *, tick_t, BlockId id)
-{
- dumb_ptr<invocation> invocation = map_id_is_spell(id);
-
- assert (invocation);
- {
- spell_execute(invocation);
- }
-}
-
-static
-void clear_stack(dumb_ptr<invocation> invocation_)
-{
- int i;
-
- for (i = 0; i < invocation_->stack.size(); i++)
- clear_activation_record(&invocation_->stack[i]);
-
- invocation_->stack.clear();
-}
-
-void spell_free_invocation(dumb_ptr<invocation> invocation_)
-{
- invocation_->status_change_refv.clear();
-
- if (bool(invocation_->flags & INVOCATION_FLAG::BOUND))
- {
- dumb_ptr<map_session_data> e = map_id_is_player(invocation_->subject);
- if (e)
- spell_unbind(e, invocation_);
- }
-
- clear_stack(invocation_);
-
- invocation_->timer.cancel();
-
- magic_free_env(invocation_->env);
-
- map_delblock(invocation_);
- map_delobject(invocation_->bl_id, BL::SPELL); // also frees the object
-// free(invocation_);
-}
-
-static
-void char_set_weapon_icon(dumb_ptr<map_session_data> subject, int count,
- StatusChange icon, ItemNameId look)
-{
- const StatusChange old_icon = subject->attack_spell_icon_override;
-
- subject->attack_spell_icon_override = icon;
- subject->attack_spell_look_override = look;
-
- if (old_icon != StatusChange::ZERO && old_icon != icon)
- clif_status_change(subject, old_icon, 0);
-
- clif_fixpcpos(subject);
- if (count)
- {
- clif_changelook(subject, LOOK::WEAPON, unwrap<ItemNameId>(look));
- if (icon != StatusChange::ZERO)
- clif_status_change(subject, icon, 1);
- }
- else
- {
- /* Set it to `normal' */
- clif_changelook(subject, LOOK::WEAPON,
- static_cast<uint16_t>(subject->status.weapon));
- }
-}
-
-static
-void char_set_attack_info(dumb_ptr<map_session_data> subject, interval_t speed, int range)
-{
- subject->attack_spell_delay = speed;
- subject->attack_spell_range = range;
-
- if (speed == interval_t::zero())
- {
- pc_calcstatus(subject, 1);
- clif_updatestatus(subject, SP::ASPD);
- clif_updatestatus(subject, SP::ATTACKRANGE);
- }
- else
- {
- subject->aspd = speed;
- clif_updatestatus(subject, SP::ASPD);
- clif_updatestatus(subject, SP::ATTACKRANGE);
- }
-}
-
-void magic_stop_completely(dumb_ptr<map_session_data> c)
-{
- // Zap all status change references to spells
- for (StatusChange i : erange(StatusChange(), StatusChange::MAX_STATUSCHANGE))
- c->sc_data[i].spell_invocation = BlockId();
-
- while (c->active_spells)
- spell_free_invocation(c->active_spells);
-
- if (c->attack_spell_override)
- {
- dumb_ptr<invocation> attack_spell = map_id_is_spell(c->attack_spell_override);
- if (attack_spell)
- spell_free_invocation(attack_spell);
- c->attack_spell_override = BlockId();
- char_set_weapon_icon(c, 0, StatusChange::ZERO, ItemNameId());
- char_set_attack_info(c, interval_t::zero(), 0);
- }
-}
-
-/* Spell execution has finished normally or we have been notified by a finished skill timer */
-static
-void try_to_finish_invocation(dumb_ptr<invocation> invocation)
-{
- if (invocation->status_change_refv.empty() && !invocation->current_effect)
- {
- if (invocation->end_effect)
- {
- clear_stack(invocation);
- invocation->current_effect = invocation->end_effect;
- invocation->end_effect = nullptr;
- spell_execute(invocation);
- }
- else
- spell_free_invocation(invocation);
- }
-}
-
-static
-BlockId trigger_spell(BlockId subject, BlockId spell)
-{
- dumb_ptr<invocation> invocation_ = map_id_is_spell(spell);
-
- if (!invocation_)
- return BlockId();
-
- invocation_ = spell_clone_effect(invocation_);
-
- spell_bind(map_id_is_player(subject), invocation_);
- magic_clear_var(&invocation_->env->varu[VAR_CASTER]);
- invocation_->env->varu[VAR_CASTER] = ValEntityInt{subject};
-
- return invocation_->bl_id;
-}
-
-static
-void entity_warp(dumb_ptr<block_list> target, Borrowed<map_local> destm, int destx, int desty);
-
-static
-void char_update(dumb_ptr<map_session_data> character)
-{
- entity_warp(character, character->bl_m, character->bl_x,
- character->bl_y);
-}
-
-static
-void timer_callback_effect(TimerData *, tick_t, BlockId id, int data)
-{
- dumb_ptr<block_list> target = map_id2bl(id);
- if (target)
- clif_misceffect(target, data);
-}
-
-static
-void entity_effect(dumb_ptr<block_list> entity, int effect_nr, interval_t delay)
-{
- Timer(gettick() + delay,
- std::bind(&timer_callback_effect, ph::_1, ph::_2,
- entity->bl_id, effect_nr)
- ).detach();
-}
-
-void magic_unshroud(dumb_ptr<map_session_data> other_char)
-{
- other_char->state.shroud_active = 0;
- // Now warp the caster out of and back into here to refresh everyone's display
- char_update(other_char);
- clif_displaymessage(other_char->sess, "Your shroud has been dispelled!"_s);
-// entity_effect(other_char, MAGIC_EFFECT_REVEAL);
-}
-
-static
-void timer_callback_effect_npc_delete(TimerData *, tick_t, BlockId npc_id)
-{
- dumb_ptr<npc_data> effect_npc = map_id_is_npc(npc_id);
- npc_free(effect_npc);
-}
-
-static
-dumb_ptr<npc_data> local_spell_effect(Borrowed<map_local> m, int x, int y, int effect,
- interval_t tdelay)
-{
- /* 1 minute should be enough for all interesting spell effects, I hope */
- std::chrono::seconds delay = 30_s;
- dumb_ptr<npc_data> effect_npc = npc_spawn_text(m, x, y,
- INVISIBLE_NPC, NpcName(), "?"_s);
- BlockId effect_npc_id = effect_npc->bl_id;
-
- entity_effect(effect_npc, effect, tdelay);
- Timer(gettick() + delay,
- std::bind(timer_callback_effect_npc_delete, ph::_1, ph::_2,
- effect_npc_id)
- ).detach();
-
- return effect_npc;
-}
-
-static
-int op_sfx(dumb_ptr<env_t>, Slice<val_t> args)
-{
- interval_t delay = static_cast<interval_t>(ARGINT(2));
-
- if (args[0].is<ValEntityPtr>())
- {
- entity_effect(ARGENTITY(0), ARGINT(1), delay);
- }
- else if (args[0].is<ValLocation>())
- {
- local_spell_effect(ARGLOCATION(0).m,
- ARGLOCATION(0).x,
- ARGLOCATION(0).y, ARGINT(1), delay);
- }
- else
- return 1;
-
- return 0;
-}
-
-static
-int op_instaheal(dumb_ptr<env_t> env, Slice<val_t> args)
-{
- 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;
-
- if (caster->bl_type == BL::PC && subject->bl_type == BL::PC)
- {
- dumb_ptr<map_session_data> caster_pc = caster->is_player();
- dumb_ptr<map_session_data> subject_pc = subject->is_player();
- MAP_LOG_PC(caster_pc, "SPELLHEAL-INSTA PC%d FOR %d"_fmt,
- subject_pc->status_key.char_id, ARGINT(1));
- }
-
- battle_heal(caster, subject, ARGINT(1), ARGINT(2), 0);
- return 0;
-}
-
-static
-int op_itemheal(dumb_ptr<env_t> env, Slice<val_t> args)
-{
- dumb_ptr<block_list> subject = ARGENTITY(0);
- if (subject->bl_type == BL::PC)
- {
- pc_itemheal(subject->is_player(),
- ARGINT(1), ARGINT(2));
- }
- else
- return op_instaheal(env, args);
-
- return 0;
-}
-
-namespace e
-{
-enum class Shroud
-{
- HIDE_NAME_TALKING_FLAG = 1 << 0,
- DISAPPEAR_ON_PICKUP_FLAG = 1 << 1,
- DISAPPEAR_ON_TALK_FLAG = 1 << 2,
-};
-ENUM_BITWISE_OPERATORS(Shroud)
-}
-using e::Shroud;
-
-// differs from ARGPC by checking
-#define ARGCHAR(n) (ARGENTITY(n)->is_player())
-
-static
-int op_shroud(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<map_session_data> subject = ARGCHAR(0);
- Shroud arg = static_cast<Shroud>(ARGINT(1));
-
- if (!subject)
- return 0;
-
- subject->state.shroud_active = 1;
- subject->state.shroud_hides_name_talking =
- bool(arg & Shroud::HIDE_NAME_TALKING_FLAG);
- subject->state.shroud_disappears_on_pickup =
- bool(arg & Shroud::DISAPPEAR_ON_PICKUP_FLAG);
- subject->state.shroud_disappears_on_talk =
- bool(arg & Shroud::DISAPPEAR_ON_TALK_FLAG);
- return 0;
-}
-
-static
-int op_reveal(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<map_session_data> subject = ARGCHAR(0);
-
- if (subject && subject->state.shroud_active)
- magic_unshroud(subject);
-
- return 0;
-}
-
-static
-int op_message(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<map_session_data> subject = ARGCHAR(0);
-
- if (subject)
- clif_displaymessage(subject->sess, ARGSTR(1));
-
- return 0;
-}
-
-static
-void timer_callback_kill_npc(TimerData *, tick_t, BlockId npc_id)
-{
- dumb_ptr<npc_data> npc = map_id_is_npc(npc_id);
- if (npc)
- npc_free(npc);
-}
-
-static
-int op_messenger_npc(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<npc_data> npc;
- location_t *loc = &ARGLOCATION(0);
-
- NpcName npcname = stringish<NpcName>(ARGSTR(2));
- npc = npc_spawn_text(loc->m, loc->x, loc->y,
- wrap<Species>(static_cast<uint16_t>(ARGINT(1))), npcname, ARGSTR(3));
-
- Timer(gettick() + static_cast<interval_t>(ARGINT(4)),
- std::bind(timer_callback_kill_npc, ph::_1, ph::_2,
- npc->bl_id)
- ).detach();
-
- return 0;
-}
-
-static
-void entity_warp(dumb_ptr<block_list> target, Borrowed<map_local> destm, int destx, int desty)
-{
- if (target->bl_type == BL::PC || target->bl_type == BL::MOB)
- {
-
- switch (target->bl_type)
- {
- case BL::PC:
- {
- dumb_ptr<map_session_data> character = target->is_player();
- clif_clearchar(character, BeingRemoveWhy::WARPED);
- map_delblock(character);
- character->bl_x = destx;
- character->bl_y = desty;
- character->bl_m = destm;
-
- pc_touch_all_relevant_npcs(character);
-
- // Note that touching NPCs may have triggered warping and thereby updated x and y:
- MapName map_name = character->bl_m->name_;
-
- // Warp part #1: update relevant data, interrupt trading etc.:
- pc_setpos(character, map_name, character->bl_x, character->bl_y, BeingRemoveWhy::GONE);
- // Warp part #2: now notify the client
- clif_changemap(character, map_name,
- character->bl_x, character->bl_y);
- break;
- }
- case BL::MOB:
- target->bl_x = destx;
- target->bl_y = desty;
- target->bl_m = destm;
- clif_fixmobpos(target->is_mob());
- break;
- }
- }
-}
-
-static
-int op_move(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<block_list> subject = ARGENTITY(0);
- DIR dir = ARGDIR(1);
-
- int newx = subject->bl_x + dirx[dir];
- int newy = subject->bl_y + diry[dir];
-
- if (!bool(map_getcell(subject->bl_m, newx, newy) & MapCell::UNWALKABLE))
- entity_warp(subject, subject->bl_m, newx, newy);
-
- return 0;
-}
-
-static
-int op_warp(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<block_list> subject = ARGENTITY(0);
- location_t *loc = &ARGLOCATION(1);
-
- entity_warp(subject, loc->m, loc->x, loc->y);
-
- return 0;
-}
-
-static
-int op_banish(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<block_list> subject = ARGENTITY(0);
-
- if (subject->bl_type == BL::MOB)
- {
- dumb_ptr<mob_data> mob = subject->is_mob();
-
- if (bool(mob->mode & MobMode::SUMMONED))
- mob_catch_delete(mob, BeingRemoveWhy::WARPED);
- }
-
- return 0;
-}
-
-static
-void record_status_change(dumb_ptr<invocation> invocation_, BlockId bl_id,
- StatusChange sc_id)
-{
- status_change_ref_t cr {};
- cr.sc_type = sc_id;
- cr.bl_id = bl_id;
-
- invocation_->status_change_refv.push_back(cr);
-}
-
-static
-int op_status_change(dumb_ptr<env_t> env, Slice<val_t> args)
-{
- dumb_ptr<block_list> subject = ARGENTITY(0);
- 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));
- assert (!ARGINT(4));
- assert (!ARGINT(5));
- skill_status_effect(subject, static_cast<StatusChange>(ARGINT(1)),
- ARGINT(2),
- static_cast<interval_t>(ARGINT(6)), invocation_id);
-
- if (invocation_ && subject->bl_type == BL::PC)
- record_status_change(invocation_, subject->bl_id, static_cast<StatusChange>(ARGINT(1)));
-
- return 0;
-}
-
-static
-int op_stop_status_change(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<block_list> subject = ARGENTITY(0);
-
- StatusChange sc = static_cast<StatusChange>(ARGINT(1));
- skill_status_change_end(subject, sc, nullptr);
-
- return 0;
-}
-
-static
-int op_override_attack(dumb_ptr<env_t> env, Slice<val_t> args)
-{
- dumb_ptr<block_list> psubject = ARGENTITY(0);
- int charges = ARGINT(1);
- interval_t attack_delay = static_cast<interval_t>(ARGINT(2));
- int attack_range = ARGINT(3);
- StatusChange icon = StatusChange(ARGINT(4));
- ItemNameId look = wrap<ItemNameId>(static_cast<uint16_t>(ARGINT(5)));
- int stopattack = ARGINT(6);
- dumb_ptr<map_session_data> subject;
-
- if (psubject->bl_type != BL::PC)
- return 0;
-
- subject = psubject->is_player();
-
- if (subject->attack_spell_override)
- {
- dumb_ptr<invocation> old_invocation = map_id_is_spell(subject->attack_spell_override);
- if (old_invocation)
- spell_free_invocation(old_invocation);
- }
-
- ValInvocationInt *ii = env->VAR(VAR_INVOCATION).get_if<ValInvocationInt>();
- subject->attack_spell_override =
- trigger_spell(subject->bl_id, ii->v_iid);
- subject->attack_spell_charges = charges;
-
- if (subject->attack_spell_override)
- {
- dumb_ptr<invocation> attack_spell = map_id_is_spell(subject->attack_spell_override);
- if (attack_spell && stopattack)
- attack_spell->flags |= INVOCATION_FLAG::STOPATTACK;
-
- char_set_weapon_icon(subject, charges, icon, look);
- char_set_attack_info(subject, attack_delay, attack_range);
- }
-
- return 0;
-}
-
-static
-int op_create_item(dumb_ptr<env_t>, Slice<val_t> args)
-{
- Item item;
- dumb_ptr<block_list> entity = ARGENTITY(0);
- dumb_ptr<map_session_data> subject;
- int stackable;
- int count = ARGINT(2);
- if (count <= 0)
- return 0;
-
- if (entity->bl_type == BL::PC)
- subject = entity->is_player();
- else
- return 0;
-
- GET_ARG_ITEM(1, item, stackable);
-
- if (!stackable)
- while (count--)
- pc_additem(subject, &item, 1);
- else
- pc_additem(subject, &item, count);
-
- return 0;
-}
-
-inline
-bool AGGRAVATION_MODE_ATTACKS_CASTER(int n)
-{
- return n == 0 || n == 2;
-}
-inline
-bool AGGRAVATION_MODE_MAKES_AGGRESSIVE(int n)
-{
- return n > 0;
-}
-
-static
-int op_aggravate(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<block_list> victim = ARGENTITY(2);
- int mode = ARGINT(1);
- dumb_ptr<block_list> target = ARGENTITY(0);
- dumb_ptr<mob_data> other;
-
- if (target->bl_type == BL::MOB)
- other = target->is_mob();
- else
- return 0;
-
- mob_target(other, victim, battle_get_range(victim));
-
- if (AGGRAVATION_MODE_MAKES_AGGRESSIVE(mode))
- other->mode = MobMode::war | (other->mode & MobMode::SENSIBLE_MASK);
-
- if (AGGRAVATION_MODE_ATTACKS_CASTER(mode))
- {
- other->target_id = victim->bl_id;
- other->attacked_id = victim->bl_id;
- }
-
- return 0;
-}
-
-enum class MonsterAttitude
-{
- HOSTILE = 0,
- FRIENDLY = 1,
- SERVANT = 2,
- FROZEN = 3,
-};
-
-static
-int op_spawn(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<area_t> area = ARGAREA(0);
- dumb_ptr<block_list> owner_e = ARGENTITY(1);
- Species monster_id = wrap<Species>(ARGINT(2));
- MonsterAttitude monster_attitude = static_cast<MonsterAttitude>(ARGINT(3));
- int monster_count = ARGINT(4);
- interval_t monster_lifetime = static_cast<interval_t>(ARGINT(5));
- int i;
-
- dumb_ptr<map_session_data> owner = nullptr;
- if (monster_attitude == MonsterAttitude::SERVANT
- && owner_e->bl_type == BL::PC)
- owner = owner_e->is_player();
-
- for (i = 0; i < monster_count; i++)
- {
- location_t loc;
- magic_random_location(&loc, area);
-
- BlockId mob_id;
- dumb_ptr<mob_data> mob;
-
- mob_id = mob_once_spawn(owner, loc.m->name_, loc.x, loc.y, JAPANESE_NAME, // Is that needed?
- monster_id, 1, NpcEvent());
-
- mob = map_id_is_mob(mob_id);
-
- if (mob)
- {
- mob->mode = get_mob_db(monster_id).mode;
-
- switch (monster_attitude)
- {
- case MonsterAttitude::SERVANT:
- mob->state.special_mob_ai = 1;
- mob->mode |= MobMode::AGGRESSIVE;
- break;
-
- case MonsterAttitude::FRIENDLY:
- mob->mode = MobMode::CAN_ATTACK | (mob->mode & MobMode::CAN_MOVE);
- break;
-
- case MonsterAttitude::HOSTILE:
- mob->mode = MobMode::CAN_ATTACK | MobMode::AGGRESSIVE | (mob->mode & MobMode::CAN_MOVE);
- if (owner)
- {
- mob->target_id = owner->bl_id;
- mob->attacked_id = owner->bl_id;
- }
- break;
-
- case MonsterAttitude::FROZEN:
- mob->mode = MobMode::ZERO;
- break;
- }
-
- mob->mode |=
- MobMode::SUMMONED | MobMode::TURNS_AGAINST_BAD_MASTER;
-
- mob->deletetimer = Timer(gettick() + monster_lifetime,
- std::bind(mob_timer_delete, ph::_1, ph::_2,
- mob_id));
-
- if (owner)
- {
- mob->master_id = owner->bl_id;
- mob->master_dist = 6;
- }
- }
- }
-
- return 0;
-}
-
-static
-ZString get_invocation_name(dumb_ptr<env_t> env)
-{
- assert (!env->VAR(VAR_INVOCATION).is<ValInvocationPtr>());
-
- ValInvocationInt *ii = env->VAR(VAR_INVOCATION).get_if<ValInvocationInt>();
- if (!ii)
- return "?"_s;
-
- dumb_ptr<invocation> invocation_;
- invocation_ = map_id_is_spell(ii->v_iid);
-
- if (invocation_)
- return invocation_->spell->name;
- else
- return "??"_s;
-}
-
-static
-int op_injure(dumb_ptr<env_t> env, Slice<val_t> args)
-{
- dumb_ptr<block_list> caster = ARGENTITY(0);
- dumb_ptr<block_list> target = ARGENTITY(1);
- int damage_caused = ARGINT(2);
- int mp_damage = ARGINT(3);
- int target_hp = battle_get_hp(target);
- int mdef = battle_get_mdef(target);
-
- if (target->bl_type == BL::PC // target is player
- && !target->bl_m->flag.get(MapFlag::PVP) // there is no pvpon flag
- && (caster->bl_type == BL::PC) // caster is player
- && ((target->is_player()->state.pvpchannel == 0)
- || ((caster->is_player()->state.pvpchannel > 0)
- && (target->is_player()->state.pvpchannel != caster->is_player()->state.pvpchannel))))
- return 0; /* Cannot damage other players outside of pvp */
-
- if (target != caster)
- {
- /* Not protected against own spells */
- damage_caused = (damage_caused * (100 - mdef)) / 100;
- mp_damage = (mp_damage * (100 - mdef)) / 100;
- }
-
- damage_caused = (damage_caused > target_hp) ? target_hp : damage_caused;
-
- if (damage_caused < 0)
- damage_caused = 0;
-
- // display damage first, because dealing damage may deallocate the target.
- clif_damage(caster, target,
- gettick(), interval_t::zero(), interval_t::zero(),
- damage_caused, 0, DamageType::NORMAL);
-
- if (caster->bl_type == BL::PC)
- {
- dumb_ptr<map_session_data> caster_pc = caster->is_player();
- if (target->bl_type == BL::MOB)
- {
- dumb_ptr<mob_data> mob = target->is_mob();
-
- MAP_LOG_PC(caster_pc, "SPELLDMG MOB%d %d FOR %d BY %s"_fmt,
- mob->bl_id, mob->mob_class, damage_caused,
- get_invocation_name(env));
- }
- }
- battle_damage(caster, target, damage_caused, mp_damage);
-
- return 0;
-}
-
-static
-int op_emote(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<block_list> victim = ARGENTITY(0);
- int emotion = ARGINT(1);
- clif_emotion(victim, emotion);
-
- return 0;
-}
-
-static
-int op_set_script_variable(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<map_session_data> c = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr;
- VarName varname = stringish<VarName>(ARGSTR(1));
- int array_index = 0;
-
- if (!c)
- return 1;
-
- set_script_var_i(c, varname, array_index, ARGINT(2));
-
- return 0;
-}
-
-static
-int op_set_script_str(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<map_session_data> c = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr;
- VarName varname = stringish<VarName>(ARGSTR(1));
- int array_index = 0;
-
- if (!c)
- return 1;
-
- set_script_var_s(c, varname, array_index, ARGSTR(2));
-
- return 0;
-}
-
-static
-int op_set_hair_colour(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<map_session_data> c = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr;
-
- if (!c)
- return 1;
-
- pc_changelook(c, LOOK::HAIR_COLOR, ARGINT(1));
-
- return 0;
-}
-
-static
-int op_set_hair_style(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<map_session_data> c = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr;
-
- if (!c)
- return 1;
-
- pc_changelook(c, LOOK::HAIR, ARGINT(1));
-
- return 0;
-}
-
-static
-int op_drop_item_for (dumb_ptr<env_t>, Slice<val_t> args)
-{
- Item item;
- int stackable;
- location_t *loc = &ARGLOCATION(0);
- int count = ARGINT(2);
- interval_t interval = static_cast<interval_t>(ARGINT(3));
- dumb_ptr<map_session_data> c = ((args.size() > 4) && (ENTITY_TYPE(4) == BL::PC)) ? ARGPC(4) : nullptr;
- interval_t delay = (args.size() > 5) ? static_cast<interval_t>(ARGINT(5)) : interval_t::zero();
- interval_t delaytime[3] = { delay, delay, delay };
- dumb_ptr<map_session_data> owners[3] = { c, nullptr, nullptr };
-
- GET_ARG_ITEM(1, item, stackable);
-
- if (stackable)
- {
- map_addflooritem_any(&item, count, loc->m, loc->x, loc->y,
- owners, delaytime, interval, 0);
- }
- else
- {
- while (count-- > 0)
- map_addflooritem_any(&item, 1, loc->m, loc->x, loc->y,
- owners, delaytime, interval, 0);
- }
-
- return 0;
-}
-
-static
-int op_gain_exp(dumb_ptr<env_t>, Slice<val_t> args)
-{
- dumb_ptr<map_session_data> c = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr;
-
- if (!c)
- return 1;
-
- pc_gainexp_reason(c, ARGINT(1), ARGINT(2),
- static_cast<PC_GAINEXP_REASON>(ARGINT(3)));
- return 0;
-}
-
-#define MAGIC_OPERATION(name, args, impl) {{name}, {{name}, {args}, impl}}
-#define MAGIC_OPERATION1(name, args) MAGIC_OPERATION(#name##_s, args, op_##name)
-static
-std::map<ZString, op_t> operations =
-{
- MAGIC_OPERATION1(sfx, ".ii"_s),
- MAGIC_OPERATION1(instaheal, "eii"_s),
- MAGIC_OPERATION1(itemheal, "eii"_s),
- MAGIC_OPERATION1(shroud, "ei"_s),
- MAGIC_OPERATION("unshroud"_s, "e"_s, op_reveal),
- MAGIC_OPERATION1(message, "es"_s),
- MAGIC_OPERATION1(messenger_npc, "lissi"_s),
- MAGIC_OPERATION1(move, "ed"_s),
- MAGIC_OPERATION1(warp, "el"_s),
- MAGIC_OPERATION1(banish, "e"_s),
- MAGIC_OPERATION1(status_change, "eiiiiii"_s),
- MAGIC_OPERATION1(stop_status_change, "ei"_s),
- MAGIC_OPERATION1(override_attack, "eiiiiii"_s),
- MAGIC_OPERATION1(create_item, "e.i"_s),
- MAGIC_OPERATION1(aggravate, "eie"_s),
- MAGIC_OPERATION1(spawn, "aeiiii"_s),
- MAGIC_OPERATION1(injure, "eeii"_s),
- MAGIC_OPERATION1(emote, "ei"_s),
- MAGIC_OPERATION1(set_script_variable, "esi"_s),
- MAGIC_OPERATION1(set_script_str, "ess"_s),
- MAGIC_OPERATION1(set_hair_colour, "ei"_s),
- MAGIC_OPERATION1(set_hair_style, "ei"_s),
- MAGIC_OPERATION("drop_item"_s, "l.ii"_s, op_drop_item_for),
- MAGIC_OPERATION1(drop_item_for, "l.iiei"_s),
- MAGIC_OPERATION("gain_experience"_s, "eiii"_s, op_gain_exp),
-};
-
-op_t *magic_get_op(ZString name)
-{
- auto it = operations.find(name);
- if (it == operations.end())
- return nullptr;
- return &it->second;
-}
-
-void spell_effect_report_termination(BlockId invocation_id, BlockId bl_id,
- StatusChange sc_id, int)
-{
- dumb_ptr<invocation> invocation_ = map_id_is_spell(invocation_id);
-
- if (!invocation_ || invocation_->bl_type != BL::SPELL)
- return;
-
- for (status_change_ref_t& cr : invocation_->status_change_refv)
- {
- if (cr.sc_type == sc_id && cr.bl_id == bl_id)
- {
- if (&cr != &invocation_->status_change_refv.back())
- std::swap(cr, invocation_->status_change_refv.back());
- invocation_->status_change_refv.pop_back();
-
- try_to_finish_invocation(invocation_);
- return;
- }
- }
-
- {
- dumb_ptr<block_list> entity = map_id2bl(bl_id);
- if (entity->bl_type == BL::PC)
- FPRINTF(stderr,
- "[magic] INTERNAL ERROR: spell-effect-report-termination: tried to terminate on unexpected bl %d, sc %d\n"_fmt,
- bl_id, sc_id);
- return;
- }
-
-}
-
-static
-dumb_ptr<effect_t> return_to_stack(dumb_ptr<invocation> invocation_)
-{
- if (invocation_->stack.empty())
- return nullptr;
- else
- {
- cont_activation_record_t *ar =
- &invocation_->stack.back();
- MATCH_BEGIN (*ar)
- {
- MATCH_CASE (const CarProc&, c_proc)
- {
- dumb_ptr<effect_t> ret = ar->return_location;
- for (int i = 0; i < c_proc.args_nr; i++)
- {
- val_t *var =
- &invocation_->env->varu[c_proc.formalap[i]];
- magic_clear_var(var);
- *var = std::move(c_proc.old_actualpa[i]);
- }
-
- // pop the stack
- clear_activation_record(ar);
- invocation_->stack.pop_back();
-
- return ret;
- }
- MATCH_CASE (CarForEach&, c_foreach)
- {
- BlockId entity_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 (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.pop_back();
- return ret;
- }
-
- entity_id =
- (*c_foreach.entities_vp)[c_foreach.index++];
- }
- while (!entity_id || !map_id2bl(entity_id));
-
- magic_clear_var(var);
- if (c_foreach.ty_is_spell_not_entity)
- *var = ValInvocationInt{entity_id};
- else
- *var = ValEntityInt{entity_id};
-
- return c_foreach.body;
- }
- MATCH_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.pop_back();
- return ret;
- }
-
- magic_clear_var(&invocation_->env->varu[c_for.id]);
- invocation_->env->varu[c_for.id] = ValInt{c_for.current++};
-
- return c_for.body;
- }
- }
- MATCH_END ();
- abort();
- }
-}
-
-static
-void find_entities_in_area_c(dumb_ptr<block_list> target,
- std::vector<BlockId> *entities_vp,
- FOREACH_FILTER filter)
-{
- switch (target->bl_type)
- {
-
- case BL::PC:
- if (filter == FOREACH_FILTER::PC
- || filter == FOREACH_FILTER::ENTITY
- || (filter == FOREACH_FILTER::TARGET
- && target->bl_m->flag.get(MapFlag::PVP)))
- break;
- else if (filter == FOREACH_FILTER::SPELL)
- { /* Check all spells bound to the caster */
- dumb_ptr<invocation> invoc = target->is_player()->active_spells;
- /* Add all spells locked onto thie PC */
-
- while (invoc)
- {
- entities_vp->push_back(invoc->bl_id);
- invoc = invoc->next_invocation;
- }
- }
- return;
-
- case BL::MOB:
- if (filter == FOREACH_FILTER::MOB
- || filter == FOREACH_FILTER::ENTITY
- || filter == FOREACH_FILTER::TARGET)
- break;
- else
- return;
-
- case BL::SPELL:
- if (filter == FOREACH_FILTER::SPELL)
- {
- dumb_ptr<invocation> invocation = target->is_spell();
-
- /* Check whether the spell is `bound'-- if so, we'll consider it iff we see the caster(case BL::PC). */
- if (bool(invocation->flags & INVOCATION_FLAG::BOUND))
- return;
- else
- break; /* Add the spell */
- }
- else
- return;
-
- case BL::NPC:
- if (filter == FOREACH_FILTER::NPC)
- break;
- else
- return;
-
- default:
- return;
- }
-
- entities_vp->push_back(target->bl_id);
-}
-
-static
-void find_entities_in_area(area_t& area_,
- std::vector<BlockId> *entities_vp,
- FOREACH_FILTER filter)
-{
- MATCH_BEGIN (area_)
- {
- MATCH_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);
- }
- MATCH_CASE (const location_t&, a_loc)
- {
- (void)a_loc;
- // TODO this can be simplified
- int x, y, width, height;
- Borrowed<map_local> m = magic_area_rect(&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 */);
- }
- MATCH_CASE (const AreaRect&, a_rect)
- {
- (void)a_rect;
- // TODO this can be simplified
- int x, y, width, height;
- Borrowed<map_local> m = magic_area_rect(&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 */);
- }
- MATCH_CASE (const AreaBar&, a_bar)
- {
- (void)a_bar;
- // TODO this is wrong
- int x, y, width, height;
- Borrowed<map_local> m = magic_area_rect(&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 */);
- }
- }
- MATCH_END ();
-}
-
-static
-dumb_ptr<effect_t> run_foreach(dumb_ptr<invocation> invocation,
- const EffectForEach *foreach,
- dumb_ptr<effect_t> return_location)
-{
- const EffectForEach& e_foreach = *foreach;
-
- val_t area;
- FOREACH_FILTER filter = e_foreach.filter;
- int id = e_foreach.id;
- dumb_ptr<effect_t> body = e_foreach.body;
-
- magic_eval(invocation->env, &area, e_foreach.area);
-
- auto va = area.get_if<ValArea>();
- if (!va)
- {
- magic_clear_var(&area);
- FPRINTF(stderr,
- "[magic] Error in spell `%s': FOREACH loop over non-area\n"_fmt,
- invocation->spell->name);
- return return_location;
- }
-
- {
- std::vector<BlockId> entities_v;
- 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);
-
- 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);
-
- return return_to_stack(invocation);
- }
-}
-
-static
-dumb_ptr<effect_t> run_for (dumb_ptr<invocation> invocation,
- const EffectFor *for_,
- dumb_ptr<effect_t> return_location)
-{
- const EffectFor& e_for = *for_;
-
- int id = e_for.id;
- val_t start;
- val_t stop;
-
- magic_eval(invocation->env, &start, e_for.start);
- magic_eval(invocation->env, &stop, e_for.stop);
-
- if (!start.is<ValInt>() || !stop.is<ValInt>())
- {
- magic_clear_var(&start);
- magic_clear_var(&stop);
- FPRINTF(stderr,
- "[magic] Error in spell `%s': FOR loop start or stop point is not an integer\n"_fmt,
- invocation->spell->name);
- return return_location;
- }
-
- CarFor c_for;
-
- 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)
-{
- 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);
-
- 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, (*e_call.actualvp)[i]);
- }
-
- return e_call.body;
-}
-
-/**
- * Execute a spell invocation until we abort, finish, or hit the next `sleep'.
- *
- * Use spell_execute() to automate handling of timers
- *
- * Returns: 0 if finished (all memory is freed implicitly)
- * >1 if we hit `sleep'; the result is the number of ticks we should sleep for.
- * -1 if we paused to wait for a user action (via script interaction)
- */
-static
-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();
-
- while (invocation_->current_effect)
- {
- dumb_ptr<effect_t> e = invocation_->current_effect;
- dumb_ptr<effect_t> next = e->next;
- int i;
-
- MATCH_BEGIN (*e)
- {
- MATCH_CASE (const EffectSkip&, e_)
- {
- (void)e_;
- }
- MATCH_CASE (const EffectAbort&, e_)
- {
- (void)e_;
- invocation_->flags |= INVOCATION_FLAG::ABORTED;
- invocation_->end_effect = nullptr;
- clear_stack(invocation_);
- next = nullptr;
- }
- MATCH_CASE (const EffectEnd&, e_)
- {
- (void)e_;
- clear_stack(invocation_);
- next = nullptr;
- }
- MATCH_CASE (const EffectAssign&, e_assign)
- {
- magic_eval(invocation_->env,
- &invocation_->env->varu[e_assign.id],
- e_assign.expr);
- }
- MATCH_CASE (const EffectForEach&, e_foreach)
- {
- next = run_foreach(invocation_, &e_foreach, next);
- }
- MATCH_CASE (const EffectFor&, e_for)
- {
- next = run_for (invocation_, &e_for, next);
- }
- MATCH_CASE (const EffectIf&, e_if)
- {
- if (magic_eval_int(invocation_->env, e_if.cond))
- next = e_if.true_branch;
- else
- next = e_if.false_branch;
- }
- MATCH_CASE (const EffectSleep&, e_)
- {
- interval_t sleeptime = static_cast<interval_t>(
- magic_eval_int(invocation_->env, e_.e_sleep));
- invocation_->current_effect = next;
- if (sleeptime > interval_t::zero())
- return sleeptime;
- }
- MATCH_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[1] =
- {
- {"@caster_name$"_s, caster_name},
- };
- assert (!env->VAR(VAR_SCRIPTTARGET).is<ValEntityPtr>());
- ValEntityInt *ei = env->VAR(VAR_SCRIPTTARGET).get_if<ValEntityInt>();
- BlockId message_recipient =
- ei
- ? ei->v_eid
- : invocation_->caster;
- dumb_ptr<map_session_data> recipient = map_id_is_player(message_recipient);
-
- if (recipient->npc_id
- && recipient->npc_id != invocation_->bl_id)
- goto break_match; /* Don't send multiple message boxes at once */
-
- if (!invocation_->script_pos) // first time running this script?
- clif_spawn_fake_npc_for_player(recipient,
- invocation_->bl_id);
- // We have to do this or otherwise the client won't think that it's
- // dealing with an NPC
-
- int newpos = run_script_l(
- ScriptPointer(borrow(*e_.e_script), invocation_->script_pos),
- message_recipient, invocation_->bl_id,
- arg);
- /* Returns the new script position, or -1 once the script is finished */
- if (newpos != -1)
- {
- /* Must set up for continuation */
- recipient->npc_id = invocation_->bl_id;
- recipient->npc_pos = invocation_->script_pos = newpos;
- return static_cast<interval_t>(-1); /* Signal `wait for script' */
- }
- else
- invocation_->script_pos = 0;
- clif_clearchar_id(invocation_->bl_id, BeingRemoveWhy::DEAD, caster->sess);
- }
- REFRESH_INVOCATION; // Script may have killed the caster
- }
- MATCH_CASE (const EffectBreak&, e_)
- {
- (void)e_;
- next = return_to_stack(invocation_);
- }
- MATCH_CASE (const EffectOp&, e_op)
- {
- op_t *op = e_op.opp;
- val_t args[MAX_ARGS];
-
- 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_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_op.args_nr; i++)
- magic_clear_var(&args[i]);
-
- REFRESH_INVOCATION; // Effect may have killed the caster
- }
- MATCH_CASE (const EffectCall&, e_call)
- {
- next = run_call(invocation_, &e_call, next);
- }
- }
- MATCH_END ();
-
- break_match:
- if (!next)
- next = return_to_stack(invocation_);
-
- invocation_->current_effect = next;
- }
-
- if (allow_delete)
- try_to_finish_invocation(invocation_);
- return interval_t::zero();
-#undef REFRESH_INVOCATION
-}
-
-static
-void spell_execute_d(dumb_ptr<invocation> invocation, int allow_deletion)
-{
- spell_update_location(invocation);
- interval_t delta = spell_run(invocation, allow_deletion);
-
- if (delta > interval_t::zero())
- {
- assert (!invocation->timer);
- invocation->timer = Timer(gettick() + delta,
- std::bind(invocation_timer_callback, ph::_1, ph::_2,
- invocation->bl_id));
- }
-
- /* If 0, the script cleaned itself. If -1(wait-for-script), we must wait for the user. */
-}
-
-void spell_execute(dumb_ptr<invocation> invocation)
-{
- spell_execute_d(invocation, 1);
-}
-
-void spell_execute_script(dumb_ptr<invocation> invocation)
-{
- if (invocation->script_pos)
- spell_execute_d(invocation, 1);
- /* Otherwise the script-within-the-spell has been terminated by some other means.
- * In practice this happens when the script doesn't wait for user input: the client
- * may still notify the server that it's done. Without the above check, we'd be
- * running the same spell twice! */
-}
-
-int spell_attack(BlockId caster_id, BlockId target_id)
-{
- dumb_ptr<map_session_data> caster = map_id_is_player(caster_id);
- dumb_ptr<invocation> invocation_;
- int stop_attack = 0;
-
- if (!caster)
- return 0;
-
- invocation_ = map_id_is_spell(caster->attack_spell_override);
-
- if (invocation_ && bool(invocation_->flags & INVOCATION_FLAG::STOPATTACK))
- stop_attack = 1;
-
- if (invocation_ && caster->attack_spell_charges > 0)
- {
- magic_clear_var(&invocation_->env->varu[VAR_TARGET]);
- invocation_->env->varu[VAR_TARGET] = ValEntityInt{target_id};
-
- invocation_->current_effect = invocation_->trigger_effect;
- invocation_->flags &= ~INVOCATION_FLAG::ABORTED;
- spell_execute_d(invocation_,
- 0 /* don't delete the invocation if done */ );
-
- // If the caster died, we need to refresh here:
- invocation_ = map_id_is_spell(caster->attack_spell_override);
-
- if (invocation_ && !bool(invocation_->flags & INVOCATION_FLAG::ABORTED)) // If we didn't abort:
- caster->attack_spell_charges--;
- }
-
- if (invocation_ && caster->attack_spell_override != invocation_->bl_id)
- {
- /* Attack spell changed / was refreshed */
- // spell_free_invocation(invocation); // [Fate] This would be a double free.
- }
- else if (!invocation_ || caster->attack_spell_charges <= 0)
- {
- caster->attack_spell_override = BlockId();
- char_set_weapon_icon(caster, 0, StatusChange::ZERO, ItemNameId());
- char_set_attack_info(caster, interval_t::zero(), 0);
-
- if (stop_attack)
- pc_stopattack(caster);
-
- if (invocation_)
- spell_free_invocation(invocation_);
- }
-
- return 1;
-}
-} // namespace magic
-} // namespace map
-} // namespace tmwa
diff --git a/src/map/magic-stmt.hpp b/src/map/magic-stmt.hpp
deleted file mode 100644
index 3b04fe3..0000000
--- a/src/map/magic-stmt.hpp
+++ /dev/null
@@ -1,93 +0,0 @@
-#pragma once
-// magic-stmt.hpp - Imperative commands for the magic backend.
-//
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include "fwd.hpp"
-
-#include "../strings/zstring.hpp"
-
-#include "../mmo/skill.t.hpp"
-
-
-namespace tmwa
-{
-namespace map
-{
-namespace magic
-{
-struct op_t
-{
- LString name;
- LString signature;
- int (*op)(dumb_ptr<env_t> env, Slice<val_t> arga);
-};
-
-/**
- * Retrieves an operation by name
- * @param name The name to look up
- * @return An operation of that name, or nullptr, and a function index
- */
-op_t *magic_get_op(ZString name);
-
-/**
- * Removes the shroud from a character
- *
- * \param character The character to remove the shroud from
- */
-void magic_unshroud(dumb_ptr<map_session_data> character);
-
-/**
- * Notifies a running spell that a status_change timer triggered by the spell has expired
- *
- * \param invocation The invocation to notify
- * \param bl_id ID of the PC for whom this happened
- * \param sc_id ID of the status change entry that finished
- * \param supplanted Whether the status_change finished normally (0) or was supplanted by a new status_change (1)
- */
-void spell_effect_report_termination(BlockId invocation, BlockId bl_id,
- StatusChange sc_id, int supplanted);
-
-/**
- * Execute a spell invocation and sets up timers to finish
- */
-void spell_execute(dumb_ptr<invocation> invocation);
-
-/**
- * Continue an NPC script embedded in a spell
- */
-void spell_execute_script(dumb_ptr<invocation> invocation);
-
-/**
- * Stops all magic bound to the specified character
- *
- */
-void magic_stop_completely(dumb_ptr<map_session_data> c);
-
-/**
- * Attacks with a magical spell charged to the character
- *
- * Returns 0 if there is no charged spell or the spell is depleted.
- */
-int spell_attack(BlockId caster, BlockId target);
-
-void spell_free_invocation(dumb_ptr<invocation> invocation);
-} // namespace magic
-} // namespace map
-} // namespace tmwa
diff --git a/src/map/magic-stmt.py b/src/map/magic-stmt.py
deleted file mode 100644
index 7cc43d0..0000000
--- a/src/map/magic-stmt.py
+++ /dev/null
@@ -1,37 +0,0 @@
-class op_t(object):
- __slots__ = ('_value')
-
- name = 'tmwa::map::magic::op_t'
- depth = 1
- enabled = True
-
- def __init__(self, value):
- if not value:
- value = None
- self._value = value
-
- def to_string(self):
- value = self._value
- if value is None:
- return '(op_t *) nullptr'
- return '(op_t *)'
-
- def children(self):
- value = self._value
- if value is None:
- return
- value = value.dereference()
- yield '->name', value['name']
- yield '->signature', value['signature']
- yield '->op', value['op']
-
- test_extra = '''
- using tmwa::operator "" _s;
- '''
-
- tests = [
- ('static_cast<tmwa::map::magic::op_t *>(nullptr)',
- '(op_t *) nullptr'),
- ('new tmwa::map::magic::op_t{"name"_s, "sig"_s, nullptr}',
- '(op_t *) = {->name = "name", ->signature = "sig", ->op = nullptr}'),
- ]
diff --git a/src/map/magic-v2.cpp b/src/map/magic-v2.cpp
deleted file mode 100644
index 52b1b8f..0000000
--- a/src/map/magic-v2.cpp
+++ /dev/null
@@ -1,1295 +0,0 @@
-#include "magic-v2.hpp"
-// magic-v2.cpp - second generation magic parser
-//
-// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include <cstddef>
-
-#include <algorithm>
-#include <map>
-#include <set>
-
-#include "../range/slice.hpp"
-
-#include "../strings/rstring.hpp"
-#include "../strings/literal.hpp"
-
-#include "../generic/dumb_ptr.hpp"
-
-#include "../io/cxxstdio.hpp"
-#include "../io/line.hpp"
-
-#include "../sexpr/parser.hpp"
-
-#include "../ast/script.hpp"
-
-#include "globals.hpp"
-#include "itemdb.hpp"
-#include "magic-expr.hpp"
-#include "magic-interpreter.hpp"
-#include "magic-interpreter-base.hpp"
-#include "magic-stmt.hpp"
-#include "script-parse.hpp"
-
-#include "../poison.hpp"
-
-
-namespace tmwa
-{
-namespace map
-{
-namespace magic
-{
-namespace magic_v2
-{
- static
- size_t intern_id(ZString id_name)
- {
- // TODO use InternPool
- size_t i;
- for (i = 0; i < magic_conf.varv.size(); i++)
- if (id_name == magic_conf.varv[i].name)
- return i;
-
- // i = magic_conf.varv.size();
- /* Must add new */
- magic_conf_t::mcvar new_var {};
- new_var.name = id_name;
- new_var.val = ValUndef();
- magic_conf.varv.push_back(std::move(new_var));
-
- return i;
- }
- inline
- bool INTERN_ASSERT(ZString name, int id)
- {
- int zid = intern_id(name);
- if (zid != id)
- {
- FPRINTF(stderr,
- "[magic-conf] INTERNAL ERROR: Builtin special var %s interned to %d, not %d as it should be!\n"_fmt,
- name, zid, id);
- }
- return zid == id;
- }
-
- static
- bool init0()
- {
- bool ok = true;
-
- ok &= INTERN_ASSERT("min_casttime"_s, VAR_MIN_CASTTIME);
- ok &= INTERN_ASSERT("obscure_chance"_s, VAR_OBSCURE_CHANCE);
- ok &= INTERN_ASSERT("caster"_s, VAR_CASTER);
- ok &= INTERN_ASSERT("spellpower"_s, VAR_SPELLPOWER);
- ok &= INTERN_ASSERT("self_spell"_s, VAR_SPELL);
- ok &= INTERN_ASSERT("self_invocation"_s, VAR_INVOCATION);
- ok &= INTERN_ASSERT("target"_s, VAR_TARGET);
- ok &= INTERN_ASSERT("script_target"_s, VAR_SCRIPTTARGET);
- ok &= INTERN_ASSERT("location"_s, VAR_LOCATION);
-
- return ok;
- }
-
-
- static
- bool bind_constant(io::LineSpan span, RString name, val_t val)
- {
- if (!const_defm.insert(std::make_pair(name, std::move(val))).second)
- {
- span.error(STRPRINTF("Redefinition of constant '%s'"_fmt, name));
- return false;
- }
- return true;
- }
- static
- const val_t *find_constant(RString name)
- {
- auto it = const_defm.find(name);
- if (it != const_defm.end())
- return &it->second;
-
- return nullptr;
- }
- static
- dumb_ptr<effect_t> set_effect_continuation(dumb_ptr<effect_t> src, dumb_ptr<effect_t> continuation)
- {
- dumb_ptr<effect_t> retval = src;
- /* This function is completely analogous to `spellguard_implication' above; read the control flow implications above first before pondering it. */
-
- if (src == continuation)
- return retval;
-
- /* 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. */
- MATCH_BEGIN (*src)
- {
- MATCH_CASE (EffectIf&, e_if)
- {
- set_effect_continuation(e_if.true_branch, continuation);
- set_effect_continuation(e_if.false_branch, continuation);
- }
- }
- MATCH_END ();
-
- if (src->next)
- set_effect_continuation(src->next, continuation);
- else
- src->next = continuation;
-
- 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;
-
- if (a == b)
- {
- /* This can happen due to reference sharing:
- * e.g.,
- * (R0 -> (R1 | R2)) => (R3)
- * yields
- * (R0 -> (R1 -> R3 | R2 -> R3))
- *
- * So if we now add => R4 to that, we want
- * (R0 -> (R1 -> R3 -> R4 | R2 -> R3 -> R4))
- *
- * but we only need to add it once, because the R3 reference is shared.
- */
- return retval;
- }
-
- /* If the premise is a disjunction, b is the continuation of _all_ branches */
- MATCH_BEGIN (*a)
- {
- MATCH_CASE (const GuardChoice&, s)
- {
- spellguard_implication(s.s_alt, b);
- }
- }
- MATCH_END ();
-
- if (a->next)
- spellguard_implication(a->next, b);
- else
- // this is the important bit
- a->next = b;
-
- return retval;
- }
-
-
- static
- bool add_spell(io::LineSpan span, dumb_ptr<spell_t> spell)
- {
- auto pair1 = magic_conf.spells_by_name.insert({spell->name, spell});
- if (!pair1.second)
- {
- span.error(STRPRINTF("Attempt to redefine spell '%s'"_fmt, spell->name));
- return false;
- }
-
- auto pair2 = magic_conf.spells_by_invocation.insert({spell->invocation, spell});
- if (!pair2.second)
- {
- span.error(STRPRINTF("Attempt to redefine spell invocation '%s'"_fmt, spell->invocation));
- magic_conf.spells_by_name.erase(pair1.first);
- return false;
- }
- return true;
- }
- static
- bool add_teleport_anchor(io::LineSpan span, dumb_ptr<teleport_anchor_t> anchor)
- {
- auto pair1 = magic_conf.anchors_by_name.insert({anchor->name, anchor});
- if (!pair1.second)
- {
- span.error(STRPRINTF("Attempt to redefine teleport anchor '%s'"_fmt, anchor->name));
- return false;
- }
-
- auto pair2 = magic_conf.anchors_by_invocation.insert({anchor->name, anchor});
- if (!pair2.second)
- {
- span.error(STRPRINTF("Attempt to redefine anchor invocation '%s'"_fmt, anchor->invocation));
- magic_conf.anchors_by_name.erase(pair1.first);
- return false;
- }
- return true;
- }
-
- static
- bool install_proc(io::LineSpan span, dumb_ptr<proc_t> proc)
- {
- RString name = proc->name;
- if (!procs.insert({name, std::move(*proc)}).second)
- {
- span.error("procedure already exists"_s);
- return false;
- }
- return true;
- }
- static
- bool call_proc(io::LineSpan span, ZString name, dumb_ptr<std::vector<dumb_ptr<expr_t>>> argvp, dumb_ptr<effect_t>& retval)
- {
- auto pi = procs.find(name);
- if (pi == procs.end())
- {
- span.error(STRPRINTF("Unknown procedure '%s'"_fmt, name));
- return false;
- }
-
- proc_t *p = &pi->second;
-
- if (p->argv.size() != argvp->size())
- {
- span.error(STRPRINTF("Procedure %s/%zu invoked with %zu parameters"_fmt,
- name, p->argv.size(), argvp->size()));
- return false;
- }
-
- 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
- bool op_effect(io::LineSpan span, ZString name, Slice<dumb_ptr<expr_t>> argv, dumb_ptr<effect_t>& effect)
- {
- op_t *op = magic_get_op(name);
- if (!op)
- {
- span.error(STRPRINTF("Unknown operation '%s'"_fmt, name));
- return false;
- }
- if (op->signature.size() != argv.size())
- {
- span.error(STRPRINTF("Incorrect number of arguments to operation '%s': Expected %zu, found %zu"_fmt,
- name, op->signature.size(), argv.size()));
- return false;
- }
-
- 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);
- e_op.args_nr = argv.size();
-
- 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)
- {
- 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;
- }
- static
- bool fun_expr(io::LineSpan span, ZString name, Slice<dumb_ptr<expr_t>> argv, dumb_ptr<expr_t>& expr)
- {
- fun_t *fun = magic_get_fun(name);
- if (!fun)
- {
- span.error(STRPRINTF("Unknown function '%s'"_fmt, name));
- return false;
- }
- if (fun->signature.size() != argv.size())
- {
- span.error(STRPRINTF("Incorrect number of arguments to function '%s': Expected %zu, found %zu"_fmt,
- name, fun->signature.size(), argv.size()));
- return false;
- }
- 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);
- e_funapp.args_nr = argv.size();
-
- std::copy(argv.begin(), argv.end(), e_funapp.args);
- expr = dumb_ptr<expr_t>::make(e_funapp);
- return true;
- }
- static
- dumb_ptr<expr_t> BIN_EXPR(io::LineSpan span, ZString name, dumb_ptr<expr_t> left, dumb_ptr<expr_t> right)
- {
- dumb_ptr<expr_t> e[2];
- e[0] = left;
- e[1] = right;
- dumb_ptr<expr_t> rv;
- if (!fun_expr(span, name, e, rv))
- abort();
- return rv;
- }
-
- static
- bool fail(const sexpr::SExpr& s, ZString msg)
- {
- s._span.error(msg);
- return false;
- }
-}
-
-namespace magic_v2
-{
- using sexpr::SExpr;
-
- static
- bool parse_expression(const SExpr& x, dumb_ptr<expr_t>& out);
- static
- bool parse_effect(const SExpr& s, dumb_ptr<effect_t>& out);
- static
- bool parse_spellguard(const SExpr& s, dumb_ptr<spellguard_t>& out);
- static
- bool parse_spellbody(const SExpr& s, dumb_ptr<spellguard_t>& out);
-
- // Note: anything with dumb_ptr leaks memory on failure
- // once this is all done, we can convert it to unique_ptr
- // (may require bimaps somewhere)
- static
- bool is_comment(const SExpr& s)
- {
- if (s._type == sexpr::STRING)
- return true;
- if (s._type != sexpr::LIST)
- return false;
- if (s._list.empty())
- return false;
- if (s._list[0]._type != sexpr::TOKEN)
- return false;
- return s._list[0]._str == "DISABLED"_s;
- }
-
- static
- bool parse_loc(const SExpr& s, e_location_t& loc)
- {
- if (s._type != sexpr::LIST)
- return fail(s, "loc not list"_s);
- if (s._list.size() != 4)
- return fail(s, "loc not 3 args"_s);
- if (s._list[0]._type != sexpr::TOKEN)
- return fail(s._list[0], "loc cmd not tok"_s);
- if (s._list[0]._str != "@"_s)
- return fail(s._list[0], "loc cmd not cmd"_s);
- return parse_expression(s._list[1], loc.m)
- && parse_expression(s._list[2], loc.x)
- && parse_expression(s._list[3], loc.y);
- }
-
- static
- bool parse_expression(const SExpr& x, dumb_ptr<expr_t>& out)
- {
- switch (x._type)
- {
- case sexpr::INT:
- {
- val_t val;
- 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 = dumb_ptr<expr_t>::make(std::move(val));
- return true;
- }
- case sexpr::STRING:
- {
- val_t val;
- val = ValString{x._str};
-
- out = dumb_ptr<expr_t>::make(std::move(val));
- return true;
- }
- case sexpr::TOKEN:
- {
- earray<LString, DIR, DIR::COUNT> dirs //=
- {{
- "S"_s, "SW"_s, "W"_s, "NW"_s,
- "N"_s, "NE"_s, "E"_s, "SE"_s,
- }};
- auto begin = std::begin(dirs);
- auto end = std::end(dirs);
- auto it = std::find(begin, end, x._str);
- if (it != end)
- {
- val_t val;
- val = ValDir{static_cast<DIR>(it - begin)};
-
- out = dumb_ptr<expr_t>::make(std::move(val));
- return true;
- }
- }
- {
- if (const val_t *val = find_constant(x._str))
- {
- val_t copy;
- magic_copy_var(&copy, val);
- out = dumb_ptr<expr_t>::make(std::move(copy));
- return true;
- }
- else
- {
- ExprId e;
- e.e_id = intern_id(x._str);
- out = dumb_ptr<expr_t>::make(e);
- return true;
- }
- }
- break;
- case sexpr::LIST:
- if (x._list.empty())
- return fail(x, "empty list"_s);
- {
- if (x._list[0]._type != sexpr::TOKEN)
- return fail(x._list[0], "op not token"_s);
- ZString op = x._list[0]._str;
- // area
- if (op == "@"_s)
- {
- e_location_t loc;
- if (!parse_loc(x, loc))
- return false;
- out = dumb_ptr<expr_t>::make(loc);
- return true;
- }
- if (op == "@+"_s)
- {
- e_location_t loc;
- dumb_ptr<expr_t> width;
- dumb_ptr<expr_t> height;
- if (!parse_loc(x._list[1], loc))
- return false;
- if (!parse_expression(x._list[2], width))
- return false;
- if (!parse_expression(x._list[3], height))
- return false;
- 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)
- {
- e_location_t loc;
- dumb_ptr<expr_t> dir;
- dumb_ptr<expr_t> width;
- dumb_ptr<expr_t> depth;
- if (!parse_loc(x._list[1], loc))
- return false;
- if (!parse_expression(x._list[2], dir))
- return false;
- if (!parse_expression(x._list[3], width))
- return false;
- if (!parse_expression(x._list[4], depth))
- return false;
- 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)
- {
- if (x._list.size() != 3)
- return fail(x, ". not 2"_s);
- dumb_ptr<expr_t> expr;
- if (!parse_expression(x._list[1], expr))
- return false;
- if (x._list[2]._type != sexpr::TOKEN)
- return fail(x._list[2], ".elem not name"_s);
- ZString elem = x._list[2]._str;
- out = dot_expr(expr, intern_id(elem));
- return true;
- }
- static // TODO LString
- std::set<ZString> ops =
- {
- "<"_s, ">"_s, "<="_s, ">="_s, "=="_s, "!="_s,
- "+"_s, "-"_s, "*"_s, "%"_s, "/"_s,
- "&"_s, "^"_s, "|"_s, "<<"_s, ">>"_s,
- "&&"_s, "||"_s,
- };
- // TODO implement unary operators
- if (ops.count(op))
- {
- // operators are n-ary and left-associative
- if (x._list.size() < 3)
- return fail(x, "operator not at least 2 args"_s);
- auto begin = x._list.begin() + 1;
- auto end = x._list.end();
- if (!parse_expression(*begin, out))
- return false;
- ++begin;
- for (; begin != end; ++begin)
- {
- dumb_ptr<expr_t> tmp;
- if (!parse_expression(*begin, tmp))
- return false;
- out = BIN_EXPR(x._span, op, out, tmp);
- }
- return true;
- }
- std::vector<dumb_ptr<expr_t>> argv;
- for (auto it = x._list.begin() + 1, end = x._list.end(); it != end; ++it)
- {
- dumb_ptr<expr_t> expr;
- if (!parse_expression(*it, expr))
- return false;
- argv.push_back(expr);
- }
- return fun_expr(x._span, op, argv, out);
- }
- break;
- }
- abort();
- }
-
- static
- bool parse_item(const SExpr& s, ItemNameId& id, int& count)
- {
- if (s._type == sexpr::STRING)
- {
- count = 1;
-
- Borrowed<item_data> item = TRY_UNWRAP(itemdb_searchname(s._str),
- return fail(s, "no such item"_s)
- );
- id = item->nameid;
- return true;
- }
- if (s._type != sexpr::LIST)
- return fail(s, "item not string or list"_s);
- if (s._list.size() != 2)
- return fail(s, "item list is not pair"_s);
- if (s._list[0]._type != sexpr::INT)
- return fail(s._list[0], "item pair first not int"_s);
- count = s._list[0]._int;
- if (s._list[1]._type != sexpr::STRING)
- return fail(s._list[1], "item pair second not name"_s);
-
- Borrowed<item_data> item = TRY_UNWRAP(itemdb_searchname(s._list[1]._str),
- return fail(s, "no such item"_s)
- );
- id = item->nameid;
- return true;
- }
-
- static
- bool parse_spellguard(const SExpr& s, dumb_ptr<spellguard_t>& out)
- {
- if (s._type != sexpr::LIST)
- return fail(s, "not list"_s);
- if (s._list.empty())
- return fail(s, "empty list"_s);
- if (s._list[0]._type != sexpr::TOKEN)
- return fail(s._list[0], "not token"_s);
- ZString cmd = s._list[0]._str;
- if (cmd == "OR"_s)
- {
- auto begin = s._list.begin() + 1;
- auto end = s._list.end();
- if (begin == end)
- return fail(s, "missing arguments"_s);
- if (!parse_spellguard(*begin, out))
- return false;
- ++begin;
- for (; begin != end; ++begin)
- {
- dumb_ptr<spellguard_t> alt;
- if (!parse_spellguard(*begin, alt))
- return false;
- GuardChoice choice;
- auto next = out;
- choice.s_alt = alt;
- out = dumb_ptr<spellguard_t>::make(choice, next);
- }
- return true;
- }
- if (cmd == "GUARD"_s)
- {
- auto begin = s._list.begin() + 1;
- auto end = s._list.end();
- while (is_comment(end[-1]))
- --end;
- if (begin == end)
- return fail(s, "missing arguments"_s);
- if (!parse_spellguard(end[-1], out))
- return false;
- --end;
- for (; begin != end; --end)
- {
- if (is_comment(end[-1]))
- continue;
- dumb_ptr<spellguard_t> implier;
- if (!parse_spellguard(end[-1], implier))
- return false;
- out = spellguard_implication(implier, out);
- }
- return true;
- }
- if (cmd == "REQUIRE"_s)
- {
- if (s._list.size() != 2)
- return fail(s, "not one argument"_s);
- dumb_ptr<expr_t> condition;
- if (!parse_expression(s._list[1], condition))
- return false;
- GuardCondition cond;
- cond.s_condition = condition;
- out = dumb_ptr<spellguard_t>::make(cond, nullptr);
- return true;
- }
- if (cmd == "MANA"_s)
- {
- if (s._list.size() != 2)
- return fail(s, "not one argument"_s);
- dumb_ptr<expr_t> mana;
- if (!parse_expression(s._list[1], mana))
- return false;
- GuardMana sp;
- sp.s_mana = mana;
- out = dumb_ptr<spellguard_t>::make(sp, nullptr);
- return true;
- }
- if (cmd == "CASTTIME"_s)
- {
- if (s._list.size() != 2)
- return fail(s, "not one argument"_s);
- dumb_ptr<expr_t> casttime;
- if (!parse_expression(s._list[1], casttime))
- return false;
- GuardCastTime ct;
- ct.s_casttime = casttime;
- out = dumb_ptr<spellguard_t>::make(ct, nullptr);
- return true;
- }
- if (cmd == "CATALYSTS"_s)
- {
- dumb_ptr<component_t> items = nullptr;
- for (auto it = s._list.begin() + 1, end = s._list.end(); it != end; ++it)
- {
- ItemNameId id;
- int count;
- if (!parse_item(*it, id, count))
- return false;
- magic_add_component(&items, id, count);
- }
- GuardCatalysts cat;
- cat.s_catalysts = items;
- out = dumb_ptr<spellguard_t>::make(cat, nullptr);
- return true;
- }
- if (cmd == "COMPONENTS"_s)
- {
- dumb_ptr<component_t> items = nullptr;
- for (auto it = s._list.begin() + 1, end = s._list.end(); it != end; ++it)
- {
- ItemNameId id;
- int count;
- if (!parse_item(*it, id, count))
- return false;
- magic_add_component(&items, id, count);
- }
- GuardComponents comp;
- comp.s_components = items;
- out = dumb_ptr<spellguard_t>::make(comp, nullptr);
- return true;
- }
- return fail(s._list[0], "unknown guard"_s);
- }
-
- static
- bool build_effect_list(std::vector<SExpr>::const_iterator begin,
- std::vector<SExpr>::const_iterator end, dumb_ptr<effect_t>& out)
- {
- // these backward lists could be forward by keeping the reference
- // I know this is true because Linus said so
- out = dumb_ptr<effect_t>::make(EffectSkip{}, nullptr);
- while (end != begin)
- {
- const SExpr& s = *--end;
- if (is_comment(s))
- continue;
- dumb_ptr<effect_t> chain;
- if (!parse_effect(s, chain))
- return false;
- out = set_effect_continuation(chain, out);
- }
- return true;
- }
-
- static
- bool parse_effect(const SExpr& s, dumb_ptr<effect_t>& out)
- {
- if (s._type != sexpr::LIST)
- return fail(s, "not list"_s);
- if (s._list.empty())
- return fail(s, "empty list"_s);
- if (s._list[0]._type != sexpr::TOKEN)
- return fail(s._list[0], "not token"_s);
- ZString cmd = s._list[0]._str;
- if (cmd == "BLOCK"_s)
- {
- return build_effect_list(s._list.begin() + 1, s._list.end(), out);
- }
- if (cmd == "SET"_s)
- {
- if (s._list.size() != 3)
- return fail(s, "not 2 args"_s);
- if (s._list[1]._type != sexpr::TOKEN)
- return fail(s._list[1], "not token"_s);
- ZString name = s._list[1]._str;
- if (find_constant(name))
- return fail(s._list[1], "assigning to constant"_s);
- dumb_ptr<expr_t> expr;
- if (!parse_expression(s._list[2], expr))
- return false;
-
- 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)
- {
- if (s._list.size() != 2)
- return fail(s, "not 1 arg"_s);
- if (s._list[1]._type != sexpr::STRING)
- return fail(s._list[1], "not string"_s);
- ZString body = s._list[1]._str;
- auto begin = s._list[1]._span.begin;
- io::LineCharReader lr(io::from_string, begin.filename, body, begin.line, begin.column);
- ast::script::ScriptOptions opt;
- opt.implicit_start = true;
- opt.implicit_end = true;
- opt.no_event = true;
- auto code_res = ast::script::parse_script_body(lr, opt);
- if (code_res.get_failure())
- {
- PRINTF("%s\n"_fmt, code_res.get_failure());
- }
- auto code = TRY_UNWRAP(code_res.get_success(),
- return fail(s._list[1], "script does not compile"_s));
- std::unique_ptr<const ScriptBuffer> script = compile_script(STRPRINTF("script magic %s:%d"_fmt, begin.filename, begin.line), code, true);
- if (!script)
- return fail(s._list[1], "script does not compile"_s);
- 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 = 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 = 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 = 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 = dumb_ptr<effect_t>::make(EffectBreak{}, nullptr);
- return true;
- }
- if (cmd == "FOREACH"_s)
- {
- if (s._list.size() != 5)
- return fail(s, "not 4 arg"_s);
- if (s._list[1]._type != sexpr::TOKEN)
- return fail(s._list[1], "foreach type not token"_s);
- ZString type = s._list[1]._str;
- FOREACH_FILTER filter;
- if (type == "PC"_s)
- filter = FOREACH_FILTER::PC;
- else if (type == "MOB"_s)
- filter = FOREACH_FILTER::MOB;
- else if (type == "ENTITY"_s)
- filter = FOREACH_FILTER::ENTITY;
- else if (type == "SPELL"_s)
- filter = FOREACH_FILTER::SPELL;
- else if (type == "TARGET"_s)
- filter = FOREACH_FILTER::TARGET;
- else if (type == "NPC"_s)
- filter = FOREACH_FILTER::NPC;
- else
- return fail(s._list[1], "unknown foreach filter"_s);
- if (s._list[2]._type != sexpr::TOKEN)
- return fail(s._list[2], "foreach var not token"_s);
- ZString var = s._list[2]._str;
- dumb_ptr<expr_t> area;
- dumb_ptr<effect_t> effect;
- if (!parse_expression(s._list[3], area))
- return false;
- if (!parse_effect(s._list[4], effect))
- return false;
-
- 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)
- {
- if (s._list.size() != 5)
- return fail(s, "not 4 arg"_s);
- if (s._list[1]._type != sexpr::TOKEN)
- return fail(s._list[1], "for var not token"_s);
- ZString var = s._list[1]._str;
- dumb_ptr<expr_t> low;
- dumb_ptr<expr_t> high;
- dumb_ptr<effect_t> effect;
- if (!parse_expression(s._list[2], low))
- return false;
- if (!parse_expression(s._list[3], high))
- return false;
- if (!parse_effect(s._list[4], effect))
- return false;
-
- 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)
- {
- if (s._list.size() != 3 && s._list.size() != 4)
- return fail(s, "not 2 or 3 args"_s);
- dumb_ptr<expr_t> cond;
- dumb_ptr<effect_t> if_true;
- dumb_ptr<effect_t> if_false;
- if (!parse_expression(s._list[1], cond))
- return false;
- if (!parse_effect(s._list[2], if_true))
- return false;
- if (s._list.size() == 4)
- {
- if (!parse_effect(s._list[3], if_false))
- return false;
- }
- else
- 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)
- {
- if (s._list.size() != 2)
- return fail(s, "not 1 arg"_s);
- dumb_ptr<expr_t> expr;
- if (!parse_expression(s._list[1], expr))
- return false;
- EffectSleep e;
- e.e_sleep = expr;
- out = dumb_ptr<effect_t>::make(e, nullptr);
- return true;
- }
- if (cmd == "CALL"_s)
- {
- if (s._list.size() < 2)
- return fail(s, "call what?"_s);
- if (s._list[1]._type != sexpr::TOKEN)
- return fail(s._list[1], "call token please"_s);
- ZString func = s._list[1]._str;
- auto argvp = dumb_ptr<std::vector<dumb_ptr<expr_t>>>::make();
- for (auto it = s._list.begin() + 2, end = s._list.end(); it != end; ++it)
- {
- dumb_ptr<expr_t> expr;
- if (!parse_expression(*it, expr))
- return false;
- argvp->push_back(expr);
- }
- return call_proc(s._span, func, argvp, out);
- }
- auto argv = std::vector<dumb_ptr<expr_t>>();
- for (auto it = s._list.begin() + 1, end = s._list.end(); it != end; ++it)
- {
- dumb_ptr<expr_t> expr;
- if (!parse_expression(*it, expr))
- return false;
- argv.push_back(expr);
- }
- return op_effect(s._span, cmd, argv, out);
- }
-
- static
- bool parse_spellbody(const SExpr& s, dumb_ptr<spellguard_t>& out)
- {
- if (s._type != sexpr::LIST)
- return fail(s, "not list"_s);
- if (s._list.empty())
- return fail(s, "empty list"_s);
- if (s._list[0]._type != sexpr::TOKEN)
- return fail(s._list[0], "not token"_s);
- ZString cmd = s._list[0]._str;
- if (cmd == "=>"_s)
- {
- if (s._list.size() != 3)
- return fail(s, "list does not have exactly 2 arguments"_s);
- dumb_ptr<spellguard_t> guard;
- if (!parse_spellguard(s._list[1], guard))
- return false;
- dumb_ptr<spellguard_t> body;
- if (!parse_spellbody(s._list[2], body))
- return false;
- out = spellguard_implication(guard, body);
- return true;
- }
- if (cmd == "|"_s)
- {
- if (s._list.size() == 1)
- return fail(s, "spellbody choice empty"_s);
- auto begin = s._list.begin() + 1;
- auto end = s._list.end();
- if (!parse_spellbody(*begin, out))
- return false;
- ++begin;
- for (; begin != end; ++begin)
- {
- dumb_ptr<spellguard_t> alt;
- if (!parse_spellbody(*begin, alt))
- return false;
- auto tmp = out;
- GuardChoice choice;
- choice.s_alt = alt;
- out = dumb_ptr<spellguard_t>::make(choice, tmp);
- }
- return true;
- }
- if (cmd == "EFFECT"_s)
- {
- auto begin = s._list.begin() + 1;
- auto end = s._list.end();
-
- dumb_ptr<effect_t> effect, attrig, atend;
-
- // decreasing end can never pass begin, since we know that
- // begin[-1] is token EFFECT
- while (is_comment(end[-1]))
- --end;
- if (end[-1]._type == sexpr::LIST && !end[-1]._list.empty()
- && end[-1]._list[0]._type == sexpr::TOKEN
- && end[-1]._list[0]._str == "ATEND"_s)
- {
- auto atb = end[-1]._list.begin() + 1;
- auto ate = end[-1]._list.end();
- if (!build_effect_list(atb, ate, atend))
- return false;
- --end;
-
- while (is_comment(end[-1]))
- --end;
- }
- else
- {
- atend = nullptr;
- }
- if (end[-1]._type == sexpr::LIST && !end[-1]._list.empty()
- && end[-1]._list[0]._type == sexpr::TOKEN
- && end[-1]._list[0]._str == "ATTRIGGER"_s)
- {
- auto atb = end[-1]._list.begin() + 1;
- auto ate = end[-1]._list.end();
- if (!build_effect_list(atb, ate, attrig))
- return false;
- --end;
- }
- else
- {
- attrig = nullptr;
- }
- if (!build_effect_list(begin, end, effect))
- return false;
- 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);
- }
-
- static
- bool parse_top_set(const std::vector<SExpr>& in)
- {
- if (in.size() != 3)
- return fail(in[0], "not 2 arguments"_s);
- ZString name = in[1]._str;
- dumb_ptr<expr_t> expr;
- if (!parse_expression(in[2], expr))
- return false;
- if (find_constant(name))
- return fail(in[1], "assign constant"_s);
- size_t var_id = intern_id(name);
- magic_eval(dumb_ptr<env_t>(&magic_default_env), &magic_conf.varv[var_id].val, expr);
- return true;
- }
- static
- bool parse_const(io::LineSpan span, const std::vector<SExpr>& in)
- {
- if (in.size() != 3)
- return fail(in[0], "not 2 arguments"_s);
- if (in[1]._type != sexpr::TOKEN)
- return fail(in[1], "not token"_s);
- ZString name = in[1]._str;
- dumb_ptr<expr_t> expr;
- if (!parse_expression(in[2], expr))
- return false;
- val_t tmp;
- magic_eval(dumb_ptr<env_t>(&magic_default_env), &tmp, expr);
- return bind_constant(span, name, std::move(tmp));
- }
- static
- bool parse_anchor(io::LineSpan span, const std::vector<SExpr>& in)
- {
- if (in.size() != 4)
- return fail(in[0], "not 3 arguments"_s);
- auto anchor = dumb_ptr<teleport_anchor_t>::make();
- if (in[1]._type != sexpr::TOKEN)
- return fail(in[1], "not token"_s);
- anchor->name = in[1]._str;
- if (in[2]._type != sexpr::STRING)
- return fail(in[2], "not string"_s);
- anchor->invocation = in[2]._str;
- dumb_ptr<expr_t> expr;
- if (!parse_expression(in[3], expr))
- return false;
- anchor->location = expr;
- return add_teleport_anchor(span, anchor);
- }
- static
- bool parse_proc(io::LineSpan span, const std::vector<SExpr>& in)
- {
- if (in.size() < 4)
- return fail(in[0], "not at least 3 arguments"_s);
- auto proc = dumb_ptr<proc_t>::make();
- if (in[1]._type != sexpr::TOKEN)
- return fail(in[1], "name not token"_s);
- proc->name = in[1]._str;
- if (in[2]._type != sexpr::LIST)
- return fail(in[2], "args not list"_s);
- for (const SExpr& arg : in[2]._list)
- {
- if (arg._type != sexpr::TOKEN)
- return fail(arg, "arg not token"_s);
- proc->argv.push_back(intern_id(arg._str));
- }
- if (!build_effect_list(in.begin() + 3, in.end(), proc->body))
- return false;
- return install_proc(span, proc);
- }
- static
- bool parse_spell(io::LineSpan span, const std::vector<SExpr>& in)
- {
- if (in.size() < 6)
- return fail(in[0], "not at least 5 arguments"_s);
- if (in[1]._type != sexpr::LIST)
- return fail(in[1], "flags not list"_s);
-
- auto spell = dumb_ptr<spell_t>::make();
-
- for (const SExpr& s : in[1]._list)
- {
- if (s._type != sexpr::TOKEN)
- return fail(s, "flag not token"_s);
- SPELL_FLAG flag = SPELL_FLAG::ZERO;
- if (s._str == "LOCAL"_s)
- flag = SPELL_FLAG::LOCAL;
- else if (s._str == "NONMAGIC"_s)
- flag = SPELL_FLAG::NONMAGIC;
- else if (s._str == "SILENT"_s)
- flag = SPELL_FLAG::SILENT;
- else
- return fail(s, "unknown flag"_s);
- if (bool(spell->flags & flag))
- return fail(s, "duplicate flag"_s);
- spell->flags |= flag;
- }
- if (in[2]._type != sexpr::TOKEN)
- return fail(in[2], "name not token"_s);
- spell->name = in[2]._str;
- if (in[3]._type != sexpr::STRING)
- return fail(in[3], "invoc not string"_s);
- spell->invocation = in[3]._str;
- if (in[4]._type != sexpr::LIST)
- return fail(in[4], "spellarg not list"_s);
- if (in[4]._list.size() == 0)
- {
- spell->spellarg_ty = SPELLARG::NONE;
- }
- else
- {
- if (in[4]._list.size() != 2)
- return fail(in[4], "spellarg not empty list or pair"_s);
- if (in[4]._list[0]._type != sexpr::TOKEN)
- return fail(in[4]._list[0], "spellarg type not token"_s);
- if (in[4]._list[1]._type != sexpr::TOKEN)
- return fail(in[4]._list[1], "spellarg name not token"_s);
- ZString ty = in[4]._list[0]._str;
- if (ty == "PC"_s)
- spell->spellarg_ty = SPELLARG::PC;
- else if (ty == "STRING"_s)
- spell->spellarg_ty = SPELLARG::STRING;
- else
- return fail(in[4]._list[0], "unknown spellarg type"_s);
- ZString an = in[4]._list[1]._str;
- spell->arg = intern_id(an);
- }
- std::vector<SExpr>::const_iterator it = in.begin() + 5;
- for (;; ++it)
- {
- if (it == in.end())
- return fail(it[-1], "end of list scanning LET defs"_s);
- if (is_comment(*it))
- continue;
- if (it->_type != sexpr::LIST || it->_list.empty())
- break;
- if (it->_list[0]._type != sexpr::TOKEN || it->_list[0]._str != "LET"_s)
- break;
-
- if (it->_list[1]._type != sexpr::TOKEN)
- return fail(it->_list[1], "let name not token"_s);
- ZString name = it->_list[1]._str;
- if (find_constant(name))
- return fail(it->_list[1], "constant exists"_s);
- dumb_ptr<expr_t> expr;
- if (!parse_expression(it->_list[2], expr))
- return false;
- letdef_t let;
- let.id = intern_id(name);
- let.expr = expr;
- spell->letdefv.push_back(let);
- }
- if (it + 1 != in.end())
- return fail(*it, "expected only one body entry besides LET"_s);
-
- // formally, 'guard' only refers to the first argument of '=>'
- // but internally, spellbodies use the same thing
- dumb_ptr<spellguard_t> guard;
- if (!parse_spellbody(*it, guard))
- return false;
- spell->spellguard = guard;
- return add_spell(span, spell);
- }
-
- static
- bool parse_top(io::LineSpan span, const std::vector<SExpr>& vs)
- {
- if (vs.empty())
- {
- span.error("Empty list at top"_s);
- return false;
- }
- if (vs[0]._type != sexpr::TOKEN)
- return fail(vs[0], "top not token"_s);
- ZString cmd = vs[0]._str;
- if (cmd == "CONST"_s)
- return parse_const(span, vs);
- if (cmd == "PROCEDURE"_s)
- return parse_proc(span, vs);
- if (cmd == "SET"_s)
- return parse_top_set(vs);
- if (cmd == "SPELL"_s)
- return parse_spell(span, vs);
- if (cmd == "TELEPORT-ANCHOR"_s)
- return parse_anchor(span, vs);
- return fail(vs[0], "Unknown top-level command"_s);
- }
-
- static
- bool loop(sexpr::Lexer& in)
- {
- SExpr s;
- while (sexpr::parse(in, s))
- {
- if (is_comment(s))
- continue;
- if (s._type != sexpr::LIST)
- return fail(s, "top-level entity not a list or comment"_s);
- if (!parse_top(s._span, s._list))
- return false;
- }
- // handle low-level errors
- if (in.peek() != sexpr::TOK_EOF)
- {
- in.span().error("parser gave up before end of file"_s);
- return false;
- }
- return true;
- }
-} // namespace magic_v2
-
-bool magic_init0()
-{
- return magic_v2::init0();
-}
-
-bool load_magic_file_v2(ZString filename)
-{
- sexpr::Lexer in(filename);
- bool rv = magic_v2::loop(in);
- if (!rv)
- {
- in.span().error(STRPRINTF("next token: %s '%s'"_fmt, sexpr::token_name(in.peek()), in.val_string()));
- }
- return rv;
-}
-} // namespace magic
-} // namespace map
-} // namespace tmwa
diff --git a/src/map/magic-v2.hpp b/src/map/magic-v2.hpp
deleted file mode 100644
index fac2773..0000000
--- a/src/map/magic-v2.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#pragma once
-// magic-v2.hpp - second generation magic parser
-//
-// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include "fwd.hpp"
-
-#include "../strings/zstring.hpp"
-
-
-namespace tmwa
-{
-namespace map
-{
-namespace magic
-{
-bool magic_init0();
-// must be called after itemdb initialization
-bool load_magic_file_v2(ZString filename);
-} // namespace magic
-} // namespace map
-} // namespace tmwa
diff --git a/src/map/magic.cpp b/src/map/magic.cpp
deleted file mode 100644
index 418312a..0000000
--- a/src/map/magic.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-#include "magic.hpp"
-// magic.cpp - Entry to the magic system.
-//
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include <algorithm>
-#include <utility>
-
-#include "../strings/xstring.hpp"
-
-#include "../generic/dumb_ptr.hpp"
-
-#include "../io/cxxstdio.hpp"
-
-#include "globals.hpp"
-#include "magic-expr.hpp"
-#include "magic-interpreter.hpp"
-#include "magic-interpreter-base.hpp"
-#include "magic-stmt.hpp"
-#include "map.hpp"
-#include "pc.hpp"
-
-#include "../poison.hpp"
-
-
-namespace tmwa
-{
-namespace map
-{
-namespace magic
-{
-/// Return a pair of strings, {spellname, parameter}
-/// Parameter may be empty.
-static
-std::pair<XString, XString> magic_tokenise(XString src)
-{
- auto seeker = std::find(src.begin(), src.end(), ' ');
-
- if (seeker == src.end())
- {
- return {src, XString()};
- }
- else
- {
- XString rv1 = src.xislice_h(seeker);
- ++seeker;
-
- while (seeker != src.end() && *seeker == ' ')
- ++seeker;
-
- // Note: this very well could be empty
- XString rv2 = src.xislice_t(seeker);
- return {rv1, rv2};
- }
-}
-
-int magic_message(dumb_ptr<map_session_data> caster, XString source_invocation)
-{
- if (pc_isdead(caster))
- return 0;
- if (bool(caster->status.option & Opt0::HIDE))
- return 0; // No spellcasting while hidden
-
- int power = caster->matk1;
-
- // This was the only thing worth saving from magic_preprocess_message.
- // May it rest only, and never rise again.
- // For more information on how this code worked, travel through time
- // and watch all the comments I wrote for myself while trying to figure
- // out if it was safe to delete.
- if (caster->state.shroud_active && caster->state.shroud_disappears_on_talk)
- magic_unshroud(caster);
-
- auto pair = magic_tokenise(source_invocation);
- XString spell_invocation = pair.first;
- XString parameter = pair.second;
-
- dumb_ptr<spell_t> spell = magic_find_spell(spell_invocation);
-
- if (spell)
- {
- int near_miss;
- dumb_ptr<env_t> env =
- spell_create_env(&magic_conf, spell, caster, power, parameter);
- 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;
-
- MAP_LOG_PC(caster, "CAST %s %s"_fmt,
- spell->name, effects ? "SUCCESS"_s : "FAILURE"_s);
-
- if (effects)
- {
- dumb_ptr<invocation> invocation = spell_instantiate(effects, env);
-
- spell_bind(caster, invocation);
- spell_execute(invocation);
-
- return bool(spell->flags & SPELL_FLAG::SILENT) ? -1 : 1;
- }
- else
- magic_free_env(env);
-
- return 1;
- }
-
- return 0; /* Not a spell */
-}
-} // namespace magic
-} // namespace map
-} // namespace tmwa
diff --git a/src/map/magic.hpp b/src/map/magic.hpp
deleted file mode 100644
index 70d40dc..0000000
--- a/src/map/magic.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#pragma once
-// magic.hpp - Entry to the magic system.
-//
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include "fwd.hpp"
-
-#include "map.t.hpp"
-#include "../mmo/skill.t.hpp"
-
-
-namespace tmwa
-{
-namespace map
-{
-namespace magic
-{
-/**
- * Try to cast magic.
- *
- * As an intended side effect, the magic message may be distorted (text only).
- * No, it can't. Thank God.
- *
- * \param caster Player attempting to cast magic
- * \param source_invocation The prospective incantation
- * \return 1 or -1 if the input message was magic and was handled by this function, 0 otherwise. -1 is returned when the
- * message should not be repeated.
- */
-int magic_message(dumb_ptr<map_session_data> caster, XString source_invocation);
-} // namespace magic
-} // namespace map
-} // namespace tmwa
diff --git a/src/map/map.cpp b/src/map/map.cpp
index d40977f..362d5d2 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -69,9 +69,6 @@
#include "globals.hpp"
#include "grfio.hpp"
#include "itemdb.hpp"
-#include "magic-interpreter.hpp" // for is_spell inline body
-#include "magic-stmt.hpp"
-#include "magic-v2.hpp"
#include "map_conf.hpp"
#include "mob.hpp"
#include "quest.hpp"
@@ -1454,9 +1451,6 @@ void cleanup_sub(dumb_ptr<block_list> bl)
case BL::ITEM:
map_clearflooritem(bl->bl_id);
break;
- case BL::SPELL:
- magic::spell_free_invocation(bl->is_spell());
- break;
}
}
@@ -1497,8 +1491,6 @@ bool map_confs(io::Spanned<XString> key, io::Spanned<ZString> value)
return mob_readskilldb(value.data);
if (key.data == "skill_db"_s)
return skill_readdb(value.data);
- if (key.data == "magic_conf"_s)
- return magic::load_magic_file_v2(value.data);
if (key.data == "resnametable"_s)
return load_resnametable(value.data);
@@ -1515,16 +1507,7 @@ int map_scriptcont(dumb_ptr<map_session_data> sd, BlockId id)
if (!bl)
return 0;
- switch (bl->bl_type)
- {
- case BL::NPC:
- return npc_scriptcont(sd, id);
- case BL::SPELL:
- magic::spell_execute_script(bl->is_spell());
- break;
- }
-
- return 0;
+ return npc_scriptcont(sd, id);
}
} // namespace map
@@ -1571,7 +1554,6 @@ int do_init(Slice<ZString> argv)
using namespace tmwa::map;
ZString argv0 = argv.pop_front();
- runflag &= magic::magic_init0();
bool loaded_config_yet = false;
while (argv)
diff --git a/src/map/map.hpp b/src/map/map.hpp
index a2f2ff2..66253ca 100644
--- a/src/map/map.hpp
+++ b/src/map/map.hpp
@@ -89,13 +89,11 @@ private:
dumb_ptr<npc_data> as_npc();
dumb_ptr<mob_data> as_mob();
dumb_ptr<flooritem_data> as_item();
- dumb_ptr<magic::invocation> as_spell();
public:
dumb_ptr<map_session_data> is_player();
dumb_ptr<npc_data> is_npc();
dumb_ptr<mob_data> is_mob();
dumb_ptr<flooritem_data> is_item();
- dumb_ptr<magic::invocation> is_spell();
};
struct walkpath_data
@@ -107,7 +105,6 @@ struct status_change
{
Timer timer;
int val1;
- BlockId spell_invocation; /* [Fate] If triggered by a spell, record here */
};
struct quick_regeneration
@@ -205,8 +202,7 @@ struct map_session_data : block_list, SessionData
// used by @hugo and @linus
BlockId followtarget;
- tick_t cast_tick; // [Fate] Next tick at which spellcasting is allowed
- dumb_ptr<magic::invocation> active_spells; // [Fate] Singly-linked list of active spells linked to this PC
+ //tick_t cast_tick; // [Fate] Next tick at which spellcasting is allowed
BlockId attack_spell_override; // [Fate] When an attack spell is active for this player, they trigger it
NpcEvent magic_attack;
// like a weapon. Check pc_attack_timer() for details.
@@ -639,13 +635,6 @@ dumb_ptr<flooritem_data> map_id_is_item(BlockId id)
dumb_ptr<block_list> bl = map_id2bl(id);
return bl ? bl->is_item() : nullptr;
}
-inline
-dumb_ptr<magic::invocation> map_id_is_spell(BlockId id)
-{
- dumb_ptr<block_list> bl = map_id2bl(id);
- return bl ? bl->is_spell() : nullptr;
-}
-
Option<Borrowed<map_local>> map_mapname2mapid(MapName);
int map_mapname2ipport(MapName, Borrowed<IP4Address>, Borrowed<int>);
@@ -679,13 +668,11 @@ inline dumb_ptr<map_session_data> block_list::as_player() { return dumb_ptr<map_
inline dumb_ptr<npc_data> block_list::as_npc() { return dumb_ptr<npc_data>(static_cast<npc_data *>(this)) ; }
inline dumb_ptr<mob_data> block_list::as_mob() { return dumb_ptr<mob_data>(static_cast<mob_data *>(this)) ; }
inline dumb_ptr<flooritem_data> block_list::as_item() { return dumb_ptr<flooritem_data>(static_cast<flooritem_data *>(this)) ; }
-//inline dumb_ptr<invocation> block_list::as_spell() { return dumb_ptr<invocation>(static_cast<invocation *>(this)) ; }
inline dumb_ptr<map_session_data> block_list::is_player() { return bl_type == BL::PC ? as_player() : nullptr; }
inline dumb_ptr<npc_data> block_list::is_npc() { return bl_type == BL::NPC ? as_npc() : nullptr; }
inline dumb_ptr<mob_data> block_list::is_mob() { return bl_type == BL::MOB ? as_mob() : nullptr; }
inline dumb_ptr<flooritem_data> block_list::is_item() { return bl_type == BL::ITEM ? as_item() : nullptr; }
-//inline dumb_ptr<invocation> block_list::is_spell() { return bl_type == BL::SPELL ? as_spell() : nullptr; }
// struct invocation is defined in another header
diff --git a/src/map/map.t.hpp b/src/map/map.t.hpp
index 267c049..89b9a87 100644
--- a/src/map/map.t.hpp
+++ b/src/map/map.t.hpp
@@ -43,7 +43,6 @@ enum class BL : uint8_t
NPC,
MOB,
ITEM,
- SPELL,
};
enum class NpcSubtype : uint8_t
{
diff --git a/src/map/npc.cpp b/src/map/npc.cpp
index 0175916..eaf54ec 100644
--- a/src/map/npc.cpp
+++ b/src/map/npc.cpp
@@ -146,15 +146,24 @@ dumb_ptr<npc_data> npc_name2id(NpcName name)
}
/*==========================================
- * NPCを名前で探す
+ * NPC Spells
*------------------------------------------
*/
-NpcEvent spell_name2id(RString name)
+NpcName spell_name2id(RString name)
{
return spells_by_name.get(name);
}
/*==========================================
+ * NPC Spells Events
+ *------------------------------------------
+ */
+NpcEvent spell_event2id(RString name)
+{
+ return spells_by_events.get(name);
+}
+
+/*==========================================
* Spell Toknise
* Return a pair of strings, {spellname, parameter}
* Parameter may be empty.
@@ -189,26 +198,45 @@ std::pair<XString, XString> magic_tokenise(XString src)
*/
int magic_message(dumb_ptr<map_session_data> caster, XString source_invocation)
{
- if (pc_isdead(caster))
- return 0;
- if (bool(caster->status.option & Opt0::HIDE))
- return 0;
- if (caster->cast_tick > gettick())
- return 0;
-
auto pair = magic_tokenise(source_invocation);
// Spell Cast
- NpcName spell_name = stringish<NpcName>(pair.first);
+ NpcName spell_name = spell_name2id(pair.first);
+ NpcEvent spell_event = spell_event2id(pair.first);
+ PRINTF("Cast: %s\n"_fmt, RString(pair.first));
+
RString spell_params = pair.second;
- NpcEvent event = spell_name2id(spell_name);
+ dumb_ptr<npc_data> nd = npc_name2id(spell_name);
- if (event)
+ if (nd)
{
- PRINTF("Cast: %s\n"_fmt, spell_name);
- PRINTF("event: %s\n"_fmt, event);
+ PRINTF("NPC: %s %d\n"_fmt, nd->name, nd->bl_id);
PRINTF("Params: %s\n"_fmt, spell_params);
- npc_event(caster, event, 0);
+ caster->npc_id = nd->bl_id;
+ dumb_ptr<block_list> map_bl = map_id2bl(nd->bl_id);
+ if (!map_bl)
+ map_addnpc(caster->bl_m, nd);
+ argrec_t arg[1] =
+ {
+ {"@args$"_s, spell_params},
+ };
+ caster->npc_pos = run_script_l(ScriptPointer(borrow(*nd->is_script()->scr.script), 0), caster->bl_id, nd->bl_id, arg);
+ return 1;
+ }
+ if (spell_event.label)
+ {
+ dumb_ptr<npc_data> nd = npc_name2id(spell_event.npc);
+ PRINTF("NPC: %s %d\n"_fmt, nd->name, nd->bl_id);
+ PRINTF("Params: %s\n"_fmt, spell_params);
+ caster->npc_id = nd->bl_id;
+ dumb_ptr<block_list> map_bl = map_id2bl(nd->bl_id);
+ if (!map_bl)
+ map_addnpc(caster->bl_m, nd);
+ argrec_t arg[1] =
+ {
+ {"@args$"_s, spell_params},
+ };
+ caster->npc_pos = npc_event_do_l(spell_event, caster->bl_id, arg);
return 1;
}
return 0;
diff --git a/src/map/pc.cpp b/src/map/pc.cpp
index c4c3ad9..7f7512c 100644
--- a/src/map/pc.cpp
+++ b/src/map/pc.cpp
@@ -54,7 +54,6 @@
#include "globals.hpp"
#include "intif.hpp"
#include "itemdb.hpp"
-#include "magic-stmt.hpp"
#include "map.hpp"
#include "map_conf.hpp"
#include "npc.hpp"
@@ -742,7 +741,7 @@ int pc_authok(AccountId id, int login_id2, ClientVersion client_version,
// The above is no longer accurate now that we use <chrono>, but
// I'm still not reverting this.
// -o11c
- sd->cast_tick = tick; // + pc_readglobalreg (sd, "MAGIC_CAST_TICK"_s);
+ //sd->cast_tick = tick; // + pc_readglobalreg (sd, "MAGIC_CAST_TICK"_s);
// アカウント変数の送信要求
intif_request_accountreg(sd);
@@ -3272,8 +3271,8 @@ int pc_damage(dumb_ptr<block_list> src, dumb_ptr<map_session_data> sd,
clif_updatestatus(sd, SP::HP);
pc_calcstatus(sd, 0);
// [Fate] Reset magic
- sd->cast_tick = gettick();
- magic::magic_stop_completely(sd);
+ //sd->cast_tick = gettick();
+ //magic_stop_completely(sd);
if (battle_config.death_penalty_type > 0 && sd->status.base_level >= 20)
{
@@ -4992,7 +4991,7 @@ void do_init_pc(void)
void pc_cleanup(dumb_ptr<map_session_data> sd)
{
- magic::magic_stop_completely(sd);
+ //magic_stop_completely(sd);
}
void pc_invisibility(dumb_ptr<map_session_data> sd, int enabled)
diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp
index 35e119b..2d9ac23 100644
--- a/src/map/script-fun.cpp
+++ b/src/map/script-fun.cpp
@@ -47,7 +47,6 @@
#include "globals.hpp"
#include "intif.hpp"
#include "itemdb.hpp"
-#include "magic-interpreter-base.hpp"
#include "map.hpp"
#include "mob.hpp"
#include "npc.hpp"
@@ -259,7 +258,6 @@ void builtin_menu(ScriptState *st)
buf += choice_str;
buf += ':';
}
-
clif_scriptmenu(script_rid2sd(st), st->oid, AString(buf));
}
else
@@ -2768,18 +2766,6 @@ void builtin_getitemlink(ScriptState *st)
}
static
-void builtin_getspellinvocation(ScriptState *st)
-{
- RString name = conv_str(st, &AARG(0));
-
- AString invocation = magic::magic_find_invocation(name);
- if (!invocation)
- invocation = "..."_s;
-
- push_str<ScriptDataStr>(st->stack, invocation);
-}
-
-static
void builtin_getpartnerid2(ScriptState *st)
{
dumb_ptr<map_session_data> sd = script_rid2sd(st);
@@ -3329,31 +3315,21 @@ void builtin_npctalk(ScriptState *st)
}
/*==========================================
- * casttime
- *------------------------------------------
- */
-static
-void builtin_casttime(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- interval_t tick = static_cast<interval_t>(conv_num(st, &AARG(0)));
- sd->cast_tick = gettick() + tick;
-}
-
-/*==========================================
* register cmd
*------------------------------------------
*/
static
void builtin_registercmd(ScriptState *st)
{
- dumb_ptr<npc_data> nd = map_id_is_npc(st->oid);
RString evoke = conv_str(st, &AARG(0));
+ NpcName npcname = stringish<NpcName>(conv_str(st, &AARG(1)));
ZString event_ = conv_str(st, &AARG(1));
NpcEvent event;
extract(event_, &event);
-
- spells_by_name.put(evoke, event);
+ if (event.label)
+ spells_by_events.put(evoke, event);
+ else
+ spells_by_name.put(evoke, npcname);
}
/*==========================================
@@ -3826,7 +3802,6 @@ BuiltinFunction builtin_functions[] =
BUILTIN(marriage, "P"_s, 'i'),
BUILTIN(divorce, ""_s, 'i'),
BUILTIN(getitemlink, "I"_s, 's'),
- BUILTIN(getspellinvocation, "s"_s, 's'),
BUILTIN(getpartnerid2, ""_s, 'i'),
BUILTIN(explode, "Nss"_s, '\0'),
BUILTIN(getinventorylist, ""_s, '\0'),
@@ -3843,8 +3818,7 @@ BuiltinFunction builtin_functions[] =
BUILTIN(npcareawarp, "xyxyis"_s, '\0'),
BUILTIN(message, "Ps"_s, '\0'),
BUILTIN(npctalk, "ss?"_s, '\0'),
- BUILTIN(casttime, "i"_s, '\0'),
- BUILTIN(registercmd, "sE"_s, '\0'),
+ BUILTIN(registercmd, "ss"_s, '\0'),
BUILTIN(title, "s"_s, '\0'),
BUILTIN(smsg, "e??"_s, '\0'),
BUILTIN(remotecmd, "s?"_s, '\0'),
diff --git a/src/map/skill.cpp b/src/map/skill.cpp
index 8a397a3..6066a0d 100644
--- a/src/map/skill.cpp
+++ b/src/map/skill.cpp
@@ -51,7 +51,6 @@
#include "battle_conf.hpp"
#include "clif.hpp"
#include "globals.hpp"
-#include "magic-stmt.hpp"
#include "mob.hpp"
#include "pc.hpp"
@@ -822,13 +821,6 @@ void skill_status_change_timer(TimerData *tid, tick_t tick, BlockId id, StatusCh
if (bl->bl_type == BL::PC)
sd = bl->is_player();
- if (sc_data[type].spell_invocation)
- { // Must report termination
- magic::spell_effect_report_termination(sc_data[type].spell_invocation,
- bl->bl_id, type, 0);
- sc_data[type].spell_invocation = BlockId();
- }
-
switch (type)
{
case StatusChange::SC_POISON:
@@ -1050,11 +1042,6 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type,
clif_changeoption(bl);
sc_data[type].val1 = val1;
- if (sc_data[type].spell_invocation) // Supplant by newer spell
- magic::spell_effect_report_termination(sc_data[type].spell_invocation,
- bl->bl_id, type, 1);
-
- sc_data[type].spell_invocation = spell_invocation;
/* タイマー設定 */
sc_data[type].timer = Timer(gettick() + tick,
diff --git a/src/mmo/cxxstdio_enums.hpp b/src/mmo/cxxstdio_enums.hpp
index 28a8a14..01e8842 100644
--- a/src/mmo/cxxstdio_enums.hpp
+++ b/src/mmo/cxxstdio_enums.hpp
@@ -64,13 +64,6 @@ auto decay_for_printf(BF v) -> typename remove_enum<decltype(v)>::type { return
inline
auto decay_for_printf(MapCell v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); }
} // namespace map::e
-namespace magic
-{
-enum class SPELLARG : uint8_t;
-
-inline
-auto decay_for_printf(SPELLARG v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); }
-} // namespace map::magic
enum class BL : uint8_t;
enum class ByteCode : uint8_t;
diff --git a/src/mmo/skill.t.hpp b/src/mmo/skill.t.hpp
index 21e4059..df9c40c 100644
--- a/src/mmo/skill.t.hpp
+++ b/src/mmo/skill.t.hpp
@@ -41,11 +41,7 @@ enum class StatusChange : uint16_t
// these ones are used by clif_status_change,
// e.g. by the magic system
ZERO = 0,
- ATTACK_ICON_GENERIC = 2000,
- ATTACK_ICON_SHEARING = 2001,
- CART = 0x0c,
CLIF_OPTION_SC_INVISIBILITY = 0x1000,
- CLIF_OPTION_SC_SCRIBE = 0x1001,
// the rest are the normal effects
SC_SLOWPOISON = 14, // item script