diff options
Diffstat (limited to 'src/map/magic-stmt.cpp')
-rw-r--r-- | src/map/magic-stmt.cpp | 712 |
1 files changed, 306 insertions, 406 deletions
diff --git a/src/map/magic-stmt.cpp b/src/map/magic-stmt.cpp index ba99409..fd02d45 100644 --- a/src/map/magic-stmt.cpp +++ b/src/map/magic-stmt.cpp @@ -29,16 +29,17 @@ #include "../generic/random2.hpp" #include "../io/cxxstdio.hpp" +#include "../io/cxxstdio_enums.hpp" -#include "../mmo/timer.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-aux.hpp" - -#include "battle.hpp" -#include "clif.hpp" +#include "magic-interpreter-base.hpp" #include "mob.hpp" #include "npc.hpp" #include "pc.hpp" @@ -46,69 +47,32 @@ #include "../poison.hpp" -/* used for local spell effects */ -constexpr int INVISIBLE_NPC = 127; - -//#define DEBUG -#ifdef DEBUG -static -void print_val(val_t *v) +namespace tmwa { - switch (v->ty) - { - case TYPE::UNDEF: - FPRINTF(stderr, "UNDEF"); - break; - case TYPE::INT: - FPRINTF(stderr, "%d", v->v.v_int); - break; - case TYPE::DIR: - FPRINTF(stderr, "dir%d", v->v.v_int); - break; - case TYPE::STRING: - FPRINTF(stderr, "`%s'", v->v.v_string); - break; - default: - FPRINTF(stderr, "ty%d", v->ty); - break; - } -} - -static -void dump_env(env_t *env) +namespace magic { - int i; - for (i = 0; i < env->base_env->vars_nr; i++) - { - val_t *v = &env->vars[i]; - val_t *bv = &env->base_env->vars[i]; - - FPRINTF(stderr, "%02x %30s ", i, env->base_env->var_name[i]); - print_val(v); - FPRINTF(stderr, "\t("); - print_val(bv); - FPRINTF(stderr, ")\n"); - } -} -#endif +/* used for local spell effects */ +constexpr Species INVISIBLE_NPC = wrap<Species>(127); static void clear_activation_record(cont_activation_record_t *ar) { - switch (ar->ty) + MATCH (*ar) { - case CONT_STACK::FOREACH: - ar->c.c_foreach.entities_vp.delete_(); - break; - case CONT_STACK::PROC: - ar->c.c_proc.old_actualpa.delete_(); - break; + CASE (CarForEach&, c_foreach) + { + c_foreach.entities_vp.delete_(); + } + CASE (CarProc&, c_proc) + { + c_proc.old_actualpa.delete_(); + } } } static -void invocation_timer_callback(TimerData *, tick_t, int id) +void invocation_timer_callback(TimerData *, tick_t, BlockId id) { dumb_ptr<invocation> invocation = map_id_is_spell(id); @@ -123,10 +87,10 @@ void clear_stack(dumb_ptr<invocation> invocation_) { int i; - for (i = 0; i < invocation_->stack_size; i++) + for (i = 0; i < invocation_->stack.size(); i++) clear_activation_record(&invocation_->stack[i]); - invocation_->stack_size = 0; + invocation_->stack.clear(); } void spell_free_invocation(dumb_ptr<invocation> invocation_) @@ -153,7 +117,7 @@ void spell_free_invocation(dumb_ptr<invocation> invocation_) static void char_set_weapon_icon(dumb_ptr<map_session_data> subject, int count, - StatusChange icon, int look) + StatusChange icon, ItemNameId look) { const StatusChange old_icon = subject->attack_spell_icon_override; @@ -166,7 +130,7 @@ void char_set_weapon_icon(dumb_ptr<map_session_data> subject, int count, clif_fixpcpos(subject); if (count) { - clif_changelook(subject, LOOK::WEAPON, look); + clif_changelook(subject, LOOK::WEAPON, unwrap<ItemNameId>(look)); if (icon != StatusChange::ZERO) clif_status_change(subject, icon, 1); } @@ -202,7 +166,7 @@ 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 = 0; + c->sc_data[i].spell_invocation = BlockId(); while (c->active_spells) spell_free_invocation(c->active_spells); @@ -212,8 +176,8 @@ void magic_stop_completely(dumb_ptr<map_session_data> c) 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 = 0; - char_set_weapon_icon(c, 0, StatusChange::ZERO, 0); + c->attack_spell_override = BlockId(); + char_set_weapon_icon(c, 0, StatusChange::ZERO, ItemNameId()); char_set_attack_info(c, interval_t::zero(), 0); } } @@ -228,7 +192,7 @@ void try_to_finish_invocation(dumb_ptr<invocation> invocation) { clear_stack(invocation); invocation->current_effect = invocation->end_effect; - invocation->end_effect = NULL; + invocation->end_effect = nullptr; spell_execute(invocation); } else @@ -237,19 +201,18 @@ void try_to_finish_invocation(dumb_ptr<invocation> invocation) } static -int trigger_spell(int subject, int spell) +BlockId trigger_spell(BlockId subject, BlockId spell) { dumb_ptr<invocation> invocation_ = map_id_is_spell(spell); if (!invocation_) - return 0; + 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].ty = TYPE::ENTITY; - invocation_->env->varu[VAR_CASTER].v.v_int = subject; + invocation_->env->varu[VAR_CASTER] = ValEntityInt{subject}; return invocation_->bl_id; } @@ -265,7 +228,7 @@ void char_update(dumb_ptr<map_session_data> character) } static -void timer_callback_effect(TimerData *, tick_t, int id, int data) +void timer_callback_effect(TimerData *, tick_t, BlockId id, int data) { dumb_ptr<block_list> target = map_id2bl(id); if (target) @@ -286,12 +249,12 @@ 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!"); + 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, int npc_id) +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); @@ -302,10 +265,10 @@ dumb_ptr<npc_data> local_spell_effect(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 = std::chrono::seconds(30); + std::chrono::seconds delay = 30_s; dumb_ptr<npc_data> effect_npc = npc_spawn_text(m, x, y, - INVISIBLE_NPC, NpcName(), "?"); - int effect_npc_id = effect_npc->bl_id; + INVISIBLE_NPC, NpcName(), "?"_s); + BlockId effect_npc_id = effect_npc->bl_id; entity_effect(effect_npc, effect, tdelay); Timer(gettick() + delay, @@ -321,11 +284,11 @@ int op_sfx(dumb_ptr<env_t>, Slice<val_t> args) { interval_t delay = static_cast<interval_t>(ARGINT(2)); - if (ARG_TYPE(0) == TYPE::ENTITY) + if (args[0].is<ValEntityPtr>()) { entity_effect(ARGENTITY(0), ARGINT(1), delay); } - else if (ARG_TYPE(0) == TYPE::LOCATION) + else if (args[0].is<ValLocation>()) { local_spell_effect(ARGLOCATION(0).m, ARGLOCATION(0).x, @@ -340,8 +303,10 @@ int op_sfx(dumb_ptr<env_t>, Slice<val_t> args) static int op_instaheal(dumb_ptr<env_t> env, Slice<val_t> args) { - dumb_ptr<block_list> caster = (env->VAR(VAR_CASTER).ty == TYPE::ENTITY) - ? map_id2bl(env->VAR(VAR_CASTER).v.v_int) : NULL; + 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; @@ -350,8 +315,8 @@ int op_instaheal(dumb_ptr<env_t> env, Slice<val_t> args) { 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", - subject_pc->status_key.char_id, ARGINT(1)); + 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); @@ -430,7 +395,7 @@ int op_message(dumb_ptr<env_t>, Slice<val_t> args) } static -void timer_callback_kill_npc(TimerData *, tick_t, int npc_id) +void timer_callback_kill_npc(TimerData *, tick_t, BlockId npc_id) { dumb_ptr<npc_data> npc = map_id_is_npc(npc_id); if (npc) @@ -445,7 +410,7 @@ int op_messenger_npc(dumb_ptr<env_t>, Slice<val_t> args) NpcName npcname = stringish<NpcName>(ARGSTR(2)); npc = npc_spawn_text(loc->m, loc->x, loc->y, - ARGINT(1), npcname, ARGSTR(3)); + 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, @@ -537,7 +502,7 @@ int op_banish(dumb_ptr<env_t>, Slice<val_t> args) } static -void record_status_change(dumb_ptr<invocation> invocation_, int bl_id, +void record_status_change(dumb_ptr<invocation> invocation_, BlockId bl_id, StatusChange sc_id) { status_change_ref_t cr {}; @@ -551,8 +516,10 @@ static int op_status_change(dumb_ptr<env_t> env, Slice<val_t> args) { dumb_ptr<block_list> subject = ARGENTITY(0); - int invocation_id = env->VAR(VAR_INVOCATION).ty == TYPE::INVOCATION - ? env->VAR(VAR_INVOCATION).v.v_int : 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)); @@ -563,7 +530,7 @@ int op_status_change(dumb_ptr<env_t> env, Slice<val_t> args) static_cast<interval_t>(ARGINT(6)), invocation_id); if (invocation_ && subject->bl_type == BL::PC) - record_status_change(invocation_, subject->bl_id, StatusChange(ARGINT(1))); + record_status_change(invocation_, subject->bl_id, static_cast<StatusChange>(ARGINT(1))); return 0; } @@ -587,7 +554,7 @@ int op_override_attack(dumb_ptr<env_t> env, Slice<val_t> args) interval_t attack_delay = static_cast<interval_t>(ARGINT(2)); int attack_range = ARGINT(3); StatusChange icon = StatusChange(ARGINT(4)); - int look = ARGINT(5); + ItemNameId look = wrap<ItemNameId>(static_cast<uint16_t>(ARGINT(5))); int stopattack = ARGINT(6); dumb_ptr<map_session_data> subject; @@ -603,8 +570,9 @@ int op_override_attack(dumb_ptr<env_t> env, Slice<val_t> args) spell_free_invocation(old_invocation); } + ValInvocationInt *ii = env->VAR(VAR_INVOCATION).get_if<ValInvocationInt>(); subject->attack_spell_override = - trigger_spell(subject->bl_id, env->VAR(VAR_INVOCATION).v.v_int); + trigger_spell(subject->bl_id, ii->v_iid); subject->attack_spell_charges = charges; if (subject->attack_spell_override) @@ -623,7 +591,7 @@ int op_override_attack(dumb_ptr<env_t> env, Slice<val_t> args) static int op_create_item(dumb_ptr<env_t>, Slice<val_t> args) { - struct item item; + Item item; dumb_ptr<block_list> entity = ARGENTITY(0); dumb_ptr<map_session_data> subject; int stackable; @@ -698,13 +666,13 @@ 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); - int monster_id = ARGINT(2); + 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 = NULL; + dumb_ptr<map_session_data> owner = nullptr; if (monster_attitude == MonsterAttitude::SERVANT && owner_e->bl_type == BL::PC) owner = owner_e->is_player(); @@ -714,7 +682,7 @@ int op_spawn(dumb_ptr<env_t>, Slice<val_t> args) location_t loc; magic_random_location(&loc, area); - int mob_id; + 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? @@ -724,7 +692,7 @@ int op_spawn(dumb_ptr<env_t>, Slice<val_t> args) if (mob) { - mob->mode = mob_db[monster_id].mode; + mob->mode = get_mob_db(monster_id).mode; switch (monster_attitude) { @@ -770,18 +738,21 @@ int op_spawn(dumb_ptr<env_t>, Slice<val_t> args) } static -const char *get_invocation_name(dumb_ptr<env_t> env) +ZString get_invocation_name(dumb_ptr<env_t> env) { - dumb_ptr<invocation> invocation_; + assert (!env->VAR(VAR_INVOCATION).is<ValInvocationPtr>()); - if (env->VAR(VAR_INVOCATION).ty != TYPE::INVOCATION) - return "?"; - invocation_ = map_id_is_spell(env->VAR(VAR_INVOCATION).v.v_int); + 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.c_str(); + return invocation_->spell->name; else - return "??"; + return "??"_s; } static @@ -824,9 +795,9 @@ int op_injure(dumb_ptr<env_t> env, Slice<val_t> args) { dumb_ptr<mob_data> mob = target->is_mob(); - MAP_LOG_PC(caster_pc, "SPELLDMG MOB%d %d FOR %d BY %s", - mob->bl_id, mob->mob_class, damage_caused, - get_invocation_name(env)); + 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); @@ -847,7 +818,7 @@ int op_emote(dumb_ptr<env_t>, Slice<val_t> args) 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) : NULL; + dumb_ptr<map_session_data> c = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr; VarName varname = stringish<VarName>(ARGSTR(1)); int array_index = 0; @@ -862,7 +833,7 @@ int op_set_script_variable(dumb_ptr<env_t>, Slice<val_t> args) 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) : NULL; + dumb_ptr<map_session_data> c = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr; VarName varname = stringish<VarName>(ARGSTR(1)); int array_index = 0; @@ -877,7 +848,7 @@ int op_set_script_str(dumb_ptr<env_t>, Slice<val_t> args) 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) : NULL; + dumb_ptr<map_session_data> c = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr; if (!c) return 1; @@ -890,7 +861,7 @@ int op_set_hair_colour(dumb_ptr<env_t>, Slice<val_t> args) 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) : NULL; + dumb_ptr<map_session_data> c = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr; if (!c) return 1; @@ -903,25 +874,29 @@ int op_set_hair_style(dumb_ptr<env_t>, Slice<val_t> args) static int op_drop_item_for (dumb_ptr<env_t>, Slice<val_t> args) { - struct item item; + 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) : NULL; + 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, NULL, NULL }; + 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; } @@ -929,46 +904,46 @@ int op_drop_item_for (dumb_ptr<env_t>, Slice<val_t> args) 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) : NULL; + 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), - PC_GAINEXP_REASON(ARGINT(3))); + 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, args, op_##name) +#define MAGIC_OPERATION1(name, args) MAGIC_OPERATION(#name##_s, args, op_##name) static std::map<ZString, op_t> operations = { - MAGIC_OPERATION1(sfx, ".ii"), - MAGIC_OPERATION1(instaheal, "eii"), - MAGIC_OPERATION1(itemheal, "eii"), - MAGIC_OPERATION1(shroud, "ei"), - MAGIC_OPERATION("unshroud", "e", op_reveal), - MAGIC_OPERATION1(message, "es"), - MAGIC_OPERATION1(messenger_npc, "lissi"), - MAGIC_OPERATION1(move, "ed"), - MAGIC_OPERATION1(warp, "el"), - MAGIC_OPERATION1(banish, "e"), - MAGIC_OPERATION1(status_change, "eiiiiii"), - MAGIC_OPERATION1(stop_status_change, "ei"), - MAGIC_OPERATION1(override_attack, "eiiiiii"), - MAGIC_OPERATION1(create_item, "e.i"), - MAGIC_OPERATION1(aggravate, "eie"), - MAGIC_OPERATION1(spawn, "aeiiii"), - MAGIC_OPERATION1(injure, "eeii"), - MAGIC_OPERATION1(emote, "ei"), - MAGIC_OPERATION1(set_script_variable, "esi"), - MAGIC_OPERATION1(set_script_str, "ess"), - MAGIC_OPERATION1(set_hair_colour, "ei"), - MAGIC_OPERATION1(set_hair_style, "ei"), - MAGIC_OPERATION("drop_item", "l.ii", op_drop_item_for), - MAGIC_OPERATION1(drop_item_for, "l.iiei"), - MAGIC_OPERATION("gain_experience", "eiii", op_gain_exp), + 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) @@ -979,7 +954,7 @@ op_t *magic_get_op(ZString name) return &it->second; } -void spell_effect_report_termination(int invocation_id, int bl_id, +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); @@ -1004,8 +979,8 @@ void spell_effect_report_termination(int invocation_id, int bl_id, 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", - bl_id, sc_id); + "[magic] INTERNAL ERROR: spell-effect-report-termination: tried to terminate on unexpected bl %d, sc %d\n"_fmt, + bl_id, sc_id); return; } @@ -1014,111 +989,86 @@ void spell_effect_report_termination(int invocation_id, int bl_id, static dumb_ptr<effect_t> return_to_stack(dumb_ptr<invocation> invocation_) { - if (!invocation_->stack_size) - return NULL; + if (invocation_->stack.empty()) + return nullptr; else { cont_activation_record_t *ar = - invocation_->stack + (invocation_->stack_size - 1); - switch (ar->ty) + &invocation_->stack.back(); + MATCH (*ar) { - case CONT_STACK::PROC: + CASE (const CarProc&, c_proc) { dumb_ptr<effect_t> ret = ar->return_location; - for (int i = 0; i < ar->c.c_proc.args_nr; i++) + for (int i = 0; i < c_proc.args_nr; i++) { val_t *var = - &invocation_->env->varu[ar->c.c_proc.formalap[i]]; + &invocation_->env->varu[c_proc.formalap[i]]; magic_clear_var(var); - *var = ar->c.c_proc.old_actualpa[i]; + *var = std::move(c_proc.old_actualpa[i]); } // pop the stack clear_activation_record(ar); - --invocation_->stack_size; + invocation_->stack.pop_back(); return ret; } - - case CONT_STACK::FOREACH: + CASE (CarForEach&, c_foreach) { - int entity_id; - val_t *var = &invocation_->env->varu[ar->c.c_foreach.id]; + 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 (ar->c.c_foreach.index >= ar->c.c_foreach.entities_vp->size()) + if (c_foreach.index >= c_foreach.entities_vp->size()) { // pop the stack dumb_ptr<effect_t> ret = ar->return_location; clear_activation_record(ar); - --invocation_->stack_size; + invocation_->stack.pop_back(); return ret; } entity_id = - (*ar->c.c_foreach.entities_vp)[ar->c.c_foreach.index++]; + (*c_foreach.entities_vp)[c_foreach.index++]; } while (!entity_id || !map_id2bl(entity_id)); magic_clear_var(var); - var->ty = ar->c.c_foreach.ty; - var->v.v_int = entity_id; + if (c_foreach.ty_is_spell_not_entity) + *var = ValInvocationInt{entity_id}; + else + *var = ValEntityInt{entity_id}; - return ar->c.c_foreach.body; + return c_foreach.body; } - - case CONT_STACK::FOR: - if (ar->c.c_for.current > ar->c.c_for.stop) + CASE (CarFor&, c_for) + { + if (c_for.current > c_for.stop) { dumb_ptr<effect_t> ret = ar->return_location; // pop the stack clear_activation_record(ar); - --invocation_->stack_size; + invocation_->stack.pop_back(); return ret; } - magic_clear_var(&invocation_->env->varu[ar->c.c_for.id]); - invocation_->env->varu[ar->c.c_for.id].ty = TYPE::INT; - invocation_->env->varu[ar->c.c_for.id].v.v_int = - ar->c.c_for.current++; - - return ar->c.c_for.body; + magic_clear_var(&invocation_->env->varu[c_for.id]); + invocation_->env->varu[c_for.id] = ValInt{c_for.current++}; - default: - FPRINTF(stderr, - "[magic] INTERNAL ERROR: While executing spell `%s': stack corruption\n", - invocation_->spell->name); - return NULL; + return c_for.body; + } } + abort(); } } static -cont_activation_record_t *add_stack_entry(dumb_ptr<invocation> invocation_, - CONT_STACK ty, dumb_ptr<effect_t> return_location) -{ - cont_activation_record_t *ar = - invocation_->stack + invocation_->stack_size++; - if (invocation_->stack_size >= MAX_STACK_SIZE) - { - FPRINTF(stderr, - "[magic] Execution stack size exceeded in spell `%s'; truncating effect\n", - invocation_->spell->name); - invocation_->stack_size--; - return NULL; - } - - ar->ty = ty; - ar->return_location = return_location; - return ar; -} - -static void find_entities_in_area_c(dumb_ptr<block_list> target, - std::vector<int> *entities_vp, + std::vector<BlockId> *entities_vp, FOREACH_FILTER filter) { switch (target->bl_type) @@ -1180,22 +1130,49 @@ void find_entities_in_area_c(dumb_ptr<block_list> target, static void find_entities_in_area(area_t& area_, - std::vector<int> *entities_vp, + std::vector<BlockId> *entities_vp, FOREACH_FILTER filter) { - area_t *area = &area_; // temporary hack to "keep diff small". Heh. - switch (area->ty) + MATCH (area_) { - case AREA::UNION: - find_entities_in_area(*area->a.a_union[0], entities_vp, filter); - find_entities_in_area(*area->a.a_union[1], entities_vp, filter); - break; - - default: + CASE (const AreaUnion&, a) + { + find_entities_in_area(*a.a_union[0], entities_vp, filter); + find_entities_in_area(*a.a_union[1], entities_vp, filter); + } + CASE (const location_t&, a_loc) { + (void)a_loc; + // TODO this can be simplified map_local *m; int x, y, width, height; - magic_area_rect(&m, &x, &y, &width, &height, *area); + magic_area_rect(&m, &x, &y, &width, &height, area_); + map_foreachinarea(std::bind(find_entities_in_area_c, ph::_1, entities_vp, filter), + m, + x, y, + x + width, y + height, + BL::NUL /* filter elsewhere */); + } + CASE (const AreaRect&, a_rect) + { + (void)a_rect; + // TODO this can be simplified + map_local *m; + int x, y, width, height; + magic_area_rect(&m, &x, &y, &width, &height, area_); + map_foreachinarea(std::bind(find_entities_in_area_c, ph::_1, entities_vp, filter), + m, + x, y, + x + width, y + height, + BL::NUL /* filter elsewhere */); + } + CASE (const AreaBar&, a_bar) + { + (void)a_bar; + // TODO this is wrong + map_local *m; + int x, y, width, height; + magic_area_rect(&m, &x, &y, &width, &height, area_); map_foreachinarea(std::bind(find_entities_in_area_c, ph::_1, entities_vp, filter), m, x, y, @@ -1207,45 +1184,44 @@ void find_entities_in_area(area_t& area_, static dumb_ptr<effect_t> run_foreach(dumb_ptr<invocation> invocation, - dumb_ptr<effect_t> foreach, + const EffectForEach *foreach, dumb_ptr<effect_t> return_location) { + const EffectForEach& e_foreach = *foreach; + val_t area; - FOREACH_FILTER filter = foreach->e.e_foreach.filter; - int id = foreach->e.e_foreach.id; - dumb_ptr<effect_t> body = foreach->e.e_foreach.body; + FOREACH_FILTER filter = e_foreach.filter; + int id = e_foreach.id; + dumb_ptr<effect_t> body = e_foreach.body; - magic_eval(invocation->env, &area, foreach->e.e_foreach.area); + magic_eval(invocation->env, &area, e_foreach.area); - if (area.ty != TYPE::AREA) + auto va = area.get_if<ValArea>(); + if (!va) { magic_clear_var(&area); FPRINTF(stderr, - "[magic] Error in spell `%s': FOREACH loop over non-area\n", - invocation->spell->name.c_str()); + "[magic] Error in spell `%s': FOREACH loop over non-area\n"_fmt, + invocation->spell->name); return return_location; } - else - { - cont_activation_record_t *ar = - add_stack_entry(invocation, CONT_STACK::FOREACH, return_location); - if (!ar) - return return_location; - - std::vector<int> entities_v; - find_entities_in_area(*area.v.v_area, + { + 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); - ar->c.c_foreach.id = id; - ar->c.c_foreach.body = body; - ar->c.c_foreach.index = 0; - ar->c.c_foreach.entities_vp.new_(std::move(entities_v)); - ar->c.c_foreach.ty = - (filter == FOREACH_FILTER::SPELL) ? TYPE::INVOCATION : TYPE::ENTITY; + CarForEach c_foreach; + c_foreach.id = id; + c_foreach.body = body; + c_foreach.index = 0; + c_foreach.entities_vp.new_(std::move(entities_v)); + c_foreach.ty_is_spell_not_entity = + (filter == FOREACH_FILTER::SPELL); + invocation->stack.emplace_back(c_foreach, return_location); magic_clear_var(&area); @@ -1255,130 +1231,66 @@ dumb_ptr<effect_t> run_foreach(dumb_ptr<invocation> invocation, static dumb_ptr<effect_t> run_for (dumb_ptr<invocation> invocation, - dumb_ptr<effect_t> for_, + const EffectFor *for_, dumb_ptr<effect_t> return_location) { - cont_activation_record_t *ar; - int id = for_->e.e_for.id; + const EffectFor& e_for = *for_; + + int id = e_for.id; val_t start; val_t stop; - magic_eval(invocation->env, &start, for_->e.e_for.start); - magic_eval(invocation->env, &stop, for_->e.e_for.stop); + magic_eval(invocation->env, &start, e_for.start); + magic_eval(invocation->env, &stop, e_for.stop); - if (start.ty != TYPE::INT || stop.ty != TYPE::INT) + if (!start.is<ValInt>() || !stop.is<ValInt>()) { magic_clear_var(&start); magic_clear_var(&stop); FPRINTF(stderr, - "[magic] Error in spell `%s': FOR loop start or stop point is not an integer\n", - invocation->spell->name); + "[magic] Error in spell `%s': FOR loop start or stop point is not an integer\n"_fmt, + invocation->spell->name); return return_location; } - ar = add_stack_entry(invocation, CONT_STACK::FOR, return_location); + CarFor c_for; - if (!ar) - return return_location; - - ar->c.c_for.id = id; - ar->c.c_for.current = start.v.v_int; - ar->c.c_for.stop = stop.v.v_int; - ar->c.c_for.body = for_->e.e_for.body; + c_for.id = id; + c_for.current = start.get_if<ValInt>()->v_int; + c_for.stop = stop.get_if<ValInt>()->v_int; + c_for.body = e_for.body; + invocation->stack.emplace_back(c_for, return_location); return return_to_stack(invocation); } static dumb_ptr<effect_t> run_call(dumb_ptr<invocation> invocation, + const EffectCall *call, dumb_ptr<effect_t> return_location) { - dumb_ptr<effect_t> current = invocation->current_effect; - cont_activation_record_t *ar; - int args_nr = current->e.e_call.formalv->size(); - int *formals = current->e.e_call.formalv->data(); + const EffectCall& e_call = *call; + + int args_nr = e_call.formalv->size(); + int *formals = e_call.formalv->data(); auto old_actuals = dumb_ptr<val_t[]>::make(args_nr); - ar = add_stack_entry(invocation, CONT_STACK::PROC, return_location); - ar->c.c_proc.args_nr = args_nr; - ar->c.c_proc.formalap = formals; - ar->c.c_proc.old_actualpa = old_actuals; + CarProc c_proc; + c_proc.args_nr = args_nr; + c_proc.formalap = formals; + c_proc.old_actualpa = old_actuals; + invocation->stack.emplace_back(c_proc, return_location); + for (int i = 0; i < args_nr; i++) { val_t *env_val = &invocation->env->varu[formals[i]]; magic_copy_var(&old_actuals[i], env_val); - magic_eval(invocation->env, env_val, (*current->e.e_call.actualvp)[i]); + magic_eval(invocation->env, env_val, (*e_call.actualvp)[i]); } - return current->e.e_call.body; + return e_call.body; } -#ifdef DEBUG -static -void print_cfg(int i, effect_t *e) -{ - int j; - for (j = 0; j < i; j++) - PRINTF(" "); - - PRINTF("%p: ", e); - - if (!e) - { - puts(" -- end --"); - return; - } - - switch (e->ty) - { - case EFFECT::SKIP: - puts("SKIP"); - break; - case EFFECT::END: - puts("END"); - break; - case EFFECT::ABORT: - puts("ABORT"); - break; - case EFFECT::ASSIGN: - puts("ASSIGN"); - break; - case EFFECT::FOREACH: - puts("FOREACH"); - print_cfg(i + 1, e->e.e_foreach.body); - break; - case EFFECT::FOR: - puts("FOR"); - print_cfg(i + 1, e->e.e_for.body); - break; - case EFFECT::IF: - puts("IF"); - for (j = 0; j < i; j++) - PRINTF(" "); - puts("THEN"); - print_cfg(i + 1, e->e.e_if.true_branch); - for (j = 0; j < i; j++) - PRINTF(" "); - puts("ELSE"); - print_cfg(i + 1, e->e.e_if.false_branch); - break; - case EFFECT::SLEEP: - puts("SLEEP"); - break; - case EFFECT::SCRIPT: - puts("NpcSubtype::SCRIPT"); - break; - case EFFECT::BREAK: - puts("BREAK"); - break; - case EFFECT::OP: - puts("OP"); - break; - } - print_cfg(i, e->next); -} -#endif - /** * Execute a spell invocation until we abort, finish, or hit the next `sleep'. * @@ -1391,87 +1303,81 @@ void print_cfg(int i, effect_t *e) static interval_t spell_run(dumb_ptr<invocation> invocation_, int allow_delete) { - const int invocation_id = invocation_->bl_id; + const BlockId invocation_id = invocation_->bl_id; #define REFRESH_INVOCATION invocation_ = map_id_is_spell(invocation_id); if (!invocation_) return interval_t::zero(); -#ifdef DEBUG - FPRINTF(stderr, "Resuming execution: invocation of `%s'\n", - invocation_->spell->name); - print_cfg(1, invocation_->current_effect); -#endif while (invocation_->current_effect) { dumb_ptr<effect_t> e = invocation_->current_effect; dumb_ptr<effect_t> next = e->next; int i; -#ifdef DEBUG - FPRINTF(stderr, "Next step of type %d\n", e->ty); - dump_env(invocation_->env); -#endif - - switch (e->ty) + MATCH (*e) { - case EFFECT::SKIP: - break; - - case EFFECT::ABORT: + CASE (const EffectSkip&, e_) + { + (void)e_; + } + CASE (const EffectAbort&, e_) + { + (void)e_; invocation_->flags |= INVOCATION_FLAG::ABORTED; - invocation_->end_effect = NULL; - FALLTHROUGH; - case EFFECT::END: + invocation_->end_effect = nullptr; clear_stack(invocation_); - next = NULL; - break; - - case EFFECT::ASSIGN: + next = nullptr; + } + CASE (const EffectEnd&, e_) + { + (void)e_; + clear_stack(invocation_); + next = nullptr; + } + CASE (const EffectAssign&, e_assign) + { magic_eval(invocation_->env, - &invocation_->env->varu[e->e.e_assign.id], - e->e.e_assign.expr); - break; - - case EFFECT::FOREACH: - next = run_foreach(invocation_, e, next); - break; - - case EFFECT::FOR: - next = run_for (invocation_, e, next); - break; - - case EFFECT::IF: - if (magic_eval_int(invocation_->env, e->e.e_if.cond)) - next = e->e.e_if.true_branch; + &invocation_->env->varu[e_assign.id], + e_assign.expr); + } + CASE (const EffectForEach&, e_foreach) + { + next = run_foreach(invocation_, &e_foreach, next); + } + CASE (const EffectFor&, e_for) + { + next = run_for (invocation_, &e_for, next); + } + CASE (const EffectIf&, e_if) + { + if (magic_eval_int(invocation_->env, e_if.cond)) + next = e_if.true_branch; else - next = e->e.e_if.false_branch; - break; - - case EFFECT::SLEEP: + next = e_if.false_branch; + } + CASE (const EffectSleep&, e_) { interval_t sleeptime = static_cast<interval_t>( - magic_eval_int(invocation_->env, e->e.e_sleep)); + magic_eval_int(invocation_->env, e_.e_sleep)); invocation_->current_effect = next; if (sleeptime > interval_t::zero()) return sleeptime; - break; } - - case EFFECT::SCRIPT: + CASE (const EffectScript&, e_) { dumb_ptr<map_session_data> caster = map_id_is_player(invocation_->caster); if (caster) { dumb_ptr<env_t> env = invocation_->env; ZString caster_name = (caster ? caster->status_key.name : CharName()).to__actual(); - argrec_t arg[3] = + argrec_t arg[1] = { - {"@target", env->VAR(VAR_TARGET).ty == TYPE::ENTITY ? 0 : env->VAR(VAR_TARGET).v.v_int}, - {"@caster", invocation_->caster}, - {"@caster_name$", caster_name}, + {"@caster_name$"_s, caster_name}, }; - int message_recipient = - env->VAR(VAR_SCRIPTTARGET).ty == - TYPE::ENTITY ? env->VAR(VAR_SCRIPTTARGET). - v.v_int : invocation_->caster; + 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 @@ -1485,7 +1391,7 @@ interval_t spell_run(dumb_ptr<invocation> invocation_, int allow_delete) // dealing with an NPC int newpos = run_script_l( - ScriptPointer(&*e->e.e_script, invocation_->script_pos), + ScriptPointer(&*e_.e_script, invocation_->script_pos), message_recipient, invocation_->bl_id, arg); /* Returns the new script position, or -1 once the script is finished */ @@ -1501,42 +1407,35 @@ interval_t spell_run(dumb_ptr<invocation> invocation_, int allow_delete) clif_clearchar_id(invocation_->bl_id, BeingRemoveWhy::DEAD, caster->sess); } REFRESH_INVOCATION; // Script may have killed the caster - break; } - - case EFFECT::BREAK: + CASE (const EffectBreak&, e_) + { + (void)e_; next = return_to_stack(invocation_); - break; - - case EFFECT::OP: + } + CASE (const EffectOp&, e_op) { - op_t *op = e->e.e_op.opp; + op_t *op = e_op.opp; val_t args[MAX_ARGS]; - for (i = 0; i < e->e.e_op.args_nr; i++) - magic_eval(invocation_->env, &args[i], e->e.e_op.args[i]); + for (i = 0; i < e_op.args_nr; i++) + magic_eval(invocation_->env, &args[i], e_op.args[i]); - if (!magic_signature_check("effect", op->name, op->signature, - Slice<val_t>(args, e->e.e_op.args_nr), - e->e.e_op.line_nr, - e->e.e_op.column)) - op->op(invocation_->env, Slice<val_t>(args, e->e.e_op.args_nr)); + 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->e.e_op.args_nr; i++) + for (i = 0; i < e_op.args_nr; i++) magic_clear_var(&args[i]); REFRESH_INVOCATION; // Effect may have killed the caster - break; } - - case EFFECT::CALL: - next = run_call(invocation_, next); - break; - - default: - FPRINTF(stderr, - "[magic] INTERNAL ERROR: Unknown effect %d\n", - e->ty); + CASE (const EffectCall&, e_call) + { + next = run_call(invocation_, &e_call, next); + } } if (!next) @@ -1583,7 +1482,7 @@ void spell_execute_script(dumb_ptr<invocation> invocation) * running the same spell twice! */ } -int spell_attack(int caster_id, int target_id) +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_; @@ -1600,8 +1499,7 @@ int spell_attack(int caster_id, int target_id) if (invocation_ && caster->attack_spell_charges > 0) { magic_clear_var(&invocation_->env->varu[VAR_TARGET]); - invocation_->env->varu[VAR_TARGET].ty = TYPE::ENTITY; - invocation_->env->varu[VAR_TARGET].v.v_int = target_id; + invocation_->env->varu[VAR_TARGET] = ValEntityInt{target_id}; invocation_->current_effect = invocation_->trigger_effect; invocation_->flags &= ~INVOCATION_FLAG::ABORTED; @@ -1622,8 +1520,8 @@ int spell_attack(int caster_id, int target_id) } else if (!invocation_ || caster->attack_spell_charges <= 0) { - caster->attack_spell_override = 0; - char_set_weapon_icon(caster, 0, StatusChange::ZERO, 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) @@ -1635,3 +1533,5 @@ int spell_attack(int caster_id, int target_id) return 1; } +} // namespace magic +} // namespace tmwa |