diff options
Diffstat (limited to 'src/map')
67 files changed, 9795 insertions, 8825 deletions
diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 240df8b..342f6ef 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -20,10 +20,10 @@ // 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 <cmath> -#include <cstring> #include <ctime> +#include <algorithm> + #include "../conf/version.hpp" #include "../compat/nullpo.hpp" @@ -35,19 +35,25 @@ #include "../strings/xstring.hpp" #include "../strings/vstring.hpp" +#include "../generic/db.hpp" #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" +#include "../io/cxxstdio_enums.hpp" #include "../io/read.hpp" #include "../io/write.hpp" +#include "../net/socket.hpp" +#include "../net/timer.hpp" + #include "../mmo/config_parse.hpp" #include "../mmo/core.hpp" #include "../mmo/extract.hpp" +#include "../mmo/extract_enums.hpp" #include "../mmo/human_time_diff.hpp" +#include "../mmo/ids.hpp" #include "../mmo/mmo.hpp" -#include "../mmo/socket.hpp" -#include "../mmo/timer.hpp" +#include "../mmo/utils.hpp" #include "../mmo/version.hpp" #include "battle.hpp" @@ -60,7 +66,6 @@ #include "npc.hpp" #include "party.hpp" #include "pc.hpp" -#include "script.hpp" #include "skill.hpp" #include "storage.hpp" #include "tmw.hpp" @@ -69,6 +74,8 @@ #include "../poison.hpp" +namespace tmwa +{ enum class ATCE { OKAY, @@ -81,12 +88,12 @@ enum class ATCE struct AtCommandInfo { ZString args; - int level; + GmLevel level; ATCE (*proc)(Session *s, dumb_ptr<map_session_data> sd, ZString message); ZString help; - AtCommandInfo(ZString a, int l, ATCE (*p)(Session *s, dumb_ptr<map_session_data>, ZString), ZString h) - : args(a), level(l), proc(p), help(h) + AtCommandInfo(ZString a, uint32_t l, ATCE (*p)(Session *s, dumb_ptr<map_session_data>, ZString), ZString h) + : args(a), level(GmLevel::from(l)), proc(p), help(h) {} }; @@ -121,23 +128,23 @@ void atcommand_config_write(ZString cfgName) if (!out.is_open()) { - FPRINTF(stderr, "Failed to write atcommand config: %s\n", cfgName); + FPRINTF(stderr, "Failed to write atcommand config: %s\n"_fmt, cfgName); return; } - FPRINTF(out, "// Generated by %s\n", CURRENT_VERSION_STRING); + FPRINTF(out, "// Generated by %s\n"_fmt, CURRENT_VERSION_STRING); for (const auto& pair : atcommand_info) { // This XString is really a ZString, but not declared as one // in order to allow non-heterogenous lookup by XString. - const char *cmd = &*pair.first.begin(); + auto cmd = ZString(strings::really_construct_from_a_pointer, &*pair.first.begin(), nullptr); const AtCommandInfo& info = pair.second; FPRINTF(out, "\n" "// %s\n" "// Usage: @%s %s\n" - "%s: %d\n", + "%s: %d\n"_fmt, info.help, cmd, info.args, cmd, info.level); @@ -198,8 +205,8 @@ void log_atcommand(dumb_ptr<map_session_data> sd, ZString cmd) stamp_time(tmpstr); MapName map = (sd->bl_m ? sd->bl_m->name_ - : stringish<MapName>("undefined.gat")); - FPRINTF(*fp, "[%s] %s(%d,%d) %s(%d) : %s\n", + : stringish<MapName>("undefined.gat"_s)); + FPRINTF(*fp, "[%s] %s(%d,%d) %s(%d) : %s\n"_fmt, tmpstr, map, sd->bl_x, sd->bl_y, sd->status_key.name, sd->status_key.account_id, @@ -211,7 +218,7 @@ AString gm_log; io::AppendFile *get_gm_log() { if (!gm_log) - return NULL; + return nullptr; struct tm ctime = TimeT::now(); @@ -225,7 +232,7 @@ io::AppendFile *get_gm_log() return gm_logfile.get(); last_logfile_nr = logfile_nr; - AString fullname = STRPRINTF("%s.%04d-%02d", + AString fullname = STRPRINTF("%s.%04d-%02d"_fmt, gm_log, year, month); if (gm_logfile) @@ -242,7 +249,7 @@ io::AppendFile *get_gm_log() } bool is_atcommand(Session *s, dumb_ptr<map_session_data> sd, - ZString message, int gmlvl) + ZString message, GmLevel gmlvl) { nullpo_retr(false, sd); @@ -259,22 +266,22 @@ bool is_atcommand(Session *s, dumb_ptr<map_session_data> sd, gmlvl = pc_isGM(sd); if (battle_config.atcommand_gm_only != 0 && !gmlvl) { - AString output = STRPRINTF("GM command is level 0, but this server disables level 0 commands: %s", + AString output = STRPRINTF("GM command is level 0, but this server disables level 0 commands: %s"_fmt, AString(command)); clif_displaymessage(s, output); return true; } if (!info) { - AString output = STRPRINTF("GM command not found: %s", + AString output = STRPRINTF("GM command not found: %s"_fmt, AString(command)); clif_displaymessage(s, output); return true; // don't show in chat } - if (info->level > gmlvl) + if (!(gmlvl.satisfies(info->level))) { - AString output = STRPRINTF("GM command is level %d, but you are level %d: %s", + AString output = STRPRINTF("GM command is level %d, but you are level %d: %s"_fmt, info->level, gmlvl, AString(command)); clif_displaymessage(s, output); @@ -292,17 +299,17 @@ bool is_atcommand(Session *s, dumb_ptr<map_session_data> sd, log_atcommand(sd, message); break; case ATCE::USAGE: - clif_displaymessage(s, "Command failed: usage error"); - clif_displaymessage(s, STRPRINTF("Usage: %s %s", AString(command), info->args)); + clif_displaymessage(s, "Command failed: usage error"_s); + clif_displaymessage(s, STRPRINTF("Usage: %s %s"_fmt, AString(command), info->args)); break; case ATCE::EXIST: - clif_displaymessage(s, "Command failed: something does not exist (or already exists)"); + clif_displaymessage(s, "Command failed: something does not exist (or already exists)"_s); break; case ATCE::RANGE: - clif_displaymessage(s, "Command failed: value out of range"); + clif_displaymessage(s, "Command failed: value out of range"_s); break; case ATCE::PERM: - clif_displaymessage(s, "Command failed: permission denied"); + clif_displaymessage(s, "Command failed: permission denied"_s); break; default: abort(); @@ -331,7 +338,7 @@ void atkillmonster_sub(dumb_ptr<block_list> bl, int flag) dumb_ptr<mob_data> md = bl->is_mob(); if (flag) - mob_damage(NULL, md, md->hp, 2); + mob_damage(nullptr, md, md->hp, 2); else mob_delete(md); } @@ -347,7 +354,7 @@ bool atcommand_config_read(ZString cfgName) io::ReadFile in(cfgName); if (!in.is_open()) { - PRINTF("At commands configuration file not found: %s\n", cfgName); + PRINTF("At commands configuration file not found: %s\n"_fmt, cfgName); return false; } @@ -361,24 +368,20 @@ bool atcommand_config_read(ZString cfgName) ZString w2; if (!config_split(line, &w1, &w2)) { - PRINTF("Bad config line: %s\n", line); + PRINTF("Bad config line: %s\n"_fmt, line); rv = false; continue; } AtCommandInfo *p = get_atcommandinfo_byname(w1); - if (p != NULL) + if (p != nullptr) { - p->level = atoi(w2.c_str()); - if (p->level > 100) - p->level = 100; - else if (p->level < 0) - p->level = 0; + p->level = GmLevel::from(static_cast<uint32_t>(atoi(w2.c_str()))); } - else if (w1 == "import") + else if (w1 == "import"_s) rv &= atcommand_config_read(w2); else { - PRINTF("%s: bad line: %s\n", cfgName, line); + PRINTF("%s: bad line: %s\n"_fmt, cfgName, line); rv = false; } } @@ -389,14 +392,16 @@ bool atcommand_config_read(ZString cfgName) /// @ command processing functions static -void atc_do_help(Session *s, const char *cmd, const AtCommandInfo& info) +void atc_do_help(Session *s, ZString cmd, const AtCommandInfo& info) { - auto msg = STRPRINTF("\u2007\u2007%d: @%s %s", info.level, cmd, info.args); + // TODO convert to hex or something + uint32_t level = info.level.get_all_bits(); + auto msg = STRPRINTF("\u2007\u2007%d: @%s %s"_fmt, info.level, cmd, info.args); // manually padding because *space* size_t ll = 1; - if (info.level >= 10) + if (level >= 10) ++ll; - if (info.level >= 100) + if (level >= 100) ++ll; clif_displaymessage(s, msg.xslice_t((ll - 1) * 3)); } @@ -407,9 +412,9 @@ ATCE atcommand_help(Session *s, dumb_ptr<map_session_data>, { if (!message) { - clif_displaymessage(s, "There is too much help to display it all at once"); - clif_displaymessage(s, "Try @help <@command> or @help <category> or @help <level[-level]>"); - clif_displaymessage(s, "Right now the only category is 'all'"); + clif_displaymessage(s, "There is too much help to display it all at once"_s); + clif_displaymessage(s, "Try @help <@command> or @help <category> or @help <level[-level]>"_s); + clif_displaymessage(s, "Right now the only category is 'all'"_s); return ATCE::OKAY; } @@ -419,37 +424,51 @@ ATCE atcommand_help(Session *s, dumb_ptr<map_session_data>, const AtCommandInfo *info = atcommand_info.search(cmd); if (!info) return ATCE::EXIST; - clif_displaymessage(s, STRPRINTF("Usage: @%s %s", cmd, info->args)); + clif_displaymessage(s, STRPRINTF("Usage: @%s %s"_fmt, cmd, info->args)); clif_displaymessage(s, info->help); return ATCE::OKAY; } - if (message == "all") + if (message == "all"_s) { - clif_displaymessage(s, "Synopses of GM commands in category 'all':"); + clif_displaymessage(s, "Synopses of GM commands in category 'all':"_s); for (const auto& pair : atcommand_info) { - const char *cmd = &*pair.first.begin(); + auto cmd = ZString(strings::really_construct_from_a_pointer, &*pair.first.begin(), nullptr); const AtCommandInfo& info = pair.second; atc_do_help(s, cmd, info); } return ATCE::OKAY; } - int low = 0, high; + // previous logic is silly + // + // @help N: list all commands available at level N + // @help M-N: list all commands available at level N that were not at level M + GmLevel low, high; + bool pass; if (extract(message, &high)) - ++high; - else if (!extract(message, record<'-'>(&low, &high))) + { + pass = true; + } + else if (extract(message, record<'-'>(&low, &high))) + { + pass = false; + } + else return ATCE::USAGE; - if (low < 0 || high > 100 || low >= high) + if (low.obsoletes(high)) return ATCE::RANGE; - clif_displaymessage(s, STRPRINTF("Synopses of GM commands in level [%d, %d):", low, high)); + if (pass) + clif_displaymessage(s, STRPRINTF("Synopses of GM commands available at level %u:"_fmt, high)); + else + clif_displaymessage(s, STRPRINTF("Synopses of GM commands available at level %u, but not at level %u:"_fmt, high, low)); for (const auto& pair : atcommand_info) { - const char *cmd = &*pair.first.begin(); + auto cmd = ZString(strings::really_construct_from_a_pointer, &*pair.first.begin(), nullptr); const AtCommandInfo& info = pair.second; - if (low <= info.level && info.level < high) + if ((!low.satisfies(info.level) || pass) && high.satisfies(info.level)) atc_do_help(s, cmd, info); } return ATCE::OKAY; @@ -467,25 +486,25 @@ ATCE atcommand_setup(Session *s, dumb_ptr<map_session_data> sd, level--; AString buf; - buf = STRPRINTF("-255 %s", character); + buf = STRPRINTF("-255 %s"_fmt, character); atcommand_character_baselevel(s, sd, buf); - buf = STRPRINTF("%d %s", level, character); + buf = STRPRINTF("%d %s"_fmt, level, character); atcommand_character_baselevel(s, sd, buf); // Emote skill - buf = STRPRINTF("1 1 %s", character); + buf = STRPRINTF("1 1 %s"_fmt, character); atcommand_skill_learn(s, sd, buf); // Trade skill - buf = STRPRINTF("2 1 %s", character); + buf = STRPRINTF("2 1 %s"_fmt, character); atcommand_skill_learn(s, sd, buf); // Party skill - STRPRINTF("2 2 %s", character); + STRPRINTF("2 2 %s"_fmt, character); atcommand_skill_learn(s, sd, buf); - STRPRINTF("018-1.gat 24 98 %s", character); + STRPRINTF("018-1.gat 24 98 %s"_fmt, character); atcommand_charwarp(s, sd, buf); return ATCE::OKAY; @@ -510,52 +529,52 @@ ATCE atcommand_charwarp(Session *s, dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); if (pl_sd) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can rura+ only lower or same GM level if (x > 0 && x < 800 && y > 0 && y < 800) { map_local *m = map_mapname2mapid(map_name); if (m != nullptr && m->flag.get(MapFlag::NOWARPTO) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level)))) { clif_displaymessage(s, - "You are not authorised to warp someone to this map."); + "You are not authorised to warp someone to this map."_s); return ATCE::PERM; } if (pl_sd->bl_m && pl_sd->bl_m->flag.get(MapFlag::NOWARP) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp this player from its actual map."); + "You are not authorised to warp this player from its actual map."_s); return ATCE::PERM; } if (pc_setpos(pl_sd, map_name, x, y, BeingRemoveWhy::WARPED) == 0) { - clif_displaymessage(pl_sd->sess, "Warped."); - clif_displaymessage(s, "Player warped (message sends to player too)."); + clif_displaymessage(pl_sd->sess, "Warped."_s); + clif_displaymessage(s, "Player warped (message sends to player too)."_s); } else { - clif_displaymessage(s, "Map not found."); + clif_displaymessage(s, "Map not found."_s); return ATCE::EXIST; } } else { - clif_displaymessage(s, "Coordinates out of range."); + clif_displaymessage(s, "Coordinates out of range."_s); return ATCE::RANGE; } } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -573,7 +592,7 @@ ATCE atcommand_warp(Session *s, dumb_ptr<map_session_data> sd, || !extract(message, record<' ', 1>(&map_name, &x, &y))) { clif_displaymessage(s, - "Please, enter a map (usage: @warp <mapname> <x> <y>)."); + "Please, enter a map (usage: @warp <mapname> <x> <y>)."_s); return ATCE::USAGE; } @@ -586,30 +605,30 @@ ATCE atcommand_warp(Session *s, dumb_ptr<map_session_data> sd, { map_local *m = map_mapname2mapid(map_name); if (m != nullptr && m->flag.get(MapFlag::NOWARPTO) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp you to this map."); + "You are not authorised to warp you to this map."_s); return ATCE::PERM; } if (sd->bl_m && sd->bl_m->flag.get(MapFlag::NOWARP) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp you from your actual map."); + "You are not authorised to warp you from your actual map."_s); return ATCE::PERM; } if (pc_setpos(sd, map_name, x, y, BeingRemoveWhy::WARPED) == 0) - clif_displaymessage(s, "Warped."); + clif_displaymessage(s, "Warped."_s); else { - clif_displaymessage(s, "Map not found."); + clif_displaymessage(s, "Map not found."_s); return ATCE::EXIST; } } else { - clif_displaymessage(s, "Coordinates out of range."); + clif_displaymessage(s, "Coordinates out of range."_s); return ATCE::RANGE; } @@ -624,20 +643,20 @@ ATCE atcommand_where(Session *s, dumb_ptr<map_session_data> sd, extract(message, &character); dumb_ptr<map_session_data> pl_sd = character.to__actual() ? map_nick2sd(character) : sd; - if (pl_sd != NULL && + if (pl_sd != nullptr && !((battle_config.hide_GM_session || bool(pl_sd->status.option & Option::HIDE)) - && (pc_isGM(pl_sd) > pc_isGM(sd)))) + && !(pc_isGM(sd).detects(pc_isGM(pl_sd))))) { // you can look only lower or same level - AString output = STRPRINTF("%s: %s (%d,%d)", + AString output = STRPRINTF("%s: %s (%d,%d)"_fmt, pl_sd->status_key.name, pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y); clif_displaymessage(s, output); } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -653,34 +672,34 @@ ATCE atcommand_goto(Session *s, dumb_ptr<map_session_data> sd, if (!asplit(message, &character)) { clif_displaymessage(s, - "Please, enter a player name (usage: @jumpto/@warpto/@goto <char name>)."); + "Please, enter a player name (usage: @jumpto/@warpto/@goto <char name>)."_s); return ATCE::USAGE; } dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { if (pl_sd->bl_m && pl_sd->bl_m->flag.get(MapFlag::NOWARPTO) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp you to the map of this player."); + "You are not authorised to warp you to the map of this player."_s); return ATCE::PERM; } if (sd->bl_m && sd->bl_m->flag.get(MapFlag::NOWARP) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp you from your actual map."); + "You are not authorised to warp you from your actual map."_s); return ATCE::PERM; } pc_setpos(sd, pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y, BeingRemoveWhy::WARPED); - AString output = STRPRINTF("Jump to %s", character); + AString output = STRPRINTF("Jump to %s"_fmt, character); clif_displaymessage(s, output); } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -702,26 +721,26 @@ ATCE atcommand_jump(Session *s, dumb_ptr<map_session_data> sd, if (x > 0 && x < 800 && y > 0 && y < 800) { if (sd->bl_m && sd->bl_m->flag.get(MapFlag::NOWARPTO) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp you to your actual map."); + "You are not authorised to warp you to your actual map."_s); return ATCE::PERM; } if (sd->bl_m && sd->bl_m->flag.get(MapFlag::NOWARP) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp you from your actual map."); + "You are not authorised to warp you from your actual map."_s); return ATCE::PERM; } pc_setpos(sd, sd->mapname_, x, y, BeingRemoveWhy::WARPED); - AString output = STRPRINTF("Jump to %d %d", x, y); + AString output = STRPRINTF("Jump to %d %d"_fmt, x, y); clif_displaymessage(s, output); } else { - clif_displaymessage(s, "Coordinates out of range."); + clif_displaymessage(s, "Coordinates out of range."_s); return ATCE::RANGE; } @@ -733,12 +752,11 @@ ATCE atcommand_who(Session *s, dumb_ptr<map_session_data> sd, ZString message) { int count; - int pl_GM_level, GM_level; VString<23> match_text = message; match_text = match_text.to_lower(); count = 0; - GM_level = pc_isGM(sd); + GmLevel gm_level = pc_isGM(sd); for (io::FD i : iter_fds()) { Session *s2 = get_session(i); @@ -747,11 +765,11 @@ ATCE atcommand_who(Session *s, dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get())); if (pl_sd && pl_sd->state.auth) { - pl_GM_level = pc_isGM(pl_sd); + GmLevel pl_gm_level = pc_isGM(pl_sd); if (! ((battle_config.hide_GM_session || bool(pl_sd->status.option & Option::HIDE)) - && (pl_GM_level > GM_level))) + && !(gm_level.detects(pl_gm_level)))) { // you can look only lower or same level VString<23> player_name = pl_sd->status_key.name.to__lower(); @@ -759,14 +777,14 @@ ATCE atcommand_who(Session *s, dumb_ptr<map_session_data> sd, { // search with no case sensitive AString output; - if (pl_GM_level > 0) + if (pl_gm_level) output = STRPRINTF( - "Name: %s (GM:%d) | Location: %s %d %d", - pl_sd->status_key.name, pl_GM_level, + "Name: %s (GM:%u) | Location: %s %d %d"_fmt, + pl_sd->status_key.name, pl_gm_level, pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y); else output = STRPRINTF( - "Name: %s | Location: %s %d %d", + "Name: %s | Location: %s %d %d"_fmt, pl_sd->status_key.name, pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y); clif_displaymessage(s, output); @@ -777,12 +795,12 @@ ATCE atcommand_who(Session *s, dumb_ptr<map_session_data> sd, } if (count == 0) - clif_displaymessage(s, "No player found."); + clif_displaymessage(s, "No player found."_s); else if (count == 1) - clif_displaymessage(s, "1 player found."); + clif_displaymessage(s, "1 player found."_s); else { - AString output = STRPRINTF("%d players found.", count); + AString output = STRPRINTF("%d players found."_fmt, count); clif_displaymessage(s, output); } @@ -794,14 +812,13 @@ ATCE atcommand_whogroup(Session *s, dumb_ptr<map_session_data> sd, ZString message) { int count; - int pl_GM_level, GM_level; - struct party *p; + PartyPair p; VString<23> match_text = message; match_text = match_text.to_lower(); count = 0; - GM_level = pc_isGM(sd); + GmLevel gm_level = pc_isGM(sd); for (io::FD i : iter_fds()) { Session *s2 = get_session(i); @@ -810,11 +827,11 @@ ATCE atcommand_whogroup(Session *s, dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get())); if (pl_sd && pl_sd->state.auth) { - pl_GM_level = pc_isGM(pl_sd); + GmLevel pl_gm_level = pc_isGM(pl_sd); if (! ((battle_config.hide_GM_session || bool(pl_sd->status.option & Option::HIDE)) - && (pl_GM_level > GM_level))) + && (!(gm_level.detects(pl_gm_level))))) { // you can look only lower or same level VString<23> player_name = pl_sd->status_key.name.to__lower(); @@ -822,12 +839,12 @@ ATCE atcommand_whogroup(Session *s, dumb_ptr<map_session_data> sd, { // search with no case sensitive p = party_search(pl_sd->status.party_id); - PartyName temp0 = p ? p->name : stringish<PartyName>("None"); + PartyName temp0 = p ? p->name : stringish<PartyName>("None"_s); AString output; - if (pl_GM_level > 0) + if (pl_gm_level) output = STRPRINTF( - "Name: %s (GM:%d) | Party: '%s'", - pl_sd->status_key.name, pl_GM_level, temp0); + "Name: %s (GM:%d) | Party: '%s'"_fmt, + pl_sd->status_key.name, pl_gm_level, temp0); clif_displaymessage(s, output); count++; } @@ -836,12 +853,12 @@ ATCE atcommand_whogroup(Session *s, dumb_ptr<map_session_data> sd, } if (count == 0) - clif_displaymessage(s, "No player found."); + clif_displaymessage(s, "No player found."_s); else if (count == 1) - clif_displaymessage(s, "1 player found."); + clif_displaymessage(s, "1 player found."_s); else { - AString output = STRPRINTF("%d players found.", count); + AString output = STRPRINTF("%d players found."_fmt, count); clif_displaymessage(s, output); } @@ -853,7 +870,6 @@ ATCE atcommand_whomap(Session *s, dumb_ptr<map_session_data> sd, ZString message) { int count; - int pl_GM_level, GM_level; map_local *map_id; { @@ -865,7 +881,7 @@ ATCE atcommand_whomap(Session *s, dumb_ptr<map_session_data> sd, } count = 0; - GM_level = pc_isGM(sd); + GmLevel gm_level = pc_isGM(sd); for (io::FD i : iter_fds()) { Session *s2 = get_session(i); @@ -874,24 +890,24 @@ ATCE atcommand_whomap(Session *s, dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get())); if (pl_sd && pl_sd->state.auth) { - pl_GM_level = pc_isGM(pl_sd); + GmLevel pl_gm_level = pc_isGM(pl_sd); if (! ((battle_config.hide_GM_session || bool(pl_sd->status.option & Option::HIDE)) - && (pl_GM_level > GM_level))) + && (!(gm_level.detects(pl_gm_level))))) { // you can look only lower or same level if (pl_sd->bl_m == map_id) { AString output; - if (pl_GM_level > 0) + if (pl_gm_level) output = STRPRINTF( - "Name: %s (GM:%d) | Location: %s %d %d", - pl_sd->status_key.name, pl_GM_level, + "Name: %s (GM:%d) | Location: %s %d %d"_fmt, + pl_sd->status_key.name, pl_gm_level, pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y); else output = STRPRINTF( - "Name: %s | Location: %s %d %d", + "Name: %s | Location: %s %d %d"_fmt, pl_sd->status_key.name, pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y); clif_displaymessage(s, output); @@ -901,7 +917,7 @@ ATCE atcommand_whomap(Session *s, dumb_ptr<map_session_data> sd, } } - AString output = STRPRINTF("%d players found in map '%s'.", + AString output = STRPRINTF("%d players found in map '%s'."_fmt, count, map_id->name_); clif_displaymessage(s, output); @@ -913,8 +929,7 @@ ATCE atcommand_whomapgroup(Session *s, dumb_ptr<map_session_data> sd, ZString message) { int count; - int pl_GM_level, GM_level; - struct party *p; + PartyPair p; map_local *map_id; { @@ -926,7 +941,7 @@ ATCE atcommand_whomapgroup(Session *s, dumb_ptr<map_session_data> sd, } count = 0; - GM_level = pc_isGM(sd); + GmLevel gm_level = pc_isGM(sd); for (io::FD i : iter_fds()) { Session *s2 = get_session(i); @@ -935,23 +950,23 @@ ATCE atcommand_whomapgroup(Session *s, dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get())); if (pl_sd && pl_sd->state.auth) { - pl_GM_level = pc_isGM(pl_sd); + GmLevel pl_gm_level = pc_isGM(pl_sd); if (! ((battle_config.hide_GM_session || bool(pl_sd->status.option & Option::HIDE)) - && (pl_GM_level > GM_level))) + && (!(gm_level.detects(pl_gm_level))))) { // you can look only lower or same level if (pl_sd->bl_m == map_id) { p = party_search(pl_sd->status.party_id); - PartyName temp0 = p ? p->name : stringish<PartyName>("None"); + PartyName temp0 = p ? p->name : stringish<PartyName>("None"_s); AString output; - if (pl_GM_level > 0) - output = STRPRINTF("Name: %s (GM:%d) | Party: '%s'", - pl_sd->status_key.name, pl_GM_level, temp0); + if (pl_gm_level) + output = STRPRINTF("Name: %s (GM:%d) | Party: '%s'"_fmt, + pl_sd->status_key.name, pl_gm_level, temp0); else - output = STRPRINTF("Name: %s | Party: '%s'", + output = STRPRINTF("Name: %s | Party: '%s'"_fmt, pl_sd->status_key.name, temp0); clif_displaymessage(s, output); count++; @@ -962,12 +977,12 @@ ATCE atcommand_whomapgroup(Session *s, dumb_ptr<map_session_data> sd, AString output; if (count == 0) - output = STRPRINTF("No player found in map '%s'.", map_id->name_); + output = STRPRINTF("No player found in map '%s'."_fmt, map_id->name_); else if (count == 1) - output = STRPRINTF("1 player found in map '%s'.", map_id->name_); + output = STRPRINTF("1 player found in map '%s'."_fmt, map_id->name_); else { - output = STRPRINTF("%d players found in map '%s'.", count, map_id->name_); + output = STRPRINTF("%d players found in map '%s'."_fmt, count, map_id->name_); } clif_displaymessage(s, output); @@ -979,14 +994,13 @@ ATCE atcommand_whogm(Session *s, dumb_ptr<map_session_data> sd, ZString message) { int count; - int pl_GM_level, GM_level; - struct party *p; + PartyPair p; VString<23> match_text = message; match_text = match_text.to_lower(); count = 0; - GM_level = pc_isGM(sd); + GmLevel gm_level = pc_isGM(sd); for (io::FD i : iter_fds()) { Session *s2 = get_session(i); @@ -995,13 +1009,13 @@ ATCE atcommand_whogm(Session *s, dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get())); if (pl_sd && pl_sd->state.auth) { - pl_GM_level = pc_isGM(pl_sd); - if (pl_GM_level > 0) + GmLevel pl_gm_level = pc_isGM(pl_sd); + if (pl_gm_level) { if (! ((battle_config.hide_GM_session || bool(pl_sd->status.option & Option::HIDE)) - && (pl_GM_level > GM_level))) + && (!(gm_level.detects(pl_gm_level))))) { // you can look only lower or same level VString<23> player_name = pl_sd->status_key.name.to__lower(); @@ -1010,20 +1024,20 @@ ATCE atcommand_whogm(Session *s, dumb_ptr<map_session_data> sd, // search with no case sensitive AString output; output = STRPRINTF( - "Name: %s (GM:%d) | Location: %s %d %d", - pl_sd->status_key.name, pl_GM_level, + "Name: %s (GM:%d) | Location: %s %d %d"_fmt, + pl_sd->status_key.name, pl_gm_level, pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y); clif_displaymessage(s, output); output = STRPRINTF( - " BLvl: %d | Job: %s (Lvl: %d)", + " BLvl: %d | Job: %s (Lvl: %d)"_fmt, pl_sd->status.base_level, - "Novice/Human", + "Novice/Human"_s, pl_sd->status.job_level); clif_displaymessage(s, output); p = party_search(pl_sd->status.party_id); - PartyName temp0 = p ? p->name : stringish<PartyName>("None"); + PartyName temp0 = p ? p->name : stringish<PartyName>("None"_s); output = STRPRINTF( - " Party: '%s'", + " Party: '%s'"_fmt, temp0); clif_displaymessage(s, output); count++; @@ -1034,12 +1048,12 @@ ATCE atcommand_whogm(Session *s, dumb_ptr<map_session_data> sd, } if (count == 0) - clif_displaymessage(s, "No GM found."); + clif_displaymessage(s, "No GM found."_s); else if (count == 1) - clif_displaymessage(s, "1 GM found."); + clif_displaymessage(s, "1 GM found."_s); else { - AString output = STRPRINTF("%d GMs found.", count); + AString output = STRPRINTF("%d GMs found."_fmt, count); clif_displaymessage(s, output); } @@ -1053,7 +1067,7 @@ ATCE atcommand_save(Session *s, dumb_ptr<map_session_data> sd, pc_setsavepoint(sd, sd->mapname_, sd->bl_x, sd->bl_y); pc_makesavestatus(sd); chrif_save(sd); - clif_displaymessage(s, "Character data respawn point saved."); + clif_displaymessage(s, "Character data respawn point saved."_s); return ATCE::OKAY; } @@ -1064,17 +1078,17 @@ ATCE atcommand_load(Session *s, dumb_ptr<map_session_data> sd, { map_local *m = map_mapname2mapid(sd->status.save_point.map_); if (m != nullptr && m->flag.get(MapFlag::NOWARPTO) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp you to your save map."); + "You are not authorised to warp you to your save map."_s); return ATCE::PERM; } if (sd->bl_m && sd->bl_m->flag.get(MapFlag::NOWARP) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp you from your actual map."); + "You are not authorised to warp you from your actual map."_s); return ATCE::PERM; } @@ -1089,7 +1103,7 @@ ATCE atcommand_load(Session *s, dumb_ptr<map_session_data> sd, pc_setpos(sd, sd->status.save_point.map_, sd->status.save_point.x, sd->status.save_point.y, BeingRemoveWhy::GONE); } - clif_displaymessage(s, "Warping to respawn point."); + clif_displaymessage(s, "Warping to respawn point."_s); return ATCE::OKAY; } @@ -1101,7 +1115,7 @@ ATCE atcommand_speed(Session *s, dumb_ptr<map_session_data> sd, if (!message) { AString output = STRPRINTF( - "Please, enter a speed value (usage: @speed <%d-%d>).", + "Please, enter a speed value (usage: @speed <%d-%d>)."_fmt, static_cast<uint32_t>(MIN_WALK_SPEED.count()), static_cast<uint32_t>(MAX_WALK_SPEED.count())); clif_displaymessage(s, output); @@ -1115,12 +1129,12 @@ ATCE atcommand_speed(Session *s, dumb_ptr<map_session_data> sd, //sd->walktimer = x; //この文を追加 by れ clif_updatestatus(sd, SP::SPEED); - clif_displaymessage(s, "Speed changed."); + clif_displaymessage(s, "Speed changed."_s); } else { AString output = STRPRINTF( - "Please, enter a valid speed value (usage: @speed <%d-%d>).", + "Please, enter a valid speed value (usage: @speed <%d-%d>)."_fmt, static_cast<uint32_t>(MIN_WALK_SPEED.count()), static_cast<uint32_t>(MAX_WALK_SPEED.count())); clif_displaymessage(s, output); @@ -1134,18 +1148,18 @@ static ATCE atcommand_storage(Session *s, dumb_ptr<map_session_data> sd, ZString) { - struct storage *stor; + Storage *stor; if (sd->state.storage_open) { - clif_displaymessage(s, "msg_table[250]"); + clif_displaymessage(s, "msg_table[250]"_s); return ATCE::EXIST; } - if ((stor = account2storage2(sd->status_key.account_id)) != NULL + if ((stor = account2storage2(sd->status_key.account_id)) != nullptr && stor->storage_status == 1) { - clif_displaymessage(s, "msg_table[250]"); + clif_displaymessage(s, "msg_table[250]"_s); return ATCE::EXIST; } @@ -1171,7 +1185,7 @@ ATCE atcommand_option(Session *s, dumb_ptr<map_session_data> sd, clif_changeoption(sd); pc_calcstatus(sd, 0); - clif_displaymessage(s, "Options changed."); + clif_displaymessage(s, "Options changed."_s); return ATCE::OKAY; } @@ -1183,12 +1197,12 @@ ATCE atcommand_hide(Session *s, dumb_ptr<map_session_data> sd, if (bool(sd->status.option & Option::HIDE)) { sd->status.option &= ~Option::HIDE; - clif_displaymessage(s, "Invisible: Off."); + clif_displaymessage(s, "Invisible: Off."_s); } else { sd->status.option |= Option::HIDE; - clif_displaymessage(s, "Invisible: On."); + clif_displaymessage(s, "Invisible: On."_s); } clif_changeoption(sd); @@ -1199,8 +1213,8 @@ static ATCE atcommand_die(Session *s, dumb_ptr<map_session_data> sd, ZString) { - pc_damage(NULL, sd, sd->status.hp + 1); - clif_displaymessage(s, "A pity! You've died."); + pc_damage(nullptr, sd, sd->status.hp + 1); + clif_displaymessage(s, "A pity! You've died."_s); return ATCE::OKAY; } @@ -1215,23 +1229,23 @@ ATCE atcommand_kill(Session *s, dumb_ptr<map_session_data> sd, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can kill only lower or same level - pc_damage(NULL, pl_sd, pl_sd->status.hp + 1); - clif_displaymessage(s, "Character killed."); + pc_damage(nullptr, pl_sd, pl_sd->status.hp + 1); + clif_displaymessage(s, "Character killed."_s); } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -1250,7 +1264,7 @@ ATCE atcommand_alive(Session *s, dumb_ptr<map_session_data> sd, clif_updatestatus(sd, SP::HP); clif_updatestatus(sd, SP::SP); clif_resurrection(sd, 1); - clif_displaymessage(s, "You've been revived! It's a miracle!"); + clif_displaymessage(s, "You've been revived! It's a miracle!"_s); return ATCE::OKAY; } @@ -1304,13 +1318,13 @@ ATCE atcommand_heal(Session *s, dumb_ptr<map_session_data> sd, { pc_heal(sd, hp, sp); if (hp >= 0 && sp >= 0) - clif_displaymessage(s, "HP, SP recovered."); + clif_displaymessage(s, "HP, SP recovered."_s); else - clif_displaymessage(s, "HP or/and SP modified."); + clif_displaymessage(s, "HP or/and SP modified."_s); } else { - clif_displaymessage(s, "HP and SP are already with the good value."); + clif_displaymessage(s, "HP and SP are already with the good value."_s); return ATCE::RANGE; } @@ -1322,29 +1336,29 @@ ATCE atcommand_item(Session *s, dumb_ptr<map_session_data> sd, ZString message) { XString item_name; - int number = 0, item_id; - struct item_data *item_data = NULL; + int number = 0; + ItemNameId item_id; + struct item_data *item_data = nullptr; int get_count, i; if (!extract(message, record<' ', 1>(&item_name, &number))) { clif_displaymessage(s, - "Please, enter an item name/id (usage: @item <item name or ID> [quantity])."); + "Please, enter an item name/id (usage: @item <item name or ID> [quantity])."_s); return ATCE::USAGE; } if (number <= 0) number = 1; - item_id = 0; - if ((item_data = itemdb_searchname(item_name)) != NULL) + if ((item_data = itemdb_searchname(item_name)) != nullptr) item_id = item_data->nameid; - else if (extract(item_name, &item_id) && (item_data = itemdb_exists(item_id)) != NULL) + else if (extract(item_name, &item_id) && (item_data = itemdb_exists(item_id)) != nullptr) item_id = item_data->nameid; else - item_id = 0; + return ATCE::EXIST; - if (item_id >= 500) + if (item_id) { get_count = number; if (item_data->type == ItemType::WEAPON @@ -1356,18 +1370,18 @@ ATCE atcommand_item(Session *s, dumb_ptr<map_session_data> sd, } for (i = 0; i < number; i += get_count) { - struct item item_tmp {}; + Item item_tmp {}; item_tmp.nameid = item_id; PickupFail flag; if ((flag = pc_additem(sd, &item_tmp, get_count)) != PickupFail::OKAY) - clif_additem(sd, 0, 0, flag); + clif_additem(sd, IOff0::from(0), 0, flag); } - clif_displaymessage(s, "Item created."); + clif_displaymessage(s, "Item created."_s); } else { - clif_displaymessage(s, "Invalid item ID or name."); + clif_displaymessage(s, "Invalid item ID or name."_s); return ATCE::EXIST; } @@ -1378,15 +1392,13 @@ static ATCE atcommand_itemreset(Session *s, dumb_ptr<map_session_data> sd, ZString) { - int i; - - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { if (sd->status.inventory[i].amount && sd->status.inventory[i].equip == EPOS::ZERO) pc_delitem(sd, i, sd->status.inventory[i].amount, 0); } - clif_displaymessage(s, "All of your items have been removed."); + clif_displaymessage(s, "All of your items have been removed."_s); return ATCE::OKAY; } @@ -1409,7 +1421,7 @@ ATCE atcommand_baselevelup(Session *s, dumb_ptr<map_session_data> sd, if (!extract(message, &level) || !level) { clif_displaymessage(s, - "Please, enter a level adjustement (usage: @blvl <number of levels>)."); + "Please, enter a level adjustement (usage: @blvl <number of levels>)."_s); return ATCE::USAGE; } @@ -1417,7 +1429,7 @@ ATCE atcommand_baselevelup(Session *s, dumb_ptr<map_session_data> sd, { if (sd->status.base_level == battle_config.maximum_level) { - clif_displaymessage(s, "Base level can't go any higher."); + clif_displaymessage(s, "Base level can't go any higher."_s); return ATCE::RANGE; } if (level > battle_config.maximum_level || level > (battle_config.maximum_level - sd->status.base_level)) @@ -1432,13 +1444,13 @@ ATCE atcommand_baselevelup(Session *s, dumb_ptr<map_session_data> sd, pc_calcstatus(sd, 0); pc_heal(sd, sd->status.max_hp, sd->status.max_sp); clif_misceffect(sd, 0); - clif_displaymessage(s, "Base level raised."); + clif_displaymessage(s, "Base level raised."_s); } else { if (sd->status.base_level == 1) { - clif_displaymessage(s, "Base level can't go any lower."); + clif_displaymessage(s, "Base level can't go any lower."_s); return ATCE::USAGE; } if (level < -battle_config.maximum_level || level < (1 - sd->status.base_level)) @@ -1458,7 +1470,7 @@ ATCE atcommand_baselevelup(Session *s, dumb_ptr<map_session_data> sd, clif_updatestatus(sd, SP::BASELEVEL); clif_updatestatus(sd, SP::NEXTBASEEXP); pc_calcstatus(sd, 0); - clif_displaymessage(s, "Base level lowered."); + clif_displaymessage(s, "Base level lowered."_s); } return ATCE::OKAY; @@ -1481,7 +1493,7 @@ ATCE atcommand_joblevelup(Session *s, dumb_ptr<map_session_data> sd, { if (sd->status.job_level == up_level) { - clif_displaymessage(s, "Job level can't go any higher."); + clif_displaymessage(s, "Job level can't go any higher."_s); return ATCE::RANGE; } if (level > up_level || level > (up_level - sd->status.job_level)) @@ -1494,13 +1506,13 @@ ATCE atcommand_joblevelup(Session *s, dumb_ptr<map_session_data> sd, clif_updatestatus(sd, SP::SKILLPOINT); pc_calcstatus(sd, 0); clif_misceffect(sd, 1); - clif_displaymessage(s, "Job level raised."); + clif_displaymessage(s, "Job level raised."_s); } else { if (sd->status.job_level == 1) { - clif_displaymessage(s, "Job level can't go any lower."); + clif_displaymessage(s, "Job level can't go any lower."_s); return ATCE::RANGE; } if (level < -up_level || level < (1 - sd->status.job_level)) @@ -1518,7 +1530,7 @@ ATCE atcommand_joblevelup(Session *s, dumb_ptr<map_session_data> sd, } // to add: remove status points from skills pc_calcstatus(sd, 0); - clif_displaymessage(s, "Job level lowered."); + clif_displaymessage(s, "Job level lowered."_s); } return ATCE::OKAY; @@ -1534,7 +1546,7 @@ ATCE atcommand_gm(Session *s, dumb_ptr<map_session_data> sd, if (pc_isGM(sd)) { // a GM can not use this function. only a normal player (become gm is not for gm!) - clif_displaymessage(s, "You already have some GM powers."); + clif_displaymessage(s, "You already have some GM powers."_s); return ATCE::PERM; } else @@ -1550,7 +1562,7 @@ ATCE atcommand_pvpoff(Session *s, dumb_ptr<map_session_data> sd, if (battle_config.pk_mode) { //disable command if server is in PK mode [Valaris] - clif_displaymessage(s, "This option cannot be used in PK Mode."); + clif_displaymessage(s, "This option cannot be used in PK Mode."_s); return ATCE::EXIST; } @@ -1571,11 +1583,11 @@ ATCE atcommand_pvpoff(Session *s, dumb_ptr<map_session_data> sd, } } } - clif_displaymessage(s, "PvP: Off."); + clif_displaymessage(s, "PvP: Off."_s); } else { - clif_displaymessage(s, "PvP is already Off."); + clif_displaymessage(s, "PvP is already Off."_s); return ATCE::EXIST; } @@ -1589,7 +1601,7 @@ ATCE atcommand_pvpon(Session *s, dumb_ptr<map_session_data> sd, if (battle_config.pk_mode) { //disable command if server is in PK mode [Valaris] - clif_displaymessage(s, "This option cannot be used in PK Mode."); + clif_displaymessage(s, "This option cannot be used in PK Mode."_s); return ATCE::EXIST; } @@ -1606,7 +1618,7 @@ ATCE atcommand_pvpon(Session *s, dumb_ptr<map_session_data> sd, { if (sd->bl_m == pl_sd->bl_m && !pl_sd->pvp_timer) { - pl_sd->pvp_timer = Timer(gettick() + std::chrono::milliseconds(200), + pl_sd->pvp_timer = Timer(gettick() + 200_ms, std::bind(pc_calc_pvprank_timer, ph::_1, ph::_2, pl_sd->bl_id)); pl_sd->pvp_rank = 0; pl_sd->pvp_lastusers = 0; @@ -1614,11 +1626,11 @@ ATCE atcommand_pvpon(Session *s, dumb_ptr<map_session_data> sd, } } } - clif_displaymessage(s, "PvP: On."); + clif_displaymessage(s, "PvP: On."_s); } else { - clif_displaymessage(s, "PvP is already On."); + clif_displaymessage(s, "PvP is already On."_s); return ATCE::EXIST; } @@ -1642,7 +1654,7 @@ ATCE atcommand_model(Session *s, dumb_ptr<map_session_data> sd, pc_changelook(sd, LOOK::HAIR, hair_style); pc_changelook(sd, LOOK::HAIR_COLOR, hair_color); pc_changelook(sd, LOOK::CLOTHES_COLOR, cloth_color); - clif_displaymessage(s, "Appearence changed."); + clif_displaymessage(s, "Appearence changed."_s); } } else @@ -1664,7 +1676,7 @@ ATCE atcommand_dye(Session *s, dumb_ptr<map_session_data> sd, { { pc_changelook(sd, LOOK::CLOTHES_COLOR, cloth_color); - clif_displaymessage(s, "Appearence changed."); + clif_displaymessage(s, "Appearence changed."_s); } } else @@ -1686,7 +1698,7 @@ ATCE atcommand_hair_style(Session *s, dumb_ptr<map_session_data> sd, { { pc_changelook(sd, LOOK::HAIR, hair_style); - clif_displaymessage(s, "Appearence changed."); + clif_displaymessage(s, "Appearence changed."_s); } } else @@ -1708,7 +1720,7 @@ ATCE atcommand_hair_color(Session *s, dumb_ptr<map_session_data> sd, { { pc_changelook(sd, LOOK::HAIR_COLOR, hair_color); - clif_displaymessage(s, "Appearence changed."); + clif_displaymessage(s, "Appearence changed."_s); } } else @@ -1722,22 +1734,21 @@ ATCE atcommand_spawn(Session *s, dumb_ptr<map_session_data> sd, ZString message) { MobName monster; - int mob_id; + Species mob_id; int number = 0; int x = 0, y = 0; int count; - int i, j, k; int mx, my, range; if (!extract(message, record<' ', 1>(&monster, &number, &x, &y))) return ATCE::USAGE; // If monster identifier/name argument is a name - if ((mob_id = mobdb_searchname(monster)) == 0) + if ((mob_id = mobdb_searchname(monster)) == Species()) // check name first (to avoid possible name begining by a number) - mob_id = mobdb_checkid(atoi(monster.c_str())); + mob_id = mobdb_checkid(wrap<Species>(atoi(monster.c_str()))); - if (mob_id == 0) + if (mob_id == Species()) return ATCE::EXIST; if (number <= 0) @@ -1749,18 +1760,18 @@ ATCE atcommand_spawn(Session *s, dumb_ptr<map_session_data> sd, number = battle_config.atcommand_spawn_quantity_limit; if (battle_config.etc_log) - PRINTF("@spawn monster='%s' id=%d count=%d (%d,%d)\n", + PRINTF("@spawn monster='%s' id=%d count=%d (%d,%d)\n"_fmt, monster, mob_id, number, x, y); count = 0; range = sqrt(number) / 2; range = range * 2 + 5; // calculation of an odd number (+ 4 area around) - for (i = 0; i < number; i++) + for (int i = 0; i < number; i++) { - j = 0; - k = 0; - while (j++ < 8 && k == 0) + int j = 0; + BlockId k; + while (j++ < 8 && !k) { // try 8 times to spawn the monster (needed for close area) if (x <= 0) @@ -1773,21 +1784,21 @@ ATCE atcommand_spawn(Session *s, dumb_ptr<map_session_data> sd, my = y; k = mob_once_spawn(sd, MOB_THIS_MAP, mx, my, MobName(), mob_id, 1, NpcEvent()); } - count += (k != 0) ? 1 : 0; + count += k ? 1 : 0; } if (count != 0) if (number == count) - clif_displaymessage(s, "All monster summoned!"); + clif_displaymessage(s, "All monster summoned!"_s); else { - AString output = STRPRINTF("%d monster(s) summoned!", + AString output = STRPRINTF("%d monster(s) summoned!"_fmt, count); clif_displaymessage(s, output); } else { - clif_displaymessage(s, "Invalid monster ID or name."); + clif_displaymessage(s, "Invalid monster ID or name."_s); return ATCE::EXIST; } @@ -1813,7 +1824,7 @@ void atcommand_killmonster_sub(Session *s, dumb_ptr<map_session_data> sd, map_id->xs, map_id->ys, BL::MOB); - clif_displaymessage(s, "All monsters killed!"); + clif_displaymessage(s, "All monsters killed!"_s); } static @@ -1830,7 +1841,7 @@ void atlist_nearby_sub(dumb_ptr<block_list> bl, Session *s) { nullpo_retv(bl); - AString buf = STRPRINTF(" - \"%s\"", + AString buf = STRPRINTF(" - \"%s\""_fmt, bl->is_player()->status_key.name); clif_displaymessage(s, buf); } @@ -1839,7 +1850,7 @@ static ATCE atcommand_list_nearby(Session *s, dumb_ptr<map_session_data> sd, ZString) { - clif_displaymessage(s, "Nearby players:"); + clif_displaymessage(s, "Nearby players:"_s); map_foreachinarea(std::bind(atlist_nearby_sub, ph::_1, s), sd->bl_m, sd->bl_x - 1, sd->bl_y - 1, @@ -1867,7 +1878,7 @@ ATCE atcommand_gat(Session *s, dumb_ptr<map_session_data> sd, for (y = 2; y >= -2; y--) { AString output = STRPRINTF( - "%s (x= %d, y= %d) %02X %02X %02X %02X %02X", + "%s (x= %d, y= %d) %02X %02X %02X %02X %02X"_fmt, sd->bl_m->name_, sd->bl_x - 2, sd->bl_y + y, map_getcell(sd->bl_m, sd->bl_x - 2, sd->bl_y + y), map_getcell(sd->bl_m, sd->bl_x - 1, sd->bl_y + y), @@ -1916,7 +1927,7 @@ ATCE atcommand_statuspoint(Session *s, dumb_ptr<map_session_data> sd, { sd->status.status_point = new_status_point; clif_updatestatus(sd, SP::STATUSPOINT); - clif_displaymessage(s, "Number of status points changed!"); + clif_displaymessage(s, "Number of status points changed!"_s); } else return ATCE::RANGE; @@ -1945,7 +1956,7 @@ ATCE atcommand_skillpoint(Session *s, dumb_ptr<map_session_data> sd, { sd->status.skill_point = new_skill_point; clif_updatestatus(sd, SP::SKILLPOINT); - clif_displaymessage(s, "Number of skill points changed!"); + clif_displaymessage(s, "Number of skill points changed!"_s); } else return ATCE::RANGE; @@ -1974,7 +1985,7 @@ ATCE atcommand_zeny(Session *s, dumb_ptr<map_session_data> sd, { sd->status.zeny = new_zeny; clif_updatestatus(sd, SP::ZENY); - clif_displaymessage(s, "Number of zenys changed!"); + clif_displaymessage(s, "Number of zenys changed!"_s); } else return ATCE::RANGE; @@ -2006,7 +2017,7 @@ ATCE atcommand_param(Session *s, dumb_ptr<map_session_data> sd, clif_updatestatus(sd, attr_to_sp(attr)); clif_updatestatus(sd, attr_to_usp(attr)); pc_calcstatus(sd, 0); - clif_displaymessage(s, "Stat changed."); + clif_displaymessage(s, "Stat changed."_s); } else return ATCE::RANGE; @@ -2047,7 +2058,7 @@ ATCE atcommand_all_stats(Session *s, dumb_ptr<map_session_data> sd, if (count > 0) // if at least 1 stat modified - clif_displaymessage(s, "All stats changed!"); + clif_displaymessage(s, "All stats changed!"_s); else return ATCE::RANGE; @@ -2064,38 +2075,38 @@ ATCE atcommand_recall(Session *s, dumb_ptr<map_session_data> sd, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can recall only lower or same level if (sd->bl_m && sd->bl_m->flag.get(MapFlag::NOWARPTO) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp somenone to your actual map."); + "You are not authorised to warp somenone to your actual map."_s); return ATCE::PERM; } if (pl_sd->bl_m && pl_sd->bl_m->flag.get(MapFlag::NOWARP) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp this player from its actual map."); + "You are not authorised to warp this player from its actual map."_s); return ATCE::PERM; } pc_setpos(pl_sd, sd->mapname_, sd->bl_x, sd->bl_y, BeingRemoveWhy::QUIT); - AString output = STRPRINTF("%s recalled!", character); + AString output = STRPRINTF("%s recalled!"_fmt, character); clif_displaymessage(s, output); } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -2112,7 +2123,7 @@ ATCE atcommand_revive(Session *s, dumb_ptr<map_session_data> sd, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { pl_sd->status.hp = pl_sd->status.max_hp; pc_setstand(pl_sd); @@ -2121,11 +2132,11 @@ ATCE atcommand_revive(Session *s, dumb_ptr<map_session_data> sd, clif_updatestatus(pl_sd, SP::HP); clif_updatestatus(pl_sd, SP::SP); clif_resurrection(pl_sd, 1); - clif_displaymessage(s, "Character revived."); + clif_displaymessage(s, "Character revived."_s); } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -2142,41 +2153,41 @@ ATCE atcommand_character_stats(Session *s, dumb_ptr<map_session_data>, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { AString output; - output = STRPRINTF("'%s' stats:", pl_sd->status_key.name); + output = STRPRINTF("'%s' stats:"_fmt, pl_sd->status_key.name); clif_displaymessage(s, output); - output = STRPRINTF("Base Level - %d", pl_sd->status.base_level), + output = STRPRINTF("Base Level - %d"_fmt, pl_sd->status.base_level); clif_displaymessage(s, output); - output = STRPRINTF("Job - Novice/Human (level %d)", pl_sd->status.job_level); + output = STRPRINTF("Job - Novice/Human (level %d)"_fmt, pl_sd->status.job_level); clif_displaymessage(s, output); - output = STRPRINTF("Hp - %d", pl_sd->status.hp); + output = STRPRINTF("Hp - %d"_fmt, pl_sd->status.hp); clif_displaymessage(s, output); - output = STRPRINTF("MaxHp - %d", pl_sd->status.max_hp); + output = STRPRINTF("MaxHp - %d"_fmt, pl_sd->status.max_hp); clif_displaymessage(s, output); - output = STRPRINTF("Sp - %d", pl_sd->status.sp); + output = STRPRINTF("Sp - %d"_fmt, pl_sd->status.sp); clif_displaymessage(s, output); - output = STRPRINTF("MaxSp - %d", pl_sd->status.max_sp); + output = STRPRINTF("MaxSp - %d"_fmt, pl_sd->status.max_sp); clif_displaymessage(s, output); - output = STRPRINTF("Str - %3d", pl_sd->status.attrs[ATTR::STR]); + output = STRPRINTF("Str - %3d"_fmt, pl_sd->status.attrs[ATTR::STR]); clif_displaymessage(s, output); - output = STRPRINTF("Agi - %3d", pl_sd->status.attrs[ATTR::AGI]); + output = STRPRINTF("Agi - %3d"_fmt, pl_sd->status.attrs[ATTR::AGI]); clif_displaymessage(s, output); - output = STRPRINTF("Vit - %3d", pl_sd->status.attrs[ATTR::VIT]); + output = STRPRINTF("Vit - %3d"_fmt, pl_sd->status.attrs[ATTR::VIT]); clif_displaymessage(s, output); - output = STRPRINTF("Int - %3d", pl_sd->status.attrs[ATTR::INT]); + output = STRPRINTF("Int - %3d"_fmt, pl_sd->status.attrs[ATTR::INT]); clif_displaymessage(s, output); - output = STRPRINTF("Dex - %3d", pl_sd->status.attrs[ATTR::DEX]); + output = STRPRINTF("Dex - %3d"_fmt, pl_sd->status.attrs[ATTR::DEX]); clif_displaymessage(s, output); - output = STRPRINTF("Luk - %3d", pl_sd->status.attrs[ATTR::LUK]); + output = STRPRINTF("Luk - %3d"_fmt, pl_sd->status.attrs[ATTR::LUK]); clif_displaymessage(s, output); - output = STRPRINTF("Zeny - %d", pl_sd->status.zeny); + output = STRPRINTF("Zeny - %d"_fmt, pl_sd->status.zeny); clif_displaymessage(s, output); } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -2199,41 +2210,41 @@ ATCE atcommand_character_stats_all(Session *s, dumb_ptr<map_session_data>, if (pl_sd && pl_sd->state.auth) { AString gmlevel; - if (pc_isGM(pl_sd) > 0) - gmlevel = STRPRINTF("| GM Lvl: %d", pc_isGM(pl_sd)); + if (GmLevel pl_gm_level = pc_isGM(pl_sd)) + gmlevel = STRPRINTF("| GM Lvl: %d"_fmt, pl_gm_level); else - gmlevel = " "; + gmlevel = " "_s; AString output; output = STRPRINTF( - "Name: %s | BLvl: %d | Job: Novice/Human (Lvl: %d) | HP: %d/%d | SP: %d/%d", + "Name: %s | BLvl: %d | Job: Novice/Human (Lvl: %d) | HP: %d/%d | SP: %d/%d"_fmt, pl_sd->status_key.name, pl_sd->status.base_level, pl_sd->status.job_level, pl_sd->status.hp, pl_sd->status.max_hp, pl_sd->status.sp, pl_sd->status.max_sp); clif_displaymessage(s, output); - output = STRPRINTF("STR: %d | AGI: %d | VIT: %d | INT: %d | DEX: %d | LUK: %d | Zeny: %d %s", - pl_sd->status.attrs[ATTR::STR], - pl_sd->status.attrs[ATTR::AGI], - pl_sd->status.attrs[ATTR::VIT], - pl_sd->status.attrs[ATTR::INT], - pl_sd->status.attrs[ATTR::DEX], - pl_sd->status.attrs[ATTR::LUK], - pl_sd->status.zeny, - gmlevel); + output = STRPRINTF("STR: %d | AGI: %d | VIT: %d | INT: %d | DEX: %d | LUK: %d | Zeny: %d %s"_fmt, + pl_sd->status.attrs[ATTR::STR], + pl_sd->status.attrs[ATTR::AGI], + pl_sd->status.attrs[ATTR::VIT], + pl_sd->status.attrs[ATTR::INT], + pl_sd->status.attrs[ATTR::DEX], + pl_sd->status.attrs[ATTR::LUK], + pl_sd->status.zeny, + gmlevel); clif_displaymessage(s, output); - clif_displaymessage(s, "--------"); + clif_displaymessage(s, "--------"_s); count++; } } if (count == 0) - clif_displaymessage(s, "No player found."); + clif_displaymessage(s, "No player found."_s); else if (count == 1) - clif_displaymessage(s, "1 player found."); + clif_displaymessage(s, "1 player found."_s); else { - AString output = STRPRINTF("%d players found.", count); + AString output = STRPRINTF("%d players found."_fmt, count); clif_displaymessage(s, output); } @@ -2252,9 +2263,9 @@ ATCE atcommand_character_option(Session *s, dumb_ptr<map_session_data> sd, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can change option only to lower or same level pl_sd->opt1 = opt1; @@ -2263,17 +2274,17 @@ ATCE atcommand_character_option(Session *s, dumb_ptr<map_session_data> sd, clif_changeoption(pl_sd); pc_calcstatus(pl_sd, 0); - clif_displaymessage(s, "Character's options changed."); + clif_displaymessage(s, "Character's options changed."_s); } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -2292,7 +2303,7 @@ ATCE atcommand_char_change_sex(Session *s, dumb_ptr<map_session_data> sd, { chrif_char_ask_name(sd->status_key.account_id, character, 5, HumanTimeDiff()); // type: 5 - changesex - clif_displaymessage(s, "Character name sends to char-server to ask it."); + clif_displaymessage(s, "Character name sends to char-server to ask it."_s); } return ATCE::OKAY; @@ -2310,7 +2321,7 @@ ATCE atcommand_char_block(Session *s, dumb_ptr<map_session_data> sd, { chrif_char_ask_name(sd->status_key.account_id, character, 1, HumanTimeDiff()); // type: 1 - block - clif_displaymessage(s, "Character name sends to char-server to ask it."); + clif_displaymessage(s, "Character name sends to char-server to ask it."_s); } return ATCE::OKAY; @@ -2330,7 +2341,7 @@ ATCE atcommand_char_ban(Session *s, dumb_ptr<map_session_data> sd, { chrif_char_ask_name(sd->status_key.account_id, character, 2, modif); // type: 2 - ban - clif_displaymessage(s, "Character name sends to char-server to ask it."); + clif_displaymessage(s, "Character name sends to char-server to ask it."_s); } return ATCE::OKAY; @@ -2349,7 +2360,7 @@ ATCE atcommand_char_unblock(Session *s, dumb_ptr<map_session_data> sd, // send answer to login server via char-server chrif_char_ask_name(sd->status_key.account_id, character, 3, HumanTimeDiff()); // type: 3 - unblock - clif_displaymessage(s, "Character name sends to char-server to ask it."); + clif_displaymessage(s, "Character name sends to char-server to ask it."_s); } return ATCE::OKAY; @@ -2368,7 +2379,7 @@ ATCE atcommand_char_unban(Session *s, dumb_ptr<map_session_data> sd, // send answer to login server via char-server chrif_char_ask_name(sd->status_key.account_id, character, 4, HumanTimeDiff()); // type: 4 - unban - clif_displaymessage(s, "Character name sends to char-server to ask it."); + clif_displaymessage(s, "Character name sends to char-server to ask it."_s); } return ATCE::OKAY; @@ -2387,39 +2398,39 @@ ATCE atcommand_character_save(Session *s, dumb_ptr<map_session_data> sd, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can change save point only to lower or same gm level map_local *m = map_mapname2mapid(map_name); if (m == nullptr) { - clif_displaymessage(s, "Map not found."); + clif_displaymessage(s, "Map not found."_s); return ATCE::EXIST; } else { if (m != nullptr && m->flag.get(MapFlag::NOWARPTO) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to set this map as a save map."); + "You are not authorised to set this map as a save map."_s); return ATCE::PERM; } pc_setsavepoint(pl_sd, map_name, x, y); - clif_displaymessage(s, "Character's respawn point changed."); + clif_displaymessage(s, "Character's respawn point changed."_s); } } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -2438,14 +2449,14 @@ ATCE atcommand_doom(Session *s, dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get())); if (pl_sd && pl_sd->state.auth && s2 != s - && pc_isGM(sd) >= pc_isGM(pl_sd)) + && pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can doom only lower or same gm level - pc_damage(NULL, pl_sd, pl_sd->status.hp + 1); - clif_displaymessage(pl_sd->sess, "The holy messenger has given judgement."); + pc_damage(nullptr, pl_sd, pl_sd->status.hp + 1); + clif_displaymessage(pl_sd->sess, "The holy messenger has given judgement."_s); } } - clif_displaymessage(s, "Judgement was made."); + clif_displaymessage(s, "Judgement was made."_s); return ATCE::OKAY; } @@ -2462,14 +2473,14 @@ ATCE atcommand_doommap(Session *s, dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get())); if (pl_sd && pl_sd->state.auth && s2 != s && sd->bl_m == pl_sd->bl_m - && pc_isGM(sd) >= pc_isGM(pl_sd)) + && pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can doom only lower or same gm level - pc_damage(NULL, pl_sd, pl_sd->status.hp + 1); - clif_displaymessage(pl_sd->sess, "The holy messenger has given judgement."); + pc_damage(nullptr, pl_sd, pl_sd->status.hp + 1); + clif_displaymessage(pl_sd->sess, "The holy messenger has given judgement."_s); } } - clif_displaymessage(s, "Judgement was made."); + clif_displaymessage(s, "Judgement was made."_s); return ATCE::OKAY; } @@ -2485,7 +2496,7 @@ void atcommand_raise_sub(dumb_ptr<map_session_data> sd) clif_updatestatus(sd, SP::HP); clif_updatestatus(sd, SP::SP); clif_resurrection(sd, 1); - clif_displaymessage(sd->sess, "Mercy has been shown."); + clif_displaymessage(sd->sess, "Mercy has been shown."_s); } } @@ -2501,7 +2512,7 @@ ATCE atcommand_raise(Session *s, dumb_ptr<map_session_data>, dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get())); atcommand_raise_sub(pl_sd); } - clif_displaymessage(s, "Mercy has been granted."); + clif_displaymessage(s, "Mercy has been granted."_s); return ATCE::OKAY; } @@ -2520,7 +2531,7 @@ ATCE atcommand_raisemap(Session *s, dumb_ptr<map_session_data> sd, && pl_sd->state.auth && sd->bl_m == pl_sd->bl_m) atcommand_raise_sub(pl_sd); } - clif_displaymessage(s, "Mercy has been granted."); + clif_displaymessage(s, "Mercy has been granted."_s); return ATCE::OKAY; } @@ -2537,16 +2548,16 @@ ATCE atcommand_character_baselevel(Session *s, dumb_ptr<map_session_data> sd, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can change base level only lower or same gm level if (level > 0) { if (pl_sd->status.base_level == battle_config.maximum_level) { - clif_displaymessage(s, "Character's base level can't go any higher."); + clif_displaymessage(s, "Character's base level can't go any higher."_s); return ATCE::RANGE; } if (level > battle_config.maximum_level || level > (battle_config.maximum_level - pl_sd->status.base_level)) @@ -2564,13 +2575,13 @@ ATCE atcommand_character_baselevel(Session *s, dumb_ptr<map_session_data> sd, pc_calcstatus(pl_sd, 0); pc_heal(pl_sd, pl_sd->status.max_hp, pl_sd->status.max_sp); clif_misceffect(pl_sd, 0); - clif_displaymessage(s, "Character's base level raised."); + clif_displaymessage(s, "Character's base level raised."_s); } else { if (pl_sd->status.base_level == 1) { - clif_displaymessage(s, "Character's base level can't go any lower."); + clif_displaymessage(s, "Character's base level can't go any lower."_s); return ATCE::RANGE; } if (level < -battle_config.maximum_level || level < (1 - pl_sd->status.base_level)) @@ -2592,20 +2603,20 @@ ATCE atcommand_character_baselevel(Session *s, dumb_ptr<map_session_data> sd, clif_updatestatus(pl_sd, SP::NEXTBASEEXP); clif_updatestatus(pl_sd, SP::BASEEXP); pc_calcstatus(pl_sd, 0); - clif_displaymessage(s, "Character's base level lowered."); + clif_displaymessage(s, "Character's base level lowered."_s); } // Reset their stat points to prevent extra points from stacking atcommand_charstreset(s, sd, character.to__actual()); } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -2624,9 +2635,9 @@ ATCE atcommand_character_joblevel(Session *s, dumb_ptr<map_session_data> sd, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can change job level only lower or same gm level max_level -= 40; @@ -2635,7 +2646,7 @@ ATCE atcommand_character_joblevel(Session *s, dumb_ptr<map_session_data> sd, { if (pl_sd->status.job_level == max_level) { - clif_displaymessage(s, "Character's job level can't go any higher."); + clif_displaymessage(s, "Character's job level can't go any higher."_s); return ATCE::RANGE; } if (pl_sd->status.job_level + level > max_level) @@ -2647,13 +2658,13 @@ ATCE atcommand_character_joblevel(Session *s, dumb_ptr<map_session_data> sd, clif_updatestatus(pl_sd, SP::SKILLPOINT); pc_calcstatus(pl_sd, 0); clif_misceffect(pl_sd, 1); - clif_displaymessage(s, "character's job level raised."); + clif_displaymessage(s, "character's job level raised."_s); } else { if (pl_sd->status.job_level == 1) { - clif_displaymessage(s, "Character's job level can't go any lower."); + clif_displaymessage(s, "Character's job level can't go any lower."_s); return ATCE::RANGE; } if (pl_sd->status.job_level + level < 1) @@ -2670,18 +2681,18 @@ ATCE atcommand_character_joblevel(Session *s, dumb_ptr<map_session_data> sd, } // to add: remove status points from skills pc_calcstatus(pl_sd, 0); - clif_displaymessage(s, "Character's job level lowered."); + clif_displaymessage(s, "Character's job level lowered."_s); } } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -2698,20 +2709,20 @@ ATCE atcommand_kick(Session *s, dumb_ptr<map_session_data> sd, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) // you can kick only lower or same gm level clif_GM_kick(sd, pl_sd, 1); else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -2729,7 +2740,7 @@ ATCE atcommand_kickall(Session *s, dumb_ptr<map_session_data> sd, continue; dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get())); if (pl_sd - && pl_sd->state.auth && pc_isGM(sd) >= pc_isGM(pl_sd)) + && pl_sd->state.auth && pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can kick only lower or same gm level if (sd->status_key.account_id != pl_sd->status_key.account_id) @@ -2737,7 +2748,7 @@ ATCE atcommand_kickall(Session *s, dumb_ptr<map_session_data> sd, } } - clif_displaymessage(s, "All players have been kicked!"); + clif_displaymessage(s, "All players have been kicked!"_s); return ATCE::OKAY; } @@ -2758,23 +2769,23 @@ ATCE atcommand_questskill(Session *s, dumb_ptr<map_session_data> sd, if (pc_checkskill(sd, skill_id) == 0) { pc_skill(sd, skill_id, 1, 0); - clif_displaymessage(s, "You have learned the skill."); + clif_displaymessage(s, "You have learned the skill."_s); } else { - clif_displaymessage(s, "You already have this quest skill."); + clif_displaymessage(s, "You already have this quest skill."_s); return ATCE::EXIST; } } else { - clif_displaymessage(s, "This skill number doesn't exist or isn't a quest skill."); + clif_displaymessage(s, "This skill number doesn't exist or isn't a quest skill."_s); return ATCE::RANGE; } } else { - clif_displaymessage(s, "This skill number doesn't exist."); + clif_displaymessage(s, "This skill number doesn't exist."_s); return ATCE::RANGE; } @@ -2796,34 +2807,34 @@ ATCE atcommand_charquestskill(Session *s, dumb_ptr<map_session_data>, if (skill_get_inf2(skill_id) & 0x01) { dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { if (pc_checkskill(pl_sd, skill_id) == 0) { pc_skill(pl_sd, skill_id, 1, 0); - clif_displaymessage(s, "This player has learned the skill."); + clif_displaymessage(s, "This player has learned the skill."_s); } else { - clif_displaymessage(s, "This player already has this quest skill."); + clif_displaymessage(s, "This player already has this quest skill."_s); return ATCE::EXIST; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } } else { - clif_displaymessage(s, "This skill number doesn't exist or isn't a quest skill."); + clif_displaymessage(s, "This skill number doesn't exist or isn't a quest skill."_s); return ATCE::RANGE; } } else { - clif_displaymessage(s, "This skill number doesn't exist."); + clif_displaymessage(s, "This skill number doesn't exist."_s); return ATCE::RANGE; } @@ -2848,23 +2859,23 @@ ATCE atcommand_lostskill(Session *s, dumb_ptr<map_session_data> sd, sd->status.skill[skill_id].lv = 0; sd->status.skill[skill_id].flags = SkillFlags::ZERO; clif_skillinfoblock(sd); - clif_displaymessage(s, "You have forgotten the skill."); + clif_displaymessage(s, "You have forgotten the skill."_s); } else { - clif_displaymessage(s, "You don't have this quest skill."); + clif_displaymessage(s, "You don't have this quest skill."_s); return ATCE::EXIST; } } else { - clif_displaymessage(s, "This skill number doesn't exist or isn't a quest skill."); + clif_displaymessage(s, "This skill number doesn't exist or isn't a quest skill."_s); return ATCE::RANGE; } } else { - clif_displaymessage(s, "This skill number doesn't exist."); + clif_displaymessage(s, "This skill number doesn't exist."_s); return ATCE::RANGE; } @@ -2886,36 +2897,36 @@ ATCE atcommand_charlostskill(Session *s, dumb_ptr<map_session_data>, if (skill_get_inf2(skill_id) & 0x01) { dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { if (pc_checkskill(pl_sd, skill_id) > 0) { pl_sd->status.skill[skill_id].lv = 0; pl_sd->status.skill[skill_id].flags = SkillFlags::ZERO; clif_skillinfoblock(pl_sd); - clif_displaymessage(s, "This player has forgotten the skill."); + clif_displaymessage(s, "This player has forgotten the skill."_s); } else { - clif_displaymessage(s, "This player doesn't have this quest skill."); + clif_displaymessage(s, "This player doesn't have this quest skill."_s); return ATCE::EXIST; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } } else { - clif_displaymessage(s, "This skill number doesn't exist or isn't a quest skill."); + clif_displaymessage(s, "This skill number doesn't exist or isn't a quest skill."_s); return ATCE::RANGE; } } else { - clif_displaymessage(s, "This skill number doesn't exist."); + clif_displaymessage(s, "This skill number doesn't exist."_s); return ATCE::RANGE; } @@ -2964,26 +2975,26 @@ ATCE atcommand_idsearch(Session *s, dumb_ptr<map_session_data>, ZString message) { ItemName item_name; - int i, match; + int match; struct item_data *item; if (!extract(message, &item_name) || !item_name) return ATCE::USAGE; - AString output = STRPRINTF("The reference result of '%s' (name: id):", item_name); + AString output = STRPRINTF("The reference result of '%s' (name: id):"_fmt, item_name); clif_displaymessage(s, output); match = 0; - for (i = 0; i < 20000; i++) + for (ItemNameId i = wrap<ItemNameId>(0); i < wrap<ItemNameId>(-1); i = next(i)) { - if ((item = itemdb_exists(i)) != NULL + if ((item = itemdb_exists(i)) != nullptr && item->jname.contains_seq(item_name)) { match++; - output = STRPRINTF("%s: %d", item->jname, item->nameid); + output = STRPRINTF("%s: %d"_fmt, item->jname, item->nameid); clif_displaymessage(s, output); } } - output = STRPRINTF("It is %d affair above.", match); + output = STRPRINTF("It is %d affair above."_fmt, match); clif_displaymessage(s, output); return ATCE::OKAY; @@ -2999,25 +3010,25 @@ ATCE atcommand_charskreset(Session *s, dumb_ptr<map_session_data> sd, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can reset skill points only lower or same gm level pc_resetskill(pl_sd); AString output = STRPRINTF( - "'%s' skill points reseted!", character); + "'%s' skill points reseted!"_fmt, character); clif_displaymessage(s, output); } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -3034,26 +3045,26 @@ ATCE atcommand_charstreset(Session *s, dumb_ptr<map_session_data> sd, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can reset stats points only lower or same gm level pc_resetstate(pl_sd); AString output = STRPRINTF( - "'%s' stats points reseted!", + "'%s' stats points reseted!"_fmt, character); clif_displaymessage(s, output); } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -3070,30 +3081,30 @@ ATCE atcommand_charreset(Session *s, dumb_ptr<map_session_data> sd, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can reset a character only for lower or same GM level pc_resetstate(pl_sd); pc_resetskill(pl_sd); - pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_FLAGS"), 0); + pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_FLAGS"_s), 0); // [Fate] Reset magic quest variables - pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_EXP"), 0); + pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_EXP"_s), 0); // [Fate] Reset magic experience AString output = STRPRINTF( - "'%s' skill and stats points reseted!", character); + "'%s' skill and stats points reseted!"_fmt, character); clif_displaymessage(s, output); } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -3110,12 +3121,11 @@ ATCE atcommand_char_wipe(Session *s, dumb_ptr<map_session_data> sd, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can reset a character only for lower or same GM level - int i; // Reset base level pl_sd->status.base_level = 1; @@ -3136,7 +3146,7 @@ ATCE atcommand_char_wipe(Session *s, dumb_ptr<map_session_data> sd, clif_updatestatus(pl_sd, SP::ZENY); // Clear inventory - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { if (sd->status.inventory[i].amount) { @@ -3147,33 +3157,33 @@ ATCE atcommand_char_wipe(Session *s, dumb_ptr<map_session_data> sd, } // Give knife and shirt - struct item item; - item.nameid = 1201; + Item item; + item.nameid = wrap<ItemNameId>(1201); pc_additem(pl_sd, &item, 1); - item.nameid = 1202; + item.nameid = wrap<ItemNameId>(1202); pc_additem(pl_sd, &item, 1); // Reset stats and skills pc_calcstatus(pl_sd, 0); pc_resetstate(pl_sd); pc_resetskill(pl_sd); - pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_FLAGS"), 0); + pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_FLAGS"_s), 0); // [Fate] Reset magic quest variables - pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_EXP"), 0); + pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_EXP"_s), 0); // [Fate] Reset magic experience - AString output = STRPRINTF("%s: wiped.", character); + AString output = STRPRINTF("%s: wiped."_fmt, character); clif_displaymessage(s, output); } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -3191,7 +3201,7 @@ ATCE atcommand_charmodel(Session *s, dumb_ptr<map_session_data>, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE && hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR && @@ -3201,7 +3211,7 @@ ATCE atcommand_charmodel(Session *s, dumb_ptr<map_session_data>, pc_changelook(pl_sd, LOOK::HAIR, hair_style); pc_changelook(pl_sd, LOOK::HAIR_COLOR, hair_color); pc_changelook(pl_sd, LOOK::CLOTHES_COLOR, cloth_color); - clif_displaymessage(s, "Appearence changed."); + clif_displaymessage(s, "Appearence changed."_s); } } else @@ -3209,7 +3219,7 @@ ATCE atcommand_charmodel(Session *s, dumb_ptr<map_session_data>, } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -3229,7 +3239,7 @@ ATCE atcommand_charskpoint(Session *s, dumb_ptr<map_session_data>, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { new_skill_point = pl_sd->status.skill_point + point; if (point > 0 && (point > 0x7FFF || new_skill_point > 0x7FFF)) @@ -3242,14 +3252,14 @@ ATCE atcommand_charskpoint(Session *s, dumb_ptr<map_session_data>, { pl_sd->status.skill_point = new_skill_point; clif_updatestatus(pl_sd, SP::SKILLPOINT); - clif_displaymessage(s, "Character's number of skill points changed!"); + clif_displaymessage(s, "Character's number of skill points changed!"_s); } else return ATCE::RANGE; } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -3269,7 +3279,7 @@ ATCE atcommand_charstpoint(Session *s, dumb_ptr<map_session_data>, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { new_status_point = pl_sd->status.status_point + point; if (point > 0 && (point > 0x7FFF || new_status_point > 0x7FFF)) @@ -3282,14 +3292,14 @@ ATCE atcommand_charstpoint(Session *s, dumb_ptr<map_session_data>, { pl_sd->status.status_point = new_status_point; clif_updatestatus(pl_sd, SP::STATUSPOINT); - clif_displaymessage(s, "Character's number of status points changed!"); + clif_displaymessage(s, "Character's number of status points changed!"_s); } else return ATCE::RANGE; } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -3307,7 +3317,7 @@ ATCE atcommand_charzeny(Session *s, dumb_ptr<map_session_data>, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { new_zeny = pl_sd->status.zeny + zeny; if (zeny > 0 && (zeny > MAX_ZENY || new_zeny > MAX_ZENY)) @@ -3320,14 +3330,14 @@ ATCE atcommand_charzeny(Session *s, dumb_ptr<map_session_data>, { pl_sd->status.zeny = new_zeny; clif_updatestatus(pl_sd, SP::ZENY); - clif_displaymessage(s, "Character's number of zenys changed!"); + clif_displaymessage(s, "Character's number of zenys changed!"_s); } else return ATCE::RANGE; } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -3341,10 +3351,10 @@ ATCE atcommand_recallall(Session *s, dumb_ptr<map_session_data> sd, int count; if (sd->bl_m && sd->bl_m->flag.get(MapFlag::NOWARPTO) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp somenone to your actual map."); + "You are not authorised to warp somenone to your actual map."_s); return ATCE::PERM; } @@ -3358,22 +3368,22 @@ ATCE atcommand_recallall(Session *s, dumb_ptr<map_session_data> sd, if (pl_sd && pl_sd->state.auth && sd->status_key.account_id != pl_sd->status_key.account_id - && pc_isGM(sd) >= pc_isGM(pl_sd)) + && pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can recall only lower or same level if (pl_sd->bl_m && pl_sd->bl_m->flag.get(MapFlag::NOWARP) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) count++; else pc_setpos(pl_sd, sd->mapname_, sd->bl_x, sd->bl_y, BeingRemoveWhy::QUIT); } } - clif_displaymessage(s, "All characters recalled!"); + clif_displaymessage(s, "All characters recalled!"_s); if (count) { AString output = STRPRINTF( - "Because you are not authorised to warp from some maps, %d player(s) have not been recalled.", + "Because you are not authorised to warp from some maps, %d player(s) have not been recalled."_fmt, count); clif_displaymessage(s, output); } @@ -3386,23 +3396,23 @@ ATCE atcommand_partyrecall(Session *s, dumb_ptr<map_session_data> sd, ZString message) { PartyName party_name; - struct party *p; + PartyPair p; int count; if (!extract(message, &party_name) || !party_name) return ATCE::USAGE; if (sd->bl_m && sd->bl_m->flag.get(MapFlag::NOWARPTO) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp somenone to your actual map."); + "You are not authorised to warp somenone to your actual map."_s); return ATCE::PERM; } - if ((p = party_searchname(party_name)) != NULL || + if ((p = party_searchname(party_name)) || // name first to avoid error when name begin with a number - (p = party_search(atoi(message.c_str()))) != NULL) + (p = party_search(wrap<PartyId>(static_cast<uint32_t>(atoi(message.c_str())))))) { count = 0; for (io::FD i : iter_fds()) @@ -3413,28 +3423,28 @@ ATCE atcommand_partyrecall(Session *s, dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get())); if (pl_sd && pl_sd->state.auth && sd->status_key.account_id != pl_sd->status_key.account_id - && pl_sd->status.party_id == p->party_id) + && pl_sd->status.party_id == p.party_id) { if (pl_sd->bl_m && pl_sd->bl_m->flag.get(MapFlag::NOWARP) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) count++; else pc_setpos(pl_sd, sd->mapname_, sd->bl_x, sd->bl_y, BeingRemoveWhy::QUIT); } } - AString output = STRPRINTF("All online characters of the %s party are near you.", p->name); + AString output = STRPRINTF("All online characters of the %s party are near you."_fmt, p->name); clif_displaymessage(s, output); if (count) { output = STRPRINTF( - "Because you are not authorised to warp from some maps, %d player(s) have not been recalled.", + "Because you are not authorised to warp from some maps, %d player(s) have not been recalled."_fmt, count); clif_displaymessage(s, output); } } else { - clif_displaymessage(s, "Incorrect name or ID, or no one from the party is online."); + clif_displaymessage(s, "Incorrect name or ID, or no one from the party is online."_s); return ATCE::EXIST; } @@ -3445,9 +3455,9 @@ static ATCE atcommand_mapinfo(Session *s, dumb_ptr<map_session_data> sd, ZString message) { - dumb_ptr<npc_data> nd = NULL; + dumb_ptr<npc_data> nd = nullptr; MapName map_name; - const char *direction = NULL; + LString direction = ""_s; int list = 0; extract(message, record<' '>(&list, &map_name)); @@ -3462,35 +3472,35 @@ ATCE atcommand_mapinfo(Session *s, dumb_ptr<map_session_data> sd, if (m_id != nullptr) return ATCE::EXIST; - clif_displaymessage(s, "------ Map Info ------"); - AString output = STRPRINTF("Map Name: %s", map_name); + clif_displaymessage(s, "------ Map Info ------"_s); + AString output = STRPRINTF("Map Name: %s"_fmt, map_name); clif_displaymessage(s, output); - output = STRPRINTF("Players In Map: %d", m_id->users); + output = STRPRINTF("Players In Map: %d"_fmt, m_id->users); clif_displaymessage(s, output); - output = STRPRINTF("NPCs In Map: %d", m_id->npc_num); + output = STRPRINTF("NPCs In Map: %d"_fmt, m_id->npc_num); clif_displaymessage(s, output); - clif_displaymessage(s, "------ Map Flags ------"); - output = STRPRINTF("Player vs Player: %s | No Party: %s", - (m_id->flag.get(MapFlag::PVP)) ? "True" : "False", - (m_id->flag.get(MapFlag::PVP_NOPARTY)) ? "True" : "False"); + clif_displaymessage(s, "------ Map Flags ------"_s); + output = STRPRINTF("Player vs Player: %s | No Party: %s"_fmt, + (m_id->flag.get(MapFlag::PVP)) ? "True"_s : "False"_s, + (m_id->flag.get(MapFlag::PVP_NOPARTY)) ? "True"_s : "False"_s); clif_displaymessage(s, output); - output = STRPRINTF("No Penalty: %s", - (m_id->flag.get(MapFlag::NOPENALTY)) ? "True" : "False"); + output = STRPRINTF("No Penalty: %s"_fmt, + (m_id->flag.get(MapFlag::NOPENALTY)) ? "True"_s : "False"_s); clif_displaymessage(s, output); - output = STRPRINTF("No Return: %s", - (m_id->flag.get(MapFlag::NORETURN)) ? "True" : "False"); + output = STRPRINTF("No Return: %s"_fmt, + (m_id->flag.get(MapFlag::NORETURN)) ? "True"_s : "False"_s); clif_displaymessage(s, output); - output = STRPRINTF("No Save: %s", - (m_id->flag.get(MapFlag::NOSAVE)) ? "True" : "False"); + output = STRPRINTF("No Save: %s"_fmt, + (m_id->flag.get(MapFlag::NOSAVE)) ? "True"_s : "False"_s); clif_displaymessage(s, output); - output = STRPRINTF("Re Save: %s", - (m_id->flag.get(MapFlag::RESAVE)) ? "True" : "False"); + output = STRPRINTF("Re Save: %s"_fmt, + (m_id->flag.get(MapFlag::RESAVE)) ? "True"_s : "False"_s); clif_displaymessage(s, output); - output = STRPRINTF("No Teleport: %s", - (m_id->flag.get(MapFlag::NOTELEPORT)) ? "True" : "False"); + output = STRPRINTF("No Teleport: %s"_fmt, + (m_id->flag.get(MapFlag::NOTELEPORT)) ? "True"_s : "False"_s); clif_displaymessage(s, output); - output = STRPRINTF("No Monster Teleport: %s", - (m_id->flag.get(MapFlag::MONSTER_NOTELEPORT)) ? "True" : "False"); + output = STRPRINTF("No Monster Teleport: %s"_fmt, + (m_id->flag.get(MapFlag::MONSTER_NOTELEPORT)) ? "True"_s : "False"_s); clif_displaymessage(s, output); switch (list) @@ -3499,7 +3509,7 @@ ATCE atcommand_mapinfo(Session *s, dumb_ptr<map_session_data> sd, // Do nothing. It's list 0, no additional display. break; case 1: - clif_displaymessage(s, "----- Players in Map -----"); + clif_displaymessage(s, "----- Players in Map -----"_s); for (io::FD i : iter_fds()) { Session *s2 = get_session(i); @@ -3510,54 +3520,54 @@ ATCE atcommand_mapinfo(Session *s, dumb_ptr<map_session_data> sd, && pl_sd->mapname_ == map_name) { output = STRPRINTF( - "Player '%s' (session #%d) | Location: %d,%d", + "Player '%s' (session #%d) | Location: %d,%d"_fmt, pl_sd->status_key.name, s2, pl_sd->bl_x, pl_sd->bl_y); clif_displaymessage(s, output); } } break; case 2: - clif_displaymessage(s, "----- NPCs in Map -----"); + clif_displaymessage(s, "----- NPCs in Map -----"_s); for (int i = 0; i < m_id->npc_num;) { nd = m_id->npc[i]; switch (nd->dir) { case DIR::S: - direction = "North"; + direction = "North"_s; break; case DIR::SW: - direction = "North West"; + direction = "North West"_s; break; case DIR::W: - direction = "West"; + direction = "West"_s; break; case DIR::NW: - direction = "South West"; + direction = "South West"_s; break; case DIR::N: - direction = "South"; + direction = "South"_s; break; case DIR::NE: - direction = "South East"; + direction = "South East"_s; break; case DIR::E: - direction = "East"; + direction = "East"_s; break; case DIR::SE: - direction = "North East"; + direction = "North East"_s; break; #if 0 case 9: - direction = "North"; + direction = "North"_s; break; #endif default: - direction = "Unknown"; + direction = "Unknown"_s; break; } output = STRPRINTF( - "NPC %d: %s | Direction: %s | Sprite: %d | Location: %d %d", + "NPC %d: %s | Direction: %s | Sprite: %d | Location: %d %d"_fmt, ++i, nd->name, direction, nd->npc_class, nd->bl_x, nd->bl_y); clif_displaymessage(s, output); @@ -3566,7 +3576,7 @@ ATCE atcommand_mapinfo(Session *s, dumb_ptr<map_session_data> sd, default: // normally impossible to arrive here clif_displaymessage(s, - "Please, enter at least a valid list number (usage: @mapinfo <0-2> [map])."); + "Please, enter at least a valid list number (usage: @mapinfo <0-2> [map])."_s); return ATCE::USAGE; } @@ -3582,27 +3592,27 @@ ATCE atcommand_partyspy(Session *s, dumb_ptr<map_session_data> sd, if (!extract(message, &party_name)) return ATCE::USAGE; - struct party *p; - if ((p = party_searchname(party_name)) != NULL || + PartyPair p; + if ((p = party_searchname(party_name)) || // name first to avoid error when name begin with a number - (p = party_search(atoi(message.c_str()))) != NULL) + (p = party_search(wrap<PartyId>(static_cast<uint32_t>(atoi(message.c_str())))))) { - if (sd->partyspy == p->party_id) + if (sd->partyspy == p.party_id) { - sd->partyspy = 0; - AString output = STRPRINTF("No longer spying on the %s party.", p->name); + sd->partyspy = PartyId(); + AString output = STRPRINTF("No longer spying on the %s party."_fmt, p->name); clif_displaymessage(s, output); } else { - sd->partyspy = p->party_id; - AString output = STRPRINTF("Spying on the %s party.", p->name); + sd->partyspy = p.party_id; + AString output = STRPRINTF("Spying on the %s party."_fmt, p->name); clif_displaymessage(s, output); } } else { - clif_displaymessage(s, "Incorrect name or ID, or no one from the party is online."); + clif_displaymessage(s, "Incorrect name or ID, or no one from the party is online."_s); return ATCE::EXIST; } @@ -3618,14 +3628,14 @@ ATCE atcommand_enablenpc(Session *s, dumb_ptr<map_session_data>, if (!extract(message, &NPCname) || !NPCname) return ATCE::USAGE; - if (npc_name2id(NPCname) != NULL) + if (npc_name2id(NPCname) != nullptr) { npc_enable(NPCname, 1); - clif_displaymessage(s, "Npc Enabled."); + clif_displaymessage(s, "Npc Enabled."_s); } else { - clif_displaymessage(s, "This NPC doesn't exist."); + clif_displaymessage(s, "This NPC doesn't exist."_s); return ATCE::EXIST; } @@ -3641,14 +3651,14 @@ ATCE atcommand_disablenpc(Session *s, dumb_ptr<map_session_data>, if (!extract(message, &NPCname) || !NPCname) return ATCE::USAGE; - if (npc_name2id(NPCname) != NULL) + if (npc_name2id(NPCname) != nullptr) { npc_enable(NPCname, 0); - clif_displaymessage(s, "Npc Disabled."); + clif_displaymessage(s, "Npc Disabled."_s); } else { - clif_displaymessage(s, "This NPC doesn't exist."); + clif_displaymessage(s, "This NPC doesn't exist."_s); return ATCE::EXIST; } @@ -3661,7 +3671,7 @@ ATCE atcommand_servertime(Session *s, dumb_ptr<map_session_data>, { timestamp_seconds_buffer tsbuf; stamp_time(tsbuf); - AString temp = STRPRINTF("Server time: %s", tsbuf); + AString temp = STRPRINTF("Server time: %s"_fmt, tsbuf); clif_displaymessage(s, temp); return ATCE::OKAY; @@ -3673,33 +3683,32 @@ ATCE atcommand_chardelitem(Session *s, dumb_ptr<map_session_data> sd, { CharName character; XString item_name; - int i, number = 0, item_id, item_position, count; + int i, number = 0; + ItemNameId item_id; + int count; struct item_data *item_data; if (!asplit(message, &item_name, &number, &character) || number < 1) return ATCE::USAGE; - item_id = 0; - if ((item_data = itemdb_searchname(item_name)) != NULL) + if ((item_data = itemdb_searchname(item_name)) != nullptr) item_id = item_data->nameid; - else if (extract(item_name, &item_id) && (item_data = itemdb_exists(item_id)) != NULL) + else if (extract(item_name, &item_id) && (item_data = itemdb_exists(item_id)) != nullptr) item_id = item_data->nameid; - else - item_id = 0; - if (item_id > 500) + if (item_id) { dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can kill only lower or same level - item_position = pc_search_inventory(pl_sd, item_id); - if (item_position >= 0) + IOff0 item_position = pc_search_inventory(pl_sd, item_id); + if (item_position.ok()) { count = 0; - for (i = 0; i < number && item_position >= 0; i++) + for (i = 0; i < number && item_position.ok(); i++) { pc_delitem(pl_sd, item_position, 1, 0); count++; @@ -3707,37 +3716,37 @@ ATCE atcommand_chardelitem(Session *s, dumb_ptr<map_session_data> sd, // for next loop } AString output = STRPRINTF( - "%d item(s) removed by a GM.", + "%d item(s) removed by a GM."_fmt, count); clif_displaymessage(pl_sd->sess, output); if (number == count) - output = STRPRINTF("%d item(s) removed from the player.", count); + output = STRPRINTF("%d item(s) removed from the player."_fmt, count); else - output = STRPRINTF("%d item(s) removed. Player had only %d on %d items.", count, count, number); + output = STRPRINTF("%d item(s) removed. Player had only %d on %d items."_fmt, count, count, number); clif_displaymessage(s, output); } else { - clif_displaymessage(s, "Character does not have the item."); + clif_displaymessage(s, "Character does not have the item."_s); return ATCE::EXIST; } } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } } else { - clif_displaymessage(s, "Invalid item ID or name."); + clif_displaymessage(s, "Invalid item ID or name."_s); return ATCE::RANGE; } @@ -3751,7 +3760,7 @@ ATCE atcommand_broadcast(Session *, dumb_ptr<map_session_data> sd, if (!message) return ATCE::USAGE; - AString output = STRPRINTF("%s : %s", sd->status_key.name, message); + AString output = STRPRINTF("%s : %s"_fmt, sd->status_key.name, message); intif_GMmessage(output); return ATCE::OKAY; @@ -3764,7 +3773,7 @@ ATCE atcommand_localbroadcast(Session *, dumb_ptr<map_session_data> sd, if (!message) return ATCE::USAGE; - AString output = STRPRINTF("%s : %s", sd->status_key.name, message); + AString output = STRPRINTF("%s : %s"_fmt, sd->status_key.name, message); clif_GMmessage(sd, output, 1); @@ -3783,28 +3792,28 @@ ATCE atcommand_email(Session *s, dumb_ptr<map_session_data> sd, if (!e_mail_check(actual_email)) { - clif_displaymessage(s, "Invalid actual email. If you have default e-mail, type a@a.com."); + clif_displaymessage(s, "Invalid actual email. If you have default e-mail, type a@a.com."_s); return ATCE::RANGE; } else if (!e_mail_check(new_email)) { - clif_displaymessage(s, "Invalid new email. Please enter a real e-mail."); + clif_displaymessage(s, "Invalid new email. Please enter a real e-mail."_s); return ATCE::RANGE; } else if (new_email == DEFAULT_EMAIL) { - clif_displaymessage(s, "New email must be a real e-mail."); + clif_displaymessage(s, "New email must be a real e-mail."_s); return ATCE::RANGE; } else if (actual_email == new_email) { - clif_displaymessage(s, "New email must be different of the actual e-mail."); + clif_displaymessage(s, "New email must be different of the actual e-mail."_s); return ATCE::RANGE; } else { chrif_changeemail(sd->status_key.account_id, actual_email, new_email); - clif_displaymessage(s, "Information sended to login-server via char-server."); + clif_displaymessage(s, "Information sended to login-server via char-server."_s); } return ATCE::OKAY; @@ -3821,7 +3830,7 @@ ATCE atcommand_effect(Session *s, dumb_ptr<map_session_data> sd, if (flag <= 0) { clif_specialeffect(sd, type, flag); - clif_displaymessage(s, "Your Effect Has Changed."); + clif_displaymessage(s, "Your Effect Has Changed."_s); } else { @@ -3834,7 +3843,7 @@ ATCE atcommand_effect(Session *s, dumb_ptr<map_session_data> sd, if (pl_sd && pl_sd->state.auth) { clif_specialeffect(pl_sd, type, flag); - clif_displaymessage(pl_sd->sess, "Your Effect Has Changed."); + clif_displaymessage(pl_sd->sess, "Your Effect Has Changed."_s); } } } @@ -3846,34 +3855,34 @@ static ATCE atcommand_character_item_list(Session *s, dumb_ptr<map_session_data> sd, ZString message) { - struct item_data *item_data = NULL; - int i, count, counter; + struct item_data *item_data = nullptr; + int count, counter; CharName character; if (!asplit(message, &character)) return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can look items only lower or same level counter = 0; count = 0; - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { - if (pl_sd->status.inventory[i].nameid > 0 + if (pl_sd->status.inventory[i].nameid && (item_data = itemdb_search(pl_sd->status.inventory[i].nameid)) != - NULL) + nullptr) { counter = counter + pl_sd->status.inventory[i].amount; count++; if (count == 1) { AString output = STRPRINTF( - "------ Items list of '%s' ------", + "------ Items list of '%s' ------"_fmt, pl_sd->status_key.name); clif_displaymessage(s, output); } @@ -3881,35 +3890,35 @@ ATCE atcommand_character_item_list(Session *s, dumb_ptr<map_session_data> sd, MString equipstr; if (bool(equip)) { - equipstr += "| equiped: "; + equipstr += "| equiped: "_s; if (bool(equip & EPOS::GLOVES)) - equipstr += "robe/gargment, "; + equipstr += "robe/gargment, "_s; if (bool(equip & EPOS::CAPE)) - equipstr += "left accessory, "; + equipstr += "left accessory, "_s; if (bool(equip & EPOS::MISC1)) - equipstr += "body/armor, "; + equipstr += "body/armor, "_s; if ((equip & (EPOS::WEAPON | EPOS::SHIELD)) == EPOS::WEAPON) - equipstr += "right hand, "; + equipstr += "right hand, "_s; if ((equip & (EPOS::WEAPON | EPOS::SHIELD)) == EPOS::SHIELD) - equipstr += "left hand, "; + equipstr += "left hand, "_s; if ((equip & (EPOS::WEAPON | EPOS::SHIELD)) == (EPOS::WEAPON | EPOS::SHIELD)) - equipstr += "both hands, "; + equipstr += "both hands, "_s; if (bool(equip & EPOS::SHOES)) - equipstr += "feet, "; + equipstr += "feet, "_s; if (bool(equip & EPOS::MISC2)) - equipstr += "right accessory, "; + equipstr += "right accessory, "_s; if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == EPOS::LEGS) - equipstr += "lower head, "; + equipstr += "lower head, "_s; if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == EPOS::HAT) - equipstr += "top head, "; + equipstr += "top head, "_s; if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == (EPOS::HAT | EPOS::LEGS)) - equipstr += "lower/top head, "; + equipstr += "lower/top head, "_s; if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == EPOS::TORSO) - equipstr += "mid head, "; + equipstr += "mid head, "_s; if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == (EPOS::TORSO | EPOS::LEGS)) - equipstr += "lower/mid head, "; + equipstr += "lower/mid head, "_s; if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) - equipstr += "lower/mid/top head, "; + equipstr += "lower/mid/top head, "_s; // remove final ', ' equipstr.pop_back(2); } @@ -3918,35 +3927,35 @@ ATCE atcommand_character_item_list(Session *s, dumb_ptr<map_session_data> sd, AString output; if (true) - output = STRPRINTF("%d %s (%s, id: %d) %s", - pl_sd->status.inventory[i].amount, - item_data->name, item_data->jname, - pl_sd->status.inventory[i].nameid, - AString(equipstr)); + output = STRPRINTF("%d %s (%s, id: %d) %s"_fmt, + pl_sd->status.inventory[i].amount, + item_data->name, item_data->jname, + pl_sd->status.inventory[i].nameid, + AString(equipstr)); clif_displaymessage(s, output); // snip cards } } if (count == 0) - clif_displaymessage(s, "No item found on this player."); + clif_displaymessage(s, "No item found on this player."_s); else { AString output = STRPRINTF( - "%d item(s) found in %d kind(s) of items.", + "%d item(s) found in %d kind(s) of items."_fmt, counter, count); clif_displaymessage(s, output); } } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -3957,74 +3966,74 @@ static ATCE atcommand_character_storage_list(Session *s, dumb_ptr<map_session_data> sd, ZString message) { - struct storage *stor; - struct item_data *item_data = NULL; - int i, count, counter; + Storage *stor; + struct item_data *item_data = nullptr; + int count, counter; CharName character; if (!asplit(message, &character)) return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { - if (pc_isGM(sd) >= pc_isGM(pl_sd)) + if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can look items only lower or same level - if ((stor = account2storage2(pl_sd->status_key.account_id)) != NULL) + if ((stor = account2storage2(pl_sd->status_key.account_id)) != nullptr) { counter = 0; count = 0; - for (i = 0; i < MAX_STORAGE; i++) + for (SOff0 i : SOff0::iter()) { - if (stor->storage_[i].nameid > 0 + if (stor->storage_[i].nameid && (item_data = - itemdb_search(stor->storage_[i].nameid)) != NULL) + itemdb_search(stor->storage_[i].nameid)) != nullptr) { counter = counter + stor->storage_[i].amount; count++; if (count == 1) { AString output = STRPRINTF( - "------ Storage items list of '%s' ------", + "------ Storage items list of '%s' ------"_fmt, pl_sd->status_key.name); clif_displaymessage(s, output); } AString output; if (true) - output = STRPRINTF("%d %s (%s, id: %d)", - stor->storage_[i].amount, - item_data->name, item_data->jname, - stor->storage_[i].nameid); + output = STRPRINTF("%d %s (%s, id: %d)"_fmt, + stor->storage_[i].amount, + item_data->name, item_data->jname, + stor->storage_[i].nameid); clif_displaymessage(s, output); } } if (count == 0) clif_displaymessage(s, - "No item found in the storage of this player."); + "No item found in the storage of this player."_s); else { AString output = STRPRINTF( - "%d item(s) found in %d kind(s) of items.", + "%d item(s) found in %d kind(s) of items."_fmt, counter, count); clif_displaymessage(s, output); } } else { - clif_displaymessage(s, "This player has no storage."); + clif_displaymessage(s, "This player has no storage."_s); return ATCE::OKAY; } } else { - clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."); + clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s); return ATCE::PERM; } } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -4038,9 +4047,9 @@ ATCE atcommand_killer(Session *s, dumb_ptr<map_session_data> sd, sd->special_state.killer = !sd->special_state.killer; if (sd->special_state.killer) - clif_displaymessage(s, "You be a killa..."); + clif_displaymessage(s, "You be a killa..."_s); else - clif_displaymessage(s, "You gonna be own3d..."); + clif_displaymessage(s, "You gonna be own3d..."_s); return ATCE::OKAY; } @@ -4055,20 +4064,20 @@ ATCE atcommand_charkiller(Session *s, dumb_ptr<map_session_data>, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd == NULL) + if (pl_sd == nullptr) return ATCE::EXIST; pl_sd->special_state.killer = !pl_sd->special_state.killer; if (pl_sd->special_state.killer) { - clif_displaymessage(s, "The player is now a killer"); - clif_displaymessage(pl_sd->sess, "You are now a killer"); + clif_displaymessage(s, "The player is now a killer"_s); + clif_displaymessage(pl_sd->sess, "You are now a killer"_s); } else { - clif_displaymessage(s, "The player is no longer a killer"); - clif_displaymessage(pl_sd->sess, "You are no longer a killer"); + clif_displaymessage(s, "The player is no longer a killer"_s); + clif_displaymessage(pl_sd->sess, "You are no longer a killer"_s); } return ATCE::OKAY; @@ -4081,9 +4090,9 @@ ATCE atcommand_killable(Session *s, dumb_ptr<map_session_data> sd, sd->special_state.killable = !sd->special_state.killable; if (sd->special_state.killable) - clif_displaymessage(s, "You gonna be own3d..."); + clif_displaymessage(s, "You gonna be own3d..."_s); else - clif_displaymessage(s, "You be a killa..."); + clif_displaymessage(s, "You be a killa..."_s); return ATCE::OKAY; } @@ -4098,15 +4107,15 @@ ATCE atcommand_charkillable(Session *s, dumb_ptr<map_session_data>, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd == NULL) + if (pl_sd == nullptr) return ATCE::EXIST; pl_sd->special_state.killable = !pl_sd->special_state.killable; if (pl_sd->special_state.killable) - clif_displaymessage(s, "The player is now killable"); + clif_displaymessage(s, "The player is now killable"_s); else - clif_displaymessage(s, "The player is no longer killable"); + clif_displaymessage(s, "The player is no longer killable"_s); return ATCE::OKAY; } @@ -4117,13 +4126,13 @@ ATCE atcommand_npcmove(Session *, dumb_ptr<map_session_data>, { NpcName character; int x = 0, y = 0; - dumb_ptr<npc_data> nd = 0; + dumb_ptr<npc_data> nd = nullptr; if (!asplit(message, &x, &y, &character)) return ATCE::USAGE; nd = npc_name2id(character); - if (nd == NULL) + if (nd == nullptr) return ATCE::EXIST; npc_enable(character, 0); @@ -4146,17 +4155,17 @@ ATCE atcommand_addwarp(Session *s, dumb_ptr<map_session_data> sd, if (!extract(message, record<' '>(&mapname, &x, &y))) return ATCE::USAGE; - AString w1 = STRPRINTF("%s,%d,%d", sd->mapname_, sd->bl_x, sd->bl_y); - AString w3 = STRPRINTF("%s%d%d%d%d", mapname, sd->bl_x, sd->bl_y, x, y); - AString w4 = STRPRINTF("1,1,%s.gat,%d,%d", mapname, x, y); + AString w1 = STRPRINTF("%s,%d,%d"_fmt, sd->mapname_, sd->bl_x, sd->bl_y); + AString w3 = STRPRINTF("%s%d%d%d%d"_fmt, mapname, sd->bl_x, sd->bl_y, x, y); + AString w4 = STRPRINTF("1,1,%s.gat,%d,%d"_fmt, mapname, x, y); NpcName w3name = stringish<NpcName>(w3); - int ret = npc_parse_warp(w1, ZString("warp"), w3name, w4); + int ret = npc_parse_warp(w1, "warp"_s, w3name, w4); if (ret) // warp failed return ATCE::RANGE; - AString output = STRPRINTF("New warp NPC => %s", w3); + AString output = STRPRINTF("New warp NPC => %s"_fmt, w3); clif_displaymessage(s, output); return ATCE::OKAY; @@ -4173,11 +4182,11 @@ ATCE atcommand_chareffect(Session *s, dumb_ptr<map_session_data>, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(target); - if (pl_sd == NULL) + if (pl_sd == nullptr) return ATCE::EXIST; clif_specialeffect(pl_sd, type, 0); - clif_displaymessage(s, "Your Effect Has Changed."); + clif_displaymessage(s, "Your Effect Has Changed."_s); return ATCE::OKAY; } @@ -4186,8 +4195,7 @@ static ATCE atcommand_dropall(Session *, dumb_ptr<map_session_data> sd, ZString) { - int i; - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { if (sd->status.inventory[i].amount) { @@ -4208,9 +4216,9 @@ ATCE atcommand_chardropall(Session *s, dumb_ptr<map_session_data>, if (!asplit(message, &character)) return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd == NULL) + if (pl_sd == nullptr) return ATCE::EXIST; - for (int i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { if (pl_sd->status.inventory[i].amount) { @@ -4220,9 +4228,8 @@ ATCE atcommand_chardropall(Session *s, dumb_ptr<map_session_data>, } } - clif_displaymessage(pl_sd->sess, "Ever play 52 card pickup?"); - clif_displaymessage(s, "It is done"); - //clif_displaymessage(s, "It is offical.. your a jerk"); + clif_displaymessage(pl_sd->sess, "Ever play 52 card pickup?"_s); + clif_displaymessage(s, "It is official.. you're a jerk."_s); return ATCE::OKAY; } @@ -4231,8 +4238,6 @@ static ATCE atcommand_storeall(Session *s, dumb_ptr<map_session_data> sd, ZString) { - int i; - if (!sd->state.storage_open) { //Open storage. @@ -4240,16 +4245,16 @@ ATCE atcommand_storeall(Session *s, dumb_ptr<map_session_data> sd, { case 2: //Try again - clif_displaymessage(s, "run this command again.."); + clif_displaymessage(s, "run this command again.."_s); return ATCE::OKAY; case 1: //Failure clif_displaymessage(s, - "You can't open the storage currently."); + "You can't open the storage currently."_s); return ATCE::EXIST; } } - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { if (sd->status.inventory[i].amount) { @@ -4260,7 +4265,7 @@ ATCE atcommand_storeall(Session *s, dumb_ptr<map_session_data> sd, } storage_storageclose(sd); - clif_displaymessage(s, "It is done"); + clif_displaymessage(s, "It is done"_s); return ATCE::OKAY; } @@ -4273,7 +4278,7 @@ ATCE atcommand_charstoreall(Session *s, dumb_ptr<map_session_data> sd, if (!asplit(message, &character)) return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd == NULL) + if (pl_sd == nullptr) return ATCE::EXIST; if (storage_storageopen(pl_sd) == 1) @@ -4281,11 +4286,11 @@ ATCE atcommand_charstoreall(Session *s, dumb_ptr<map_session_data> sd, // TODO figure out what the hell this is talking about, // and especially why it's different from the other one. clif_displaymessage(s, - "Had to open the characters storage window..."); - clif_displaymessage(s, "run this command again.."); + "Had to open the characters storage window..."_s); + clif_displaymessage(s, "run this command again.."_s); return ATCE::OKAY; } - for (int i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { if (pl_sd->status.inventory[i].amount) { @@ -4297,12 +4302,12 @@ ATCE atcommand_charstoreall(Session *s, dumb_ptr<map_session_data> sd, storage_storageclose(pl_sd); clif_displaymessage(pl_sd->sess, - "Everything you own has been put away for safe keeping."); + "Everything you own has been put away for safe keeping."_s); clif_displaymessage(pl_sd->sess, - "go to the nearest kafka to retrieve it.."); - clif_displaymessage(pl_sd->sess, " -- the management"); + "go to the nearest kafka to retrieve it.."_s); + clif_displaymessage(pl_sd->sess, " -- the management"_s); - clif_displaymessage(s, "It is done"); + clif_displaymessage(s, "It is done"_s); return ATCE::OKAY; } @@ -4383,31 +4388,30 @@ ATCE atcommand_summon(Session *, dumb_ptr<map_session_data> sd, ZString message) { MobName name; - int mob_id = 0; + Species mob_id; int x = 0; int y = 0; - int id = 0; tick_t tick = gettick(); if (!extract(message, &name) || !name) return ATCE::USAGE; - if ((mob_id = atoi(name.c_str())) == 0) + if ((mob_id = wrap<Species>(static_cast<uint16_t>(atoi(name.c_str())))) == Species()) mob_id = mobdb_searchname(name); - if (mob_id == 0) + if (mob_id == Species()) return ATCE::EXIST; x = sd->bl_x + random_::in(-5, 4); y = sd->bl_y + random_::in(-5, 4); - id = mob_once_spawn(sd, MOB_THIS_MAP, x, y, JAPANESE_NAME, mob_id, 1, NpcEvent()); + BlockId id = mob_once_spawn(sd, MOB_THIS_MAP, x, y, JAPANESE_NAME, mob_id, 1, NpcEvent()); dumb_ptr<mob_data> md = map_id_is_mob(id); if (md) { md->master_id = sd->bl_id; md->state.special_mob_ai = 1; - md->mode = mob_db[md->mob_class].mode | MobMode::AGGRESSIVE; - md->deletetimer = Timer(tick + std::chrono::minutes(1), + md->mode = get_mob_db(md->mob_class).mode | MobMode::AGGRESSIVE; + md->deletetimer = Timer(tick + 1_min, std::bind(mob_timer_delete, ph::_1, ph::_2, id)); clif_misceffect(md, 344); @@ -4420,12 +4424,12 @@ static ATCE atcommand_adjcmdlvl(Session *s, dumb_ptr<map_session_data>, ZString message) { - int newlev; + GmLevel newlev; XString cmd; if (!extract(message, record<' '>(&newlev, &cmd))) { - clif_displaymessage(s, "usage: @adjcmdlvl <lvl> <command>."); + clif_displaymessage(s, "usage: @adjcmdlvl <lvl> <command>."_s); return ATCE::USAGE; } @@ -4434,12 +4438,12 @@ ATCE atcommand_adjcmdlvl(Session *s, dumb_ptr<map_session_data>, if (it) { it->level = newlev; - clif_displaymessage(s, "@command level changed."); + clif_displaymessage(s, "@command level changed."_s); return ATCE::OKAY; } } - clif_displaymessage(s, "@command not found."); + clif_displaymessage(s, "@command not found."_s); return ATCE::EXIST; } @@ -4447,18 +4451,17 @@ static ATCE atcommand_adjgmlvl(Session *s, dumb_ptr<map_session_data>, ZString message) { - int newlev; + GmLevel newlev; CharName user; - if (!asplit(message, &newlev, &user) - || newlev < 0 || newlev > 99) + if (!asplit(message, &newlev, &user)) { - clif_displaymessage(s, "usage: @adjgmlvl <lvl> <user>."); + clif_displaymessage(s, "usage: @adjgmlvl <lvl> <user>."_s); return ATCE::USAGE; } dumb_ptr<map_session_data> pl_sd = map_nick2sd(user); - if (pl_sd == NULL) + if (pl_sd == nullptr) return ATCE::EXIST; pc_set_gm_level(pl_sd->status_key.account_id, newlev); @@ -4501,14 +4504,14 @@ constexpr size_t magic_skills_nr = sizeof(magic_skills) / sizeof(magic_skills[0]); static -ZString magic_skill_names[magic_skills_nr] = +LString magic_skill_names[magic_skills_nr] = { - {"magic"}, - {"life"}, - {"war"}, - {"transmute"}, - {"nature"}, - {"astral"}, + "magic"_s, + "life"_s, + "war"_s, + "transmute"_s, + "nature"_s, + "astral"_s, }; static @@ -4524,7 +4527,7 @@ ATCE atcommand_magic_info(Session *s, dumb_ptr<map_session_data>, if (pl_sd) { AString buf = STRPRINTF( - "`%s' has the following magic skills:", + "`%s' has the following magic skills:"_fmt, character); clif_displaymessage(s, buf); @@ -4532,7 +4535,7 @@ ATCE atcommand_magic_info(Session *s, dumb_ptr<map_session_data>, { SkillID sk = magic_skills[i]; buf = STRPRINTF( - "%d in %s", + "%d in %s"_fmt, pl_sd->status.skill[sk].lv, magic_skill_names[i]); if (pl_sd->status.skill[sk].lv) @@ -4542,7 +4545,7 @@ ATCE atcommand_magic_info(Session *s, dumb_ptr<map_session_data>, return ATCE::OKAY; } - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -4563,12 +4566,12 @@ ATCE atcommand_set_magic(Session *s, dumb_ptr<map_session_data>, if (!asplit(message, &magic_type, &value, &character)) { clif_displaymessage(s, - "Usage: @setmagic <school> <value> <char-name>, where <school> is either `magic', one of the school names, or `all'."); + "Usage: @setmagic <school> <value> <char-name>, where <school> is either `magic', one of the school names, or `all'."_s); return ATCE::USAGE; } SkillID skill_index = SkillID::NEGATIVE; - if ("all" == magic_type) + if ("all"_s == magic_type) skill_index = SkillID::ZERO; else { @@ -4585,12 +4588,12 @@ ATCE atcommand_set_magic(Session *s, dumb_ptr<map_session_data>, if (skill_index == SkillID::NEGATIVE) { clif_displaymessage(s, - "Incorrect school of magic. Use `magic', `nature', `life', `war', `transmute', `ether', or `all'."); + "Incorrect school of magic. Use `magic', `nature', `life', `war', `transmute', `ether', or `all'."_s); return ATCE::RANGE; } dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { if (skill_index == SkillID::ZERO) for (SkillID sk : magic_skills) @@ -4602,7 +4605,7 @@ ATCE atcommand_set_magic(Session *s, dumb_ptr<map_session_data>, return ATCE::OKAY; } - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -4661,21 +4664,21 @@ ATCE atcommand_jump_iterate(Session *s, dumb_ptr<map_session_data> sd, } if (pl_sd->bl_m && pl_sd->bl_m->flag.get(MapFlag::NOWARPTO) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp you to the map of this player."); + "You are not authorised to warp you to the map of this player."_s); return ATCE::PERM; } if (sd->bl_m && sd->bl_m->flag.get(MapFlag::NOWARP) - && battle_config.any_warp_GM_min_level > pc_isGM(sd)) + && !(pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.any_warp_GM_min_level))))) { clif_displaymessage(s, - "You are not authorised to warp you from your actual map."); + "You are not authorised to warp you from your actual map."_s); return ATCE::PERM; } pc_setpos(sd, pl_sd->bl_m->name_, pl_sd->bl_x, pl_sd->bl_y, BeingRemoveWhy::WARPED); - AString output = STRPRINTF("Jump to %s", pl_sd->status_key.name); + AString output = STRPRINTF("Jump to %s"_fmt, pl_sd->status_key.name); clif_displaymessage(s, output); sd->followtarget = pl_sd->bl_id; @@ -4702,9 +4705,9 @@ ATCE atcommand_wgm(Session *s, dumb_ptr<map_session_data> sd, if (tmw_CheckChatSpam(sd, message)) return ATCE::OKAY; - tmw_GmHackMsg(STRPRINTF("[GM] %s: %s", sd->status_key.name, message)); + tmw_GmHackMsg(STRPRINTF("[GM] %s: %s"_fmt, sd->status_key.name, message)); if (!pc_isGM(sd)) - clif_displaymessage(s, "Message sent."); + clif_displaymessage(s, "Message sent."_s); return ATCE::OKAY; } @@ -4720,26 +4723,26 @@ ATCE atcommand_skillpool_info(Session *s, dumb_ptr<map_session_data>, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { SkillID pool_skills[MAX_SKILL_POOL]; int pool_skills_nr = skill_pool(pl_sd, pool_skills); int i; AString buf = STRPRINTF( - "Active skills %d out of %d for %s:", + "Active skills %d out of %d for %s:"_fmt, pool_skills_nr, skill_pool_max(pl_sd), character); clif_displaymessage(s, buf); for (i = 0; i < pool_skills_nr; ++i) { - buf = STRPRINTF(" - %s [%d]: power %d", + buf = STRPRINTF(" - %s [%d]: power %d"_fmt, skill_name(pool_skills[i]), pool_skills[i], skill_power(pl_sd, pool_skills[i])); clif_displaymessage(s, buf); } - buf = STRPRINTF("Learned skills out of %d for %s:", + buf = STRPRINTF("Learned skills out of %d for %s:"_fmt, skill_pool_skills_size, character); clif_displaymessage(s, buf); @@ -4750,7 +4753,7 @@ ATCE atcommand_skillpool_info(Session *s, dumb_ptr<map_session_data>, if (lvl) { - buf = STRPRINTF(" - %s [%d]: lvl %d", + buf = STRPRINTF(" - %s [%d]: lvl %d"_fmt, name, skill_pool_skills[i], lvl); clif_displaymessage(s, buf); } @@ -4759,7 +4762,7 @@ ATCE atcommand_skillpool_info(Session *s, dumb_ptr<map_session_data>, } else { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -4775,20 +4778,20 @@ ATCE atcommand_skillpool_focus(Session *s, dumb_ptr<map_session_data>, if (!asplit(message, &skill, &character)) { - clif_displaymessage(s, "Usage: @sp-focus <skill-nr> <char_name>"); + clif_displaymessage(s, "Usage: @sp-focus <skill-nr> <char_name>"_s); return ATCE::USAGE; } dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { if (skill_pool_activate(pl_sd, skill)) - clif_displaymessage(s, "Activation failed."); + clif_displaymessage(s, "Activation failed."_s); else - clif_displaymessage(s, "Activation successful."); + clif_displaymessage(s, "Activation successful."_s); } else - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::OKAY; } @@ -4804,15 +4807,15 @@ ATCE atcommand_skillpool_unfocus(Session *s, dumb_ptr<map_session_data>, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { if (skill_pool_deactivate(pl_sd, skill)) - clif_displaymessage(s, "Deactivation failed."); + clif_displaymessage(s, "Deactivation failed."_s); else - clif_displaymessage(s, "Deactivation successful."); + clif_displaymessage(s, "Deactivation successful."_s); } else - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::OKAY; } @@ -4829,13 +4832,13 @@ ATCE atcommand_skill_learn(Session *s, dumb_ptr<map_session_data>, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd != NULL) + if (pl_sd != nullptr) { set_skill(pl_sd, skill, level); clif_skillinfoblock(pl_sd); } else - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::OKAY; } @@ -4850,9 +4853,9 @@ ATCE atcommand_ipcheck(Session *s, dumb_ptr<map_session_data>, return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd == NULL) + if (pl_sd == nullptr) { - clif_displaymessage(s, "Character not found."); + clif_displaymessage(s, "Character not found."_s); return ATCE::EXIST; } @@ -4873,7 +4876,7 @@ ATCE atcommand_ipcheck(Session *s, dumb_ptr<map_session_data>, if (ip == pl_sd->get_ip()) { AString output = STRPRINTF( - "Name: %s | Location: %s %d %d", + "Name: %s | Location: %s %d %d"_fmt, pl_sd->status_key.name, pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y); clif_displaymessage(s, output); @@ -4881,7 +4884,7 @@ ATCE atcommand_ipcheck(Session *s, dumb_ptr<map_session_data>, } } - clif_displaymessage(s, "End of list"); + clif_displaymessage(s, "End of list"_s); return ATCE::OKAY; } @@ -4898,14 +4901,14 @@ ATCE atcommand_doomspot(Session *s, dumb_ptr<map_session_data> sd, if (pl_sd && pl_sd->state.auth && s2 != s && sd->bl_m == pl_sd->bl_m && sd->bl_x == pl_sd->bl_x && sd->bl_y == pl_sd->bl_y - && pc_isGM(sd) >= pc_isGM(pl_sd)) + && pc_isGM(sd).overwhelms(pc_isGM(pl_sd))) { // you can doom only lower or same gm level - pc_damage(NULL, pl_sd, pl_sd->status.hp + 1); - clif_displaymessage(pl_sd->sess, "The holy messenger has given judgement."); + pc_damage(nullptr, pl_sd, pl_sd->status.hp + 1); + clif_displaymessage(pl_sd->sess, "The holy messenger has given judgement."_s); } } - clif_displaymessage(s, "Judgement was made."); + clif_displaymessage(s, "Judgement was made."_s); return ATCE::OKAY; } @@ -4915,13 +4918,13 @@ ATCE atcommand_source(Session *s, dumb_ptr<map_session_data>, ZString) { clif_displaymessage(s, - "This server code consists of Free Software under GPL3&AGPL3"); + "This server code consists of Free Software under GPL3&AGPL3"_s); clif_displaymessage(s, - "This is commit " VERSION_HASH ", also known as " VERSION_FULL); + "This is commit " VERSION_HASH ", also known as " VERSION_FULL ""_s); clif_displaymessage(s, - "The version is " VERSION_STRING); + "The version is " VERSION_STRING ""_s); clif_displaymessage(s, - "For source, see " VENDOR_SOURCE); + "For source, see " VENDOR_SOURCE ""_s); return ATCE::OKAY; } @@ -4931,424 +4934,425 @@ ATCE atcommand_source(Session *s, dumb_ptr<map_session_data>, // declared extern above Map<XString, AtCommandInfo> atcommand_info = { - {"help", {"[level[-level]|category|@command]", + {"help"_s, {"[level[-level]|category|@command]"_s, 0, atcommand_help, - "Show help"}}, - {"setup", {"<level> <charname>", + "Show help"_s}}, + {"setup"_s, {"<level> <charname>"_s, 40, atcommand_setup, - "Safely set a chars levels and warp them to a special place (for TAW)"}}, - {"charwarp", {"<mapname> <x> <y> <charname>", + "Safely set a chars levels and warp them to a special place (for TAW)"_s}}, + {"charwarp"_s, {"<mapname> <x> <y> <charname>"_s, 60, atcommand_charwarp, - "Warp a character to a point on another map"}}, - {"warp", {"<mapname> [x] [y]", + "Warp a character to a point on another map"_s}}, + {"warp"_s, {"<mapname> [x] [y]"_s, 40, atcommand_warp, - "Warp yourself to another map"}}, - {"where", {"[charname]", + "Warp yourself to another map"_s}}, + {"where"_s, {"[charname]"_s, 40, atcommand_where, - "Show location of a character or yourself"}}, - {"goto", {"<charname>", + "Show location of a character or yourself"_s}}, + {"goto"_s, {"<charname>"_s, 40, atcommand_goto, - "Warp yourself to another character"}}, - {"jump", {"[x] [y]", + "Warp yourself to another character"_s}}, + {"jump"_s, {"[x] [y]"_s, 40, atcommand_jump, - "Warp yourself within a map"}}, - {"who", {"[subsequence]", + "Warp yourself within a map"_s}}, + {"who"_s, {"[subsequence]"_s, 40, atcommand_who, - "List matching players online, with location info"}}, - {"whogroup", {"[subsequence]", + "List matching players online, with location info"_s}}, + {"whogroup"_s, {"[subsequence]"_s, 40, atcommand_whogroup, - "List matching players online, with party info"}}, - {"whomap", {"[mapname]", + "List matching players online, with party info"_s}}, + {"whomap"_s, {"[mapname]"_s, 40, atcommand_whomap, - "List all players on the map, with location info"}}, - {"whomapgroup", {"[mapname]", + "List all players on the map, with location info"_s}}, + {"whomapgroup"_s, {"[mapname]"_s, 40, atcommand_whomapgroup, - "List all players on the map, with party info"}}, - {"whogm", {"[subsequence]", + "List all players on the map, with party info"_s}}, + {"whogm"_s, {"[subsequence]"_s, 40, atcommand_whogm, - "List matching GM players, with location, level, and party info"}}, - {"save", {"", + "List matching GM players, with location, level, and party info"_s}}, + {"save"_s, {""_s, 40, atcommand_save, - "Set your respawn point to your current location"}}, - {"return", {"", + "Set your respawn point to your current location"_s}}, + {"return"_s, {""_s, 40, atcommand_load, - "Return to your respawn point"}}, - {"load", {"", + "Return to your respawn point"_s}}, + {"load"_s, {""_s, 40, atcommand_load, - "Return to your respawn point"}}, - {"speed", {"<rate>", + "Return to your respawn point"_s}}, + {"speed"_s, {"<rate>"_s, 60, atcommand_speed, - "Set walk rate"}}, - {"storage", {"", + "Set walk rate"_s}}, + {"storage"_s, {""_s, 99, atcommand_storage, - "Open your storage"}}, - {"option", {"<opt1> [opt2] [option]", + "Open your storage"_s}}, + {"option"_s, {"<opt1> [opt2] [option]"_s, 80, atcommand_option, - "Set your 'option' status flags"}}, - {"hide", {"", + "Set your 'option' status flags"_s}}, + {"hide"_s, {""_s, 40, atcommand_hide, - "Toggle invisibility from monsters and certain commands"}}, - {"die", {"", + "Toggle invisibility from monsters and certain commands"_s}}, + {"die"_s, {""_s, 40, atcommand_die, - "Cause fatal damage to yourself"}}, - {"kill", {"<charname>", + "Cause fatal damage to yourself"_s}}, + {"kill"_s, {"<charname>"_s, 60, atcommand_kill, - "Cause fatal damage to another player"}}, - {"alive", {"", + "Cause fatal damage to another player"_s}}, + {"alive"_s, {""_s, 60, atcommand_alive, - "Restore life to yourself"}}, - {"kami", {"<message ...>", + "Restore life to yourself"_s}}, + {"kami"_s, {"<message ...>"_s, 99, atcommand_kami, - "Send an anonymous broadcast"}}, - {"heal", {"[hp] [sp]", + "Send an anonymous broadcast"_s}}, + {"heal"_s, {"[hp] [sp]"_s, 40, atcommand_heal, - "Restore or destroy your health"}}, - {"item", {"<item-name-or-id> [count]", + "Restore or destroy your health"_s}}, + {"item"_s, {"<item-name-or-id> [count]"_s, 80, atcommand_item, - "Summon items out of the void"}}, - {"itemreset", {"", + "Summon items out of the void"_s}}, + {"itemreset"_s, {""_s, 40, atcommand_itemreset, - "Cast all of your itens into the void (why would you ever want this?)"}}, - {"itemcheck", {"", + "Cast all of your itens into the void (why would you ever want this?)"_s}}, + {"itemcheck"_s, {""_s, 80, atcommand_itemcheck, - "Perform an internal integrity check on your items"}}, - {"blvl", {"<delta>", + "Perform an internal integrity check on your items"_s}}, + {"blvl"_s, {"<delta>"_s, 60, atcommand_baselevelup, - "Adjust your level"}}, - {"jlvl", {"<delta>", + "Adjust your level"_s}}, + {"jlvl"_s, {"<delta>"_s, 60, atcommand_joblevelup, - "Adjust your job level"}}, - {"gm", {"<password>", + "Adjust your job level"_s}}, + {"gm"_s, {"<password>"_s, 100, atcommand_gm, - "Receive GM powers"}}, - {"pvpoff", {"", + "Receive GM powers"_s}}, + {"pvpoff"_s, {""_s, 60, atcommand_pvpoff, - "Enable PvP on your map"}}, - {"pvpon", {"", + "Enable PvP on your map"_s}}, + {"pvpon"_s, {""_s, 60, atcommand_pvpon, - "Disable PvP on your map"}}, - {"model", {"<style> [color] [dye]", + "Disable PvP on your map"_s}}, + {"model"_s, {"<style> [color] [dye]"_s, 99, atcommand_model, - "Change your hairstyle and hair color"}}, - {"spawn", {"<mob-name-or-id> [count] [x] [y]", + "Change your hairstyle and hair color"_s}}, + {"spawn"_s, {"<mob-name-or-id> [count] [x] [y]"_s, 50, atcommand_spawn, - "Spawn normal monsters at location."}}, - {"killmonster", {"[map]", + "Spawn normal monsters at location."_s}}, + {"killmonster"_s, {"[map]"_s, 60, atcommand_killmonster, - "Kill all monsters (with drops)"}}, - {"killmonster2", {"[map]", + "Kill all monsters (with drops)"_s}}, + {"killmonster2"_s, {"[map]"_s, 60, atcommand_killmonster2, - "Kill all monsters (no drops)"}}, - {"gat", {"", + "Kill all monsters (no drops)"_s}}, + {"gat"_s, {""_s, 99, atcommand_gat, - "Dump the local walkmap"}}, - {"packet", {"<type> <flag>", + "Dump the local walkmap"_s}}, + {"packet"_s, {"<type> <flag>"_s, 99, atcommand_packet, - "Force a status change"}}, - {"stpoint", {"<amount>", + "Force a status change"_s}}, + {"stpoint"_s, {"<amount>"_s, 60, atcommand_statuspoint, - "Increase your stat points"}}, - {"skpoint", {"<amount>", + "Increase your stat points"_s}}, + {"skpoint"_s, {"<amount>"_s, 60, atcommand_skillpoint, - "Increase your skill points"}}, - {"zeny", {"<amount>", + "Increase your skill points"_s}}, + {"zeny"_s, {"<amount>"_s, 80, atcommand_zeny, - "Change how much money you have"}}, - {"str", {"<delta>", + "Change how much money you have"_s}}, + {"str"_s, {"<delta>"_s, 60, atcommand_param<ATTR::STR>, - "Adjust your strength"}}, - {"agi", {"<delta>", + "Adjust your strength"_s}}, + {"agi"_s, {"<delta>"_s, 60, atcommand_param<ATTR::AGI>, - "Adjust your agility"}}, - {"vit", {"<delta>", + "Adjust your agility"_s}}, + {"vit"_s, {"<delta>"_s, 60, atcommand_param<ATTR::VIT>, - "Adjust your vitality"}}, - {"int", {"<delta>", + "Adjust your vitality"_s}}, + {"int"_s, {"<delta>"_s, 60, atcommand_param<ATTR::INT>, - "Adjust your intelligence\0(TODO make this work in real life, I'm lonely)"}}, - {"dex", {"<delta>", + "Adjust your intelligence\0(TODO make this work in real life, I'm lonely)"_s}}, + {"dex"_s, {"<delta>"_s, 60, atcommand_param<ATTR::DEX>, - "Adjust your dexterity"}}, - {"luk", {"<delta>", + "Adjust your dexterity"_s}}, + {"luk"_s, {"<delta>"_s, 60, atcommand_param<ATTR::LUK>, - "Adjust your luck"}}, - {"recall", {"<charname>", + "Adjust your luck"_s}}, + {"recall"_s, {"<charname>"_s, 60, atcommand_recall, - "Warp a player to you"}}, - {"revive", {"<charname>", + "Warp a player to you"_s}}, + {"revive"_s, {"<charname>"_s, 60, atcommand_revive, - "Restore a player to full health"}}, - {"charstats", {"<charname>", + "Restore a player to full health"_s}}, + {"charstats"_s, {"<charname>"_s, 40, atcommand_character_stats, - "Show a bunch of stats about a single user"}}, - {"charstatsall", {"", + "Show a bunch of stats about a single user"_s}}, + {"charstatsall"_s, {""_s, 60, atcommand_character_stats_all, - "Show a bunch of stats about all online users"}}, - {"charoption", {"<opt1> <opt2> <opt3> <charname>", + "Show a bunch of stats about all online users"_s}}, + {"charoption"_s, {"<opt1> <opt2> <opt3> <charname>"_s, 80, atcommand_character_option, - "Set option flags on another character"}}, - {"charsave", {"<map> <x> <y> <charname>", + "Set option flags on another character"_s}}, + {"charsave"_s, {"<map> <x> <y> <charname>"_s, 60, atcommand_character_save, - "Set another character's save point"}}, - {"doom", {"", + "Set another character's save point"_s}}, + {"doom"_s, {""_s, 80, atcommand_doom, - "Kill everyone on the server"}}, - {"doommap", {"", + "Kill everyone on the server"_s}}, + {"doommap"_s, {""_s, 80, atcommand_doommap, - "Kill everyone on your map"}}, - {"raise", {"", + "Kill everyone on your map"_s}}, + {"raise"_s, {""_s, 80, atcommand_raise, - "Resurrect all players on the server"}}, - {"raisemap", {"", + "Resurrect all players on the server"_s}}, + {"raisemap"_s, {""_s, 80, atcommand_raisemap, - "Resurrect all players on your map"}}, - {"charbaselvl", {"<delta> <charname>", + "Resurrect all players on your map"_s}}, + {"charbaselvl"_s, {"<delta> <charname>"_s, 60, atcommand_character_baselevel, - "Adjust another character's level"}}, - {"charjlvl", {"<delta> <charname>", + "Adjust another character's level"_s}}, + {"charjlvl"_s, {"<delta> <charname>"_s, 60, atcommand_character_joblevel, - "Adjust another character's job level"}}, - {"kick", {"<charname>", + "Adjust another character's job level"_s}}, + {"kick"_s, {"<charname>"_s, 40, atcommand_kick, - "Transiently kick a player off the server"}}, - {"kickall", {"", + "Transiently kick a player off the server"_s}}, + {"kickall"_s, {""_s, 99, atcommand_kickall, - "Transiently kick all players off the server"}}, - {"questskill", {"<skill-id>", + "Transiently kick all players off the server"_s}}, + {"questskill"_s, {"<skill-id>"_s, 99, atcommand_questskill, - "Give yourself a quest (?) skill"}}, - {"charquestskill", {"<skill-id> <charname>", + "Give yourself a quest (?) skill"_s}}, + {"charquestskill"_s, {"<skill-id> <charname>"_s, 99, atcommand_charquestskill, - "Give another player a quest (?) skill"}}, - {"lostskill", {"<skill-id>", + "Give another player a quest (?) skill"_s}}, + {"lostskill"_s, {"<skill-id>"_s, 80, atcommand_lostskill, - "Take away one of your quest (?) skills"}}, - {"charlostskill", {"<skill-id> <charname>", + "Take away one of your quest (?) skills"_s}}, + {"charlostskill"_s, {"<skill-id> <charname>"_s, 99, atcommand_charlostskill, - "Take away one of another player's quest (?) skills"}}, - {"party", {"<name>", + "Take away one of another player's quest (?) skills"_s}}, + {"party"_s, {"<name>"_s, 99, atcommand_party, - "Create a new party"}}, - {"mapexit", {"", + "Create a new party"_s}}, + {"mapexit"_s, {""_s, 99, atcommand_mapexit, - "Try to kill the server kindly"}}, - {"idsearch", {"<item-subseq>", + "Try to kill the server kindly"_s}}, + {"idsearch"_s, {"<item-subseq>"_s, 80, atcommand_idsearch, - "Search for some items that might match"}}, - {"mapmove", {"<mapname> [x] [y]", + "Search for some items that might match"_s}}, + {"mapmove"_s, {"<mapname> [x] [y]"_s, 40, atcommand_warp, - "Warp to a different map"}}, - {"broadcast", {"<message ...>", + "Warp to a different map"_s}}, + {"broadcast"_s, {"<message ...>"_s, 40, atcommand_broadcast, - "Broadcast a message from you"}}, - {"localbroadcast", {"<message ...>", + "Broadcast a message from you"_s}}, + {"localbroadcast"_s, {"<message ...>"_s, 40, atcommand_localbroadcast, - "Broadcast a message from you locally"}}, - {"recallall", {"", + "Broadcast a message from you locally"_s}}, + {"recallall"_s, {""_s, 80, atcommand_recallall, - "Warp every online player to your current map"}}, - {"charskreset", {"<charname>", + "Warp every online player to your current map"_s}}, + {"charskreset"_s, {"<charname>"_s, 60, atcommand_charskreset, - "Reset a player's skill points"}}, - {"charstreset", {"<charname>", + "Reset a player's skill points"_s}}, + {"charstreset"_s, {"<charname>"_s, 60, atcommand_charstreset, - "Reset a player's stat points"}}, - {"charreset", {"<charname>", + "Reset a player's stat points"_s}}, + {"charreset"_s, {"<charname>"_s, 60, atcommand_charreset, - "Reset a player's skills, stats, and magic"}}, - {"charmodel", {"<hairstyle> <hair-color> <dye> <charname>", + "Reset a player's skills, stats, and magic"_s}}, + {"charmodel"_s, {"<hairstyle> <hair-color> <dye> <charname>"_s, 99, atcommand_charmodel, - "Change another character's appearance"}}, - {"charskpoint", {"<amount> <charname>", + "Change another character's appearance"_s}}, + {"charskpoint"_s, {"<amount> <charname>"_s, 60, atcommand_charskpoint, - "Adjust another player's skill points"}}, - {"charstpoint", {"<amount> <charname>", + "Adjust another player's skill points"_s}}, + {"charstpoint"_s, {"<amount> <charname>"_s, 60, atcommand_charstpoint, - "Adjust another player's stat points"}}, - {"charzeny", {"<delta> <charname>", + "Adjust another player's stat points"_s}}, + {"charzeny"_s, {"<delta> <charname>"_s, 80, atcommand_charzeny, - "Adjust another player's money"}}, - {"mapinfo", {"<0-2> [map]", + "Adjust another player's money"_s}}, + {"mapinfo"_s, {"<0-2> [map]"_s, 99, atcommand_mapinfo, - "Show some stats for the map. 1 also shows players, 2 also shows NPCs"}}, - {"dye", {"<dye>", + "Show some stats for the map. 1 also shows players, 2 also shows NPCs"_s}}, + {"dye"_s, {"<dye>"_s, 40, atcommand_dye, - "Don't use"}}, - {"ccolor", {"<dye>", + "Don't use"_s}}, + {"ccolor"_s, {"<dye>"_s, 40, atcommand_dye, - "Don't use"}}, - {"hairstyle", {"<style>", + "Don't use"_s}}, + {"hairstyle"_s, {"<style>"_s, 40, atcommand_hair_style, - "Change your hairstyle"}}, - {"haircolor", {"<color>", + "Change your hairstyle"_s}}, + {"haircolor"_s, {"<color>"_s, 40, atcommand_hair_color, - "Change your hair color"}}, - {"allstats", {"[value]", + "Change your hair color"_s}}, + {"allstats"_s, {"[value]"_s, 60, atcommand_all_stats, - "Adjust all stats by value (or maximum)"}}, - {"charchangesex", {"<charname>", + "Adjust all stats by value (or maximum)"_s}}, + {"charchangesex"_s, {"<charname>"_s, 60, atcommand_char_change_sex, - "Flip a characters sex and disconnect them"}}, - {"block", {"<charname>", + "Flip a characters sex and disconnect them"_s}}, + {"block"_s, {"<charname>"_s, 60, atcommand_char_block, - "Permanently block a player's account from the server"}}, - {"unblock", {"<charname>", + "Permanently block a player's account from the server"_s}}, + {"unblock"_s, {"<charname>"_s, 60, atcommand_char_unblock, - "Remove a permanent block from a player's account"}}, - {"ban", {"<timedelta> <charname>", + "Remove a permanent block from a player's account"_s}}, + {"ban"_s, {"<timedelta> <charname>"_s, 60, atcommand_char_ban, - "Ban a player's account from the server for a limited time"}}, - {"unban", {"<timedelta> <charname>", + "Ban a player's account from the server for a limited time"_s}}, + {"unban"_s, {"<timedelta> <charname>"_s, 60, atcommand_char_unban, - "Remove a limited ban from a player's account"}}, - {"partyspy", {"<party-name-or-id>", + "Remove a limited ban from a player's account"_s}}, + {"partyspy"_s, {"<party-name-or-id>"_s, 99, atcommand_partyspy, - "Listen to all chat within a party"}}, - {"partyrecall", {"<party-name-or-id>", + "Listen to all chat within a party"_s}}, + {"partyrecall"_s, {"<party-name-or-id>"_s, 99, atcommand_partyrecall, - "Warp all members of a party to you"}}, - {"enablenpc", {"<npc-name>", + "Warp all members of a party to you"_s}}, + {"enablenpc"_s, {"<npc-name>"_s, 80, atcommand_enablenpc, - "Enable an NPC for visibility"}}, - {"disablenpc", {"<npc-name>", + "Enable an NPC for visibility"_s}}, + {"disablenpc"_s, {"<npc-name>"_s, 80, atcommand_disablenpc, - "Disable an NPC for visibility"}}, - {"servertime", {"", + "Disable an NPC for visibility"_s}}, + {"servertime"_s, {""_s, 0, atcommand_servertime, - "Print the server's idea of the current time"}}, - {"chardelitem", {"<item-name-or-id> <count> <charname>", + "Print the server's idea of the current time"_s}}, + {"chardelitem"_s, {"<item-name-or-id> <count> <charname>"_s, 60, atcommand_chardelitem, - "Delete items from a player's inventory"}}, - {"listnearby", {"", + "Delete items from a player's inventory"_s}}, + {"listnearby"_s, {""_s, 40, atcommand_list_nearby, - "Print name of all nearby players"}}, - {"email", {"<actual@email> <new@email>", + "Print name of all nearby players"_s}}, + {"email"_s, {"<actual@email> <new@email>"_s, 0, atcommand_email, - "Changed your account's email"}}, - {"effect", {"<type> <flag>", + "Changed your account's email"_s}}, + {"effect"_s, {"<type> <flag>"_s, 99, atcommand_effect, - "Apply a special effect to yourself (or everyone! wtf?)"}}, - {"charitemlist", {"<charname>", + "Apply a special effect to yourself (or everyone! wtf?)"_s}}, + {"charitemlist"_s, {"<charname>"_s, 99, atcommand_character_item_list, - "List a player's items"}}, - {"charstoragelist", {"<charname>", + "List a player's items"_s}}, + {"charstoragelist"_s, {"<charname>"_s, 99, atcommand_character_storage_list, - "List a player's storage"}}, - {"addwarp", {"<mapname> <x> <y>", + "List a player's storage"_s}}, + {"addwarp"_s, {"<mapname> <x> <y>"_s, 80, atcommand_addwarp, - "Create a new permanent warp"}}, - {"killer", {"", + "Create a new permanent warp"_s}}, + {"killer"_s, {""_s, 60, atcommand_killer, - "Toggle whether you are a killer"}}, - {"charkiller", {"<charname>", + "Toggle whether you are a killer"_s}}, + {"charkiller"_s, {"<charname>"_s, 60, atcommand_charkiller, - "Toggle whether a player is a killer"}}, - {"npcmove", {"<x> <y> <npc-name>", + "Toggle whether a player is a killer"_s}}, + {"npcmove"_s, {"<x> <y> <npc-name>"_s, 80, atcommand_npcmove, - "Force an NPC to move on the map"}}, - {"killable", {"", + "Force an NPC to move on the map"_s}}, + {"killable"_s, {""_s, 60, atcommand_killable, - "Toggle whether you are killable"}}, - {"charkillable", {"<charname>", + "Toggle whether you are killable"_s}}, + {"charkillable"_s, {"<charname>"_s, 60, atcommand_charkillable, - "Toggle whether a player is killable"}}, - {"chareffect", {"<type> <target>", + "Toggle whether a player is killable"_s}}, + {"chareffect"_s, {"<type> <target>"_s, 40, atcommand_chareffect, - "Apply effect type with arg 0 to a player"}}, - {"dropall", {"", + "Apply effect type with arg 0 to a player"_s}}, + {"dropall"_s, {""_s, 99, atcommand_dropall, - "Drop all of your items"}}, - {"chardropall", {"<charname>", + "Drop all of your items"_s}}, + {"chardropall"_s, {"<charname>"_s, 60, atcommand_chardropall, - "Force a player to drop all of their items"}}, - {"storeall", {"", + "Force a player to drop all of their items"_s}}, + {"storeall"_s, {""_s, 60, atcommand_storeall, - "Store all of your items"}}, - {"charstoreall", {"<charname>", + "Store all of your items"_s}}, + {"charstoreall"_s, {"<charname>"_s, 60, atcommand_charstoreall, - "Store all of a player's items"}}, - {"rain", {"", + "Store all of a player's items"_s}}, + {"rain"_s, {""_s, 99, atcommand_rain, - "Enable the rain mapflag"}}, - {"snow", {"", + "Enable the rain mapflag"_s}}, + {"snow"_s, {""_s, 99, atcommand_snow, - "Enable the snow mapflag"}}, - {"sakura", {"", + "Enable the snow mapflag"_s}}, + {"sakura"_s, {""_s, 99, atcommand_sakura, - "Enable the sakura mapflag"}}, - {"fog", {"", + "Enable the sakura mapflag"_s}}, + {"fog"_s, {""_s, 99, atcommand_fog, - "Enable the fog mapflag"}}, - {"leaves", {"", + "Enable the fog mapflag"_s}}, + {"leaves"_s, {""_s, 99, atcommand_leaves, - "Enable the leaves mapflag"}}, - {"summon", {"<mob-id-or-name>", + "Enable the leaves mapflag"_s}}, + {"summon"_s, {"<mob-id-or-name>"_s, 50, atcommand_summon, - "Summon a slave monster temporarily"}}, - {"adjgmlvl", {"<level> <cmd>", + "Summon a slave monster temporarily"_s}}, + {"adjgmlvl"_s, {"<level> <cmd>"_s, 99, atcommand_adjgmlvl, - "Temporarily adjust the GM level of a command"}}, - {"adjcmdlvl", {"<level> <charname>", + "Temporarily adjust the GM level of a command"_s}}, + {"adjcmdlvl"_s, {"<level> <charname>"_s, 99, atcommand_adjcmdlvl, - "Temporarily adjust the GM level of a player"}}, - {"trade", {"<charname>", + "Temporarily adjust the GM level of a player"_s}}, + {"trade"_s, {"<charname>"_s, 60, atcommand_trade, - "Initiate trade with a player anywhere"}}, - {"charwipe", {"<charname>", + "Initiate trade with a player anywhere"_s}}, + {"charwipe"_s, {"<charname>"_s, 60, atcommand_char_wipe, - "Reset a character almost completely"}}, - {"setmagic", {"<school> <value> <charname>", + "Reset a character almost completely"_s}}, + {"setmagic"_s, {"<school> <value> <charname>"_s, 80, atcommand_set_magic, - "Force magic skill level"}}, - {"magicinfo", {"<charname>", + "Force magic skill level"_s}}, + {"magicinfo"_s, {"<charname>"_s, 80, atcommand_magic_info, - "Show magic skills of a palyer"}}, - {"log", {"<message ...>", + "Show magic skills of a palyer"_s}}, + {"log"_s, {"<message ...>"_s, 40, atcommand_log, - "Write something directly to the log"}}, - {"l", {"<message ...>", + "Write something directly to the log"_s}}, + {"l"_s, {"<message ...>"_s, 40, atcommand_log, - "Write something directly to the log"}}, - {"tee", {"<message ...>", + "Write something directly to the log"_s}}, + {"tee"_s, {"<message ...>"_s, 40, atcommand_tee, - "Duplicate a message to the log and public chat"}}, - {"t", {"<message ...>", + "Duplicate a message to the log and public chat"_s}}, + {"t"_s, {"<message ...>"_s, 40, atcommand_tee, - "Duplicate a message to the log and public chat"}}, - {"invisible", {"", + "Duplicate a message to the log and public chat"_s}}, + {"invisible"_s, {""_s, 50, atcommand_invisible, - "Make yourself invisible to players"}}, - {"visible", {"", + "Make yourself invisible to players"_s}}, + {"visible"_s, {""_s, 50, atcommand_visible, - "Make yourself visible to players"}}, - {"hugo", {"", + "Make yourself visible to players"_s}}, + {"hugo"_s, {""_s, 60, atcommand_iterate_forward_over_players, - "Jump to the next player"}}, - {"linus", {"", + "Jump to the next player"_s}}, + {"linus"_s, {""_s, 60, atcommand_iterate_backwards_over_players, - "Jump to the previous player"}}, - {"sp-info", {"<charname>", + "Jump to the previous player"_s}}, + {"sp-info"_s, {"<charname>"_s, 40, atcommand_skillpool_info, - "Show info about pool skills"}}, - {"sp-focus", {"<skill-id> <charname>", + "Show info about pool skills"_s}}, + {"sp-focus"_s, {"<skill-id> <charname>"_s, 80, atcommand_skillpool_focus, - "Focus on a pool skill"}}, - {"sp-unfocus", {"<skill-id> <charname>", + "Focus on a pool skill"_s}}, + {"sp-unfocus"_s, {"<skill-id> <charname>"_s, 80, atcommand_skillpool_unfocus, - "Unfocus off of a pool skill"}}, - {"skill-learn", {"<skill-id> <level> <charname>", + "Unfocus off of a pool skill"_s}}, + {"skill-learn"_s, {"<skill-id> <level> <charname>"_s, 80, atcommand_skill_learn, - "Change a skill level"}}, - {"wgm", {"<message ...>", + "Change a skill level"_s}}, + {"wgm"_s, {"<message ...>"_s, 0, atcommand_wgm, - "Send a message to online GMs"}}, - {"ipcheck", {"<charname>", + "Send a message to online GMs"_s}}, + {"ipcheck"_s, {"<charname>"_s, 60, atcommand_ipcheck, - "List players on the same IP address"}}, - {"doomspot", {"", + "List players on the same IP address"_s}}, + {"doomspot"_s, {""_s, 60, atcommand_doomspot, - "Kill all players on the same tile"}}, - {"source", {"", + "Kill all players on the same tile"_s}}, + {"source"_s, {""_s, 0, atcommand_source, - "Legal information about source code (must be a level 0 command!)"}}, + "Legal information about source code (must be a level 0 command!)"_s}}, }; +} // namespace tmwa diff --git a/src/map/atcommand.hpp b/src/map/atcommand.hpp index 95e3814..4bf5277 100644 --- a/src/map/atcommand.hpp +++ b/src/map/atcommand.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_ATCOMMAND_HPP -#define TMWA_MAP_ATCOMMAND_HPP +#pragma once // atcommand.hpp - GM commands. // // Copyright © ????-2004 Athena Dev Teams @@ -21,14 +20,21 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "../strings/fwd.hpp" +#include "../strings/fwd.hpp" -# include "map.hpp" +#include "../generic/fwd.hpp" +#include "../net/fwd.hpp" + +#include "../mmo/fwd.hpp" + + +namespace tmwa +{ bool is_atcommand(Session *s, dumb_ptr<map_session_data> sd, - ZString message, int gmlvl); + ZString message, GmLevel gmlvl); bool atcommand_config_read(ZString cfgName); @@ -38,5 +44,4 @@ void log_atcommand(dumb_ptr<map_session_data> sd, ZString cmd); extern AString gm_log; void atcommand_config_write(ZString cfgName); - -#endif // TMWA_MAP_ATCOMMAND_HPP +} // namespace tmwa diff --git a/src/map/battle.cpp b/src/map/battle.cpp index 8e4d435..856408c 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -21,17 +21,18 @@ // 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 <cstring> +#include <algorithm> -#include "../compat/alg.hpp" #include "../compat/nullpo.hpp" #include "../strings/astring.hpp" #include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" +#include "../io/cxxstdio_enums.hpp" #include "../io/read.hpp" #include "../mmo/config_parse.hpp" @@ -47,12 +48,14 @@ #include "../poison.hpp" +namespace tmwa +{ static Battle_Config init_battle_config(); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wshadow" +DIAG_PUSH(); +DIAG_I(shadow); struct Battle_Config battle_config = init_battle_config(); -#pragma GCC diagnostic pop +DIAG_POP(); /*========================================== * 自分をロックしている対象の数を返す(汎用) @@ -63,7 +66,7 @@ static int battle_counttargeted(dumb_ptr<block_list> bl, dumb_ptr<block_list> src, ATK target_lv) { - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::PC) return pc_counttargeted(bl->is_player(), src, target_lv); @@ -77,15 +80,15 @@ int battle_counttargeted(dumb_ptr<block_list> bl, dumb_ptr<block_list> src, * 戻りは整数で0以上 *------------------------------------------ */ -int battle_get_class(dumb_ptr<block_list> bl) +Species battle_get_class(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retr(Species(), bl); if (bl->bl_type == BL::MOB) return bl->is_mob()->mob_class; else if (bl->bl_type == BL::PC) - return 0; + return bl->is_player()->status.species; else - return 0; + return Species(); } /*========================================== @@ -111,7 +114,7 @@ DIR battle_get_dir(dumb_ptr<block_list> bl) */ int battle_get_lv(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::MOB) return bl->is_mob()->stats[mob_stat::LV]; else if (bl->bl_type == BL::PC) @@ -127,9 +130,9 @@ int battle_get_lv(dumb_ptr<block_list> bl) */ int battle_get_range(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::MOB) - return mob_db[bl->is_mob()->mob_class].range; + return get_mob_db(bl->is_mob()->mob_class).range; else if (bl->bl_type == BL::PC) return bl->is_player()->attackrange; else @@ -189,7 +192,7 @@ int battle_get_str(dumb_ptr<block_list> bl) int str = 0; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(bl); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); if (bl->bl_type == BL::MOB) str = bl->is_mob()->stats[mob_stat::STR]; @@ -212,7 +215,7 @@ int battle_get_agi(dumb_ptr<block_list> bl) int agi = 0; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(bl); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); if (bl->bl_type == BL::MOB) agi = bl->is_mob()->stats[mob_stat::AGI]; @@ -234,7 +237,7 @@ int battle_get_vit(dumb_ptr<block_list> bl) int vit = 0; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(bl); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); if (bl->bl_type == BL::MOB) vit = bl->is_mob()->stats[mob_stat::VIT]; @@ -256,7 +259,7 @@ int battle_get_int(dumb_ptr<block_list> bl) int int_ = 0; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(bl); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); if (bl->bl_type == BL::MOB) int_ = bl->is_mob()->stats[mob_stat::INT]; @@ -278,7 +281,7 @@ int battle_get_dex(dumb_ptr<block_list> bl) int dex = 0; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(bl); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); if (bl->bl_type == BL::MOB) dex = bl->is_mob()->stats[mob_stat::DEX]; @@ -300,7 +303,7 @@ int battle_get_luk(dumb_ptr<block_list> bl) int luk = 0; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(bl); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); if (bl->bl_type == BL::MOB) luk = bl->is_mob()->stats[mob_stat::LUK]; @@ -466,7 +469,7 @@ int battle_get_atk(dumb_ptr<block_list> bl) eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; int atk = 0; - nullpo_ret(bl); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); if (bl->bl_type == BL::PC) atk = bl->is_player()->watk; @@ -486,7 +489,7 @@ int battle_get_atk(dumb_ptr<block_list> bl) static int battle_get_atk_(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::PC) return bl->is_player()->watk_; else @@ -501,7 +504,7 @@ int battle_get_atk_(dumb_ptr<block_list> bl) static int battle_get_atk2(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::PC) return bl->is_player()->watk2; else @@ -524,7 +527,7 @@ int battle_get_atk2(dumb_ptr<block_list> bl) static int battle_get_atk_2(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::PC) return bl->is_player()->watk_2; else @@ -540,7 +543,7 @@ static int battle_get_matk1(dumb_ptr<block_list> bl) { eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(bl); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); if (bl->bl_type == BL::MOB) { @@ -563,7 +566,7 @@ int battle_get_matk1(dumb_ptr<block_list> bl) static int battle_get_matk2(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::MOB) { int matk, int_ = battle_get_int(bl); @@ -587,7 +590,7 @@ int battle_get_def(dumb_ptr<block_list> bl) eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; int def = 0; - nullpo_ret(bl); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); if (bl->bl_type == BL::PC) { @@ -623,7 +626,7 @@ int battle_get_mdef(dumb_ptr<block_list> bl) eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; int mdef = 0; - nullpo_ret(bl); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); if (bl->bl_type == BL::PC) mdef = bl->is_player()->mdef; @@ -685,7 +688,7 @@ int battle_get_mdef2(dumb_ptr<block_list> bl) { int mdef2 = 0; - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::MOB) { dumb_ptr<mob_data> md = bl->is_mob(); @@ -710,16 +713,16 @@ int battle_get_mdef2(dumb_ptr<block_list> bl) */ interval_t battle_get_speed(dumb_ptr<block_list> bl) { - nullpo_retr(std::chrono::seconds(1), bl); + nullpo_retr(1_s, bl); if (bl->bl_type == BL::PC) return bl->is_player()->speed; else { - interval_t speed = std::chrono::seconds(1); + interval_t speed = 1_s; if (bl->bl_type == BL::MOB) speed = static_cast<interval_t>(bl->is_mob()->stats[mob_stat::SPEED]); - return std::max(speed, std::chrono::milliseconds(1)); + return std::max(speed, 1_ms); } } @@ -731,13 +734,13 @@ interval_t battle_get_speed(dumb_ptr<block_list> bl) // TODO figure out what all the doubling is about interval_t battle_get_adelay(dumb_ptr<block_list> bl) { - nullpo_retr(std::chrono::seconds(4), bl); + nullpo_retr(4_s, bl); if (bl->bl_type == BL::PC) return bl->is_player()->aspd * 2; else { eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data = battle_get_sc_data(bl); - interval_t adelay = std::chrono::seconds(4); + interval_t adelay = 4_s; int aspd_rate = 100; if (bl->bl_type == BL::MOB) adelay = static_cast<interval_t>(bl->is_mob()->stats[mob_stat::ADELAY]); @@ -759,16 +762,16 @@ interval_t battle_get_adelay(dumb_ptr<block_list> bl) interval_t battle_get_amotion(dumb_ptr<block_list> bl) { - nullpo_retr(std::chrono::seconds(2), bl); + nullpo_retr(2_s, bl); if (bl->bl_type == BL::PC) return bl->is_player()->amotion; else { eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data = battle_get_sc_data(bl); - interval_t amotion = std::chrono::seconds(2); + interval_t amotion = 2_s; int aspd_rate = 100; if (bl->bl_type == BL::MOB) - amotion = static_cast<interval_t>(mob_db[bl->is_mob()->mob_class].amotion); + amotion = static_cast<interval_t>(get_mob_db(bl->is_mob()->mob_class).amotion); if (sc_data) { @@ -789,14 +792,14 @@ interval_t battle_get_dmotion(dumb_ptr<block_list> bl) nullpo_retr(interval_t::zero(), bl); if (bl->bl_type == BL::MOB) { - return static_cast<interval_t>(mob_db[bl->is_mob()->mob_class].dmotion); + return static_cast<interval_t>(get_mob_db(bl->is_mob()->mob_class).dmotion); } else if (bl->bl_type == BL::PC) { return bl->is_player()->dmotion; } else - return std::chrono::seconds(2); + return 2_s; } LevelElement battle_get_element(dumb_ptr<block_list> bl) @@ -810,26 +813,26 @@ LevelElement battle_get_element(dumb_ptr<block_list> bl) return ret; } -int battle_get_party_id(dumb_ptr<block_list> bl) +PartyId battle_get_party_id(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retr(PartyId(), bl); if (bl->bl_type == BL::PC) return bl->is_player()->status.party_id; else if (bl->bl_type == BL::MOB) { dumb_ptr<mob_data> md = bl->is_mob(); - if (md->master_id > 0) - return -md->master_id; - return -md->bl_id; + if (md->master_id) + return wrap<PartyId>(-unwrap<BlockId>(md->master_id)); + return wrap<PartyId>(-unwrap<BlockId>(md->bl_id)); } - return 0; + return PartyId(); } Race battle_get_race(dumb_ptr<block_list> bl) { nullpo_retr(Race::formless, bl); if (bl->bl_type == BL::MOB) - return mob_db[bl->is_mob()->mob_class].race; + return get_mob_db(bl->is_mob()->mob_class).race; else if (bl->bl_type == BL::PC) return Race::demihuman; else @@ -840,7 +843,7 @@ MobMode battle_get_mode(dumb_ptr<block_list> bl) { nullpo_retr(MobMode::CAN_MOVE, bl); if (bl->bl_type == BL::MOB) - return mob_db[bl->is_mob()->mob_class].mode; + return get_mob_db(bl->is_mob()->mob_class).mode; // とりあえず動くということで1 return MobMode::CAN_MOVE; } @@ -883,60 +886,60 @@ eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> battle_ short *battle_get_sc_count(dumb_ptr<block_list> bl) { - nullpo_retr(NULL, bl); + nullpo_retr(nullptr, bl); if (bl->bl_type == BL::MOB) return &bl->is_mob()->sc_count; else if (bl->bl_type == BL::PC) return &bl->is_player()->sc_count; - return NULL; + return nullptr; } Opt1 *battle_get_opt1(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retn(bl); if (bl->bl_type == BL::MOB) return &bl->is_mob()->opt1; else if (bl->bl_type == BL::PC) return &bl->is_player()->opt1; else if (bl->bl_type == BL::NPC) return &bl->is_npc()->opt1; - return 0; + return nullptr; } Opt2 *battle_get_opt2(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retn(bl); if (bl->bl_type == BL::MOB) return &bl->is_mob()->opt2; else if (bl->bl_type == BL::PC) return &bl->is_player()->opt2; else if (bl->bl_type == BL::NPC) return &bl->is_npc()->opt2; - return 0; + return nullptr; } Opt3 *battle_get_opt3(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retn(bl); if (bl->bl_type == BL::MOB) return &bl->is_mob()->opt3; else if (bl->bl_type == BL::PC) return &bl->is_player()->opt3; else if (bl->bl_type == BL::NPC) return &bl->is_npc()->opt3; - return 0; + return nullptr; } Option *battle_get_option(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retn(bl); if (bl->bl_type == BL::MOB) return &bl->is_mob()->option; else if (bl->bl_type == BL::PC) return &bl->is_player()->status.option; else if (bl->bl_type == BL::NPC) return &bl->is_npc()->option; - return 0; + return nullptr; } //------------------------------------------------------------------- @@ -953,17 +956,17 @@ struct battle_delay_damage_ int battle_damage(dumb_ptr<block_list> bl, dumb_ptr<block_list> target, int damage, int flag) { - nullpo_ret(target); //blはNULLで呼ばれることがあるので他でチェック + nullpo_retz(target); //blはNULLで呼ばれることがあるので他でチェック if (damage == 0) return 0; - if (target->bl_prev == NULL) + if (target->bl_prev == nullptr) return 0; if (bl) { - if (bl->bl_prev == NULL) + if (bl->bl_prev == nullptr) return 0; } @@ -991,7 +994,7 @@ int battle_damage(dumb_ptr<block_list> bl, dumb_ptr<block_list> target, int battle_heal(dumb_ptr<block_list> bl, dumb_ptr<block_list> target, int hp, int sp, int flag) { - nullpo_ret(target); //blはNULLで呼ばれることがあるので他でチェック + nullpo_retz(target); //blはNULLで呼ばれることがあるので他でチェック if (target->bl_type == BL::PC && pc_isdead(target->is_player())) @@ -1012,7 +1015,7 @@ int battle_heal(dumb_ptr<block_list> bl, dumb_ptr<block_list> target, int hp, // 攻撃停止 int battle_stopattack(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::MOB) return mob_stopattack(bl->is_mob()); else if (bl->bl_type == BL::PC) @@ -1023,7 +1026,7 @@ int battle_stopattack(dumb_ptr<block_list> bl) // 移動停止 int battle_stopwalking(dumb_ptr<block_list> bl, int type) { - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::MOB) return mob_stop_walking(bl->is_mob(), type); else if (bl->bl_type == BL::PC) @@ -1040,9 +1043,9 @@ int battle_calc_damage(dumb_ptr<block_list>, dumb_ptr<block_list> bl, int damage, int div_, SkillID, int, BF flag) { - dumb_ptr<mob_data> md = NULL; + dumb_ptr<mob_data> md = nullptr; - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::MOB) md = bl->is_mob(); @@ -1059,7 +1062,7 @@ int battle_calc_damage(dumb_ptr<block_list>, dumb_ptr<block_list> bl, damage = 3; } - if (md != NULL && md->hp > 0 && damage > 0) // 反撃などのMOBスキル判定 + if (md != nullptr && md->hp > 0 && damage > 0) // 反撃などのMOBスキル判定 mobskill_event(md, flag); return damage; @@ -1071,8 +1074,8 @@ struct Damage battle_calc_mob_weapon_attack(dumb_ptr<block_list> src, SkillID skill_num, int skill_lv, int) { - dumb_ptr<map_session_data> tsd = NULL; - dumb_ptr<mob_data> md = src->is_mob(), tmd = NULL; + dumb_ptr<map_session_data> tsd = nullptr; + dumb_ptr<mob_data> md = src->is_mob(), tmd = nullptr; int hitrate, flee, cri = 0, atkmin, atkmax; int target_count = 1; int def1 = battle_get_def(target); @@ -1143,7 +1146,7 @@ struct Damage battle_calc_mob_weapon_attack(dumb_ptr<block_list> src, atkmin = battle_get_atk(src); atkmax = battle_get_atk2(src); } - if (mob_db[md->mob_class].range > 3) + if (get_mob_db(md->mob_class).range > 3) flag = (flag & ~BF::RANGEMASK) | BF::LONG; if (atkmin > atkmax) @@ -1282,7 +1285,7 @@ struct Damage battle_calc_mob_weapon_attack(dumb_ptr<block_list> src, damage = 0; // 完全回避の判定 - if (skill_num == SkillID::ZERO && skill_lv >= 0 && tsd != NULL + if (skill_num == SkillID::ZERO && skill_lv >= 0 && tsd != nullptr && random_::chance({battle_get_flee2(target), 1000})) { damage = 0; @@ -1292,7 +1295,7 @@ struct Damage battle_calc_mob_weapon_attack(dumb_ptr<block_list> src, if (battle_config.enemy_perfect_flee) { - if (skill_num == SkillID::ZERO && skill_lv >= 0 && tmd != NULL + if (skill_num == SkillID::ZERO && skill_lv >= 0 && tmd != nullptr && random_::chance({battle_get_flee2(target), 1000})) { damage = 0; @@ -1327,9 +1330,9 @@ int battle_is_unarmed(dumb_ptr<block_list> bl) { dumb_ptr<map_session_data> sd = bl->is_player(); - int sidx = sd->equip_index_maybe[EQUIP::SHIELD]; - int widx = sd->equip_index_maybe[EQUIP::WEAPON]; - return sidx == -1 && widx == -1; + IOff0 sidx = sd->equip_index_maybe[EQUIP::SHIELD]; + IOff0 widx = sd->equip_index_maybe[EQUIP::WEAPON]; + return !sidx.ok() && !widx.ok(); } else return 0; @@ -1346,8 +1349,8 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr<block_list> src, SkillID skill_num, int skill_lv, int) { - dumb_ptr<map_session_data> sd = src->is_player(), tsd = NULL; - dumb_ptr<mob_data> tmd = NULL; + dumb_ptr<map_session_data> sd = src->is_player(), tsd = nullptr; + dumb_ptr<mob_data> tmd = nullptr; int hitrate, flee, cri = 0, atkmin, atkmax; int dex, target_count = 1; int def1 = battle_get_def(target); @@ -1417,9 +1420,9 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr<block_list> src, int dy = abs(src->bl_y - target->bl_y); int malus_dist; - target_distance = max(dx, dy); + target_distance = std::max(dx, dy); malus_dist = - max(0, target_distance - (skill_power(sd, SkillID::AC_OWL) / 75)); + std::max(0, target_distance - (skill_power(sd, SkillID::AC_OWL) / 75)); hitrate -= (malus_dist * (malus_dist + 1)); } @@ -1449,12 +1452,12 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr<block_list> src, atkmin = atkmin_ = dex; //最低ATKはDEXで初期化? sd->state.arrow_atk = 0; //arrow_atk初期化 - int widx = sd->equip_index_maybe[EQUIP::WEAPON]; - int sidx = sd->equip_index_maybe[EQUIP::SHIELD]; + IOff0 widx = sd->equip_index_maybe[EQUIP::WEAPON]; + IOff0 sidx = sd->equip_index_maybe[EQUIP::SHIELD]; - if (widx >= 0 && sd->inventory_data[widx]) + if (widx.ok() && sd->inventory_data[widx]) atkmin = atkmin * (80 + sd->inventory_data[widx]->wlv * 20) / 100; - if (sidx >= 0 && sd->inventory_data[sidx]) + if (sidx.ok() && sd->inventory_data[sidx]) atkmin_ = atkmin_ * (80 + sd->inventory_data[sidx]->wlv * 20) / 100; if (sd->status.weapon == ItemLook::BOW) { //武器が弓矢の場合 @@ -1708,7 +1711,7 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr<block_list> src, } // 完全回避の判定 - if (skill_num == SkillID::ZERO && skill_lv >= 0 && tsd != NULL && div_ < 255 + if (skill_num == SkillID::ZERO && skill_lv >= 0 && tsd != nullptr && div_ < 255 && random_::chance({battle_get_flee2(target), 1000})) { damage = damage2 = 0; @@ -1719,7 +1722,7 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr<block_list> src, // 対象が完全回避をする設定がONなら if (battle_config.enemy_perfect_flee) { - if (skill_num == SkillID::ZERO && skill_lv >= 0 && tmd != NULL && div_ < 255 + if (skill_num == SkillID::ZERO && skill_lv >= 0 && tmd != nullptr && div_ < 255 && random_::chance({battle_get_flee2(target), 1000})) { damage = damage2 = 0; @@ -1809,7 +1812,7 @@ struct Damage battle_calc_magic_attack(dumb_ptr<block_list> bl, int matk1, matk2, damage = 0, div_ = 1; struct Damage md {}; int normalmagic_flag = 1; - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; nullpo_retr(md, bl); nullpo_retr(md, target); @@ -1885,7 +1888,7 @@ struct Damage battle_calc_misc_attack(dumb_ptr<block_list> bl, dumb_ptr<block_list> target, SkillID skill_num, int skill_lv, int) { - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; int damage = 0, div_ = 1; struct Damage md {}; int damagefix = 1; @@ -1965,7 +1968,7 @@ struct Damage battle_calc_attack(BF attack_type, flag); default: if (battle_config.error_log) - PRINTF("battle_calc_attack: unknwon attack type ! %d\n", + PRINTF("battle_calc_attack: unknwon attack type ! %d\n"_fmt, attack_type); break; } @@ -1979,7 +1982,7 @@ struct Damage battle_calc_attack(BF attack_type, ATK battle_weapon_attack(dumb_ptr<block_list> src, dumb_ptr<block_list> target, tick_t tick) { - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> t_sc_data = battle_get_sc_data(target); struct Damage wd; @@ -1989,7 +1992,7 @@ ATK battle_weapon_attack(dumb_ptr<block_list> src, dumb_ptr<block_list> target, if (src->bl_type == BL::PC) sd = src->is_player(); - if (src->bl_prev == NULL || target->bl_prev == NULL) + if (src->bl_prev == nullptr || target->bl_prev == nullptr) return ATK::ZERO; if (src->bl_type == BL::PC && pc_isdead(sd)) return ATK::ZERO; @@ -1998,7 +2001,7 @@ ATK battle_weapon_attack(dumb_ptr<block_list> src, dumb_ptr<block_list> target, return ATK::ZERO; Opt1 *opt1 = battle_get_opt1(src); - if (opt1 != NULL && bool(*opt1)) + if (opt1 != nullptr && bool(*opt1)) { battle_stopattack(src); return ATK::ZERO; @@ -2010,8 +2013,8 @@ ATK battle_weapon_attack(dumb_ptr<block_list> src, dumb_ptr<block_list> target, // 攻撃対象となりうるので攻撃 if (sd && sd->status.weapon == ItemLook::BOW) { - int aidx = sd->equip_index_maybe[EQUIP::ARROW]; - if (aidx >= 0) + IOff0 aidx = sd->equip_index_maybe[EQUIP::ARROW]; + if (aidx.ok()) { if (battle_config.arrow_decrement) pc_delitem(sd, aidx, 1, 0); @@ -2040,7 +2043,7 @@ ATK battle_weapon_attack(dumb_ptr<block_list> src, dumb_ptr<block_list> target, wd.damage -= reduction; MAP_LOG_PC(target->is_player(), - "MAGIC-ABSORB-DMG %d", reduction); + "MAGIC-ABSORB-DMG %d"_fmt, reduction); } { @@ -2050,7 +2053,7 @@ ATK battle_weapon_attack(dumb_ptr<block_list> src, dumb_ptr<block_list> target, && (sd->status.weapon == ItemLook::_16 || sd->status.weapon >= ItemLook::SINGLE_HANDED_COUNT) && wd.damage2 == 0) - clif_damage(src, target, tick + std::chrono::milliseconds(10), + clif_damage(src, target, tick + 10_ms, wd.amotion, wd.dmotion, 0, 1, DamageType::NORMAL, 0); } @@ -2058,37 +2061,37 @@ ATK battle_weapon_attack(dumb_ptr<block_list> src, dumb_ptr<block_list> target, if (src->bl_type == BL::PC) { - int weapon_index = sd->equip_index_maybe[EQUIP::WEAPON]; - int weapon = 0; - if (weapon_index >= 0 && sd->inventory_data[weapon_index] + IOff0 weapon_index = sd->equip_index_maybe[EQUIP::WEAPON]; + ItemNameId weapon; + if (weapon_index.ok() && sd->inventory_data[weapon_index] && bool(sd->status.inventory[weapon_index].equip & EPOS::WEAPON)) weapon = sd->inventory_data[weapon_index]->nameid; - MAP_LOG("PC%d %s:%d,%d WPNDMG %s%d %d FOR %d WPN %d", - sd->status_key.char_id, src->bl_m->name_, src->bl_x, src->bl_y, - (target->bl_type == BL::PC) ? "PC" : "MOB", - (target->bl_type == BL::PC) - ? target->is_player()-> status_key.char_id - : target->bl_id, - battle_get_class(target), - wd.damage + wd.damage2, weapon); + MAP_LOG("PC%d %s:%d,%d WPNDMG %s%d %d FOR %d WPN %d"_fmt, + sd->status_key.char_id, src->bl_m->name_, src->bl_x, src->bl_y, + (target->bl_type == BL::PC) ? "PC"_s : "MOB"_s, + (target->bl_type == BL::PC) + ? unwrap<CharId>(target->is_player()->status_key.char_id) + : unwrap<BlockId>(target->bl_id), + battle_get_class(target), + wd.damage + wd.damage2, weapon); } if (target->bl_type == BL::PC) { dumb_ptr<map_session_data> sd2 = target->is_player(); - MAP_LOG("PC%d %s:%d,%d WPNINJURY %s%d %d FOR %d", - sd2->status_key.char_id, target->bl_m->name_, target->bl_x, target->bl_y, - (src->bl_type == BL::PC) ? "PC" : "MOB", - (src->bl_type == BL::PC) - ? src->is_player()->status_key.char_id - : src->bl_id, - battle_get_class(src), - wd.damage + wd.damage2); + MAP_LOG("PC%d %s:%d,%d WPNINJURY %s%d %d FOR %d"_fmt, + sd2->status_key.char_id, target->bl_m->name_, target->bl_x, target->bl_y, + (src->bl_type == BL::PC) ? "PC"_s : "MOB"_s, + (src->bl_type == BL::PC) + ? unwrap<CharId>(src->is_player()->status_key.char_id) + : unwrap<BlockId>(src->bl_id), + battle_get_class(src), + wd.damage + wd.damage2); } battle_damage(src, target, (wd.damage + wd.damage2), 0); - if (target->bl_prev != NULL && + if (target->bl_prev != nullptr && (target->bl_type != BL::PC || (target->bl_type == BL::PC && !pc_isdead(target->is_player())))) @@ -2161,11 +2164,11 @@ bool battle_check_undead(Race race, Element element) int battle_check_target(dumb_ptr<block_list> src, dumb_ptr<block_list> target, BCT flag) { - int s_p, t_p; + PartyId s_p, t_p; dumb_ptr<block_list> ss = src; - nullpo_ret(src); - nullpo_ret(target); + nullpo_retz(src); + nullpo_retz(target); if (flag & BCT_ENEMY) { // 反転フラグ @@ -2191,7 +2194,7 @@ int battle_check_target(dumb_ptr<block_list> src, dumb_ptr<block_list> target, if (src->bl_type == BL::MOB) { dumb_ptr<mob_data> md = src->is_mob(); - if (md && md->master_id > 0) + if (md && md->master_id) { if (md->master_id == target->bl_id) // 主なら肯定 return 1; @@ -2214,7 +2217,7 @@ int battle_check_target(dumb_ptr<block_list> src, dumb_ptr<block_list> target, } } } - if ((ss = map_id2bl(md->master_id)) == NULL) + if ((ss = map_id2bl(md->master_id)) == nullptr) return -1; } } @@ -2226,7 +2229,7 @@ int battle_check_target(dumb_ptr<block_list> src, dumb_ptr<block_list> target, && pc_isinvisible(target->is_player())) return -1; - if (src->bl_prev == NULL || // 死んでるならエラー + if (src->bl_prev == nullptr || // 死んでるならエラー (src->bl_type == BL::PC && pc_isdead(src->is_player()))) return -1; @@ -2246,9 +2249,6 @@ int battle_check_target(dumb_ptr<block_list> src, dumb_ptr<block_list> target, return 0; } -//PRINTF("ss:%d src:%d target:%d flag:0x%x %d %d ",ss->bl_id,src->bl_id,target->bl_id,flag,src->bl_type,target->bl_type); -//PRINTF("p:%d %d g:%d %d\n",s_p,t_p,s_g,t_g); - if (ss->bl_type == BL::PC && target->bl_type == BL::PC) { // 両方PVPモードなら否定(敵) if (ss->bl_m->flag.get(MapFlag::PVP) @@ -2256,7 +2256,7 @@ int battle_check_target(dumb_ptr<block_list> src, dumb_ptr<block_list> target, { // [MouseJstr] if (battle_config.pk_mode) return 1; // prevent novice engagement in pk_mode [Valaris] - else if (ss->bl_m->flag.get(MapFlag::PVP_NOPARTY) && s_p > 0 && t_p > 0 + else if (ss->bl_m->flag.get(MapFlag::PVP_NOPARTY) && s_p && t_p && s_p == t_p) return 1; return 0; @@ -2278,8 +2278,8 @@ int battle_check_range(dumb_ptr<block_list> src, dumb_ptr<block_list> bl, struct walkpath_data wpd; int arange; - nullpo_ret(src); - nullpo_ret(bl); + nullpo_retz(src); + nullpo_retz(bl); dx = abs(bl->bl_x - src->bl_x); dy = abs(bl->bl_y - src->bl_y); @@ -2313,10 +2313,10 @@ int battle_check_range(dumb_ptr<block_list> src, dumb_ptr<block_list> bl, Battle_Config init_battle_config() { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wshadow" + DIAG_PUSH(); + DIAG_I(shadow); Battle_Config battle_config; -#pragma GCC diagnostic pop + DIAG_POP(); { battle_config.warp_point_debug = 0; battle_config.enemy_critical = 0; @@ -2430,17 +2430,17 @@ bool battle_config_read(ZString cfgName) io::ReadFile in(cfgName); if (!in.is_open()) { - PRINTF("file not found: %s\n", cfgName); + PRINTF("file not found: %s\n"_fmt, cfgName); return false; } AString line; while (in.getline(line)) { -#define BATTLE_CONFIG_VAR(name) {{#name}, &battle_config.name} +#define BATTLE_CONFIG_VAR(name) {#name##_s, &battle_config.name} const struct { - ZString str; + LString str; int *val; } data[] = { @@ -2550,12 +2550,12 @@ bool battle_config_read(ZString cfgName) ZString w2; if (!config_split(line, &w1, &w2)) { - PRINTF("Bad config line: %s\n", line); + PRINTF("Bad config line: %s\n"_fmt, line); rv = false; continue; } - if (w1 == "import") + if (w1 == "import"_s) { battle_config_read(w2); continue; @@ -2568,7 +2568,7 @@ bool battle_config_read(ZString cfgName) goto continue_outer; } - PRINTF("WARNING: unknown battle conf key: %s\n", AString(w1)); + PRINTF("WARNING: unknown battle conf key: %s\n"_fmt, AString(w1)); rv = false; continue_outer: @@ -2581,7 +2581,7 @@ bool battle_config_read(ZString cfgName) void battle_config_check() { { - if (static_cast<interval_t>(battle_config.flooritem_lifetime) < std::chrono::seconds(1)) + if (static_cast<interval_t>(battle_config.flooritem_lifetime) < 1_s) battle_config.flooritem_lifetime = std::chrono::duration_cast<std::chrono::milliseconds>(LIFETIME_FLOORITEM).count(); if (battle_config.restart_hp_rate < 0) battle_config.restart_hp_rate = 0; @@ -2686,3 +2686,4 @@ void battle_config_check() battle_config.mask_ip_gms = 1; } } +} // namespace tmwa diff --git a/src/map/battle.hpp b/src/map/battle.hpp index b8060a9..97a4a86 100644 --- a/src/map/battle.hpp +++ b/src/map/battle.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_BATTLE_HPP -#define TMWA_MAP_BATTLE_HPP +#pragma once // battle.hpp - Not so scary code. // // Copyright © ????-2004 Athena Dev Teams @@ -21,18 +20,23 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "battle.t.hpp" +#include "battle.t.hpp" -# include "../strings/fwd.hpp" +#include "../strings/fwd.hpp" -# include "../mmo/timer.t.hpp" +#include "../generic/fwd.hpp" -# include "magic-interpreter.t.hpp" -# include "map.t.hpp" -# include "skill.t.hpp" +#include "../net/timer.t.hpp" +#include "clif.t.hpp" +#include "map.t.hpp" +#include "skill.t.hpp" + + +namespace tmwa +{ // ダメージ struct Damage { @@ -44,10 +48,6 @@ struct Damage ATK dmg_lv; }; -struct map_session_data; -struct mob_data; -struct block_list; - // ダメージ計算 struct Damage battle_calc_attack(BF attack_type, @@ -69,7 +69,7 @@ ATK battle_weapon_attack(dumb_ptr<block_list> bl, dumb_ptr<block_list> target, tick_t tick); int battle_is_unarmed(dumb_ptr<block_list> bl); -int battle_get_class(dumb_ptr<block_list> bl); +Species battle_get_class(dumb_ptr<block_list> bl); DIR battle_get_dir(dumb_ptr<block_list> bl); int battle_get_lv(dumb_ptr<block_list> bl); int battle_get_range(dumb_ptr<block_list> bl); @@ -95,7 +95,7 @@ Element battle_get_elem_type(dumb_ptr<block_list> bl) { return battle_get_element(bl).element; } -int battle_get_party_id(dumb_ptr<block_list> bl); +PartyId battle_get_party_id(dumb_ptr<block_list> bl); Race battle_get_race(dumb_ptr<block_list> bl); MobMode battle_get_mode(dumb_ptr<block_list> bl); int battle_get_stat(SP stat_id, dumb_ptr<block_list> bl); @@ -225,5 +225,4 @@ extern struct Battle_Config bool battle_config_read(ZString cfgName); void battle_config_check(); - -#endif // TMWA_MAP_BATTLE_HPP +} // namespace tmwa diff --git a/src/map/battle.t.hpp b/src/map/battle.t.hpp index 9685ae7..53c34ff 100644 --- a/src/map/battle.t.hpp +++ b/src/map/battle.t.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_BATTLE_T_HPP -#define TMWA_MAP_BATTLE_T_HPP +#pragma once // battle.t.hpp - Not so scary code. // // Copyright © ????-2004 Athena Dev Teams @@ -21,10 +20,15 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "../generic/enum.hpp" +#include <cstdint> +#include "../generic/enum.hpp" + + +namespace tmwa +{ namespace e { enum class BF : uint16_t @@ -65,11 +69,11 @@ struct BCT }; constexpr -BCT operator & (BCT l, BCT r) { return {uint8_t(l.lo & r.lo), uint8_t(l.mid & r.mid), uint8_t(l.classic & r.classic), uint8_t(l.level & r.level), uint8_t(l.unused & r.unused) }; } +BCT operator & (BCT l, BCT r) { return {static_cast<uint8_t>(l.lo & r.lo), static_cast<uint8_t>(l.mid & r.mid), static_cast<uint8_t>(l.classic & r.classic), static_cast<uint8_t>(l.level & r.level), static_cast<uint8_t>(l.unused & r.unused) }; } constexpr -BCT operator | (BCT l, BCT r) { return {uint8_t(l.lo | r.lo), uint8_t(l.mid | r.mid), uint8_t(l.classic | r.classic), uint8_t(l.level | r.level), uint8_t(l.unused | r.unused) }; } +BCT operator | (BCT l, BCT r) { return {static_cast<uint8_t>(l.lo | r.lo), static_cast<uint8_t>(l.mid | r.mid), static_cast<uint8_t>(l.classic | r.classic), static_cast<uint8_t>(l.level | r.level), static_cast<uint8_t>(l.unused | r.unused) }; } constexpr -BCT operator ^ (BCT l, BCT r) { return {uint8_t(l.lo ^ r.lo), uint8_t(l.mid ^ r.mid), uint8_t(l.classic ^ r.classic), uint8_t(l.level ^ r.level), uint8_t(l.unused ^ r.unused) }; } +BCT operator ^ (BCT l, BCT r) { return {static_cast<uint8_t>(l.lo ^ r.lo), static_cast<uint8_t>(l.mid ^ r.mid), static_cast<uint8_t>(l.classic ^ r.classic), static_cast<uint8_t>(l.level ^ r.level), static_cast<uint8_t>(l.unused ^ r.unused) }; } inline BCT& operator &= (BCT& l, BCT r) { return l = l & r; } inline @@ -237,15 +241,4 @@ earray<Races, Race, Race::COUNT> race_shift //= Races::boss, Races::other, }}; - -enum class DamageType : uint8_t -{ - NORMAL = 0x00, - TAKEITEM = 0x01, - RETURNED = 0x04, - DOUBLED = 0x08, - CRITICAL = 0x0a, - FLEE2 = 0x0b, -}; - -#endif // TMWA_MAP_BATTLE_T_HPP +} // namespace tmwa diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp index fa95be7..0748f43 100644 --- a/src/map/chrif.cpp +++ b/src/map/chrif.cpp @@ -20,10 +20,6 @@ // 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 <arpa/inet.h> - -#include <cstring> - #include "../compat/fun.hpp" #include "../compat/nullpo.hpp" @@ -32,8 +28,15 @@ #include "../io/cxxstdio.hpp" -#include "../mmo/socket.hpp" -#include "../mmo/timer.hpp" +#include "../net/ip.hpp" +#include "../net/packets.hpp" +#include "../net/socket.hpp" +#include "../net/timer.hpp" + +#include "../proto2/char-map.hpp" + +#include "../mmo/human_time_diff.hpp" +#include "../mmo/mmo.hpp" #include "../mmo/utils.hpp" #include "battle.hpp" @@ -47,15 +50,9 @@ #include "../poison.hpp" -static -const int packet_len_table[0x20] = -{ - 60, 3, 10, 27, 22, -1, 6, -1, // 2af8-2aff - 6, -1, 18, 7, -1, 49, 44, 0, // 2b00-2b07 - 6, 30, -1, 10, 86, 7, 44, 34, // 2b08-2b0f - -1, -1, 10, 6, 11, -1, 0, 0, // 2b10-2b17 -}; +namespace tmwa +{ Session *char_session; static IP4Address char_ip; @@ -132,13 +129,12 @@ int chrif_save(dumb_ptr<map_session_data> sd) pc_makesavestatus(sd); - WFIFOW(char_session, 0) = 0x2b01; - WFIFOW(char_session, 2) = sizeof(sd->status_key) + sizeof(sd->status) + 12; - WFIFOL(char_session, 4) = sd->bl_id; - WFIFOL(char_session, 8) = sd->char_id; - WFIFO_STRUCT(char_session, 12, sd->status_key); - WFIFO_STRUCT(char_session, 12 + sizeof(sd->status_key), sd->status); - WFIFOSET(char_session, WFIFOW(char_session, 2)); + Packet_Payload<0x2b01> payload_01; + payload_01.account_id = block_to_account(sd->bl_id); + payload_01.char_id = sd->char_id_; + payload_01.char_key = sd->status_key; + payload_01.char_data = sd->status; + send_ppacket<0x2b01>(char_session, payload_01); //For data sync if (sd->state.storage_open) @@ -154,13 +150,13 @@ int chrif_save(dumb_ptr<map_session_data> sd) static int chrif_connect(Session *s) { - WFIFOW(s, 0) = 0x2af8; - WFIFO_STRING(s, 2, userid, 24); - WFIFO_STRING(s, 26, passwd, 24); - WFIFOL(s, 50) = 0; - WFIFOIP(s, 54) = clif_getip(); - WFIFOW(s, 58) = clif_getport(); // [Valaris] thanks to fov - WFIFOSET(s, 60); + Packet_Fixed<0x2af8> fixed_f8; + fixed_f8.account_name = userid; + fixed_f8.account_pass = passwd; + fixed_f8.unused = 0; + fixed_f8.ip = clif_getip(); + fixed_f8.port = clif_getport(); + send_fpacket<0x2af8, 60>(s, fixed_f8); return 0; } @@ -172,19 +168,17 @@ int chrif_connect(Session *s) static int chrif_sendmap(Session *s) { - int i = 0; - - WFIFOW(s, 0) = 0x2afa; + std::vector<Packet_Repeat<0x2afa>> repeat_fa; for (auto& pair : maps_db) { map_abstract *ma = pair.second.get(); if (!ma->gat) continue; - WFIFO_STRING(s, 4 + i * 16, ma->name_, 16); - i++; + Packet_Repeat<0x2afa> info; + info.map_name = ma->name_; + repeat_fa.push_back(info); } - WFIFOW(s, 2) = 4 + i * 16; - WFIFOSET(s, WFIFOW(s, 2)); + send_packet_repeatonly<0x2afa, 4, 16>(s, repeat_fa); return 0; } @@ -194,23 +188,21 @@ int chrif_sendmap(Session *s) *------------------------------------------ */ static -int chrif_recvmap(Session *s) +int chrif_recvmap(Session *, Packet_Head<0x2b04> head, const std::vector<Packet_Repeat<0x2b04>>& repeat) { - int i, j; - if (chrif_state < 2) // まだ準備中 return -1; - IP4Address ip = RFIFOIP(s, 4); - uint16_t port = RFIFOW(s, 8); - for (i = 10, j = 0; i < RFIFOW(s, 2); i += 16, j++) + IP4Address ip = head.ip; + uint16_t port = head.port; + for (const Packet_Repeat<0x2b04>& i : repeat) { - MapName map = RFIFO_STRING<16>(s, i); + MapName map = i.map_name; map_setipport(map, ip, port); } if (battle_config.etc_log) - PRINTF("recv map on %s:%d (%d maps)\n", - ip, port, j); + PRINTF("recv map on %s:%d (%zu maps)\n"_fmt, + ip, port, repeat.size()); return 0; } @@ -224,6 +216,9 @@ int chrif_changemapserver(dumb_ptr<map_session_data> sd, { nullpo_retr(-1, sd); + if (!char_session) + return -1; + IP4Address s_ip; for (io::FD i : iter_fds()) { @@ -238,19 +233,19 @@ int chrif_changemapserver(dumb_ptr<map_session_data> sd, } } - WFIFOW(char_session, 0) = 0x2b05; - WFIFOL(char_session, 2) = sd->bl_id; - WFIFOL(char_session, 6) = sd->login_id1; - WFIFOL(char_session, 10) = sd->login_id2; - WFIFOL(char_session, 14) = sd->status_key.char_id; - WFIFO_STRING(char_session, 18, name, 16); - WFIFOW(char_session, 34) = x; - WFIFOW(char_session, 36) = y; - WFIFOIP(char_session, 38) = ip; - WFIFOL(char_session, 42) = port; - WFIFOB(char_session, 44) = static_cast<uint8_t>(sd->status.sex); - WFIFOIP(char_session, 45) = s_ip; - WFIFOSET(char_session, 49); + Packet_Fixed<0x2b05> fixed_05; + fixed_05.account_id = block_to_account(sd->bl_id); + fixed_05.login_id1 = sd->login_id1; + fixed_05.login_id2 = sd->login_id2; + fixed_05.char_id = sd->status_key.char_id; + fixed_05.map_name = name; + fixed_05.x = x; + fixed_05.y = y; + fixed_05.map_ip = ip; + fixed_05.map_port = port; + fixed_05.sex = sd->status.sex; + fixed_05.client_ip = s_ip; + send_fpacket<0x2b05, 49>(char_session, fixed_05); return 0; } @@ -260,25 +255,26 @@ int chrif_changemapserver(dumb_ptr<map_session_data> sd, *------------------------------------------ */ static -int chrif_changemapserverack(Session *s) +int chrif_changemapserverack(Session *, const Packet_Fixed<0x2b06>& fixed) { - dumb_ptr<map_session_data> sd = map_id2sd(RFIFOL(s, 2)); + dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(fixed.account_id)); - if (sd == NULL || sd->status_key.char_id != RFIFOL(s, 14)) + if (sd == nullptr || sd->status_key.char_id != fixed.char_id) return -1; - if (RFIFOL(s, 6) == 1) + // I am fairly certain that this is not possible + if (fixed.error == 1) { if (battle_config.error_log) - PRINTF("map server change failed.\n"); + PRINTF("map server change failed.\n"_fmt); pc_authfail(sd->status_key.account_id); return 0; } - MapName mapname = RFIFO_STRING<16>(s, 18); - uint16_t x = RFIFOW(s, 34); - uint16_t y = RFIFOW(s, 36); - IP4Address ip = RFIFOIP(s, 38); - uint16_t port = RFIFOW(s, 42); + MapName mapname = fixed.map_name; + uint16_t x = fixed.x; + uint16_t y = fixed.y; + IP4Address ip = fixed.map_ip; + uint16_t port = fixed.map_port; clif_changemapserver(sd, mapname, x, y, ip, port); return 0; @@ -289,25 +285,22 @@ int chrif_changemapserverack(Session *s) *------------------------------------------ */ static -int chrif_connectack(Session *s) +int chrif_connectack(Session *s, const Packet_Fixed<0x2af9>& fixed) { - if (RFIFOB(s, 2)) + if (fixed.code) { - PRINTF("Connected to char-server failed %d.\n", RFIFOB(s, 2)); + PRINTF("Connected to char-server failed %d.\n"_fmt, fixed.code); exit(1); } - PRINTF("Connected to char-server (connection #%d).\n", s); + PRINTF("Connected to char-server (connection #%d).\n"_fmt, s); chrif_state = 1; chrif_sendmap(s); - PRINTF("chrif: OnCharIfInit event done. (%d events)\n", - npc_event_doall(stringish<ScriptLabel>("OnCharIfInit"))); - PRINTF("chrif: OnInterIfInit event done. (%d events)\n", - npc_event_doall(stringish<ScriptLabel>("OnInterIfInit"))); - - // <Agit> Run Event [AgitInit] -// PRINTF("NPC_Event:[OnAgitInit] do (%d) events (Agit Initialize).\n", npc_event_doall("OnAgitInit")); + PRINTF("chrif: OnCharIfInit event done. (%d events)\n"_fmt, + npc_event_doall(stringish<ScriptLabel>("OnCharIfInit"_s))); + PRINTF("chrif: OnInterIfInit event done. (%d events)\n"_fmt, + npc_event_doall(stringish<ScriptLabel>("OnInterIfInit"_s))); return 0; } @@ -317,16 +310,16 @@ int chrif_connectack(Session *s) *------------------------------------------ */ static -int chrif_sendmapack(Session *s) +int chrif_sendmapack(Session *, Packet_Fixed<0x2afb> fixed) { - if (RFIFOB(s, 2)) + if (fixed.unknown) //impossible { - PRINTF("chrif : send map list to char server failed %d\n", - RFIFOB(s, 2)); + PRINTF("chrif : send map list to char server failed %d\n"_fmt, + fixed.unknown); exit(1); } - wisp_server_name = stringish<CharName>(RFIFO_STRING<24>(s, 3)); + wisp_server_name = fixed.whisper_name; chrif_state = 2; @@ -352,13 +345,13 @@ int chrif_authreq(dumb_ptr<map_session_data> sd) if (dumb_ptr<map_session_data>(static_cast<map_session_data *>(s->session_data.get())) == sd) { assert (s == sd->sess); - WFIFOW(char_session, 0) = 0x2afc; - WFIFOL(char_session, 2) = sd->bl_id; - WFIFOL(char_session, 6) = sd->char_id; - WFIFOL(char_session, 10) = sd->login_id1; - WFIFOL(char_session, 14) = sd->login_id2; - WFIFOIP(char_session, 18) = s->client_ip; - WFIFOSET(char_session, 22); + Packet_Fixed<0x2afc> fixed_fc; + fixed_fc.account_id = block_to_account(sd->bl_id); + fixed_fc.char_id = sd->char_id_; + fixed_fc.login_id1 = sd->login_id1; + fixed_fc.login_id2 = sd->login_id2; + fixed_fc.ip = s->client_ip; + send_fpacket<0x2afc, 22>(char_session, fixed_fc); break; } } @@ -391,12 +384,12 @@ int chrif_charselectreq(dumb_ptr<map_session_data> sd) } } - WFIFOW(char_session, 0) = 0x2b02; - WFIFOL(char_session, 2) = sd->bl_id; - WFIFOL(char_session, 6) = sd->login_id1; - WFIFOL(char_session, 10) = sd->login_id2; - WFIFOIP(char_session, 14) = s_ip; - WFIFOSET(char_session, 18); + Packet_Fixed<0x2b02> fixed_02; + fixed_02.account_id = block_to_account(sd->bl_id); + fixed_02.login_id1 = sd->login_id1; + fixed_02.login_id2 = sd->login_id2; + fixed_02.ip = s_ip; + send_fpacket<0x2b02, 18>(char_session, fixed_02); return 0; } @@ -405,35 +398,38 @@ int chrif_charselectreq(dumb_ptr<map_session_data> sd) * GMに変化要求 *------------------------------------------ */ -void chrif_changegm(int id, ZString pass) +void chrif_changegm(AccountId id, ZString pass) { + if (!char_session) + return; + if (battle_config.etc_log) - PRINTF("chrif_changegm: account: %d, password: '%s'.\n", id, pass); - - size_t len = pass.size() + 1; - WFIFOW(char_session, 0) = 0x2b0a; - WFIFOW(char_session, 2) = len + 8; - WFIFOL(char_session, 4) = id; - WFIFO_STRING(char_session, 8, pass, len); - WFIFOSET(char_session, len + 8); + PRINTF("chrif_changegm: account: %d, password: '%s'.\n"_fmt, id, pass); + + Packet_Head<0x2b0a> head_0a; + head_0a.account_id = id; + send_vpacket<0x2b0a, 8, 1>(char_session, head_0a, pass); } /*========================================== * Change Email *------------------------------------------ */ -void chrif_changeemail(int id, AccountEmail actual_email, +void chrif_changeemail(AccountId id, AccountEmail actual_email, AccountEmail new_email) { + if (!char_session) + return; + if (battle_config.etc_log) - PRINTF("chrif_changeemail: account: %d, actual_email: '%s', new_email: '%s'.\n", - id, actual_email, new_email); - - WFIFOW(char_session, 0) = 0x2b0c; - WFIFOL(char_session, 2) = id; - WFIFO_STRING(char_session, 6, actual_email, 40); - WFIFO_STRING(char_session, 46, new_email, 40); - WFIFOSET(char_session, 86); + PRINTF("chrif_changeemail: account: %d, actual_email: '%s', new_email: '%s'.\n"_fmt, + id, actual_email, new_email); + + Packet_Fixed<0x2b0c> fixed_0c; + fixed_0c.account_id = id; + fixed_0c.old_email = actual_email; + fixed_0c.new_email = new_email; + send_fpacket<0x2b0c, 86>(char_session, fixed_0c); } /*========================================== @@ -447,17 +443,20 @@ void chrif_changeemail(int id, AccountEmail actual_email, * 5: changesex *------------------------------------------ */ -void chrif_char_ask_name(int id, CharName character_name, short operation_type, +void chrif_char_ask_name(AccountId id, CharName character_name, short operation_type, HumanTimeDiff modif) { - WFIFOW(char_session, 0) = 0x2b0e; - WFIFOL(char_session, 2) = id; // account_id of who ask (for answer) -1 if nobody - WFIFO_STRING(char_session, 6, character_name.to__actual(), 24); - WFIFOW(char_session, 30) = operation_type; // type of operation + if (!char_session) + return; + + Packet_Fixed<0x2b0e> fixed_0e; + fixed_0e.account_id = id; // who ask, or nobody + fixed_0e.char_name = character_name; + fixed_0e.operation = operation_type; // type of operation if (operation_type == 2) - WFIFO_STRUCT(char_session, 32, modif); - PRINTF("chrif : sended 0x2b0e\n"); - WFIFOSET(char_session, 44); + fixed_0e.ban_add = modif; + PRINTF("chrif : sended 0x2b0e\n"_fmt); + send_fpacket<0x2b0e, 44>(char_session, fixed_0e); } /*========================================== @@ -477,123 +476,123 @@ void chrif_char_ask_name(int id, CharName character_name, short operation_type, *------------------------------------------ */ static -int chrif_char_ask_name_answer(Session *s) +int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed) { - int acc = RFIFOL(s, 2); // account_id of who has asked (-1 if nobody) - CharName player_name = stringish<CharName>(RFIFO_STRING<24>(s, 6)); + AccountId acc = fixed.account_id; // who asked, or nobody + CharName player_name = fixed.char_name; - dumb_ptr<map_session_data> sd = map_id2sd(acc); - if (acc >= 0 && sd != NULL) + dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(acc)); + if (acc && sd != nullptr) { AString output; - if (RFIFOW(s, 32) == 1) // player not found - output = STRPRINTF("The player '%s' doesn't exist.", + if (fixed.error == 1) // player not found + output = STRPRINTF("The player '%s' doesn't exist."_fmt, player_name); else { - switch (RFIFOW(s, 30)) + switch (fixed.operation) { case 1: // block - switch (RFIFOW(s, 32)) + switch (fixed.error) { case 0: // login-server resquest done output = STRPRINTF( - "Login-server has been asked to block the player '%s'.", + "Login-server has been asked to block the player '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( - "Your GM level don't authorise you to block the player '%s'.", + "Your GM level don't authorise you to block the player '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( - "Login-server is offline. Impossible to block the the player '%s'.", + "Login-server is offline. Impossible to block the the player '%s'."_fmt, player_name); break; } break; case 2: // ban - switch (RFIFOW(s, 32)) + switch (fixed.error) { case 0: // login-server resquest done output = STRPRINTF( - "Login-server has been asked to ban the player '%s'.", + "Login-server has been asked to ban the player '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( - "Your GM level don't authorise you to ban the player '%s'.", + "Your GM level don't authorise you to ban the player '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( - "Login-server is offline. Impossible to ban the the player '%s'.", + "Login-server is offline. Impossible to ban the the player '%s'."_fmt, player_name); break; } break; case 3: // unblock - switch (RFIFOW(s, 32)) + switch (fixed.error) { case 0: // login-server resquest done output = STRPRINTF( - "Login-server has been asked to unblock the player '%s'.", + "Login-server has been asked to unblock the player '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( - "Your GM level don't authorise you to unblock the player '%s'.", + "Your GM level don't authorise you to unblock the player '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( - "Login-server is offline. Impossible to unblock the the player '%s'.", + "Login-server is offline. Impossible to unblock the the player '%s'."_fmt, player_name); break; } break; case 4: // unban - switch (RFIFOW(s, 32)) + switch (fixed.error) { case 0: // login-server resquest done output = STRPRINTF( - "Login-server has been asked to unban the player '%s'.", + "Login-server has been asked to unban the player '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( - "Your GM level don't authorise you to unban the player '%s'.", + "Your GM level don't authorise you to unban the player '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( - "Login-server is offline. Impossible to unban the the player '%s'.", + "Login-server is offline. Impossible to unban the the player '%s'."_fmt, player_name); break; } break; case 5: // changesex - switch (RFIFOW(s, 32)) + switch (fixed.error) { case 0: // login-server resquest done output = STRPRINTF( - "Login-server has been asked to change the sex of the player '%s'.", + "Login-server has been asked to change the sex of the player '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( - "Your GM level don't authorise you to change the sex of the player '%s'.", + "Your GM level don't authorise you to change the sex of the player '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( - "Login-server is offline. Impossible to change the sex of the the player '%s'.", + "Login-server is offline. Impossible to change the sex of the the player '%s'."_fmt, player_name); break; } @@ -604,7 +603,7 @@ int chrif_char_ask_name_answer(Session *s) clif_displaymessage(sd->sess, output); } else - PRINTF("chrif_char_ask_name_answer failed - player not online.\n"); + PRINTF("chrif_char_ask_name_answer failed - player not online.\n"_fmt); return 0; } @@ -614,25 +613,22 @@ int chrif_char_ask_name_answer(Session *s) *------------------------------------------ */ static -void chrif_changedgm(Session *s) +void chrif_changedgm(Session *, const Packet_Fixed<0x2b0b>& fixed) { - int acc, level; - dumb_ptr<map_session_data> sd = NULL; - - acc = RFIFOL(s, 2); - level = RFIFOL(s, 6); + AccountId acc = fixed.account_id; + GmLevel level = fixed.gm_level; - sd = map_id2sd(acc); + dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(acc)); if (battle_config.etc_log) - PRINTF("chrif_changedgm: account: %d, GM level 0 -> %d.\n", acc, + PRINTF("chrif_changedgm: account: %d, GM level 0 -> %d.\n"_fmt, acc, level); - if (sd != NULL) + if (sd != nullptr) { - if (level > 0) - clif_displaymessage(sd->sess, "GM modification success."); + if (level) + clif_displaymessage(sd->sess, "GM modification success."_s); else - clif_displaymessage(sd->sess, "Failure of GM modification."); + clif_displaymessage(sd->sess, "Failure of GM modification."_s); } } @@ -641,26 +637,25 @@ void chrif_changedgm(Session *s) *------------------------------------------ */ static -void chrif_changedsex(Session *s) +void chrif_changedsex(Session *, const Packet_Fixed<0x2b0d>& fixed) { - int acc, i; dumb_ptr<map_session_data> sd; - acc = RFIFOL(s, 2); - SEX sex = static_cast<SEX>(RFIFOB(s, 6)); + AccountId acc = fixed.account_id; + SEX sex = fixed.sex; if (battle_config.etc_log) - PRINTF("chrif_changedsex %d.\n", acc); - sd = map_id2sd(acc); - if (acc > 0) + PRINTF("chrif_changedsex %d.\n"_fmt, acc); + sd = map_id2sd(account_to_block(acc)); + if (acc) { - if (sd != NULL && sd->status.sex != sex) + if (sd != nullptr && sd->status.sex != sex) { if (sd->status.sex == SEX::MALE) sd->sex = sd->status.sex = SEX::FEMALE; else if (sd->status.sex == SEX::FEMALE) sd->sex = sd->status.sex = SEX::MALE; // to avoid any problem with equipment and invalid sex, equipment is unequiped. - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { if (sd->status.inventory[i].nameid && bool(sd->status.inventory[i].equip)) @@ -671,15 +666,15 @@ void chrif_changedsex(Session *s) sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters // do same modify in login-server for the account, but no in char-server (it ask again login_id1 to login, and don't remember it) clif_displaymessage(sd->sess, - "Your sex has been changed (need disconexion by the server)..."); + "Your sex has been changed (need disconexion by the server)..."_s); clif_setwaitclose(sd->sess); // forced to disconnect for the change } } else { - if (sd != NULL) + if (sd != nullptr) { - PRINTF("chrif_changedsex failed.\n"); + PRINTF("chrif_changedsex failed.\n"_fmt); } } } @@ -690,24 +685,27 @@ void chrif_changedsex(Session *s) */ int chrif_saveaccountreg2(dumb_ptr<map_session_data> sd) { - int p, j; nullpo_retr(-1, sd); - p = 8; - for (j = 0; j < sd->status.account_reg2_num; j++) + if (!char_session) + return -1; + + std::vector<Packet_Repeat<0x2b10>> repeat_10; + for (size_t j = 0; j < sd->status.account_reg2_num; j++) { - struct global_reg *reg = &sd->status.account_reg2[j]; + GlobalReg *reg = &sd->status.account_reg2[j]; if (reg->str && reg->value != 0) { - WFIFO_STRING(char_session, p, reg->str, 32); - WFIFOL(char_session, p + 32) = reg->value; - p += 36; + Packet_Repeat<0x2b10> info; + info.name = reg->str; + info.value = reg->value; + repeat_10.push_back(info); } } - WFIFOW(char_session, 0) = 0x2b10; - WFIFOW(char_session, 2) = p; - WFIFOL(char_session, 4) = sd->bl_id; - WFIFOSET(char_session, p); + + Packet_Head<0x2b10> head_10; + head_10.account_id = block_to_account(sd->bl_id); + send_vpacket<0x2b10, 8, 36>(char_session, head_10, repeat_10); return 0; } @@ -717,20 +715,19 @@ int chrif_saveaccountreg2(dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -int chrif_accountreg2(Session *s) +int chrif_accountreg2(Session *, const Packet_Head<0x2b11>& head, const std::vector<Packet_Repeat<0x2b11>>& repeat) { - int j, p; - dumb_ptr<map_session_data> sd = map_id2sd(RFIFOL(s, 4)); - if (sd == NULL) + dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(head.account_id)); + if (sd == nullptr) return 1; - for (p = 8, j = 0; p < RFIFOW(s, 2) && j < ACCOUNT_REG2_NUM; - p += 36, j++) + size_t jlim = std::min(ACCOUNT_REG2_NUM, repeat.size()); + for (size_t j = 0; j < jlim; j++) { - sd->status.account_reg2[j].str = stringish<VarName>(RFIFO_STRING<32>(s, p)); - sd->status.account_reg2[j].value = RFIFOL(s, p + 32); + sd->status.account_reg2[j].str = repeat[j].name; + sd->status.account_reg2[j].value = repeat[j].value; } - sd->status.account_reg2_num = j; + sd->status.account_reg2_num = jlim; return 0; } @@ -742,9 +739,9 @@ int chrif_accountreg2(Session *s) *------------------------------------------ */ static -int chrif_divorce(int char_id, int partner_id) +int chrif_divorce(CharId char_id, CharId partner_id) { - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; if (!char_id || !partner_id) return 0; @@ -752,7 +749,7 @@ int chrif_divorce(int char_id, int partner_id) sd = map_nick2sd(map_charid2nick(char_id)); if (sd && sd->status.partner_id == partner_id) { - sd->status.partner_id = 0; + sd->status.partner_id = CharId(); if (sd->npc_flags.divorce) { @@ -762,9 +759,9 @@ int chrif_divorce(int char_id, int partner_id) } sd = map_nick2sd(map_charid2nick(partner_id)); - nullpo_ret(sd); + nullpo_retz(sd); if (sd->status.partner_id == char_id) - sd->status.partner_id = 0; + sd->status.partner_id = CharId(); return 0; } @@ -774,14 +771,14 @@ int chrif_divorce(int char_id, int partner_id) * Needed to divorce when partner is not connected to map server *------------------------------------- */ -int chrif_send_divorce(int char_id) +int chrif_send_divorce(CharId char_id) { if (!char_session) return -1; - WFIFOW(char_session, 0) = 0x2b16; - WFIFOL(char_session, 2) = char_id; - WFIFOSET(char_session, 6); + Packet_Fixed<0x2b16> fixed_16; + fixed_16.char_id = char_id; + send_fpacket<0x2b16, 6>(char_session, fixed_16); return 0; } @@ -790,29 +787,28 @@ int chrif_send_divorce(int char_id) *------------------------------------------ */ static -int chrif_accountdeletion(Session *s) +int chrif_accountdeletion(Session *, const Packet_Fixed<0x2b13>& fixed) { - int acc; dumb_ptr<map_session_data> sd; - acc = RFIFOL(s, 2); + AccountId acc = fixed.account_id; if (battle_config.etc_log) - PRINTF("chrif_accountdeletion %d.\n", acc); - sd = map_id2sd(acc); - if (acc > 0) + PRINTF("chrif_accountdeletion %d.\n"_fmt, acc); + sd = map_id2sd(account_to_block(acc)); + if (acc) { - if (sd != NULL) + if (sd != nullptr) { sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters clif_displaymessage(sd->sess, - "Your account has been deleted (disconnection)..."); + "Your account has been deleted (disconnection)..."_s); clif_setwaitclose(sd->sess); // forced to disconnect for the change } } else { - if (sd != NULL) - PRINTF("chrif_accountdeletion failed - player not online.\n"); + if (sd != nullptr) + PRINTF("chrif_accountdeletion failed - player not online.\n"_fmt); } return 0; @@ -823,85 +819,85 @@ int chrif_accountdeletion(Session *s) *------------------------------------------ */ static -int chrif_accountban(Session *s) +int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed) { - int acc; dumb_ptr<map_session_data> sd; - acc = RFIFOL(s, 2); + AccountId acc = fixed.account_id; if (battle_config.etc_log) - PRINTF("chrif_accountban %d.\n", acc); - sd = map_id2sd(acc); - if (acc > 0) + PRINTF("chrif_accountban %d.\n"_fmt, acc); + sd = map_id2sd(account_to_block(acc)); + if (acc) { - if (sd != NULL) + if (sd != nullptr) { sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters - if (RFIFOB(s, 6) == 0) + if (fixed.ban_not_status == 0) { // 0: change of statut, 1: ban - switch (RFIFOL(s, 7)) + switch (static_cast<time_t>(fixed.status_or_ban_until)) { // status or final date of a banishment case 1: // 0 = Unregistered ID clif_displaymessage(sd->sess, - "Your account has 'Unregistered'."); + "Your account has 'Unregistered'."_s); break; case 2: // 1 = Incorrect Password clif_displaymessage(sd->sess, - "Your account has an 'Incorrect Password'..."); + "Your account has an 'Incorrect Password'..."_s); break; case 3: // 2 = This ID is expired clif_displaymessage(sd->sess, - "Your account has expired."); + "Your account has expired."_s); break; case 4: // 3 = Rejected from Server clif_displaymessage(sd->sess, - "Your account has been rejected from server."); + "Your account has been rejected from server."_s); break; case 5: // 4 = You have been blocked by the GM Team clif_displaymessage(sd->sess, - "Your account has been blocked by the GM Team."); + "Your account has been blocked by the GM Team."_s); break; case 6: // 5 = Your Game's EXE file is not the latest version clif_displaymessage(sd->sess, - "Your Game's EXE file is not the latest version."); + "Your Game's EXE file is not the latest version."_s); break; case 7: // 6 = Your are Prohibited to log in until %s clif_displaymessage(sd->sess, - "Your account has been prohibited to log in."); + "Your account has been prohibited to log in."_s); break; case 8: // 7 = Server is jammed due to over populated clif_displaymessage(sd->sess, - "Server is jammed due to over populated."); + "Server is jammed due to over populated."_s); break; case 9: // 8 = No MSG (actually, all states after 9 except 99 are No MSG, use only this) clif_displaymessage(sd->sess, - "Your account has not more authorised."); + "Your account has not more authorised."_s); break; case 100: // 99 = This ID has been totally erased clif_displaymessage(sd->sess, - "Your account has been totally erased."); + "Your account has been totally erased."_s); break; default: clif_displaymessage(sd->sess, - "Your account has not more authorised."); + "Your account has not more authorised."_s); break; } } - else if (RFIFOB(s, 6) == 1) + else if (fixed.ban_not_status == 1) { // 0: change of statut, 1: ban - TimeT timestamp = static_cast<time_t>(RFIFOL(s, 7)); // status or final date of a banishment - char tmpstr[] = WITH_TIMESTAMP("Your account has been banished until "); - REPLACE_TIMESTAMP(tmpstr, timestamp); - clif_displaymessage(sd->sess, const_(tmpstr)); + const TimeT timestamp = fixed.status_or_ban_until; // status or final date of a banishment + timestamp_seconds_buffer buffer; + stamp_time(buffer, ×tamp); + AString tmpstr = STRPRINTF("Your account has been banished until %s"_fmt, buffer); + clif_displaymessage(sd->sess, tmpstr); } clif_setwaitclose(sd->sess); // forced to disconnect for the change } } else { - if (sd != NULL) - PRINTF("chrif_accountban failed - player not online.\n"); + if (sd != nullptr) + PRINTF("chrif_accountban failed - player not online.\n"_fmt); } return 0; @@ -912,10 +908,10 @@ int chrif_accountban(Session *s) *------------------------------------------ */ static -int chrif_recvgmaccounts(Session *s) +int chrif_recvgmaccounts(Session *s, const std::vector<Packet_Repeat<0x2b15>>& repeat) { - PRINTF("From login-server: receiving of %d GM accounts information.\n", - pc_read_gm_account(s)); + PRINTF("From login-server: receiving of %d GM accounts information.\n"_fmt, + pc_read_gm_account(s, repeat)); return 0; } @@ -926,9 +922,11 @@ int chrif_recvgmaccounts(Session *s) */ int chrif_reloadGMdb(void) { + if (!char_session) + return -1; - WFIFOW(char_session, 0) = 0x2af7; - WFIFOSET(char_session, 2); + Packet_Fixed<0x2af7> fixed_f7; + send_fpacket<0x2af7, 2>(char_session, fixed_f7); return 0; } @@ -939,7 +937,7 @@ int chrif_reloadGMdb(void) */ static -void ladmin_itemfrob_fix_item(int source, int dest, struct item *item) +void ladmin_itemfrob_fix_item(ItemNameId source, ItemNameId dest, Item *item) { if (item && item->nameid == source) { @@ -949,7 +947,7 @@ void ladmin_itemfrob_fix_item(int source, int dest, struct item *item) } static -void ladmin_itemfrob_c2(dumb_ptr<block_list> bl, int source_id, int dest_id) +void ladmin_itemfrob_c2(dumb_ptr<block_list> bl, ItemNameId source_id, ItemNameId dest_id) { #define IFIX(v) if (v == source_id) {v = dest_id; } #define FIX(item) ladmin_itemfrob_fix_item(source_id, dest_id, &item) @@ -962,10 +960,9 @@ void ladmin_itemfrob_c2(dumb_ptr<block_list> bl, int source_id, int dest_id) case BL::PC: { dumb_ptr<map_session_data> pc = bl->is_player(); - struct storage *stor = account2storage2(pc->status_key.account_id); - int j; + Storage *stor = account2storage2(pc->status_key.account_id); - for (j = 0; j < MAX_INVENTORY; j++) + for (IOff0 j : IOff0::iter()) IFIX(pc->status.inventory[j].nameid); // cart is no longer supported // IFIX(pc->status.weapon); @@ -975,10 +972,12 @@ void ladmin_itemfrob_c2(dumb_ptr<block_list> bl, int source_id, int dest_id) IFIX(pc->status.head_bottom); if (stor) - for (j = 0; j < stor->storage_amount; j++) + { + for (SOff0 j : SOff0::iter()) FIX(stor->storage_[j]); + } - for (j = 0; j < MAX_INVENTORY; j++) + for (IOff0 j : IOff0::iter()) { struct item_data *item = pc->inventory_data[j]; if (item && item->nameid == source_id) @@ -996,7 +995,7 @@ void ladmin_itemfrob_c2(dumb_ptr<block_list> bl, int source_id, int dest_id) case BL::MOB: { dumb_ptr<mob_data> mob = bl->is_mob(); - for (struct item& itm : mob->lootitemv) + for (Item& itm : mob->lootitemv) FIX(itm); break; } @@ -1013,16 +1012,16 @@ void ladmin_itemfrob_c2(dumb_ptr<block_list> bl, int source_id, int dest_id) } static -void ladmin_itemfrob_c(dumb_ptr<block_list> bl, int source_id, int dest_id) +void ladmin_itemfrob_c(dumb_ptr<block_list> bl, ItemNameId source_id, ItemNameId dest_id) { ladmin_itemfrob_c2(bl, source_id, dest_id); } static -void ladmin_itemfrob(Session *s) +void ladmin_itemfrob(Session *, const Packet_Fixed<0x2afa>& fixed) { - int source_id = RFIFOL(s, 2); - int dest_id = RFIFOL(s, 6); + ItemNameId source_id = fixed.source_item_id; + ItemNameId dest_id = fixed.dest_item_id; dumb_ptr<block_list> bl = map_get_first_session(); // flooritems @@ -1041,7 +1040,7 @@ static void chrif_delete(Session *s) { assert (s == char_session); - PRINTF("Map-server can't connect to char-server (connection #%d).\n", + PRINTF("Map-server can't connect to char-server (connection #%d).\n"_fmt, s); char_session = nullptr; } @@ -1053,121 +1052,213 @@ void chrif_delete(Session *s) static void chrif_parse(Session *s) { - int packet_len, cmd; - - // only char-server can have an access to here. - // so, if it isn't the char-server, we disconnect the session (fd != char_fd). - if (s != char_session) - { - s->set_eof(); - return; - } + assert (s == char_session); - while (RFIFOREST(s) >= 2) + RecvResult rv = RecvResult::Complete; + uint16_t packet_id; + while (rv == RecvResult::Complete && packet_peek_id(s, &packet_id)) { - cmd = RFIFOW(s, 0); - if (cmd < 0x2af8 - || cmd >= - 0x2af8 + - (sizeof(packet_len_table) / sizeof(packet_len_table[0])) - || packet_len_table[cmd - 0x2af8] == 0) - { - - int r = intif_parse(s); // intifに渡す - - if (r == 1) - continue; // intifで処理した - if (r == 2) - return; // intifで処理したが、データが足りない - - s->set_eof(); - return; - } - packet_len = packet_len_table[cmd - 0x2af8]; - if (packet_len == -1) - { - if (RFIFOREST(s) < 4) - return; - packet_len = RFIFOW(s, 2); - } - if (RFIFOREST(s) < packet_len) - return; - - switch (cmd) + switch (packet_id) { case 0x2af9: - chrif_connectack(s); + { + Packet_Fixed<0x2af9> fixed; + rv = recv_fpacket<0x2af9, 3>(s, fixed); + if (rv != RecvResult::Complete) + break; + + chrif_connectack(s, fixed); break; + } case 0x2afa: - ladmin_itemfrob(s); + { + Packet_Fixed<0x2afa> fixed; + rv = recv_fpacket<0x2afa, 10>(s, fixed); + if (rv != RecvResult::Complete) + break; + + ladmin_itemfrob(s, fixed); break; + } case 0x2afb: - chrif_sendmapack(s); + { + Packet_Fixed<0x2afb> fixed; + rv = recv_fpacket<0x2afb, 27>(s, fixed); + if (rv != RecvResult::Complete) + break; + + chrif_sendmapack(s, fixed); break; + } case 0x2afd: { - int id = RFIFOL(s, 4); - int login_id2 = RFIFOL(s, 8); - TimeT connect_until_time = static_cast<time_t>(RFIFOL(s, 12)); - short tmw_version = RFIFOW(s, 16); - CharKey st_key; - CharData st_data; - RFIFO_STRUCT(s, 18, st_key); - RFIFO_STRUCT(s, 18 + sizeof(st_key), st_data); + Packet_Payload<0x2afd> payload; + rv = recv_ppacket<0x2afd>(s, payload); + if (rv != RecvResult::Complete) + break; + + AccountId id = payload.account_id; + int login_id2 = payload.login_id2; + TimeT connect_until_time = payload.connect_until; + short tmw_version = payload.packet_tmw_version; + CharKey st_key = payload.char_key; + CharData st_data = payload.char_data; pc_authok(id, login_id2, connect_until_time, tmw_version, &st_key, &st_data); - } break; + } case 0x2afe: - pc_authfail(RFIFOL(s, 2)); + { + Packet_Fixed<0x2afe> fixed; + rv = recv_fpacket<0x2afe, 6>(s, fixed); + if (rv != RecvResult::Complete) + break; + + pc_authfail(fixed.account_id); break; + } case 0x2b00: - map_setusers(RFIFOL(s, 2)); + { + Packet_Fixed<0x2b00> fixed; + rv = recv_fpacket<0x2b00, 6>(s, fixed); + if (rv != RecvResult::Complete) + break; + + map_setusers(fixed.users); break; + } case 0x2b03: - clif_charselectok(RFIFOL(s, 2)); + { + Packet_Fixed<0x2b03> fixed; + rv = recv_fpacket<0x2b03, 7>(s, fixed); + if (rv != RecvResult::Complete) + break; + + clif_charselectok(account_to_block(fixed.account_id)); break; + } case 0x2b04: - chrif_recvmap(s); + { + Packet_Head<0x2b04> head; + std::vector<Packet_Repeat<0x2b04>> repeat; + rv = recv_vpacket<0x2b04, 10, 16>(s, head, repeat); + if (rv != RecvResult::Complete) + break; + + chrif_recvmap(s, head, repeat); break; + } case 0x2b06: - chrif_changemapserverack(s); + { + Packet_Fixed<0x2b06> fixed; + rv = recv_fpacket<0x2b06, 44>(s, fixed); + if (rv != RecvResult::Complete) + break; + + chrif_changemapserverack(s, fixed); break; + } case 0x2b0b: - chrif_changedgm(s); + { + Packet_Fixed<0x2b0b> fixed; + rv = recv_fpacket<0x2b0b, 10>(s, fixed); + if (rv != RecvResult::Complete) + break; + + chrif_changedgm(s, fixed); break; + } case 0x2b0d: - chrif_changedsex(s); + { + Packet_Fixed<0x2b0d> fixed; + rv = recv_fpacket<0x2b0d, 7>(s, fixed); + if (rv != RecvResult::Complete) + break; + + chrif_changedsex(s, fixed); break; + } case 0x2b0f: - chrif_char_ask_name_answer(s); + { + Packet_Fixed<0x2b0f> fixed; + rv = recv_fpacket<0x2b0f, 34>(s, fixed); + if (rv != RecvResult::Complete) + break; + + chrif_char_ask_name_answer(s, fixed); break; + } case 0x2b11: - chrif_accountreg2(s); + { + Packet_Head<0x2b11> head; + std::vector<Packet_Repeat<0x2b11>> repeat; + rv = recv_vpacket<0x2b11, 8, 36>(s, head, repeat); + if (rv != RecvResult::Complete) + break; + + chrif_accountreg2(s, head, repeat); break; + } case 0x2b12: - chrif_divorce(RFIFOL(s, 2), RFIFOL(s, 6)); + { + Packet_Fixed<0x2b12> fixed; + rv = recv_fpacket<0x2b12, 10>(s, fixed); + if (rv != RecvResult::Complete) + break; + + chrif_divorce(fixed.char_id, fixed.partner_id); break; + } case 0x2b13: - chrif_accountdeletion(s); + { + Packet_Fixed<0x2b13> fixed; + rv = recv_fpacket<0x2b13, 6>(s, fixed); + if (rv != RecvResult::Complete) + break; + + chrif_accountdeletion(s, fixed); break; + } case 0x2b14: - chrif_accountban(s); + { + Packet_Fixed<0x2b14> fixed; + rv = recv_fpacket<0x2b14, 11>(s, fixed); + if (rv != RecvResult::Complete) + break; + + chrif_accountban(s, fixed); break; + } case 0x2b15: - chrif_recvgmaccounts(s); - break; + { + std::vector<Packet_Repeat<0x2b15>> repeat; + rv = recv_packet_repeatonly<0x2b15, 4, 5>(s, repeat); + if (rv != RecvResult::Complete) + break; + chrif_recvgmaccounts(s, repeat); + break; + } default: + { + RecvResult r = intif_parse(s, packet_id); + + if (r == RecvResult::Complete) + break; + if (r == RecvResult::Incomplete) + return; + if (battle_config.error_log) - PRINTF("chrif_parse : unknown packet %d %d\n", s, - RFIFOW(s, 0)); + PRINTF("chrif_parse : unknown packet %d %d\n"_fmt, s, + packet_id); s->set_eof(); return; + } } - RFIFOSKIP(s, packet_len); } + if (rv == RecvResult::Error) + s->set_eof(); } /*========================================== @@ -1178,12 +1269,11 @@ void chrif_parse(Session *s) static void send_users_tochar(TimerData *, tick_t) { - int users = 0; - if (!char_session) return; - WFIFOW(char_session, 0) = 0x2aff; + Packet_Head<0x2aff> head_ff; + std::vector<Packet_Repeat<0x2aff>> repeat_ff; for (io::FD i : iter_fds()) { Session *s = get_session(i); @@ -1195,13 +1285,13 @@ void send_users_tochar(TimerData *, tick_t) || sd->state.shroud_active || bool(sd->status.option & Option::HIDE)) && pc_isGM(sd))) { - WFIFOL(char_session, 6 + 4 * users) = sd->status_key.char_id; - users++; + Packet_Repeat<0x2aff> info; + info.char_id = sd->status_key.char_id; + repeat_ff.push_back(info); } } - WFIFOW(char_session, 2) = 6 + 4 * users; - WFIFOW(char_session, 4) = users; - WFIFOSET(char_session, 6 + 4 * users); + head_ff.users = repeat_ff.size(); + send_vpacket<0x2aff, 6, 4>(char_session, head_ff, repeat_ff); } /*========================================== @@ -1214,10 +1304,10 @@ void check_connect_char_server(TimerData *, tick_t) { if (!char_session) { - PRINTF("Attempt to connect to char-server...\n"); + PRINTF("Attempt to connect to char-server...\n"_fmt); chrif_state = 0; char_session = make_connection(char_ip, char_port, - SessionParsers{func_parse: chrif_parse, func_delete: chrif_delete}); + SessionParsers{.func_parse= chrif_parse, .func_delete= chrif_delete}); if (!char_session) return; realloc_fifo(char_session, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); @@ -1232,12 +1322,13 @@ void check_connect_char_server(TimerData *, tick_t) */ void do_init_chrif(void) { - Timer(gettick() + std::chrono::seconds(1), + Timer(gettick() + 1_s, check_connect_char_server, - std::chrono::seconds(10) + 10_s ).detach(); - Timer(gettick() + std::chrono::seconds(1), + Timer(gettick() + 1_s, send_users_tochar, - std::chrono::seconds(5) + 5_s ).detach(); } +} // namespace tmwa diff --git a/src/map/chrif.hpp b/src/map/chrif.hpp index afeba75..4711bc5 100644 --- a/src/map/chrif.hpp +++ b/src/map/chrif.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_CHRIF_HPP -#define TMWA_MAP_CHRIF_HPP +#pragma once // chrif.hpp - Network interface to the character server. // // Copyright © ????-2004 Athena Dev Teams @@ -21,16 +20,19 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "../strings/fwd.hpp" +#include "../strings/fwd.hpp" -# include "../mmo/dumb_ptr.hpp" -# include "../mmo/human_time_diff.hpp" -# include "../mmo/ip.hpp" +#include "../generic/fwd.hpp" -# include "map.hpp" +#include "../net/fwd.hpp" +#include "../mmo/fwd.hpp" + + +namespace tmwa +{ void chrif_setuserid(AccountName); void chrif_setpasswd(AccountPass); AccountPass chrif_getpasswd(void); @@ -48,18 +50,17 @@ int chrif_changemapserver(dumb_ptr<map_session_data> sd, MapName name, int x, int y, IP4Address ip, short port); -void chrif_changegm(int id, ZString pass); -void chrif_changeemail(int id, AccountEmail actual_email, AccountEmail new_email); -void chrif_char_ask_name(int id, CharName character_name, short operation_type, +void chrif_changegm(AccountId id, ZString pass); +void chrif_changeemail(AccountId id, AccountEmail actual_email, AccountEmail new_email); +void chrif_char_ask_name(AccountId id, CharName character_name, short operation_type, HumanTimeDiff modif); int chrif_saveaccountreg2(dumb_ptr<map_session_data> sd); int chrif_reloadGMdb(void); -int chrif_send_divorce(int char_id); +int chrif_send_divorce(CharId char_id); void do_init_chrif(void); // only used by intif.cpp // and clif.cpp for the new on_delete stuff ... extern Session *char_session; - -#endif // TMWA_MAP_CHRIF_HPP +} // namespace tmwa diff --git a/src/map/clif.cpp b/src/map/clif.cpp index eb008e4..fb4041c 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -20,29 +20,36 @@ // 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 <arpa/inet.h> - -#include <cstdlib> -#include <cstring> +#include <cassert> #include <ctime> -#include "../compat/alg.hpp" +#include <algorithm> + #include "../compat/attr.hpp" #include "../compat/fun.hpp" #include "../compat/nullpo.hpp" +#include "../ints/cmp.hpp" + #include "../strings/astring.hpp" #include "../strings/zstring.hpp" #include "../strings/xstring.hpp" -#include "../generic/random.hpp" - #include "../io/cxxstdio.hpp" +#include "../io/cxxstdio_enums.hpp" #include "../io/write.hpp" +#include "../net/ip.hpp" +#include "../net/packets.hpp" +#include "../net/socket.hpp" +#include "../net/timer.hpp" + +#include "../proto2/any-user.hpp" +#include "../proto2/char-map.hpp" +#include "../proto2/map-user.hpp" + #include "../mmo/md5more.hpp" -#include "../mmo/socket.hpp" -#include "../mmo/timer.hpp" +#include "../mmo/utils.hpp" #include "../mmo/version.hpp" #include "atcommand.hpp" @@ -51,6 +58,7 @@ #include "intif.hpp" #include "itemdb.hpp" #include "magic.hpp" +#include "magic-stmt.hpp" #include "map.hpp" #include "npc.hpp" #include "party.hpp" @@ -62,8 +70,9 @@ #include "../poison.hpp" -#define DUMP_UNKNOWN_PACKET 1 +namespace tmwa +{ constexpr int EMOTE_IGNORED = 0x0e; // functions list. Rate is how many milliseconds are required between @@ -71,20 +80,20 @@ constexpr int EMOTE_IGNORED = 0x0e; // map.h must be the same length as this table. rate 0 is default // rate -1 is unlimited -typedef void (*clif_func)(Session *s, dumb_ptr<map_session_data> sd); +typedef RecvResult (*clif_func)(Session *s, dumb_ptr<map_session_data> sd); struct func_table { interval_t rate; - int len; + uint16_t len_unused; clif_func func; // ctor exists because interval_t must be explicit - func_table(int r, int l, clif_func f) - : rate(r), len(l), func(f) + func_table(int r, uint16_t l, clif_func f) + : rate(r), len_unused(l), func(f) {} }; -constexpr int VAR = -1; +constexpr uint16_t VAR = 1; extern // not really - defined below func_table clif_parse_func_table[0x0220]; @@ -107,36 +116,6 @@ enum class SendWho SELF, }; -inline -void WBUFPOS(uint8_t *p, size_t pos, uint16_t x, uint16_t y) -{ - p += pos; - p[0] = x >> 2; - p[1] = (x << 6) | ((y >> 4) & 0x3f); - p[2] = y << 4; -} -inline -void WBUFPOS2(uint8_t *p, size_t pos, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) -{ - p += pos; - p[0] = x0 >> 2; - p[1] = (x0 << 6) | ((y0 >> 4) & 0x3f); - p[2] = (y0 << 4) | ((x1 >> 6) & 0x0f); - p[3] = (x1 << 2) | ((y1 >> 8) & 0x03); - p[4] = y1; -} - -inline -void WFIFOPOS(Session *s, size_t pos, uint16_t x, uint16_t y) -{ - WBUFPOS(static_cast<uint8_t *>(WFIFOP(s, pos)), 0, x, y); -} -inline -void WFIFOPOS2(Session *s, size_t pos, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) -{ - WBUFPOS2(static_cast<uint8_t *>(WFIFOP(s, pos)), 0, x0, y0, x1, y1); -} - static IP4Address map_ip; static @@ -159,11 +138,11 @@ void clif_delete(Session *s) pc_logout(sd); clif_quitsave(s, sd); - PRINTF("Player [%s] has logged off your server.\n", sd->status_key.name); // Player logout display [Valaris] + PRINTF("Player [%s] has logged off your server.\n"_fmt, sd->status_key.name); // Player logout display [Valaris] } else if (sd) { // not authentified! (refused by char-server or disconnect before to be authentified) - PRINTF("Player with account [%d] has logged off your server (not auth account).\n", sd->bl_id); // Player logout display [Yor] + PRINTF("Player with account [%d] has logged off your server (not auth account).\n"_fmt, sd->bl_id); // Player logout display [Yor] map_deliddb(sd); // account_id has been included in the DB before auth answer } } @@ -265,14 +244,14 @@ enum class ChatType }; static -AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type); +AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type, XString buf); /*========================================== * clif_sendでSendWho::AREA*指定時用 *------------------------------------------ */ static -void clif_send_sub(dumb_ptr<block_list> bl, const unsigned char *buf, int len, +void clif_send_sub(dumb_ptr<block_list> bl, const Buffer& buf, dumb_ptr<block_list> src_bl, SendWho type) { nullpo_retv(bl); @@ -299,14 +278,11 @@ void clif_send_sub(dumb_ptr<block_list> bl, const unsigned char *buf, int len, break; } - if (sd->sess != NULL) + if (sd->sess != nullptr) { { - if (clif_parse_func_table[RBUFW(buf, 0)].len) { - // packet must exist - WFIFO_BUF_CLONE(sd->sess, buf, len); - WFIFOSET(sd->sess, len); + send_buffer(sd->sess, buf); } } } @@ -317,14 +293,14 @@ void clif_send_sub(dumb_ptr<block_list> bl, const unsigned char *buf, int len, *------------------------------------------ */ static -int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type) +int clif_send(const Buffer& buf, dumb_ptr<block_list> bl, SendWho type) { - struct party *p = NULL; + PartyPair p; int x0 = 0, x1 = 0, y0 = 0, y1 = 0; if (type != SendWho::ALL_CLIENT) { - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::PC) { @@ -360,11 +336,8 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s->session_data.get())); if (sd && sd->state.auth) { - if (clif_parse_func_table[RBUFW(buf, 0)].len) { - // packet must exist - WFIFO_BUF_CLONE(s, buf, len); - WFIFOSET(s, len); + send_buffer(s, buf); } } } @@ -378,25 +351,22 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s->session_data.get())); if (sd && sd->state.auth && sd->bl_m == bl->bl_m) { - if (clif_parse_func_table[RBUFW(buf, 0)].len) { - // packet must exist - WFIFO_BUF_CLONE(s, buf, len); - WFIFOSET(s, len); + send_buffer(s, buf); } } } break; case SendWho::AREA: case SendWho::AREA_WOS: - map_foreachinarea(std::bind(clif_send_sub, ph::_1, buf, len, bl, type), + map_foreachinarea(std::bind(clif_send_sub, ph::_1, buf, bl, type), bl->bl_m, bl->bl_x - AREA_SIZE, bl->bl_y - AREA_SIZE, bl->bl_x + AREA_SIZE, bl->bl_y + AREA_SIZE, BL::PC); break; case SendWho::AREA_CHAT_WOC: - map_foreachinarea(std::bind(clif_send_sub, ph::_1, buf, len, bl, SendWho::AREA_CHAT_WOC), + map_foreachinarea(std::bind(clif_send_sub, ph::_1, buf, bl, SendWho::AREA_CHAT_WOC), bl->bl_m, bl->bl_x - (AREA_SIZE), bl->bl_y - (AREA_SIZE), bl->bl_x + (AREA_SIZE), bl->bl_y + (AREA_SIZE), @@ -417,13 +387,13 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type if (bl->bl_type == BL::PC) { dumb_ptr<map_session_data> sd = bl->is_player(); - if (sd->partyspy > 0) + if (sd->partyspy) { p = party_search(sd->partyspy); } else { - if (sd->status.party_id > 0) + if (sd->status.party_id) p = party_search(sd->status.party_id); } } @@ -444,11 +414,8 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type (sd->bl_x < x0 || sd->bl_y < y0 || sd->bl_x > x1 || sd->bl_y > y1)) continue; - if (clif_parse_func_table[RBUFW(buf, 0)].len) { - // packet must exist - WFIFO_BUF_CLONE(sd->sess, buf, len); - WFIFOSET(sd->sess, len); + send_buffer(sd->sess, buf); } } } @@ -460,13 +427,10 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s->session_data.get())); if (sd && sd->state.auth) { - if (sd->partyspy == p->party_id) + if (sd->partyspy == p.party_id) { - if (clif_parse_func_table[RBUFW(buf, 0)].len) { - // packet must exist - WFIFO_BUF_CLONE(sd->sess, buf, len); - WFIFOSET(sd->sess, len); + send_buffer(sd->sess, buf); } } } @@ -476,18 +440,16 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type case SendWho::SELF: { dumb_ptr<map_session_data> sd = bl->is_player(); - if (clif_parse_func_table[RBUFW(buf, 0)].len) + { - // packet must exist - WFIFO_BUF_CLONE(sd->sess, buf, len); - WFIFOSET(sd->sess, len); + send_buffer(sd->sess, buf); } } break; default: if (battle_config.error_log) - PRINTF("clif_send まだ作ってないよー\n"); + PRINTF("clif_send まだ作ってないよー\n"_fmt); return -1; } @@ -503,7 +465,7 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type */ int clif_authok(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); if (!sd) return 0; @@ -513,12 +475,12 @@ int clif_authok(dumb_ptr<map_session_data> sd) Session *s = sd->sess; - WFIFOW(s, 0) = 0x73; - WFIFOL(s, 2) = gettick().time_since_epoch().count(); - WFIFOPOS(s, 6, sd->bl_x, sd->bl_y); - WFIFOB(s, 9) = 5; - WFIFOB(s, 10) = 5; - WFIFOSET(s, clif_parse_func_table[0x73].len); + Packet_Fixed<0x0073> fixed_73; + fixed_73.tick = gettick(); + fixed_73.pos = Position1{static_cast<uint16_t>(sd->bl_x), static_cast<uint16_t>(sd->bl_y), DIR::S}; + fixed_73.five1 = 5; + fixed_73.five2 = 5; + send_fpacket<0x0073, 11>(s, fixed_73); return 0; } @@ -532,9 +494,9 @@ int clif_authfail_fd(Session *s, int type) if (!s) return 0; - WFIFOW(s, 0) = 0x81; - WFIFOL(s, 2) = type; - WFIFOSET(s, clif_parse_func_table[0x81].len); + Packet_Fixed<0x0081> fixed_81; + fixed_81.error_code = type; + send_fpacket<0x0081, 3>(s, fixed_81); clif_setwaitclose(s); @@ -545,20 +507,20 @@ int clif_authfail_fd(Session *s, int type) * *------------------------------------------ */ -int clif_charselectok(int id) +int clif_charselectok(BlockId id) { dumb_ptr<map_session_data> sd; - if ((sd = map_id2sd(id)) == NULL) + if ((sd = map_id2sd(id)) == nullptr) return 1; if (!sd->sess) return 1; Session *s = sd->sess; - WFIFOW(s, 0) = 0xb3; - WFIFOB(s, 2) = 1; - WFIFOSET(s, clif_parse_func_table[0xb3].len); + Packet_Fixed<0x00b3> fixed_b3; + fixed_b3.one = 1; + send_fpacket<0x00b3, 3>(s, fixed_b3); return 0; } @@ -568,22 +530,21 @@ int clif_charselectok(int id) *------------------------------------------ */ static -int clif_set009e(dumb_ptr<flooritem_data> fitem, uint8_t *buf) +void clif_set009e(dumb_ptr<flooritem_data> fitem, Buffer& buf) { - nullpo_ret(fitem); + nullpo_retv(fitem); - //009e <ID>.l <name ID>.w <identify flag>.B <X>.w <Y>.w <subX>.B <subY>.B <amount>.w - WBUFW(buf, 0) = 0x9e; - WBUFL(buf, 2) = fitem->bl_id; - WBUFW(buf, 6) = fitem->item_data.nameid; - WBUFB(buf, 8) = 1; //identify; - WBUFW(buf, 9) = fitem->bl_x; - WBUFW(buf, 11) = fitem->bl_y; - WBUFB(buf, 13) = fitem->subx; - WBUFB(buf, 14) = fitem->suby; - WBUFW(buf, 15) = fitem->item_data.amount; + Packet_Fixed<0x009e> fixed_9e; + fixed_9e.block_id = fitem->bl_id; + fixed_9e.name_id = fitem->item_data.nameid; + fixed_9e.identify = 1; + fixed_9e.x = fitem->bl_x; + fixed_9e.y = fitem->bl_y; + fixed_9e.subx = fitem->subx; + fixed_9e.suby = fitem->suby; + fixed_9e.amount = fitem->item_data.amount; - return clif_parse_func_table[0x9e].len; + buf = create_fpacket<0x009e, 17>(fixed_9e); } /*========================================== @@ -592,14 +553,14 @@ int clif_set009e(dumb_ptr<flooritem_data> fitem, uint8_t *buf) */ int clif_dropflooritem(dumb_ptr<flooritem_data> fitem) { - uint8_t buf[64]; + nullpo_retz(fitem); - nullpo_ret(fitem); - - if (fitem->item_data.nameid <= 0) + if (!fitem->item_data.nameid) return 0; + + Buffer buf; clif_set009e(fitem, buf); - clif_send(buf, clif_parse_func_table[0x9e].len, fitem, SendWho::AREA); + clif_send(buf, fitem, SendWho::AREA); return 0; } @@ -610,21 +571,19 @@ int clif_dropflooritem(dumb_ptr<flooritem_data> fitem) */ int clif_clearflooritem(dumb_ptr<flooritem_data> fitem, Session *s) { - unsigned char buf[16]; - - nullpo_ret(fitem); + nullpo_retz(fitem); - WBUFW(buf, 0) = 0xa1; - WBUFL(buf, 2) = fitem->bl_id; + Packet_Fixed<0x00a1> fixed_a1; + fixed_a1.block_id = fitem->bl_id; if (!s) { - clif_send(buf, clif_parse_func_table[0xa1].len, fitem, SendWho::AREA); + Buffer buf = create_fpacket<0x00a1, 6>(fixed_a1); + clif_send(buf, fitem, SendWho::AREA); } else { - WFIFO_BUF_CLONE(s, buf, 6); - WFIFOSET(s, clif_parse_func_table[0xa1].len); + send_fpacket<0x00a1, 6>(s, fixed_a1); } return 0; @@ -636,21 +595,22 @@ int clif_clearflooritem(dumb_ptr<flooritem_data> fitem, Session *s) */ int clif_clearchar(dumb_ptr<block_list> bl, BeingRemoveWhy type) { - unsigned char buf[16]; + nullpo_retz(bl); - nullpo_ret(bl); + Packet_Fixed<0x0080> fixed_80; + fixed_80.block_id = bl->bl_id; - WBUFW(buf, 0) = 0x80; - WBUFL(buf, 2) = bl->bl_id; if (type == BeingRemoveWhy::DISGUISE) { - WBUFB(buf, 6) = static_cast<uint8_t>(BeingRemoveWhy::GONE); - clif_send(buf, clif_parse_func_table[0x80].len, bl, SendWho::AREA); + fixed_80.type = BeingRemoveWhy::GONE; + Buffer buf = create_fpacket<0x0080, 7>(fixed_80); + clif_send(buf, bl, SendWho::AREA); } else { - WBUFB(buf, 6) = static_cast<uint8_t>(type); - clif_send(buf, clif_parse_func_table[0x80].len, bl, + fixed_80.type = type; + Buffer buf = create_fpacket<0x0080, 7>(fixed_80); + clif_send(buf, bl, type == BeingRemoveWhy::DEAD ? SendWho::AREA : SendWho::AREA_WOS); } @@ -692,12 +652,12 @@ int clif_clearchar_delay(tick_t tick, * *------------------------------------------ */ -void clif_clearchar_id(int id, BeingRemoveWhy type, Session *s) +void clif_clearchar_id(BlockId id, BeingRemoveWhy type, Session *s) { - WFIFOW(s, 0) = 0x80; - WFIFOL(s, 2) = id; - WFIFOB(s, 6) = static_cast<uint8_t>(type); - WFIFOSET(s, clif_parse_func_table[0x80].len); + Packet_Fixed<0x0080> fixed_80; + fixed_80.block_id = id; + fixed_80.type = type; + send_fpacket<0x0080, 7>(s, fixed_80); } /*========================================== @@ -705,59 +665,111 @@ void clif_clearchar_id(int id, BeingRemoveWhy type, Session *s) *------------------------------------------ */ static -int clif_set0078(dumb_ptr<map_session_data> sd, unsigned char *buf) +void clif_set0078_main_1d8(dumb_ptr<map_session_data> sd, Buffer& buf) { - nullpo_ret(sd); + nullpo_retv(sd); - WBUFW(buf, 0) = 0x1d8; - WBUFL(buf, 2) = sd->bl_id; - WBUFW(buf, 6) = static_cast<uint16_t>(sd->speed.count()); - WBUFW(buf, 8) = static_cast<uint16_t>(sd->opt1); - WBUFW(buf, 10) = static_cast<uint16_t>(sd->opt2); - WBUFW(buf, 12) = static_cast<uint16_t>(sd->status.option); - WBUFW(buf, 14) = sd->status.species; - WBUFW(buf, 16) = sd->status.hair; + Packet_Fixed<0x01d8> fixed_1d8; + fixed_1d8.block_id = sd->bl_id; + fixed_1d8.speed = sd->speed; + fixed_1d8.opt1 = sd->opt1; + fixed_1d8.opt2 = sd->opt2; + fixed_1d8.option = sd->status.option; + fixed_1d8.species = sd->status.species; + fixed_1d8.hair_style = sd->status.hair; + + IOff0 widx = sd->equip_index_maybe[EQUIP::WEAPON]; + IOff0 sidx = sd->equip_index_maybe[EQUIP::SHIELD]; + if (sd->attack_spell_override) + fixed_1d8.weapon = sd->attack_spell_look_override; + else + { + if (widx.ok() && sd->inventory_data[widx]) + { + fixed_1d8.weapon = sd->status.inventory[widx].nameid; + } + else + fixed_1d8.weapon = ItemNameId(); + } + if (sidx.ok() && sidx != widx && sd->inventory_data[sidx]) + { + fixed_1d8.shield = sd->status.inventory[sidx].nameid; + } + else + fixed_1d8.shield = ItemNameId(); + fixed_1d8.head_bottom = sd->status.head_bottom; + fixed_1d8.head_top = sd->status.head_top; + fixed_1d8.head_mid = sd->status.head_mid; + fixed_1d8.hair_color = sd->status.hair_color; + fixed_1d8.clothes_color = sd->status.clothes_color; + fixed_1d8.head_dir = sd->head_dir; + fixed_1d8.guild_id = 0; + fixed_1d8.guild_emblem_id = 0; + fixed_1d8.manner = sd->status.manner; + fixed_1d8.opt3 = sd->opt3; + fixed_1d8.karma = sd->status.karma; + fixed_1d8.sex = sd->sex; + fixed_1d8.pos.x = sd->bl_x; + fixed_1d8.pos.y = sd->bl_y; + fixed_1d8.pos.dir = sd->dir; + fixed_1d8.gm_bits = pc_isGM(sd).get_public_word(); + fixed_1d8.dead_sit = sd->state.dead_sit; + fixed_1d8.unused = 0; + + buf = create_fpacket<0x01d8, 54>(fixed_1d8); +} +static +void clif_set0078_alt_1d9(dumb_ptr<map_session_data> sd, Buffer& buf) +{ + nullpo_retv(sd); - int widx = sd->equip_index_maybe[EQUIP::WEAPON]; - int sidx = sd->equip_index_maybe[EQUIP::SHIELD]; + Packet_Fixed<0x01d9> fixed_1d8; // LIES + fixed_1d8.block_id = sd->bl_id; + fixed_1d8.speed = sd->speed; + fixed_1d8.opt1 = sd->opt1; + fixed_1d8.opt2 = sd->opt2; + fixed_1d8.option = sd->status.option; + fixed_1d8.species = sd->status.species; + fixed_1d8.hair_style = sd->status.hair; + + IOff0 widx = sd->equip_index_maybe[EQUIP::WEAPON]; + IOff0 sidx = sd->equip_index_maybe[EQUIP::SHIELD]; if (sd->attack_spell_override) - WBUFW(buf, 18) = sd->attack_spell_look_override; + fixed_1d8.weapon = sd->attack_spell_look_override; else { - if (widx >= 0 && sd->inventory_data[widx]) + if (widx.ok() && sd->inventory_data[widx]) { - WBUFW(buf, 18) = sd->status.inventory[widx].nameid; + fixed_1d8.weapon = sd->status.inventory[widx].nameid; } else - WBUFW(buf, 18) = 0; + fixed_1d8.weapon = ItemNameId(); } - if (sidx >= 0 && sidx != widx && sd->inventory_data[sidx]) + if (sidx.ok() && sidx != widx && sd->inventory_data[sidx]) { - WBUFW(buf, 20) = sd->status.inventory[sidx].nameid; + fixed_1d8.shield = sd->status.inventory[sidx].nameid; } else - WBUFW(buf, 20) = 0; - WBUFW(buf, 22) = sd->status.head_bottom; - WBUFW(buf, 24) = sd->status.head_top; - WBUFW(buf, 26) = sd->status.head_mid; - WBUFW(buf, 28) = sd->status.hair_color; - WBUFW(buf, 30) = sd->status.clothes_color; - WBUFW(buf, 32) = static_cast<uint8_t>(sd->head_dir); - WBUFL(buf, 34) = 0 /*guild_id*/; - WBUFW(buf, 38) = 0 /*guild_emblem_id*/; - WBUFW(buf, 40) = sd->status.manner; - WBUFW(buf, 42) = static_cast<uint16_t>(sd->opt3); - WBUFB(buf, 44) = sd->status.karma; - WBUFB(buf, 45) = static_cast<uint8_t>(sd->sex); - WBUFPOS(buf, 46, sd->bl_x, sd->bl_y); - // work around ICE in gcc 4.6 - uint8_t dir = static_cast<uint8_t>(sd->dir); - WBUFB(buf, 48) |= dir; - WBUFW(buf, 49) = (pc_isGM(sd) == 60 || pc_isGM(sd) == 99) ? 0x80 : 0; - WBUFB(buf, 51) = sd->state.dead_sit; - WBUFW(buf, 52) = 0; - - return clif_parse_func_table[0x1d8].len; + fixed_1d8.shield = ItemNameId(); + fixed_1d8.head_bottom = sd->status.head_bottom; + fixed_1d8.head_top = sd->status.head_top; + fixed_1d8.head_mid = sd->status.head_mid; + fixed_1d8.hair_color = sd->status.hair_color; + fixed_1d8.clothes_color = sd->status.clothes_color; + fixed_1d8.head_dir = sd->head_dir; + fixed_1d8.guild_id = 0; + fixed_1d8.guild_emblem_id = 0; + fixed_1d8.manner = sd->status.manner; + fixed_1d8.opt3 = sd->opt3; + fixed_1d8.karma = sd->status.karma; + fixed_1d8.sex = sd->sex; + fixed_1d8.pos.x = sd->bl_x; + fixed_1d8.pos.y = sd->bl_y; + fixed_1d8.pos.dir = sd->dir; + fixed_1d8.gm_bits = pc_isGM(sd).get_public_word(); + fixed_1d8.unused = 0; + + buf = create_fpacket<0x01d9, 53>(fixed_1d8); } /*========================================== @@ -765,51 +777,54 @@ int clif_set0078(dumb_ptr<map_session_data> sd, unsigned char *buf) *------------------------------------------ */ static -int clif_set007b(dumb_ptr<map_session_data> sd, unsigned char *buf) -{ - nullpo_ret(sd); - - WBUFW(buf, 0) = 0x1da; - WBUFL(buf, 2) = sd->bl_id; - WBUFW(buf, 6) = static_cast<uint16_t>(sd->speed.count()); - WBUFW(buf, 8) = static_cast<uint16_t>(sd->opt1); - WBUFW(buf, 10) = static_cast<uint16_t>(sd->opt2); - WBUFW(buf, 12) = static_cast<uint16_t>(sd->status.option); - WBUFW(buf, 14) = sd->status.species; - WBUFW(buf, 16) = sd->status.hair; - int widx = sd->equip_index_maybe[EQUIP::WEAPON]; - int sidx = sd->equip_index_maybe[EQUIP::SHIELD]; - if (widx >= 0 && sd->inventory_data[widx]) +void clif_set007b(dumb_ptr<map_session_data> sd, Buffer& buf) +{ + nullpo_retv(sd); + + Packet_Fixed<0x01da> fixed_1da; + fixed_1da.block_id = sd->bl_id; + fixed_1da.speed = sd->speed; + fixed_1da.opt1 = sd->opt1; + fixed_1da.opt2 = sd->opt2; + fixed_1da.option = sd->status.option; + fixed_1da.species = sd->status.species; + fixed_1da.hair_style = sd->status.hair; + IOff0 widx = sd->equip_index_maybe[EQUIP::WEAPON]; + IOff0 sidx = sd->equip_index_maybe[EQUIP::SHIELD]; + if (widx.ok() && sd->inventory_data[widx]) { - WBUFW(buf, 18) = sd->status.inventory[widx].nameid; + fixed_1da.weapon = sd->status.inventory[widx].nameid; } else - WBUFW(buf, 18) = 0; - if (sidx >= 0 && sidx != widx && sd->inventory_data[sidx]) + fixed_1da.weapon = ItemNameId(); + if (sidx.ok() && sidx != widx && sd->inventory_data[sidx]) { - WBUFW(buf, 20) = sd->status.inventory[sidx].nameid; + fixed_1da.shield = sd->status.inventory[sidx].nameid; } else - WBUFW(buf, 20) = 0; - WBUFW(buf, 22) = sd->status.head_bottom; - WBUFL(buf, 24) = gettick().time_since_epoch().count(); - WBUFW(buf, 28) = sd->status.head_top; - WBUFW(buf, 30) = sd->status.head_mid; - WBUFW(buf, 32) = sd->status.hair_color; - WBUFW(buf, 34) = sd->status.clothes_color; - WBUFW(buf, 36) = static_cast<uint8_t>(sd->head_dir); - WBUFL(buf, 38) = 0/*guild_id*/; - WBUFW(buf, 42) = 0/*guild_emblem_id*/; - WBUFW(buf, 44) = sd->status.manner; - WBUFW(buf, 46) = static_cast<uint16_t>(sd->opt3); - WBUFB(buf, 48) = sd->status.karma; - WBUFB(buf, 49) = static_cast<uint8_t>(sd->sex); - WBUFPOS2(buf, 50, sd->bl_x, sd->bl_y, sd->to_x, sd->to_y); - WBUFW(buf, 55) = pc_isGM(sd) == 60 ? 0x80 : 0; - WBUFB(buf, 57) = 5; - WBUFW(buf, 58) = 0; - - return clif_parse_func_table[0x1da].len; + fixed_1da.shield = ItemNameId(); + fixed_1da.head_bottom = sd->status.head_bottom; + fixed_1da.tick = gettick(); + fixed_1da.head_top = sd->status.head_top; + fixed_1da.head_mid = sd->status.head_mid; + fixed_1da.hair_color = sd->status.hair_color; + fixed_1da.clothes_color = sd->status.clothes_color; + fixed_1da.head_dir = sd->head_dir; + fixed_1da.guild_id = 0; + fixed_1da.guild_emblem_id = 0; + fixed_1da.manner = sd->status.manner; + fixed_1da.opt3 = sd->opt3; + fixed_1da.karma = sd->status.karma; + fixed_1da.sex = sd->sex; + fixed_1da.pos2.x0 = sd->bl_x; + fixed_1da.pos2.y0 = sd->bl_y; + fixed_1da.pos2.x1 = sd->to_x; + fixed_1da.pos2.y1 = sd->to_y; + fixed_1da.gm_bits = pc_isGM(sd).get_public_word(); + fixed_1da.five = 5; + fixed_1da.unused = 0; + + buf = create_fpacket<0x01da, 60>(fixed_1da); } /*========================================== @@ -817,30 +832,27 @@ int clif_set007b(dumb_ptr<map_session_data> sd, unsigned char *buf) *------------------------------------------ */ static -int clif_mob0078(dumb_ptr<mob_data> md, unsigned char *buf) +void clif_mob0078(dumb_ptr<mob_data> md, Buffer& buf) { - really_memset0(buf, clif_parse_func_table[0x78].len); - - nullpo_ret(md); + nullpo_retv(md); - WBUFW(buf, 0) = 0x78; - WBUFL(buf, 2) = md->bl_id; - WBUFW(buf, 6) = static_cast<uint16_t>(battle_get_speed(md).count()); - WBUFW(buf, 8) = static_cast<uint16_t>(md->opt1); - WBUFW(buf, 10) = static_cast<uint16_t>(md->opt2); - WBUFW(buf, 12) = static_cast<uint16_t>(md->option); - WBUFW(buf, 14) = md->mob_class; + Packet_Fixed<0x0078> fixed_78; + fixed_78.block_id = md->bl_id; + fixed_78.speed = battle_get_speed(md); + fixed_78.opt1 = md->opt1; + fixed_78.opt2 = md->opt2; + fixed_78.option = md->option; + fixed_78.species = md->mob_class; // snip: stuff do do with disguise as a PC - WBUFPOS(buf, 46, md->bl_x, md->bl_y); - // work around ICE in gcc 4.6 - uint8_t dir = static_cast<uint8_t>(md->dir); - WBUFB(buf, 48) |= dir; - WBUFB(buf, 49) = 5; - WBUFB(buf, 50) = 5; + fixed_78.pos.x = md->bl_x; + fixed_78.pos.y = md->bl_y; + fixed_78.pos.dir = md->dir; + fixed_78.five1 = 5; + fixed_78.five2 = 5; int level = battle_get_lv(md); - WBUFW(buf, 52) = (level > battle_config.max_lv) ? battle_config.max_lv : level; + fixed_78.level = (level > battle_config.max_lv) ? battle_config.max_lv : level; - return clif_parse_func_table[0x78].len; + buf = create_fpacket<0x0078, 54>(fixed_78); } /*========================================== @@ -848,29 +860,30 @@ int clif_mob0078(dumb_ptr<mob_data> md, unsigned char *buf) *------------------------------------------ */ static -int clif_mob007b(dumb_ptr<mob_data> md, unsigned char *buf) +void clif_mob007b(dumb_ptr<mob_data> md, Buffer& buf) { - really_memset0(buf, clif_parse_func_table[0x7b].len); - - nullpo_ret(md); + nullpo_retv(md); - WBUFW(buf, 0) = 0x7b; - WBUFL(buf, 2) = md->bl_id; - WBUFW(buf, 6) = static_cast<uint16_t>(battle_get_speed(md).count()); - WBUFW(buf, 8) = static_cast<uint16_t>(md->opt1); - WBUFW(buf, 10) = static_cast<uint16_t>(md->opt2); - WBUFW(buf, 12) = static_cast<uint16_t>(md->option); - WBUFW(buf, 14) = md->mob_class; + Packet_Fixed<0x007b> fixed_7b; + fixed_7b.block_id = md->bl_id; + fixed_7b.speed = battle_get_speed(md); + fixed_7b.opt1 = md->opt1; + fixed_7b.opt2 = md->opt2; + fixed_7b.option = md->option; + fixed_7b.mob_class = md->mob_class; // snip: stuff for monsters disguised as PCs - WBUFL(buf, 22) = gettick().time_since_epoch().count(); - - WBUFPOS2(buf, 50, md->bl_x, md->bl_y, md->to_x, md->to_y); - WBUFB(buf, 56) = 5; - WBUFB(buf, 57) = 5; + fixed_7b.tick_and_maybe_part_of_guild_emblem = gettick(); + + fixed_7b.pos2.x0 = md->bl_x; + fixed_7b.pos2.y0 = md->bl_y; + fixed_7b.pos2.x1 = md->to_x; + fixed_7b.pos2.y1 = md->to_y; + fixed_7b.five1 = 5; + fixed_7b.five2 = 5; int level = battle_get_lv(md); - WBUFW(buf, 58) = (level > battle_config.max_lv) ? battle_config.max_lv : level; + fixed_7b.level = (level > battle_config.max_lv) ? battle_config.max_lv : level; - return clif_parse_func_table[0x7b].len; + buf = create_fpacket<0x007b, 60>(fixed_7b); } /*========================================== @@ -878,24 +891,23 @@ int clif_mob007b(dumb_ptr<mob_data> md, unsigned char *buf) *------------------------------------------ */ static -int clif_npc0078(dumb_ptr<npc_data> nd, unsigned char *buf) +void clif_npc0078(dumb_ptr<npc_data> nd, Buffer& buf) { - nullpo_ret(nd); - - really_memset0(buf, clif_parse_func_table[0x78].len); + nullpo_retv(nd); - WBUFW(buf, 0) = 0x78; - WBUFL(buf, 2) = nd->bl_id; - WBUFW(buf, 6) = static_cast<uint16_t>(nd->speed.count()); - WBUFW(buf, 14) = nd->npc_class; - WBUFPOS(buf, 46, nd->bl_x, nd->bl_y); - // work around ICE in gcc 4.6 - uint8_t dir = static_cast<uint8_t>(nd->dir); - WBUFB(buf, 48) |= dir; - WBUFB(buf, 49) = 5; - WBUFB(buf, 50) = 5; + Packet_Fixed<0x0078> fixed_78; + fixed_78.block_id = nd->bl_id; + fixed_78.speed = nd->speed; + fixed_78.species = nd->npc_class; + fixed_78.pos.x = nd->bl_x; + fixed_78.pos.y = nd->bl_y; + fixed_78.pos.dir = nd->dir; + fixed_78.five1 = 5; + fixed_78.five2 = 5; + fixed_78.zero = 0; + fixed_78.level = 0; - return clif_parse_func_table[0x78].len; + buf = create_fpacket<0x0078, 54>(fixed_78); } /* These indices are derived from equip_pos in pc.c and some guesswork */ @@ -924,15 +936,12 @@ earray<EQUIP, LOOK, LOOK::COUNT> equip_points //= */ int clif_spawnpc(dumb_ptr<map_session_data> sd) { - unsigned char buf[128]; + nullpo_retz(sd); - nullpo_ret(sd); + Buffer buf; + clif_set0078_alt_1d9(sd, buf); - clif_set0078(sd, buf); - - WBUFW(buf, 0) = 0x1d9; - WBUFW(buf, 51) = 0; - clif_send(buf, clif_parse_func_table[0x1d9].len, sd, SendWho::AREA_WOS); + clif_send(buf, sd, SendWho::AREA_WOS); if (sd->bl_m->flag.get(MapFlag::SNOW)) clif_specialeffect(sd, 162, 1); @@ -945,7 +954,7 @@ int clif_spawnpc(dumb_ptr<map_session_data> sd) if (sd->bl_m->flag.get(MapFlag::RAIN)) clif_specialeffect(sd, 161, 1); -// clif_changelook_accessories(sd, NULL); +// clif_changelook_accessories(sd, nullptr); return 0; } @@ -956,62 +965,64 @@ int clif_spawnpc(dumb_ptr<map_session_data> sd) */ int clif_spawnnpc(dumb_ptr<npc_data> nd) { - unsigned char buf[64]; - int len; - - nullpo_ret(nd); + nullpo_retz(nd); - if (nd->npc_class < 0 || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS) + if (nd->npc_class == NEGATIVE_SPECIES || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS) return 0; - really_memset0(buf, clif_parse_func_table[0x7c].len); + Packet_Fixed<0x007c> fixed_7c; + fixed_7c.block_id = nd->bl_id; + fixed_7c.speed = nd->speed; + fixed_7c.species = nd->npc_class; + fixed_7c.pos.x = nd->bl_x; + fixed_7c.pos.y = nd->bl_y; - WBUFW(buf, 0) = 0x7c; - WBUFL(buf, 2) = nd->bl_id; - WBUFW(buf, 6) = static_cast<uint16_t>(nd->speed.count()); - WBUFW(buf, 20) = nd->npc_class; - WBUFPOS(buf, 36, nd->bl_x, nd->bl_y); + Buffer buf = create_fpacket<0x007c, 41>(fixed_7c); + clif_send(buf, nd, SendWho::AREA); - clif_send(buf, clif_parse_func_table[0x7c].len, nd, SendWho::AREA); - - len = clif_npc0078(nd, buf); - clif_send(buf, len, nd, SendWho::AREA); + clif_npc0078(nd, buf); + clif_send(buf, nd, SendWho::AREA); return 0; } -int clif_spawn_fake_npc_for_player(dumb_ptr<map_session_data> sd, int fake_npc_id) +int clif_spawn_fake_npc_for_player(dumb_ptr<map_session_data> sd, BlockId fake_npc_id) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; if (!s) return 0; - WFIFOW(s, 0) = 0x7c; - WFIFOL(s, 2) = fake_npc_id; - WFIFOW(s, 6) = 0; - WFIFOW(s, 8) = 0; - WFIFOW(s, 10) = 0; - WFIFOW(s, 12) = 0; - WFIFOW(s, 20) = 127; - WFIFOPOS(s, 36, sd->bl_x, sd->bl_y); - WFIFOSET(s, clif_parse_func_table[0x7c].len); - - WFIFOW(s, 0) = 0x78; - WFIFOL(s, 2) = fake_npc_id; - WFIFOW(s, 6) = 0; - WFIFOW(s, 8) = 0; - WFIFOW(s, 10) = 0; - WFIFOW(s, 12) = 0; - WFIFOW(s, 14) = 127; // identifies as NPC - WFIFOW(s, 20) = 127; - WFIFOPOS(s, 46, sd->bl_x, sd->bl_y); - WFIFOPOS(s, 36, sd->bl_x, sd->bl_y); - WFIFOB(s, 49) = 5; - WFIFOB(s, 50) = 5; - WFIFOSET(s, clif_parse_func_table[0x78].len); + Packet_Fixed<0x007c> fixed_7c; + fixed_7c.block_id = fake_npc_id; + fixed_7c.speed = interval_t(); + fixed_7c.opt1 = Opt1::ZERO; + fixed_7c.opt2 = Opt2::ZERO; + fixed_7c.option = Option::ZERO; + fixed_7c.species = FAKE_NPC_CLASS; + fixed_7c.pos.x = sd->bl_x; + fixed_7c.pos.y = sd->bl_y; + send_fpacket<0x007c, 41>(s, fixed_7c); + + Packet_Fixed<0x0078> fixed_78; + fixed_78.block_id = fake_npc_id; + fixed_78.speed = interval_t(); + fixed_78.opt1 = Opt1::ZERO; + fixed_78.opt2 = Opt2::ZERO; + fixed_78.option = Option::ZERO; + fixed_78.species = FAKE_NPC_CLASS; + fixed_78.unused_head_bottom_or_species_again = unwrap<Species>(FAKE_NPC_CLASS); + fixed_78.pos.x = sd->bl_x; + fixed_78.pos.y = sd->bl_y; + fixed_78.unused_pos_again.x = sd->bl_x; + fixed_78.unused_pos_again.y = sd->bl_y; + fixed_78.five1 = 5; + fixed_78.five2 = 5; + fixed_78.zero = 0; + fixed_78.level = 0; + send_fpacket<0x0078, 54>(s, fixed_78); return 0; } @@ -1022,27 +1033,25 @@ int clif_spawn_fake_npc_for_player(dumb_ptr<map_session_data> sd, int fake_npc_i */ int clif_spawnmob(dumb_ptr<mob_data> md) { - unsigned char buf[64]; - int len; - - nullpo_ret(md); + nullpo_retz(md); { - really_memset0(buf, clif_parse_func_table[0x7c].len); - - WBUFW(buf, 0) = 0x7c; - WBUFL(buf, 2) = md->bl_id; - WBUFW(buf, 6) = md->stats[mob_stat::SPEED]; - WBUFW(buf, 8) = uint16_t(md->opt1); - WBUFW(buf, 10) = uint16_t(md->opt2); - WBUFW(buf, 12) = uint16_t(md->option); - WBUFW(buf, 20) = md->mob_class; - WBUFPOS(buf, 36, md->bl_x, md->bl_y); - clif_send(buf, clif_parse_func_table[0x7c].len, md, SendWho::AREA); + Packet_Fixed<0x007c> fixed_7c; + fixed_7c.block_id = md->bl_id; + fixed_7c.speed = interval_t(md->stats[mob_stat::SPEED]); + fixed_7c.opt1 = md->opt1; + fixed_7c.opt2 = md->opt2; + fixed_7c.option = md->option; + fixed_7c.species = md->mob_class; + fixed_7c.pos.x = md->bl_x; + fixed_7c.pos.y = md->bl_y; + Buffer buf = create_fpacket<0x007c, 41>(fixed_7c); + clif_send(buf, md, SendWho::AREA); } - len = clif_mob0078(md, buf); - clif_send(buf, len, md, SendWho::AREA); + Buffer buf; + clif_mob0078(md, buf); + clif_send(buf, md, SendWho::AREA); return 0; } @@ -1054,12 +1063,12 @@ int clif_spawnmob(dumb_ptr<mob_data> md) static int clif_servertick(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x7f; - WFIFOL(s, 2) = sd->server_tick.time_since_epoch().count(); - WFIFOSET(s, clif_parse_func_table[0x7f].len); + Packet_Fixed<0x007f> fixed_7f; + fixed_7f.tick = gettick(); + send_fpacket<0x007f, 6>(s, fixed_7f); return 0; } @@ -1070,14 +1079,17 @@ int clif_servertick(dumb_ptr<map_session_data> sd) */ int clif_walkok(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x87; - WFIFOL(s, 2) = gettick().time_since_epoch().count(); - WFIFOPOS2(s, 6, sd->bl_x, sd->bl_y, sd->to_x, sd->to_y); - WFIFOB(s, 11) = 0; - WFIFOSET(s, clif_parse_func_table[0x87].len); + Packet_Fixed<0x0087> fixed_87; + fixed_87.tick = gettick(); + fixed_87.pos2.x0 = sd->bl_x; + fixed_87.pos2.y0 = sd->bl_y; + fixed_87.pos2.x1 = sd->to_x; + fixed_87.pos2.y1 = sd->to_y; + fixed_87.zero = 0; + send_fpacket<0x0087, 12>(s, fixed_87); return 0; } @@ -1088,14 +1100,12 @@ int clif_walkok(dumb_ptr<map_session_data> sd) */ int clif_movechar(dumb_ptr<map_session_data> sd) { - int len; - unsigned char buf[256]; + nullpo_retz(sd); - nullpo_ret(sd); + Buffer buf; + clif_set007b(sd, buf); - len = clif_set007b(sd, buf); - - clif_send(buf, len, sd, SendWho::AREA_WOS); + clif_send(buf, sd, SendWho::AREA_WOS); if (battle_config.save_clothcolor == 1 && sd->status.clothes_color > 0) clif_changelook(sd, LOOK::CLOTHES_COLOR, @@ -1131,7 +1141,7 @@ void clif_waitclose(TimerData *, tick_t, Session *s) */ void clif_setwaitclose(Session *s) { - s->timed_close = Timer(gettick() + std::chrono::seconds(5), + s->timed_close = Timer(gettick() + 5_s, std::bind(clif_waitclose, ph::_1, ph::_2, s) ); @@ -1147,11 +1157,11 @@ void clif_changemap(dumb_ptr<map_session_data> sd, MapName mapname, int x, int y Session *s = sd->sess; - WFIFOW(s, 0) = 0x91; - WFIFO_STRING(s, 2, mapname, 16); - WFIFOW(s, 18) = x; - WFIFOW(s, 20) = y; - WFIFOSET(s, clif_parse_func_table[0x91].len); + Packet_Fixed<0x0091> fixed_91; + fixed_91.map_name = mapname; + fixed_91.x = x; + fixed_91.y = y; + send_fpacket<0x0091, 22>(s, fixed_91); } /*========================================== @@ -1164,13 +1174,13 @@ void clif_changemapserver(dumb_ptr<map_session_data> sd, nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x92; - WFIFO_STRING(s, 2, mapname, 16); - WFIFOW(s, 18) = x; - WFIFOW(s, 20) = y; - WFIFOIP(s, 22) = ip; - WFIFOW(s, 26) = port; - WFIFOSET(s, clif_parse_func_table[0x92].len); + Packet_Fixed<0x0092> fixed_92; + fixed_92.map_name = mapname; + fixed_92.x = x; + fixed_92.y = y; + fixed_92.ip = ip; + fixed_92.port = port; + send_fpacket<0x0092, 28>(s, fixed_92); } /*========================================== @@ -1179,30 +1189,29 @@ void clif_changemapserver(dumb_ptr<map_session_data> sd, */ void clif_fixpos(dumb_ptr<block_list> bl) { - uint8_t buf[16]; - nullpo_retv(bl); - WBUFW(buf, 0) = 0x88; - WBUFL(buf, 2) = bl->bl_id; - WBUFW(buf, 6) = bl->bl_x; - WBUFW(buf, 8) = bl->bl_y; + Packet_Fixed<0x0088> fixed_88; + fixed_88.block_id = bl->bl_id; + fixed_88.x = bl->bl_x; + fixed_88.y = bl->bl_y; - clif_send(buf, clif_parse_func_table[0x88].len, bl, SendWho::AREA); + Buffer buf = create_fpacket<0x0088, 10>(fixed_88); + clif_send(buf, bl, SendWho::AREA); } /*========================================== * *------------------------------------------ */ -int clif_npcbuysell(dumb_ptr<map_session_data> sd, int id) +int clif_npcbuysell(dumb_ptr<map_session_data> sd, BlockId id) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xc4; - WFIFOL(s, 2) = id; - WFIFOSET(s, clif_parse_func_table[0xc4].len); + Packet_Fixed<0x00c4> fixed_c4; + fixed_c4.block_id = id; + send_fpacket<0x00c4, 6>(s, fixed_c4); return 0; } @@ -1216,22 +1225,21 @@ int clif_buylist(dumb_ptr<map_session_data> sd, dumb_ptr<npc_data_shop> nd) struct item_data *id; int i, val; - nullpo_ret(sd); - nullpo_ret(nd); + nullpo_retz(sd); + nullpo_retz(nd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xc6; + std::vector<Packet_Repeat<0x00c6>> repeat_c6(nd->shop_items.size()); for (i = 0; i < nd->shop_items.size(); i++) { id = itemdb_search(nd->shop_items[i].nameid); val = nd->shop_items[i].value; - WFIFOL(s, 4 + i * 11) = val; // base price - WFIFOL(s, 8 + i * 11) = val; // actual price - WFIFOB(s, 12 + i * 11) = uint8_t(id->type); - WFIFOW(s, 13 + i * 11) = nd->shop_items[i].nameid; + repeat_c6[i].base_price = val; // base price + repeat_c6[i].actual_price = val; // actual price + repeat_c6[i].type = id->type; + repeat_c6[i].name_id = nd->shop_items[i].nameid; } - WFIFOW(s, 2) = i * 11 + 4; - WFIFOSET(s, WFIFOW(s, 2)); + send_packet_repeatonly<0x00c6, 4, 11>(s, repeat_c6); return 0; } @@ -1242,27 +1250,25 @@ int clif_buylist(dumb_ptr<map_session_data> sd, dumb_ptr<npc_data_shop> nd) */ int clif_selllist(dumb_ptr<map_session_data> sd) { - int i, c = 0, val; - - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xc7; - for (i = 0; i < MAX_INVENTORY; i++) + std::vector<Packet_Repeat<0x00c7>> repeat_c7; + for (IOff0 i : IOff0::iter()) { - if (sd->status.inventory[i].nameid > 0 && sd->inventory_data[i]) + if (sd->status.inventory[i].nameid && sd->inventory_data[i]) { - val = sd->inventory_data[i]->value_sell; + int val = sd->inventory_data[i]->value_sell; if (val < 0) continue; - WFIFOW(s, 4 + c * 10) = i + 2; - WFIFOL(s, 6 + c * 10) = val; // base price - WFIFOL(s, 10 + c * 10) = val; // actual price - c++; + Packet_Repeat<0x00c7> info; + info.ioff2 = i.shift(); + info.base_price = val; + info.actual_price = val; + repeat_c7.push_back(info); } } - WFIFOW(s, 2) = c * 10 + 4; - WFIFOSET(s, WFIFOW(s, 2)); + send_packet_repeatonly<0x00c7, 4, 10>(s, repeat_c7); return 0; } @@ -1271,166 +1277,130 @@ int clif_selllist(dumb_ptr<map_session_data> sd) * *------------------------------------------ */ -void clif_scriptmes(dumb_ptr<map_session_data> sd, int npcid, XString mes) +void clif_scriptmes(dumb_ptr<map_session_data> sd, BlockId npcid, XString mes) { nullpo_retv(sd); Session *s = sd->sess; - size_t len = mes.size() + 1; - WFIFOW(s, 0) = 0xb4; - WFIFOW(s, 2) = len + 8; - WFIFOL(s, 4) = npcid; - WFIFO_STRING(s, 8, mes, len); - WFIFOSET(s, WFIFOW(s, 2)); + Packet_Head<0x00b4> head_b4; + head_b4.block_id = npcid; + send_vpacket<0x00b4, 8, 1>(s, head_b4, mes); } /*========================================== * *------------------------------------------ */ -void clif_scriptnext(dumb_ptr<map_session_data> sd, int npcid) +void clif_scriptnext(dumb_ptr<map_session_data> sd, BlockId npcid) { nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xb5; - WFIFOL(s, 2) = npcid; - WFIFOSET(s, clif_parse_func_table[0xb5].len); + Packet_Fixed<0x00b5> fixed_b5; + fixed_b5.block_id = npcid; + send_fpacket<0x00b5, 6>(s, fixed_b5); } /*========================================== * *------------------------------------------ */ -void clif_scriptclose(dumb_ptr<map_session_data> sd, int npcid) +void clif_scriptclose(dumb_ptr<map_session_data> sd, BlockId npcid) { nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xb6; - WFIFOL(s, 2) = npcid; - WFIFOSET(s, clif_parse_func_table[0xb6].len); + Packet_Fixed<0x00b6> fixed_b6; + fixed_b6.block_id = npcid; + send_fpacket<0x00b6, 6>(s, fixed_b6); } /*========================================== * *------------------------------------------ */ -void clif_scriptmenu(dumb_ptr<map_session_data> sd, int npcid, XString mes) +void clif_scriptmenu(dumb_ptr<map_session_data> sd, BlockId npcid, XString mes) { nullpo_retv(sd); Session *s = sd->sess; - size_t len = mes.size() + 1; - WFIFOW(s, 0) = 0xb7; - WFIFOW(s, 2) = len + 8; - WFIFOL(s, 4) = npcid; - WFIFO_STRING(s, 8, mes, len); - WFIFOSET(s, WFIFOW(s, 2)); + Packet_Head<0x00b7> head_b7; + head_b7.block_id = npcid; + send_vpacket<0x00b7, 8, 1>(s, head_b7, mes); } /*========================================== * *------------------------------------------ */ -void clif_scriptinput(dumb_ptr<map_session_data> sd, int npcid) +void clif_scriptinput(dumb_ptr<map_session_data> sd, BlockId npcid) { nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x142; - WFIFOL(s, 2) = npcid; - WFIFOSET(s, clif_parse_func_table[0x142].len); + Packet_Fixed<0x0142> fixed_142; + fixed_142.block_id = npcid; + send_fpacket<0x0142, 6>(s, fixed_142); } /*========================================== * *------------------------------------------ */ -void clif_scriptinputstr(dumb_ptr<map_session_data> sd, int npcid) +void clif_scriptinputstr(dumb_ptr<map_session_data> sd, BlockId npcid) { nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x1d4; - WFIFOL(s, 2) = npcid; - WFIFOSET(s, clif_parse_func_table[0x1d4].len); + Packet_Fixed<0x01d4> fixed_1d4; + fixed_1d4.block_id = npcid; + send_fpacket<0x01d4, 6>(s, fixed_1d4); } /*========================================== * *------------------------------------------ */ -void clif_viewpoint(dumb_ptr<map_session_data> sd, int npc_id, int type, - int x, int y, int id, int color) +int clif_additem(dumb_ptr<map_session_data> sd, IOff0 n, int amount, PickupFail fail) { - nullpo_retv(sd); - - Session *s = sd->sess; - WFIFOW(s, 0) = 0x144; - WFIFOL(s, 2) = npc_id; - WFIFOL(s, 6) = type; - WFIFOL(s, 10) = x; - WFIFOL(s, 14) = y; - WFIFOB(s, 18) = id; - WFIFOL(s, 19) = color; - WFIFOSET(s, clif_parse_func_table[0x144].len); -} - -/*========================================== - * - *------------------------------------------ - */ -int clif_additem(dumb_ptr<map_session_data> sd, int n, int amount, PickupFail fail) -{ - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; + Packet_Fixed<0x00a0> fixed_a0; if (fail != PickupFail::OKAY) { - WFIFOW(s, 0) = 0xa0; - WFIFOW(s, 2) = n + 2; - WFIFOW(s, 4) = amount; - WFIFOW(s, 6) = 0; - WFIFOB(s, 8) = 0; - WFIFOB(s, 9) = 0; - WFIFOB(s, 10) = 0; - WFIFOW(s, 11) = 0; - WFIFOW(s, 13) = 0; - WFIFOW(s, 15) = 0; - WFIFOW(s, 17) = 0; - WFIFOW(s, 19) = 0; - WFIFOB(s, 21) = 0; - WFIFOB(s, 22) = uint8_t(fail); + fixed_a0.ioff2 = n.shift(); + fixed_a0.amount = amount; + fixed_a0.name_id = ItemNameId(); + fixed_a0.pickup_fail = fail; } else { - if (n < 0 || n >= MAX_INVENTORY || sd->status.inventory[n].nameid <= 0 - || sd->inventory_data[n] == NULL) + if (!n.ok() || !sd->status.inventory[n].nameid + || sd->inventory_data[n] == nullptr) return 1; - WFIFOW(s, 0) = 0xa0; - WFIFOW(s, 2) = n + 2; - WFIFOW(s, 4) = amount; - WFIFOW(s, 6) = sd->status.inventory[n].nameid; - WFIFOB(s, 8) = 1; //identify; - WFIFOB(s, 9) = 0; // broken or attribute; - WFIFOB(s, 10) = 0; //refine; + fixed_a0.ioff2 = n.shift(); + fixed_a0.amount = amount; + fixed_a0.name_id = sd->status.inventory[n].nameid; + fixed_a0.identify = 1; + fixed_a0.broken_or_attribute = 0; + fixed_a0.refine = 0; { - WFIFOW(s, 11) = 0; //card[0]; - WFIFOW(s, 13) = 0; //card[1]; - WFIFOW(s, 15) = 0; //card[2]; - WFIFOW(s, 17) = 0; //card[3]; + fixed_a0.card0 = 0; + fixed_a0.card1 = 0; + fixed_a0.card2 = 0; + fixed_a0.card3 = 0; } - WFIFOW(s, 19) = uint16_t(pc_equippoint(sd, n)); - WFIFOB(s, 21) = uint8_t(sd->inventory_data[n]->type == ItemType::_7 + fixed_a0.epos = pc_equippoint(sd, n); + fixed_a0.item_type = (sd->inventory_data[n]->type == ItemType::_7 ? ItemType::WEAPON : sd->inventory_data[n]->type); - WFIFOB(s, 22) = uint8_t(fail); + fixed_a0.pickup_fail = fail; } - WFIFOSET(s, clif_parse_func_table[0xa0].len); + send_fpacket<0x00a0, 23>(s, fixed_a0); return 0; } @@ -1438,16 +1408,16 @@ int clif_additem(dumb_ptr<map_session_data> sd, int n, int amount, PickupFail fa * *------------------------------------------ */ -void clif_delitem(dumb_ptr<map_session_data> sd, int n, int amount) +void clif_delitem(dumb_ptr<map_session_data> sd, IOff0 n, int amount) { nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xaf; - WFIFOW(s, 2) = n + 2; - WFIFOW(s, 4) = amount; + Packet_Fixed<0x00af> fixed_af; + fixed_af.ioff2 = n.shift(); + fixed_af.amount = amount; - WFIFOSET(s, clif_parse_func_table[0xaf].len); + send_fpacket<0x00af, 6>(s, fixed_af); } /*========================================== @@ -1458,41 +1428,40 @@ void clif_itemlist(dumb_ptr<map_session_data> sd) { nullpo_retv(sd); - int n = 0; - int arrow = -1; + IOff0 arrow = IOff0::from(-1); Session *s = sd->sess; - WFIFOW(s, 0) = 0x1ee; - for (int i = 0; i < MAX_INVENTORY; i++) + std::vector<Packet_Repeat<0x01ee>> repeat_1ee; + for (IOff0 i : IOff0::iter()) { - if (sd->status.inventory[i].nameid <= 0 - || sd->inventory_data[i] == NULL + if (!sd->status.inventory[i].nameid + || sd->inventory_data[i] == nullptr || itemdb_isequip2(sd->inventory_data[i])) continue; - WFIFOW(s, n * 18 + 4) = i + 2; - WFIFOW(s, n * 18 + 6) = sd->status.inventory[i].nameid; - WFIFOB(s, n * 18 + 8) = uint8_t(sd->inventory_data[i]->type); - WFIFOB(s, n * 18 + 9) = 1; //identify; - WFIFOW(s, n * 18 + 10) = sd->status.inventory[i].amount; + Packet_Repeat<0x01ee> info; + info.ioff2 = i.shift(); + info.name_id = sd->status.inventory[i].nameid; + info.item_type = sd->inventory_data[i]->type; + info.identify = 1; + info.amount = sd->status.inventory[i].amount; if (sd->inventory_data[i]->equip == EPOS::ARROW) { - WFIFOW(s, n * 18 + 12) = uint16_t(EPOS::ARROW); + info.epos = EPOS::ARROW; if (bool(sd->status.inventory[i].equip)) - arrow = i; // ついでに矢装備チェック + arrow = i; } else - WFIFOW(s, n * 18 + 12) = uint16_t(EPOS::ZERO); - WFIFOW(s, n * 18 + 14) = 0; //card[0]; - WFIFOW(s, n * 18 + 16) = 0; //card[1]; - WFIFOW(s, n * 18 + 18) = 0; //card[2]; - WFIFOW(s, n * 18 + 20) = 0; //card[3]; - n++; + info.epos = EPOS::ZERO; + info.card0 = 0; + info.card1 = 0; + info.card2 = 0; + info.card3 = 0; + repeat_1ee.push_back(info); } - if (n) + if (!repeat_1ee.empty()) { - WFIFOW(s, 2) = 4 + n * 18; - WFIFOSET(s, WFIFOW(s, 2)); + send_packet_repeatonly<0x01ee, 4, 18>(s, repeat_1ee); } - if (arrow >= 0) + if (arrow.ok()) clif_arrowequip(sd, arrow); } @@ -1505,37 +1474,36 @@ void clif_equiplist(dumb_ptr<map_session_data> sd) nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xa4; - int n = 0; - for (int i = 0; i < MAX_INVENTORY; i++) + std::vector<Packet_Repeat<0x00a4>> repeat_a4; + for (IOff0 i : IOff0::iter()) { - if (sd->status.inventory[i].nameid <= 0 - || sd->inventory_data[i] == NULL + if (!sd->status.inventory[i].nameid + || sd->inventory_data[i] == nullptr || !itemdb_isequip2(sd->inventory_data[i])) continue; - WFIFOW(s, n * 20 + 4) = i + 2; - WFIFOW(s, n * 20 + 6) = sd->status.inventory[i].nameid; - WFIFOB(s, n * 20 + 8) = uint8_t( + Packet_Repeat<0x00a4> info; + info.ioff2 = i.shift(); + info.name_id = sd->status.inventory[i].nameid; + info.item_type = ( sd->inventory_data[i]->type == ItemType::_7 ? ItemType::WEAPON : sd->inventory_data[i]->type); - WFIFOB(s, n * 20 + 9) = 0; //identify; - WFIFOW(s, n * 20 + 10) = uint16_t(pc_equippoint(sd, i)); - WFIFOW(s, n * 20 + 12) = uint16_t(sd->status.inventory[i].equip); - WFIFOB(s, n * 20 + 14) = 0; //broken or attribute; - WFIFOB(s, n * 20 + 15) = 0; //refine; + info.identify = 0; + info.epos_pc = pc_equippoint(sd, i); + info.epos_inv = sd->status.inventory[i].equip; + info.broken_or_attribute = 0; + info.refine = 0; { - WFIFOW(s, n * 20 + 16) = 0; //card[0]; - WFIFOW(s, n * 20 + 18) = 0; //card[1]; - WFIFOW(s, n * 20 + 20) = 0; //card[2]; - WFIFOW(s, n * 20 + 22) = 0; //card[3]; + info.card0 = 0; + info.card1 = 0; + info.card2 = 0; + info.card3 = 0; } - n++; + repeat_a4.push_back(info); } - if (n) + if (!repeat_a4.empty()) { - WFIFOW(s, 2) = 4 + n * 20; - WFIFOSET(s, WFIFOW(s, 2)); + send_packet_repeatonly<0x00a4, 4, 20>(s, repeat_a4); } } @@ -1543,41 +1511,40 @@ void clif_equiplist(dumb_ptr<map_session_data> sd) * カプラさんに預けてある消耗品&収集品リスト *------------------------------------------ */ -int clif_storageitemlist(dumb_ptr<map_session_data> sd, struct storage *stor) +int clif_storageitemlist(dumb_ptr<map_session_data> sd, Storage *stor) { - nullpo_ret(sd); - nullpo_ret(stor); + nullpo_retz(sd); + nullpo_retz(stor); Session *s = sd->sess; - WFIFOW(s, 0) = 0x1f0; - int n = 0; - for (int i = 0; i < MAX_STORAGE; i++) + std::vector<Packet_Repeat<0x01f0>> repeat_1f0; + for (SOff0 i : SOff0::iter()) { - if (stor->storage_[i].nameid <= 0) + if (!stor->storage_[i].nameid) continue; struct item_data *id; id = itemdb_search(stor->storage_[i].nameid); - nullpo_ret(id); + nullpo_retz(id); if (itemdb_isequip2(id)) continue; - WFIFOW(s, n * 18 + 4) = i + 1; - WFIFOW(s, n * 18 + 6) = stor->storage_[i].nameid; - WFIFOB(s, n * 18 + 8) = uint8_t(id->type); - WFIFOB(s, n * 18 + 9) = 0; //identify; - WFIFOW(s, n * 18 + 10) = stor->storage_[i].amount; - WFIFOW(s, n * 18 + 12) = 0; - WFIFOW(s, n * 18 + 14) = 0; //card[0]; - WFIFOW(s, n * 18 + 16) = 0; //card[1]; - WFIFOW(s, n * 18 + 18) = 0; //card[2]; - WFIFOW(s, n * 18 + 20) = 0; //card[3]; - n++; + Packet_Repeat<0x01f0> info; + info.soff1 = i.shift(); + info.name_id = stor->storage_[i].nameid; + info.item_type = id->type; + info.identify = 0; + info.amount = stor->storage_[i].amount; + info.epos_zero = EPOS::ZERO; + info.card0 = 0; + info.card1 = 0; + info.card2 = 0; + info.card3 = 0; + repeat_1f0.push_back(info); } - if (n) + if (!repeat_1f0.empty()) { - WFIFOW(s, 2) = 4 + n * 18; - WFIFOSET(s, WFIFOW(s, 2)); + send_packet_repeatonly<0x01f0, 4, 18>(s, repeat_1f0); } return 0; } @@ -1586,44 +1553,43 @@ int clif_storageitemlist(dumb_ptr<map_session_data> sd, struct storage *stor) * カプラさんに預けてある装備リスト *------------------------------------------ */ -int clif_storageequiplist(dumb_ptr<map_session_data> sd, struct storage *stor) +int clif_storageequiplist(dumb_ptr<map_session_data> sd, Storage *stor) { - nullpo_ret(sd); - nullpo_ret(stor); + nullpo_retz(sd); + nullpo_retz(stor); Session *s = sd->sess; - WFIFOW(s, 0) = 0xa6; - int n = 0; - for (int i = 0; i < MAX_STORAGE; i++) + std::vector<Packet_Repeat<0x00a6>> repeat_a6; + for (SOff0 i : SOff0::iter()) { - if (stor->storage_[i].nameid <= 0) + if (!stor->storage_[i].nameid) continue; struct item_data *id; id = itemdb_search(stor->storage_[i].nameid); - nullpo_ret(id); + nullpo_retz(id); if (!itemdb_isequip2(id)) continue; - WFIFOW(s, n * 20 + 4) = i + 1; - WFIFOW(s, n * 20 + 6) = stor->storage_[i].nameid; - WFIFOB(s, n * 20 + 8) = uint8_t(id->type); - WFIFOB(s, n * 20 + 9) = 0; //identify; - WFIFOW(s, n * 20 + 10) = uint16_t(id->equip); - WFIFOW(s, n * 20 + 12) = uint16_t(stor->storage_[i].equip); - WFIFOB(s, n * 20 + 14) = 0; //broken or attribute - WFIFOB(s, n * 20 + 15) = 0; //refine; + Packet_Repeat<0x00a6> info; + info.soff1 = i.shift(); + info.name_id = stor->storage_[i].nameid; + info.item_type = id->type; + info.identify = 0; + info.epos_id = id->equip; + info.epos_stor = stor->storage_[i].equip; + info.broken_or_attribute = 0; + info.refine = 0; { - WFIFOW(s, n * 20 + 16) = 0; //card[0]; - WFIFOW(s, n * 20 + 18) = 0; //card[1]; - WFIFOW(s, n * 20 + 20) = 0; //card[2]; - WFIFOW(s, n * 20 + 22) = 0; //card[3]; + info.card0 = 0; + info.card1 = 0; + info.card2 = 0; + info.card3 = 0; } - n++; + repeat_a6.push_back(info); } - if (n) + if (!repeat_a6.empty()) { - WFIFOW(s, 2) = 4 + n * 20; - WFIFOSET(s, WFIFOW(s, 2)); + send_packet_repeatonly<0x00a6, 4, 20>(s, repeat_a6); } return 0; } @@ -1635,140 +1601,183 @@ int clif_storageequiplist(dumb_ptr<map_session_data> sd, struct storage *stor) */ int clif_updatestatus(dumb_ptr<map_session_data> sd, SP type) { - int len = 8; - - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xb0; - WFIFOW(s, 2) = static_cast<uint16_t>(type); - switch (type) { - // 00b0 + Packet_Fixed<0x00b0> fixed_b0; + fixed_b0.sp_type = type; + switch (type) + { case SP::WEIGHT: pc_checkweighticon(sd); - // is this because pc_checkweighticon can send other packets? - WFIFOW(s, 0) = 0xb0; - WFIFOW(s, 2) = static_cast<uint16_t>(type); - WFIFOL(s, 4) = sd->weight; + fixed_b0.value = sd->weight; break; case SP::MAXWEIGHT: - WFIFOL(s, 4) = sd->max_weight; + fixed_b0.value = sd->max_weight; break; case SP::SPEED: - // ... - WFIFOL(s, 4) = static_cast<uint16_t>(sd->speed.count()); + // 'speed' is actually delay, in milliseconds + fixed_b0.value = sd->speed.count(); break; case SP::BASELEVEL: - WFIFOL(s, 4) = sd->status.base_level; + fixed_b0.value = sd->status.base_level; break; case SP::JOBLEVEL: - WFIFOL(s, 4) = 0; + fixed_b0.value = sd->status.job_level; break; case SP::STATUSPOINT: - WFIFOL(s, 4) = sd->status.status_point; + fixed_b0.value = sd->status.status_point; break; case SP::SKILLPOINT: - WFIFOL(s, 4) = sd->status.skill_point; + fixed_b0.value = sd->status.skill_point; break; case SP::HIT: - WFIFOL(s, 4) = sd->hit; + fixed_b0.value = sd->hit; break; case SP::FLEE1: - WFIFOL(s, 4) = sd->flee; + fixed_b0.value = sd->flee; break; case SP::FLEE2: - WFIFOL(s, 4) = sd->flee2 / 10; + fixed_b0.value = sd->flee2 / 10; break; case SP::MAXHP: - WFIFOL(s, 4) = sd->status.max_hp; + fixed_b0.value = sd->status.max_hp; break; case SP::MAXSP: - WFIFOL(s, 4) = sd->status.max_sp; + fixed_b0.value = sd->status.max_sp; break; case SP::HP: - WFIFOL(s, 4) = sd->status.hp; + fixed_b0.value = sd->status.hp; break; case SP::SP: - WFIFOL(s, 4) = sd->status.sp; + fixed_b0.value = sd->status.sp; break; case SP::ASPD: - WFIFOL(s, 4) = static_cast<uint16_t>(sd->aspd.count()); + fixed_b0.value = sd->aspd.count(); break; case SP::ATK1: - WFIFOL(s, 4) = sd->base_atk + sd->watk; + fixed_b0.value = sd->base_atk + sd->watk; break; case SP::DEF1: - WFIFOL(s, 4) = sd->def; + fixed_b0.value = sd->def; break; case SP::MDEF1: - WFIFOL(s, 4) = sd->mdef; + fixed_b0.value = sd->mdef; break; case SP::ATK2: - WFIFOL(s, 4) = sd->watk2; + fixed_b0.value = sd->watk2; break; case SP::DEF2: - WFIFOL(s, 4) = sd->def2; + fixed_b0.value = sd->def2; break; case SP::MDEF2: - WFIFOL(s, 4) = sd->mdef2; + fixed_b0.value = sd->mdef2; break; case SP::CRITICAL: - WFIFOL(s, 4) = sd->critical / 10; + fixed_b0.value = sd->critical / 10; break; case SP::MATK1: - WFIFOL(s, 4) = sd->matk1; + fixed_b0.value = sd->matk1; break; case SP::MATK2: - WFIFOL(s, 4) = sd->matk2; + fixed_b0.value = sd->matk2; + break; + case SP::GM: + fixed_b0.value = pc_isGM(sd).get_all_bits(); break; + default: + goto not_b0; + } + + send_fpacket<0x00b0, 8>(s, fixed_b0); + return 0; + } +not_b0: + + { + Packet_Fixed<0x00b1> fixed_b1; + fixed_b1.sp_type = type; + switch (type) + { case SP::ZENY: trade_verifyzeny(sd); - WFIFOW(s, 0) = 0xb1; if (sd->status.zeny < 0) sd->status.zeny = 0; - WFIFOL(s, 4) = sd->status.zeny; + fixed_b1.value = sd->status.zeny; break; + case SP::BASEEXP: - WFIFOW(s, 0) = 0xb1; - WFIFOL(s, 4) = sd->status.base_exp; + fixed_b1.value = sd->status.base_exp; break; case SP::JOBEXP: - WFIFOW(s, 0) = 0xb1; - WFIFOL(s, 4) = sd->status.job_exp; + fixed_b1.value = sd->status.job_exp; break; case SP::NEXTBASEEXP: - WFIFOW(s, 0) = 0xb1; - WFIFOL(s, 4) = pc_nextbaseexp(sd); + fixed_b1.value = pc_nextbaseexp(sd); break; case SP::NEXTJOBEXP: - WFIFOW(s, 0) = 0xb1; - WFIFOL(s, 4) = pc_nextjobexp(sd); + fixed_b1.value = pc_nextjobexp(sd); break; - // 00be 終了 + default: + goto not_b1; + } + + send_fpacket<0x00b1, 8>(s, fixed_b1); + return 0; + } +not_b1: + + { + Packet_Fixed<0x00be> fixed_be; + fixed_be.sp_type = type; + switch (type) + { case SP::USTR: case SP::UAGI: case SP::UVIT: case SP::UINT: case SP::UDEX: case SP::ULUK: - WFIFOW(s, 0) = 0xbe; - WFIFOB(s, 4) = pc_need_status_point(sd, usp_to_sp(type)); - len = 5; + fixed_be.value = pc_need_status_point(sd, usp_to_sp(type)); break; - // 013a 終了 + default: + goto not_be; + } + + send_fpacket<0x00be, 5>(s, fixed_be); + return 0; + } +not_be: + + { + Packet_Fixed<0x013a> fixed_13a; + switch (type) + { case SP::ATTACKRANGE: - WFIFOW(s, 0) = 0x13a; - WFIFOW(s, 2) = (sd->attack_spell_override) - ? sd->attack_spell_range : sd->attackrange; - len = 4; + fixed_13a.attack_range = (sd->attack_spell_override + ? sd->attack_spell_range + : sd->attackrange); break; - // 0141 終了 + default: + goto not_13a; + } + + send_fpacket<0x013a, 4>(s, fixed_13a); + return 0; + } +not_13a: + + { + Packet_Fixed<0x00141> fixed_141; + fixed_141.sp_type = type; + switch (type) + { case SP::STR: case SP::AGI: case SP::VIT: @@ -1777,27 +1786,28 @@ int clif_updatestatus(dumb_ptr<map_session_data> sd, SP type) case SP::LUK: { ATTR attr = sp_to_attr(type); - WFIFOW(s, 0) = 0x141; - WFIFOL(s, 2) = uint16_t(type); - WFIFOL(s, 6) = sd->status.attrs[attr]; - WFIFOL(s, 10) = sd->paramb[attr] + sd->parame[attr]; - len = 14; + fixed_141.value_status = sd->status.attrs[attr]; + fixed_141.value_b_e = sd->paramb[attr] + sd->parame[attr]; } break; - case SP::GM: - WFIFOL(s, 4) = pc_isGM(sd); - break; - default: + goto not_141; + } + + send_fpacket<0x0141, 14>(s, fixed_141); + return 0; + } + +not_141: + { + { if (battle_config.error_log) - PRINTF("clif_updatestatus : make %d routine\n", + PRINTF("clif_updatestatus : make %d routine\n"_fmt, type); return 1; + } } - WFIFOSET(s, len); - - return 0; } /*========================================== @@ -1806,16 +1816,15 @@ int clif_updatestatus(dumb_ptr<map_session_data> sd, SP type) */ int clif_changelook(dumb_ptr<block_list> bl, LOOK type, int val) { - return clif_changelook_towards(bl, type, val, NULL); + return clif_changelook_towards(bl, type, val, nullptr); } int clif_changelook_towards(dumb_ptr<block_list> bl, LOOK type, int val, dumb_ptr<map_session_data> dstsd) { - unsigned char buf[32]; - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::PC) sd = bl->is_player(); @@ -1826,61 +1835,65 @@ int clif_changelook_towards(dumb_ptr<block_list> bl, LOOK type, int val, if (sd && (type == LOOK::WEAPON || type == LOOK::SHIELD || type >= LOOK::SHOES)) { - WBUFW(buf, 0) = 0x1d7; - WBUFL(buf, 2) = bl->bl_id; + Packet_Fixed<0x01d7> fixed_1d7; + fixed_1d7.block_id = bl->bl_id; if (type >= LOOK::SHOES) { EQUIP equip_point = equip_points[type]; - WBUFB(buf, 6) = uint16_t(type); - int idx = sd->equip_index_maybe[equip_point]; - if (idx >= 0 && sd->inventory_data[idx]) + fixed_1d7.look_type = type; + IOff0 idx = sd->equip_index_maybe[equip_point]; + if (idx.ok() && sd->inventory_data[idx]) { - WBUFW(buf, 7) = sd->status.inventory[idx].nameid; + fixed_1d7.weapon_or_name_id_or_value = unwrap<ItemNameId>(sd->status.inventory[idx].nameid); } else - WBUFW(buf, 7) = 0; - WBUFW(buf, 9) = 0; + fixed_1d7.weapon_or_name_id_or_value = unwrap<ItemNameId>(ItemNameId()); + fixed_1d7.shield = ItemNameId(); } else { - WBUFB(buf, 6) = 2; - int widx = sd->equip_index_maybe[EQUIP::WEAPON]; - int sidx = sd->equip_index_maybe[EQUIP::SHIELD]; + fixed_1d7.look_type = LOOK::WEAPON; + IOff0 widx = sd->equip_index_maybe[EQUIP::WEAPON]; + IOff0 sidx = sd->equip_index_maybe[EQUIP::SHIELD]; if (sd->attack_spell_override) - WBUFW(buf, 7) = sd->attack_spell_look_override; + fixed_1d7.weapon_or_name_id_or_value = unwrap<ItemNameId>(sd->attack_spell_look_override); else { - if (widx >= 0 && sd->inventory_data[widx]) + if (widx.ok() && sd->inventory_data[widx]) { - WBUFW(buf, 7) = sd->status.inventory[widx].nameid; + fixed_1d7.weapon_or_name_id_or_value = unwrap<ItemNameId>(sd->status.inventory[widx].nameid); } else - WBUFW(buf, 7) = 0; + fixed_1d7.weapon_or_name_id_or_value = unwrap<ItemNameId>(ItemNameId()); } - if (sidx >= 0 && sidx != widx && sd->inventory_data[sidx]) + if (sidx.ok() && sidx != widx && sd->inventory_data[sidx]) { - WBUFW(buf, 9) = sd->status.inventory[sidx].nameid; + fixed_1d7.shield = sd->status.inventory[sidx].nameid; } else - WBUFW(buf, 9) = 0; + fixed_1d7.shield = ItemNameId(); } + + Buffer buf = create_fpacket<0x01d7, 11>(fixed_1d7); if (dstsd) - clif_send(buf, clif_parse_func_table[0x1d7].len, dstsd, SendWho::SELF); + clif_send(buf, dstsd, SendWho::SELF); else - clif_send(buf, clif_parse_func_table[0x1d7].len, bl, SendWho::AREA); + clif_send(buf, bl, SendWho::AREA); } else { - WBUFW(buf, 0) = 0x1d7; - WBUFL(buf, 2) = bl->bl_id; - WBUFB(buf, 6) = uint8_t(type); - WBUFW(buf, 7) = val; - WBUFW(buf, 9) = 0; + Packet_Fixed<0x01d7> fixed_1d7; + fixed_1d7.block_id = bl->bl_id; + fixed_1d7.look_type = type; + fixed_1d7.weapon_or_name_id_or_value = val; + fixed_1d7.shield = ItemNameId(); + + Buffer buf = create_fpacket<0x01d7, 11>(fixed_1d7); if (dstsd) - clif_send(buf, clif_parse_func_table[0x1d7].len, dstsd, SendWho::SELF); + clif_send(buf, dstsd, SendWho::SELF); else - clif_send(buf, clif_parse_func_table[0x1d7].len, bl, SendWho::AREA); + clif_send(buf, bl, SendWho::AREA); } return 0; } @@ -1892,42 +1905,42 @@ int clif_changelook_towards(dumb_ptr<block_list> bl, LOOK type, int val, static int clif_initialstatus(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xbd; - WFIFOW(s, 2) = sd->status.status_point; - - WFIFOB(s, 4) = min(sd->status.attrs[ATTR::STR], 255); - WFIFOB(s, 5) = pc_need_status_point(sd, SP::STR); - WFIFOB(s, 6) = min(sd->status.attrs[ATTR::AGI], 255); - WFIFOB(s, 7) = pc_need_status_point(sd, SP::AGI); - WFIFOB(s, 8) = min(sd->status.attrs[ATTR::VIT], 255); - WFIFOB(s, 9) = pc_need_status_point(sd, SP::VIT); - WFIFOB(s, 10) = min(sd->status.attrs[ATTR::INT], 255); - WFIFOB(s, 11) = pc_need_status_point(sd, SP::INT); - WFIFOB(s, 12) = min(sd->status.attrs[ATTR::DEX], 255); - WFIFOB(s, 13) = pc_need_status_point(sd, SP::DEX); - WFIFOB(s, 14) = min(sd->status.attrs[ATTR::LUK], 255); - WFIFOB(s, 15) = pc_need_status_point(sd, SP::LUK); - - WFIFOW(s, 16) = sd->base_atk + sd->watk; - WFIFOW(s, 18) = sd->watk2; //atk bonus - WFIFOW(s, 20) = sd->matk1; - WFIFOW(s, 22) = sd->matk2; - WFIFOW(s, 24) = sd->def; // def - WFIFOW(s, 26) = sd->def2; - WFIFOW(s, 28) = sd->mdef; // mdef - WFIFOW(s, 30) = sd->mdef2; - WFIFOW(s, 32) = sd->hit; - WFIFOW(s, 34) = sd->flee; - WFIFOW(s, 36) = sd->flee2 / 10; - WFIFOW(s, 38) = sd->critical / 10; - WFIFOW(s, 40) = sd->status.karma; - WFIFOW(s, 42) = sd->status.manner; - - WFIFOSET(s, clif_parse_func_table[0xbd].len); + Packet_Fixed<0x00bd> fixed_bd; + fixed_bd.status_point = sd->status.status_point; + + fixed_bd.str_attr = saturate<uint8_t>(sd->status.attrs[ATTR::STR]); + fixed_bd.str_upd = pc_need_status_point(sd, SP::STR); + fixed_bd.agi_attr = saturate<uint8_t>(sd->status.attrs[ATTR::AGI]); + fixed_bd.agi_upd = pc_need_status_point(sd, SP::AGI); + fixed_bd.vit_attr = saturate<uint8_t>(sd->status.attrs[ATTR::VIT]); + fixed_bd.vit_upd = pc_need_status_point(sd, SP::VIT); + fixed_bd.int_attr = saturate<uint8_t>(sd->status.attrs[ATTR::INT]); + fixed_bd.int_upd = pc_need_status_point(sd, SP::INT); + fixed_bd.dex_attr = saturate<uint8_t>(sd->status.attrs[ATTR::DEX]); + fixed_bd.dex_upd = pc_need_status_point(sd, SP::DEX); + fixed_bd.luk_attr = saturate<uint8_t>(sd->status.attrs[ATTR::LUK]); + fixed_bd.luk_upd = pc_need_status_point(sd, SP::LUK); + + fixed_bd.atk_sum = sd->base_atk + sd->watk; + fixed_bd.watk2 = sd->watk2; //atk bonus + fixed_bd.matk1 = sd->matk1; + fixed_bd.matk2 = sd->matk2; + fixed_bd.def = sd->def; + fixed_bd.def2 = sd->def2; + fixed_bd.mdef = sd->mdef; + fixed_bd.mdef2 = sd->mdef2; + fixed_bd.hit = sd->hit; + fixed_bd.flee = sd->flee; + fixed_bd.flee2 = sd->flee2 / 10; + fixed_bd.critical = sd->critical / 10; + fixed_bd.karma = sd->status.karma; + fixed_bd.manner = sd->status.manner; + + send_fpacket<0x00bd, 44>(s, fixed_bd); clif_updatestatus(sd, SP::STR); clif_updatestatus(sd, SP::AGI); @@ -1946,18 +1959,16 @@ int clif_initialstatus(dumb_ptr<map_session_data> sd) *矢装備 *------------------------------------------ */ -int clif_arrowequip(dumb_ptr<map_session_data> sd, int val) +int clif_arrowequip(dumb_ptr<map_session_data> sd, IOff0 val) { - nullpo_ret(sd); + nullpo_retz(sd); - if (sd->attacktarget && sd->attacktarget > 0) // [Valaris] - sd->attacktarget = 0; + sd->attacktarget = BlockId(); Session *s = sd->sess; - WFIFOW(s, 0) = 0x013c; - WFIFOW(s, 2) = val + 2; //矢のアイテムID - - WFIFOSET(s, clif_parse_func_table[0x013c].len); + Packet_Fixed<0x013c> fixed_13c; + fixed_13c.ioff2 = val.shift(); + send_fpacket<0x013c, 4>(s, fixed_13c); return 0; } @@ -1968,14 +1979,13 @@ int clif_arrowequip(dumb_ptr<map_session_data> sd, int val) */ int clif_arrow_fail(dumb_ptr<map_session_data> sd, int type) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x013b; - WFIFOW(s, 2) = type; - - WFIFOSET(s, clif_parse_func_table[0x013b].len); + Packet_Fixed<0x013b> fixed_13b; + fixed_13b.type = type; + send_fpacket<0x013b, 4>(s, fixed_13b); return 0; } @@ -1986,14 +1996,14 @@ int clif_arrow_fail(dumb_ptr<map_session_data> sd, int type) */ int clif_statusupack(dumb_ptr<map_session_data> sd, SP type, int ok, int val) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xbc; - WFIFOW(s, 2) = uint16_t(type); - WFIFOB(s, 4) = ok; - WFIFOB(s, 5) = val; - WFIFOSET(s, clif_parse_func_table[0xbc].len); + Packet_Fixed<0x00bc> fixed_bc; + fixed_bc.sp_type = type; + fixed_bc.ok = ok; + fixed_bc.val = val; + send_fpacket<0x00bc, 6>(s, fixed_bc); return 0; } @@ -2002,16 +2012,16 @@ int clif_statusupack(dumb_ptr<map_session_data> sd, SP type, int ok, int val) * *------------------------------------------ */ -int clif_equipitemack(dumb_ptr<map_session_data> sd, int n, EPOS pos, int ok) +int clif_equipitemack(dumb_ptr<map_session_data> sd, IOff0 n, EPOS pos, int ok) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xaa; - WFIFOW(s, 2) = n + 2; - WFIFOW(s, 4) = uint16_t(pos); - WFIFOB(s, 6) = ok; - WFIFOSET(s, clif_parse_func_table[0xaa].len); + Packet_Fixed<0x00aa> fixed_aa; + fixed_aa.ioff2 = n.shift(); + fixed_aa.epos = pos; + fixed_aa.ok = ok; + send_fpacket<0x00aa, 7>(s, fixed_aa); return 0; } @@ -2020,16 +2030,16 @@ int clif_equipitemack(dumb_ptr<map_session_data> sd, int n, EPOS pos, int ok) * *------------------------------------------ */ -int clif_unequipitemack(dumb_ptr<map_session_data> sd, int n, EPOS pos, int ok) +int clif_unequipitemack(dumb_ptr<map_session_data> sd, IOff0 n, EPOS pos, int ok) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xac; - WFIFOW(s, 2) = n + 2; - WFIFOW(s, 4) = uint16_t(pos); - WFIFOB(s, 6) = ok; - WFIFOSET(s, clif_parse_func_table[0xac].len); + Packet_Fixed<0x00ac> fixed_ac; + fixed_ac.ioff2 = n.shift(); + fixed_ac.epos = pos; + fixed_ac.ok = ok; + send_fpacket<0x00ac, 7>(s, fixed_ac); return 0; } @@ -2040,15 +2050,14 @@ int clif_unequipitemack(dumb_ptr<map_session_data> sd, int n, EPOS pos, int ok) */ int clif_misceffect(dumb_ptr<block_list> bl, int type) { - uint8_t buf[32]; + nullpo_retz(bl); - nullpo_ret(bl); + Packet_Fixed<0x019b> fixed_19b; + fixed_19b.block_id = bl->bl_id; + fixed_19b.type = type; + Buffer buf = create_fpacket<0x019b, 10>(fixed_19b); - WBUFW(buf, 0) = 0x19b; - WBUFL(buf, 2) = bl->bl_id; - WBUFL(buf, 6) = type; - - clif_send(buf, clif_parse_func_table[0x19b].len, bl, SendWho::AREA); + clif_send(buf, bl, SendWho::AREA); return 0; } @@ -2059,22 +2068,22 @@ int clif_misceffect(dumb_ptr<block_list> bl, int type) */ int clif_changeoption(dumb_ptr<block_list> bl) { - uint8_t buf[32]; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(bl); + nullpo_retz(bl); Option option = *battle_get_option(bl); sc_data = battle_get_sc_data(bl); - WBUFW(buf, 0) = 0x119; - WBUFL(buf, 2) = bl->bl_id; - WBUFW(buf, 6) = uint16_t(*battle_get_opt1(bl)); - WBUFW(buf, 8) = uint16_t(*battle_get_opt2(bl)); - WBUFW(buf, 10) = uint16_t(option); - WBUFB(buf, 12) = 0; // ?? + Packet_Fixed<0x0119> fixed_119; + fixed_119.block_id = bl->bl_id; + fixed_119.opt1 = *battle_get_opt1(bl); + fixed_119.opt2 = *battle_get_opt2(bl); + fixed_119.option = option; + fixed_119.zero = 0; + Buffer buf = create_fpacket<0x0119, 13>(fixed_119); - clif_send(buf, clif_parse_func_table[0x119].len, bl, SendWho::AREA); + clif_send(buf, bl, SendWho::AREA); return 0; } @@ -2083,31 +2092,30 @@ int clif_changeoption(dumb_ptr<block_list> bl) * *------------------------------------------ */ -int clif_useitemack(dumb_ptr<map_session_data> sd, int index, int amount, +int clif_useitemack(dumb_ptr<map_session_data> sd, IOff0 index, int amount, int ok) { - nullpo_ret(sd); + nullpo_retz(sd); if (!ok) { Session *s = sd->sess; - WFIFOW(s, 0) = 0xa8; - WFIFOW(s, 2) = index + 2; - WFIFOW(s, 4) = amount; - WFIFOB(s, 6) = ok; - WFIFOSET(s, clif_parse_func_table[0xa8].len); + Packet_Fixed<0x00a8> fixed_a8; + fixed_a8.ioff2 = index.shift(); + fixed_a8.amount = amount; + fixed_a8.ok = ok; + send_fpacket<0x00a8, 7>(s, fixed_a8); } else { - uint8_t buf[32]; - - WBUFW(buf, 0) = 0x1c8; - WBUFW(buf, 2) = index + 2; - WBUFW(buf, 4) = sd->status.inventory[index].nameid; - WBUFL(buf, 6) = sd->bl_id; - WBUFW(buf, 10) = amount; - WBUFB(buf, 12) = ok; - clif_send(buf, clif_parse_func_table[0x1c8].len, sd, SendWho::SELF); + Packet_Fixed<0x01c8> fixed_1c8; + fixed_1c8.ioff2 = index.shift(); + fixed_1c8.name_id = sd->status.inventory[index].nameid; + fixed_1c8.block_id = sd->bl_id; + fixed_1c8.amount = amount; + fixed_1c8.ok = ok; + Buffer buf = create_fpacket<0x01c8, 13>(fixed_1c8); + clif_send(buf, sd, SendWho::SELF); } return 0; @@ -2122,9 +2130,9 @@ void clif_traderequest(dumb_ptr<map_session_data> sd, CharName name) nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xe5; - WFIFO_STRING(s, 2, name.to__actual(), 24); - WFIFOSET(s, clif_parse_func_table[0xe5].len); + Packet_Fixed<0x00e5> fixed_e5; + fixed_e5.char_name = name; + send_fpacket<0x00e5, 26>(s, fixed_e5); } /*========================================== @@ -2136,9 +2144,9 @@ void clif_tradestart(dumb_ptr<map_session_data> sd, int type) nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xe7; - WFIFOB(s, 2) = type; - WFIFOSET(s, clif_parse_func_table[0xe7].len); + Packet_Fixed<0x00e7> fixed_e7; + fixed_e7.type = type; + send_fpacket<0x00e7, 3>(s, fixed_e7); } /*========================================== @@ -2146,57 +2154,57 @@ void clif_tradestart(dumb_ptr<map_session_data> sd, int type) *------------------------------------------ */ void clif_tradeadditem(dumb_ptr<map_session_data> sd, - dumb_ptr<map_session_data> tsd, int index, int amount) + dumb_ptr<map_session_data> tsd, IOff2 index2, int amount) { nullpo_retv(sd); nullpo_retv(tsd); Session *s = tsd->sess; - WFIFOW(s, 0) = 0xe9; - WFIFOL(s, 2) = amount; - if (index == 0) + Packet_Fixed<0x00e9> fixed_e9; + fixed_e9.amount = amount; + if (!index2.ok()) { - WFIFOW(s, 6) = 0; // type id - WFIFOB(s, 8) = 0; //identify flag - WFIFOB(s, 9) = 0; // attribute - WFIFOB(s, 10) = 0; //refine - WFIFOW(s, 11) = 0; //card (4w) - WFIFOW(s, 13) = 0; //card (4w) - WFIFOW(s, 15) = 0; //card (4w) - WFIFOW(s, 17) = 0; //card (4w) + fixed_e9.name_id = ItemNameId(); + fixed_e9.identify = 0; + fixed_e9.broken_or_attribute = 0; + fixed_e9.refine = 0; + fixed_e9.card0 = 0; + fixed_e9.card1 = 0; + fixed_e9.card2 = 0; + fixed_e9.card3 = 0; } else { - index -= 2; - WFIFOW(s, 6) = sd->status.inventory[index].nameid; // type id - WFIFOB(s, 8) = 0; //identify; - WFIFOB(s, 9) = 0; //broken or attribute; - WFIFOB(s, 10) = 0; //refine; + IOff0 index0 = index2.unshift(); + fixed_e9.name_id = sd->status.inventory[index0].nameid; + fixed_e9.identify = 0; + fixed_e9.broken_or_attribute = 0; + fixed_e9.refine = 0; { - WFIFOW(s, 11) = 0; //card[0]; - WFIFOW(s, 13) = 0; //card[1]; - WFIFOW(s, 15) = 0; //card[2]; - WFIFOW(s, 17) = 0; //card[3]; + fixed_e9.card0 = 0; + fixed_e9.card1 = 0; + fixed_e9.card2 = 0; + fixed_e9.card3 = 0; } } - WFIFOSET(s, clif_parse_func_table[0xe9].len); + send_fpacket<0x00e9, 19>(s, fixed_e9); } /*========================================== * アイテム追加成功/失敗 *------------------------------------------ */ -int clif_tradeitemok(dumb_ptr<map_session_data> sd, int index, int amount, +int clif_tradeitemok(dumb_ptr<map_session_data> sd, IOff2 index2, int amount, int fail) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x1b1; - WFIFOW(s, 2) = index; - WFIFOW(s, 4) = amount; - WFIFOB(s, 6) = fail; - WFIFOSET(s, clif_parse_func_table[0x1b1].len); + Packet_Fixed<0x01b1> fixed_1b1; + fixed_1b1.ioff2 = index2; + fixed_1b1.amount = amount; + fixed_1b1.fail = fail; + send_fpacket<0x01b1, 7>(s, fixed_1b1); return 0; } @@ -2207,12 +2215,12 @@ int clif_tradeitemok(dumb_ptr<map_session_data> sd, int index, int amount, */ int clif_tradedeal_lock(dumb_ptr<map_session_data> sd, int fail) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xec; - WFIFOB(s, 2) = fail; // 0=you 1=the other person - WFIFOSET(s, clif_parse_func_table[0xec].len); + Packet_Fixed<0x00ec> fixed_ec; + fixed_ec.fail = fail; // 0=you 1=the other person + send_fpacket<0x00ec, 3>(s, fixed_ec); return 0; } @@ -2223,11 +2231,11 @@ int clif_tradedeal_lock(dumb_ptr<map_session_data> sd, int fail) */ int clif_tradecancelled(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xee; - WFIFOSET(s, clif_parse_func_table[0xee].len); + Packet_Fixed<0x00ee> fixed_ee; + send_fpacket<0x00ee, 2>(s, fixed_ee); return 0; } @@ -2238,12 +2246,12 @@ int clif_tradecancelled(dumb_ptr<map_session_data> sd) */ int clif_tradecompleted(dumb_ptr<map_session_data> sd, int fail) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xf0; - WFIFOB(s, 2) = fail; - WFIFOSET(s, clif_parse_func_table[0xf0].len); + Packet_Fixed<0x00f0> fixed_f0; + fixed_f0.fail = fail; + send_fpacket<0x00f0, 3>(s, fixed_f0); return 0; } @@ -2253,16 +2261,16 @@ int clif_tradecompleted(dumb_ptr<map_session_data> sd, int fail) *------------------------------------------ */ int clif_updatestorageamount(dumb_ptr<map_session_data> sd, - struct storage *stor) + Storage *stor) { - nullpo_ret(sd); - nullpo_ret(stor); + nullpo_retz(sd); + nullpo_retz(stor); Session *s = sd->sess; - WFIFOW(s, 0) = 0xf2; // update storage amount - WFIFOW(s, 2) = stor->storage_amount; //items - WFIFOW(s, 4) = MAX_STORAGE; //items max - WFIFOSET(s, clif_parse_func_table[0xf2].len); + Packet_Fixed<0x00f2> fixed_f2; + fixed_f2.current_slots = stor->storage_amount; //items + fixed_f2.max_slots = MAX_STORAGE; //items max + send_fpacket<0x00f2, 6>(s, fixed_f2); return 0; } @@ -2271,30 +2279,27 @@ int clif_updatestorageamount(dumb_ptr<map_session_data> sd, * カプラ倉庫にアイテムを追加する *------------------------------------------ */ -int clif_storageitemadded(dumb_ptr<map_session_data> sd, struct storage *stor, - int index, int amount) +int clif_storageitemadded(dumb_ptr<map_session_data> sd, Storage *stor, + SOff0 index, int amount) { - nullpo_ret(sd); - nullpo_ret(stor); + nullpo_retz(sd); + nullpo_retz(stor); Session *s = sd->sess; - WFIFOW(s, 0) = 0xf4; // Storage item added - WFIFOW(s, 2) = index + 1; // index - WFIFOL(s, 4) = amount; // amount -/* if ((view = itemdb_viewid(stor->storage_[index].nameid)) > 0) - WFIFOW(fd,8) =view; - else*/ - WFIFOW(s, 8) = stor->storage_[index].nameid; - WFIFOB(s, 10) = 0; //identify; - WFIFOB(s, 11) = 0; //broken or attribute; - WFIFOB(s, 12) = 0; //refine; + Packet_Fixed<0x00f4> fixed_f4; + fixed_f4.soff1 = index.shift(); + fixed_f4.amount = amount; + fixed_f4.name_id = stor->storage_[index].nameid; + fixed_f4.identify = 0; + fixed_f4.broken_or_attribute = 0; + fixed_f4.refine = 0; { - WFIFOW(s, 13) = 0; //card[0]; - WFIFOW(s, 15) = 0; //card[1]; - WFIFOW(s, 17) = 0; //card[2]; - WFIFOW(s, 19) = 0; //card[3]; + fixed_f4.card0 = 0; + fixed_f4.card1 = 0; + fixed_f4.card2 = 0; + fixed_f4.card3 = 0; } - WFIFOSET(s, clif_parse_func_table[0xf4].len); + send_fpacket<0x00f4, 21>(s, fixed_f4); return 0; } @@ -2303,16 +2308,16 @@ int clif_storageitemadded(dumb_ptr<map_session_data> sd, struct storage *stor, * カプラ倉庫からアイテムを取り去る *------------------------------------------ */ -int clif_storageitemremoved(dumb_ptr<map_session_data> sd, int index, +int clif_storageitemremoved(dumb_ptr<map_session_data> sd, SOff0 index, int amount) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xf6; // Storage item removed - WFIFOW(s, 2) = index + 1; - WFIFOL(s, 4) = amount; - WFIFOSET(s, clif_parse_func_table[0xf6].len); + Packet_Fixed<0x00f6> fixed_f6; + fixed_f6.soff1 = index.shift(); + fixed_f6.amount = amount; + send_fpacket<0x00f6, 8>(s, fixed_f6); return 0; } @@ -2323,11 +2328,11 @@ int clif_storageitemremoved(dumb_ptr<map_session_data> sd, int index, */ int clif_storageclose(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xf8; // Storage Closed - WFIFOSET(s, clif_parse_func_table[0xf8].len); + Packet_Fixed<0x00f8> fixed_f8; + send_fpacket<0x00f8, 2>(s, fixed_f8); return 0; } @@ -2335,7 +2340,7 @@ int clif_storageclose(dumb_ptr<map_session_data> sd) void clif_changelook_accessories(dumb_ptr<block_list> bl, dumb_ptr<map_session_data> dest) { - for (LOOK i = LOOK::SHOES; i < LOOK::COUNT; i = LOOK(uint8_t(i) + 1)) + for (LOOK i = LOOK::SHOES; i < LOOK::COUNT; i = LOOK(static_cast<uint8_t>(i) + 1)) clif_changelook_towards(bl, i, 0, dest); } @@ -2350,25 +2355,22 @@ static void clif_getareachar_pc(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> dstsd) { - int len; - if (bool(dstsd->status.option & Option::INVISIBILITY)) return; nullpo_retv(sd); nullpo_retv(dstsd); - uint8_t buf[256]; + Buffer buf; if (dstsd->walktimer) { - len = clif_set007b(dstsd, buf); + clif_set007b(dstsd, buf); } else { - len = clif_set0078(dstsd, buf); + clif_set0078_main_1d8(dstsd, buf); } - WFIFO_BUF_CLONE(sd->sess, buf, len); - WFIFOSET(sd->sess, len); + send_buffer(sd->sess, buf); if (battle_config.save_clothcolor == 1 && dstsd->status.clothes_color > 0) clif_changelook(dstsd, LOOK::CLOTHES_COLOR, @@ -2385,16 +2387,15 @@ void clif_getareachar_pc(dumb_ptr<map_session_data> sd, static void clif_getareachar_npc(dumb_ptr<map_session_data> sd, dumb_ptr<npc_data> nd) { - int len; - nullpo_retv(sd); nullpo_retv(nd); - if (nd->npc_class < 0 || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS) + if (nd->npc_class == NEGATIVE_SPECIES || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS) return; - len = clif_npc0078(nd, static_cast<uint8_t *>(WFIFOP(sd->sess, 0))); - WFIFOSET(sd->sess, len); + Buffer buf; + clif_npc0078(nd, buf); + send_buffer(sd->sess, buf); } /*========================================== @@ -2403,13 +2404,11 @@ void clif_getareachar_npc(dumb_ptr<map_session_data> sd, dumb_ptr<npc_data> nd) */ int clif_movemob(dumb_ptr<mob_data> md) { - unsigned char buf[256]; - int len; + nullpo_retz(md); - nullpo_ret(md); - - len = clif_mob007b(md, buf); - clif_send(buf, len, md, SendWho::AREA); + Buffer buf; + clif_mob007b(md, buf); + clif_send(buf, md, SendWho::AREA); return 0; } @@ -2420,20 +2419,19 @@ int clif_movemob(dumb_ptr<mob_data> md) */ int clif_fixmobpos(dumb_ptr<mob_data> md) { - unsigned char buf[256]; - int len; - - nullpo_ret(md); + nullpo_retz(md); if (md->state.state == MS::WALK) { - len = clif_mob007b(md, buf); - clif_send(buf, len, md, SendWho::AREA); + Buffer buf; + clif_mob007b(md, buf); + clif_send(buf, md, SendWho::AREA); } else { - len = clif_mob0078(md, buf); - clif_send(buf, len, md, SendWho::AREA); + Buffer buf; + clif_mob0078(md, buf); + clif_send(buf, md, SendWho::AREA); } return 0; @@ -2445,22 +2443,21 @@ int clif_fixmobpos(dumb_ptr<mob_data> md) */ int clif_fixpcpos(dumb_ptr<map_session_data> sd) { - unsigned char buf[256]; - int len; - - nullpo_ret(sd); + nullpo_retz(sd); if (sd->walktimer) { - len = clif_set007b(sd, buf); - clif_send(buf, len, sd, SendWho::AREA); + Buffer buf; + clif_set007b(sd, buf); + clif_send(buf, sd, SendWho::AREA); } else { - len = clif_set0078(sd, buf); - clif_send(buf, len, sd, SendWho::AREA); + Buffer buf; + clif_set0078_main_1d8(sd, buf); + clif_send(buf, sd, SendWho::AREA); } - clif_changelook_accessories(sd, NULL); + clif_changelook_accessories(sd, nullptr); return 0; } @@ -2473,25 +2470,25 @@ int clif_damage(dumb_ptr<block_list> src, dumb_ptr<block_list> dst, tick_t tick, interval_t sdelay, interval_t ddelay, int damage, int div, DamageType type, int damage2) { - unsigned char buf[256]; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(src); - nullpo_ret(dst); + nullpo_retz(src); + nullpo_retz(dst); sc_data = battle_get_sc_data(dst); - WBUFW(buf, 0) = 0x8a; - WBUFL(buf, 2) = src->bl_id; - WBUFL(buf, 6) = dst->bl_id; - WBUFL(buf, 10) = tick.time_since_epoch().count(); - WBUFL(buf, 14) = sdelay.count(); - WBUFL(buf, 18) = ddelay.count(); - WBUFW(buf, 22) = (damage > 0x7fff) ? 0x7fff : damage; - WBUFW(buf, 24) = div; - WBUFB(buf, 26) = static_cast<uint8_t>(type); - WBUFW(buf, 27) = damage2; - clif_send(buf, clif_parse_func_table[0x8a].len, src, SendWho::AREA); + Packet_Fixed<0x008a> fixed_8a; + fixed_8a.src_id = src->bl_id; + fixed_8a.dst_id = dst->bl_id; + fixed_8a.tick = tick; + fixed_8a.sdelay = sdelay; + fixed_8a.ddelay = ddelay; + fixed_8a.damage = (damage > 0x7fff) ? 0x7fff : damage; + fixed_8a.div = div; + fixed_8a.damage_type = type; + fixed_8a.damage2 = damage2; + Buffer buf = create_fpacket<0x008a, 29>(fixed_8a); + clif_send(buf, src, SendWho::AREA); return 0; } @@ -2503,19 +2500,20 @@ int clif_damage(dumb_ptr<block_list> src, dumb_ptr<block_list> dst, static void clif_getareachar_mob(dumb_ptr<map_session_data> sd, dumb_ptr<mob_data> md) { - int len; nullpo_retv(sd); nullpo_retv(md); if (md->state.state == MS::WALK) { - len = clif_mob007b(md, static_cast<uint8_t *>(WFIFOP(sd->sess, 0))); - WFIFOSET(sd->sess, len); + Buffer buf; + clif_mob007b(md, buf); + send_buffer(sd->sess, buf); } else { - len = clif_mob0078(md, static_cast<uint8_t *>(WFIFOP(sd->sess, 0))); - WFIFOSET(sd->sess, len); + Buffer buf; + clif_mob0078(md, buf); + send_buffer(sd->sess, buf); } } @@ -2531,18 +2529,16 @@ void clif_getareachar_item(dumb_ptr<map_session_data> sd, nullpo_retv(fitem); Session *s = sd->sess; - //009d <ID>.l <item ID>.w <identify flag>.B <X>.w <Y>.w <amount>.w <subX>.B <subY>.B - WFIFOW(s, 0) = 0x9d; - WFIFOL(s, 2) = fitem->bl_id; - WFIFOW(s, 6) = fitem->item_data.nameid; - WFIFOB(s, 8) = 0; //identify; - WFIFOW(s, 9) = fitem->bl_x; - WFIFOW(s, 11) = fitem->bl_y; - WFIFOW(s, 13) = fitem->item_data.amount; - WFIFOB(s, 15) = fitem->subx; - WFIFOB(s, 16) = fitem->suby; - - WFIFOSET(s, clif_parse_func_table[0x9d].len); + Packet_Fixed<0x009d> fixed_9d; + fixed_9d.block_id = fitem->bl_id; + fixed_9d.name_id = fitem->item_data.nameid; + fixed_9d.identify = 0; + fixed_9d.x = fitem->bl_x; + fixed_9d.y = fitem->bl_y; + fixed_9d.amount = fitem->item_data.amount; + fixed_9d.subx = fitem->subx; + fixed_9d.suby = fitem->suby; + send_fpacket<0x009d, 17>(s, fixed_9d); } /*========================================== @@ -2578,7 +2574,7 @@ void clif_getareachar(dumb_ptr<block_list> bl, dumb_ptr<map_session_data> sd) break; default: if (battle_config.error_log) - PRINTF("get area char ??? %d\n", + PRINTF("get area char ??? %d\n"_fmt, bl->bl_type); break; } @@ -2694,32 +2690,32 @@ void clif_mobinsight(dumb_ptr<block_list> bl, dumb_ptr<mob_data> md) int clif_skillinfo(dumb_ptr<map_session_data> sd, SkillID skillid, int type, int range) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; if (!sd->status.skill[skillid].lv) return 0; - WFIFOW(s, 0) = 0x147; - WFIFOW(s, 2) = static_cast<uint16_t>(skillid); + Packet_Fixed<0x0147> fixed_147; + fixed_147.info.skill_id = skillid; if (type < 0) - WFIFOW(s, 4) = skill_get_inf(skillid); + fixed_147.info.type_or_inf = skill_get_inf(skillid); else - WFIFOW(s, 4) = type; - WFIFOW(s, 6) = 0; - WFIFOW(s, 8) = sd->status.skill[skillid].lv; - WFIFOW(s, 10) = skill_get_sp(skillid, sd->status.skill[skillid].lv); + fixed_147.info.type_or_inf = type; + fixed_147.info.flags = SkillFlags::ZERO; + fixed_147.info.level = sd->status.skill[skillid].lv; + fixed_147.info.sp = skill_get_sp(skillid, sd->status.skill[skillid].lv); if (range < 0) { range = skill_get_range(skillid, sd->status.skill[skillid].lv); if (range < 0) range = battle_get_range(sd) - (range + 1); - WFIFOW(s, 12) = range; + fixed_147.info.range = range; } else - WFIFOW(s, 12) = range; - WFIFO_ZERO(s, 14, 24); - WFIFOB(s, 38) = sd->status.skill[skillid].lv < skill_get_max_raise(skillid); - WFIFOSET(s, clif_parse_func_table[0x147].len); + fixed_147.info.range = range; + fixed_147.info.unused = ""_s; + fixed_147.info.can_raise = sd->status.skill[skillid].lv < skill_get_max_raise(skillid); + send_fpacket<0x0147, 39>(s, fixed_147); return 0; } @@ -2730,35 +2726,34 @@ int clif_skillinfo(dumb_ptr<map_session_data> sd, SkillID skillid, int type, */ void clif_skillinfoblock(dumb_ptr<map_session_data> sd) { - int len = 4, range; - nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x10f; + std::vector<Packet_Repeat<0x010f>> repeat_10f; for (SkillID i : erange(SkillID(), MAX_SKILL)) { if (sd->status.skill[i].lv && sd->tmw_version >= 1) { + Packet_Repeat<0x010f> info; // [Fate] Version 1 and later don't crash because of bad skill IDs anymore - WFIFOW(s, len) = static_cast<uint16_t>(i); - WFIFOW(s, len + 2) = skill_get_inf(i); - WFIFOW(s, len + 4) = static_cast<uint16_t>( + info.info.skill_id = i; + info.info.type_or_inf = skill_get_inf(i); + info.info.flags = ( skill_db[i].poolflags | (sd->status.skill[i].flags & SkillFlags::POOL_ACTIVATED)); - WFIFOW(s, len + 6) = sd->status.skill[i].lv; - WFIFOW(s, len + 8) = skill_get_sp(i, sd->status.skill[i].lv); - range = skill_get_range(i, sd->status.skill[i].lv); + info.info.level = sd->status.skill[i].lv; + info.info.sp = skill_get_sp(i, sd->status.skill[i].lv); + int range = skill_get_range(i, sd->status.skill[i].lv); if (range < 0) range = battle_get_range(sd) - (range + 1); - WFIFOW(s, len + 10) = range; - WFIFO_ZERO(s, len + 12, 24); - WFIFOB(s, len + 36) = sd->status.skill[i].lv < skill_get_max_raise(i); - len += 37; + info.info.range = range; + info.info.unused = ""_s; + info.info.can_raise = sd->status.skill[i].lv < skill_get_max_raise(i); + + repeat_10f.push_back(info); } } - WFIFOW(s, 2) = len; - WFIFOSET(s, len); + send_packet_repeatonly<0x010f, 4, 37>(s, repeat_10f); } /*========================================== @@ -2767,21 +2762,19 @@ void clif_skillinfoblock(dumb_ptr<map_session_data> sd) */ int clif_skillup(dumb_ptr<map_session_data> sd, SkillID skill_num) { - int range; - - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x10e; - WFIFOW(s, 2) = uint16_t(skill_num); - WFIFOW(s, 4) = sd->status.skill[skill_num].lv; - WFIFOW(s, 6) = skill_get_sp(skill_num, sd->status.skill[skill_num].lv); - range = skill_get_range(skill_num, sd->status.skill[skill_num].lv); + Packet_Fixed<0x010e> fixed_10e; + fixed_10e.skill_id = skill_num; + fixed_10e.level = sd->status.skill[skill_num].lv; + fixed_10e.sp = skill_get_sp(skill_num, sd->status.skill[skill_num].lv); + int range = skill_get_range(skill_num, sd->status.skill[skill_num].lv); if (range < 0) range = battle_get_range(sd) - (range + 1); - WFIFOW(s, 8) = range; - WFIFOB(s, 10) = sd->status.skill[skill_num].lv < skill_get_max_raise(skill_num); - WFIFOSET(s, clif_parse_func_table[0x10e].len); + fixed_10e.range = range; + fixed_10e.can_raise = sd->status.skill[skill_num].lv < skill_get_max_raise(skill_num); + send_fpacket<0x010e, 11>(s, fixed_10e); return 0; } @@ -2792,14 +2785,11 @@ int clif_skillup(dumb_ptr<map_session_data> sd, SkillID skill_num) */ int clif_skillcastcancel(dumb_ptr<block_list> bl) { - unsigned char buf[16]; - - nullpo_ret(bl); - - WBUFW(buf, 0) = 0x1b9; - WBUFL(buf, 2) = bl->bl_id; - clif_send(buf, clif_parse_func_table[0x1b9].len, bl, SendWho::AREA); + // packet 0x01b9 was being sent with length 0, + // even though there were 6 bytes involved + // and the client ignores it anyway + (void)bl; return 0; } @@ -2810,7 +2800,7 @@ int clif_skillcastcancel(dumb_ptr<block_list> bl) int clif_skill_fail(dumb_ptr<map_session_data> sd, SkillID skill_id, int type, int btype) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; @@ -2819,13 +2809,13 @@ int clif_skill_fail(dumb_ptr<map_session_data> sd, SkillID skill_id, int type, return 0; } - WFIFOW(s, 0) = 0x110; - WFIFOW(s, 2) = uint16_t(skill_id); - WFIFOW(s, 4) = btype; - WFIFOW(s, 6) = 0; - WFIFOB(s, 8) = 0; - WFIFOB(s, 9) = type; - WFIFOSET(s, clif_parse_func_table[0x110].len); + Packet_Fixed<0x0110> fixed_110; + fixed_110.skill_id = skill_id; + fixed_110.btype = btype; + fixed_110.zero1 = 0; + fixed_110.zero2 = 0; + fixed_110.type = type; + send_fpacket<0x0110, 10>(s, fixed_110); return 0; } @@ -2838,26 +2828,26 @@ int clif_skill_damage(dumb_ptr<block_list> src, dumb_ptr<block_list> dst, tick_t tick, interval_t sdelay, interval_t ddelay, int damage, int div, SkillID skill_id, int skill_lv, int type) { - unsigned char buf[64]; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(src); - nullpo_ret(dst); + nullpo_retz(src); + nullpo_retz(dst); sc_data = battle_get_sc_data(dst); - WBUFW(buf, 0) = 0x1de; - WBUFW(buf, 2) = uint16_t(skill_id); - WBUFL(buf, 4) = src->bl_id; - WBUFL(buf, 8) = dst->bl_id; - WBUFL(buf, 12) = static_cast<uint32_t>(tick.time_since_epoch().count()); - WBUFL(buf, 16) = static_cast<uint32_t>(sdelay.count()); - WBUFL(buf, 20) = static_cast<uint32_t>(ddelay.count()); - WBUFL(buf, 24) = damage; - WBUFW(buf, 28) = skill_lv; - WBUFW(buf, 30) = div; - WBUFB(buf, 32) = (type > 0) ? type : skill_get_hit(skill_id); - clif_send(buf, clif_parse_func_table[0x1de].len, src, SendWho::AREA); + Packet_Fixed<0x01de> fixed_1de; + fixed_1de.skill_id = skill_id; + fixed_1de.src_id = src->bl_id; + fixed_1de.dst_id = dst->bl_id; + fixed_1de.tick = tick; + fixed_1de.sdelay = sdelay; + fixed_1de.ddelay = ddelay; + fixed_1de.damage = damage; + fixed_1de.skill_level = skill_lv; + fixed_1de.div = div; + fixed_1de.type_or_hit = (type > 0) ? type : skill_get_hit(skill_id); + Buffer buf = create_fpacket<0x01de, 33>(fixed_1de); + clif_send(buf, src, SendWho::AREA); return 0; } @@ -2868,15 +2858,14 @@ int clif_skill_damage(dumb_ptr<block_list> src, dumb_ptr<block_list> dst, */ int clif_status_change(dumb_ptr<block_list> bl, StatusChange type, int flag) { - unsigned char buf[16]; - - nullpo_ret(bl); + nullpo_retz(bl); - WBUFW(buf, 0) = 0x0196; - WBUFW(buf, 2) = uint16_t(type); - WBUFL(buf, 4) = bl->bl_id; - WBUFB(buf, 8) = flag; - clif_send(buf, clif_parse_func_table[0x196].len, bl, SendWho::AREA); + Packet_Fixed<0x0196> fixed_196; + fixed_196.sc_type = type; + fixed_196.block_id = bl->bl_id; + fixed_196.flag = flag; + Buffer buf = create_fpacket<0x0196, 9>(fixed_196); + clif_send(buf, bl, SendWho::AREA); return 0; } @@ -2889,11 +2878,8 @@ void clif_displaymessage(Session *s, XString mes) if (mes) { // don't send a void message (it's not displaying on the client chat). @help can send void line. - WFIFOW(s, 0) = 0x8e; - size_t str_len = mes.size() + 1; // NUL (might not be NUL yet) - WFIFOW(s, 2) = 4 + str_len; - WFIFO_STRING(s, 4, mes, str_len); - WFIFOSET(s, 4 + str_len); + // This is untrue now ^ + send_packet_repeatonly<0x008e, 4, 1>(s, mes); } } @@ -2903,14 +2889,9 @@ void clif_displaymessage(Session *s, XString mes) */ void clif_GMmessage(dumb_ptr<block_list> bl, XString mes, int flag) { - size_t str_len = mes.size() + 1; - unsigned char buf[str_len + 4]; - - WBUFW(buf, 0) = 0x9a; - WBUFW(buf, 2) = str_len + 4; - WBUF_STRING(buf, 4, mes, str_len); + Buffer buf = create_packet_repeatonly<0x009a, 4, 1>(mes); flag &= 0x07; - clif_send(buf, WBUFW(buf, 2), bl, + clif_send(buf, bl, (flag == 1) ? SendWho::ALL_SAMEMAP : (flag == 2) ? SendWho::AREA : (flag == 3) ? SendWho::SELF : @@ -2923,15 +2904,14 @@ void clif_GMmessage(dumb_ptr<block_list> bl, XString mes, int flag) */ void clif_resurrection(dumb_ptr<block_list> bl, int type) { - uint8_t buf[16]; - nullpo_retv(bl); - WBUFW(buf, 0) = 0x148; - WBUFL(buf, 2) = bl->bl_id; - WBUFW(buf, 6) = type; + Packet_Fixed<0x0148> fixed_148; + fixed_148.block_id = bl->bl_id; + fixed_148.type = type; + Buffer buf = create_fpacket<0x0148, 8>(fixed_148); - clif_send(buf, clif_parse_func_table[0x148].len, bl, + clif_send(buf, bl, type == 1 ? SendWho::AREA : SendWho::AREA_WOS); } @@ -2941,12 +2921,9 @@ void clif_resurrection(dumb_ptr<block_list> bl, int type) */ void clif_wis_message(Session *s, CharName nick, XString mes) // R 0097 <len>.w <nick>.24B <message>.?B { - size_t mes_len = mes.size() + 1; - WFIFOW(s, 0) = 0x97; - WFIFOW(s, 2) = mes_len + 24 + 4; - WFIFO_STRING(s, 4, nick.to__actual(), 24); - WFIFO_STRING(s, 28, mes, mes_len); - WFIFOSET(s, WFIFOW(s, 2)); + Packet_Head<0x0097> head_97; + head_97.char_name = nick; + send_vpacket<0x0097, 28, 1>(s, head_97, mes); } /*========================================== @@ -2955,9 +2932,9 @@ void clif_wis_message(Session *s, CharName nick, XString mes) // R 0097 <len>. */ void clif_wis_end(Session *s, int flag) // R 0098 <type>.B: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target { - WFIFOW(s, 0) = 0x98; - WFIFOW(s, 2) = flag; - WFIFOSET(s, clif_parse_func_table[0x98].len); + Packet_Fixed<0x0098> fixed_98; + fixed_98.flag = flag; + send_fpacket<0x0098, 3>(s, fixed_98); } /*========================================== @@ -2974,12 +2951,12 @@ void clif_wis_end(Session *s, int flag) // R 0098 <type>.B: 0: success to send w */ int clif_party_created(dumb_ptr<map_session_data> sd, int flag) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xfa; - WFIFOB(s, 2) = flag; - WFIFOSET(s, clif_parse_func_table[0xfa].len); + Packet_Fixed<0x00fa> fixed_fa; + fixed_fa.flag = flag; + send_fpacket<0x00fa, 3>(s, fixed_fa); return 0; } @@ -2987,43 +2964,45 @@ int clif_party_created(dumb_ptr<map_session_data> sd, int flag) * パーティ情報送信 *------------------------------------------ */ -int clif_party_info(struct party *p, Session *s) +int clif_party_info(PartyPair p, Session *s) { - unsigned char buf[1024]; - int i, c; - dumb_ptr<map_session_data> sd = NULL; + int i; + dumb_ptr<map_session_data> sd = nullptr; - nullpo_ret(p); + nullpo_retz(p); - WBUFW(buf, 0) = 0xfb; - WBUF_STRING(buf, 4, p->name, 24); - for (i = c = 0; i < MAX_PARTY; i++) + Packet_Head<0x00fb> head_fb; + std::vector<Packet_Repeat<0x00fb>> repeat_fb; + head_fb.party_name = p->name; + for (i = 0; i < MAX_PARTY; i++) { - struct party_member *m = &p->member[i]; - if (m->account_id > 0) + PartyMember *m = &p->member[i]; + if (m->account_id) { - if (sd == NULL) + Packet_Repeat<0x00fb> info; + if (sd == nullptr) sd = dumb_ptr<map_session_data>(m->sd); - WBUFL(buf, 28 + c * 46) = m->account_id; - WBUF_STRING(buf, 28 + c * 46 + 4, m->name.to__actual(), 24); - WBUF_STRING(buf, 28 + c * 46 + 28, m->map, 16); - WBUFB(buf, 28 + c * 46 + 44) = (m->leader) ? 0 : 1; - WBUFB(buf, 28 + c * 46 + 45) = (m->online) ? 0 : 1; - c++; + + info.account_id = m->account_id; + info.char_name = m->name; + info.map_name = m->map; + info.leader = (m->leader) ? 0 : 1; + info.online = (m->online) ? 0 : 1; + repeat_fb.push_back(info); } } - size_t len = 28 + c * 46; - WBUFW(buf, 2) = len; if (s) { // If set, send only to fd. - WFIFO_BUF_CLONE(s, buf, len); - WFIFOSET(s, len); + send_vpacket<0x00fb, 28, 46>(s, head_fb, repeat_fb); return 9; } // else, send it to all the party, if they exist. - if (sd != NULL) - clif_send(buf, len, sd, SendWho::PARTY); + if (sd != nullptr) + { + Buffer buf = create_vpacket<0x00fb, 28, 46>(head_fb, repeat_fb); + clif_send(buf, sd, SendWho::PARTY); + } return 0; } @@ -3037,7 +3016,7 @@ int clif_party_info(struct party *p, Session *s) void clif_party_invite(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> tsd) { - struct party *p; + PartyPair p; nullpo_retv(sd); nullpo_retv(tsd); @@ -3047,10 +3026,10 @@ void clif_party_invite(dumb_ptr<map_session_data> sd, if (!(p = party_search(sd->status.party_id))) return; - WFIFOW(s, 0) = 0xfe; - WFIFOL(s, 2) = sd->status_key.account_id; - WFIFO_STRING(s, 6, p->name, 24); - WFIFOSET(s, clif_parse_func_table[0xfe].len); + Packet_Fixed<0x00fe> fixed_fe; + fixed_fe.account_id = sd->status_key.account_id; + fixed_fe.party_name = p->name; + send_fpacket<0x00fe, 30>(s, fixed_fe); } /*========================================== @@ -3072,10 +3051,10 @@ void clif_party_inviteack(dumb_ptr<map_session_data> sd, CharName nick, int flag nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xfd; - WFIFO_STRING(s, 2, nick.to__actual(), 24); - WFIFOB(s, 26) = flag; - WFIFOSET(s, clif_parse_func_table[0xfd].len); + Packet_Fixed<0x00fd> fixed_fd; + fixed_fd.char_name = nick; + fixed_fd.flag = flag; + send_fpacket<0x00fd, 27>(s, fixed_fd); } /*========================================== @@ -3085,32 +3064,30 @@ void clif_party_inviteack(dumb_ptr<map_session_data> sd, CharName nick, int flag * 0x100=一人にのみ送信 *------------------------------------------ */ -void clif_party_option(struct party *p, dumb_ptr<map_session_data> sd, int flag) +void clif_party_option(PartyPair p, dumb_ptr<map_session_data> sd, int flag) { - unsigned char buf[16]; - nullpo_retv(p); -// if(battle_config.etc_log) -// PRINTF("clif_party_option: %d %d %d\n",p->exp,p->item,flag); - if (sd == NULL && flag == 0) + if (sd == nullptr && flag == 0) { int i; for (i = 0; i < MAX_PARTY; i++) - if ((sd = map_id2sd(p->member[i].account_id)) != NULL) + if ((sd = map_id2sd(account_to_block(p->member[i].account_id))) != nullptr) break; } - if (sd == NULL) + if (sd == nullptr) return; - WBUFW(buf, 0) = 0x101; - WBUFW(buf, 2) = ((flag & 0x01) ? 2 : p->exp); - WBUFW(buf, 4) = ((flag & 0x10) ? 2 : p->item); + Packet_Fixed<0x0101> fixed_101; + fixed_101.exp = ((flag & 0x01) ? 2 : p->exp); + fixed_101.item = ((flag & 0x10) ? 2 : p->item); if (flag == 0) - clif_send(buf, clif_parse_func_table[0x101].len, sd, SendWho::PARTY); + { + Buffer buf = create_fpacket<0x0101, 6>(fixed_101); + clif_send(buf, sd, SendWho::PARTY); + } else { - WFIFO_BUF_CLONE(sd->sess, buf, clif_parse_func_table[0x101].len); - WFIFOSET(sd->sess, clif_parse_func_table[0x101].len); + send_fpacket<0x0101, 6>(sd->sess, fixed_101); } } @@ -3118,35 +3095,36 @@ void clif_party_option(struct party *p, dumb_ptr<map_session_data> sd, int flag) * パーティ脱退(脱退前に呼ぶこと) *------------------------------------------ */ -void clif_party_leaved(struct party *p, dumb_ptr<map_session_data> sd, - int account_id, CharName name, int flag) +void clif_party_leaved(PartyPair p, dumb_ptr<map_session_data> sd, + AccountId account_id, CharName name, int flag) { - unsigned char buf[64]; int i; nullpo_retv(p); - WBUFW(buf, 0) = 0x105; - WBUFL(buf, 2) = account_id; - WBUF_STRING(buf, 6, name.to__actual(), 24); - WBUFB(buf, 30) = flag & 0x0f; + Packet_Fixed<0x0105> fixed_105; + fixed_105.account_id = account_id; + fixed_105.char_name = name; + fixed_105.flag = flag & 0x0f; if ((flag & 0xf0) == 0) { - if (sd == NULL) + if (sd == nullptr) for (i = 0; i < MAX_PARTY; i++) { sd = dumb_ptr<map_session_data>(p->member[i].sd); - if (sd != NULL) + if (sd != nullptr) break; } - if (sd != NULL) - clif_send(buf, clif_parse_func_table[0x105].len, sd, SendWho::PARTY); + if (sd != nullptr) + { + Buffer buf = create_fpacket<0x0105, 31>(fixed_105); + clif_send(buf, sd, SendWho::PARTY); + } } - else if (sd != NULL) + else if (sd != nullptr) { - WFIFO_BUF_CLONE(sd->sess, buf, clif_parse_func_table[0x105].len); - WFIFOSET(sd->sess, clif_parse_func_table[0x105].len); + send_fpacket<0x0105, 31>(sd->sess, fixed_105); } } @@ -3154,7 +3132,7 @@ void clif_party_leaved(struct party *p, dumb_ptr<map_session_data> sd, * パーティメッセージ送信 *------------------------------------------ */ -void clif_party_message(struct party *p, int account_id, XString mes) +void clif_party_message(PartyPair p, AccountId account_id, XString mes) { // always set, but clang is not smart enough dumb_ptr<map_session_data> sd = nullptr; @@ -3165,18 +3143,15 @@ void clif_party_message(struct party *p, int account_id, XString mes) for (i = 0; i < MAX_PARTY; i++) { sd = dumb_ptr<map_session_data>(p->member[i].sd); - if (sd != NULL) + if (sd != nullptr) break; } - if (sd != NULL) + if (sd != nullptr) { - size_t len = mes.size() + 1; - unsigned char buf[len + 8]; - WBUFW(buf, 0) = 0x109; - WBUFW(buf, 2) = len + 8; - WBUFL(buf, 4) = account_id; - WBUF_STRING(buf, 8, mes, len); - clif_send(buf, len + 8, sd, SendWho::PARTY); + Packet_Head<0x0109> head_109; + head_109.account_id = account_id; + Buffer buf = create_vpacket<0x0109, 8, 1>(head_109, mes); + clif_send(buf, sd, SendWho::PARTY); } } @@ -3184,19 +3159,16 @@ void clif_party_message(struct party *p, int account_id, XString mes) * パーティ座標通知 *------------------------------------------ */ -int clif_party_xy(struct party *, dumb_ptr<map_session_data> sd) +int clif_party_xy(PartyPair , dumb_ptr<map_session_data> sd) { - unsigned char buf[16]; - - nullpo_ret(sd); + nullpo_retz(sd); - WBUFW(buf, 0) = 0x107; - WBUFL(buf, 2) = sd->status_key.account_id; - WBUFW(buf, 6) = sd->bl_x; - WBUFW(buf, 8) = sd->bl_y; - clif_send(buf, clif_parse_func_table[0x107].len, sd, SendWho::PARTY_SAMEMAP_WOS); -// if(battle_config.etc_log) -// PRINTF("clif_party_xy %d\n",sd->status_key.account_id); + Packet_Fixed<0x0107> fixed_107; + fixed_107.account_id = sd->status_key.account_id; + fixed_107.x = sd->bl_x; + fixed_107.y = sd->bl_y; + Buffer buf = create_fpacket<0x0107, 10>(fixed_107); + clif_send(buf, sd, SendWho::PARTY_SAMEMAP_WOS); return 0; } @@ -3204,20 +3176,17 @@ int clif_party_xy(struct party *, dumb_ptr<map_session_data> sd) * パーティHP通知 *------------------------------------------ */ -int clif_party_hp(struct party *, dumb_ptr<map_session_data> sd) +int clif_party_hp(PartyPair , dumb_ptr<map_session_data> sd) { - unsigned char buf[16]; - - nullpo_ret(sd); + nullpo_retz(sd); - WBUFW(buf, 0) = 0x106; - WBUFL(buf, 2) = sd->status_key.account_id; - WBUFW(buf, 6) = (sd->status.hp > 0x7fff) ? 0x7fff : sd->status.hp; - WBUFW(buf, 8) = + Packet_Fixed<0x0106> fixed_106; + fixed_106.account_id = sd->status_key.account_id; + fixed_106.hp = (sd->status.hp > 0x7fff) ? 0x7fff : sd->status.hp; + fixed_106.max_hp = (sd->status.max_hp > 0x7fff) ? 0x7fff : sd->status.max_hp; - clif_send(buf, clif_parse_func_table[0x106].len, sd, SendWho::PARTY_AREA_WOS); -// if(battle_config.etc_log) -// PRINTF("clif_party_hp %d\n",sd->status_key.account_id); + Buffer buf = create_fpacket<0x0106, 10>(fixed_106); + clif_send(buf, sd, SendWho::PARTY_AREA_WOS); return 0; } @@ -3227,18 +3196,18 @@ int clif_party_hp(struct party *, dumb_ptr<map_session_data> sd) */ int clif_movetoattack(dumb_ptr<map_session_data> sd, dumb_ptr<block_list> bl) { - nullpo_ret(sd); - nullpo_ret(bl); + nullpo_retz(sd); + nullpo_retz(bl); Session *s = sd->sess; - WFIFOW(s, 0) = 0x139; - WFIFOL(s, 2) = bl->bl_id; - WFIFOW(s, 6) = bl->bl_x; - WFIFOW(s, 8) = bl->bl_y; - WFIFOW(s, 10) = sd->bl_x; - WFIFOW(s, 12) = sd->bl_y; - WFIFOW(s, 14) = sd->attackrange; - WFIFOSET(s, clif_parse_func_table[0x139].len); + Packet_Fixed<0x0139> fixed_139; + fixed_139.block_id = bl->bl_id; + fixed_139.bl_x = bl->bl_x; + fixed_139.bl_y = bl->bl_y; + fixed_139.sd_x = sd->bl_x; + fixed_139.sd_y = sd->bl_y; + fixed_139.range = sd->attackrange; + send_fpacket<0x0139, 16>(s, fixed_139); return 0; } @@ -3248,13 +3217,12 @@ int clif_movetoattack(dumb_ptr<map_session_data> sd, dumb_ptr<block_list> bl) */ int clif_mvp_effect(dumb_ptr<map_session_data> sd) { - unsigned char buf[16]; + nullpo_retz(sd); - nullpo_ret(sd); - - WBUFW(buf, 0) = 0x10c; - WBUFL(buf, 2) = sd->bl_id; - clif_send(buf, clif_parse_func_table[0x10c].len, sd, SendWho::AREA); + Packet_Fixed<0x010c> fixed_10c; + fixed_10c.block_id = sd->bl_id; + Buffer buf = create_fpacket<0x010c, 6>(fixed_10c); + clif_send(buf, sd, SendWho::AREA); return 0; } @@ -3264,22 +3232,19 @@ int clif_mvp_effect(dumb_ptr<map_session_data> sd) */ void clif_emotion(dumb_ptr<block_list> bl, int type) { - unsigned char buf[8]; - nullpo_retv(bl); - WBUFW(buf, 0) = 0xc0; - WBUFL(buf, 2) = bl->bl_id; - WBUFB(buf, 6) = type; - clif_send(buf, clif_parse_func_table[0xc0].len, bl, SendWho::AREA); + Packet_Fixed<0x00c0> fixed_c0; + fixed_c0.block_id = bl->bl_id; + fixed_c0.type = type; + Buffer buf = create_fpacket<0x00c0, 7>(fixed_c0); + clif_send(buf, bl, SendWho::AREA); } static void clif_emotion_towards(dumb_ptr<block_list> bl, dumb_ptr<block_list> target, int type) { - unsigned char buf[8]; - int len = clif_parse_func_table[0xc0].len; dumb_ptr<map_session_data> sd = target->is_player(); nullpo_retv(bl); @@ -3288,12 +3253,11 @@ void clif_emotion_towards(dumb_ptr<block_list> bl, if (target->bl_type != BL::PC) return; - WBUFW(buf, 0) = 0xc0; - WBUFL(buf, 2) = bl->bl_id; - WBUFB(buf, 6) = type; + Packet_Fixed<0x00c0> fixed_c0; + fixed_c0.block_id = bl->bl_id; + fixed_c0.type = type; - WFIFO_BUF_CLONE(sd->sess, buf, len); - WFIFOSET(sd->sess, len); + send_fpacket<0x00c0, 7>(sd->sess, fixed_c0); } /*========================================== @@ -3302,14 +3266,13 @@ void clif_emotion_towards(dumb_ptr<block_list> bl, */ void clif_sitting(Session *, dumb_ptr<map_session_data> sd) { - unsigned char buf[64]; - nullpo_retv(sd); - WBUFW(buf, 0) = 0x8a; - WBUFL(buf, 2) = sd->bl_id; - WBUFB(buf, 26) = 2; - clif_send(buf, clif_parse_func_table[0x8a].len, sd, SendWho::AREA); + Packet_Fixed<0x008a> fixed_8a; + fixed_8a.src_id = sd->bl_id; + fixed_8a.damage_type = DamageType::SIT; + Buffer buf = create_fpacket<0x008a, 29>(fixed_8a); + clif_send(buf, sd, SendWho::AREA); } /*========================================== @@ -3317,30 +3280,30 @@ void clif_sitting(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -int clif_GM_kickack(dumb_ptr<map_session_data> sd, int id) +int clif_GM_kickack(dumb_ptr<map_session_data> sd, AccountId id) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xcd; - WFIFOL(s, 2) = id; - WFIFOSET(s, clif_parse_func_table[0xcd].len); + Packet_Fixed<0x00cd> fixed_cd; + fixed_cd.account_id = id; + send_fpacket<0x00cd, 6>(s, fixed_cd); return 0; } static -void clif_parse_QuitGame(Session *s, dumb_ptr<map_session_data> sd); +void clif_do_quit_game(Session *s, dumb_ptr<map_session_data> sd); int clif_GM_kick(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> tsd, int type) { - nullpo_ret(tsd); + nullpo_retz(tsd); if (type) clif_GM_kickack(sd, tsd->status_key.account_id); tsd->opt1 = Opt1::ZERO; tsd->opt2 = Opt2::ZERO; - clif_parse_QuitGame(tsd->sess, tsd); + clif_do_quit_game(tsd->sess, tsd); return 0; } @@ -3348,15 +3311,12 @@ int clif_GM_kick(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> tsd, // displaying special effects (npcs, weather, etc) [Valaris] int clif_specialeffect(dumb_ptr<block_list> bl, int type, int flag) { - unsigned char buf[24]; - - nullpo_ret(bl); + nullpo_retz(bl); - WBUF_ZERO(buf, 0, clif_parse_func_table[0x19b].len); - - WBUFW(buf, 0) = 0x19b; - WBUFL(buf, 2) = bl->bl_id; - WBUFL(buf, 6) = type; + Packet_Fixed<0x019b> fixed_19b; + fixed_19b.block_id = bl->bl_id; + fixed_19b.type = type; + Buffer buf = create_fpacket<0x019b, 10>(fixed_19b); if (flag == 2) { @@ -3371,9 +3331,9 @@ int clif_specialeffect(dumb_ptr<block_list> bl, int type, int flag) } } else if (flag == 1) - clif_send(buf, clif_parse_func_table[0x19b].len, bl, SendWho::SELF); + clif_send(buf, bl, SendWho::SELF); else if (!flag) - clif_send(buf, clif_parse_func_table[0x19b].len, bl, SendWho::AREA); + clif_send(buf, bl, SendWho::AREA); return 0; @@ -3388,35 +3348,39 @@ int clif_specialeffect(dumb_ptr<block_list> bl, int type, int flag) *------------------------------------------ */ static -void clif_parse_WantToConnection(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_WantToConnection(Session *s, dumb_ptr<map_session_data> sd) { - int account_id; // account_id in the packet + AccountId account_id; // account_id in the packet if (sd) { if (battle_config.error_log) - PRINTF("clif_parse_WantToConnection : invalid request?\n"); - return; + PRINTF("clif_parse_WantToConnection : invalid request?\n"_fmt); + return RecvResult::Error; } - if (RFIFOW(s, 0) == 0x72) + Packet_Fixed<0x0072> fixed; + RecvResult rv = recv_fpacket<0x0072, 19>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + { - account_id = RFIFOL(s, 2); + account_id = fixed.account_id; } - else - return; // Not the auth packet - WFIFOL(s, 0) = account_id; - WFIFOSET(s, 4); + // formerly: account id + Packet_Payload<0x8000> special; + special.magic_packet_length = 4; + send_ppacket<0x8000>(s, special); // if same account already connected, we disconnect the 2 sessions - dumb_ptr<map_session_data> old_sd = map_id2sd(account_id); + dumb_ptr<map_session_data> old_sd = map_id2sd(account_to_block(account_id)); if (old_sd) { clif_authfail_fd(s, 2); // same id clif_authfail_fd(old_sd->sess, 2); // same id - PRINTF("clif_parse_WantToConnection: Double connection for account %d (sessions: #%d (new) and #%d (old)).\n", - account_id, s, old_sd->sess); + PRINTF("clif_parse_WantToConnection: Double connection for account %d (sessions: #%d (new) and #%d (old)).\n"_fmt, + account_id, s, old_sd->sess); } else { @@ -3424,16 +3388,16 @@ void clif_parse_WantToConnection(Session *s, dumb_ptr<map_session_data> sd) s->session_data.reset(sd.operator->()); sd->sess = s; - pc_setnewpc(sd, account_id, RFIFOL(s, 6), RFIFOL(s, 10), - tick_t(static_cast<interval_t>(RFIFOL(s, 14))), - static_cast<SEX>(RFIFOB(s, 18))); + pc_setnewpc(sd, account_id, fixed.char_id, fixed.login_id1, + fixed.client_tick, + fixed.sex); map_addiddb(sd); chrif_authreq(sd); } - return; + return RecvResult::Complete; } /*========================================== @@ -3442,12 +3406,15 @@ void clif_parse_WantToConnection(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_LoadEndAck(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_LoadEndAck(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + if (sd->bl_prev != nullptr) + return RecvResult::Error; - if (sd->bl_prev != NULL) - return; + Packet_Fixed<0x007d> fixed; + RecvResult rv = recv_fpacket<0x007d, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; // 接続ok時 //clif_authok(); @@ -3494,7 +3461,7 @@ void clif_parse_LoadEndAck(Session *, dumb_ptr<map_session_data> sd) if (!battle_config.pk_mode) { // remove pvp stuff for pk_mode [Valaris] - sd->pvp_timer = Timer(gettick() + std::chrono::milliseconds(200), + sd->pvp_timer = Timer(gettick() + 200_ms, std::bind(pc_calc_pvprank_timer, ph::_1, ph::_2, sd->bl_id)); sd->pvp_rank = 0; @@ -3519,7 +3486,7 @@ void clif_parse_LoadEndAck(Session *, dumb_ptr<map_session_data> sd) clif_changeoption(sd); // broken equipment -// clif_changelook_accessories(sd, NULL); +// clif_changelook_accessories(sd, nullptr); map_foreachinarea(std::bind(clif_getareachar, ph::_1, sd), sd->bl_m, @@ -3529,6 +3496,8 @@ void clif_parse_LoadEndAck(Session *, dumb_ptr<map_session_data> sd) if (!sd->state.seen_motd) pc_show_motd(sd); + + return rv; } /*========================================== @@ -3536,13 +3505,18 @@ void clif_parse_LoadEndAck(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TickSend(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TickSend(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x007e> fixed; + RecvResult rv = recv_fpacket<0x007e, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - sd->client_tick = tick_t(static_cast<interval_t>(RFIFOL(s, 2))); - sd->server_tick = gettick(); + uint32_t client_tick = fixed.client_tick; + (void)client_tick; clif_servertick(sd); + + return rv; } /*========================================== @@ -3550,71 +3524,83 @@ void clif_parse_TickSend(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_WalkToXY(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_WalkToXY(Session *s, dumb_ptr<map_session_data> sd) { - int x, y; - - nullpo_retv(sd); + Packet_Fixed<0x0085> fixed; + RecvResult rv = recv_fpacket<0x0085, 5>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - if (sd->npc_id != 0 || sd->state.storage_open) - return; + if (sd->npc_id || sd->state.storage_open) + return rv; if (sd->canmove_tick > gettick()) - return; + return rv; // ステータス異常やハイディング中(トンネルドライブ無)で動けない if (bool(sd->opt1) && sd->opt1 != (Opt1::_stone6)) - return; + return rv; if (sd->invincible_timer) pc_delinvincibletimer(sd); pc_stopattack(sd); - x = RFIFOB(s, 2) * 4 + (RFIFOB(s, 3) >> 6); - y = ((RFIFOB(s, 3) & 0x3f) << 4) + (RFIFOB(s, 4) >> 4); + int x = fixed.pos.x; + int y = fixed.pos.y; pc_walktoxy(sd, x, y); + return rv; } /*========================================== * *------------------------------------------ */ -void clif_parse_QuitGame(Session *s, dumb_ptr<map_session_data> sd) +static +RecvResult clif_parse_QuitGame(Session *s, dumb_ptr<map_session_data> sd) { - tick_t tick = gettick(); + Packet_Fixed<0x018a> fixed; + RecvResult rv = recv_fpacket<0x018a, 4>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - nullpo_retv(sd); + clif_do_quit_game(s, sd); + return rv; +} + +void clif_do_quit_game(Session *s, dumb_ptr<map_session_data> sd) +{ + + tick_t tick = gettick(); - WFIFOW(s, 0) = 0x18b; + Packet_Fixed<0x018b> fixed_18b; if ((!pc_isdead(sd) && (sd->opt1 != Opt1::ZERO || sd->opt2 != Opt2::ZERO)) || (tick < sd->canact_tick)) { - WFIFOW(s, 2) = 1; - WFIFOSET(s, clif_parse_func_table[0x18b].len); + fixed_18b.okay = 1; + send_fpacket<0x018b, 4>(s, fixed_18b); return; } /* Rovert's prevent logout option fixed [Valaris] */ if (!battle_config.prevent_logout - || tick >= sd->canlog_tick + std::chrono::seconds(10)) + || tick >= sd->canlog_tick + 10_s) { clif_setwaitclose(s); - WFIFOW(s, 2) = 0; + fixed_18b.okay = 0; } else { - WFIFOW(s, 2) = 1; + fixed_18b.okay = 1; } - WFIFOSET(s, clif_parse_func_table[0x18b].len); - + send_fpacket<0x018b, 4>(s, fixed_18b); } /*========================================== @@ -3622,18 +3608,23 @@ void clif_parse_QuitGame(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_GetCharNameRequest(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_GetCharNameRequest(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x0094> fixed; + RecvResult rv = recv_fpacket<0x0094, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + dumb_ptr<block_list> bl; - int account_id; + BlockId account_id; - account_id = RFIFOL(s, 2); + account_id = fixed.block_id; bl = map_id2bl(account_id); - if (bl == NULL) - return; + if (bl == nullptr) + return rv; - WFIFOW(s, 0) = 0x95; - WFIFOL(s, 2) = account_id; + Packet_Fixed<0x0095> fixed_95; + fixed_95.block_id = account_id; switch (bl->bl_type) { @@ -3641,21 +3632,21 @@ void clif_parse_GetCharNameRequest(Session *s, dumb_ptr<map_session_data> sd) { dumb_ptr<map_session_data> ssd = bl->is_player(); - nullpo_retv(ssd); + nullpo_retr(rv, ssd); if (ssd->state.shroud_active) - WFIFO_STRING(s, 6, "", 24); + fixed_95.char_name = CharName(); else - WFIFO_STRING(s, 6, ssd->status_key.name.to__actual(), 24); - WFIFOSET(s, clif_parse_func_table[0x95].len); + fixed_95.char_name = ssd->status_key.name; + send_fpacket<0x0095, 30>(s, fixed_95); - struct party *p = NULL; + PartyPair p; PartyName party_name; int send = 0; - if (ssd->status.party_id > 0 && (p = party_search(ssd->status.party_id)) != NULL) + if (ssd->status.party_id && (p = party_search(ssd->status.party_id))) { party_name = p->name; send = 1; @@ -3663,30 +3654,28 @@ void clif_parse_GetCharNameRequest(Session *s, dumb_ptr<map_session_data> sd) if (send) { - WFIFOW(s, 0) = 0x195; - WFIFOL(s, 2) = account_id; - WFIFO_STRING(s, 6, party_name, 24); - WFIFO_STRING(s, 30, "", 24); - WFIFO_STRING(s, 54, "", 24); - WFIFO_STRING(s, 78, "", 24); // We send this value twice because the client expects it - WFIFOSET(s, clif_parse_func_table[0x195].len); - + Packet_Fixed<0x0195> fixed_195; + fixed_195.block_id = account_id; + fixed_195.party_name = party_name; + fixed_195.guild_name = ""_s; + fixed_195.guild_pos = ""_s; + fixed_195.guild_pos = ""_s; // We send this value twice because the client expects it + send_fpacket<0x0195, 102>(s, fixed_195); } - if (pc_isGM(sd) >= battle_config.hack_info_GM_level) + if (pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.hack_info_GM_level)))) { IP4Address ip = ssd->get_ip(); - WFIFOW(s, 0) = 0x20C; + Packet_Fixed<0x020c> fixed_20c; // Mask the IP using the char-server password if (battle_config.mask_ip_gms) ip = MD5_ip(ip); - WFIFOL(s, 2) = account_id; - WFIFOIP(s, 6) = ip; - WFIFOSET(s, clif_parse_func_table[0x20C].len); + fixed_20c.block_id = account_id; + fixed_20c.ip = ip; + send_fpacket<0x020c, 10>(s, fixed_20c); } - } break; case BL::NPC: @@ -3694,26 +3683,28 @@ void clif_parse_GetCharNameRequest(Session *s, dumb_ptr<map_session_data> sd) NpcName name = bl->is_npc()->name; // [fate] elim hashed out/invisible names for the client auto it = std::find(name.begin(), name.end(), '#'); - WFIFO_STRING(s, 6, name.xislice_h(it), 24); - WFIFOSET(s, clif_parse_func_table[0x95].len); + fixed_95.char_name = stringish<CharName>(name.xislice_h(it)); + send_fpacket<0x0095, 30>(s, fixed_95); } break; case BL::MOB: { dumb_ptr<mob_data> md = bl->is_mob(); - nullpo_retv(md); + nullpo_retr(rv, md); - WFIFO_STRING(s, 6, md->name, 24); - WFIFOSET(s, clif_parse_func_table[0x95].len); + fixed_95.char_name = stringish<CharName>(md->name); + send_fpacket<0x0095, 30>(s, fixed_95); } break; default: if (battle_config.error_log) - PRINTF("clif_parse_GetCharNameRequest : bad type %d (%d)\n", + PRINTF("clif_parse_GetCharNameRequest : bad type %d (%d)\n"_fmt, bl->bl_type, account_id); break; } + + return rv; } /*========================================== @@ -3724,63 +3715,60 @@ void clif_parse_GetCharNameRequest(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_GlobalMessage(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_GlobalMessage(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + AString repeat; + RecvResult rv = recv_packet_repeatonly<0x008c, 4, 1>(s, repeat); + if (rv != RecvResult::Complete) + return rv; - AString mbuf = clif_validate_chat(sd, ChatType::Global); + AString mbuf = clif_validate_chat(sd, ChatType::Global, repeat); if (!mbuf) { - clif_displaymessage(s, "Your message could not be sent."); - return; + clif_displaymessage(s, "Your message could not be sent."_s); + return rv; } - if (is_atcommand(s, sd, mbuf, 0)) - return; + if (is_atcommand(s, sd, mbuf, GmLevel())) + return rv; - if (!magic_message(sd, mbuf)) + if (!magic::magic_message(sd, mbuf)) { /* Don't send chat that results in an automatic ban. */ if (tmw_CheckChatSpam(sd, mbuf)) { - clif_displaymessage(s, "Your message could not be sent."); - return; + clif_displaymessage(s, "Your message could not be sent."_s); + return rv; } /* It's not a spell/magic message, so send the message to others. */ - size_t mbuf_size = mbuf.size() + 1; - uint8_t sendbuf[mbuf_size + 8]; - WBUFW(sendbuf, 0) = 0x8d; - WBUFW(sendbuf, 2) = mbuf_size + 8; /* Header(2) + length(2) + ID(4). */ - WBUFL(sendbuf, 4) = sd->bl_id; - WBUF_STRING(sendbuf, 8, mbuf, mbuf_size); - - clif_send(sendbuf, mbuf_size + 8, sd, SendWho::AREA_CHAT_WOC); + Packet_Head<0x008d> head_8d; + head_8d.block_id = sd->bl_id; + XString repeat_8d = mbuf; + Buffer sendbuf = create_vpacket<0x008d, 8, 1>(head_8d, repeat_8d); + + clif_send(sendbuf, sd, SendWho::AREA_CHAT_WOC); } /* Send the message back to the speaker. */ - size_t len = RFIFOW(s, 2); - RFIFO_WFIFO_CLONE(s, s, len); - WFIFOW(s, 0) = 0x8e; - WFIFOSET(s, len); + send_packet_repeatonly<0x008e, 4, 1>(s, repeat); + + return rv; } void clif_message(dumb_ptr<block_list> bl, XString msg) { size_t msg_len = msg.size() + 1; - uint8_t buf[512]; - if (msg_len + 16 > 512) return; nullpo_retv(bl); - WBUFW(buf, 0) = 0x8d; - WBUFW(buf, 2) = msg_len + 8; - WBUFL(buf, 4) = bl->bl_id; - WBUF_STRING(buf, 8, msg, msg_len); + Packet_Head<0x008d> head_8d; + head_8d.block_id = bl->bl_id; + Buffer buf = create_vpacket<0x008d, 8, 1>(head_8d, msg); - clif_send(buf, WBUFW(buf, 2), bl, SendWho::AREA); + clif_send(buf, bl, SendWho::AREA); } /*========================================== @@ -3788,16 +3776,17 @@ void clif_message(dumb_ptr<block_list> bl, XString msg) *------------------------------------------ */ static -void clif_parse_ChangeDir(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_ChangeDir(Session *s, dumb_ptr<map_session_data> sd) { - unsigned char buf[64]; + Packet_Fixed<0x009b> fixed; + RecvResult rv = recv_fpacket<0x009b, 5>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - nullpo_retv(sd); - - // RFIFOW(fd, 2) and WBUFW(buf, 6) are always 0 + // RFIFOW(fd,2) and WBUFW(buf,6) are always 0 // TODO perhaps we could use that to remove this hack? DIR dir; - uint8_t client_dir = RFIFOB(s, 4); + uint8_t client_dir = fixed.client_dir; // the client uses a diffenent direction enum ... ugh switch (client_dir) { @@ -3810,21 +3799,22 @@ void clif_parse_ChangeDir(Session *s, dumb_ptr<map_session_data> sd) case 0 | 8: dir = DIR::E; break; // right case 1 | 8: dir = DIR::SE; break; default: - return; + return rv; } if (dir == sd->dir) - return; + return rv; pc_setdir(sd, dir); - WBUFW(buf, 0) = 0x9c; - WBUFL(buf, 2) = sd->bl_id; - WBUFW(buf, 6) = 0; - WBUFB(buf, 8) = client_dir; + Packet_Fixed<0x009c> fixed_9c; + fixed_9c.block_id = sd->bl_id; + fixed_9c.client_dir = client_dir; + Buffer buf = create_fpacket<0x009c, 9>(fixed_9c); - clif_send(buf, clif_parse_func_table[0x9c].len, sd, SendWho::AREA_WOS); + clif_send(buf, sd, SendWho::AREA_WOS); + return rv; } /*========================================== @@ -3832,23 +3822,27 @@ void clif_parse_ChangeDir(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_Emotion(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_Emotion(Session *s, dumb_ptr<map_session_data> sd) { - unsigned char buf[64]; - - nullpo_retv(sd); + Packet_Fixed<0x00bf> fixed; + RecvResult rv = recv_fpacket<0x00bf, 3>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, SkillID::NV_EMOTE) >= 1) { - uint8_t emote = RFIFOB(s, 2); - WBUFW(buf, 0) = 0xc0; - WBUFL(buf, 2) = sd->bl_id; - WBUFB(buf, 6) = emote; - clif_send(buf, clif_parse_func_table[0xc0].len, sd, SendWho::AREA); + uint8_t emote = fixed.emote; + Packet_Fixed<0x00c0> fixed_c0; + fixed_c0.block_id = sd->bl_id; + fixed_c0.type = emote; + Buffer buf = create_fpacket<0x00c0, 7>(fixed_c0); + clif_send(buf, sd, SendWho::AREA); } else clif_skill_fail(sd, SkillID::ONE, 0, 1); + + return rv; } /*========================================== @@ -3856,11 +3850,18 @@ void clif_parse_Emotion(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_HowManyConnections(Session *s, dumb_ptr<map_session_data>) +RecvResult clif_parse_HowManyConnections(Session *s, dumb_ptr<map_session_data>) { - WFIFOW(s, 0) = 0xc2; - WFIFOL(s, 2) = map_getusers(); - WFIFOSET(s, clif_parse_func_table[0xc2].len); + Packet_Fixed<0x00c1> fixed; + RecvResult rv = recv_fpacket<0x00c1, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + Packet_Fixed<0x00c2> fixed_c2; + fixed_c2.users = map_getusers(); + send_fpacket<0x00c2, 6>(s, fixed_c2); + + return rv; } /*========================================== @@ -3868,64 +3869,69 @@ void clif_parse_HowManyConnections(Session *s, dumb_ptr<map_session_data>) *------------------------------------------ */ static -void clif_parse_ActionRequest(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_ActionRequest(Session *s, dumb_ptr<map_session_data> sd) { - unsigned char buf[64]; - int action_type, target_id; + Packet_Fixed<0x0089> fixed; + RecvResult rv = recv_fpacket<0x0089, 7>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - nullpo_retv(sd); + DamageType action_type; + BlockId target_id; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - if (sd->npc_id != 0 + if (sd->npc_id || bool(sd->opt1) || sd->state.storage_open) - return; + return rv; tick_t tick = gettick(); pc_stop_walking(sd, 0); pc_stopattack(sd); - target_id = RFIFOL(s, 2); - action_type = RFIFOB(s, 6); + target_id = fixed.target_id; + action_type = fixed.action; switch (action_type) { - case 0x00: // once attack - case 0x07: // continuous attack + case DamageType::NORMAL: + case DamageType::CONTINUOUS: if (bool(sd->status.option & Option::HIDE)) - return; + return rv; if (!battle_config.skill_delay_attack_enable) { if (tick < sd->canact_tick) { clif_skill_fail(sd, SkillID::ONE, 4, 0); - return; + return rv; } } if (sd->invincible_timer) pc_delinvincibletimer(sd); - if (sd->attacktarget > 0) // [Valaris] - sd->attacktarget = 0; - pc_attack(sd, target_id, action_type != 0); + sd->attacktarget = BlockId(); + pc_attack(sd, target_id, action_type != DamageType::NORMAL); break; - case 0x02: // sitdown + case DamageType::SIT: pc_stop_walking(sd, 1); pc_setsit(sd); clif_sitting(s, sd); break; - case 0x03: // standup + case DamageType::STAND: pc_setstand(sd); - WBUFW(buf, 0) = 0x8a; - WBUFL(buf, 2) = sd->bl_id; - WBUFB(buf, 26) = 3; - clif_send(buf, clif_parse_func_table[0x8a].len, sd, SendWho::AREA); + Packet_Fixed<0x008a> fixed_8a; + fixed_8a.src_id = sd->bl_id; + fixed_8a.damage_type = DamageType::STAND; + Buffer buf = create_fpacket<0x008a, 29>(fixed_8a); + clif_send(buf, sd, SendWho::AREA); break; } + + return rv; } /*========================================== @@ -3933,11 +3939,14 @@ void clif_parse_ActionRequest(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_Restart(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_Restart(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00b2> fixed; + RecvResult rv = recv_fpacket<0x00b2, 3>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - switch (RFIFOB(s, 2)) + switch (fixed.flag) { case 0x00: if (pc_isdead(sd)) @@ -3961,19 +3970,21 @@ void clif_parse_Restart(Session *s, dumb_ptr<map_session_data> sd) case 0x01: /* Rovert's Prevent logout option - Fixed [Valaris] */ if (!battle_config.prevent_logout - || gettick() >= sd->canlog_tick + std::chrono::seconds(10)) + || gettick() >= sd->canlog_tick + 10_s) { chrif_charselectreq(sd); } else { - WFIFOW(s, 0) = 0x18b; - WFIFOW(s, 2) = 1; + Packet_Fixed<0x018b> fixed_18b; + fixed_18b.okay = 1; - WFIFOSET(s, clif_parse_func_table[0x018b].len); + send_fpacket<0x018b, 4>(s, fixed_18b); } break; } + + return rv; } /*========================================== @@ -3987,29 +3998,33 @@ void clif_parse_Restart(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_Wis(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_Wis(Session *s, dumb_ptr<map_session_data> sd) { - dumb_ptr<map_session_data> dstsd = NULL; + Packet_Head<0x0096> head; + AString repeat; + RecvResult rv = recv_vpacket<0x0096, 28, 1>(s, head, repeat); + if (rv != RecvResult::Complete) + return rv; - nullpo_retv(sd); + dumb_ptr<map_session_data> dstsd = nullptr; - AString mbuf = clif_validate_chat(sd, ChatType::Whisper); + AString mbuf = clif_validate_chat(sd, ChatType::Whisper, repeat); if (!mbuf) { - clif_displaymessage(s, "Your message could not be sent."); - return; + clif_displaymessage(s, "Your message could not be sent."_s); + return rv; } - if (is_atcommand(s, sd, mbuf, 0)) + if (is_atcommand(s, sd, mbuf, GmLevel())) { - return; + return rv; } /* Don't send chat that results in an automatic ban. */ if (tmw_CheckChatSpam(sd, mbuf)) { - clif_displaymessage(s, "Your message could not be sent."); - return; + clif_displaymessage(s, "Your message could not be sent."_s); + return rv; } /* @@ -4018,7 +4033,7 @@ void clif_parse_Wis(Session *s, dumb_ptr<map_session_data> sd) * conflict (for instance, "Test" versus "test"), the char-server must * settle the discrepancy. */ - CharName tname = stringish<CharName>(RFIFO_STRING<24>(s, 4)); + CharName tname = head.target_name; if (!(dstsd = map_nick2sd(tname)) || dstsd->status_key.name != tname) intif_wis_message(sd, tname, mbuf); @@ -4027,7 +4042,7 @@ void clif_parse_Wis(Session *s, dumb_ptr<map_session_data> sd) /* Refuse messages addressed to self. */ if (dstsd->sess == s) { - ZString mes = "You cannot page yourself."; + ZString mes = "You cannot page yourself."_s; clif_wis_message(s, wisp_server_name, mes); } else @@ -4042,6 +4057,8 @@ void clif_parse_Wis(Session *s, dumb_ptr<map_session_data> sd) } } } + + return rv; } /*========================================== @@ -4049,37 +4066,41 @@ void clif_parse_Wis(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TakeItem(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TakeItem(Session *s, dumb_ptr<map_session_data> sd) { - dumb_ptr<flooritem_data> fitem; - int map_object_id; + Packet_Fixed<0x009f> fixed; + RecvResult rv = recv_fpacket<0x009f, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - nullpo_retv(sd); + dumb_ptr<flooritem_data> fitem; - map_object_id = RFIFOL(s, 2); + BlockId map_object_id = fixed.object_id; fitem = map_id_is_item(map_object_id); if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - if (sd->npc_id != 0 + if (sd->npc_id || sd->opt1 != Opt1::ZERO) //会話禁止 - return; + return rv; - if (fitem == NULL || fitem->bl_m != sd->bl_m) - return; + if (fitem == nullptr || fitem->bl_m != sd->bl_m) + return rv; if (abs(sd->bl_x - fitem->bl_x) >= 2 || abs(sd->bl_y - fitem->bl_y) >= 2) - return; // too far away to pick up + return rv; // too far away to pick up if (sd->state.shroud_active && sd->state.shroud_disappears_on_pickup) - magic_unshroud(sd); + magic::magic_unshroud(sd); pc_takeitem(sd, fitem); + + return rv; } /*========================================== @@ -4087,33 +4108,38 @@ void clif_parse_TakeItem(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_DropItem(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_DropItem(Session *s, dumb_ptr<map_session_data> sd) { - int item_index, item_amount; - - nullpo_retv(sd); + Packet_Fixed<0x00a2> fixed; + RecvResult rv = recv_fpacket<0x00a2, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } if (sd->bl_m->flag.get(MapFlag::NO_PLAYER_DROPS)) { - clif_displaymessage(sd->sess, "Can't drop items here."); - return; + clif_displaymessage(sd->sess, "Can't drop items here."_s); + return rv; } - if (sd->npc_id != 0 + if (sd->npc_id || sd->opt1 != Opt1::ZERO) { - clif_displaymessage(sd->sess, "Can't drop items right now."); - return; + clif_displaymessage(sd->sess, "Can't drop items right now."_s); + return rv; } - item_index = RFIFOW(s, 2) - 2; - item_amount = RFIFOW(s, 4); + if (!fixed.ioff2.ok()) + return RecvResult::Error; + IOff0 item_index = fixed.ioff2.unshift(); + int item_amount = fixed.amount; pc_dropitem(sd, item_index, item_amount); + + return rv; } /*========================================== @@ -4121,23 +4147,30 @@ void clif_parse_DropItem(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_UseItem(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_UseItem(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00a7> fixed; + RecvResult rv = recv_fpacket<0x00a7, 8>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - if (sd->npc_id != 0 + if (sd->npc_id || sd->opt1 != Opt1::ZERO) //会話禁止 - return; + return rv; if (sd->invincible_timer) pc_delinvincibletimer(sd); - pc_useitem(sd, RFIFOW(s, 2) - 2); + if (!fixed.ioff2.ok()) + return RecvResult::Error; + pc_useitem(sd, fixed.ioff2.unshift()); + + return rv; } /*========================================== @@ -4145,30 +4178,35 @@ void clif_parse_UseItem(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_EquipItem(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_EquipItem(Session *s, dumb_ptr<map_session_data> sd) { - int index; - - nullpo_retv(sd); + Packet_Fixed<0x00a9> fixed; + RecvResult rv = recv_fpacket<0x00a9, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - index = RFIFOW(s, 2) - 2; - if (sd->npc_id != 0) - return; + if (!fixed.ioff2.ok()) + return RecvResult::Error; + IOff0 index = fixed.ioff2.unshift(); + if (sd->npc_id) + return rv; if (sd->inventory_data[index]) { - EPOS epos = EPOS(RFIFOW(s, 4)); + EPOS epos = fixed.epos_ignored; if (sd->inventory_data[index]->type == ItemType::ARROW) epos = EPOS::ARROW; // Note: the EPOS argument to pc_equipitem is actually ignored pc_equipitem(sd, index, epos); } + + return rv; } /*========================================== @@ -4176,23 +4214,28 @@ void clif_parse_EquipItem(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_UnequipItem(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_UnequipItem(Session *s, dumb_ptr<map_session_data> sd) { - int index; - - nullpo_retv(sd); + Packet_Fixed<0x00ab> fixed; + RecvResult rv = recv_fpacket<0x00ab, 4>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - index = RFIFOW(s, 2) - 2; + if (!fixed.ioff2.ok()) + return RecvResult::Error; + IOff0 index = fixed.ioff2.unshift(); - if (sd->npc_id != 0 + if (sd->npc_id || sd->opt1 != Opt1::ZERO) - return; + return rv; pc_unequipitem(sd, index, CalcStatus::NOW); + + return rv; } /*========================================== @@ -4200,18 +4243,23 @@ void clif_parse_UnequipItem(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcClicked(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcClicked(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x0090> fixed; + RecvResult rv = recv_fpacket<0x0090, 7>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - if (sd->npc_id != 0) - return; - npc_click(sd, RFIFOL(s, 2)); + if (sd->npc_id) + return rv; + npc_click(sd, fixed.block_id); + + return rv; } /*========================================== @@ -4219,9 +4267,16 @@ void clif_parse_NpcClicked(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcBuySellSelected(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcBuySellSelected(Session *s, dumb_ptr<map_session_data> sd) { - npc_buysellsel(sd, RFIFOL(s, 2), RFIFOB(s, 6)); + Packet_Fixed<0x00c5> fixed; + RecvResult rv = recv_fpacket<0x00c5, 7>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + npc_buysellsel(sd, fixed.block_id, fixed.type); + + return rv; } /*========================================== @@ -4229,17 +4284,20 @@ void clif_parse_NpcBuySellSelected(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcBuyListSend(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcBuyListSend(Session *s, dumb_ptr<map_session_data> sd) { - int n = (RFIFOW(s, 2) - 4) / 4; - // really an array of pairs of uint16_t - const uint16_t *item_list = static_cast<const uint16_t *>(RFIFOP(s, 4)); + std::vector<Packet_Repeat<0x00c8>> repeat; + RecvResult rv = recv_packet_repeatonly<0x00c8, 4, 4>(s, repeat); + if (rv != RecvResult::Complete) + return rv; - int fail = npc_buylist(sd, n, item_list); + int fail = npc_buylist(sd, repeat); - WFIFOW(s, 0) = 0xca; - WFIFOB(s, 2) = fail; - WFIFOSET(s, clif_parse_func_table[0xca].len); + Packet_Fixed<0x00ca> fixed_ca; + fixed_ca.fail = fail; + send_fpacket<0x00ca, 3>(s, fixed_ca); + + return rv; } /*========================================== @@ -4247,17 +4305,20 @@ void clif_parse_NpcBuyListSend(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcSellListSend(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcSellListSend(Session *s, dumb_ptr<map_session_data> sd) { - int n = (RFIFOW(s, 2) - 4) / 4; - // really an array of pairs of uint16_t - const uint16_t *item_list = static_cast<const uint16_t *>(RFIFOP(s, 4)); + std::vector<Packet_Repeat<0x00c9>> repeat; + RecvResult rv = recv_packet_repeatonly<0x00c9, 4, 4>(s, repeat); + if (rv != RecvResult::Complete) + return rv; + + int fail = npc_selllist(sd, repeat); - int fail = npc_selllist(sd, n, item_list); + Packet_Fixed<0x00cb> fixed_cb; + fixed_cb.fail = fail; + send_fpacket<0x00cb, 3>(s, fixed_cb); - WFIFOW(s, 0) = 0xcb; - WFIFOB(s, 2) = fail; - WFIFOSET(s, clif_parse_func_table[0xcb].len); + return rv; } /*========================================== @@ -4265,17 +4326,22 @@ void clif_parse_NpcSellListSend(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TradeRequest(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TradeRequest(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00e4> fixed; + RecvResult rv = recv_fpacket<0x00e4, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, SkillID::NV_TRADE) >= 1) { - trade_traderequest(sd, RFIFOL(sd->sess, 2)); + trade_traderequest(sd, fixed.block_id); } else clif_skill_fail(sd, SkillID::ONE, 0, 0); + + return rv; } /*========================================== @@ -4283,11 +4349,16 @@ void clif_parse_TradeRequest(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TradeAck(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TradeAck(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00e6> fixed; + RecvResult rv = recv_fpacket<0x00e6, 3>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - trade_tradeack(sd, RFIFOB(sd->sess, 2)); + trade_tradeack(sd, fixed.type); + + return rv; } /*========================================== @@ -4295,11 +4366,18 @@ void clif_parse_TradeAck(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TradeAddItem(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TradeAddItem(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00e8> fixed; + RecvResult rv = recv_fpacket<0x00e8, 8>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - trade_tradeadditem(sd, RFIFOW(sd->sess, 2), RFIFOL(sd->sess, 4)); + if (fixed.zeny_or_ioff2.index != 0 && !fixed.zeny_or_ioff2.ok()) + return RecvResult::Error; + trade_tradeadditem(sd, fixed.zeny_or_ioff2, fixed.amount); + + return rv; } /*========================================== @@ -4307,9 +4385,16 @@ void clif_parse_TradeAddItem(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TradeOk(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TradeOk(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x00eb> fixed; + RecvResult rv = recv_fpacket<0x00eb, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + trade_tradeok(sd); + + return rv; } /*========================================== @@ -4317,9 +4402,16 @@ void clif_parse_TradeOk(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TradeCansel(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TradeCansel(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x00ed> fixed; + RecvResult rv = recv_fpacket<0x00ed, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + trade_tradecancel(sd); + + return rv; } /*========================================== @@ -4327,9 +4419,16 @@ void clif_parse_TradeCansel(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TradeCommit(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TradeCommit(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x00ef> fixed; + RecvResult rv = recv_fpacket<0x00ef, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + trade_tradecommit(sd); + + return rv; } /*========================================== @@ -4337,9 +4436,16 @@ void clif_parse_TradeCommit(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_StopAttack(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_StopAttack(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x0118> fixed; + RecvResult rv = recv_fpacket<0x0118, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + pc_stopattack(sd); + + return rv; } /*========================================== @@ -4347,9 +4453,16 @@ void clif_parse_StopAttack(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_StatusUp(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_StatusUp(Session *s, dumb_ptr<map_session_data> sd) { - pc_statusup(sd, SP(RFIFOW(s, 2))); + Packet_Fixed<0x00bb> fixed; + RecvResult rv = recv_fpacket<0x00bb, 5>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + pc_statusup(sd, fixed.asp); + + return rv; } /*========================================== @@ -4357,9 +4470,16 @@ void clif_parse_StatusUp(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_SkillUp(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_SkillUp(Session *s, dumb_ptr<map_session_data> sd) { - pc_skillup(sd, SkillID(RFIFOW(s, 2))); + Packet_Fixed<0x0112> fixed; + RecvResult rv = recv_fpacket<0x0112, 4>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + pc_skillup(sd, fixed.skill_id); + + return rv; } /*========================================== @@ -4367,12 +4487,17 @@ void clif_parse_SkillUp(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcSelectMenu(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcSelectMenu(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00b8> fixed; + RecvResult rv = recv_fpacket<0x00b8, 7>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + sd->npc_menu = fixed.menu_entry; + map_scriptcont(sd, fixed.npc_id); - sd->npc_menu = RFIFOB(s, 6); - map_scriptcont(sd, RFIFOL(s, 2)); + return rv; } /*========================================== @@ -4380,9 +4505,16 @@ void clif_parse_NpcSelectMenu(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcNextClicked(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcNextClicked(Session *s, dumb_ptr<map_session_data> sd) { - map_scriptcont(sd, RFIFOL(s, 2)); + Packet_Fixed<0x00b9> fixed; + RecvResult rv = recv_fpacket<0x00b9, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + map_scriptcont(sd, fixed.npc_id); + + return rv; } /*========================================== @@ -4390,12 +4522,17 @@ void clif_parse_NpcNextClicked(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcAmountInput(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcAmountInput(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x0143> fixed; + RecvResult rv = recv_fpacket<0x0143, 10>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - sd->npc_amount = RFIFOL(s, 6); - map_scriptcont(sd, RFIFOL(s, 2)); + sd->npc_amount = fixed.input_int_value; + map_scriptcont(sd, fixed.block_id); + + return rv; } /*========================================== @@ -4405,22 +4542,19 @@ void clif_parse_NpcAmountInput(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcStringInput(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcStringInput(Session *s, dumb_ptr<map_session_data> sd) { - int len; - nullpo_retv(sd); + Packet_Head<0x01d5> head; + AString repeat; + RecvResult rv = recv_vpacket<0x01d5, 8, 1>(s, head, repeat); + if (rv != RecvResult::Complete) + return rv; - len = RFIFOW(s, 2) - 8; + sd->npc_str = repeat; - /* - * If we check for equal to 0, too, we'll freeze clients that send (or - * claim to have sent) an "empty" message. - */ - if (len < 0) - return; - sd->npc_str = RFIFO_STRING(s, 8, len); + map_scriptcont(sd, head.block_id); - map_scriptcont(sd, RFIFOL(s, 4)); + return rv; } /*========================================== @@ -4428,9 +4562,16 @@ void clif_parse_NpcStringInput(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcCloseClicked(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcCloseClicked(Session *s, dumb_ptr<map_session_data> sd) { - map_scriptcont(sd, RFIFOL(s, 2)); + Packet_Fixed<0x0146> fixed; + RecvResult rv = recv_fpacket<0x0146, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + map_scriptcont(sd, fixed.block_id); + + return rv; } /*========================================== @@ -4438,21 +4579,26 @@ void clif_parse_NpcCloseClicked(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_MoveToKafra(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_MoveToKafra(Session *s, dumb_ptr<map_session_data> sd) { - int item_index, item_amount; + Packet_Fixed<0x00f3> fixed; + RecvResult rv = recv_fpacket<0x00f3, 8>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - nullpo_retv(sd); - - item_index = RFIFOW(s, 2) - 2; - item_amount = RFIFOL(s, 4); + if (!fixed.ioff2.ok()) + return RecvResult::Error; + IOff0 item_index = fixed.ioff2.unshift(); + int item_amount = fixed.amount; - if ((sd->npc_id != 0 && !sd->npc_flags.storage) || sd->trade_partner != 0 + if ((sd->npc_id && !sd->npc_flags.storage) || sd->trade_partner || !sd->state.storage_open) - return; + return rv; if (sd->state.storage_open) storage_storageadd(sd, item_index, item_amount); + + return rv; } /*========================================== @@ -4460,21 +4606,26 @@ void clif_parse_MoveToKafra(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_MoveFromKafra(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_MoveFromKafra(Session *s, dumb_ptr<map_session_data> sd) { - int item_index, item_amount; - - nullpo_retv(sd); + Packet_Fixed<0x00f5> fixed; + RecvResult rv = recv_fpacket<0x00f5, 8>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - item_index = RFIFOW(s, 2) - 1; - item_amount = RFIFOL(s, 4); + if (!fixed.soff1.ok()) + return RecvResult::Error; + SOff0 item_index = fixed.soff1.unshift(); + int item_amount = fixed.amount; - if ((sd->npc_id != 0 && !sd->npc_flags.storage) || sd->trade_partner != 0 + if ((sd->npc_id && !sd->npc_flags.storage) || sd->trade_partner || !sd->state.storage_open) - return; + return rv; if (sd->state.storage_open) storage_storageget(sd, item_index, item_amount); + + return rv; } /*========================================== @@ -4482,12 +4633,17 @@ void clif_parse_MoveFromKafra(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_CloseKafra(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_CloseKafra(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00f7> fixed; + RecvResult rv = recv_fpacket<0x00f7, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (sd->state.storage_open) storage_storageclose(sd); + + return rv; } /*========================================== @@ -4498,16 +4654,23 @@ void clif_parse_CloseKafra(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_CreateParty(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_CreateParty(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x00f9> fixed; + RecvResult rv = recv_fpacket<0x00f9, 26>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, SkillID::NV_PARTY) >= 2) { - PartyName name = stringish<PartyName>(RFIFO_STRING<24>(s, 2)); + PartyName name = fixed.party_name; party_create(sd, name); } else clif_skill_fail(sd, SkillID::ONE, 0, 4); + + return rv; } /*========================================== @@ -4518,9 +4681,16 @@ void clif_parse_CreateParty(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_PartyInvite(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_PartyInvite(Session *s, dumb_ptr<map_session_data> sd) { - party_invite(sd, RFIFOL(s, 2)); + Packet_Fixed<0x00fc> fixed; + RecvResult rv = recv_fpacket<0x00fc, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + party_invite(sd, fixed.account_id); + + return rv; } /*========================================== @@ -4531,18 +4701,25 @@ void clif_parse_PartyInvite(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_ReplyPartyInvite(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_ReplyPartyInvite(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x00ff> fixed; + RecvResult rv = recv_fpacket<0x00ff, 10>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, SkillID::NV_PARTY) >= 1) { - party_reply_invite(sd, RFIFOL(s, 2), RFIFOL(s, 6)); + party_reply_invite(sd, fixed.account_id, fixed.flag); } else { - party_reply_invite(sd, RFIFOL(s, 2), 0); + party_reply_invite(sd, fixed.account_id, 0); clif_skill_fail(sd, SkillID::ONE, 0, 4); } + + return rv; } /*========================================== @@ -4550,9 +4727,16 @@ void clif_parse_ReplyPartyInvite(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_LeaveParty(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_LeaveParty(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x0100> fixed; + RecvResult rv = recv_fpacket<0x0100, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + party_leave(sd); + + return rv; } /*========================================== @@ -4560,11 +4744,18 @@ void clif_parse_LeaveParty(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_RemovePartyMember(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_RemovePartyMember(Session *s, dumb_ptr<map_session_data> sd) { - int account_id = RFIFOL(s, 2); - // unused RFIFO_STRING<24>(fd, 6); + Packet_Fixed<0x0103> fixed; + RecvResult rv = recv_fpacket<0x0103, 30>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + AccountId account_id = fixed.account_id; + // unused fixed.unusedchar_name; party_removemember(sd, account_id); + + return rv; } /*========================================== @@ -4572,9 +4763,16 @@ void clif_parse_RemovePartyMember(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_PartyChangeOption(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_PartyChangeOption(Session *s, dumb_ptr<map_session_data> sd) { - party_changeoption(sd, RFIFOW(s, 2), RFIFOW(s, 4)); + Packet_Fixed<0x0102> fixed; + RecvResult rv = recv_fpacket<0x0102, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + party_changeoption(sd, fixed.exp, fixed.item); + + return rv; } /*========================================== @@ -4586,582 +4784,604 @@ void clif_parse_PartyChangeOption(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_PartyMessage(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_PartyMessage(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + AString repeat; + RecvResult rv = recv_packet_repeatonly<0x0108, 4, 1>(s, repeat); + if (rv != RecvResult::Complete) + return rv; - AString mbuf = clif_validate_chat(sd, ChatType::Party); + AString mbuf = clif_validate_chat(sd, ChatType::Party, repeat); if (!mbuf) { - clif_displaymessage(s, "Your message could not be sent."); - return; + clif_displaymessage(s, "Your message could not be sent."_s); + return rv; } - if (is_atcommand(s, sd, mbuf, 0)) - return; + if (is_atcommand(s, sd, mbuf, GmLevel())) + return rv; /* Don't send chat that results in an automatic ban. */ if (tmw_CheckChatSpam(sd, mbuf)) { - clif_displaymessage(s, "Your message could not be sent."); - return; + clif_displaymessage(s, "Your message could not be sent."_s); + return rv; } party_send_message(sd, mbuf); + + return rv; } func_table clif_parse_func_table[0x0220] = { - {0, 10, NULL, }, // 0x0000 - {0, 0, NULL, }, // 0x0001 - {0, 0, NULL, }, // 0x0002 - {0, 0, NULL, }, // 0x0003 - {0, 0, NULL, }, // 0x0004 - {0, 0, NULL, }, // 0x0005 - {0, 0, NULL, }, // 0x0006 - {0, 0, NULL, }, // 0x0007 - {0, 0, NULL, }, // 0x0008 - {0, 0, NULL, }, // 0x0009 - {0, 0, NULL, }, // 0x000a - {0, 0, NULL, }, // 0x000b - {0, 0, NULL, }, // 0x000c - {0, 0, NULL, }, // 0x000d - {0, 0, NULL, }, // 0x000e - {0, 0, NULL, }, // 0x000f - {0, 0, NULL, }, // 0x0010 - {0, 0, NULL, }, // 0x0011 - {0, 0, NULL, }, // 0x0012 - {0, 0, NULL, }, // 0x0013 - {0, 0, NULL, }, // 0x0014 - {0, 0, NULL, }, // 0x0015 - {0, 0, NULL, }, // 0x0016 - {0, 0, NULL, }, // 0x0017 - {0, 0, NULL, }, // 0x0018 - {0, 0, NULL, }, // 0x0019 - {0, 0, NULL, }, // 0x001a - {0, 0, NULL, }, // 0x001b - {0, 0, NULL, }, // 0x001c - {0, 0, NULL, }, // 0x001d - {0, 0, NULL, }, // 0x001e - {0, 0, NULL, }, // 0x001f - {0, 0, NULL, }, // 0x0020 - {0, 0, NULL, }, // 0x0021 - {0, 0, NULL, }, // 0x0022 - {0, 0, NULL, }, // 0x0023 - {0, 0, NULL, }, // 0x0024 - {0, 0, NULL, }, // 0x0025 - {0, 0, NULL, }, // 0x0026 - {0, 0, NULL, }, // 0x0027 - {0, 0, NULL, }, // 0x0028 - {0, 0, NULL, }, // 0x0029 - {0, 0, NULL, }, // 0x002a - {0, 0, NULL, }, // 0x002b - {0, 0, NULL, }, // 0x002c - {0, 0, NULL, }, // 0x002d - {0, 0, NULL, }, // 0x002e - {0, 0, NULL, }, // 0x002f - {0, 0, NULL, }, // 0x0030 - {0, 0, NULL, }, // 0x0031 - {0, 0, NULL, }, // 0x0032 - {0, 0, NULL, }, // 0x0033 - {0, 0, NULL, }, // 0x0034 - {0, 0, NULL, }, // 0x0035 - {0, 0, NULL, }, // 0x0036 - {0, 0, NULL, }, // 0x0037 - {0, 0, NULL, }, // 0x0038 - {0, 0, NULL, }, // 0x0039 - {0, 0, NULL, }, // 0x003a - {0, 0, NULL, }, // 0x003b - {0, 0, NULL, }, // 0x003c - {0, 0, NULL, }, // 0x003d - {0, 0, NULL, }, // 0x003e - {0, 0, NULL, }, // 0x003f - {0, 0, NULL, }, // 0x0040 - {0, 0, NULL, }, // 0x0041 - {0, 0, NULL, }, // 0x0042 - {0, 0, NULL, }, // 0x0043 - {0, 0, NULL, }, // 0x0044 - {0, 0, NULL, }, // 0x0045 - {0, 0, NULL, }, // 0x0046 - {0, 0, NULL, }, // 0x0047 - {0, 0, NULL, }, // 0x0048 - {0, 0, NULL, }, // 0x0049 - {0, 0, NULL, }, // 0x004a - {0, 0, NULL, }, // 0x004b - {0, 0, NULL, }, // 0x004c - {0, 0, NULL, }, // 0x004d - {0, 0, NULL, }, // 0x004e - {0, 0, NULL, }, // 0x004f - {0, 0, NULL, }, // 0x0050 - {0, 0, NULL, }, // 0x0051 - {0, 0, NULL, }, // 0x0052 - {0, 0, NULL, }, // 0x0053 - {0, 0, NULL, }, // 0x0054 - {0, 0, NULL, }, // 0x0055 - {0, 0, NULL, }, // 0x0056 - {0, 0, NULL, }, // 0x0057 - {0, 0, NULL, }, // 0x0058 - {0, 0, NULL, }, // 0x0059 - {0, 0, NULL, }, // 0x005a - {0, 0, NULL, }, // 0x005b - {0, 0, NULL, }, // 0x005c - {0, 0, NULL, }, // 0x005d - {0, 0, NULL, }, // 0x005e - {0, 0, NULL, }, // 0x005f - {0, 0, NULL, }, // 0x0060 - {0, 0, NULL, }, // 0x0061 - {0, 0, NULL, }, // 0x0062 - {0, VAR,NULL, }, // 0x0063 - {0, 55, NULL, }, // 0x0064 - {0, 17, NULL, }, // 0x0065 - {0, 3, NULL, }, // 0x0066 - {0, 37, NULL, }, // 0x0067 - {0, 46, NULL, }, // 0x0068 - {0, VAR,NULL, }, // 0x0069 - {0, 23, NULL, }, // 0x006a - {0, VAR,NULL, }, // 0x006b - {0, 3, NULL, }, // 0x006c - {0, 108,NULL, }, // 0x006d - {0, 3, NULL, }, // 0x006e - {0, 2, NULL, }, // 0x006f - {0, 3, NULL, }, // 0x0070 - {0, 28, NULL, }, // 0x0071 + {0, 10, nullptr, }, // 0x0000 + {0, 0, nullptr, }, // 0x0001 + {0, 0, nullptr, }, // 0x0002 + {0, 0, nullptr, }, // 0x0003 + {0, 0, nullptr, }, // 0x0004 + {0, 0, nullptr, }, // 0x0005 + {0, 0, nullptr, }, // 0x0006 + {0, 0, nullptr, }, // 0x0007 + {0, 0, nullptr, }, // 0x0008 + {0, 0, nullptr, }, // 0x0009 + {0, 0, nullptr, }, // 0x000a + {0, 0, nullptr, }, // 0x000b + {0, 0, nullptr, }, // 0x000c + {0, 0, nullptr, }, // 0x000d + {0, 0, nullptr, }, // 0x000e + {0, 0, nullptr, }, // 0x000f + {0, 0, nullptr, }, // 0x0010 + {0, 0, nullptr, }, // 0x0011 + {0, 0, nullptr, }, // 0x0012 + {0, 0, nullptr, }, // 0x0013 + {0, 0, nullptr, }, // 0x0014 + {0, 0, nullptr, }, // 0x0015 + {0, 0, nullptr, }, // 0x0016 + {0, 0, nullptr, }, // 0x0017 + {0, 0, nullptr, }, // 0x0018 + {0, 0, nullptr, }, // 0x0019 + {0, 0, nullptr, }, // 0x001a + {0, 0, nullptr, }, // 0x001b + {0, 0, nullptr, }, // 0x001c + {0, 0, nullptr, }, // 0x001d + {0, 0, nullptr, }, // 0x001e + {0, 0, nullptr, }, // 0x001f + {0, 0, nullptr, }, // 0x0020 + {0, 0, nullptr, }, // 0x0021 + {0, 0, nullptr, }, // 0x0022 + {0, 0, nullptr, }, // 0x0023 + {0, 0, nullptr, }, // 0x0024 + {0, 0, nullptr, }, // 0x0025 + {0, 0, nullptr, }, // 0x0026 + {0, 0, nullptr, }, // 0x0027 + {0, 0, nullptr, }, // 0x0028 + {0, 0, nullptr, }, // 0x0029 + {0, 0, nullptr, }, // 0x002a + {0, 0, nullptr, }, // 0x002b + {0, 0, nullptr, }, // 0x002c + {0, 0, nullptr, }, // 0x002d + {0, 0, nullptr, }, // 0x002e + {0, 0, nullptr, }, // 0x002f + {0, 0, nullptr, }, // 0x0030 + {0, 0, nullptr, }, // 0x0031 + {0, 0, nullptr, }, // 0x0032 + {0, 0, nullptr, }, // 0x0033 + {0, 0, nullptr, }, // 0x0034 + {0, 0, nullptr, }, // 0x0035 + {0, 0, nullptr, }, // 0x0036 + {0, 0, nullptr, }, // 0x0037 + {0, 0, nullptr, }, // 0x0038 + {0, 0, nullptr, }, // 0x0039 + {0, 0, nullptr, }, // 0x003a + {0, 0, nullptr, }, // 0x003b + {0, 0, nullptr, }, // 0x003c + {0, 0, nullptr, }, // 0x003d + {0, 0, nullptr, }, // 0x003e + {0, 0, nullptr, }, // 0x003f + {0, 0, nullptr, }, // 0x0040 + {0, 0, nullptr, }, // 0x0041 + {0, 0, nullptr, }, // 0x0042 + {0, 0, nullptr, }, // 0x0043 + {0, 0, nullptr, }, // 0x0044 + {0, 0, nullptr, }, // 0x0045 + {0, 0, nullptr, }, // 0x0046 + {0, 0, nullptr, }, // 0x0047 + {0, 0, nullptr, }, // 0x0048 + {0, 0, nullptr, }, // 0x0049 + {0, 0, nullptr, }, // 0x004a + {0, 0, nullptr, }, // 0x004b + {0, 0, nullptr, }, // 0x004c + {0, 0, nullptr, }, // 0x004d + {0, 0, nullptr, }, // 0x004e + {0, 0, nullptr, }, // 0x004f + {0, 0, nullptr, }, // 0x0050 + {0, 0, nullptr, }, // 0x0051 + {0, 0, nullptr, }, // 0x0052 + {0, 0, nullptr, }, // 0x0053 + {0, 0, nullptr, }, // 0x0054 + {0, 0, nullptr, }, // 0x0055 + {0, 0, nullptr, }, // 0x0056 + {0, 0, nullptr, }, // 0x0057 + {0, 0, nullptr, }, // 0x0058 + {0, 0, nullptr, }, // 0x0059 + {0, 0, nullptr, }, // 0x005a + {0, 0, nullptr, }, // 0x005b + {0, 0, nullptr, }, // 0x005c + {0, 0, nullptr, }, // 0x005d + {0, 0, nullptr, }, // 0x005e + {0, 0, nullptr, }, // 0x005f + {0, 0, nullptr, }, // 0x0060 + {0, 0, nullptr, }, // 0x0061 + {0, 0, nullptr, }, // 0x0062 + {0, VAR,nullptr, }, // 0x0063 + {0, 55, nullptr, }, // 0x0064 + {0, 17, nullptr, }, // 0x0065 + {0, 3, nullptr, }, // 0x0066 + {0, 37, nullptr, }, // 0x0067 + {0, 46, nullptr, }, // 0x0068 + {0, VAR,nullptr, }, // 0x0069 + {0, 23, nullptr, }, // 0x006a + {0, VAR,nullptr, }, // 0x006b + {0, 3, nullptr, }, // 0x006c + {0, 108,nullptr, }, // 0x006d + {0, 3, nullptr, }, // 0x006e + {0, 2, nullptr, }, // 0x006f + {0, 3, nullptr, }, // 0x0070 + {0, 28, nullptr, }, // 0x0071 {0, 19, clif_parse_WantToConnection, }, // 0x0072 - {0, 11, NULL, }, // 0x0073 - {0, 3, NULL, }, // 0x0074 - {0, VAR,NULL, }, // 0x0075 - {0, 9, NULL, }, // 0x0076 - {0, 5, NULL, }, // 0x0077 - {0, 54, NULL, }, // 0x0078 - {0, 53, NULL, }, // 0x0079 - {0, 58, NULL, }, // 0x007a - {0, 60, NULL, }, // 0x007b - {0, 41, NULL, }, // 0x007c + {0, 11, nullptr, }, // 0x0073 + {0, 3, nullptr, }, // 0x0074 + {0, VAR,nullptr, }, // 0x0075 + {0, 9, nullptr, }, // 0x0076 + {0, 5, nullptr, }, // 0x0077 + {0, 54, nullptr, }, // 0x0078 + {0, 53, nullptr, }, // 0x0079 + {0, 58, nullptr, }, // 0x007a + {0, 60, nullptr, }, // 0x007b + {0, 41, nullptr, }, // 0x007c {-1, 2, clif_parse_LoadEndAck, }, // 0x007d {0, 6, clif_parse_TickSend, }, // 0x007e - {0, 6, NULL, }, // 0x007f - {0, 7, NULL, }, // 0x0080 - {0, 3, NULL, }, // 0x0081 - {0, 2, NULL, }, // 0x0082 - {0, 2, NULL, }, // 0x0083 - {0, 2, NULL, }, // 0x0084 + {0, 6, nullptr, }, // 0x007f + {0, 7, nullptr, }, // 0x0080 + {0, 3, nullptr, }, // 0x0081 + {0, 2, nullptr, }, // 0x0082 + {0, 2, nullptr, }, // 0x0083 + {0, 2, nullptr, }, // 0x0084 {-1, 5, clif_parse_WalkToXY, }, // 0x0085 Walk code limits this on it's own - {0, 16, NULL, }, // 0x0086 - {0, 12, NULL, }, // 0x0087 - {0, 10, NULL, }, // 0x0088 + {0, 16, nullptr, }, // 0x0086 + {0, 12, nullptr, }, // 0x0087 + {0, 10, nullptr, }, // 0x0088 {1000, 7, clif_parse_ActionRequest, }, // 0x0089 Special case - see below - {0, 29, NULL, }, // 0x008a - {0, 23, NULL, }, // 0x008b unknown... size 2 or 23? + {0, 29, nullptr, }, // 0x008a + {0, 23, nullptr, }, // 0x008b unknown... size 2 or 23? {300, VAR,clif_parse_GlobalMessage, }, // 0x008c - {0, VAR,NULL, }, // 0x008d - {0, VAR,NULL, }, // 0x008e - {0, 0, NULL, }, // 0x008f + {0, VAR,nullptr, }, // 0x008d + {0, VAR,nullptr, }, // 0x008e + {0, 0, nullptr, }, // 0x008f {500, 7, clif_parse_NpcClicked, }, // 0x0090 - {0, 22, NULL, }, // 0x0091 - {0, 28, NULL, }, // 0x0092 - {0, 2, NULL, }, // 0x0093 + {0, 22, nullptr, }, // 0x0091 + {0, 28, nullptr, }, // 0x0092 + {0, 2, nullptr, }, // 0x0093 {-1, 6, clif_parse_GetCharNameRequest, }, // 0x0094 - {0, 30, NULL, }, // 0x0095 + {0, 30, nullptr, }, // 0x0095 {300, VAR,clif_parse_Wis, }, // 0x0096 - {0, VAR,NULL, }, // 0x0097 - {0, 3, NULL, }, // 0x0098 - {300, VAR,NULL, }, // 0x0099 - {0, VAR,NULL, }, // 0x009a + {0, VAR,nullptr, }, // 0x0097 + {0, 3, nullptr, }, // 0x0098 + {300, VAR,nullptr, }, // 0x0099 + {0, VAR,nullptr, }, // 0x009a {-1, 5, clif_parse_ChangeDir, }, // 0x009b - {0, 9, NULL, }, // 0x009c - {0, 17, NULL, }, // 0x009d - {0, 17, NULL, }, // 0x009e + {0, 9, nullptr, }, // 0x009c + {0, 17, nullptr, }, // 0x009d + {0, 17, nullptr, }, // 0x009e {400, 6, clif_parse_TakeItem, }, // 0x009f - {0, 23, NULL, }, // 0x00a0 - {0, 6, NULL, }, // 0x00a1 + {0, 23, nullptr, }, // 0x00a0 + {0, 6, nullptr, }, // 0x00a1 {50, 6, clif_parse_DropItem, }, // 0x00a2 - {0, VAR,NULL, }, // 0x00a3 - {0, VAR,NULL, }, // 0x00a4 - {0, VAR,NULL, }, // 0x00a5 - {0, VAR,NULL, }, // 0x00a6 + {0, VAR,nullptr, }, // 0x00a3 + {0, VAR,nullptr, }, // 0x00a4 + {0, VAR,nullptr, }, // 0x00a5 + {0, VAR,nullptr, }, // 0x00a6 {0, 8, clif_parse_UseItem, }, // 0x00a7 - {0, 7, NULL, }, // 0x00a8 + {0, 7, nullptr, }, // 0x00a8 {-1, 6, clif_parse_EquipItem, }, // 0x00a9 Special case - outfit window (not implemented yet - needs to allow bursts) - {0, 7, NULL, }, // 0x00aa + {0, 7, nullptr, }, // 0x00aa {-1, 4, clif_parse_UnequipItem, }, // 0x00ab Special case - outfit window (not implemented yet - needs to allow bursts) - {0, 7, NULL, }, // 0x00ac - {0, 0, NULL, }, // 0x00ad - {0, VAR,NULL, }, // 0x00ae - {0, 6, NULL, }, // 0x00af - {0, 8, NULL, }, // 0x00b0 - {0, 8, NULL, }, // 0x00b1 + {0, 7, nullptr, }, // 0x00ac + {0, 0, nullptr, }, // 0x00ad + {0, VAR,nullptr, }, // 0x00ae + {0, 6, nullptr, }, // 0x00af + {0, 8, nullptr, }, // 0x00b0 + {0, 8, nullptr, }, // 0x00b1 {0, 3, clif_parse_Restart, }, // 0x00b2 - {0, 3, NULL, }, // 0x00b3 - {0, VAR,NULL, }, // 0x00b4 - {0, 6, NULL, }, // 0x00b5 - {0, 6, NULL, }, // 0x00b6 - {0, VAR,NULL, }, // 0x00b7 + {0, 3, nullptr, }, // 0x00b3 + {0, VAR,nullptr, }, // 0x00b4 + {0, 6, nullptr, }, // 0x00b5 + {0, 6, nullptr, }, // 0x00b6 + {0, VAR,nullptr, }, // 0x00b7 {0, 7, clif_parse_NpcSelectMenu, }, // 0x00b8 {-1, 6, clif_parse_NpcNextClicked, }, // 0x00b9 - {0, 2, NULL, }, // 0x00ba + {0, 2, nullptr, }, // 0x00ba {-1, 5, clif_parse_StatusUp, }, // 0x00bb People click this very quickly - {0, 6, NULL, }, // 0x00bc - {0, 44, NULL, }, // 0x00bd - {0, 5, NULL, }, // 0x00be + {0, 6, nullptr, }, // 0x00bc + {0, 44, nullptr, }, // 0x00bd + {0, 5, nullptr, }, // 0x00be {1000, 3, clif_parse_Emotion, }, // 0x00bf - {0, 7, NULL, }, // 0x00c0 + {0, 7, nullptr, }, // 0x00c0 {0, 2, clif_parse_HowManyConnections, }, // 0x00c1 - {0, 6, NULL, }, // 0x00c2 - {0, 8, NULL, }, // 0x00c3 - {0, 6, NULL, }, // 0x00c4 + {0, 6, nullptr, }, // 0x00c2 + {0, 8, nullptr, }, // 0x00c3 + {0, 6, nullptr, }, // 0x00c4 {0, 7, clif_parse_NpcBuySellSelected, }, // 0x00c5 - {0, VAR,NULL, }, // 0x00c6 - {0, VAR,NULL, }, // 0x00c7 + {0, VAR,nullptr, }, // 0x00c6 + {0, VAR,nullptr, }, // 0x00c7 {-1, VAR,clif_parse_NpcBuyListSend, }, // 0x00c8 {-1, VAR,clif_parse_NpcSellListSend, }, // 0x00c9 Selling multiple 1-slot items - {0, 3, NULL, }, // 0x00ca - {0, 3, NULL, }, // 0x00cb - {0, 6, NULL, }, // 0x00cc - {0, 6, NULL, }, // 0x00cd - {0, 2, NULL, }, // 0x00ce - {0, 27, NULL, }, // 0x00cf - {0, 3, NULL, }, // 0x00d0 - {0, 4, NULL, }, // 0x00d1 - {0, 4, NULL, }, // 0x00d2 - {0, 2, NULL, }, // 0x00d3 - {0, VAR,NULL, }, // 0x00d4 - {0, VAR,NULL, }, // 0x00d5 - {0, 3, NULL, }, // 0x00d6 - {0, VAR,NULL, }, // 0x00d7 - {0, 6, NULL, }, // 0x00d8 - {0, 14, NULL, }, // 0x00d9 - {0, 3, NULL, }, // 0x00da - {0, VAR,NULL, }, // 0x00db - {0, 28, NULL, }, // 0x00dc - {0, 29, NULL, }, // 0x00dd - {0, VAR,NULL, }, // 0x00de - {0, VAR,NULL, }, // 0x00df - {0, 30, NULL, }, // 0x00e0 - {0, 30, NULL, }, // 0x00e1 - {0, 26, NULL, }, // 0x00e2 - {0, 2, NULL, }, // 0x00e3 + {0, 3, nullptr, }, // 0x00ca + {0, 3, nullptr, }, // 0x00cb + {0, 6, nullptr, }, // 0x00cc + {0, 6, nullptr, }, // 0x00cd + {0, 2, nullptr, }, // 0x00ce + {0, 27, nullptr, }, // 0x00cf + {0, 3, nullptr, }, // 0x00d0 + {0, 4, nullptr, }, // 0x00d1 + {0, 4, nullptr, }, // 0x00d2 + {0, 2, nullptr, }, // 0x00d3 + {0, VAR,nullptr, }, // 0x00d4 + {0, VAR,nullptr, }, // 0x00d5 + {0, 3, nullptr, }, // 0x00d6 + {0, VAR,nullptr, }, // 0x00d7 + {0, 6, nullptr, }, // 0x00d8 + {0, 14, nullptr, }, // 0x00d9 + {0, 3, nullptr, }, // 0x00da + {0, VAR,nullptr, }, // 0x00db + {0, 28, nullptr, }, // 0x00dc + {0, 29, nullptr, }, // 0x00dd + {0, VAR,nullptr, }, // 0x00de + {0, VAR,nullptr, }, // 0x00df + {0, 30, nullptr, }, // 0x00e0 + {0, 30, nullptr, }, // 0x00e1 + {0, 26, nullptr, }, // 0x00e2 + {0, 2, nullptr, }, // 0x00e3 {2000, 6, clif_parse_TradeRequest, }, // 0x00e4 - {0, 26, NULL, }, // 0x00e5 + {0, 26, nullptr, }, // 0x00e5 {0, 3, clif_parse_TradeAck, }, // 0x00e6 - {0, 3, NULL, }, // 0x00e7 + {0, 3, nullptr, }, // 0x00e7 {0, 8, clif_parse_TradeAddItem, }, // 0x00e8 - {0, 19, NULL, }, // 0x00e9 - {0, 5, NULL, }, // 0x00ea + {0, 19, nullptr, }, // 0x00e9 + {0, 5, nullptr, }, // 0x00ea {0, 2, clif_parse_TradeOk, }, // 0x00eb - {0, 3, NULL, }, // 0x00ec + {0, 3, nullptr, }, // 0x00ec {0, 2, clif_parse_TradeCansel, }, // 0x00ed - {0, 2, NULL, }, // 0x00ee + {0, 2, nullptr, }, // 0x00ee {0, 2, clif_parse_TradeCommit, }, // 0x00ef - {0, 3, NULL, }, // 0x00f0 - {0, 2, NULL, }, // 0x00f1 - {0, 6, NULL, }, // 0x00f2 + {0, 3, nullptr, }, // 0x00f0 + {0, 2, nullptr, }, // 0x00f1 + {0, 6, nullptr, }, // 0x00f2 {-1, 8, clif_parse_MoveToKafra, }, // 0x00f3 - {0, 21, NULL, }, // 0x00f4 + {0, 21, nullptr, }, // 0x00f4 {-1, 8, clif_parse_MoveFromKafra, }, // 0x00f5 - {0, 8, NULL, }, // 0x00f6 + {0, 8, nullptr, }, // 0x00f6 {0, 2, clif_parse_CloseKafra, }, // 0x00f7 - {0, 2, NULL, }, // 0x00f8 + {0, 2, nullptr, }, // 0x00f8 {2000, 26, clif_parse_CreateParty, }, // 0x00f9 - {0, 3, NULL, }, // 0x00fa - {0, VAR,NULL, }, // 0x00fb + {0, 3, nullptr, }, // 0x00fa + {0, VAR,nullptr, }, // 0x00fb {2000, 6, clif_parse_PartyInvite, }, // 0x00fc - {0, 27, NULL, }, // 0x00fd - {0, 30, NULL, }, // 0x00fe + {0, 27, nullptr, }, // 0x00fd + {0, 30, nullptr, }, // 0x00fe {0, 10, clif_parse_ReplyPartyInvite, }, // 0x00ff {0, 2, clif_parse_LeaveParty, }, // 0x0100 - {0, 6, NULL, }, // 0x0101 + {0, 6, nullptr, }, // 0x0101 {0, 6, clif_parse_PartyChangeOption, }, // 0x0102 {0, 30, clif_parse_RemovePartyMember, }, // 0x0103 - {0, 79, NULL, }, // 0x0104 - {0, 31, NULL, }, // 0x0105 - {0, 10, NULL, }, // 0x0106 - {0, 10, NULL, }, // 0x0107 + {0, 79, nullptr, }, // 0x0104 + {0, 31, nullptr, }, // 0x0105 + {0, 10, nullptr, }, // 0x0106 + {0, 10, nullptr, }, // 0x0107 {300, VAR,clif_parse_PartyMessage, }, // 0x0108 - {0, VAR,NULL, }, // 0x0109 - {0, 4, NULL, }, // 0x010a - {0, 6, NULL, }, // 0x010b - {0, 6, NULL, }, // 0x010c - {0, 2, NULL, }, // 0x010d - {0, 11, NULL, }, // 0x010e - {0, VAR,NULL, }, // 0x010f - {0, 10, NULL, }, // 0x0110 - {0, 39, NULL, }, // 0x0111 + {0, VAR,nullptr, }, // 0x0109 + {0, 4, nullptr, }, // 0x010a + {0, 6, nullptr, }, // 0x010b + {0, 6, nullptr, }, // 0x010c + {0, 2, nullptr, }, // 0x010d + {0, 11, nullptr, }, // 0x010e + {0, VAR,nullptr, }, // 0x010f + {0, 10, nullptr, }, // 0x0110 + {0, 39, nullptr, }, // 0x0111 {-1, 4, clif_parse_SkillUp, }, // 0x0112 - {0, 10, NULL, }, // 0x0113 - {0, 31, NULL, }, // 0x0114 - {0, 35, NULL, }, // 0x0115 - {0, 10, NULL, }, // 0x0116 - {0, 18, NULL, }, // 0x0117 + {0, 10, nullptr, }, // 0x0113 + {0, 31, nullptr, }, // 0x0114 + {0, 35, nullptr, }, // 0x0115 + {0, 10, nullptr, }, // 0x0116 + {0, 18, nullptr, }, // 0x0117 {0, 2, clif_parse_StopAttack, }, // 0x0118 - {0, 13, NULL, }, // 0x0119 - {0, 15, NULL, }, // 0x011a - {0, 20, NULL, }, // 0x011b - {0, 68, NULL, }, // 0x011c - {0, 2, NULL, }, // 0x011d - {0, 3, NULL, }, // 0x011e - {0, 16, NULL, }, // 0x011f - {0, 6, NULL, }, // 0x0120 - {0, 14, NULL, }, // 0x0121 - {0, VAR,NULL, }, // 0x0122 - {0, VAR,NULL, }, // 0x0123 - {0, 21, NULL, }, // 0x0124 - {0, 8, NULL, }, // 0x0125 - {0, 8, NULL, }, // 0x0126 - {0, 8, NULL, }, // 0x0127 - {0, 8, NULL, }, // 0x0128 - {0, 8, NULL, }, // 0x0129 - {0, 2, NULL, }, // 0x012a - {0, 2, NULL, }, // 0x012b - {0, 3, NULL, }, // 0x012c - {0, 4, NULL, }, // 0x012d - {0, 2, NULL, }, // 0x012e - {0, VAR,NULL, }, // 0x012f - {0, 6, NULL, }, // 0x0130 - {0, 86, NULL, }, // 0x0131 - {0, 6, NULL, }, // 0x0132 - {0, VAR,NULL, }, // 0x0133 - {0, VAR,NULL, }, // 0x0134 - {0, 7, NULL, }, // 0x0135 - {0, VAR,NULL, }, // 0x0136 - {0, 6, NULL, }, // 0x0137 - {0, 3, NULL, }, // 0x0138 - {0, 16, NULL, }, // 0x0139 - {0, 4, NULL, }, // 0x013a - {0, 4, NULL, }, // 0x013b - {0, 4, NULL, }, // 0x013c - {0, 6, NULL, }, // 0x013d - {0, 24, NULL, }, // 0x013e - {0, 26, NULL, }, // 0x013f - {0, 22, NULL, }, // 0x0140 - {0, 14, NULL, }, // 0x0141 - {0, 6, NULL, }, // 0x0142 + {0, 13, nullptr, }, // 0x0119 + {0, 15, nullptr, }, // 0x011a + {0, 20, nullptr, }, // 0x011b + {0, 68, nullptr, }, // 0x011c + {0, 2, nullptr, }, // 0x011d + {0, 3, nullptr, }, // 0x011e + {0, 16, nullptr, }, // 0x011f + {0, 6, nullptr, }, // 0x0120 + {0, 14, nullptr, }, // 0x0121 + {0, VAR,nullptr, }, // 0x0122 + {0, VAR,nullptr, }, // 0x0123 + {0, 21, nullptr, }, // 0x0124 + {0, 8, nullptr, }, // 0x0125 + {0, 8, nullptr, }, // 0x0126 + {0, 8, nullptr, }, // 0x0127 + {0, 8, nullptr, }, // 0x0128 + {0, 8, nullptr, }, // 0x0129 + {0, 2, nullptr, }, // 0x012a + {0, 2, nullptr, }, // 0x012b + {0, 3, nullptr, }, // 0x012c + {0, 4, nullptr, }, // 0x012d + {0, 2, nullptr, }, // 0x012e + {0, VAR,nullptr, }, // 0x012f + {0, 6, nullptr, }, // 0x0130 + {0, 86, nullptr, }, // 0x0131 + {0, 6, nullptr, }, // 0x0132 + {0, VAR,nullptr, }, // 0x0133 + {0, VAR,nullptr, }, // 0x0134 + {0, 7, nullptr, }, // 0x0135 + {0, VAR,nullptr, }, // 0x0136 + {0, 6, nullptr, }, // 0x0137 + {0, 3, nullptr, }, // 0x0138 + {0, 16, nullptr, }, // 0x0139 + {0, 4, nullptr, }, // 0x013a + {0, 4, nullptr, }, // 0x013b + {0, 4, nullptr, }, // 0x013c + {0, 6, nullptr, }, // 0x013d + {0, 24, nullptr, }, // 0x013e + {0, 26, nullptr, }, // 0x013f + {0, 22, nullptr, }, // 0x0140 + {0, 14, nullptr, }, // 0x0141 + {0, 6, nullptr, }, // 0x0142 {300, 10, clif_parse_NpcAmountInput, }, // 0x0143 - {0, 23, NULL, }, // 0x0144 - {0, 19, NULL, }, // 0x0145 + {0, 23, nullptr, }, // 0x0144 + {0, 19, nullptr, }, // 0x0145 {300, 6, clif_parse_NpcCloseClicked, }, // 0x0146 - {0, 39, NULL, }, // 0x0147 - {0, 8, NULL, }, // 0x0148 - {0, 9, NULL, }, // 0x0149 - {0, 6, NULL, }, // 0x014a - {0, 27, NULL, }, // 0x014b - {0, VAR,NULL, }, // 0x014c - {0, 2, NULL, }, // 0x014d - {0, 6, NULL, }, // 0x014e - {0, 6, NULL, }, // 0x014f - {0, 110,NULL, }, // 0x0150 - {0, 6, NULL, }, // 0x0151 - {0, VAR,NULL, }, // 0x0152 - {0, VAR,NULL, }, // 0x0153 - {0, VAR,NULL, }, // 0x0154 - {0, VAR,NULL, }, // 0x0155 - {0, VAR,NULL, }, // 0x0156 - {0, 6, NULL, }, // 0x0157 - {0, VAR,NULL, }, // 0x0158 - {0, 54, NULL, }, // 0x0159 - {0, 66, NULL, }, // 0x015a - {0, 54, NULL, }, // 0x015b - {0, 90, NULL, }, // 0x015c - {0, 42, NULL, }, // 0x015d - {0, 6, NULL, }, // 0x015e - {0, 42, NULL, }, // 0x015f - {0, VAR,NULL, }, // 0x0160 - {0, VAR,NULL, }, // 0x0161 - {0, VAR,NULL, }, // 0x0162 - {0, VAR,NULL, }, // 0x0163 - {0, VAR,NULL, }, // 0x0164 - {0, 30, NULL, }, // 0x0165 - {0, VAR,NULL, }, // 0x0166 - {0, 3, NULL, }, // 0x0167 - {0, 14, NULL, }, // 0x0168 - {0, 3, NULL, }, // 0x0169 - {0, 30, NULL, }, // 0x016a - {0, 10, NULL, }, // 0x016b - {0, 43, NULL, }, // 0x016c - {0, 14, NULL, }, // 0x016d - {0, 186,NULL, }, // 0x016e - {0, 182,NULL, }, // 0x016f - {0, 14, NULL, }, // 0x0170 - {0, 30, NULL, }, // 0x0171 - {0, 10, NULL, }, // 0x0172 - {0, 3, NULL, }, // 0x0173 - {0, VAR,NULL, }, // 0x0174 - {0, 6, NULL, }, // 0x0175 - {0, 106,NULL, }, // 0x0176 - {0, VAR,NULL, }, // 0x0177 - {0, 4, NULL, }, // 0x0178 - {0, 5, NULL, }, // 0x0179 - {0, 4, NULL, }, // 0x017a - {0, VAR,NULL, }, // 0x017b - {0, 6, NULL, }, // 0x017c - {0, 7, NULL, }, // 0x017d - {0, VAR,NULL, }, // 0x017e - {0, VAR,NULL, }, // 0x017f - {0, 6, NULL, }, // 0x0180 - {0, 3, NULL, }, // 0x0181 - {0, 106,NULL, }, // 0x0182 - {0, 10, NULL, }, // 0x0183 - {0, 10, NULL, }, // 0x0184 - {0, 34, NULL, }, // 0x0185 - {0, 0, NULL, }, // 0x0186 - {0, 6, NULL, }, // 0x0187 - {0, 8, NULL, }, // 0x0188 - {0, 4, NULL, }, // 0x0189 + {0, 39, nullptr, }, // 0x0147 + {0, 8, nullptr, }, // 0x0148 + {0, 9, nullptr, }, // 0x0149 + {0, 6, nullptr, }, // 0x014a + {0, 27, nullptr, }, // 0x014b + {0, VAR,nullptr, }, // 0x014c + {0, 2, nullptr, }, // 0x014d + {0, 6, nullptr, }, // 0x014e + {0, 6, nullptr, }, // 0x014f + {0, 110,nullptr, }, // 0x0150 + {0, 6, nullptr, }, // 0x0151 + {0, VAR,nullptr, }, // 0x0152 + {0, VAR,nullptr, }, // 0x0153 + {0, VAR,nullptr, }, // 0x0154 + {0, VAR,nullptr, }, // 0x0155 + {0, VAR,nullptr, }, // 0x0156 + {0, 6, nullptr, }, // 0x0157 + {0, VAR,nullptr, }, // 0x0158 + {0, 54, nullptr, }, // 0x0159 + {0, 66, nullptr, }, // 0x015a + {0, 54, nullptr, }, // 0x015b + {0, 90, nullptr, }, // 0x015c + {0, 42, nullptr, }, // 0x015d + {0, 6, nullptr, }, // 0x015e + {0, 42, nullptr, }, // 0x015f + {0, VAR,nullptr, }, // 0x0160 + {0, VAR,nullptr, }, // 0x0161 + {0, VAR,nullptr, }, // 0x0162 + {0, VAR,nullptr, }, // 0x0163 + {0, VAR,nullptr, }, // 0x0164 + {0, 30, nullptr, }, // 0x0165 + {0, VAR,nullptr, }, // 0x0166 + {0, 3, nullptr, }, // 0x0167 + {0, 14, nullptr, }, // 0x0168 + {0, 3, nullptr, }, // 0x0169 + {0, 30, nullptr, }, // 0x016a + {0, 10, nullptr, }, // 0x016b + {0, 43, nullptr, }, // 0x016c + {0, 14, nullptr, }, // 0x016d + {0, 186,nullptr, }, // 0x016e + {0, 182,nullptr, }, // 0x016f + {0, 14, nullptr, }, // 0x0170 + {0, 30, nullptr, }, // 0x0171 + {0, 10, nullptr, }, // 0x0172 + {0, 3, nullptr, }, // 0x0173 + {0, VAR,nullptr, }, // 0x0174 + {0, 6, nullptr, }, // 0x0175 + {0, 106,nullptr, }, // 0x0176 + {0, VAR,nullptr, }, // 0x0177 + {0, 4, nullptr, }, // 0x0178 + {0, 5, nullptr, }, // 0x0179 + {0, 4, nullptr, }, // 0x017a + {0, VAR,nullptr, }, // 0x017b + {0, 6, nullptr, }, // 0x017c + {0, 7, nullptr, }, // 0x017d + {0, VAR,nullptr, }, // 0x017e + {0, VAR,nullptr, }, // 0x017f + {0, 6, nullptr, }, // 0x0180 + {0, 3, nullptr, }, // 0x0181 + {0, 106,nullptr, }, // 0x0182 + {0, 10, nullptr, }, // 0x0183 + {0, 10, nullptr, }, // 0x0184 + {0, 34, nullptr, }, // 0x0185 + {0, 0, nullptr, }, // 0x0186 + {0, 6, nullptr, }, // 0x0187 + {0, 8, nullptr, }, // 0x0188 + {0, 4, nullptr, }, // 0x0189 {0, 4, clif_parse_QuitGame, }, // 0x018a - {0, 4, NULL, }, // 0x018b - {0, 29, NULL, }, // 0x018c - {0, VAR,NULL, }, // 0x018d - {0, 10, NULL, }, // 0x018e - {0, 6, NULL, }, // 0x018f - {0, 90, NULL, }, // 0x0190 - {0, 86, NULL, }, // 0x0191 - {0, 24, NULL, }, // 0x0192 - {0, 6, NULL, }, // 0x0193 - {0, 30, NULL, }, // 0x0194 - {0, 102,NULL, }, // 0x0195 - {0, 9, NULL, }, // 0x0196 - {0, 4, NULL, }, // 0x0197 - {0, 8, NULL, }, // 0x0198 - {0, 4, NULL, }, // 0x0199 - {0, 14, NULL, }, // 0x019a - {0, 10, NULL, }, // 0x019b - {0, VAR,NULL, }, // 0x019c - {300, 6, NULL, }, // 0x019d - {0, 2, NULL, }, // 0x019e - {0, 6, NULL, }, // 0x019f - {0, 3, NULL, }, // 0x01a0 - {0, 3, NULL, }, // 0x01a1 - {0, 35, NULL, }, // 0x01a2 - {0, 5, NULL, }, // 0x01a3 - {0, 11, NULL, }, // 0x01a4 - {0, 26, NULL, }, // 0x01a5 - {0, VAR,NULL, }, // 0x01a6 - {0, 4, NULL, }, // 0x01a7 - {0, 4, NULL, }, // 0x01a8 - {0, 6, NULL, }, // 0x01a9 - {0, 10, NULL, }, // 0x01aa - {0, 12, NULL, }, // 0x01ab - {0, 6, NULL, }, // 0x01ac - {0, VAR,NULL, }, // 0x01ad - {0, 4, NULL, }, // 0x01ae - {0, 4, NULL, }, // 0x01af - {0, 11, NULL, }, // 0x01b0 - {0, 7, NULL, }, // 0x01b1 - {0, VAR,NULL, }, // 0x01b2 - {0, 67, NULL, }, // 0x01b3 - {0, 12, NULL, }, // 0x01b4 - {0, 18, NULL, }, // 0x01b5 - {0, 114,NULL, }, // 0x01b6 - {0, 6, NULL, }, // 0x01b7 - {0, 3, NULL, }, // 0x01b8 - {0, 6, NULL, }, // 0x01b9 - {0, 26, NULL, }, // 0x01ba - {0, 26, NULL, }, // 0x01bb - {0, 26, NULL, }, // 0x01bc - {0, 26, NULL, }, // 0x01bd - {0, 2, NULL, }, // 0x01be - {0, 3, NULL, }, // 0x01bf - {0, 2, NULL, }, // 0x01c0 - {0, 14, NULL, }, // 0x01c1 - {0, 10, NULL, }, // 0x01c2 - {0, VAR,NULL, }, // 0x01c3 - {0, 22, NULL, }, // 0x01c4 - {0, 22, NULL, }, // 0x01c5 - {0, 4, NULL, }, // 0x01c6 - {0, 2, NULL, }, // 0x01c7 - {0, 13, NULL, }, // 0x01c8 - {0, 97, NULL, }, // 0x01c9 - {0, 0, NULL, }, // 0x01ca - {0, 9, NULL, }, // 0x01cb - {0, 9, NULL, }, // 0x01cc - {0, 30, NULL, }, // 0x01cd - {0, 6, NULL, }, // 0x01ce - {0, 28, NULL, }, // 0x01cf - {0, 8, NULL, }, // 0x01d0 - {0, 14, NULL, }, // 0x01d1 - {0, 10, NULL, }, // 0x01d2 - {0, 35, NULL, }, // 0x01d3 - {0, 6, NULL, }, // 0x01d4 + {0, 4, nullptr, }, // 0x018b + {0, 29, nullptr, }, // 0x018c + {0, VAR,nullptr, }, // 0x018d + {0, 10, nullptr, }, // 0x018e + {0, 6, nullptr, }, // 0x018f + {0, 90, nullptr, }, // 0x0190 + {0, 86, nullptr, }, // 0x0191 + {0, 24, nullptr, }, // 0x0192 + {0, 6, nullptr, }, // 0x0193 + {0, 30, nullptr, }, // 0x0194 + {0, 102,nullptr, }, // 0x0195 + {0, 9, nullptr, }, // 0x0196 + {0, 4, nullptr, }, // 0x0197 + {0, 8, nullptr, }, // 0x0198 + {0, 4, nullptr, }, // 0x0199 + {0, 14, nullptr, }, // 0x019a + {0, 10, nullptr, }, // 0x019b + {0, VAR,nullptr, }, // 0x019c + {300, 6, nullptr, }, // 0x019d + {0, 2, nullptr, }, // 0x019e + {0, 6, nullptr, }, // 0x019f + {0, 3, nullptr, }, // 0x01a0 + {0, 3, nullptr, }, // 0x01a1 + {0, 35, nullptr, }, // 0x01a2 + {0, 5, nullptr, }, // 0x01a3 + {0, 11, nullptr, }, // 0x01a4 + {0, 26, nullptr, }, // 0x01a5 + {0, VAR,nullptr, }, // 0x01a6 + {0, 4, nullptr, }, // 0x01a7 + {0, 4, nullptr, }, // 0x01a8 + {0, 6, nullptr, }, // 0x01a9 + {0, 10, nullptr, }, // 0x01aa + {0, 12, nullptr, }, // 0x01ab + {0, 6, nullptr, }, // 0x01ac + {0, VAR,nullptr, }, // 0x01ad + {0, 4, nullptr, }, // 0x01ae + {0, 4, nullptr, }, // 0x01af + {0, 11, nullptr, }, // 0x01b0 + {0, 7, nullptr, }, // 0x01b1 + {0, VAR,nullptr, }, // 0x01b2 + {0, 67, nullptr, }, // 0x01b3 + {0, 12, nullptr, }, // 0x01b4 + {0, 18, nullptr, }, // 0x01b5 + {0, 114,nullptr, }, // 0x01b6 + {0, 6, nullptr, }, // 0x01b7 + {0, 3, nullptr, }, // 0x01b8 + {0, 6, nullptr, }, // 0x01b9 + {0, 26, nullptr, }, // 0x01ba + {0, 26, nullptr, }, // 0x01bb + {0, 26, nullptr, }, // 0x01bc + {0, 26, nullptr, }, // 0x01bd + {0, 2, nullptr, }, // 0x01be + {0, 3, nullptr, }, // 0x01bf + {0, 2, nullptr, }, // 0x01c0 + {0, 14, nullptr, }, // 0x01c1 + {0, 10, nullptr, }, // 0x01c2 + {0, VAR,nullptr, }, // 0x01c3 + {0, 22, nullptr, }, // 0x01c4 + {0, 22, nullptr, }, // 0x01c5 + {0, 4, nullptr, }, // 0x01c6 + {0, 2, nullptr, }, // 0x01c7 + {0, 13, nullptr, }, // 0x01c8 + {0, 97, nullptr, }, // 0x01c9 + {0, 0, nullptr, }, // 0x01ca + {0, 9, nullptr, }, // 0x01cb + {0, 9, nullptr, }, // 0x01cc + {0, 30, nullptr, }, // 0x01cd + {0, 6, nullptr, }, // 0x01ce + {0, 28, nullptr, }, // 0x01cf + {0, 8, nullptr, }, // 0x01d0 + {0, 14, nullptr, }, // 0x01d1 + {0, 10, nullptr, }, // 0x01d2 + {0, 35, nullptr, }, // 0x01d3 + {0, 6, nullptr, }, // 0x01d4 {300, VAR,clif_parse_NpcStringInput, }, // 0x01d5 - set to -1 - {0, 4, NULL, }, // 0x01d6 - {0, 11, NULL, }, // 0x01d7 - {0, 54, NULL, }, // 0x01d8 - {0, 53, NULL, }, // 0x01d9 - {0, 60, NULL, }, // 0x01da - {0, 2, NULL, }, // 0x01db - {0, VAR,NULL, }, // 0x01dc - {0, 47, NULL, }, // 0x01dd - {0, 33, NULL, }, // 0x01de - {0, 6, NULL, }, // 0x01df - {0, 30, NULL, }, // 0x01e0 - {0, 8, NULL, }, // 0x01e1 - {0, 34, NULL, }, // 0x01e2 - {0, 14, NULL, }, // 0x01e3 - {0, 2, NULL, }, // 0x01e4 - {0, 6, NULL, }, // 0x01e5 - {0, 26, NULL, }, // 0x01e6 - {0, 2, NULL, }, // 0x01e7 - {0, 28, NULL, }, // 0x01e8 - {0, 81, NULL, }, // 0x01e9 - {0, 6, NULL, }, // 0x01ea - {0, 10, NULL, }, // 0x01eb - {0, 26, NULL, }, // 0x01ec - {0, 2, NULL, }, // 0x01ed - {0, VAR,NULL, }, // 0x01ee - {0, VAR,NULL, }, // 0x01ef - {0, VAR,NULL, }, // 0x01f0 - {0, VAR,NULL, }, // 0x01f1 - {0, 20, NULL, }, // 0x01f2 - {0, 10, NULL, }, // 0x01f3 - {0, 32, NULL, }, // 0x01f4 - {0, 9, NULL, }, // 0x01f5 - {0, 34, NULL, }, // 0x01f6 - {0, 14, NULL, }, // 0x01f7 - {0, 2, NULL, }, // 0x01f8 - {0, 6, NULL, }, // 0x01f9 - {0, 48, NULL, }, // 0x01fa - {0, 56, NULL, }, // 0x01fb - {0, VAR,NULL, }, // 0x01fc - {0, 4, NULL, }, // 0x01fd - {0, 5, NULL, }, // 0x01fe - {0, 10, NULL, }, // 0x01ff - {0, 26, NULL, }, // 0x0200 - {0, VAR,NULL, }, // 0x0201 - {0, 26, NULL, }, // 0x0202 - {0, 10, NULL, }, // 0x0203 - {0, 18, NULL, }, // 0x0204 - {0, 26, NULL, }, // 0x0205 - {0, 11, NULL, }, // 0x0206 - {0, 34, NULL, }, // 0x0207 - {0, 14, NULL, }, // 0x0208 - {0, 36, NULL, }, // 0x0209 - {0, 10, NULL, }, // 0x020a - {0, 19, NULL, }, // 0x020b - {0, 10, NULL, }, // 0x020c - {0, VAR,NULL, }, // 0x020d - {0, 24, NULL, }, // 0x020e - {0, 0, NULL, }, // 0x020f - {0, 0, NULL, }, // 0x0210 - {0, 0, NULL, }, // 0x0211 - {0, 0, NULL, }, // 0x0212 - {0, 0, NULL, }, // 0x0213 - {0, 0, NULL, }, // 0x0214 - {0, 0, NULL, }, // 0x0215 - {0, 0, NULL, }, // 0x0216 - {0, 0, NULL, }, // 0x0217 - {0, 0, NULL, }, // 0x0218 - {0, 0, NULL, }, // 0x0219 - {0, 0, NULL, }, // 0x021a - {0, 0, NULL, }, // 0x021b - {0, 0, NULL, }, // 0x021c - {0, 0, NULL, }, // 0x021d - {0, 0, NULL, }, // 0x021e - {0, 0, NULL, }, // 0x021f + {0, 4, nullptr, }, // 0x01d6 + {0, 11, nullptr, }, // 0x01d7 + {0, 54, nullptr, }, // 0x01d8 + {0, 53, nullptr, }, // 0x01d9 + {0, 60, nullptr, }, // 0x01da + {0, 2, nullptr, }, // 0x01db + {0, VAR,nullptr, }, // 0x01dc + {0, 47, nullptr, }, // 0x01dd + {0, 33, nullptr, }, // 0x01de + {0, 6, nullptr, }, // 0x01df + {0, 30, nullptr, }, // 0x01e0 + {0, 8, nullptr, }, // 0x01e1 + {0, 34, nullptr, }, // 0x01e2 + {0, 14, nullptr, }, // 0x01e3 + {0, 2, nullptr, }, // 0x01e4 + {0, 6, nullptr, }, // 0x01e5 + {0, 26, nullptr, }, // 0x01e6 + {0, 2, nullptr, }, // 0x01e7 + {0, 28, nullptr, }, // 0x01e8 + {0, 81, nullptr, }, // 0x01e9 + {0, 6, nullptr, }, // 0x01ea + {0, 10, nullptr, }, // 0x01eb + {0, 26, nullptr, }, // 0x01ec + {0, 2, nullptr, }, // 0x01ed + {0, VAR,nullptr, }, // 0x01ee + {0, VAR,nullptr, }, // 0x01ef + {0, VAR,nullptr, }, // 0x01f0 + {0, VAR,nullptr, }, // 0x01f1 + {0, 20, nullptr, }, // 0x01f2 + {0, 10, nullptr, }, // 0x01f3 + {0, 32, nullptr, }, // 0x01f4 + {0, 9, nullptr, }, // 0x01f5 + {0, 34, nullptr, }, // 0x01f6 + {0, 14, nullptr, }, // 0x01f7 + {0, 2, nullptr, }, // 0x01f8 + {0, 6, nullptr, }, // 0x01f9 + {0, 48, nullptr, }, // 0x01fa + {0, 56, nullptr, }, // 0x01fb + {0, VAR,nullptr, }, // 0x01fc + {0, 4, nullptr, }, // 0x01fd + {0, 5, nullptr, }, // 0x01fe + {0, 10, nullptr, }, // 0x01ff + {0, 26, nullptr, }, // 0x0200 + {0, VAR,nullptr, }, // 0x0201 + {0, 26, nullptr, }, // 0x0202 + {0, 10, nullptr, }, // 0x0203 + {0, 18, nullptr, }, // 0x0204 + {0, 26, nullptr, }, // 0x0205 + {0, 11, nullptr, }, // 0x0206 + {0, 34, nullptr, }, // 0x0207 + {0, 14, nullptr, }, // 0x0208 + {0, 36, nullptr, }, // 0x0209 + {0, 10, nullptr, }, // 0x020a + {0, 19, nullptr, }, // 0x020b + {0, 10, nullptr, }, // 0x020c + {0, VAR,nullptr, }, // 0x020d + {0, 24, nullptr, }, // 0x020e + {0, 0, nullptr, }, // 0x020f + {0, 0, nullptr, }, // 0x0210 + {0, 0, nullptr, }, // 0x0211 + {0, 0, nullptr, }, // 0x0212 + {0, 0, nullptr, }, // 0x0213 + {0, 0, nullptr, }, // 0x0214 + {0, 0, nullptr, }, // 0x0215 + {0, 0, nullptr, }, // 0x0216 + {0, 0, nullptr, }, // 0x0217 + {0, 0, nullptr, }, // 0x0218 + {0, 0, nullptr, }, // 0x0219 + {0, 0, nullptr, }, // 0x021a + {0, 0, nullptr, }, // 0x021b + {0, 0, nullptr, }, // 0x021c + {0, 0, nullptr, }, // 0x021d + {0, 0, nullptr, }, // 0x021e + {0, 0, nullptr, }, // 0x021f }; // Checks for packet flooding static -int clif_check_packet_flood(Session *s, int cmd) +uint16_t clif_check_packet_flood(Session *s, int cmd) { + uint16_t len = clif_parse_func_table[cmd].len_unused; + if (len == VAR) + { + Little16 netlen; + if (!packet_fetch(s, 2, reinterpret_cast<Byte *>(&netlen), 2)) + { + return 0; + } + if (!network_to_native(&len, netlen)) + { + s->set_eof(); + return 0; + } + } + if (packet_avail(s) < len) + return 0; + dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s->session_data.get())); tick_t tick = gettick(); @@ -5182,30 +5402,28 @@ int clif_check_packet_flood(Session *s, int cmd) // Default rate is 100ms interval_t rate = clif_parse_func_table[cmd].rate; if (rate == interval_t::zero()) - rate = std::chrono::milliseconds(100); + rate = 100_ms; // ActionRequest - attacks are allowed a faster rate than sit/stand if (cmd == 0x89) { - int action_type = RFIFOB(s, 6); - if (action_type == 0x00 || action_type == 0x07) - rate = std::chrono::milliseconds(20); + DamageType damage_type; + Byte action_type; + if (!packet_fetch(s, 6, &action_type, 1)) + return 0; + if (!network_to_native(&damage_type, action_type)) + { + s->set_eof(); + return 0; + } + if (damage_type == DamageType::NORMAL || damage_type == DamageType::CONTINUOUS) + rate = 20_ms; else - rate = std::chrono::seconds(1); + rate = 1_s; } -// Restore this code when mana1.0 is released -#if 0 - // ChangeDir - only apply limit if not walking - if (cmd == 0x9b) - { - // .29 clients spam this packet when walking into a blocked tile - if (RFIFOB(fd, 4) == sd->dir || sd->walktimer != -1) - return 0; - - rate = 500; - } -#endif + // Restore this code when mana1.0 is released + // nope, nuh-uh // They are flooding if (tick < sd->flood_rates[cmd] + rate) @@ -5223,16 +5441,16 @@ int clif_check_packet_flood(Session *s, int cmd) if (sd->packet_flood_in >= battle_config.packet_spam_flood) { - PRINTF("packet flood detected from %s [0x%x]\n", sd->status_key.name, cmd); + PRINTF("packet flood detected from %s [0x%x]\n"_fmt, sd->status_key.name, cmd); if (battle_config.packet_spam_kick) { s->set_eof(); - return 1; + return len; } sd->packet_flood_in = 0; } - return 1; + return len; } sd->flood_rates[cmd] = tick; @@ -5240,9 +5458,9 @@ int clif_check_packet_flood(Session *s, int cmd) } inline -void WARN_MALFORMED_MSG(dumb_ptr<map_session_data> sd, const char *msg) +void WARN_MALFORMED_MSG(dumb_ptr<map_session_data> sd, ZString msg) { - PRINTF("clif_validate_chat(): %s (ID %d) sent a malformed message: %s.\n", + PRINTF("clif_validate_chat(): %s (ID %d) sent a malformed message: %s.\n"_fmt, sd->status_key.name, sd->status_key.account_id, msg); } /** @@ -5256,7 +5474,7 @@ void WARN_MALFORMED_MSG(dumb_ptr<map_session_data> sd, const char *msg) * @return a dynamically allocated copy of the message, or empty string upon failure */ static -AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) +AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type, XString buf) { nullpo_retr(AString(), sd); /* @@ -5267,54 +5485,8 @@ AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) return AString(); Session *s = sd->sess; - size_t msg_len = RFIFOW(s, 2) - 4; size_t name_len = sd->status_key.name.to__actual().size(); - /* - * At least one character is required in all instances. - * Notes for length checks: - * - * For all types, header (2) + length (2) is considered empty. - * For type 1, the message must be longer than the maximum name length (24) - * to be valid. - * For type 2, the message must be longer than the sender's name length - * plus the length of the separator (" : "). - */ - size_t min_len = - (type == ChatType::Whisper) ? 24 - : (type == ChatType::Global) ? name_len + 3 - : 0; - - /* The player just sent the header (2) and length (2) words. */ - if (!msg_len) - { - WARN_MALFORMED_MSG(sd, "no message sent"); - return AString(); - } - - /* The client sent (or claims to have sent) an empty message. */ - if (msg_len == min_len) - { - WARN_MALFORMED_MSG(sd, "empty message"); - return AString(); - } - - /* The protocol specifies that the target must be 24 bytes long. */ - if (type == ChatType::Whisper && msg_len < min_len) - { - /* Disallow malformed messages. */ - clif_setwaitclose(s); - WARN_MALFORMED_MSG(sd, "illegal target name"); - return AString(); - } - - size_t pstart = 4; - size_t buf_len = msg_len; - if (type == ChatType::Whisper) - { - pstart += 24; - buf_len -= 24; - } - AString pbuf = RFIFO_STRING(s, pstart, buf_len); + XString pbuf = buf; /* * The client attempted to exceed the maximum message length. @@ -5323,20 +5495,21 @@ AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) * is truncated. But the previous behavior was to drop the message, so * we'll do that, too. */ - if (buf_len >= battle_config.chat_maxline) + // TODO this cuts global chat short by (name_length + 3) + if (buf.size() >= battle_config.chat_maxline) { - WARN_MALFORMED_MSG(sd, "exceeded maximum message length"); + WARN_MALFORMED_MSG(sd, "exceeded maximum message length"_s); return AString(); } if (type == ChatType::Global) { XString p = pbuf; - if (!(p.startswith(sd->status_key.name.to__actual()) && p.xslice_t(name_len).startswith(" : "))) + if (!(p.startswith(sd->status_key.name.to__actual()) && p.xslice_t(name_len).startswith(" : "_s))) { /* Disallow malformed/spoofed messages. */ clif_setwaitclose(s); - WARN_MALFORMED_MSG(sd, "spoofed name/invalid format"); + WARN_MALFORMED_MSG(sd, "spoofed name/invalid format"_s); return AString(); } /* Step beyond the separator. */ @@ -5354,19 +5527,39 @@ AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) static void clif_parse(Session *s) { - int packet_len = 0, cmd = 0; + // old code: + // no while loop (can hang if more than one packet) + // handles 0x7530 and 0x7532 specially, also 0x0072 + // checks packet length table + // checks rate limiter + // dispatches to actual function, unchecked + // interstitial code: + // introduces while loop + // checks rate limiter + // dispatches to actual function + // if incomplete, unchecks rate limiter + // if error, close socket + // future code: + // hoists while loop + // treats all packets as variable-length, except a hard-coded list + // reads packet of that length unconditionally into a buffer + // does rate-limit check (hoisted?) + // dispatches to actual function + // if error, close socket + dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s->session_data.get())); if (!sd || (sd && !sd->state.auth)) { - if (RFIFOREST(s) < 2) - { // too small a packet disconnect - s->set_eof(); - } - if (RFIFOW(s, 0) != 0x72 && RFIFOW(s, 0) != 0x7530) + uint16_t packet_id; + if (!packet_peek_id(s, &packet_id)) + return; + + if (packet_id != 0x0072 && packet_id != 0x7530) { // first packet must be auth or finger s->set_eof(); + return; } } @@ -5375,100 +5568,89 @@ void clif_parse(Session *s) s->set_eof(); return; } - - if (RFIFOREST(s) < 2) - return; // Too small (no packet number) - - cmd = RFIFOW(s, 0); - - // 管理用パケット処理 - if (cmd >= 30000) + if (sd && sd->state.auth == 1 && sd->state.waitingdisconnect == 1) { - switch (cmd) - { - case 0x7530: // Athena情報所得 - WFIFOW(s, 0) = 0x7531; - WFIFO_STRUCT(s, 2, CURRENT_MAP_SERVER_VERSION); - WFIFOSET(s, 10); - RFIFOSKIP(s, 2); - break; - case 0x7532: // 接続の切断 - s->set_eof(); - break; - } + packet_discard(s, packet_avail(s)); return; } - else if (cmd >= 0x200) - return; - // パケット長を計算 - packet_len = clif_parse_func_table[cmd].len; - if (packet_len == VAR) + uint16_t packet_id; + RecvResult rv = RecvResult::Complete; + while (rv == RecvResult::Complete && packet_peek_id(s, &packet_id)) { - if (RFIFOREST(s) < 4) + switch (packet_id) { - return; // Runt packet (variable length without a length sent) + case 0x7530: + { + Packet_Fixed<0x7530> fixed; + rv = recv_fpacket<0x7530, 2>(s, fixed); + if (rv != RecvResult::Complete) + break; + + Packet_Fixed<0x7531> fixed_31; + fixed_31.version = CURRENT_MAP_SERVER_VERSION; + send_fpacket<0x7531, 10>(s, fixed_31); + break; + } + case 0x7532: + { + Packet_Fixed<0x7532> fixed; + rv = recv_fpacket<0x7532, 2>(s, fixed); + if (rv != RecvResult::Complete) + break; + + s->set_eof(); + break; + } } - packet_len = RFIFOW(s, 2); - if (packet_len < 4 || packet_len > 32768) + if (packet_id < 0x0220) { - s->set_eof(); - return; // Runt packet (variable out of bounds) + if (uint16_t len = clif_check_packet_flood(s, packet_id)) + { + // Packet flood: skip packet + packet_discard(s, len); + rv = RecvResult::Complete; + } + else + { + clif_func func = clif_parse_func_table[packet_id].func; + if (!func) + goto unknown_packet; + rv = func(s, sd); + } } + else + goto unknown_packet; } - if (RFIFOREST(s) < packet_len) - { - return; // Runt packet (sent legnth is too small) - } - - if (sd && sd->state.auth == 1 && sd->state.waitingdisconnect == 1) - { // 切断待ちの場合パケットを処理しない - - } - else if (clif_parse_func_table[cmd].func) - { - if (clif_check_packet_flood(s, cmd)) - { - // Flood triggered. Skip packet. - RFIFOSKIP(sd->sess, packet_len); - return; - } + if (rv == RecvResult::Error) + s->set_eof(); + return; - clif_parse_func_table[cmd].func(s, sd); - } - else +unknown_packet: { - // 不明なパケット if (battle_config.error_log) { if (s) - PRINTF("\nclif_parse: session #%d, packet 0x%x, lenght %d\n", - s, cmd, packet_len); -#ifdef DUMP_UNKNOWN_PACKET + PRINTF("\nclif_parse: session #%d, packet 0x%x, lenght %zu\n"_fmt, + s, packet_id, packet_avail(s)); { - int i; - ZString packet_txt = "save/packet.txt"; - PRINTF("---- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F"); - for (i = 0; i < packet_len; i++) - { - if ((i & 15) == 0) - PRINTF("\n%04X ", i); - PRINTF("%02X ", RFIFOB(s, i)); - } + ZString packet_txt = "save/packet.txt"_s; if (sd && sd->state.auth) { - PRINTF("\nAccount ID %d, character ID %d, player name %s.\n", + PRINTF("Unknown packet: Account ID %d, character ID %d, player name %s.\n"_fmt, sd->status_key.account_id, sd->status_key.char_id, sd->status_key.name); } else if (sd) // not authentified! (refused by char-server or disconnect before to be authentified) - PRINTF("\nAccount ID %d.\n", sd->bl_id); + PRINTF("Unkonwn packet (unauthenticated): Account ID %d.\n"_fmt, sd->bl_id); + else + PRINTF("Unknown packet (unknown)\n"_fmt); io::AppendFile fp(packet_txt); if (!fp.is_open()) { - PRINTF("clif.c: cant write [%s] !!! data is lost !!!\n", + PRINTF("clif.c: cant write [%s] !!! data is lost !!!\n"_fmt, packet_txt); return; } @@ -5479,34 +5661,29 @@ void clif_parse(Session *s) if (sd && sd->state.auth) { FPRINTF(fp, - "%s\nPlayer with account ID %d (character ID %d, player name %s) sent wrong packet:\n", + "%s\nPlayer with account ID %d (character ID %d, player name %s) sent wrong packet:\n"_fmt, now, sd->status_key.account_id, sd->status_key.char_id, sd->status_key.name); } else if (sd) // not authentified! (refused by char-server or disconnect before to be authentified) FPRINTF(fp, - "%s\nPlayer with account ID %d sent wrong packet:\n", + "%s\nUnauthenticated player with account ID %d sent wrong packet:\n"_fmt, now, sd->bl_id); + else + FPRINTF(fp, + "%s\nUnknown connection sent wrong packet:\n"_fmt, + now); - FPRINTF(fp, - "\t---- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F"); - for (i = 0; i < packet_len; i++) - { - if ((i & 15) == 0) - FPRINTF(fp, "\n\t%04X ", i); - FPRINTF(fp, "%02X ", RFIFOB(s, i)); - } - FPRINTF(fp, "\n\n"); + packet_dump(fp, s); } } -#endif } } - RFIFOSKIP(s, packet_len); } void do_init_clif(void) { - make_listen_port(map_port, SessionParsers{func_parse: clif_parse, func_delete: clif_delete}); + make_listen_port(map_port, SessionParsers{.func_parse= clif_parse, .func_delete= clif_delete}); } +} // namespace tmwa diff --git a/src/map/clif.hpp b/src/map/clif.hpp index 1fdd67c..adb4889 100644 --- a/src/map/clif.hpp +++ b/src/map/clif.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_CLIF_HPP -#define TMWA_MAP_CLIF_HPP +#pragma once // clif.hpp - Network interface to the client. // // Copyright © ????-2004 Athena Dev Teams @@ -21,22 +20,29 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "clif.t.hpp" +#include "clif.t.hpp" -# include <functional> +#include <functional> -# include "../strings/fwd.hpp" +#include "../strings/fwd.hpp" -# include "../mmo/ip.hpp" -# include "../mmo/timer.t.hpp" +#include "../generic/fwd.hpp" -# include "battle.t.hpp" -# include "map.hpp" -# include "pc.t.hpp" -# include "skill.t.hpp" +#include "../net/timer.t.hpp" +#include "../mmo/fwd.hpp" +#include "../mmo/mmo.hpp" + +#include "battle.t.hpp" +#include "map.t.hpp" +#include "pc.t.hpp" +#include "skill.t.hpp" + + +namespace tmwa +{ void clif_setip(IP4Address); void clif_setport(int); @@ -47,16 +53,16 @@ void clif_setwaitclose(Session *); int clif_authok(dumb_ptr<map_session_data>); int clif_authfail_fd(Session *, int); -int clif_charselectok(int); +int clif_charselectok(BlockId); int clif_dropflooritem(dumb_ptr<flooritem_data>); int clif_clearflooritem(dumb_ptr<flooritem_data>, Session *); int clif_clearchar(dumb_ptr<block_list>, BeingRemoveWhy); // area or fd int clif_clearchar_delay(tick_t, dumb_ptr<block_list>, BeingRemoveWhy); -void clif_clearchar_id(int, BeingRemoveWhy, Session *); +void clif_clearchar_id(BlockId, BeingRemoveWhy, Session *); int clif_spawnpc(dumb_ptr<map_session_data>); //area int clif_spawnnpc(dumb_ptr<npc_data>); // area int clif_spawn_fake_npc_for_player(dumb_ptr<map_session_data> sd, - int fake_npc_id); + BlockId fake_npc_id); int clif_spawnmob(dumb_ptr<mob_data>); // area int clif_walkok(dumb_ptr<map_session_data>); // self int clif_movechar(dumb_ptr<map_session_data>); // area @@ -66,18 +72,18 @@ void clif_changemapserver(dumb_ptr<map_session_data>, MapName, int, int, IP4Addr void clif_fixpos(dumb_ptr<block_list>); // area int clif_fixmobpos(dumb_ptr<mob_data> md); int clif_fixpcpos(dumb_ptr<map_session_data> sd); -int clif_npcbuysell(dumb_ptr<map_session_data>, int); //self +int clif_npcbuysell(dumb_ptr<map_session_data>, BlockId); //self int clif_buylist(dumb_ptr<map_session_data>, dumb_ptr<npc_data_shop>); //self int clif_selllist(dumb_ptr<map_session_data>); //self -void clif_scriptmes(dumb_ptr<map_session_data>, int, XString); //self -void clif_scriptnext(dumb_ptr<map_session_data>, int); //self -void clif_scriptclose(dumb_ptr<map_session_data>, int); //self -void clif_scriptmenu(dumb_ptr<map_session_data>, int, XString); //self -void clif_scriptinput(dumb_ptr<map_session_data>, int); //self -void clif_scriptinputstr(dumb_ptr<map_session_data> sd, int npcid); // self -void clif_viewpoint(dumb_ptr<map_session_data>, int, int, int, int, int, int); //self -int clif_additem(dumb_ptr<map_session_data>, int, int, PickupFail); //self -void clif_delitem(dumb_ptr<map_session_data>, int, int); //self +void clif_scriptmes(dumb_ptr<map_session_data>, BlockId, XString); //self +void clif_scriptnext(dumb_ptr<map_session_data>, BlockId); //self +void clif_scriptclose(dumb_ptr<map_session_data>, BlockId); //self +void clif_scriptmenu(dumb_ptr<map_session_data>, BlockId, XString); //self +void clif_scriptinput(dumb_ptr<map_session_data>, BlockId); //self +void clif_scriptinputstr(dumb_ptr<map_session_data> sd, BlockId npcid); // self + +int clif_additem(dumb_ptr<map_session_data>, IOff0, int, PickupFail); //self +void clif_delitem(dumb_ptr<map_session_data>, IOff0, int); //self int clif_updatestatus(dumb_ptr<map_session_data>, SP); //self int clif_damage(dumb_ptr<block_list>, dumb_ptr<block_list>, tick_t, interval_t, interval_t, @@ -89,14 +95,14 @@ int clif_takeitem(dumb_ptr<block_list> src, dumb_ptr<block_list> dst) } int clif_changelook(dumb_ptr<block_list>, LOOK, int); // area void clif_changelook_accessories(dumb_ptr<block_list> bl, dumb_ptr<map_session_data> dst); // area or target; list gloves, boots etc. -int clif_arrowequip(dumb_ptr<map_session_data> sd, int val); //self +int clif_arrowequip(dumb_ptr<map_session_data> sd, IOff0 val); //self int clif_arrow_fail(dumb_ptr<map_session_data> sd, int type); //self int clif_statusupack(dumb_ptr<map_session_data>, SP, int, int); // self -int clif_equipitemack(dumb_ptr<map_session_data>, int, EPOS, int); // self -int clif_unequipitemack(dumb_ptr<map_session_data>, int, EPOS, int); // self +int clif_equipitemack(dumb_ptr<map_session_data>, IOff0, EPOS, int); // self +int clif_unequipitemack(dumb_ptr<map_session_data>, IOff0, EPOS, int); // self int clif_misceffect(dumb_ptr<block_list>, int); // area int clif_changeoption(dumb_ptr<block_list>); // area -int clif_useitemack(dumb_ptr<map_session_data>, int, int, int); // self +int clif_useitemack(dumb_ptr<map_session_data>, IOff0, int, int); // self void clif_emotion(dumb_ptr<block_list> bl, int type); void clif_sitting(Session *, dumb_ptr<map_session_data> sd); @@ -105,22 +111,22 @@ void clif_sitting(Session *, dumb_ptr<map_session_data> sd); void clif_traderequest(dumb_ptr<map_session_data> sd, CharName name); void clif_tradestart(dumb_ptr<map_session_data> sd, int type); void clif_tradeadditem(dumb_ptr<map_session_data> sd, - dumb_ptr<map_session_data> tsd, int index, int amount); -int clif_tradeitemok(dumb_ptr<map_session_data> sd, int index, int amount, + dumb_ptr<map_session_data> tsd, IOff2 index2, int amount); +int clif_tradeitemok(dumb_ptr<map_session_data> sd, IOff2 index, int amount, int fail); int clif_tradedeal_lock(dumb_ptr<map_session_data> sd, int fail); int clif_tradecancelled(dumb_ptr<map_session_data> sd); int clif_tradecompleted(dumb_ptr<map_session_data> sd, int fail); // storage -int clif_storageitemlist(dumb_ptr<map_session_data> sd, struct storage *stor); +int clif_storageitemlist(dumb_ptr<map_session_data> sd, Storage *stor); int clif_storageequiplist(dumb_ptr<map_session_data> sd, - struct storage *stor); + Storage *stor); int clif_updatestorageamount(dumb_ptr<map_session_data> sd, - struct storage *stor); -int clif_storageitemadded(dumb_ptr<map_session_data> sd, struct storage *stor, - int index, int amount); -int clif_storageitemremoved(dumb_ptr<map_session_data> sd, int index, + Storage *stor); +int clif_storageitemadded(dumb_ptr<map_session_data> sd, Storage *stor, + SOff0 index, int amount); +int clif_storageitemremoved(dumb_ptr<map_session_data> sd, SOff0 index, int amount); int clif_storageclose(dumb_ptr<map_session_data> sd); @@ -157,17 +163,17 @@ int clif_movetoattack(dumb_ptr<map_session_data> sd, dumb_ptr<block_list> bl); // party int clif_party_created(dumb_ptr<map_session_data> sd, int flag); -int clif_party_info(struct party *p, Session *s); +int clif_party_info(PartyPair p, Session *s); void clif_party_invite(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> tsd); void clif_party_inviteack(dumb_ptr<map_session_data> sd, CharName nick, int flag); -void clif_party_option(struct party *p, dumb_ptr<map_session_data> sd, +void clif_party_option(PartyPair p, dumb_ptr<map_session_data> sd, int flag); -void clif_party_leaved(struct party *p, dumb_ptr<map_session_data> sd, - int account_id, CharName name, int flag); -void clif_party_message(struct party *p, int account_id, XString mes); -int clif_party_xy(struct party *p, dumb_ptr<map_session_data> sd); -int clif_party_hp(struct party *p, dumb_ptr<map_session_data> sd); +void clif_party_leaved(PartyPair p, dumb_ptr<map_session_data> sd, + AccountId account_id, CharName name, int flag); +void clif_party_message(PartyPair p, AccountId account_id, XString mes); +int clif_party_xy(PartyPair p, dumb_ptr<map_session_data> sd); +int clif_party_hp(PartyPair p, dumb_ptr<map_session_data> sd); // atcommand void clif_displaymessage(Session *s, XString mes); @@ -183,5 +189,4 @@ int clif_GM_kick(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> tsd, int clif_foreachclient(std::function<void(dumb_ptr<map_session_data>)>); void do_init_clif(void); - -#endif // TMWA_MAP_CLIF_HPP +} // namespace tmwa diff --git a/src/map/clif.t.hpp b/src/map/clif.t.hpp index 5cb06ad..1789ee8 100644 --- a/src/map/clif.t.hpp +++ b/src/map/clif.t.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_CLIF_T_HPP -#define TMWA_MAP_CLIF_T_HPP +#pragma once // clif.t.hpp - Network interface to the client. // // Copyright © ????-2004 Athena Dev Teams @@ -21,9 +20,99 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include <cstdint> +#include <cstdint> + +#include "../ints/little.hpp" + +#include "../compat/iter.hpp" + +#include "../generic/enum.hpp" + +#include "../mmo/consts.hpp" +#include "../mmo/enums.hpp" + + +namespace tmwa +{ +namespace e +{ +// [Fate] status.option properties. These are persistent status changes. +// IDs that are not listed are not used in the code (to the best of my knowledge) +enum class Option : uint16_t +{ + ZERO = 0x0000, + + // [Fate] This is the GM `@hide' flag + HIDE = 0x0040, + // [Fate] Complete invisibility to other clients + INVISIBILITY = 0x1000, + + // ? + REAL_ANY_HIDE = HIDE, +}; +enum class Opt1 : uint16_t +{ + ZERO = 0, + _stone1 = 1, + _freeze = 2, + _stan = 3, + _sleep = 4, + _stone6 = 6, +}; +enum class Opt2 : uint16_t +{ + ZERO = 0x0000, + _poison = 0x0001, + _curse = 0x0002, + _silence = 0x0004, + BLIND = 0x0010, + _speedpotion0 = 0x0020, + _signumcrucis = 0x0040, + _atkpot = 0x0080, + _heal = 0x0100, + _slowpoison = 0x0200, +}; +enum class Opt3 : uint16_t +{ + ZERO = 0x0000, + _concentration = 0x0001, + _overthrust = 0x0002, + _energycoat = 0x0004, + _explosionspirits = 0x0008, + _steelbody = 0x0010, + _berserk = 0x0080, + + _marionette = 0x0400, + _assumptio = 0x0800, +}; + +ENUM_BITWISE_OPERATORS(Option) +ENUM_BITWISE_OPERATORS(Opt2) +ENUM_BITWISE_OPERATORS(Opt3) +} +using e::Option; +using e::Opt1; +using e::Opt2; +using e::Opt3; + + +enum class ItemType : uint8_t +{ + USE = 0, // in eA, healing only + _1 = 1, // unused + _2 = 2, // in eA, other usable items + JUNK = 3, // "useless" items (e.g. quests) + WEAPON = 4, // all weapons + ARMOR = 5, // all other equipment + _6 = 6, // in eA, card + _7 = 7, // in eA, pet egg + _8 = 8, // in eA, pet equipment + _9 = 9, // unused + ARROW = 10, // ammo + _11 = 11, // in eA, delayed use (special script) +}; enum class BeingRemoveWhy : uint8_t { @@ -40,4 +129,589 @@ enum class BeingRemoveWhy : uint8_t NEGATIVE1 = 0xff, }; -#endif // TMWA_MAP_CLIF_T_HPP +enum class PickupFail : uint8_t +{ + OKAY = 0, + BAD_ITEM = 1, + TOO_HEAVY = 2, + TOO_FAR = 3, + INV_FULL = 4, + STACK_FULL = 5, + DROP_STEAL = 6, +}; + +// this is used for both input and output +// different values are valid in 0x0089 vs 0x008a +enum class DamageType : uint8_t +{ + NORMAL = 0x00, + TAKEITEM = 0x01, + SIT = 0x02, + STAND = 0x03, + RETURNED = 0x04, + CONTINUOUS = 0x07, + DOUBLED = 0x08, + CRITICAL = 0x0a, + FLEE2 = 0x0b, +}; + +enum class LOOK : uint8_t +{ + BASE = 0, + HAIR = 1, + WEAPON = 2, + HEAD_BOTTOM = 3, + HEAD_TOP = 4, + HEAD_MID = 5, + HAIR_COLOR = 6, + CLOTHES_COLOR = 7, + SHIELD = 8, + SHOES = 9, + GLOVES = 10, + CAPE = 11, + MISC1 = 12, + MISC2 = 13, + + COUNT, +}; + +// Note: there is also a typedef by this name in <dirent.h> +// but we should be fine since we never include it. +// (in the long term we should still rename this though) +enum class DIR : uint8_t +{ + S = 0, + SW = 1, + W = 2, + NW = 3, + N = 4, + NE = 5, + E = 6, + SE = 7, + + COUNT, +}; + +constexpr +earray<int, DIR, DIR::COUNT> dirx //= +{{ + 0, -1, -1, -1, 0, 1, 1, 1, +}}, diry //= +{{ + 1, 1, 0, -1, -1, -1, 0, 1, +}}; + +constexpr +bool dir_is_diagonal(DIR d) +{ + return static_cast<uint8_t>(d) & 1; +} + + +enum class SP : uint16_t +{ + // sent to client + SPEED = 0, + + // when used as "no stat" + ZERO = 0, + + // sent to client + BASEEXP = 1, + // sent to client + JOBEXP = 2, +#if 0 + KARMA = 3, +#endif + + // sent to client + HP = 5, + // sent to client + MAXHP = 6, + // sent to client + SP = 7, + // sent to client + MAXSP = 8, + // sent to client + STATUSPOINT = 9, + + // sent to client + BASELEVEL = 11, + // sent to client + SKILLPOINT = 12, + // sent to client + STR = 13, + // sent to client + AGI = 14, + // sent to client + VIT = 15, + // sent to client + INT = 16, + // sent to client + DEX = 17, + // sent to client + LUK = 18, + CLASS = 19, + // sent to client + ZENY = 20, + SEX = 21, + // sent to client + NEXTBASEEXP = 22, + // sent to client + NEXTJOBEXP = 23, + // sent to client + WEIGHT = 24, + // sent to client + MAXWEIGHT = 25, + + // sent to client + USTR = 32, + // sent to client + UAGI = 33, + // sent to client + UVIT = 34, + // sent to client + UINT = 35, + // sent to client + UDEX = 36, + // sent to client + ULUK = 37, + + // sent to client + ATK1 = 41, + // sent to client + ATK2 = 42, + // sent to client + MATK1 = 43, + // sent to client + MATK2 = 44, + // sent to client + DEF1 = 45, + // sent to client + DEF2 = 46, + // sent to client + MDEF1 = 47, + // sent to client + MDEF2 = 48, + // sent to client + HIT = 49, + // sent to client + FLEE1 = 50, + // sent to client + FLEE2 = 51, + // sent to client + CRITICAL = 52, + // sent to client + ASPD = 53, + + // sent to client + JOBLEVEL = 55, + +#if 0 + PARTNER = 57, + CART = 58, + FAME = 59, + UNBREAKABLE = 60, +#endif + + DEAF = 70, + + // sent to client + GM = 500, + + // sent to client + ATTACKRANGE = 1000, +#if 0 + ATKELE = 1001, +#endif +#if 0 + DEFELE = 1002, +#endif +#if 0 + CASTRATE = 1003, +#endif + MAXHPRATE = 1004, +#if 0 + MAXSPRATE = 1005, +#endif +#if 0 + SPRATE = 1006, +#endif + +#if 0 + ADDEFF = 1012, +#endif +#if 0 + RESEFF = 1013, +#endif + BASE_ATK = 1014, + ASPD_RATE = 1015, + HP_RECOV_RATE = 1016, +#if 0 + SP_RECOV_RATE = 1017, +#endif +#if 0 + SPEED_RATE = 1018, +#endif + CRITICAL_DEF = 1019, +#if 0 + NEAR_ATK_DEF = 1020, +#endif +#if 0 + LONG_ATK_DEF = 1021, +#endif +#if 0 + DOUBLE_RATE = 1022, +#endif + DOUBLE_ADD_RATE = 1023, +#if 0 + MATK = 1024, +#endif +#if 0 + MATK_RATE = 1025, +#endif +#if 0 + IGNORE_DEF_ELE = 1026, +#endif +#if 0 + IGNORE_DEF_RACE = 1027, +#endif +#if 0 + ATK_RATE = 1028, +#endif + SPEED_ADDRATE = 1029, +#if 0 + ASPD_ADDRATE = 1030, +#endif +#if 0 + MAGIC_ATK_DEF = 1031, +#endif +#if 0 + MISC_ATK_DEF = 1032, +#endif +#if 0 + IGNORE_MDEF_ELE = 1033, +#endif +#if 0 + IGNORE_MDEF_RACE = 1034, +#endif + +#if 0 + PERFECT_HIT_RATE = 1038, +#endif +#if 0 + PERFECT_HIT_ADD_RATE = 1039, +#endif +#if 0 + CRITICAL_RATE = 1040, +#endif +#if 0 + GET_ZENY_NUM = 1041, +#endif +#if 0 + ADD_GET_ZENY_NUM = 1042, +#endif + +#if 0 + ADD_MONSTER_DROP_ITEM = 1047, +#endif +#if 0 + DEF_RATIO_ATK_ELE = 1048, +#endif +#if 0 + DEF_RATIO_ATK_RACE = 1049, +#endif +#if 0 + ADD_SPEED = 1050, +#endif +#if 0 + HIT_RATE = 1051, +#endif +#if 0 + FLEE_RATE = 1052, +#endif +#if 0 + FLEE2_RATE = 1053, +#endif + DEF_RATE = 1054, + DEF2_RATE = 1055, +#if 0 + MDEF_RATE = 1056, +#endif +#if 0 + MDEF2_RATE = 1057, +#endif +#if 0 + SPLASH_RANGE = 1058, +#endif +#if 0 + SPLASH_ADD_RANGE = 1059, +#endif + + HP_DRAIN_RATE = 1061, +#if 0 + SP_DRAIN_RATE = 1062, +#endif +#if 0 + SHORT_WEAPON_DAMAGE_RETURN = 1063, +#endif +#if 0 + LONG_WEAPON_DAMAGE_RETURN = 1064, +#endif + +#if 0 + ADDEFF2 = 1067, +#endif + BREAK_WEAPON_RATE = 1068, + BREAK_ARMOR_RATE = 1069, + ADD_STEAL_RATE = 1070, + MAGIC_DAMAGE_RETURN = 1071, +#if 0 + RANDOM_ATTACK_INCREASE = 1072, +#endif +}; + +constexpr +SP attr_to_sp(ATTR attr) +{ + return static_cast<SP>(static_cast<uint16_t>(attr) + static_cast<uint16_t>(SP::STR)); +} + +constexpr +ATTR sp_to_attr(SP sp) +{ + return static_cast<ATTR>(static_cast<uint16_t>(sp) - static_cast<uint16_t>(SP::STR)); +} + +constexpr +SP attr_to_usp(ATTR attr) +{ + return static_cast<SP>(static_cast<uint16_t>(attr) + static_cast<uint16_t>(SP::USTR)); +} + +constexpr +ATTR usp_to_attr(SP sp) +{ + return static_cast<ATTR>(static_cast<uint16_t>(sp) - static_cast<uint16_t>(SP::USTR)); +} + +constexpr +SP sp_to_usp(SP sp) +{ + return attr_to_usp(sp_to_attr(sp)); +} + +constexpr +SP usp_to_sp(SP sp) +{ + return attr_to_sp(usp_to_attr(sp)); +} + + +// xxxx xxxx xxyy yyyy yyyy dddd +struct NetPosition1 +{ + Byte data[3]; +}; + +struct Position1 +{ + uint16_t x, y; + DIR dir; +}; + +inline +bool native_to_network(NetPosition1 *network, Position1 native) +{ + uint16_t x = native.x; + uint16_t y = native.y; + uint8_t d = static_cast<uint8_t>(native.dir); + + uint8_t *p = reinterpret_cast<uint8_t *>(network); + p[0] = x >> 2; + p[1] = (x << 6) | ((y >> 4) & 0x3f); + p[2] = y << 4 | d; + + return x < 1024 && y < 1024 && d < 16; +} + +inline +bool network_to_native(Position1 *native, NetPosition1 network) +{ + const uint8_t *p = reinterpret_cast<const uint8_t *>(&network); + native->x = (p[0] & (0x3ff >> 2)) << 2 | p[1] >> (8 - 2); + native->y = (p[1] & (0x3ff >> 4)) << 4 | p[2] >> (8 - 4); + uint8_t d = p[2] & 0x0f; + native->dir = static_cast<DIR>(d); + return d < 8; +} + +// x0xx xxxx xxy0 yyyy yyyy x1xx xxxx xxy1 yyyy yyyy +struct NetPosition2 +{ + Byte data[5]; +}; + +struct Position2 +{ + uint16_t x0, y0; + uint16_t x1, y1; +}; + +inline +bool native_to_network(NetPosition2 *network, Position2 native) +{ + uint16_t x0 = native.x0; + uint16_t y0 = native.y0; + uint16_t x1 = native.x1; + uint16_t y1 = native.y1; + + uint8_t *p = reinterpret_cast<uint8_t *>(network); + p[0] = x0 >> 2; + p[1] = (x0 << 6) | ((y0 >> 4) & 0x3f); + p[2] = (y0 << 4) | ((x1 >> 6) & 0x0f); + p[3] = (x1 << 2) | ((y1 >> 8) & 0x03); + p[4] = y1; + + return x0 < 1024 && y0 < 1024 && x1 < 1024 && y1 < 1024; +} + +inline +bool network_to_native(Position2 *native, NetPosition2 network) +{ + const uint8_t *p = reinterpret_cast<const uint8_t *>(&network); + native->x0 = (p[0] & (0x3ff >> 2)) << 2 | p[1] >> (8 - 2); + native->y0 = (p[1] & (0x3ff >> 4)) << 4 | p[2] >> (8 - 4); + native->x1 = (p[2] & (0x3ff >> 6)) << 6 | p[3] >> (8 - 6); + native->y1 = (p[3] & (0x3ff >> 8)) << 8 | p[4] >> (8 - 8); + return true; +} + +struct IOff2; +struct SOff1; + +struct IOff0 +{ + uint16_t index; + + bool ok() const + { return get0() < MAX_INVENTORY; } + uint16_t get0() const + { return index; } + static IOff0 from(uint16_t i) + { return IOff0{i}; } + static IteratorPair<ValueIterator<IOff0>> iter() + { return {IOff0::from(0), IOff0::from(MAX_INVENTORY)}; } + friend uint16_t convert_for_printf(IOff0 i0) { return i0.index; } + + IOff0& operator ++() { ++index; return *this; } + friend bool operator == (IOff0 l, IOff0 r) { return l.index == r.index; } + friend bool operator != (IOff0 l, IOff0 r) { return !(l == r); } + IOff2 shift() const; + + IOff0() : index(0) {} +private: + explicit IOff0(uint16_t i) : index(i) {} +}; + +struct SOff0 +{ + uint16_t index; + + bool ok() const + { return get0() < MAX_STORAGE; } + uint16_t get0() const + { return index; } + static SOff0 from(uint16_t i) + { return SOff0{i}; } + static IteratorPair<ValueIterator<SOff0>> iter() + { return {SOff0::from(0), SOff0::from(MAX_STORAGE)}; } + friend uint16_t convert_for_printf(SOff0 s0) { return s0.index; } + + SOff0& operator ++() { ++index; return *this; } + friend bool operator == (SOff0 l, SOff0 r) { return l.index == r.index; } + friend bool operator != (SOff0 l, SOff0 r) { return !(l == r); } + SOff1 shift() const; + + SOff0() : index(0) {} +private: + explicit SOff0(uint16_t i) : index(i) {} +}; + +struct IOff2 +{ + uint16_t index; + + bool ok() const + { return get2() < MAX_INVENTORY; } + uint16_t get2() const + { return index - 2; } + static IOff2 from(uint16_t i) + { return IOff2{static_cast<uint16_t>(i + 2)}; } + static IteratorPair<ValueIterator<IOff2>> iter() + { return {IOff2::from(0), IOff2::from(MAX_INVENTORY)}; } + + IOff2& operator ++() { ++index; return *this; } + friend bool operator == (IOff2 l, IOff2 r) { return l.index == r.index; } + friend bool operator != (IOff2 l, IOff2 r) { return !(l == r); } + IOff0 unshift() const + { return IOff0::from(get2()); } + + IOff2() : index(0) {} +private: + explicit IOff2(uint16_t i) : index(i) {} +}; + +struct SOff1 +{ + uint16_t index; + + bool ok() const + { return get1() < MAX_STORAGE; } + uint16_t get1() const + { return index - 1; } + static SOff1 from(uint16_t i) + { return SOff1{static_cast<uint16_t>(i + 1)}; } + static IteratorPair<ValueIterator<SOff1>> iter() + { return {SOff1::from(0), SOff1::from(MAX_STORAGE)}; } + + SOff1& operator ++() { ++index; return *this; } + friend bool operator == (SOff1 l, SOff1 r) { return l.index == r.index; } + friend bool operator != (SOff1 l, SOff1 r) { return !(l == r); } + SOff0 unshift() const + { return SOff0::from(get1()); } + + SOff1() : index(0) {} +private: + explicit SOff1(uint16_t i) : index(i) {} +}; + +inline IOff2 IOff0::shift() const +{ return IOff2::from(get0()); } +inline SOff1 SOff0::shift() const +{ return SOff1::from(get0()); } + +inline +bool native_to_network(Little16 *network, IOff2 native) +{ + return native_to_network(network, native.index); +} + +inline +bool network_to_native(IOff2 *native, Little16 network) +{ + return network_to_native(&native->index, network); +} + +inline +bool native_to_network(Little16 *network, SOff1 native) +{ + return native_to_network(network, native.index); +} + +inline +bool network_to_native(SOff1 *native, Little16 network) +{ + return network_to_native(&native->index, network); +} +} // namespace tmwa diff --git a/src/map/magic-interpreter-aux.cpp b/src/map/fwd.hpp index 10a376b..79bbbcd 100644 --- a/src/map/magic-interpreter-aux.cpp +++ b/src/map/fwd.hpp @@ -1,5 +1,5 @@ -#include "magic-interpreter-aux.hpp" -// magic-interpreter-aux.cpp - Edge of the magic system. +#pragma once +// map/fwd.hpp - list of type names for map server // // Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> // @@ -18,4 +18,42 @@ // 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 "../poison.hpp" +#include "../sanity.hpp" + + +namespace tmwa +{ +// meh, add more when I feel like it +class BlockId; +struct block_list; +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; +class npc_data_warp; +class npc_data_message; +struct NpcEvent; + +struct item_data; + +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; +} // namespace magic +} // namespace tmwa diff --git a/src/map/grfio.cpp b/src/map/grfio.cpp index c3d1e40..4a1656b 100644 --- a/src/map/grfio.cpp +++ b/src/map/grfio.cpp @@ -20,28 +20,29 @@ // 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 <sys/stat.h> - #include <fcntl.h> #include <unistd.h> #include <cassert> -#include <cstdio> -#include <cstring> #include <map> #include "../strings/mstring.hpp" #include "../strings/rstring.hpp" #include "../strings/astring.hpp" +#include "../strings/zstring.hpp" #include "../io/cxxstdio.hpp" #include "../io/read.hpp" #include "../mmo/extract.hpp" +#include "../mmo/mmo.hpp" #include "../poison.hpp" + +namespace tmwa +{ static std::map<MapName, RString> resnametable; @@ -50,7 +51,7 @@ bool load_resnametable(ZString filename) io::ReadFile in(filename); if (!in.is_open()) { - FPRINTF(stderr, "Missing %s\n", filename); + FPRINTF(stderr, "Missing %s\n"_fmt, filename); return false; } @@ -63,7 +64,7 @@ bool load_resnametable(ZString filename) if (!extract(line, record<'#'>(&key, &value))) { - PRINTF("Bad resnametable line: %s\n", line); + PRINTF("Bad resnametable line: %s\n"_fmt, line); rv = false; continue; } @@ -85,7 +86,7 @@ std::vector<uint8_t> grfio_reads(MapName rname) { MString lfname_; // TODO ... instead of here - lfname_ += "data/"; + lfname_ += "data/"_s; lfname_ += grfio_resnametable(rname); AString lfname = AString(lfname_); @@ -93,7 +94,7 @@ std::vector<uint8_t> grfio_reads(MapName rname) int fd = open(lfname.c_str(), O_RDONLY); if (fd == -1) { - FPRINTF(stderr, "Resource %s (file %s) not found\n", + FPRINTF(stderr, "Resource %s (file %s) not found\n"_fmt, rname, lfname); return {}; } @@ -105,3 +106,4 @@ std::vector<uint8_t> grfio_reads(MapName rname) close(fd); return buffer; } +} // namespace tmwa diff --git a/src/map/grfio.hpp b/src/map/grfio.hpp index 9b6d5e2..d2ab058 100644 --- a/src/map/grfio.hpp +++ b/src/map/grfio.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_GRFIO_HPP -#define TMWA_MAP_GRFIO_HPP +#pragma once // grfio.hpp - Don't read GRF files, just name-map .wlk files. // // Copyright © ????-2004 Athena Dev Teams @@ -21,19 +20,23 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include <cstdint> +#include <cstdint> -# include <vector> +#include <vector> -# include "../mmo/mmo.hpp" +#include "../strings/fwd.hpp" +#include "../mmo/fwd.hpp" + + +namespace tmwa +{ bool load_resnametable(ZString filename); /// Load a resource into memory, subject to data/resnametable.txt. /// Normally, resourcename is xxx-y.gat and the file is xxx-y.wlk. /// Currently there is exactly one .wlk per .gat, but multiples are fine. std::vector<uint8_t> grfio_reads(MapName resourcename); - -#endif // TMWA_MAP_GRFIO_HPP +} // namespace tmwa diff --git a/src/map/intif.cpp b/src/map/intif.cpp index 2cae2ad..314db24 100644 --- a/src/map/intif.cpp +++ b/src/map/intif.cpp @@ -20,18 +20,21 @@ // 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 <cstdlib> -#include <cstring> - #include "../compat/nullpo.hpp" #include "../strings/astring.hpp" #include "../strings/zstring.hpp" #include "../strings/xstring.hpp" +#include "../strings/literal.hpp" #include "../io/cxxstdio.hpp" -#include "../mmo/socket.hpp" +#include "../net/packets.hpp" +#include "../net/socket.hpp" + +#include "../mmo/mmo.hpp" + +#include "../proto2/char-map.hpp" #include "battle.hpp" #include "chrif.hpp" @@ -43,32 +46,19 @@ #include "../poison.hpp" -static -const int packet_len_table[] = -{ - -1, -1, 27, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - -1, 7, 0, 0, 0, 0, 0, 0, -1, 11, 0, 0, 0, 0, 0, 0, - 35, -1, 11, 15, 34, 29, 7, -1, 0, 0, 0, 0, 0, 0, 0, 0, - 10, -1, 15, 0, 79, 19, 7, -1, 0, -1, -1, -1, 14, 67, 186, -1, - 9, 9, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 11, -1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - +namespace tmwa +{ //----------------------------------------------------------------- // inter serverへの送信 // Message for all GMs on all map servers void intif_GMmessage(XString mes) { - WFIFOW(char_session, 0) = 0x3000; - size_t len = mes.size() + 1; - WFIFOW(char_session, 2) = 4 + len; - WFIFO_STRING(char_session, 4, mes, len); - WFIFOSET(char_session, WFIFOW(char_session, 2)); + if (!char_session) + return; + + send_packet_repeatonly<0x3000, 4, 1>(char_session, mes); } // The transmission of Wisp/Page to inter-server (player not found on this server) @@ -76,65 +66,69 @@ void intif_wis_message(dumb_ptr<map_session_data> sd, CharName nick, ZString mes { nullpo_retv(sd); - size_t mes_len = mes.size() + 1; - WFIFOW(char_session, 0) = 0x3001; - WFIFOW(char_session, 2) = mes_len + 52; - WFIFO_STRING(char_session, 4, sd->status_key.name.to__actual(), 24); - WFIFO_STRING(char_session, 28, nick.to__actual(), 24); - WFIFO_STRING(char_session, 52, mes, mes_len); - WFIFOSET(char_session, WFIFOW(char_session, 2)); + if (!char_session) + return; + + Packet_Head<0x3001> head_01; + head_01.from_char_name = sd->status_key.name; + head_01.to_char_name = nick; + send_vpacket<0x3001, 52, 1>(char_session, head_01, mes); if (battle_config.etc_log) - PRINTF("intif_wis_message from %s to %s)\n", + PRINTF("intif_wis_message from %s to %s)\n"_fmt, sd->status_key.name, nick); } // The reply of Wisp/page static -void intif_wis_replay(int id, int flag) +void intif_wis_replay(CharId id, int flag) { - WFIFOW(char_session, 0) = 0x3002; - WFIFOL(char_session, 2) = id; - WFIFOB(char_session, 6) = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - WFIFOSET(char_session, 7); + if (!char_session) + return; + + Packet_Fixed<0x3002> fixed_02; + fixed_02.char_id = id; + fixed_02.flag = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + send_fpacket<0x3002, 7>(char_session, fixed_02); if (battle_config.etc_log) - PRINTF("intif_wis_replay: id: %d, flag:%d\n", id, flag); + PRINTF("intif_wis_replay: id: %d, flag:%d\n"_fmt, id, flag); } // The transmission of GM only Wisp/Page from server to inter-server -void intif_wis_message_to_gm(CharName Wisp_name, int min_gm_level, ZString mes) +void intif_wis_message_to_gm(CharName Wisp_name, GmLevel min_gm_level, ZString mes) { - size_t mes_len = mes.size() + 1; - WFIFOW(char_session, 0) = 0x3003; - WFIFOW(char_session, 2) = mes_len + 30; - WFIFO_STRING(char_session, 4, Wisp_name.to__actual(), 24); - WFIFOW(char_session, 28) = min_gm_level; - WFIFO_STRING(char_session, 30, mes, mes_len); - WFIFOSET(char_session, WFIFOW(char_session, 2)); + if (!char_session) + return; + + Packet_Head<0x3003> head_03; + head_03.char_name = Wisp_name; + head_03.min_gm_level = min_gm_level; + send_vpacket<0x3003, 30, 1>(char_session, head_03, mes); if (battle_config.etc_log) - PRINTF("intif_wis_message_to_gm: from: '%s', min level: %d, message: '%s'.\n", + PRINTF("intif_wis_message_to_gm: from: '%s', min level: %d, message: '%s'.\n"_fmt, Wisp_name, min_gm_level, mes); } // アカウント変数送信 void intif_saveaccountreg(dumb_ptr<map_session_data> sd) { - int j, p; - nullpo_retv(sd); + if (!char_session) + return; + assert (sd->status.account_reg_num < ACCOUNT_REG_NUM); - WFIFOW(char_session, 0) = 0x3004; - WFIFOL(char_session, 4) = sd->bl_id; - for (j = 0, p = 8; j < sd->status.account_reg_num; j++, p += 36) + Packet_Head<0x3004> head_04; + head_04.account_id = block_to_account(sd->bl_id); + std::vector<Packet_Repeat<0x3004>> repeat_04(sd->status.account_reg_num); + for (size_t j = 0; j < sd->status.account_reg_num; j++) { - WFIFO_STRING(char_session, p, sd->status.account_reg[j].str, 32); - WFIFOL(char_session, p + 32) = sd->status.account_reg[j].value; + repeat_04[j].name = sd->status.account_reg[j].str; + repeat_04[j].value = sd->status.account_reg[j].value; } - WFIFOW(char_session, 2) = p; - WFIFOSET(char_session, p); + send_vpacket<0x3004, 8, 36>(char_session, head_04, repeat_04); } // アカウント変数要求 @@ -142,28 +136,36 @@ void intif_request_accountreg(dumb_ptr<map_session_data> sd) { nullpo_retv(sd); - WFIFOW(char_session, 0) = 0x3005; - WFIFOL(char_session, 2) = sd->bl_id; - WFIFOSET(char_session, 6); + if (!char_session) + return; + + Packet_Fixed<0x3005> fixed_05; + fixed_05.account_id = block_to_account(sd->bl_id); + send_fpacket<0x3005, 6>(char_session, fixed_05); } // 倉庫データ要求 -void intif_request_storage(int account_id) +void intif_request_storage(AccountId account_id) { - WFIFOW(char_session, 0) = 0x3010; - WFIFOL(char_session, 2) = account_id; - WFIFOSET(char_session, 6); + if (!char_session) + return; + + Packet_Fixed<0x3010> fixed_10; + fixed_10.account_id = account_id; + send_fpacket<0x3010, 6>(char_session, fixed_10); } // 倉庫データ送信 -void intif_send_storage(struct storage *stor) +void intif_send_storage(Storage *stor) { nullpo_retv(stor); - WFIFOW(char_session, 0) = 0x3011; - WFIFOW(char_session, 2) = sizeof(struct storage) + 8; - WFIFOL(char_session, 4) = stor->account_id; - WFIFO_STRUCT(char_session, 8, *stor); - WFIFOSET(char_session, WFIFOW(char_session, 2)); + if (!char_session) + return; + + Packet_Payload<0x3011> payload_11; + payload_11.account_id = stor->account_id; + payload_11.storage = *stor; + send_ppacket<0x3011>(char_session, payload_11); } // パーティ作成要求 @@ -171,95 +173,116 @@ void intif_create_party(dumb_ptr<map_session_data> sd, PartyName name) { nullpo_retv(sd); - WFIFOW(char_session, 0) = 0x3020; - WFIFOL(char_session, 2) = sd->status_key.account_id; - WFIFO_STRING(char_session, 6, name, 24); - WFIFO_STRING(char_session, 30, sd->status_key.name.to__actual(), 24); - WFIFO_STRING(char_session, 54, sd->bl_m->name_, 16); - WFIFOW(char_session, 70) = sd->status.base_level; - WFIFOSET(char_session, 72); + if (!char_session) + return; + + Packet_Fixed<0x3020> fixed_20; + fixed_20.account_id = sd->status_key.account_id; + fixed_20.party_name = name; + fixed_20.char_name = sd->status_key.name; + fixed_20.map_name = sd->bl_m->name_; + fixed_20.level = sd->status.base_level; + send_fpacket<0x3020, 72>(char_session, fixed_20); } // パーティ情報要求 -void intif_request_partyinfo(int party_id) +void intif_request_partyinfo(PartyId party_id) { - WFIFOW(char_session, 0) = 0x3021; - WFIFOL(char_session, 2) = party_id; - WFIFOSET(char_session, 6); + if (!char_session) + return; + + Packet_Fixed<0x3021> fixed_21; + fixed_21.party_id = party_id; + send_fpacket<0x3021, 6>(char_session, fixed_21); } // パーティ追加要求 -void intif_party_addmember(int party_id, int account_id) +void intif_party_addmember(PartyId party_id, AccountId account_id) { + if (!char_session) + return; + dumb_ptr<map_session_data> sd; - sd = map_id2sd(account_id); - if (sd != NULL) + sd = map_id2sd(account_to_block(account_id)); + if (sd != nullptr) { - WFIFOW(char_session, 0) = 0x3022; - WFIFOL(char_session, 2) = party_id; - WFIFOL(char_session, 6) = account_id; - WFIFO_STRING(char_session, 10, sd->status_key.name.to__actual(), 24); - WFIFO_STRING(char_session, 34, sd->bl_m->name_, 16); - WFIFOW(char_session, 50) = sd->status.base_level; - WFIFOSET(char_session, 52); + Packet_Fixed<0x3022> fixed_22; + fixed_22.party_id = party_id; + fixed_22.account_id = account_id; + fixed_22.char_name = sd->status_key.name; + fixed_22.map_name = sd->bl_m->name_; + fixed_22.level = sd->status.base_level; + send_fpacket<0x3022, 52>(char_session, fixed_22); } } // パーティ設定変更 -void intif_party_changeoption(int party_id, int account_id, int exp, int item) -{ - WFIFOW(char_session, 0) = 0x3023; - WFIFOL(char_session, 2) = party_id; - WFIFOL(char_session, 6) = account_id; - WFIFOW(char_session, 10) = exp; - WFIFOW(char_session, 12) = item; - WFIFOSET(char_session, 14); +void intif_party_changeoption(PartyId party_id, AccountId account_id, int exp, int item) +{ + if (!char_session) + return; + + Packet_Fixed<0x3023> fixed_23; + fixed_23.party_id = party_id; + fixed_23.account_id = account_id; + fixed_23.exp = exp; + fixed_23.item = item; + send_fpacket<0x3023, 14>(char_session, fixed_23); } // パーティ脱退要求 -void intif_party_leave(int party_id, int account_id) +void intif_party_leave(PartyId party_id, AccountId account_id) { - WFIFOW(char_session, 0) = 0x3024; - WFIFOL(char_session, 2) = party_id; - WFIFOL(char_session, 6) = account_id; - WFIFOSET(char_session, 10); + if (!char_session) + return; + + Packet_Fixed<0x3024> fixed_24; + fixed_24.party_id = party_id; + fixed_24.account_id = account_id; + send_fpacket<0x3024, 10>(char_session, fixed_24); } // パーティ移動要求 void intif_party_changemap(dumb_ptr<map_session_data> sd, int online) { - if (sd != NULL) + if (!char_session) + return; + + if (sd != nullptr) { - WFIFOW(char_session, 0) = 0x3025; - WFIFOL(char_session, 2) = sd->status.party_id; - WFIFOL(char_session, 6) = sd->status_key.account_id; - WFIFO_STRING(char_session, 10, sd->bl_m->name_, 16); - WFIFOB(char_session, 26) = online; - WFIFOW(char_session, 27) = sd->status.base_level; - WFIFOSET(char_session, 29); + Packet_Fixed<0x3025> fixed_25; + fixed_25.party_id = sd->status.party_id; + fixed_25.account_id = sd->status_key.account_id; + fixed_25.map_name = sd->bl_m->name_; + fixed_25.online = online; + fixed_25.level = sd->status.base_level; + send_fpacket<0x3025, 29>(char_session, fixed_25); } } // パーティ会話送信 -void intif_party_message(int party_id, int account_id, XString mes) -{ - size_t len = mes.size() + 1; - WFIFOW(char_session, 0) = 0x3027; - WFIFOW(char_session, 2) = len + 12; - WFIFOL(char_session, 4) = party_id; - WFIFOL(char_session, 8) = account_id; - WFIFO_STRING(char_session, 12, mes, len); - WFIFOSET(char_session, len + 12); +void intif_party_message(PartyId party_id, AccountId account_id, XString mes) +{ + if (!char_session) + return; + + Packet_Head<0x3027> head_27; + head_27.party_id = party_id; + head_27.account_id = account_id; + send_vpacket<0x3027, 12, 1>(char_session, head_27, mes); } // パーティ競合チェック要求 -void intif_party_checkconflict(int party_id, int account_id, CharName nick) +void intif_party_checkconflict(PartyId party_id, AccountId account_id, CharName nick) { - WFIFOW(char_session, 0) = 0x3028; - WFIFOL(char_session, 2) = party_id; - WFIFOL(char_session, 6) = account_id; - WFIFO_STRING(char_session, 10, nick.to__actual(), 24); - WFIFOSET(char_session, 34); + if (!char_session) + return; + + Packet_Fixed<0x3028> fixed_28; + fixed_28.party_id = party_id; + fixed_28.account_id = account_id; + fixed_28.char_name = nick; + send_fpacket<0x3028, 34>(char_session, fixed_28); } //----------------------------------------------------------------- @@ -267,55 +290,52 @@ void intif_party_checkconflict(int party_id, int account_id, CharName nick) // Wisp/Page reception static -int intif_parse_WisMessage(Session *s) +int intif_parse_WisMessage(Session *, const Packet_Head<0x3801>& head, AString& buf) { // rewritten by [Yor] dumb_ptr<map_session_data> sd; - CharName from = stringish<CharName>(RFIFO_STRING<24>(s, 8)); - CharName to = stringish<CharName>(RFIFO_STRING<24>(s, 32)); - - size_t len = RFIFOW(s, 2) - 56; - AString buf = RFIFO_STRING(s, 56, len); + CharName from = head.src_char_name; + CharName to = head.dst_char_name; if (battle_config.etc_log) { - PRINTF("intif_parse_wismessage: id: %d, from: %s, to: %s\n", - RFIFOL(s, 4), - from, - to); + PRINTF("intif_parse_wismessage: id: %d, from: %s, to: %s\n"_fmt, + head.whisper_id, + from, + to); } sd = map_nick2sd(to); // Searching destination player - if (sd != NULL && sd->status_key.name == to) + if (sd != nullptr && sd->status_key.name == to) { // exactly same name (inter-server have checked the name before) { // if source player not found in ignore list { clif_wis_message(sd->sess, from, buf); - intif_wis_replay(RFIFOL(s, 4), 0); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + intif_wis_replay(head.whisper_id, 0); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target } } } else - intif_wis_replay(RFIFOL(s, 4), 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + intif_wis_replay(head.whisper_id, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target return 0; } // Wisp/page transmission result reception static -int intif_parse_WisEnd(Session *s) +int intif_parse_WisEnd(Session *, const Packet_Fixed<0x3802>& fixed) { dumb_ptr<map_session_data> sd; - CharName name = stringish<CharName>(RFIFO_STRING<24>(s, 2)); - uint8_t flag = RFIFOB(s, 26); + CharName name = fixed.sender_char_name; + uint8_t flag = fixed.flag; if (battle_config.etc_log) // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - PRINTF("intif_parse_wisend: player: %s, flag: %d\n", + PRINTF("intif_parse_wisend: player: %s, flag: %d\n"_fmt, name, flag); sd = map_nick2sd(name); - if (sd != NULL) + if (sd != nullptr) clif_wis_end(sd->sess, flag); return 0; @@ -323,19 +343,11 @@ int intif_parse_WisEnd(Session *s) // Received wisp message from map-server via char-server for ALL gm static -void mapif_parse_WisToGM(Session *s) +void mapif_parse_WisToGM(Session *, const Packet_Head<0x3803>& head, AString& message) { // 0x3003/0x3803 <packet_len>.w <wispname>.24B <min_gm_level>.w <message>.?B - int min_gm_level, len; - - if (RFIFOW(s, 2) - 30 <= 0) - return; - - len = RFIFOW(s, 2) - 30; - - min_gm_level = RFIFOW(s, 28); - CharName Wisp_name = stringish<CharName>(RFIFO_STRING<24>(s, 4)); - AString message = RFIFO_STRING(s, 30, len); + GmLevel min_gm_level = head.min_gm_level; + CharName Wisp_name = head.char_name; // information is sended to all online GM for (io::FD i : iter_fds()) { @@ -345,7 +357,7 @@ void mapif_parse_WisToGM(Session *s) dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get())); if (pl_sd && pl_sd->state.auth) { - if (pc_isGM(pl_sd) >= min_gm_level) + if (pc_isGM(pl_sd).satisfies(min_gm_level)) clif_wis_message(s2, Wisp_name, message); } } @@ -353,65 +365,57 @@ void mapif_parse_WisToGM(Session *s) // アカウント変数通知 static -int intif_parse_AccountReg(Session *s) +int intif_parse_AccountReg(Session *, const Packet_Head<0x3804>& head, const std::vector<Packet_Repeat<0x3804>>& repeat) { - int j, p; - dumb_ptr<map_session_data> sd = map_id2sd(RFIFOL(s, 4)); - if (sd == NULL) + dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(head.account_id)); + if (sd == nullptr) return 1; - for (p = 8, j = 0; p < RFIFOW(s, 2) && j < ACCOUNT_REG_NUM; - p += 36, j++) + + size_t jlim = std::min(ACCOUNT_REG_NUM, repeat.size()); + for (size_t j = 0; j < jlim; j++) { - sd->status.account_reg[j].str = stringish<VarName>(RFIFO_STRING<32>(s, p)); - sd->status.account_reg[j].value = RFIFOL(s, p + 32); + sd->status.account_reg[j].str = repeat[j].name; + sd->status.account_reg[j].value = repeat[j].value; } - sd->status.account_reg_num = j; -// PRINTF("intif: accountreg\n"); + sd->status.account_reg_num = jlim; return 0; } // 倉庫データ受信 static -int intif_parse_LoadStorage(Session *s) +int intif_parse_LoadStorage(Session *, const Packet_Payload<0x3810>& payload) { - struct storage *stor; + Storage *stor; dumb_ptr<map_session_data> sd; - sd = map_id2sd(RFIFOL(s, 4)); - if (sd == NULL) + sd = map_id2sd(account_to_block(payload.account_id)); + if (sd == nullptr) { if (battle_config.error_log) - PRINTF("intif_parse_LoadStorage: user not found %d\n", - RFIFOL(s, 4)); + PRINTF("intif_parse_LoadStorage: user not found %d\n"_fmt, + payload.account_id); return 1; } - stor = account2storage(RFIFOL(s, 4)); + stor = account2storage(payload.account_id); if (stor->storage_status == 1) { // Already open.. lets ignore this update if (battle_config.error_log) - PRINTF("intif_parse_LoadStorage: storage received for a client already open (User %d:%d)\n", - sd->status_key.account_id, sd->status_key.char_id); + PRINTF("intif_parse_LoadStorage: storage received for a client already open (User %d:%d)\n"_fmt, + sd->status_key.account_id, sd->status_key.char_id); return 1; } if (stor->dirty) { // Already have storage, and it has been modified and not saved yet! Exploit! [Skotlex] if (battle_config.error_log) - PRINTF("intif_parse_LoadStorage: received storage for an already modified non-saved storage! (User %d:%d)\n", - sd->status_key.account_id, sd->status_key.char_id); + PRINTF("intif_parse_LoadStorage: received storage for an already modified non-saved storage! (User %d:%d)\n"_fmt, + sd->status_key.account_id, sd->status_key.char_id); return 1; } - if (RFIFOW(s, 2) - 8 != sizeof(struct storage)) - { - if (battle_config.error_log) - PRINTF("intif_parse_LoadStorage: data size error %d %zu\n", - RFIFOW(s, 2) - 8, sizeof(struct storage)); - return 1; - } if (battle_config.save_log) - PRINTF("intif_openstorage: %d\n", RFIFOL(s, 4)); - RFIFO_STRUCT(s, 8, *stor); + PRINTF("intif_openstorage: %d\n"_fmt, payload.account_id); + *stor = payload.storage; stor->dirty = 0; stor->storage_status = 1; sd->state.storage_open = 1; @@ -424,199 +428,273 @@ int intif_parse_LoadStorage(Session *s) // 倉庫データ送信成功 static -void intif_parse_SaveStorage(Session *s) +void intif_parse_SaveStorage(Session *, const Packet_Fixed<0x3811>& fixed) { if (battle_config.save_log) - PRINTF("intif_savestorage: done %d %d\n", RFIFOL(s, 2), - RFIFOB(s, 6)); - storage_storage_saved(RFIFOL(s, 2)); + PRINTF("intif_savestorage: done %d %d\n"_fmt, fixed.account_id, + fixed.unknown); + storage_storage_saved(fixed.account_id); } // パーティ作成可否 static -void intif_parse_PartyCreated(Session *s) +void intif_parse_PartyCreated(Session *, const Packet_Fixed<0x3820>& fixed) { if (battle_config.etc_log) - PRINTF("intif: party created\n"); - int account_id = RFIFOL(s, 2); - int fail = RFIFOB(s, 6); - int party_id = RFIFOL(s, 7); - PartyName name = stringish<PartyName>(RFIFO_STRING<24>(s, 11)); + PRINTF("intif: party created\n"_fmt); + AccountId account_id = fixed.account_id; + int fail = fixed.error; + PartyId party_id = fixed.party_id; + PartyName name = fixed.party_name; party_created(account_id, fail, party_id, name); } // パーティ情報 static -void intif_parse_PartyInfo(Session *s) +void intif_parse_PartyInfo(Session *, const Packet_Head<0x3821>& head, bool has_opt, const Packet_Option<0x3821>& option) { - if (RFIFOW(s, 2) == 8) + if (!has_opt) { if (battle_config.error_log) - PRINTF("intif: party noinfo %d\n", RFIFOL(s, 4)); - party_recv_noinfo(RFIFOL(s, 4)); + PRINTF("intif: party noinfo %d\n"_fmt, head.party_id); + party_recv_noinfo(head.party_id); return; } -// PRINTF("intif: party info %d\n",RFIFOL(fd,4)); - if (RFIFOW(s, 2) != sizeof(struct party) + 4) - { - if (battle_config.error_log) - PRINTF("intif: party info : data size error %d %d %zu\n", - RFIFOL(s, 4), RFIFOW(s, 2), - sizeof(struct party) + 4); - } - party p {}; - RFIFO_STRUCT(s, 4, p); - party_recv_info(&p); + PartyId pi = head.party_id; + PartyMost pm = option.party_most; + PartyPair pp; + pp.party_id = pi; + pp.party_most = ± + party_recv_info(pp); } // パーティ追加通知 static -void intif_parse_PartyMemberAdded(Session *s) +void intif_parse_PartyMemberAdded(Session *, const Packet_Fixed<0x3822>& fixed) { if (battle_config.etc_log) - PRINTF("intif: party member added %d %d %d\n", RFIFOL(s, 2), - RFIFOL(s, 6), RFIFOB(s, 10)); - party_member_added(RFIFOL(s, 2), RFIFOL(s, 6), RFIFOB(s, 10)); + PRINTF("intif: party member added %d %d %d\n"_fmt, fixed.party_id, + fixed.account_id, fixed.flag); + party_member_added(fixed.party_id, fixed.account_id, fixed.flag); } // パーティ設定変更通知 static -void intif_parse_PartyOptionChanged(Session *s) +void intif_parse_PartyOptionChanged(Session *, const Packet_Fixed<0x3823>& fixed) { - party_optionchanged(RFIFOL(s, 2), RFIFOL(s, 6), RFIFOW(s, 10), - RFIFOW(s, 12), RFIFOB(s, 14)); + party_optionchanged(fixed.party_id, fixed.account_id, fixed.exp, + fixed.item, fixed.flag); } // パーティ脱退通知 static -void intif_parse_PartyMemberLeaved(Session *s) +void intif_parse_PartyMemberLeaved(Session *, const Packet_Fixed<0x3824>& fixed) { - int party_id = RFIFOL(s, 2); - int account_id = RFIFOL(s, 6); - CharName name = stringish<CharName>(RFIFO_STRING<24>(s, 10)); + PartyId party_id = fixed.party_id; + AccountId account_id = fixed.account_id; + CharName name = fixed.char_name; if (battle_config.etc_log) - PRINTF("intif: party member leaved %d %d %s\n", + PRINTF("intif: party member leaved %d %d %s\n"_fmt, party_id, account_id, name); party_member_leaved(party_id, account_id, name); } // パーティ解散通知 static -void intif_parse_PartyBroken(Session *s) +void intif_parse_PartyBroken(Session *, const Packet_Fixed<0x3826>& fixed) { - party_broken(RFIFOL(s, 2)); + party_broken(fixed.party_id); } // パーティ移動通知 static -void intif_parse_PartyMove(Session *s) +void intif_parse_PartyMove(Session *, const Packet_Fixed<0x3825>& fixed) { - int party_id = RFIFOL(s, 2); - int account_id = RFIFOL(s, 6); - MapName map = stringish<MapName>(RFIFO_STRING<16>(s, 10)); - uint8_t online = RFIFOB(s, 26); - uint16_t lv = RFIFOW(s, 27); + PartyId party_id = fixed.party_id; + AccountId account_id = fixed.account_id; + MapName map = fixed.map_name; + uint8_t online = fixed.online; + uint16_t lv = fixed.level; party_recv_movemap(party_id, account_id, map, online, lv); } // パーティメッセージ static -void intif_parse_PartyMessage(Session *s) +void intif_parse_PartyMessage(Session *, const Packet_Head<0x3827>& head, AString& buf) { - size_t len = RFIFOW(s, 2) - 12; - AString buf = RFIFO_STRING(s, 12, len); - party_recv_message(RFIFOL(s, 4), RFIFOL(s, 8), buf); + party_recv_message(head.party_id, head.account_id, buf); } //----------------------------------------------------------------- // inter serverからの通信 // エラーがあれば0(false)を返すこと // パケットが処理できれば1,パケット長が足りなければ2を返すこと -int intif_parse(Session *s) -{ - int packet_len; - int cmd = RFIFOW(s, 0); - // パケットのID確認 - if (cmd < 0x3800 - || cmd >= - 0x3800 + (sizeof(packet_len_table) / sizeof(packet_len_table[0])) - || packet_len_table[cmd - 0x3800] == 0) - { - return 0; - } - // パケットの長さ確認 - packet_len = packet_len_table[cmd - 0x3800]; - if (packet_len == -1) - { - if (RFIFOREST(s) < 4) - return 2; - packet_len = RFIFOW(s, 2); - } -// if(battle_config.etc_log) -// PRINTF("intif_parse %d %x %d %d\n",fd,cmd,packet_len,RFIFOREST(fd)); - if (RFIFOREST(s) < packet_len) - { - return 2; - } - // 処理分岐 - switch (cmd) +RecvResult intif_parse(Session *s, uint16_t packet_id) +{ + RecvResult rv; + + switch (packet_id) { case 0x3800: { - AString mes = RFIFO_STRING(s, 4, packet_len - 4); - clif_GMmessage(NULL, mes, 0); - } + AString mes; + rv = recv_packet_repeatonly<0x3800, 4, 1>(s, mes); + if (rv != RecvResult::Complete) + return rv; + + clif_GMmessage(nullptr, mes, 0); break; + } case 0x3801: - intif_parse_WisMessage(s); + { + Packet_Head<0x3801> head; + AString repeat; + rv = recv_vpacket<0x3801, 56, 1>(s, head, repeat); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_WisMessage(s, head, repeat); break; + } case 0x3802: - intif_parse_WisEnd(s); + { + Packet_Fixed<0x3802> fixed; + rv = recv_fpacket<0x3802, 27>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_WisEnd(s, fixed); break; + } case 0x3803: - mapif_parse_WisToGM(s); + { + Packet_Head<0x3803> head; + AString repeat; + rv = recv_vpacket<0x3803, 30, 1>(s, head, repeat); + if (rv != RecvResult::Complete) + return rv; + + mapif_parse_WisToGM(s, head, repeat); break; + } case 0x3804: - intif_parse_AccountReg(s); + { + Packet_Head<0x3804> head; + std::vector<Packet_Repeat<0x3804>> repeat; + rv = recv_vpacket<0x3804, 8, 36>(s, head, repeat); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_AccountReg(s, head, repeat); break; + } case 0x3810: - intif_parse_LoadStorage(s); + { + Packet_Payload<0x3810> payload; + rv = recv_ppacket<0x3810>(s, payload); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_LoadStorage(s, payload); break; + } case 0x3811: - intif_parse_SaveStorage(s); + { + Packet_Fixed<0x3811> fixed; + rv = recv_fpacket<0x3811, 7>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_SaveStorage(s, fixed); break; + } case 0x3820: - intif_parse_PartyCreated(s); + { + Packet_Fixed<0x3820> fixed; + rv = recv_fpacket<0x3820, 35>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_PartyCreated(s, fixed); break; + } case 0x3821: - intif_parse_PartyInfo(s); + { + Packet_Head<0x3821> head; + bool has_opt; + Packet_Option<0x3821> option; + rv = recv_opacket<0x3821, 8, sizeof(NetPacket_Option<0x3821>)>(s, head, &has_opt, option); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_PartyInfo(s, head, has_opt, option); break; + } case 0x3822: - intif_parse_PartyMemberAdded(s); + { + Packet_Fixed<0x3822> fixed; + rv = recv_fpacket<0x3822, 11>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_PartyMemberAdded(s, fixed); break; + } case 0x3823: - intif_parse_PartyOptionChanged(s); + { + Packet_Fixed<0x3823> fixed; + rv = recv_fpacket<0x3823, 15>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_PartyOptionChanged(s, fixed); break; + } case 0x3824: - intif_parse_PartyMemberLeaved(s); + { + Packet_Fixed<0x3824> fixed; + rv = recv_fpacket<0x3824, 34>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_PartyMemberLeaved(s, fixed); break; + } case 0x3825: - intif_parse_PartyMove(s); + { + Packet_Fixed<0x3825> fixed; + rv = recv_fpacket<0x3825, 29>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_PartyMove(s, fixed); break; + } case 0x3826: - intif_parse_PartyBroken(s); + { + Packet_Fixed<0x3826> fixed; + rv = recv_fpacket<0x3826, 7>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_PartyBroken(s, fixed); break; + } case 0x3827: - intif_parse_PartyMessage(s); + { + Packet_Head<0x3827> head; + AString repeat; + rv = recv_vpacket<0x3827, 12, 1>(s, head, repeat); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_PartyMessage(s, head, repeat); break; + } default: - if (battle_config.error_log) - PRINTF("intif_parse : unknown packet %d %x\n", s, - RFIFOW(s, 0)); - return 0; + return RecvResult::Error; } - // パケット読み飛ばし - RFIFOSKIP(s, packet_len); - return 1; + return rv; } +} // namespace tmwa diff --git a/src/map/intif.hpp b/src/map/intif.hpp index 80de797..5be61a9 100644 --- a/src/map/intif.hpp +++ b/src/map/intif.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_INTIF_HPP -#define TMWA_MAP_INTIF_HPP +#pragma once // intif.hpp - Network interface to the internal server. // // Copyright © ????-2004 Athena Dev Teams @@ -21,33 +20,39 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "../strings/fwd.hpp" +#include "../strings/fwd.hpp" -# include "map.hpp" +#include "../generic/fwd.hpp" -int intif_parse(Session *); +#include "../net/fwd.hpp" + +#include "../mmo/fwd.hpp" + + +namespace tmwa +{ +RecvResult intif_parse(Session *, uint16_t packet_id); void intif_GMmessage(XString mes); void intif_wis_message(dumb_ptr<map_session_data> sd, CharName nick, ZString mes); -void intif_wis_message_to_gm(CharName Wisp_name, int min_gm_level, ZString mes); +void intif_wis_message_to_gm(CharName Wisp_name, GmLevel min_gm_level, ZString mes); void intif_saveaccountreg(dumb_ptr<map_session_data> sd); void intif_request_accountreg(dumb_ptr<map_session_data> sd); -void intif_request_storage(int account_id); -void intif_send_storage(struct storage *stor); +void intif_request_storage(AccountId account_id); +void intif_send_storage(Storage *stor); void intif_create_party(dumb_ptr<map_session_data> sd, PartyName name); -void intif_request_partyinfo(int party_id); -void intif_party_addmember(int party_id, int account_id); -void intif_party_changeoption(int party_id, int account_id, int exp, +void intif_request_partyinfo(PartyId party_id); +void intif_party_addmember(PartyId party_id, AccountId account_id); +void intif_party_changeoption(PartyId party_id, AccountId account_id, int exp, int item); -void intif_party_leave(int party_id, int accound_id); +void intif_party_leave(PartyId party_id, AccountId accound_id); void intif_party_changemap(dumb_ptr<map_session_data> sd, int online); -void intif_party_message(int party_id, int account_id, XString mes); -void intif_party_checkconflict(int party_id, int account_id, CharName nick); - -#endif // TMWA_MAP_INTIF_HPP +void intif_party_message(PartyId party_id, AccountId account_id, XString mes); +void intif_party_checkconflict(PartyId party_id, AccountId account_id, CharName nick); +} // namespace tmwa diff --git a/src/map/itemdb.cpp b/src/map/itemdb.cpp index 4ebb52c..50cc5c4 100644 --- a/src/map/itemdb.cpp +++ b/src/map/itemdb.cpp @@ -20,29 +20,28 @@ // 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 <cstdlib> -#include <cstring> - -#include "../compat/nullpo.hpp" +#include <algorithm> #include "../strings/astring.hpp" #include "../strings/zstring.hpp" #include "../strings/xstring.hpp" #include "../generic/db.hpp" -#include "../generic/random.hpp" #include "../io/cxxstdio.hpp" #include "../io/read.hpp" #include "../mmo/config_parse.hpp" #include "../mmo/extract.hpp" -#include "../mmo/socket.hpp" +#include "../mmo/extract_enums.hpp" #include "../poison.hpp" + +namespace tmwa +{ static -Map<int, struct item_data> item_db; +Map<ItemNameId, struct item_data> item_db; // Function declarations @@ -67,7 +66,7 @@ struct item_data *itemdb_searchname(XString str_) ItemName str = stringish<ItemName>(str_); if (XString(str) != str_) return nullptr; - struct item_data *item = NULL; + struct item_data *item = nullptr; for (auto& pair : item_db) itemdb_searchname_sub(&pair.second, str, &item); return item; @@ -77,7 +76,7 @@ struct item_data *itemdb_searchname(XString str_) * DBの存在確認 *------------------------------------------ */ -struct item_data *itemdb_exists(int nameid) +struct item_data *itemdb_exists(ItemNameId nameid) { return item_db.search(nameid); } @@ -86,7 +85,7 @@ struct item_data *itemdb_exists(int nameid) * DBの検索 *------------------------------------------ */ -struct item_data *itemdb_search(int nameid) +struct item_data *itemdb_search(ItemNameId nameid) { struct item_data *id = item_db.search(nameid); if (id) @@ -101,22 +100,7 @@ struct item_data *itemdb_search(int nameid) id->sex = SEX::NEUTRAL; id->elv = 0; - if (nameid > 500 && nameid < 600) - id->type = ItemType::USE; - else if (nameid > 600 && nameid < 700) - id->type = ItemType::_2; - else if ((nameid > 700 && nameid < 1100) || - (nameid > 7000 && nameid < 8000)) - id->type = ItemType::JUNK; - else if (nameid >= 1750 && nameid < 1771) - id->type = ItemType::ARROW; - else if (nameid > 1100 && nameid < 2000) - id->type = ItemType::WEAPON; - else if ((nameid > 2100 && nameid < 3000) || - (nameid > 5000 && nameid < 6000)) - id->type = ItemType::ARMOR; - else if (nameid > 4000 && nameid < 5000) - id->type = ItemType::_6; + id->type = ItemType::JUNK; return id; } @@ -125,7 +109,7 @@ struct item_data *itemdb_search(int nameid) * *------------------------------------------ */ -int itemdb_isequip(int nameid) +int itemdb_isequip(ItemNameId nameid) { ItemType type = itemdb_type(nameid); return !(type == ItemType::USE @@ -155,7 +139,7 @@ int itemdb_isequip2(struct item_data *data) * *------------------------------------------ */ -int itemdb_isequip3(int nameid) +int itemdb_isequip3(ItemNameId nameid) { ItemType type = itemdb_type(nameid); return (type == ItemType::WEAPON @@ -174,7 +158,7 @@ bool itemdb_readdb(ZString filename) if (!in.is_open()) { - PRINTF("can't read %s\n", filename); + PRINTF("can't read %s\n"_fmt, filename); return false; } @@ -220,7 +204,7 @@ bool itemdb_readdb(ZString filename) ) ) { - PRINTF("%s:%d: error: bad item line: %s\n", + PRINTF("%s:%d: error: bad item line: %s\n"_fmt, filename, lines, line); rv = false; continue; @@ -242,8 +226,8 @@ bool itemdb_readdb(ZString filename) id->value_sell = id->value_buy / 2; } - id->use_script = NULL; - id->equip_script = NULL; + id->use_script = nullptr; + id->equip_script = nullptr; if (!tail_part) continue; @@ -254,7 +238,7 @@ bool itemdb_readdb(ZString filename) continue; id->equip_script = parse_script(tail_part, lines, true); } - PRINTF("read %s done (count=%d)\n", filename, ln); + PRINTF("read %s done (count=%d)\n"_fmt, filename, ln); } return rv; @@ -281,3 +265,4 @@ void do_final_itemdb(void) itemdb_final(&pair.second); item_db.clear(); } +} // namespace tmwa diff --git a/src/map/itemdb.hpp b/src/map/itemdb.hpp index 16802da..25b4dad 100644 --- a/src/map/itemdb.hpp +++ b/src/map/itemdb.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_ITEMDB_HPP -#define TMWA_MAP_ITEMDB_HPP +#pragma once // itemdb.hpp - Item definitions. // // Copyright © ????-2004 Athena Dev Teams @@ -21,16 +20,20 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "../mmo/mmo.hpp" +#include "../mmo/ids.hpp" +#include "../mmo/mmo.hpp" -# include "map.t.hpp" -# include "script.hpp" +#include "map.t.hpp" +#include "script.hpp" + +namespace tmwa +{ struct item_data { - int nameid; + ItemNameId nameid; ItemName name, jname; int value_buy; int value_sell; @@ -58,47 +61,47 @@ struct random_item_data inline struct item_data *itemdb_searchname(ItemName) = delete; struct item_data *itemdb_searchname(XString name); -struct item_data *itemdb_search(int nameid); -struct item_data *itemdb_exists(int nameid); +// TODO this function should die +struct item_data *itemdb_search(ItemNameId nameid); +struct item_data *itemdb_exists(ItemNameId nameid); inline -ItemType itemdb_type(int n) +ItemType itemdb_type(ItemNameId n) { return itemdb_search(n)->type; } inline -ItemLook itemdb_look(int n) +ItemLook itemdb_look(ItemNameId n) { return itemdb_search(n)->look; } inline -int itemdb_weight(int n) +int itemdb_weight(ItemNameId n) { return itemdb_search(n)->weight; } inline -const ScriptBuffer *itemdb_equipscript(int n) +const ScriptBuffer *itemdb_equipscript(ItemNameId n) { return itemdb_search(n)->equip_script.get(); } inline -int itemdb_wlv(int n) +int itemdb_wlv(ItemNameId n) { return itemdb_search(n)->wlv; } inline -int itemdb_value_sell(int n) +int itemdb_value_sell(ItemNameId n) { return itemdb_search(n)->value_sell; } -int itemdb_isequip(int); +int itemdb_isequip(ItemNameId); int itemdb_isequip2(struct item_data *); -int itemdb_isequip3(int); +int itemdb_isequip3(ItemNameId); void itemdb_reload(void); void do_final_itemdb(void); bool itemdb_readdb(ZString filename); - -#endif // TMWA_MAP_ITEMDB_HPP +} // namespace tmwa diff --git a/src/map/magic-expr-eval.cpp b/src/map/magic-expr-eval.cpp index 36b69f5..9903600 100644 --- a/src/map/magic-expr-eval.cpp +++ b/src/map/magic-expr-eval.cpp @@ -19,3 +19,11 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include "../poison.hpp" + + +namespace tmwa +{ +namespace magic +{ +} // namespace magic +} // namespace tmwa diff --git a/src/map/magic-expr-eval.hpp b/src/map/magic-expr-eval.hpp index 9b9f5f8..4529c04 100644 --- a/src/map/magic-expr-eval.hpp +++ b/src/map/magic-expr-eval.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_MAGIC_EXPR_EVAL_HPP -#define TMWA_MAP_MAGIC_EXPR_EVAL_HPP +#pragma once // magic-expr-eval.hpp - Utilities for evaluating magic. // // Copyright © 2004-2011 The Mana World Development Team @@ -20,47 +19,33 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "../range/slice.hpp" +#include "../strings/zstring.hpp" -# include "../strings/zstring.hpp" +#include "magic-interpreter.t.hpp" -# include "magic-interpreter.hpp" -/* Helper definitions for dealing with functions and operations */ +namespace tmwa +{ +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 -int magic_signature_check(ZString opname, ZString funname, ZString signature, - Slice<val_t> args, int line, int column); +#define ENTITY_TYPE(x) ARGENTITY(x)->bl_type -void magic_area_rect(map_local **m, int *x, int *y, int *width, int *height, - area_t& area); +#define ARGPC(x) (ARGENTITY(x)->is_player()) +#define ARGNPC(x) (ARGENTITY(x)->is_npc()) +#define ARGMOB(x) (ARGENTITY(x)->is_mob()) -# define ARGINT(x) args[x].v.v_int -# define ARGDIR(x) args[x].v.v_dir -# define ARGSTR(x) ZString(args[x].v.v_string) -# define ARGENTITY(x) args[x].v.v_entity -# define ARGLOCATION(x) args[x].v.v_location -# define ARGAREA(x) args[x].v.v_area -# define ARGSPELL(x) args[x].v.v_spell -# define ARGINVOCATION(x) args[x].v.v_invocation - -# define RESULTINT result->v.v_int -# define RESULTDIR result->v.v_dir -# define RESULTSTR result->v.v_string -# define RESULTENTITY result->v.v_entity -# define RESULTLOCATION result->v.v_location -# define RESULTAREA result->v.v_area -# define RESULTSPELL result->v.v_spell -# define RESULTINVOCATION result->v.v_invocation - -# define ARG_TYPE(x) args[x].ty -# define ENTITY_TYPE(x) ARGENTITY(x)->bl_type - -# define ARGPC(x) (ARGENTITY(x)->is_player()) -# define ARGNPC(x) (ARGENTITY(x)->is_npc()) -# define ARGMOB(x) (ARGENTITY(x)->is_mob()) - -# define ARG_MAY_BE_AREA(x) (ARG_TYPE(x) == TYPE::AREA || ARG_TYPE(x) == TYPE::LOCATION) - -#endif // TMWA_MAP_MAGIC_EXPR_EVAL_HPP +#define ARG_MAY_BE_AREA(x) (args[x].is<ValArea>() || args[x].is<ValArea>()) +} // namespace magic +} // namespace tmwa diff --git a/src/map/magic-expr.cpp b/src/map/magic-expr.cpp index 42ff3a7..306126e 100644 --- a/src/map/magic-expr.cpp +++ b/src/map/magic-expr.cpp @@ -1,6 +1,4 @@ -#include "magic-expr-eval.hpp" #include "magic-expr.hpp" -#include "magic-interpreter-aux.hpp" // magic-expr.cpp - Pure functions for the old magic backend. // // Copyright © 2004-2011 The Mana World Development Team @@ -22,40 +20,49 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include <cassert> -#include <cmath> -#include "../compat/alg.hpp" +#include <algorithm> #include "../strings/mstring.hpp" #include "../strings/astring.hpp" #include "../strings/zstring.hpp" #include "../strings/vstring.hpp" +#include "../strings/literal.hpp" +#include "../generic/dumb_ptr.hpp" #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" +#include "../io/cxxstdio_enums.hpp" #include "battle.hpp" +#include "itemdb.hpp" +#include "magic-expr-eval.hpp" +#include "magic-interpreter.hpp" +#include "magic-interpreter-base.hpp" #include "npc.hpp" #include "pc.hpp" -#include "itemdb.hpp" #include "../poison.hpp" + +namespace tmwa +{ +namespace magic +{ static void free_area(dumb_ptr<area_t> area) { if (!area) return; - switch (area->ty) + MATCH (*area) { - case AREA::UNION: - free_area(area->a.a_union[0]); - free_area(area->a.a_union[1]); - break; - default: - break; + CASE (const AreaUnion&, a) + { + free_area(a.a_union[0]); + free_area(a.a_union[1]); + } } area.delete_(); @@ -64,52 +71,108 @@ void free_area(dumb_ptr<area_t> area) static dumb_ptr<area_t> dup_area(dumb_ptr<area_t> area) { - dumb_ptr<area_t> retval = dumb_ptr<area_t>::make(); - *retval = *area; - - switch (area->ty) + MATCH (*area) { - case AREA::UNION: - retval->a.a_union[0] = dup_area(retval->a.a_union[0]); - retval->a.a_union[1] = dup_area(retval->a.a_union[1]); - break; - default: - break; + CASE (const location_t&, loc) + { + return dumb_ptr<area_t>::make(loc, area->size); + } + CASE (const AreaUnion&, a) + { + AreaUnion u; + u.a_union[0] = dup_area(a.a_union[0]); + u.a_union[1] = dup_area(a.a_union[1]); + return dumb_ptr<area_t>::make(u, area->size); + } + CASE (const AreaRect&, rect) + { + return dumb_ptr<area_t>::make(rect, area->size); + } + CASE (const AreaBar&, bar) + { + return dumb_ptr<area_t>::make(bar, area->size); + } } - return retval; + abort(); } -void magic_copy_var(val_t *dest, val_t *src) +void magic_copy_var(val_t *dest, const val_t *src) { - *dest = *src; - - switch (dest->ty) + MATCH (*src) { - case TYPE::STRING: - dest->v.v_string = dest->v.v_string.dup(); - break; - case TYPE::AREA: - dest->v.v_area = dup_area(dest->v.v_area); - break; + // mumble mumble not a public API ... default: - break; + { + abort(); + } + CASE (const ValUndef&, s) + { + *dest = s; + } + CASE (const ValInt&, s) + { + *dest = s; + } + CASE (const ValDir&, s) + { + *dest = s; + } + CASE (const ValString&, s) + { + *dest = ValString{s.v_string.dup()}; + } + CASE (const ValEntityInt&, s) + { + *dest = s; + } + CASE (const ValEntityPtr&, s) + { + *dest = s; + } + CASE (const ValLocation&, s) + { + *dest = s; + } + CASE (const ValArea&, s) + { + *dest = ValArea{dup_area(s.v_area)}; + } + CASE (const ValSpell&, s) + { + *dest = s; + } + CASE (const ValInvocationInt&, s) + { + *dest = s; + } + CASE (const ValInvocationPtr&, s) + { + *dest = s; + } + CASE (const ValFail&, s) + { + *dest = s; + } + CASE (const ValNegative1&, s) + { + *dest = s; + } } - } void magic_clear_var(val_t *v) { - switch (v->ty) + MATCH (*v) { - case TYPE::STRING: - v->v.v_string.delete_(); - break; - case TYPE::AREA: - free_area(v->v.v_area); - break; - default: - break; + CASE (ValString&, s) + { + s.v_string.delete_(); + } + CASE (const ValArea&, a) + { + free_area(a.v_area); + } } } @@ -125,113 +188,110 @@ AString show_entity(dumb_ptr<block_list> entity) case BL::MOB: return entity->is_mob()->name; case BL::ITEM: - assert (0 && "There is no way this code did what it was supposed to do!"); + assert (0 && "There is no way this code did what it was supposed to do!"_s); /* Sorry about this one... */ - // WTF? item_data is a struct item, not a struct item_data + // WTF? item_data is a Item, not a struct item_data // return ((struct item_data *) (&entity->is_item()->item_data))->name; abort(); case BL::SPELL: - return {"%invocation(ERROR:this-should-not-be-an-entity)"}; + return "%invocation(ERROR:this-should-not-be-an-entity)"_s; default: - return {"%unknown-entity"}; + return "%unknown-entity"_s; } } static -void stringify(val_t *v, int within_op) +void stringify(val_t *v) { - static earray<ZString, DIR, DIR::COUNT> dirs //= + static earray<LString, DIR, DIR::COUNT> dirs //= {{ - {"south"}, {"south-west"}, - {"west"}, {"north-west"}, - {"north"}, {"north-east"}, - {"east"}, {"south-east"}, + "south"_s, "south-west"_s, + "west"_s, "north-west"_s, + "north"_s, "north-east"_s, + "east"_s, "south-east"_s, }}; AString buf; - switch (v->ty) + MATCH (*v) { - case TYPE::UNDEF: - buf = "UNDEF"; - break; - - case TYPE::INT: - buf = STRPRINTF("%i", v->v.v_int); - break; - - case TYPE::STRING: + default: + { + abort(); + } + CASE (const ValUndef&, x) + { + (void)x; + buf = "UNDEF"_s; + } + CASE (const ValInt&, x) + { + buf = STRPRINTF("%i"_fmt, x.v_int); + } + CASE (const ValString&, x) + { + (void)x; return; - - case TYPE::DIR: - buf = dirs[v->v.v_dir]; - break; - - case TYPE::ENTITY: - buf = show_entity(v->v.v_entity); - break; - - case TYPE::LOCATION: - buf = STRPRINTF("<\"%s\", %d, %d>", - v->v.v_location.m->name_, - v->v.v_location.x, - v->v.v_location.y); - break; - - case TYPE::AREA: - buf = "%area"; - free_area(v->v.v_area); - break; - - case TYPE::SPELL: - buf = v->v.v_spell->name; + } + CASE (const ValDir&, x) + { + buf = dirs[x.v_dir]; + } + CASE (const ValEntityPtr&, x) + { + buf = show_entity(x.v_entity); + } + CASE (const ValLocation&, x) + { + buf = STRPRINTF("<\"%s\", %d, %d>"_fmt, + x.v_location.m->name_, + x.v_location.x, + x.v_location.y); + } + CASE (const ValArea&, x) + { + buf = "%area"_s; + free_area(x.v_area); + } + CASE (const ValSpell&, x) + { + buf = x.v_spell->name; break; - - case TYPE::INVOCATION: + } + CASE (const ValInvocationInt&, x) { - dumb_ptr<invocation> invocation_ = within_op - ? v->v.v_invocation - : map_id2bl(v->v.v_int)->is_spell(); + dumb_ptr<invocation> invocation_ = + map_id2bl(x.v_iid)->is_spell(); + buf = invocation_->spell->name; + } + CASE (const ValInvocationPtr&, x) + { + dumb_ptr<invocation> invocation_ = + x.v_invocation; buf = invocation_->spell->name; } - break; - - default: - FPRINTF(stderr, "[magic] INTERNAL ERROR: Cannot stringify %d\n", - v->ty); - return; } - v->v.v_string = dumb_string::copys(buf); - v->ty = TYPE::STRING; + *v = ValString{dumb_string::copys(buf)}; } static void intify(val_t *v) { - if (v->ty == TYPE::INT) + if (v->is<ValInt>()) return; magic_clear_var(v); - v->ty = TYPE::INT; - v->v.v_int = 1; -} - -static -dumb_ptr<area_t> area_new(AREA ty) -{ - auto retval = dumb_ptr<area_t>::make(); - retval->ty = ty; - return retval; + *v = ValInt{1}; } static dumb_ptr<area_t> area_union(dumb_ptr<area_t> area, dumb_ptr<area_t> other_area) { - dumb_ptr<area_t> retval = area_new(AREA::UNION); - retval->a.a_union[0] = area; - retval->a.a_union[1] = other_area; - retval->size = area->size + other_area->size; /* Assume no overlap */ - return retval; + AreaUnion a; + a.a_union[0] = area; + a.a_union[1] = other_area; + int size = area->size + other_area->size; /* Assume no overlap */ + return dumb_ptr<area_t>::make(a, size); } /** @@ -240,41 +300,43 @@ dumb_ptr<area_t> area_union(dumb_ptr<area_t> area, dumb_ptr<area_t> other_area) static void make_area(val_t *v) { - if (v->ty == TYPE::LOCATION) + if (ValLocation *l = v->get_if<ValLocation>()) { - auto a = dumb_ptr<area_t>::make(); - v->ty = TYPE::AREA; - a->ty = AREA::LOCATION; - a->a.a_loc = v->v.v_location; - v->v.v_area = a; + auto a = dumb_ptr<area_t>::make(l->v_location, 1); + *v = ValArea{a}; } } static void make_location(val_t *v) { - if (v->ty == TYPE::AREA && v->v.v_area->ty == AREA::LOCATION) + if (ValArea *a = v->get_if<ValArea>()) { - location_t location = v->v.v_area->a.a_loc; - free_area(v->v.v_area); - v->ty = TYPE::LOCATION; - v->v.v_location = location; + MATCH (*a->v_area) + { + CASE (const location_t&, location) + { + free_area(a->v_area); + *v = ValLocation{location}; + } + } } } static void make_spell(val_t *v) { - if (v->ty == TYPE::INVOCATION) + assert(!v->is<ValInvocationInt>()); + if (ValInvocationPtr *p = v->get_if<ValInvocationPtr>()) { - dumb_ptr<invocation> invoc = v->v.v_invocation; - //invoc = (dumb_ptr<invocation>) map_id2bl(v->v.v_int); + dumb_ptr<invocation> invoc = p->v_invocation; if (!invoc) - v->ty = TYPE::FAIL; + { + *v = ValFail{}; + } else { - v->ty = TYPE::SPELL; - v->v.v_spell = invoc->spell; + *v = ValSpell{invoc->spell}; } } } @@ -282,34 +344,31 @@ void make_spell(val_t *v) static int fun_add(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - if (ARG_TYPE(0) == TYPE::INT && ARG_TYPE(1) == TYPE::INT) + if (args[0].is<ValInt>() && args[1].is<ValInt>()) { /* Integer addition */ - RESULTINT = ARGINT(0) + ARGINT(1); - result->ty = TYPE::INT; + *result = ValInt{ARGINT(0) + ARGINT(1)}; } else if (ARG_MAY_BE_AREA(0) && ARG_MAY_BE_AREA(1)) { /* Area union */ make_area(&args[0]); make_area(&args[1]); - RESULTAREA = area_union(ARGAREA(0), ARGAREA(1)); - ARGAREA(0) = NULL; - ARGAREA(1) = NULL; - result->ty = TYPE::AREA; + *result = ValArea{area_union(ARGAREA(0), ARGAREA(1))}; + ARGAREA(0) = nullptr; args[0] = ValUndef{}; + ARGAREA(1) = nullptr; args[1] = ValUndef{}; } else { /* Anything else -> string concatenation */ - stringify(&args[0], 1); - stringify(&args[1], 1); + stringify(&args[0]); + stringify(&args[1]); /* Yes, we could speed this up. */ // ugh MString m; m += ARGSTR(0); m += ARGSTR(1); - RESULTSTR = dumb_string::copys(AString(m)); - result->ty = TYPE::STRING; + *result = ValString{dumb_string::copys(AString(m))}; } return 0; } @@ -317,14 +376,14 @@ int fun_add(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) static int fun_sub(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) - ARGINT(1); + *result = ValInt{ARGINT(0) - ARGINT(1)}; return 0; } static int fun_mul(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) * ARGINT(1); + *result = ValInt{ARGINT(0) * ARGINT(1)}; return 0; } @@ -333,7 +392,7 @@ int fun_div(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (!ARGINT(1)) return 1; /* division by zero */ - RESULTINT = ARGINT(0) / ARGINT(1); + *result = ValInt{ARGINT(0) / ARGINT(1)}; return 0; } @@ -342,52 +401,52 @@ int fun_mod(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (!ARGINT(1)) return 1; /* division by zero */ - RESULTINT = ARGINT(0) % ARGINT(1); + *result = ValInt{ARGINT(0) % ARGINT(1)}; return 0; } static int fun_or(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) || ARGINT(1); + *result = ValInt{ARGINT(0) || ARGINT(1)}; return 0; } static int fun_and(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) && ARGINT(1); + *result = ValInt{ARGINT(0) && ARGINT(1)}; return 0; } static int fun_not(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = !ARGINT(0); + *result = ValInt{!ARGINT(0)}; return 0; } static int fun_neg(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ~ARGINT(0); + *result = ValInt{~ARGINT(0)}; return 0; } static int fun_gte(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - if (ARG_TYPE(0) == TYPE::STRING || ARG_TYPE(1) == TYPE::STRING) + if (args[0].is<ValString>() || args[1].is<ValString>()) { - stringify(&args[0], 1); - stringify(&args[1], 1); - RESULTINT = ARGSTR(0) >= ARGSTR(1); + stringify(&args[0]); + stringify(&args[1]); + *result = ValInt{ARGSTR(0) >= ARGSTR(1)}; } else { intify(&args[0]); intify(&args[1]); - RESULTINT = ARGINT(0) >= ARGINT(1); + *result = ValInt{ARGINT(0) >= ARGINT(1)}; } return 0; } @@ -396,24 +455,24 @@ static int fun_lt(dumb_ptr<env_t> env, val_t *result, Slice<val_t> args) { fun_gte(env, result, args); - RESULTINT = !RESULTINT; + result->get_if<ValInt>()->v_int ^= 1; return 0; } static int fun_gt(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - if (ARG_TYPE(0) == TYPE::STRING || ARG_TYPE(1) == TYPE::STRING) + if (args[0].is<ValString>() || args[1].is<ValString>()) { - stringify(&args[0], 1); - stringify(&args[1], 1); - RESULTINT = ARGSTR(0) > ARGSTR(1); + stringify(&args[0]); + stringify(&args[1]); + *result = ValInt{ARGSTR(0) > ARGSTR(1)}; } else { intify(&args[0]); intify(&args[1]); - RESULTINT = ARGINT(0) > ARGINT(1); + *result = ValInt{ARGINT(0) > ARGINT(1)}; } return 0; } @@ -422,38 +481,38 @@ static int fun_lte(dumb_ptr<env_t> env, val_t *result, Slice<val_t> args) { fun_gt(env, result, args); - RESULTINT = !RESULTINT; + result->get_if<ValInt>()->v_int ^= 1; return 0; } static int fun_eq(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - if (ARG_TYPE(0) == TYPE::STRING || ARG_TYPE(1) == TYPE::STRING) + if (args[0].is<ValString>() || args[1].is<ValString>()) { - stringify(&args[0], 1); - stringify(&args[1], 1); - RESULTINT = ARGSTR(0) == ARGSTR(1); + stringify(&args[0]); + stringify(&args[1]); + *result = ValInt{ARGSTR(0) == ARGSTR(1)}; } - else if (ARG_TYPE(0) == TYPE::DIR && ARG_TYPE(1) == TYPE::DIR) - RESULTINT = ARGDIR(0) == ARGDIR(1); - else if (ARG_TYPE(0) == TYPE::ENTITY && ARG_TYPE(1) == TYPE::ENTITY) - RESULTINT = ARGENTITY(0) == ARGENTITY(1); - else if (ARG_TYPE(0) == TYPE::LOCATION && ARG_TYPE(1) == TYPE::LOCATION) - RESULTINT = (ARGLOCATION(0).x == ARGLOCATION(1).x + else if (args[0].is<ValDir>() && args[1].is<ValDir>()) + *result = ValInt{ARGDIR(0) == ARGDIR(1)}; + else if (args[0].is<ValEntityPtr>() && args[1].is<ValEntityPtr>()) + *result = ValInt{ARGENTITY(0) == ARGENTITY(1)}; + else if (args[0].is<ValLocation>() && args[1].is<ValLocation>()) + *result = ValInt{(ARGLOCATION(0).x == ARGLOCATION(1).x && ARGLOCATION(0).y == ARGLOCATION(1).y - && ARGLOCATION(0).m == ARGLOCATION(1).m); - else if (ARG_TYPE(0) == TYPE::AREA && ARG_TYPE(1) == TYPE::AREA) - RESULTINT = ARGAREA(0) == ARGAREA(1); /* Probably not that great an idea... */ - else if (ARG_TYPE(0) == TYPE::SPELL && ARG_TYPE(1) == TYPE::SPELL) - RESULTINT = ARGSPELL(0) == ARGSPELL(1); - else if (ARG_TYPE(0) == TYPE::INVOCATION && ARG_TYPE(1) == TYPE::INVOCATION) - RESULTINT = ARGINVOCATION(0) == ARGINVOCATION(1); + && ARGLOCATION(0).m == ARGLOCATION(1).m)}; + else if (args[0].is<ValArea>() && args[1].is<ValArea>()) + *result = ValInt{ARGAREA(0) == ARGAREA(1)}; /* Probably not that great an idea... */ + else if (args[0].is<ValSpell>() && args[1].is<ValSpell>()) + *result = ValInt{ARGSPELL(0) == ARGSPELL(1)}; + else if (args[0].is<ValInvocationPtr>() && args[1].is<ValInvocationPtr>()) + *result = ValInt{ARGINVOCATION(0) == ARGINVOCATION(1)}; else { intify(&args[0]); intify(&args[1]); - RESULTINT = ARGINT(0) == ARGINT(1); + *result = ValInt{ARGINT(0) == ARGINT(1)}; } return 0; } @@ -462,56 +521,56 @@ static int fun_ne(dumb_ptr<env_t> env, val_t *result, Slice<val_t> args) { fun_eq(env, result, args); - RESULTINT = !RESULTINT; + result->get_if<ValInt>()->v_int ^= 1; return 0; } static int fun_bitand(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) & ARGINT(1); + *result = ValInt{ARGINT(0) & ARGINT(1)}; return 0; } static int fun_bitor(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) | ARGINT(1); + *result = ValInt{ARGINT(0) | ARGINT(1)}; return 0; } static int fun_bitxor(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) ^ ARGINT(1); + *result = ValInt{ARGINT(0) ^ ARGINT(1)}; return 0; } static int fun_bitshl(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) << ARGINT(1); + *result = ValInt{ARGINT(0) << ARGINT(1)}; return 0; } static int fun_bitshr(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGINT(0) >> ARGINT(1); + *result = ValInt{ARGINT(0) >> ARGINT(1)}; return 0; } static int fun_max(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = max(ARGINT(0), ARGINT(1)); + *result = ValInt{std::max(ARGINT(0), ARGINT(1))}; return 0; } static int fun_min(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = min(ARGINT(0), ARGINT(1)); + *result = ValInt{std::min(ARGINT(0), ARGINT(1))}; return 0; } @@ -528,37 +587,38 @@ int fun_if_then_else(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) void magic_area_rect(map_local **m, int *x, int *y, int *width, int *height, area_t& area_) { - area_t *area = &area_; // diff hack - switch (area->ty) + MATCH (area_) { - case AREA::UNION: - break; - - case AREA::LOCATION: - *m = area->a.a_loc.m; - *x = area->a.a_loc.x; - *y = area->a.a_loc.y; + CASE (const AreaUnion&, a) + { + (void)a; + abort(); + } + CASE (const location_t&, a_loc) + { + *m = a_loc.m; + *x = a_loc.x; + *y = a_loc.y; *width = 1; *height = 1; - break; - - case AREA::RECT: - *m = area->a.a_rect.loc.m; - *x = area->a.a_rect.loc.x; - *y = area->a.a_rect.loc.y; - *width = area->a.a_rect.width; - *height = area->a.a_rect.height; - break; - - case AREA::BAR: + } + CASE (const AreaRect&, a_rect) + { + *m = a_rect.loc.m; + *x = a_rect.loc.x; + *y = a_rect.loc.y; + *width = a_rect.width; + *height = a_rect.height; + } + CASE (const AreaBar&, a_bar) { - int tx = area->a.a_bar.loc.x; - int ty = area->a.a_bar.loc.y; - int twidth = area->a.a_bar.width; - int tdepth = area->a.a_bar.width; - *m = area->a.a_bar.loc.m; + int tx = a_bar.loc.x; + int ty = a_bar.loc.y; + int twidth = a_bar.width; + int tdepth = a_bar.width; + *m = a_bar.loc.m; - switch (area->a.a_bar.dir) + switch (a_bar.dir) { case DIR::S: *x = tx - twidth; @@ -590,27 +650,50 @@ void magic_area_rect(map_local **m, int *x, int *y, int *width, int *height, default: FPRINTF(stderr, - "Error: Trying to compute area of NE/SE/NW/SW-facing bar"); + "Error: Trying to compute area of NE/SE/NW/SW-facing bar"_fmt); *x = tx; *y = ty; *width = *height = 1; } - break; } } } int magic_location_in_area(map_local *m, int x, int y, dumb_ptr<area_t> area) { - switch (area->ty) + MATCH (*area) { - case AREA::UNION: - return magic_location_in_area(m, x, y, area->a.a_union[0]) - || magic_location_in_area(m, x, y, area->a.a_union[1]); - case AREA::LOCATION: - case AREA::RECT: - case AREA::BAR: + CASE (const AreaUnion&, a) + { + return magic_location_in_area(m, x, y, a.a_union[0]) + || magic_location_in_area(m, x, y, a.a_union[1]); + } + CASE (const location_t&, a_loc) { + (void)a_loc; + // TODO this can be simplified + map_local *am; + int ax, ay, awidth, aheight; + magic_area_rect(&am, &ax, &ay, &awidth, &aheight, *area); + return (am == m + && (x >= ax) && (y >= ay) + && (x < ax + awidth) && (y < ay + aheight)); + } + CASE (const AreaRect&, a_rect) + { + (void)a_rect; + // TODO this is too complicated + map_local *am; + int ax, ay, awidth, aheight; + magic_area_rect(&am, &ax, &ay, &awidth, &aheight, *area); + return (am == m + && (x >= ax) && (y >= ay) + && (x < ax + awidth) && (y < ay + aheight)); + } + CASE (const AreaBar&, a_bar) + { + (void)a_bar; + // TODO this is wrong map_local *am; int ax, ay, awidth, aheight; magic_area_rect(&am, &ax, &ay, &awidth, &aheight, *area); @@ -618,18 +701,16 @@ int magic_location_in_area(map_local *m, int x, int y, dumb_ptr<area_t> area) && (x >= ax) && (y >= ay) && (x < ax + awidth) && (y < ay + aheight)); } - default: - FPRINTF(stderr, "INTERNAL ERROR: Invalid area\n"); - return 0; } + abort(); } static int fun_is_in(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = magic_location_in_area(ARGLOCATION(0).m, + *result = ValInt{magic_location_in_area(ARGLOCATION(0).m, ARGLOCATION(0).x, - ARGLOCATION(0).y, ARGAREA(1)); + ARGLOCATION(0).y, ARGAREA(1))}; return 0; } @@ -638,15 +719,16 @@ int fun_skill(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (ENTITY_TYPE(0) != BL::PC // don't convert to enum until after the range check + // (actually it would be okay, I checked) || ARGINT(1) < 0 - || ARGINT(1) >= uint16_t(MAX_SKILL)) + || ARGINT(1) >= static_cast<uint16_t>(MAX_SKILL)) { - RESULTINT = 0; + *result = ValInt{0}; } else { SkillID id = static_cast<SkillID>(ARGINT(1)); - RESULTINT = ARGPC(0)->status.skill[id].lv; + *result = ValInt{ARGPC(0)->status.skill[id].lv}; } return 0; } @@ -654,7 +736,7 @@ int fun_skill(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) static int fun_his_shroud(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = (ENTITY_TYPE(0) == BL::PC && ARGPC(0)->state.shroud_active); + *result = ValInt{(ENTITY_TYPE(0) == BL::PC && ARGPC(0)->state.shroud_active)}; return 0; } @@ -662,7 +744,7 @@ int fun_his_shroud(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) static \ int fun_get_##name(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) \ { \ - RESULTINT = battle_get_##name(ARGENTITY(0)); \ + *result = ValInt{battle_get_##name(ARGENTITY(0))}; \ return 0; \ } @@ -680,7 +762,7 @@ BATTLE_GETTER(max_hp) static int fun_get_dir(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTDIR = battle_get_dir(ARGENTITY(0)); + *result = ValDir{battle_get_dir(ARGENTITY(0))}; return 0; } @@ -689,9 +771,9 @@ static \ int fun_get_##name(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) \ { \ if (ENTITY_TYPE(0) == BL::PC) \ - RESULTINT = ARGPC(0)->status.name; \ + *result = ValInt{ARGPC(0)->status.name}; \ else \ - RESULTINT = 0; \ + *result = ValInt{0}; \ return 0; \ } @@ -701,19 +783,19 @@ MMO_GETTER(max_sp) static int fun_name_of(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - if (ARG_TYPE(0) == TYPE::ENTITY) + if (args[0].is<ValEntityPtr>()) { - RESULTSTR = dumb_string::copys(show_entity(ARGENTITY(0))); + *result = ValString{dumb_string::copys(show_entity(ARGENTITY(0)))}; return 0; } - else if (ARG_TYPE(0) == TYPE::SPELL) + else if (args[0].is<ValSpell>()) { - RESULTSTR = dumb_string::copys(ARGSPELL(0)->name); + *result = ValString{dumb_string::copys(ARGSPELL(0)->name)}; return 0; } - else if (ARG_TYPE(0) == TYPE::INVOCATION) + else if (args[0].is<ValInvocationPtr>()) { - RESULTSTR = dumb_string::copys(ARGINVOCATION(0)->spell->name); + *result = ValString{dumb_string::copys(ARGINVOCATION(0)->spell->name)}; return 0; } return 1; @@ -725,7 +807,7 @@ int fun_mob_id(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (ENTITY_TYPE(0) != BL::MOB) return 1; - RESULTINT = ARGMOB(0)->mob_class; + *result = ValInt{unwrap<Species>(ARGMOB(0)->mob_class)}; return 0; } @@ -748,7 +830,9 @@ void COPY_LOCATION(location_t& dest, block_list& src) static int fun_location(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - COPY_LOCATION(RESULTLOCATION, *(ARGENTITY(0))); + location_t loc; + COPY_LOCATION(loc, *(ARGENTITY(0))); + *result = ValLocation{loc}; return 0; } @@ -760,13 +844,13 @@ int fun_random(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) delta = -delta; if (delta == 0) { - RESULTINT = 0; + *result = ValInt{0}; return 0; } - RESULTINT = random_::to(delta); + *result = ValInt{random_::to(delta)}; if (ARGINT(0) < 0) - RESULTINT = -RESULTINT; + result->get_if<ValInt>()->v_int *= -1; return 0; } @@ -774,28 +858,28 @@ static int fun_random_dir(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (ARGINT(0)) - RESULTDIR = random_::choice({DIR::S, DIR::SW, DIR::W, DIR::NW, DIR::N, DIR::NE, DIR::E, DIR::SE}); + *result = ValDir{random_::choice({DIR::S, DIR::SW, DIR::W, DIR::NW, DIR::N, DIR::NE, DIR::E, DIR::SE})}; else - RESULTDIR = random_::choice({DIR::S, DIR::W, DIR::N, DIR::E}); + *result = ValDir{random_::choice({DIR::S, DIR::W, DIR::N, DIR::E})}; return 0; } static int fun_hash_entity(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARGENTITY(0)->bl_id; + *result = ValInt{static_cast<int32_t>(unwrap<BlockId>(ARGENTITY(0)->bl_id))}; return 0; } -int // ret -1: not a string, ret 1: no such item, ret 0: OK -magic_find_item(Slice<val_t> args, int index, struct item *item_, int *stackable) +// ret -1: not a string, ret 1: no such item, ret 0: OK +int magic_find_item(Slice<val_t> args, int index, Item *item_, int *stackable) { struct item_data *item_data; int must_add_sequentially; - if (ARG_TYPE(index) == TYPE::INT) - item_data = itemdb_exists(ARGINT(index)); - else if (ARG_TYPE(index) == TYPE::STRING) + if (args[index].is<ValInt>()) + item_data = itemdb_exists(wrap<ItemNameId>(static_cast<uint16_t>(ARGINT(index)))); + else if (args[index].is<ValString>()) item_data = itemdb_searchname(ARGSTR(index)); else return -1; @@ -813,7 +897,7 @@ magic_find_item(Slice<val_t> args, int index, struct item *item_, int *stackable if (stackable) *stackable = !must_add_sequentially; - *item_ = item(); + *item_ = Item(); item_->nameid = item_data->nameid; return 0; @@ -822,25 +906,25 @@ magic_find_item(Slice<val_t> args, int index, struct item *item_, int *stackable static int fun_count_item(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - dumb_ptr<map_session_data> chr = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : NULL; + dumb_ptr<map_session_data> chr = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr; int stackable; - struct item item; + Item item; GET_ARG_ITEM(1, item, stackable); if (!chr) return 1; - RESULTINT = pc_count_all_items(chr, item.nameid); + *result = ValInt{pc_count_all_items(chr, item.nameid)}; return 0; } static int fun_is_equipped(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - dumb_ptr<map_session_data> chr = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : NULL; + dumb_ptr<map_session_data> chr = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr; int stackable; - struct item item; + Item item; bool retval = false; GET_ARG_ITEM(1, item, stackable); @@ -850,36 +934,36 @@ int fun_is_equipped(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) for (EQUIP i : EQUIPs) { - int idx = chr->equip_index_maybe[i]; - if (idx >= 0 && chr->status.inventory[idx].nameid == item.nameid) + IOff0 idx = chr->equip_index_maybe[i]; + if (idx.ok() && chr->status.inventory[idx].nameid == item.nameid) { retval = true; break; } } - RESULTINT = retval; + *result = ValInt{retval}; return 0; } static int fun_is_married(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = (ENTITY_TYPE(0) == BL::PC && ARGPC(0)->status.partner_id); + *result = ValInt{(ENTITY_TYPE(0) == BL::PC && ARGPC(0)->status.partner_id)}; return 0; } static int fun_is_dead(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = (ENTITY_TYPE(0) == BL::PC && pc_isdead(ARGPC(0))); + *result = ValInt{(ENTITY_TYPE(0) == BL::PC && pc_isdead(ARGPC(0)))}; return 0; } static int fun_is_pc(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = (ENTITY_TYPE(0) == BL::PC); + *result = ValInt{(ENTITY_TYPE(0) == BL::PC)}; return 0; } @@ -888,8 +972,8 @@ int fun_partner(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (ENTITY_TYPE(0) == BL::PC && ARGPC(0)->status.partner_id) { - RESULTENTITY = - map_nick2sd(map_charid2nick(ARGPC(0)->status.partner_id)); + *result = + ValEntityPtr{map_nick2sd(map_charid2nick(ARGPC(0)->status.partner_id))}; return 0; } else @@ -911,14 +995,14 @@ int fun_awayfrom(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) loc->y += dy; } - RESULTLOCATION = *loc; + *result = ValLocation{*loc}; return 0; } static int fun_failed(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = ARG_TYPE(0) == TYPE::FAIL; + *result = ValInt{args[0].is<ValFail>()}; return 0; } @@ -926,26 +1010,28 @@ static int fun_npc(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { NpcName name = stringish<NpcName>(ARGSTR(0)); - RESULTENTITY = npc_name2id(name); - return RESULTENTITY == NULL; + dumb_ptr<npc_data> npc = npc_name2id(name); + *result = ValEntityPtr{npc}; + return npc == nullptr; } static int fun_pc(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { CharName name = stringish<CharName>(ARGSTR(0)); - RESULTENTITY = map_nick2sd(name); - return RESULTENTITY == NULL; + dumb_ptr<map_session_data> chr = map_nick2sd(name); + *result = ValEntityPtr{chr}; + return chr == nullptr; } static int fun_distance(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (ARGLOCATION(0).m != ARGLOCATION(1).m) - RESULTINT = 0x7fffffff; + *result = ValInt{0x7fffffff}; else - RESULTINT = max(abs(ARGLOCATION(0).x - ARGLOCATION(1).x), - abs(ARGLOCATION(0).y - ARGLOCATION(1).y)); + *result = ValInt{std::max(abs(ARGLOCATION(0).x - ARGLOCATION(1).x), + abs(ARGLOCATION(0).y - ARGLOCATION(1).y))}; return 0; } @@ -953,12 +1039,12 @@ static int fun_rdistance(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { if (ARGLOCATION(0).m != ARGLOCATION(1).m) - RESULTINT = 0x7fffffff; + *result = ValInt{0x7fffffff}; else { int dx = ARGLOCATION(0).x - ARGLOCATION(1).x; int dy = ARGLOCATION(0).y - ARGLOCATION(1).y; - RESULTINT = static_cast<int>(sqrt((dx * dx) + (dy * dy))); + *result = ValInt{static_cast<int>(sqrt((dx * dx) + (dy * dy)))}; } return 0; } @@ -974,7 +1060,7 @@ int fun_anchor(dumb_ptr<env_t> env, val_t *result, Slice<val_t> args) magic_eval(env, result, anchor->location); make_area(result); - if (result->ty != TYPE::AREA) + if (!result->is<ValArea>()) { magic_clear_var(result); return 1; @@ -991,28 +1077,48 @@ int fun_line_of_sight(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) COPY_LOCATION(e1, ARGLOCATION(0)); COPY_LOCATION(e2, ARGLOCATION(1)); - RESULTINT = battle_check_range(dumb_ptr<block_list>(&e1), dumb_ptr<block_list>(&e2), 0); + *result = ValInt{battle_check_range(dumb_ptr<block_list>(&e1), dumb_ptr<block_list>(&e2), 0)}; return 0; } void magic_random_location(location_t *dest, dumb_ptr<area_t> area) { - switch (area->ty) + MATCH (*area) { - case AREA::UNION: + CASE (const AreaUnion&, a) { - if (random_::chance({area->a.a_union[0]->size, area->size})) - magic_random_location(dest, area->a.a_union[0]); + if (random_::chance({a.a_union[0]->size, area->size})) + magic_random_location(dest, a.a_union[0]); else - magic_random_location(dest, area->a.a_union[1]); - break; + magic_random_location(dest, a.a_union[1]); } + CASE (const location_t&, a_loc) + { + (void)a_loc; + // TODO this can be simplified + map_local *m; + int x, y, w, h; + magic_area_rect(&m, &x, &y, &w, &h, *area); + + if (w <= 1) + w = 1; - case AREA::LOCATION: - case AREA::RECT: - case AREA::BAR: + if (h <= 1) + h = 1; + + // This is not exactly the same as the old logic, + // but it's better. + auto pair = map_randfreecell(m, x, y, w, h); + + dest->m = m; + dest->x = pair.first; + dest->y = pair.second; + } + CASE (const AreaRect&, a_rect) { + (void)a_rect; + // TODO this can be simplified map_local *m; int x, y, w, h; magic_area_rect(&m, &x, &y, &w, &h, *area); @@ -1030,19 +1136,38 @@ void magic_random_location(location_t *dest, dumb_ptr<area_t> area) dest->m = m; dest->x = pair.first; dest->y = pair.second; - break; } + CASE (const AreaBar&, a_bar) + { + (void)a_bar; + // TODO this is wrong + map_local *m; + int x, y, w, h; + magic_area_rect(&m, &x, &y, &w, &h, *area); - default: - FPRINTF(stderr, "Unknown area type %d\n", - area->ty); + if (w <= 1) + w = 1; + + if (h <= 1) + h = 1; + + // This is not exactly the same as the old logic, + // but it's better. + auto pair = map_randfreecell(m, x, y, w, h); + + dest->m = m; + dest->x = pair.first; + dest->y = pair.second; + } } } static int fun_pick_location(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - magic_random_location(&result->v.v_location, ARGAREA(0)); + location_t loc; + magic_random_location(&loc, ARGAREA(0)); + *result = ValLocation{loc}; return 0; } @@ -1056,7 +1181,7 @@ int fun_read_script_int(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) if (subject_p->bl_type != BL::PC) return 1; - RESULTINT = get_script_var_i(subject_p->is_player(), var_name, array_index); + *result = ValInt{get_script_var_i(subject_p->is_player(), var_name, array_index)}; return 0; } @@ -1070,7 +1195,7 @@ int fun_read_script_str(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) if (subject_p->bl_type != BL::PC) return 1; - RESULTSTR = dumb_string::copys(get_script_var_s(subject_p->is_player(), var_name, array_index)); + *result = ValString{dumb_string::copys(get_script_var_s(subject_p->is_player(), var_name, array_index))}; return 0; } @@ -1080,12 +1205,13 @@ int fun_rbox(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) location_t loc = ARGLOCATION(0); int radius = ARGINT(1); - RESULTAREA = area_new(AREA::RECT); - RESULTAREA->a.a_rect.loc.m = loc.m; - RESULTAREA->a.a_rect.loc.x = loc.x - radius; - RESULTAREA->a.a_rect.loc.y = loc.y - radius; - RESULTAREA->a.a_rect.width = radius * 2 + 1; - RESULTAREA->a.a_rect.height = radius * 2 + 1; + AreaRect a_rect; + a_rect.loc.m = loc.m; + a_rect.loc.x = loc.x - radius; + a_rect.loc.y = loc.y - radius; + a_rect.width = radius * 2 + 1; + a_rect.height = radius * 2 + 1; + *result = ValArea{dumb_ptr<area_t>::make(a_rect, a_rect.width * a_rect.height)}; return 0; } @@ -1097,28 +1223,28 @@ int fun_running_status_update(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) return 1; StatusChange sc = static_cast<StatusChange>(ARGINT(1)); - RESULTINT = bool(battle_get_sc_data(ARGENTITY(0))[sc].timer); + *result = ValInt{bool(battle_get_sc_data(ARGENTITY(0))[sc].timer)}; return 0; } static int fun_status_option(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = (bool((ARGPC(0))->status.option & static_cast<Option>(ARGINT(1)))); + *result = ValInt{(bool((ARGPC(0))->status.option & static_cast<Option>(ARGINT(1))))}; return 0; } static int fun_element(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = static_cast<int>(battle_get_element(ARGENTITY(0)).element); + *result = ValInt{static_cast<int>(battle_get_element(ARGENTITY(0)).element)}; return 0; } static int fun_element_level(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = battle_get_element(ARGENTITY(0)).level; + *result = ValInt{battle_get_element(ARGENTITY(0)).level}; return 0; } @@ -1126,14 +1252,14 @@ static int fun_is_exterior(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { #warning "Evil assumptions!" - RESULTINT = ARGLOCATION(0).m->name_[4] == '1'; + *result = ValInt{ARGLOCATION(0).m->name_[4] == '1'}; return 0; } static int fun_contains_string(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = NULL != strstr(ARGSTR(0).c_str(), ARGSTR(1).c_str()); + *result = ValInt{nullptr != strstr(ARGSTR(0).c_str(), ARGSTR(1).c_str())}; return 0; } @@ -1141,14 +1267,14 @@ static int fun_strstr(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { const char *offset = strstr(ARGSTR(0).c_str(), ARGSTR(1).c_str()); - RESULTINT = offset - ARGSTR(0).c_str(); - return offset == NULL; + *result = ValInt{static_cast<int32_t>(offset - ARGSTR(0).c_str())}; + return offset == nullptr; } static int fun_strlen(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = strlen(ARGSTR(0).c_str()); + *result = ValInt{static_cast<int32_t>(strlen(ARGSTR(0).c_str()))}; return 0; } @@ -1173,7 +1299,7 @@ int fun_substr(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) const char *begin = src + offset; const char *end = begin + len; - RESULTSTR = dumb_string::copy(begin, end); + *result = ValString{dumb_string::copy(begin, end)}; return 0; } @@ -1181,7 +1307,7 @@ int fun_substr(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) static int fun_sqrt(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - RESULTINT = static_cast<int>(sqrt(ARGINT(0))); + *result = ValInt{static_cast<int>(sqrt(ARGINT(0)))}; return 0; } @@ -1189,7 +1315,7 @@ static int fun_map_level(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { #warning "Evil assumptions!" - RESULTINT = ARGLOCATION(0).m->name_[4] - '0'; + *result = ValInt{ARGLOCATION(0).m->name_[4] - '0'}; return 0; } @@ -1199,8 +1325,8 @@ int fun_map_nr(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) #warning "Evil assumptions!" MapName mapname = ARGLOCATION(0).m->name_; - RESULTINT = ((mapname[0] - '0') * 100) - + ((mapname[1] - '0') * 10) + ((mapname[2] - '0')); + *result = ValInt{((mapname[0] - '0') * 100) + + ((mapname[1] - '0') * 10) + ((mapname[2] - '0'))}; return 0; } @@ -1222,30 +1348,30 @@ int fun_dir_towards(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) if (abs(dx) > abs(dy) * 2) { /* east or west */ if (dx < 0) - RESULTINT = 2 /* west */ ; + *result = ValDir{DIR::W}; else - RESULTINT = 6 /* east */ ; + *result = ValDir{DIR::E}; } else if (abs(dy) > abs(dx) * 2) { /* north or south */ if (dy > 0) - RESULTINT = 0 /* south */ ; + *result = ValDir{DIR::S}; else - RESULTINT = 4 /* north */ ; + *result = ValDir{DIR::N}; } else if (dx < 0) { /* north-west or south-west */ if (dy < 0) - RESULTINT = 3 /* north-west */ ; + *result = ValDir{DIR::NW}; else - RESULTINT = 1 /* south-west */ ; + *result = ValDir{DIR::SW}; } else { /* north-east or south-east */ if (dy < 0) - RESULTINT = 5 /* north-east */ ; + *result = ValDir{DIR::NE}; else - RESULTINT = 7 /* south-east */ ; + *result = ValDir{DIR::SE}; } } else @@ -1254,16 +1380,16 @@ int fun_dir_towards(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) if (abs(dx) > abs(dy)) { /* east or west */ if (dx < 0) - RESULTINT = 2 /* west */ ; + *result = ValDir{DIR::W}; else - RESULTINT = 6 /* east */ ; + *result = ValDir{DIR::E}; } else { /* north or south */ if (dy > 0) - RESULTINT = 0 /* south */ ; + *result = ValDir{DIR::S}; else - RESULTINT = 4 /* north */ ; + *result = ValDir{DIR::N}; } } @@ -1273,98 +1399,98 @@ int fun_dir_towards(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) static int fun_extract_healer_xp(dumb_ptr<env_t>, val_t *result, Slice<val_t> args) { - dumb_ptr<map_session_data> sd = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : NULL; + dumb_ptr<map_session_data> sd = (ENTITY_TYPE(0) == BL::PC) ? ARGPC(0) : nullptr; if (!sd) - RESULTINT = 0; + *result = ValInt{0}; else - RESULTINT = pc_extract_healer_exp(sd, ARGINT(1)); + *result = ValInt{pc_extract_healer_exp(sd, ARGINT(1))}; return 0; } -#define MAGIC_FUNCTION(name, args, ret, impl) {{name}, {{name}, {args}, ret, impl}} -#define MAGIC_FUNCTION1(name, args, ret) MAGIC_FUNCTION(#name, args, ret, fun_##name) -static +#define MAGIC_FUNCTION(name, args, ret, impl) {name, {name, args, ret, impl}} +#define MAGIC_FUNCTION1(name, args, ret) MAGIC_FUNCTION(#name##_s, args, ret, fun_##name) +static // should be LString, but no heterogenous lookup yet std::map<ZString, fun_t> functions = { - MAGIC_FUNCTION("+", "..", '.', fun_add), - MAGIC_FUNCTION("-", "ii", 'i', fun_sub), - MAGIC_FUNCTION("*", "ii", 'i', fun_mul), - MAGIC_FUNCTION("/", "ii", 'i', fun_div), - MAGIC_FUNCTION("%", "ii", 'i', fun_mod), - MAGIC_FUNCTION("||", "ii", 'i', fun_or), - MAGIC_FUNCTION("&&", "ii", 'i', fun_and), - MAGIC_FUNCTION("<", "..", 'i', fun_lt), - MAGIC_FUNCTION(">", "..", 'i', fun_gt), - MAGIC_FUNCTION("<=", "..", 'i', fun_lte), - MAGIC_FUNCTION(">=", "..", 'i', fun_gte), - MAGIC_FUNCTION("==", "..", 'i', fun_eq), - MAGIC_FUNCTION("!=", "..", 'i', fun_ne), - MAGIC_FUNCTION("|", "..", 'i', fun_bitor), - MAGIC_FUNCTION("&", "ii", 'i', fun_bitand), - MAGIC_FUNCTION("^", "ii", 'i', fun_bitxor), - MAGIC_FUNCTION("<<", "ii", 'i', fun_bitshl), - MAGIC_FUNCTION(">>", "ii", 'i', fun_bitshr), - MAGIC_FUNCTION1(not, "i", 'i'), - MAGIC_FUNCTION1(neg, "i", 'i'), - MAGIC_FUNCTION1(max, "ii", 'i'), - MAGIC_FUNCTION1(min, "ii", 'i'), - MAGIC_FUNCTION1(is_in, "la", 'i'), - MAGIC_FUNCTION1(if_then_else, "i__", '_'), - MAGIC_FUNCTION1(skill, "ei", 'i'), - MAGIC_FUNCTION("str", "e", 'i', fun_get_str), - MAGIC_FUNCTION("agi", "e", 'i', fun_get_agi), - MAGIC_FUNCTION("vit", "e", 'i', fun_get_vit), - MAGIC_FUNCTION("dex", "e", 'i', fun_get_dex), - MAGIC_FUNCTION("luk", "e", 'i', fun_get_luk), - MAGIC_FUNCTION("int", "e", 'i', fun_get_int), - MAGIC_FUNCTION("level", "e", 'i', fun_get_lv), - MAGIC_FUNCTION("mdef", "e", 'i', fun_get_mdef), - MAGIC_FUNCTION("def", "e", 'i', fun_get_def), - MAGIC_FUNCTION("hp", "e", 'i', fun_get_hp), - MAGIC_FUNCTION("max_hp", "e", 'i', fun_get_max_hp), - MAGIC_FUNCTION("sp", "e", 'i', fun_get_sp), - MAGIC_FUNCTION("max_sp", "e", 'i', fun_get_max_sp), - MAGIC_FUNCTION("dir", "e", 'd', fun_get_dir), - MAGIC_FUNCTION1(name_of, ".", 's'), - MAGIC_FUNCTION1(mob_id, "e", 'i'), - MAGIC_FUNCTION1(location, "e", 'l'), - MAGIC_FUNCTION1(random, "i", 'i'), - MAGIC_FUNCTION1(random_dir, "i", 'd'), - MAGIC_FUNCTION1(hash_entity, "e", 'i'), - MAGIC_FUNCTION1(is_married, "e", 'i'), - MAGIC_FUNCTION1(partner, "e", 'e'), - MAGIC_FUNCTION1(awayfrom, "ldi", 'l'), - MAGIC_FUNCTION1(failed, "_", 'i'), - MAGIC_FUNCTION1(pc, "s", 'e'), - MAGIC_FUNCTION1(npc, "s", 'e'), - MAGIC_FUNCTION1(distance, "ll", 'i'), - MAGIC_FUNCTION1(rdistance, "ll", 'i'), - MAGIC_FUNCTION1(anchor, "s", 'a'), - MAGIC_FUNCTION("random_location", "a", 'l', fun_pick_location), - MAGIC_FUNCTION("script_int", "es", 'i', fun_read_script_int), - MAGIC_FUNCTION("script_str", "es", 's', fun_read_script_str), - MAGIC_FUNCTION1(rbox, "li", 'a'), - MAGIC_FUNCTION1(count_item, "e.", 'i'), - MAGIC_FUNCTION1(line_of_sight, "ll", 'i'), - MAGIC_FUNCTION1(running_status_update, "ei", 'i'), - MAGIC_FUNCTION1(status_option, "ei", 'i'), - MAGIC_FUNCTION1(element, "e", 'i'), - MAGIC_FUNCTION1(element_level, "e", 'i'), - MAGIC_FUNCTION1(his_shroud, "e", 'i'), - MAGIC_FUNCTION1(is_equipped, "e.", 'i'), - MAGIC_FUNCTION1(is_exterior, "l", 'i'), - MAGIC_FUNCTION1(contains_string, "ss", 'i'), - MAGIC_FUNCTION1(strstr, "ss", 'i'), - MAGIC_FUNCTION1(strlen, "s", 'i'), - MAGIC_FUNCTION1(substr, "sii", 's'), - MAGIC_FUNCTION1(sqrt, "i", 'i'), - MAGIC_FUNCTION1(map_level, "l", 'i'), - MAGIC_FUNCTION1(map_nr, "l", 'i'), - MAGIC_FUNCTION1(dir_towards, "lli", 'd'), - MAGIC_FUNCTION1(is_dead, "e", 'i'), - MAGIC_FUNCTION1(is_pc, "e", 'i'), - MAGIC_FUNCTION("extract_healer_experience", "ei", 'i', fun_extract_healer_xp), + MAGIC_FUNCTION("+"_s, ".."_s, '.', fun_add), + MAGIC_FUNCTION("-"_s, "ii"_s, 'i', fun_sub), + MAGIC_FUNCTION("*"_s, "ii"_s, 'i', fun_mul), + MAGIC_FUNCTION("/"_s, "ii"_s, 'i', fun_div), + MAGIC_FUNCTION("%"_s, "ii"_s, 'i', fun_mod), + MAGIC_FUNCTION("||"_s, "ii"_s, 'i', fun_or), + MAGIC_FUNCTION("&&"_s, "ii"_s, 'i', fun_and), + MAGIC_FUNCTION("<"_s, ".."_s, 'i', fun_lt), + MAGIC_FUNCTION(">"_s, ".."_s, 'i', fun_gt), + MAGIC_FUNCTION("<="_s, ".."_s, 'i', fun_lte), + MAGIC_FUNCTION(">="_s, ".."_s, 'i', fun_gte), + MAGIC_FUNCTION("=="_s, ".."_s, 'i', fun_eq), + MAGIC_FUNCTION("!="_s, ".."_s, 'i', fun_ne), + MAGIC_FUNCTION("|"_s, ".."_s, 'i', fun_bitor), + MAGIC_FUNCTION("&"_s, "ii"_s, 'i', fun_bitand), + MAGIC_FUNCTION("^"_s, "ii"_s, 'i', fun_bitxor), + MAGIC_FUNCTION("<<"_s, "ii"_s, 'i', fun_bitshl), + MAGIC_FUNCTION(">>"_s, "ii"_s, 'i', fun_bitshr), + MAGIC_FUNCTION1(not, "i"_s, 'i'), + MAGIC_FUNCTION1(neg, "i"_s, 'i'), + MAGIC_FUNCTION1(max, "ii"_s, 'i'), + MAGIC_FUNCTION1(min, "ii"_s, 'i'), + MAGIC_FUNCTION1(is_in, "la"_s, 'i'), + MAGIC_FUNCTION1(if_then_else, "i__"_s, '_'), + MAGIC_FUNCTION1(skill, "ei"_s, 'i'), + MAGIC_FUNCTION("str"_s, "e"_s, 'i', fun_get_str), + MAGIC_FUNCTION("agi"_s, "e"_s, 'i', fun_get_agi), + MAGIC_FUNCTION("vit"_s, "e"_s, 'i', fun_get_vit), + MAGIC_FUNCTION("dex"_s, "e"_s, 'i', fun_get_dex), + MAGIC_FUNCTION("luk"_s, "e"_s, 'i', fun_get_luk), + MAGIC_FUNCTION("int"_s, "e"_s, 'i', fun_get_int), + MAGIC_FUNCTION("level"_s, "e"_s, 'i', fun_get_lv), + MAGIC_FUNCTION("mdef"_s, "e"_s, 'i', fun_get_mdef), + MAGIC_FUNCTION("def"_s, "e"_s, 'i', fun_get_def), + MAGIC_FUNCTION("hp"_s, "e"_s, 'i', fun_get_hp), + MAGIC_FUNCTION("max_hp"_s, "e"_s, 'i', fun_get_max_hp), + MAGIC_FUNCTION("sp"_s, "e"_s, 'i', fun_get_sp), + MAGIC_FUNCTION("max_sp"_s, "e"_s, 'i', fun_get_max_sp), + MAGIC_FUNCTION("dir"_s, "e"_s, 'd', fun_get_dir), + MAGIC_FUNCTION1(name_of, "."_s, 's'), + MAGIC_FUNCTION1(mob_id, "e"_s, 'i'), + MAGIC_FUNCTION1(location, "e"_s, 'l'), + MAGIC_FUNCTION1(random, "i"_s, 'i'), + MAGIC_FUNCTION1(random_dir, "i"_s, 'd'), + MAGIC_FUNCTION1(hash_entity, "e"_s, 'i'), + MAGIC_FUNCTION1(is_married, "e"_s, 'i'), + MAGIC_FUNCTION1(partner, "e"_s, 'e'), + MAGIC_FUNCTION1(awayfrom, "ldi"_s, 'l'), + MAGIC_FUNCTION1(failed, "_"_s, 'i'), + MAGIC_FUNCTION1(pc, "s"_s, 'e'), + MAGIC_FUNCTION1(npc, "s"_s, 'e'), + MAGIC_FUNCTION1(distance, "ll"_s, 'i'), + MAGIC_FUNCTION1(rdistance, "ll"_s, 'i'), + MAGIC_FUNCTION1(anchor, "s"_s, 'a'), + MAGIC_FUNCTION("random_location"_s, "a"_s, 'l', fun_pick_location), + MAGIC_FUNCTION("script_int"_s, "es"_s, 'i', fun_read_script_int), + MAGIC_FUNCTION("script_str"_s, "es"_s, 's', fun_read_script_str), + MAGIC_FUNCTION1(rbox, "li"_s, 'a'), + MAGIC_FUNCTION1(count_item, "e."_s, 'i'), + MAGIC_FUNCTION1(line_of_sight, "ll"_s, 'i'), + MAGIC_FUNCTION1(running_status_update, "ei"_s, 'i'), + MAGIC_FUNCTION1(status_option, "ei"_s, 'i'), + MAGIC_FUNCTION1(element, "e"_s, 'i'), + MAGIC_FUNCTION1(element_level, "e"_s, 'i'), + MAGIC_FUNCTION1(his_shroud, "e"_s, 'i'), + MAGIC_FUNCTION1(is_equipped, "e."_s, 'i'), + MAGIC_FUNCTION1(is_exterior, "l"_s, 'i'), + MAGIC_FUNCTION1(contains_string, "ss"_s, 'i'), + MAGIC_FUNCTION1(strstr, "ss"_s, 'i'), + MAGIC_FUNCTION1(strlen, "s"_s, 'i'), + MAGIC_FUNCTION1(substr, "sii"_s, 's'), + MAGIC_FUNCTION1(sqrt, "i"_s, 'i'), + MAGIC_FUNCTION1(map_level, "l"_s, 'i'), + MAGIC_FUNCTION1(map_nr, "l"_s, 'i'), + MAGIC_FUNCTION1(dir_towards, "lli"_s, 'd'), + MAGIC_FUNCTION1(is_dead, "e"_s, 'i'), + MAGIC_FUNCTION1(is_pc, "e"_s, 'i'), + MAGIC_FUNCTION("extract_healer_experience"_s, "ei"_s, 'i', fun_extract_healer_xp), }; fun_t *magic_get_fun(ZString name) @@ -1377,24 +1503,24 @@ fun_t *magic_get_fun(ZString name) // 1 on failure static -int eval_location(dumb_ptr<env_t> env, location_t *dest, e_location_t *expr) +int eval_location(dumb_ptr<env_t> env, location_t *dest, const e_location_t *expr) { val_t m, x, y; magic_eval(env, &m, expr->m); magic_eval(env, &x, expr->x); magic_eval(env, &y, expr->y); - if (CHECK_TYPE(&m, TYPE::STRING) - && CHECK_TYPE(&x, TYPE::INT) && CHECK_TYPE(&y, TYPE::INT)) + if (m.is<ValString>() + && x.is<ValInt>() && y.is<ValInt>()) { - MapName name = VString<15>(ZString(m.v.v_string)); + MapName name = VString<15>(ZString(m.get_if<ValString>()->v_string)); map_local *map_id = map_mapname2mapid(name); magic_clear_var(&m); if (!map_id) return 1; dest->m = map_id; - dest->x = x.v.v_int; - dest->y = y.v.v_int; + dest->x = x.get_if<ValInt>()->v_int; + dest->y = y.get_if<ValInt>()->v_int; return 0; } else @@ -1407,141 +1533,145 @@ int eval_location(dumb_ptr<env_t> env, location_t *dest, e_location_t *expr) } static -dumb_ptr<area_t> eval_area(dumb_ptr<env_t> env, e_area_t& expr_) +dumb_ptr<area_t> eval_area(dumb_ptr<env_t> env, const e_area_t& expr_) { - e_area_t *expr = &expr_; // temporary hack to reduce diff - auto area = dumb_ptr<area_t>::make(); - area->ty = expr->ty; - - switch (expr->ty) + MATCH (expr_) { - case AREA::LOCATION: - area->size = 1; - if (eval_location(env, &area->a.a_loc, &expr->a.a_loc)) + CASE (const e_location_t&, a_loc) + { + location_t loc; + int size = 1; + if (eval_location(env, &loc, &a_loc)) { - area.delete_(); - return NULL; + return nullptr; } else - return area; - - case AREA::UNION: + { + return dumb_ptr<area_t>::make(loc, size); + } + } + CASE (const ExprAreaUnion&, a) { - int i, fail = 0; - for (i = 0; i < 2; i++) + AreaUnion u; + bool fail = false; + for (int i = 0; i < 2; i++) { - area->a.a_union[i] = eval_area(env, *expr->a.a_union[i]); - if (!area->a.a_union[i]) - fail = 1; + u.a_union[i] = eval_area(env, *a.a_union[i]); + if (!u.a_union[i]) + fail = true; } if (fail) { - for (i = 0; i < 2; i++) + for (int i = 0; i < 2; i++) { - if (area->a.a_union[i]) - free_area(area->a.a_union[i]); + if (u.a_union[i]) + free_area(u.a_union[i]); } - area.delete_(); - return NULL; + return nullptr; } - area->size = area->a.a_union[0]->size + area->a.a_union[1]->size; - return area; + int size = u.a_union[0]->size + u.a_union[1]->size; + return dumb_ptr<area_t>::make(u, size); } - - case AREA::RECT: + CASE (const ExprAreaRect&, a_rect) { val_t width, height; - magic_eval(env, &width, expr->a.a_rect.width); - magic_eval(env, &height, expr->a.a_rect.height); - - area->a.a_rect.width = width.v.v_int; - area->a.a_rect.height = height.v.v_int; - - if (CHECK_TYPE(&width, TYPE::INT) - && CHECK_TYPE(&height, TYPE::INT) - && !eval_location(env, &(area->a.a_rect.loc), - &expr->a.a_rect.loc)) + magic_eval(env, &width, a_rect.width); + magic_eval(env, &height, a_rect.height); + + AreaRect a_rect_; + if (width.is<ValInt>() + && height.is<ValInt>() + && !eval_location(env, &(a_rect_.loc), + &a_rect.loc)) { - area->size = area->a.a_rect.width * area->a.a_rect.height; + a_rect_.width = width.get_if<ValInt>()->v_int; + a_rect_.height = height.get_if<ValInt>()->v_int; + + int size = a_rect_.width * a_rect_.height; magic_clear_var(&width); magic_clear_var(&height); - return area; + return dumb_ptr<area_t>::make(a_rect_, size); } else { - area.delete_(); magic_clear_var(&width); magic_clear_var(&height); - return NULL; + return nullptr; } } - - case AREA::BAR: + CASE (const ExprAreaBar&, a_bar) { val_t width, depth, dir; - magic_eval(env, &width, expr->a.a_bar.width); - magic_eval(env, &depth, expr->a.a_bar.depth); - magic_eval(env, &dir, expr->a.a_bar.dir); - - area->a.a_bar.width = width.v.v_int; - area->a.a_bar.depth = depth.v.v_int; - area->a.a_bar.dir = dir.v.v_dir; - - if (CHECK_TYPE(&width, TYPE::INT) - && CHECK_TYPE(&depth, TYPE::INT) - && CHECK_TYPE(&dir, TYPE::DIR) - && !eval_location(env, &area->a.a_bar.loc, - &expr->a.a_bar.loc)) + magic_eval(env, &width, a_bar.width); + magic_eval(env, &depth, a_bar.depth); + magic_eval(env, &dir, a_bar.dir); + + AreaBar a_bar_; + if (width.is<ValInt>() + && depth.is<ValInt>() + && dir.is<ValDir>() + && !eval_location(env, &a_bar_.loc, + &a_bar.loc)) { - area->size = - (area->a.a_bar.width * 2 + 1) * area->a.a_bar.depth; + a_bar_.width = width.get_if<ValInt>()->v_int; + a_bar_.depth = depth.get_if<ValInt>()->v_int; + a_bar_.dir = dir.get_if<ValDir>()->v_dir; + + int size = (a_bar_.width * 2 + 1) * a_bar_.depth; magic_clear_var(&width); magic_clear_var(&depth); magic_clear_var(&dir); - return area; + return dumb_ptr<area_t>::make(a_bar_, size); } else { - area.delete_(); magic_clear_var(&width); magic_clear_var(&depth); magic_clear_var(&dir); - return NULL; + return nullptr; } } - - default: - FPRINTF(stderr, "INTERNAL ERROR: Unknown area type %d\n", - area->ty); - area.delete_(); - return NULL; } + abort(); } +// This is called on arguments with begin=true, +// and on the return value with begin=false. +// In both cases, the ambiguous types are in pointer mode. static -TYPE type_key(char ty_key) +bool type_key_matches(char ty_key, val_t *arg, bool begin) { switch (ty_key) { case 'i': - return TYPE::INT; + if (begin) + intify(arg); + return arg->is<ValInt>(); case 'd': - return TYPE::DIR; + return arg->is<ValDir>(); case 's': - return TYPE::STRING; + if (begin) + stringify(arg); + return arg->is<ValString>(); case 'e': - return TYPE::ENTITY; + return arg->is<ValEntityPtr>(); case 'l': - return TYPE::LOCATION; + if (begin) + make_location(arg); + return arg->is<ValLocation>(); case 'a': - return TYPE::AREA; + if (begin) + make_area(arg); + return arg->is<ValArea>(); case 'S': - return TYPE::SPELL; + if (begin) + make_spell(arg); + return arg->is<ValSpell>(); case 'I': - return TYPE::INVOCATION; + return arg->is<ValInvocationPtr>(); default: - return TYPE::NEGATIVE_1; + return true; } } @@ -1552,76 +1682,66 @@ int magic_signature_check(ZString opname, ZString funname, ZString signature, for (i = 0; i < args.size(); i++) { val_t *arg = &args[i]; - char ty_key = signature[i]; - TYPE ty = arg->ty; - TYPE desired_ty = type_key(ty_key); - if (ty == TYPE::ENTITY) + // whoa, it turns out the second p *does* shadow this one + if (ValEntityInt *p1 = arg->get_if<ValEntityInt>()) { /* Dereference entities in preparation for calling function */ - arg->v.v_entity = map_id2bl(arg->v.v_int); - if (!arg->v.v_entity) - ty = arg->ty = TYPE::FAIL; + dumb_ptr<block_list> ent = map_id2bl(p1->v_eid); + if (ent) + { + *arg = ValEntityPtr{ent}; + } + else + { + *arg = ValFail{}; + } } - else if (ty == TYPE::INVOCATION) + else if (ValInvocationInt *p2 = arg->get_if<ValInvocationInt>()) { - arg->v.v_invocation = map_id2bl(arg->v.v_int)->is_spell(); - if (!arg->v.v_entity) - ty = arg->ty = TYPE::FAIL; + dumb_ptr<invocation> invoc = map_id2bl(p2->v_iid)->is_spell(); + if (invoc) + { + *arg = ValInvocationPtr{invoc}; + } + else + { + *arg = ValFail(); + } } + char ty_key = signature[i]; if (!ty_key) { FPRINTF(stderr, - "[magic-eval]: L%d:%d: Too many arguments (%zu) to %s `%s'\n", - line, column, args.size(), opname, funname); + "[magic-eval]: L%d:%d: Too many arguments (%zu) to %s `%s'\n"_fmt, + line, column, args.size(), opname, funname); return 1; } - if (ty == TYPE::FAIL && ty_key != '_') + if (arg->is<ValFail>() && ty_key != '_') return 1; /* Fail `in a sane way': This is a perfectly permissible error */ - if (ty == desired_ty || desired_ty == TYPE::NEGATIVE_1) + // this also does conversions now + if (type_key_matches(ty_key, arg, true)) continue; - if (ty == TYPE::UNDEF) + if (arg->is<ValUndef>()) { FPRINTF(stderr, - "[magic-eval]: L%d:%d: Argument #%d to %s `%s' undefined\n", - line, column, i + 1, opname, funname); + "[magic-eval]: L%d:%d: Argument #%d to %s `%s' undefined\n"_fmt, + line, column, i + 1, opname, funname); return 1; } - /* If we are here, we have a type mismatch but no failure _yet_. Try to coerce. */ - switch (desired_ty) - { - case TYPE::INT: - intify(arg); - break; /* 100% success rate */ - case TYPE::STRING: - stringify(arg, 1); - break; /* 100% success rate */ - case TYPE::AREA: - make_area(arg); - break; /* Only works for locations */ - case TYPE::LOCATION: - make_location(arg); - break; /* Only works for some areas */ - case TYPE::SPELL: - make_spell(arg); - break; /* Only works for still-active invocatoins */ - default: - break; /* We'll fail right below */ - } - ty = arg->ty; - if (ty != desired_ty) { /* Coercion failed? */ - if (ty != TYPE::FAIL) + if (!arg->is<ValFail>()) + { FPRINTF(stderr, - "[magic-eval]: L%d:%d: Argument #%d to %s `%s' of incorrect type (%d)\n", - line, column, i + 1, opname, funname, - ty); + "[magic-eval]: L%d:%d: Argument #%d to %s `%s' of incorrect type (sorry, types aren't integers anymore)\n"_fmt, + line, column, i + 1, opname, funname); + } return 1; } } @@ -1631,100 +1751,94 @@ int magic_signature_check(ZString opname, ZString funname, ZString signature, void magic_eval(dumb_ptr<env_t> env, val_t *dest, dumb_ptr<expr_t> expr) { - switch (expr->ty) + MATCH (*expr) { - case EXPR::VAL: - magic_copy_var(dest, &expr->e.e_val); - break; + CASE (const val_t&, e_val) + { + magic_copy_var(dest, &e_val); + } - case EXPR::LOCATION: - if (eval_location(env, &dest->v.v_location, &expr->e.e_location)) - dest->ty = TYPE::FAIL; + CASE (const e_location_t&, e_location) + { + location_t loc; + if (eval_location(env, &loc, &e_location)) + *dest = ValFail(); else - dest->ty = TYPE::LOCATION; - break; - - case EXPR::AREA: - if ((dest->v.v_area = eval_area(env, expr->e.e_area))) - dest->ty = TYPE::AREA; + *dest = ValLocation{loc}; + } + CASE (const e_area_t&, e_area) + { + if (dumb_ptr<area_t> area = eval_area(env, e_area)) + *dest = ValArea{area}; else - dest->ty = TYPE::FAIL; - break; - - case EXPR::FUNAPP: + *dest = ValFail(); + } + CASE (const ExprFunApp&, e_funapp) { val_t arguments[MAX_ARGS]; - int args_nr = expr->e.e_funapp.args_nr; + int args_nr = e_funapp.args_nr; int i; - fun_t *f = expr->e.e_funapp.funp; + fun_t *f = e_funapp.funp; for (i = 0; i < args_nr; ++i) - magic_eval(env, &arguments[i], expr->e.e_funapp.args[i]); - if (magic_signature_check("function", f->name, f->signature, Slice<val_t>(arguments, args_nr), - expr->e.e_funapp.line_nr, expr->e.e_funapp.column) + magic_eval(env, &arguments[i], e_funapp.args[i]); + if (magic_signature_check("function"_s, f->name, f->signature, Slice<val_t>(arguments, args_nr), + e_funapp.line_nr, e_funapp.column) || f->fun(env, dest, Slice<val_t>(arguments, args_nr))) - dest->ty = TYPE::FAIL; + *dest = ValFail(); else { - TYPE dest_ty = type_key(f->ret_ty); - if (dest_ty != TYPE::NEGATIVE_1) - dest->ty = dest_ty; + assert (!dest->is<ValInvocationPtr>()); + assert (!dest->is<ValInvocationInt>()); + assert (!dest->is<ValEntityInt>()); + assert (type_key_matches(f->ret_ty, dest, false)); /* translate entity back into persistent int */ - if (dest->ty == TYPE::ENTITY) + if (ValEntityPtr *ent = dest->get_if<ValEntityPtr>()) { - if (dest->v.v_entity) - dest->v.v_int = dest->v.v_entity->bl_id; + if (ent->v_entity) + *dest = ValEntityInt{ent->v_entity->bl_id}; else - dest->ty = TYPE::FAIL; + *dest = ValFail(); } + // what about invocation? } for (i = 0; i < args_nr; ++i) magic_clear_var(&arguments[i]); - break; } - - case EXPR::ID: + CASE (const ExprId&, e) { - val_t v = env->VAR(expr->e.e_id); + val_t& v = env->VAR(e.e_id); magic_copy_var(dest, &v); - break; } - - case EXPR::SPELLFIELD: + CASE (const ExprField&, e_field) { val_t v; - int id = expr->e.e_field.id; - magic_eval(env, &v, expr->e.e_field.expr); + int id = e_field.id; + magic_eval(env, &v, e_field.expr); - if (v.ty == TYPE::INVOCATION) + assert(!v.is<ValInvocationPtr>()); + if (ValInvocationInt *ii = v.get_if<ValInvocationInt>()) { - dumb_ptr<invocation> t = map_id2bl(v.v.v_int)->is_spell(); + dumb_ptr<invocation> t = map_id2bl(ii->v_iid)->is_spell(); if (!t) - dest->ty = TYPE::UNDEF; + *dest = ValUndef(); else { - val_t val = t->env->VAR(id); + val_t& val = t->env->VAR(id); magic_copy_var(dest, &val); } } else { FPRINTF(stderr, - "[magic] Attempt to access field %s on non-spell\n", - env->base_env->varv[id].name); - dest->ty = TYPE::FAIL; + "[magic] Attempt to access field %s on non-spell\n"_fmt, + env->base_env->varv[id].name); + *dest = ValFail(); } - break; } - - default: - FPRINTF(stderr, - "[magic] INTERNAL ERROR: Unknown expression type %d\n", - expr->ty); - break; } } @@ -1733,12 +1847,12 @@ int magic_eval_int(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr) val_t result; magic_eval(env, &result, expr); - if (result.ty == TYPE::FAIL || result.ty == TYPE::UNDEF) + if (result.is<ValFail>() || result.is<ValUndef>()) return 0; intify(&result); - return result.v.v_int; + return result.get_if<ValInt>()->v_int; } AString magic_eval_str(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr) @@ -1746,17 +1860,13 @@ AString magic_eval_str(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr) val_t result; magic_eval(env, &result, expr); - if (result.ty == TYPE::FAIL || result.ty == TYPE::UNDEF) - return {"?"}; + if (result.is<ValFail>() || result.is<ValUndef>()) + return "?"_s; - stringify(&result, 0); + // is this a memory leak? + stringify(&result); - return result.v.v_string.str(); -} - -dumb_ptr<expr_t> magic_new_expr(EXPR ty) -{ - auto expr = dumb_ptr<expr_t>::make(); - expr->ty = ty; - return expr; + return result.get_if<ValString>()->v_string.str(); } +} // namespace magic +} // namespace tmwa diff --git a/src/map/magic-expr.hpp b/src/map/magic-expr.hpp index 58f6596..294e665 100644 --- a/src/map/magic-expr.hpp +++ b/src/map/magic-expr.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_MAGIC_EXPR_HPP -#define TMWA_MAP_MAGIC_EXPR_HPP +#pragma once // magic-expr.hpp - Pure functions for the old magic backend. // // Copyright © 2004-2011 The Mana World Development Team @@ -20,15 +19,24 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "magic-interpreter.hpp" +#include "../generic/fwd.hpp" -# include "../range/slice.hpp" +#include "../range/fwd.hpp" -# include "../strings/fwd.hpp" -# include "../strings/zstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/literal.hpp" +#include "../mmo/fwd.hpp" + +#include "magic-interpreter.t.hpp" + + +namespace tmwa +{ +namespace magic +{ /* * Argument types: * i : int @@ -44,34 +52,20 @@ */ struct fun_t { - ZString name; - ZString signature; + LString name; + LString signature; char ret_ty; int (*fun)(dumb_ptr<env_t> env, val_t *result, Slice<val_t> arga); }; -struct op_t -{ - ZString name; - ZString signature; - int (*op)(dumb_ptr<env_t> env, Slice<val_t> arga); -}; - /** * Retrieves a function by name * @param name The name to look up - * @return A function of that name, or NULL. + * @return A function of that name, or nullptr. */ fun_t *magic_get_fun(ZString name); /** - * Retrieves an operation by name - * @param name The name to look up - * @return An operation of that name, or NULL, and a function index - */ -op_t *magic_get_op(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); @@ -86,18 +80,16 @@ int magic_eval_int(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr); */ AString magic_eval_str(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr); -dumb_ptr<expr_t> magic_new_expr(EXPR ty); - void magic_clear_var(val_t *v); -void magic_copy_var(val_t *dest, val_t *src); +void magic_copy_var(val_t *dest, const val_t *src); void magic_random_location(location_t *dest, dumb_ptr<area_t> area); // ret -1: not a string, ret 1: no such item, ret 0: OK -int magic_find_item(Slice<val_t> args, int index, struct item *item, int *stackable); +int magic_find_item(Slice<val_t> args, int index, Item *item, int *stackable); -# define GET_ARG_ITEM(index, dest, stackable) \ +#define GET_ARG_ITEM(index, dest, stackable) \ switch (magic_find_item(args, index, &dest, &stackable)) \ { \ case -1: return 1; \ @@ -107,4 +99,12 @@ int magic_find_item(Slice<val_t> args, int index, struct item *item, int *stacka int magic_location_in_area(map_local *m, int x, int y, dumb_ptr<area_t> area); -#endif // TMWA_MAP_MAGIC_EXPR_HPP +/* 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); + +void magic_area_rect(map_local **m, int *x, int *y, int *width, int *height, + area_t& area); +} // namespace magic +} // namespace tmwa diff --git a/src/map/magic-interpreter-aux.hpp b/src/map/magic-interpreter-aux.hpp deleted file mode 100644 index 1369b38..0000000 --- a/src/map/magic-interpreter-aux.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef TMWA_MAP_MAGIC_INTERPRETER_AUX_HPP -#define TMWA_MAP_MAGIC_INTERPRETER_AUX_HPP -// magic-interpreter-aux.hpp - Edge of 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 "../sanity.hpp" - -# include "magic-interpreter.t.hpp" - -template<class T> -bool CHECK_TYPE(T *v, TYPE t) -{ - return v->ty == t; -} - -#endif // TMWA_MAP_MAGIC_INTERPRETER_AUX_HPP diff --git a/src/map/magic-interpreter-base.cpp b/src/map/magic-interpreter-base.cpp index d86f595..1ac391a 100644 --- a/src/map/magic-interpreter-base.cpp +++ b/src/map/magic-interpreter-base.cpp @@ -19,73 +19,67 @@ // 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-aux.hpp" -#include "magic-interpreter.hpp" +#include <algorithm> #include "../strings/astring.hpp" #include "../strings/xstring.hpp" #include "../io/cxxstdio.hpp" +#include "../io/cxxstdio_enums.hpp" -#include "../mmo/timer.hpp" +#include "../net/timer.hpp" +#include "magic.hpp" #include "magic-expr.hpp" - +#include "magic-interpreter.hpp" #include "pc.hpp" #include "../poison.hpp" + +namespace tmwa +{ +namespace magic +{ static -void set_int_p(val_t *v, int i, TYPE t) +void set_int(val_t *v, int i) { - v->ty = t; - v->v.v_int = i; + *v = ValInt{i}; } -#warning "This code should die" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-macros" - -#define set_int(v, i) set_int_p(v, i, TYPE::INT) -#define set_dir(v, i) set_int_p(v, i, TYPE::DIR) +static __attribute__((unused)) +void set_dir(val_t *v, DIR d) +{ + *v = ValDir{d}; +} -#define SETTER(tty, dyn_ty, field) (val_t *v, tty x) { v->ty = dyn_ty; v->v.field = x; } static -void set_string SETTER(dumb_string, TYPE::STRING, v_string) +void set_string(val_t *v, dumb_string x) +{ + *v = ValString{x}; +} static void set_entity(val_t *v, dumb_ptr<block_list> e) { - v->ty = TYPE::ENTITY; - v->v.v_int = e->bl_id; + *v = ValEntityInt{e->bl_id}; } static void set_invocation(val_t *v, dumb_ptr<invocation> i) { - v->ty = TYPE::INVOCATION; - v->v.v_int = i->bl_id; + *v = ValInvocationInt{i->bl_id}; } static -void set_spell SETTER(dumb_ptr<spell_t>, TYPE::SPELL, v_spell) - -#define setenv(f, v, x) f(&(env->varu[v]), x) - -#define set_env_int(v, x) setenv(set_int, v, x) -#define set_env_dir(v, x) setenv(set_dir, v, x) -#define set_env_string(v, x) setenv(set_string, v, x) -#define set_env_entity(v, x) setenv(set_entity, v, x) -#define set_env_location(v, x) setenv(set_location, v, x) -#define set_env_area(v, x) setenv(set_area, v, x) -#define set_env_invocation(v, x) setenv(set_invocation, v, x) -#define set_env_spell(v, x) setenv(set_spell, v, x) - -#pragma GCC diagnostic pop +void set_spell(val_t *v, dumb_ptr<spell_t> x) +{ + *v = ValSpell{x}; +} magic_conf_t magic_conf; /* Global magic conf */ -env_t magic_default_env = { &magic_conf, NULL }; +env_t magic_default_env = { &magic_conf, nullptr }; AString magic_find_invocation(XString spellname) { @@ -102,7 +96,7 @@ dumb_ptr<spell_t> magic_find_spell(XString invocation) if (it != magic_conf.spells_by_invocation.end()) return it->second; - return NULL; + return nullptr; } /* -------------------------------------------------------------------------------- */ @@ -125,7 +119,7 @@ dumb_ptr<teleport_anchor_t> magic_find_anchor(XString name) if (it != magic_conf.anchors_by_invocation.end()) return it->second; - return NULL; + return nullptr; } /* -------------------------------------------------------------------------------- */ @@ -170,7 +164,7 @@ dumb_ptr<env_t> spell_create_env(magic_conf_t *conf, dumb_ptr<spell_t> spell, { case SPELLARG::STRING: - set_env_string(spell->arg, dumb_string::copys(param)); + set_string(&env->varu[spell->arg], dumb_string::copys(param)); break; case SPELLARG::PC: @@ -179,7 +173,7 @@ dumb_ptr<env_t> spell_create_env(magic_conf_t *conf, dumb_ptr<spell_t> spell, dumb_ptr<map_session_data> subject = map_nick2sd(name); if (!subject) subject = caster; - set_env_entity(spell->arg, subject); + set_entity(&env->varu[spell->arg], subject); break; } @@ -187,13 +181,13 @@ dumb_ptr<env_t> spell_create_env(magic_conf_t *conf, dumb_ptr<spell_t> spell, break; default: - FPRINTF(stderr, "Unexpected spellarg type %d\n", - spell->spellarg_ty); + FPRINTF(stderr, "Unexpected spellarg type %d\n"_fmt, + spell->spellarg_ty); } - set_env_entity(VAR_CASTER, caster); - set_env_int(VAR_SPELLPOWER, spellpower); - set_env_spell(VAR_SPELL, spell); + set_entity(&env->varu[VAR_CASTER], caster); + set_int(&env->varu[VAR_SPELLPOWER], spellpower); + set_spell(&env->varu[VAR_SPELL], spell); return env; } @@ -201,22 +195,22 @@ dumb_ptr<env_t> spell_create_env(magic_conf_t *conf, dumb_ptr<spell_t> spell, static void free_components(dumb_ptr<component_t> *component_holder) { - if (*component_holder == NULL) + if (*component_holder == nullptr) return; free_components(&(*component_holder)->next); (*component_holder).delete_(); - *component_holder = NULL; + *component_holder = nullptr; } -void magic_add_component(dumb_ptr<component_t> *component_holder, int id, int count) +void magic_add_component(dumb_ptr<component_t> *component_holder, ItemNameId id, int count) { if (count <= 0) return; - if (*component_holder == NULL) + if (*component_holder == nullptr) { auto component = dumb_ptr<component_t>::make(); - component->next = NULL; + component->next = nullptr; component->item_id = id; component->count = count; *component_holder = component; @@ -238,7 +232,7 @@ void magic_add_component(dumb_ptr<component_t> *component_holder, int id, int co static void copy_components(dumb_ptr<component_t> *component_holder, dumb_ptr<component_t> component) { - if (component == NULL) + if (component == nullptr) return; magic_add_component(component_holder, component->item_id, component->count); @@ -295,8 +289,10 @@ int spellguard_can_satisfy(spellguard_check_t *check, dumb_ptr<map_session_data> { interval_t casttime = check->casttime; - if (env->VAR(VAR_MIN_CASTTIME).ty == TYPE::INT) - casttime = max(casttime, static_cast<interval_t>(env->VAR(VAR_MIN_CASTTIME).v.v_int)); + if (ValInt *v = env->VAR(VAR_MIN_CASTTIME).get_if<ValInt>()) + { + casttime = std::max(casttime, static_cast<interval_t>(v->v_int)); + } caster->cast_tick = tick + casttime; /* Make sure not to cast too frequently */ @@ -308,37 +304,37 @@ int spellguard_can_satisfy(spellguard_check_t *check, dumb_ptr<map_session_data> } static -effect_set_t *spellguard_check_sub(spellguard_check_t *check, +const effect_set_t *spellguard_check_sub(spellguard_check_t *check, dumb_ptr<spellguard_t> guard, dumb_ptr<map_session_data> caster, dumb_ptr<env_t> env, int *near_miss) { - if (guard == NULL) - return NULL; + if (guard == nullptr) + return nullptr; - switch (guard->ty) + MATCH (*guard) { - case SPELLGUARD::CONDITION: - if (!magic_eval_int(env, guard->s.s_condition)) - return NULL; - break; - - case SPELLGUARD::COMPONENTS: - copy_components(&check->components, guard->s.s_components); - break; - - case SPELLGUARD::CATALYSTS: - copy_components(&check->catalysts, guard->s.s_catalysts); - break; - - case SPELLGUARD::CHOICE: + CASE (const GuardCondition&, s) + { + if (!magic_eval_int(env, s.s_condition)) + return nullptr; + } + CASE (const GuardComponents&, s) + { + copy_components(&check->components, s.s_components); + } + CASE (const GuardCatalysts&, s) + { + copy_components(&check->catalysts, s.s_catalysts); + } + CASE (const GuardChoice&, s) { spellguard_check_t altcheck = *check; - effect_set_t *retval; + const effect_set_t *retval; - altcheck.components = NULL; - altcheck.catalysts = NULL; + altcheck.components = nullptr; + altcheck.catalysts = nullptr; copy_components(&altcheck.catalysts, check->catalysts); copy_components(&altcheck.components, check->components); @@ -351,42 +347,38 @@ effect_set_t *spellguard_check_sub(spellguard_check_t *check, if (retval) return retval; else - return spellguard_check_sub(check, guard->s.s_alt, caster, + return spellguard_check_sub(check, s.s_alt, caster, env, near_miss); } - - case SPELLGUARD::MANA: - check->mana += magic_eval_int(env, guard->s.s_mana); - break; - - case SPELLGUARD::CASTTIME: - check->casttime += static_cast<interval_t>(magic_eval_int(env, guard->s.s_mana)); - break; - - case SPELLGUARD::EFFECT: + CASE (const GuardMana&, s) + { + check->mana += magic_eval_int(env, s.s_mana); + } + CASE (const GuardCastTime&, s) + { + check->casttime += static_cast<interval_t>(magic_eval_int(env, s.s_casttime)); + } + CASE (const effect_set_t&, s_effect) + { if (spellguard_can_satisfy(check, caster, env, near_miss)) - return &guard->s.s_effect; + return &s_effect; else - return NULL; - - default: - FPRINTF(stderr, "Unexpected spellguard type %d\n", - guard->ty); - return NULL; + return nullptr; + } } return spellguard_check_sub(check, guard->next, caster, env, near_miss); } static -effect_set_t *check_spellguard(dumb_ptr<spellguard_t> guard, +const effect_set_t *check_spellguard(dumb_ptr<spellguard_t> guard, dumb_ptr<map_session_data> caster, dumb_ptr<env_t> env, int *near_miss) { spellguard_check_t check; - effect_set_t *retval; - check.catalysts = NULL; - check.components = NULL; + const effect_set_t *retval; + check.catalysts = nullptr; + check.components = nullptr; check.mana = 0; check.casttime = interval_t::zero(); @@ -402,7 +394,7 @@ effect_set_t *check_spellguard(dumb_ptr<spellguard_t> guard, /* Public API */ /* -------------------------------------------------------------------------------- */ -effect_set_t *spell_trigger(dumb_ptr<spell_t> spell, dumb_ptr<map_session_data> caster, +const effect_set_t *spell_trigger(dumb_ptr<spell_t> spell, dumb_ptr<map_session_data> caster, dumb_ptr<env_t> env, int *near_miss) { dumb_ptr<spellguard_t> guard = spell->spellguard; @@ -420,10 +412,11 @@ static void spell_set_location(dumb_ptr<invocation> invocation, dumb_ptr<block_list> entity) { magic_clear_var(&invocation->env->varu[VAR_LOCATION]); - invocation->env->varu[VAR_LOCATION].ty = TYPE::LOCATION; - invocation->env->varu[VAR_LOCATION].v.v_location.m = entity->bl_m; - invocation->env->varu[VAR_LOCATION].v.v_location.x = entity->bl_x; - invocation->env->varu[VAR_LOCATION].v.v_location.y = entity->bl_y; + ValLocation v; + v.v_location.m = entity->bl_m; + v.v_location.x = entity->bl_x; + v.v_location.y = entity->bl_y; + invocation->env->varu[VAR_LOCATION] = v; } void spell_update_location(dumb_ptr<invocation> invocation) @@ -441,7 +434,7 @@ void spell_update_location(dumb_ptr<invocation> invocation) } } -dumb_ptr<invocation> spell_instantiate(effect_set_t *effect_set, dumb_ptr<env_t> env) +dumb_ptr<invocation> spell_instantiate(const effect_set_t *effect_set, dumb_ptr<env_t> env) { dumb_ptr<invocation> retval; retval.new_(); @@ -449,9 +442,8 @@ dumb_ptr<invocation> spell_instantiate(effect_set_t *effect_set, dumb_ptr<env_t> retval->env = env; - retval->caster = env->VAR(VAR_CASTER).v.v_int; - retval->spell = env->VAR(VAR_SPELL).v.v_spell; - retval->stack_size = 0; + retval->caster = env->VAR(VAR_CASTER).get_if<ValEntityInt>()->v_eid; + retval->spell = env->VAR(VAR_SPELL).get_if<ValSpell>()->v_spell; retval->current_effect = effect_set->effect; retval->trigger_effect = effect_set->at_trigger; retval->end_effect = effect_set->at_end; @@ -464,7 +456,7 @@ dumb_ptr<invocation> spell_instantiate(effect_set_t *effect_set, dumb_ptr<env_t> retval->bl_y = caster->bl_y; map_addblock(retval); - set_env_invocation(VAR_INVOCATION, retval); + set_invocation(&env->varu[VAR_INVOCATION], retval); return retval; } @@ -478,32 +470,31 @@ dumb_ptr<invocation> spell_clone_effect(dumb_ptr<invocation> base) // since this is the only call site, it is expanded here //*retval = *base; - retval->next_invocation = NULL; + 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 = 0; + retval->subject = BlockId(); // retval->timer = 0; - retval->stack_size = 0; // retval->stack = undef; retval->script_pos = 0; // huh? retval->current_effect = base->trigger_effect; retval->trigger_effect = base->trigger_effect; - retval->end_effect = NULL; - // retval->status_change_refs = NULL; + retval->end_effect = nullptr; + // retval->status_change_refs = nullptr; - retval->bl_id = 0; - retval->bl_prev = NULL; - retval->bl_next = NULL; + 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_env_invocation(VAR_INVOCATION, retval); + set_invocation(&env->varu[VAR_INVOCATION], retval); return retval; } @@ -517,10 +508,10 @@ void spell_bind(dumb_ptr<map_session_data> subject, dumb_ptr<invocation> invocat if (bool(invocation->flags & INVOCATION_FLAG::BOUND) || invocation->subject || invocation->next_invocation) { - int *i = NULL; + int *i = nullptr; FPRINTF(stderr, - "[magic] INTERNAL ERROR: Attempt to re-bind spell invocation `%s'\n", - invocation->spell->name); + "[magic] INTERNAL ERROR: Attempt to re-bind spell invocation `%s'\n"_fmt, + invocation->spell->name); *i = 1; return; } @@ -545,8 +536,8 @@ int spell_unbind(dumb_ptr<map_session_data> subject, dumb_ptr<invocation> invoca *seeker = invocation_->next_invocation; invocation_->flags &= ~INVOCATION_FLAG::BOUND; - invocation_->next_invocation = NULL; - invocation_->subject = 0; + invocation_->next_invocation = nullptr; + invocation_->subject = BlockId(); return 0; } @@ -555,3 +546,5 @@ int spell_unbind(dumb_ptr<map_session_data> subject, dumb_ptr<invocation> invoca return 1; } +} // namespace magic +} // namespace tmwa diff --git a/src/map/magic-interpreter-base.hpp b/src/map/magic-interpreter-base.hpp index 9b1e08a..4bb41a0 100644 --- a/src/map/magic-interpreter-base.hpp +++ b/src/map/magic-interpreter-base.hpp @@ -1,8 +1,8 @@ -#ifndef TMWA_MAP_MAGIC_INTERPRETER_BASE_HPP -#define TMWA_MAP_MAGIC_INTERPRETER_BASE_HPP -// magic-interpreter-base.hpp - dummy header to make Make dependencies work. +#pragma once +// magic-interpreter-base.hpp - Core of the old magic system. // -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// 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) // @@ -19,6 +19,72 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -#endif // TMWA_MAP_MAGIC_INTERPRETER_BASE_HPP +#include "../strings/fwd.hpp" + +#include "../generic/fwd.hpp" + +#include "../mmo/fwd.hpp" + + +namespace tmwa +{ +namespace magic +{ +extern magic_conf_t magic_conf; /* Global magic conf */ +extern env_t magic_default_env; /* Fake default environment */ + +/** + * 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 tmwa diff --git a/src/map/magic-interpreter.cpp b/src/map/magic-interpreter.cpp index 4680971..389a821 100644 --- a/src/map/magic-interpreter.cpp +++ b/src/map/magic-interpreter.cpp @@ -1,5 +1,5 @@ #include "magic-interpreter.hpp" -// magic-interpreter.hpp - Old magic. +// magic-interpreter.cpp - Old magic. // // Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> // @@ -19,3 +19,11 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include "../poison.hpp" + + +namespace tmwa +{ +namespace magic +{ +} // namespace magic +} // namespace tmwa diff --git a/src/map/magic-interpreter.hpp b/src/map/magic-interpreter.hpp index 7d529ee..01775b3 100644 --- a/src/map/magic-interpreter.hpp +++ b/src/map/magic-interpreter.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_MAGIC_INTERPRETER_HPP -#define TMWA_MAP_MAGIC_INTERPRETER_HPP +#pragma once // magic-interpreter.hpp - Old magic. // // Copyright © 2004-2011 The Mana World Development Team @@ -20,200 +19,356 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "magic-interpreter.t.hpp" +#include "magic-interpreter.t.hpp" -# include <cassert> +#include <cassert> -# include "../strings/fwd.hpp" -# include "../strings/rstring.hpp" +#include <memory> -# include "magic.hpp" -# include "map.hpp" -# include "script.hpp" -# include "skill.t.hpp" +#include "../strings/fwd.hpp" +#include "../strings/rstring.hpp" -struct fun_t; -struct op_t; -struct expr_t; -struct val_t; -struct location_t; -struct area_t; -struct spell_t; -struct invocation; +#include "../generic/fwd.hpp" +#include "../sexpr/variant.hpp" + +#include "../net/timer.t.hpp" + +#include "../mmo/ids.hpp" +#include "../mmo/utils.hpp" + +#include "map.hpp" +#include "script.hpp" +#include "skill.t.hpp" + + +namespace tmwa +{ +namespace magic +{ struct location_t { map_local *m; int x, y; }; -struct area_t +struct AreaUnion +{ + dumb_ptr<area_t> a_union[2]; +}; +struct AreaRect +{ + location_t loc; + int width, height; +}; +struct AreaBar +{ + location_t loc; + int width, depth; + DIR dir; +}; + +using AreaVariantBase = Variant< + location_t, + AreaUnion, + AreaRect, + AreaBar +>; + +struct area_t : AreaVariantBase { - union au - { - location_t a_loc; - struct - { - location_t loc; - int width, depth; - DIR dir; - } a_bar; - struct - { - location_t loc; - int width, height; - } a_rect; - dumb_ptr<area_t> a_union[2]; - - au() { really_memzero_this(this); } - ~au() = default; - au(const au&) = default; - au& operator = (const au&) = default; - } a; int size; - AREA ty; + + area_t() = delete; + area_t(area_t&&) = default; + area_t(const area_t&) = delete; + area_t& operator = (area_t&&) = default; + area_t& operator = (const area_t&) = delete; + + area_t(location_t v, int sz) : AreaVariantBase(std::move(v)), size(sz) {} + area_t(AreaUnion v, int sz) : AreaVariantBase(std::move(v)), size(sz) {} + area_t(AreaRect v, int sz) : AreaVariantBase(std::move(v)), size(sz) {} + area_t(AreaBar v, int sz) : AreaVariantBase(std::move(v)), size(sz) {} }; -struct val_t +struct ValUndef +{ +}; +struct ValInt +{ + int v_int; +}; +struct ValDir +{ + DIR v_dir; +}; +struct ValString +{ + dumb_string v_string; +}; +struct ValEntityInt +{ + BlockId v_eid; +}; +struct ValEntityPtr +{ + dumb_ptr<block_list> v_entity; +}; +struct ValLocation +{ + location_t v_location; +}; +struct ValArea +{ + dumb_ptr<area_t> v_area; +}; +struct ValSpell +{ + dumb_ptr<spell_t> v_spell; +}; +struct ValInvocationInt +{ + BlockId v_iid; +}; +struct ValInvocationPtr +{ + dumb_ptr<invocation> v_invocation; +}; +struct ValFail +{ +}; +struct ValNegative1 { - union vu - { - int v_int; - DIR v_dir; - dumb_string v_string; - /* Used ONLY during operation/function invocation; otherwise we use v_int */ - dumb_ptr<block_list> v_entity; - dumb_ptr<area_t> v_area; - location_t v_location; - /* Used ONLY during operation/function invocation; otherwise we use v_int */ - dumb_ptr<invocation> v_invocation; - dumb_ptr<spell_t> v_spell; - - vu() { really_memzero_this(this); } - ~vu() = default; - vu(const vu&) = default; - vu& operator = (const vu&) = default; - } v; - TYPE ty; }; +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 */ +#define MAX_ARGS 7 /* Max. # of args used in builtin primitive functions */ + +struct e_area_t; struct e_location_t { dumb_ptr<expr_t> m, x, y; + + e_location_t() noexcept : m(), x(), y() {} +}; +struct ExprAreaUnion +{ + dumb_ptr<e_area_t> a_union[2]; +}; +struct ExprAreaRect +{ + e_location_t loc; + dumb_ptr<expr_t> width, height; +}; +struct ExprAreaBar +{ + e_location_t loc; + dumb_ptr<expr_t> width, depth, dir; }; -struct e_area_t +using ExprAreaVariantBase = Variant< + e_location_t, + ExprAreaUnion, + ExprAreaRect, + ExprAreaBar +>; + +struct e_area_t : ExprAreaVariantBase { - union a0 - { - e_location_t a_loc; - struct - { - e_location_t loc; - dumb_ptr<expr_t> width, depth, dir; - } a_bar; - struct - { - e_location_t loc; - dumb_ptr<expr_t> width, height; - } a_rect; - dumb_ptr<e_area_t> a_union[2]; - - a0() { really_memzero_this(this); } - ~a0() = default; - a0(const a0&) = default; - a0& operator = (const a0&) = default; - } a; - AREA ty; -}; - -struct expr_t -{ - union eu - { - val_t e_val; - e_location_t e_location; - e_area_t e_area; - struct - { - fun_t *funp; - int line_nr, column; - int args_nr; - dumb_ptr<expr_t> args[MAX_ARGS]; - } e_funapp; - int e_id; - struct - { - dumb_ptr<expr_t> expr; - int id; - } e_field; - - eu() { really_memzero_this(this); } - ~eu() = default; - eu(const eu&) = default; - eu& operator = (const eu&) = default; - } e; - EXPR ty; -}; - -struct effect_t + e_area_t() = delete; + e_area_t(e_area_t&&) = default; + e_area_t(const e_area_t&) = delete; + e_area_t& operator = (e_area_t&&) = default; + e_area_t& operator = (const e_area_t&) = delete; + + e_area_t(e_location_t v) : ExprAreaVariantBase(std::move(v)) {} + e_area_t(ExprAreaUnion v) : ExprAreaVariantBase(std::move(v)) {} + e_area_t(ExprAreaRect v) : ExprAreaVariantBase(std::move(v)) {} + e_area_t(ExprAreaBar v) : ExprAreaVariantBase(std::move(v)) {} +}; + +struct ExprFunApp +{ + fun_t *funp; + int line_nr, column; + int args_nr; + dumb_ptr<expr_t> args[MAX_ARGS]; +}; +struct ExprId +{ + int e_id; +}; +struct ExprField +{ + dumb_ptr<expr_t> expr; + int id; +}; + +using ExprVariantBase = Variant< + val_t, + e_location_t, + e_area_t, + ExprFunApp, + ExprId, + ExprField +>; +struct expr_t : ExprVariantBase +{ + expr_t() = delete; + expr_t(expr_t&&) = default; + expr_t(const expr_t&) = delete; + expr_t& operator = (expr_t&&) = default; + expr_t& operator = (const expr_t&) = delete; + + expr_t(val_t v) : ExprVariantBase(std::move(v)) {} + expr_t(e_location_t v) : ExprVariantBase(std::move(v)) {} + expr_t(e_area_t v) : ExprVariantBase(std::move(v)) {} + expr_t(ExprFunApp v) : ExprVariantBase(std::move(v)) {} + expr_t(ExprId v) : ExprVariantBase(std::move(v)) {} + expr_t(ExprField v) : ExprVariantBase(std::move(v)) {} +}; + + +struct effect_t; + +struct EffectSkip +{ +}; +struct EffectAbort +{ +}; +struct EffectAssign +{ + int id; + dumb_ptr<expr_t> expr; +}; +struct EffectForEach +{ + int id; + dumb_ptr<expr_t> area; + dumb_ptr<effect_t> body; + FOREACH_FILTER filter; +}; +struct EffectFor +{ + int id; + dumb_ptr<expr_t> start, stop; + dumb_ptr<effect_t> body; +}; +struct EffectIf +{ + dumb_ptr<expr_t> cond; + dumb_ptr<effect_t> true_branch, false_branch; +}; +struct EffectSleep +{ + dumb_ptr<expr_t> e_sleep; /* sleep time */ +}; +struct EffectScript +{ + dumb_ptr<const ScriptBuffer> e_script; +}; +struct EffectBreak +{ +}; +struct EffectOp +{ + op_t *opp; + int args_nr; + int line_nr, column; + dumb_ptr<expr_t> args[MAX_ARGS]; +}; +struct EffectEnd +{ +}; +struct EffectCall +{ + std::vector<int> *formalv; + dumb_ptr<std::vector<dumb_ptr<expr_t>>> actualvp; + dumb_ptr<effect_t> body; +}; + +using EffectVariantBase = Variant< + EffectSkip, + EffectAbort, + EffectAssign, + EffectForEach, + EffectFor, + EffectIf, + EffectSleep, + EffectScript, + EffectBreak, + EffectOp, + EffectEnd, + EffectCall +>; +struct effect_t : EffectVariantBase { dumb_ptr<effect_t> next; - union e0 - { - struct - { - int id; - dumb_ptr<expr_t> expr; - } e_assign; - struct - { - int id; - dumb_ptr<expr_t> area; - dumb_ptr<effect_t> body; - FOREACH_FILTER filter; - } e_foreach; - struct - { - int id; - dumb_ptr<expr_t> start, stop; - dumb_ptr<effect_t> body; - } e_for; - struct - { - dumb_ptr<expr_t> cond; - dumb_ptr<effect_t> true_branch, false_branch; - } e_if; - dumb_ptr<expr_t> e_sleep; /* sleep time */ - dumb_ptr<const ScriptBuffer> e_script; - struct - { - op_t *opp; - int args_nr; - int line_nr, column; - dumb_ptr<expr_t> args[MAX_ARGS]; - } e_op; - struct - { - std::vector<int> *formalv; - dumb_ptr<std::vector<dumb_ptr<expr_t>>> actualvp; - dumb_ptr<effect_t> body; - } e_call; - - e0() { really_memzero_this(this); } - ~e0() = default; - e0(const e0&) = default; - e0& operator = (const e0&) = default; - } e; - EFFECT ty; + + effect_t() = delete; + effect_t(effect_t&&) = default; + effect_t(const effect_t&) = delete; + effect_t& operator = (effect_t&&) = default; + effect_t& operator = (const effect_t&) = delete; + + effect_t(EffectSkip v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectAbort v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectAssign v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectForEach v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectFor v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectIf v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectSleep v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectScript v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectBreak v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectOp v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectEnd v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} + effect_t(EffectCall v, dumb_ptr<effect_t> n) : EffectVariantBase(std::move(v)), next(n) {} }; /* ---------- */ @@ -223,34 +378,67 @@ struct effect_t struct component_t { dumb_ptr<component_t> next; - int item_id; + 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; }; -struct spellguard_t +using SpellGuardVariantBase = Variant< + GuardCondition, + GuardMana, + GuardCastTime, + GuardComponents, + GuardCatalysts, + GuardChoice, + effect_set_t +>; +struct spellguard_t : SpellGuardVariantBase { dumb_ptr<spellguard_t> next; - union su - { - dumb_ptr<expr_t> s_condition; - dumb_ptr<expr_t> s_mana; - dumb_ptr<expr_t> s_casttime; - dumb_ptr<component_t> s_components; - dumb_ptr<component_t> s_catalysts; - dumb_ptr<spellguard_t> s_alt; /* either `next' or `s.s_alt' */ - effect_set_t s_effect; - su() { really_memzero_this(this); } - ~su() = default; - su(const su&) = default; - su& operator = (const su&) = default; - } s; - SPELLGUARD ty; + + spellguard_t() = delete; + spellguard_t(spellguard_t&&) = default; + spellguard_t(const spellguard_t&) = delete; + spellguard_t& operator = (spellguard_t&&) = default; + spellguard_t& operator = (const spellguard_t&) = delete; + + spellguard_t(GuardCondition v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} + spellguard_t(GuardMana v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} + spellguard_t(GuardCastTime v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} + spellguard_t(GuardComponents v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} + spellguard_t(GuardCatalysts v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} + spellguard_t(GuardChoice v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} + spellguard_t(effect_set_t v, dumb_ptr<spellguard_t> n) : SpellGuardVariantBase(std::move(v)), next(n) {} }; /* ------ */ @@ -309,17 +497,15 @@ struct magic_conf_t /* 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 magic_config; +#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 { @@ -329,7 +515,7 @@ struct env_t val_t& VAR(size_t i) { assert (varu); - if (varu[i].ty == TYPE::UNDEF) + if (varu[i].is<ValUndef>()) return base_env->varv[i].val; else return varu[i]; @@ -337,47 +523,53 @@ struct env_t }; -# define MAX_STACK_SIZE 32 +struct CarForEach +{ + int id; + bool ty_is_spell_not_entity; + dumb_ptr<effect_t> body; + dumb_ptr<std::vector<BlockId>> entities_vp; + int index; +}; +struct CarFor +{ + int id; + dumb_ptr<effect_t> body; + int current; + int stop; +}; +struct CarProc +{ + int args_nr; + int *formalap; + dumb_ptr<val_t[]> old_actualpa; +}; -struct cont_activation_record_t +using CarVariantBase = Variant< + CarForEach, + CarFor, + CarProc +>; + +struct cont_activation_record_t : CarVariantBase { dumb_ptr<effect_t> return_location; - union cu - { - struct - { - int id; - TYPE ty; - dumb_ptr<effect_t> body; - dumb_ptr<std::vector<int>> entities_vp; - int index; - } c_foreach; - struct - { - int id; - dumb_ptr<effect_t> body; - int current; - int stop; - } c_for; - struct - { - int args_nr; - int *formalap; - dumb_ptr<val_t[]> old_actualpa; - } c_proc; - - cu() { really_memzero_this(this); } - ~cu() = default; - cu(const cu&) = default; - cu& operator = (const cu&) = default; - } c; - CONT_STACK ty; + + cont_activation_record_t() = delete; + cont_activation_record_t(cont_activation_record_t&&) = default; + cont_activation_record_t(const cont_activation_record_t&) = delete; + cont_activation_record_t& operator = (cont_activation_record_t&&) = default; + cont_activation_record_t& operator = (const cont_activation_record_t&) = delete; + + cont_activation_record_t(CarForEach v, dumb_ptr<effect_t> rl) : CarVariantBase(std::move(v)), return_location(rl) {} + cont_activation_record_t(CarFor v, dumb_ptr<effect_t> rl) : CarVariantBase(std::move(v)), return_location(rl) {} + cont_activation_record_t(CarProc v, dumb_ptr<effect_t> rl) : CarVariantBase(std::move(v)), return_location(rl) {} }; struct status_change_ref_t { StatusChange sc_type; - int bl_id; + BlockId bl_id; }; struct invocation : block_list @@ -387,66 +579,30 @@ struct invocation : block_list dumb_ptr<env_t> env; dumb_ptr<spell_t> spell; - int caster; /* this is the person who originally invoked the spell */ - int subject; /* when this person dies, the spell dies with it */ + 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 */ - int stack_size; - cont_activation_record_t stack[MAX_STACK_SIZE]; + std::vector<cont_activation_record_t> stack; int script_pos; /* Script position; if nonzero, resume the script we were running. */ dumb_ptr<effect_t> current_effect; - dumb_ptr<effect_t> trigger_effect; /* If non-NULL, this is used to spawn a cloned effect based on the same environment */ - dumb_ptr<effect_t> end_effect; /* If non-NULL, this is executed when the spell terminates naturally, e.g. when all status changes have run out or all delays are over. */ + 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 -inline dumb_ptr<invocation> block_list::as_spell() { return dumb_ptr<invocation>(static_cast<invocation *>(this)); } -inline dumb_ptr<invocation> block_list::is_spell() { return bl_type == BL::SPELL ? as_spell() : nullptr; } - -extern magic_conf_t magic_conf; /* Global magic conf */ -extern env_t magic_default_env; /* Fake default environment */ - -/** - * Adds a component selection to a component holder (which may initially be NULL) - */ -void magic_add_component(dumb_ptr<component_t> *component_holder, int id, int count); - -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) - */ -effect_set_t *spell_trigger(dumb_ptr<spell_t> spell, - dumb_ptr<map_session_data> caster, - dumb_ptr<env_t> env, int *near_miss); - -dumb_ptr<invocation> spell_instantiate(effect_set_t *effect, dumb_ptr<env_t> env); - -/** - * 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); +// 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 { @@ -465,7 +621,5 @@ struct proc_t , body() {} }; - -void spell_update_location(dumb_ptr<invocation> invocation); - -#endif // TMWA_MAP_MAGIC_INTERPRETER_HPP +} // namespace magic +} // namespace tmwa diff --git a/src/map/magic-interpreter.py b/src/map/magic-interpreter.py index 8170f27..f6fa4c9 100644 --- a/src/map/magic-interpreter.py +++ b/src/map/magic-interpreter.py @@ -2,7 +2,7 @@ class area_t(object): ''' print an area_t ''' __slots__ = ('_value') - name = 'area_t' + name = 'tmwa::area_t' enabled = True def __init__(self, value): @@ -31,7 +31,7 @@ class val_t(object): ''' print a val_t ''' __slots__ = ('_value') - name = 'val_t' + name = 'tmwa::val_t' enabled = True def __init__(self, value): @@ -69,7 +69,7 @@ class e_area_t(object): ''' print an e_area_t ''' __slots__ = ('_value') - name = 'e_area_t' + name = 'tmwa::e_area_t' enabled = True def __init__(self, value): @@ -97,7 +97,7 @@ class expr_t(object): ''' print an expr_t ''' __slots__ = ('_value') - name = 'expr_t' + name = 'tmwa::expr_t' enabled = True def __init__(self, value): @@ -129,7 +129,7 @@ class effect_t(object): ''' print an effect_t ''' __slots__ = ('_value') - name = 'effect_t' + name = 'tmwa::effect_t' enabled = True def __init__(self, value): @@ -166,7 +166,7 @@ class spellguard_t(object): ''' print a spellguard_t ''' __slots__ = ('_value') - name = 'spellguard_t' + name = 'tmwa::spellguard_t' enabled = True def __init__(self, value): @@ -201,7 +201,7 @@ class cont_activation_record_t(object): ''' print a cont_activation_record_t ''' __slots__ = ('_value') - name = 'cont_activation_record_t' + name = 'tmwa::cont_activation_record_t' enabled = True def __init__(self, value): diff --git a/src/map/magic-interpreter.t.hpp b/src/map/magic-interpreter.t.hpp index 9310a7b..ab151fc 100644 --- a/src/map/magic-interpreter.t.hpp +++ b/src/map/magic-interpreter.t.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_MAGIC_INTERPRETER_T_HPP -#define TMWA_MAP_MAGIC_INTERPRETER_T_HPP +#pragma once // magic-interpreter.t.hpp - Old magic. // // Copyright © 2004-2011 The Mana World Development Team @@ -20,10 +19,15 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "../generic/enum.hpp" +#include "../generic/enum.hpp" + +namespace tmwa +{ +namespace magic +{ enum class SPELLARG : uint8_t { NONE, @@ -31,90 +35,6 @@ enum class SPELLARG : uint8_t STRING, }; -enum class TYPE : uint8_t -{ - UNDEF, - INT, - DIR, - STRING, - ENTITY, - LOCATION, - AREA, - SPELL, - INVOCATION, - FAIL = 127, - - NEGATIVE_1 = 255, -}; - -// Note: there is also a typedef by this name in <dirent.h> -// but we should be fine since we never include it. -// (in the long term we should still rename this though) -enum class DIR : uint8_t -{ - S = 0, - SW = 1, - W = 2, - NW = 3, - N = 4, - NE = 5, - E = 6, - SE = 7, - - COUNT, -}; - -constexpr -earray<int, DIR, DIR::COUNT> dirx //= -{{ - 0, -1, -1, -1, 0, 1, 1, 1, -}}, diry //= -{{ - 1, 1, 0, -1, -1, -1, 0, 1, -}}; - -constexpr -bool dir_is_diagonal(DIR d) -{ - return static_cast<uint8_t>(d) & 1; -} - -enum class AREA : uint8_t -{ - LOCATION, - UNION, - RECT, - BAR, -}; - -enum class EXPR : uint8_t -{ - VAL, - LOCATION, - AREA, - FUNAPP, - ID, - SPELLFIELD, -}; - -// temporary rename to avoid collision with enum value -// in magic-interpreter-parser -enum class EFFECT : uint8_t -{ - SKIP, - ABORT, - ASSIGN, - FOREACH, - FOR, - IF, - SLEEP, - SCRIPT, - BREAK, - OP, - END, - CALL, -}; - enum class FOREACH_FILTER : uint8_t { MOB, @@ -125,17 +45,6 @@ enum class FOREACH_FILTER : uint8_t NPC, }; -enum class SPELLGUARD : uint8_t -{ - CONDITION, - COMPONENTS, - CATALYSTS, - CHOICE, - MANA, - CASTTIME, - EFFECT, -}; - namespace e { enum class SPELL_FLAG : uint8_t @@ -153,13 +62,6 @@ ENUM_BITWISE_OPERATORS(SPELL_FLAG) } using e::SPELL_FLAG; -enum class CONT_STACK : uint8_t -{ - FOREACH, - FOR, - PROC, -}; - namespace e { enum class INVOCATION_FLAG : uint8_t @@ -176,5 +78,5 @@ enum class INVOCATION_FLAG : uint8_t ENUM_BITWISE_OPERATORS(INVOCATION_FLAG) } using e::INVOCATION_FLAG; - -#endif // TMWA_MAP_MAGIC_INTERPRETER_T_HPP +} // namespace magic +} // namespace tmwa 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 diff --git a/src/map/magic-stmt.hpp b/src/map/magic-stmt.hpp index 838854f..28af140 100644 --- a/src/map/magic-stmt.hpp +++ b/src/map/magic-stmt.hpp @@ -1,8 +1,8 @@ -#ifndef TMWA_MAP_MAGIC_STMT_HPP -#define TMWA_MAP_MAGIC_STMT_HPP -// magic-stmt.hpp - dummy header to make Make dependencies work. +#pragma once +// magic-stmt.hpp - Imperative commands for the magic backend. // -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// 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) // @@ -19,6 +19,76 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -#endif // TMWA_MAP_MAGIC_STMT_HPP +#include "../range/fwd.hpp" + +#include "../strings/zstring.hpp" + +#include "../generic/fwd.hpp" + +#include "skill.t.hpp" + + +namespace tmwa +{ +namespace magic +{ +struct op_t +{ + ZString name; + ZString 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 tmwa diff --git a/src/map/magic-v2.cpp b/src/map/magic-v2.cpp index 41d29cd..73b7534 100644 --- a/src/map/magic-v2.cpp +++ b/src/map/magic-v2.cpp @@ -18,17 +18,35 @@ // 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 "../sexpr/parser.hpp" +#include "../strings/rstring.hpp" +#include "../strings/literal.hpp" -#include "../mmo/dumb_ptr.hpp" +#include "../generic/dumb_ptr.hpp" + +#include "../io/cxxstdio.hpp" +#include "../io/line.hpp" + +#include "../sexpr/parser.hpp" #include "itemdb.hpp" #include "magic-expr.hpp" +#include "magic-interpreter.hpp" +#include "magic-interpreter-base.hpp" +#include "magic-stmt.hpp" #include "../poison.hpp" + +namespace tmwa +{ +namespace magic +{ namespace magic_v2 { static @@ -49,8 +67,8 @@ namespace magic_v2 /* Must add new */ magic_conf_t::mcvar new_var {}; new_var.name = id_name; - new_var.val.ty = TYPE::UNDEF; - magic_conf.varv.push_back(new_var); + new_var.val = ValUndef(); + magic_conf.varv.push_back(std::move(new_var)); return i; } @@ -61,8 +79,8 @@ namespace magic_v2 if (zid != id) { FPRINTF(stderr, - "[magic-conf] INTERNAL ERROR: Builtin special var %s interned to %d, not %d as it should be!\n", - name, zid, id); + "[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; } @@ -72,45 +90,38 @@ namespace magic_v2 { bool ok = true; - ok &= INTERN_ASSERT("min_casttime", VAR_MIN_CASTTIME); - ok &= INTERN_ASSERT("obscure_chance", VAR_OBSCURE_CHANCE); - ok &= INTERN_ASSERT("caster", VAR_CASTER); - ok &= INTERN_ASSERT("spellpower", VAR_SPELLPOWER); - ok &= INTERN_ASSERT("self_spell", VAR_SPELL); - ok &= INTERN_ASSERT("self_invocation", VAR_INVOCATION); - ok &= INTERN_ASSERT("target", VAR_TARGET); - ok &= INTERN_ASSERT("script_target", VAR_SCRIPTTARGET); - ok &= INTERN_ASSERT("location", VAR_LOCATION); + 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) + bool bind_constant(io::LineSpan span, RString name, val_t val) { - if (!const_defm.insert({name, *val}).second) + if (!const_defm.insert(std::make_pair(name, std::move(val))).second) { - span.error(STRPRINTF("Redefinition of constant '%s'", name)); + span.error(STRPRINTF("Redefinition of constant '%s'"_fmt, name)); return false; } return true; } static - val_t *find_constant(RString name) + const val_t *find_constant(RString name) { auto it = const_defm.find(name); if (it != const_defm.end()) return &it->second; - return NULL; - } - static - dumb_ptr<effect_t> new_effect(EFFECT ty) - { - auto effect = dumb_ptr<effect_t>::make(); - effect->ty = ty; - return effect; + return nullptr; } static dumb_ptr<effect_t> set_effect_continuation(dumb_ptr<effect_t> src, dumb_ptr<effect_t> continuation) @@ -123,10 +134,13 @@ namespace magic_v2 /* For FOR and FOREACH, we use special stack handlers and thus don't have to set * the continuation. It's only IF that we need to handle in this fashion. */ - if (src->ty == EFFECT::IF) + MATCH (*src) { - set_effect_continuation(src->e.e_if.true_branch, continuation); - set_effect_continuation(src->e.e_if.false_branch, continuation); + CASE (EffectIf&, e_if) + { + set_effect_continuation(e_if.true_branch, continuation); + set_effect_continuation(e_if.false_branch, continuation); + } } if (src->next) @@ -137,13 +151,6 @@ namespace magic_v2 return retval; } static - dumb_ptr<spellguard_t> new_spellguard(SPELLGUARD ty) - { - dumb_ptr<spellguard_t> retval = dumb_ptr<spellguard_t>::make(); - retval->ty = ty; - return retval; - } - static dumb_ptr<spellguard_t> spellguard_implication(dumb_ptr<spellguard_t> a, dumb_ptr<spellguard_t> b) { dumb_ptr<spellguard_t> retval = a; @@ -165,8 +172,13 @@ namespace magic_v2 } /* If the premise is a disjunction, b is the continuation of _all_ branches */ - if (a->ty == SPELLGUARD::CHOICE) - spellguard_implication(a->s.s_alt, b); + MATCH (*a) + { + CASE(const GuardChoice&, s) + { + spellguard_implication(s.s_alt, b); + } + } if (a->next) spellguard_implication(a->next, b); @@ -184,14 +196,14 @@ namespace magic_v2 auto pair1 = magic_conf.spells_by_name.insert({spell->name, spell}); if (!pair1.second) { - span.error(STRPRINTF("Attempt to redefine spell '%s'", spell->name)); + 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'", spell->invocation)); + span.error(STRPRINTF("Attempt to redefine spell invocation '%s'"_fmt, spell->invocation)); magic_conf.spells_by_name.erase(pair1.first); return false; } @@ -203,14 +215,14 @@ namespace magic_v2 auto pair1 = magic_conf.anchors_by_name.insert({anchor->name, anchor}); if (!pair1.second) { - span.error(STRPRINTF("Attempt to redefine teleport anchor '%s'", anchor->name)); + 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'", anchor->invocation)); + span.error(STRPRINTF("Attempt to redefine anchor invocation '%s'"_fmt, anchor->invocation)); magic_conf.anchors_by_name.erase(pair1.first); return false; } @@ -223,7 +235,7 @@ namespace magic_v2 RString name = proc->name; if (!procs.insert({name, std::move(*proc)}).second) { - span.error("procedure already exists"); + span.error("procedure already exists"_s); return false; } return true; @@ -234,7 +246,7 @@ namespace magic_v2 auto pi = procs.find(name); if (pi == procs.end()) { - span.error(STRPRINTF("Unknown procedure '%s'", name)); + span.error(STRPRINTF("Unknown procedure '%s'"_fmt, name)); return false; } @@ -242,15 +254,16 @@ namespace magic_v2 if (p->argv.size() != argvp->size()) { - span.error(STRPRINTF("Procedure %s/%zu invoked with %zu parameters", + span.error(STRPRINTF("Procedure %s/%zu invoked with %zu parameters"_fmt, name, p->argv.size(), argvp->size())); return false; } - retval = new_effect(EFFECT::CALL); - retval->e.e_call.body = p->body; - retval->e.e_call.formalv = &p->argv; - retval->e.e_call.actualvp = argvp; + EffectCall e_call; + e_call.body = p->body; + e_call.formalv = &p->argv; + e_call.actualvp = argvp; + retval = dumb_ptr<effect_t>::make(e_call, nullptr); return true; } static @@ -259,33 +272,35 @@ namespace magic_v2 op_t *op = magic_get_op(name); if (!op) { - span.error(STRPRINTF("Unknown operation '%s'", name)); + 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", - name, 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; } - effect = new_effect(EFFECT::OP); - effect->e.e_op.line_nr = span.begin.line; - effect->e.e_op.column = span.begin.column; - effect->e.e_op.opp = op; + EffectOp e_op; + e_op.line_nr = span.begin.line; + e_op.column = span.begin.column; + e_op.opp = op; assert (argv.size() <= MAX_ARGS); - effect->e.e_op.args_nr = argv.size(); + e_op.args_nr = argv.size(); - std::copy(argv.begin(), argv.end(), effect->e.e_op.args); + std::copy(argv.begin(), argv.end(), e_op.args); + effect = dumb_ptr<effect_t>::make(e_op, nullptr); return true; } static dumb_ptr<expr_t> dot_expr(dumb_ptr<expr_t> expr, int id) { - dumb_ptr<expr_t> retval = magic_new_expr(EXPR::SPELLFIELD); - retval->e.e_field.id = id; - retval->e.e_field.expr = expr; + ExprField e_field; + e_field.id = id; + e_field.expr = expr; + dumb_ptr<expr_t> retval = dumb_ptr<expr_t>::make(e_field); return retval; } @@ -295,24 +310,25 @@ namespace magic_v2 fun_t *fun = magic_get_fun(name); if (!fun) { - span.error(STRPRINTF("Unknown function '%s'", name)); + 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", - name, 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; } - expr = magic_new_expr(EXPR::FUNAPP); - expr->e.e_funapp.line_nr = span.begin.line; - expr->e.e_funapp.column = span.begin.column; - expr->e.e_funapp.funp = fun; + ExprFunApp e_funapp; + e_funapp.line_nr = span.begin.line; + e_funapp.column = span.begin.column; + e_funapp.funp = fun; assert (argv.size() <= MAX_ARGS); - expr->e.e_funapp.args_nr = argv.size(); + e_funapp.args_nr = argv.size(); - std::copy(argv.begin(), argv.end(), expr->e.e_funapp.args); + std::copy(argv.begin(), argv.end(), e_funapp.args); + expr = dumb_ptr<expr_t>::make(e_funapp); return true; } static @@ -362,20 +378,20 @@ namespace magic_v2 return false; if (s._list[0]._type != sexpr::TOKEN) return false; - return s._list[0]._str == "DISABLED"; + 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"); + return fail(s, "loc not list"_s); if (s._list.size() != 4) - return fail(s, "loc not 3 args"); + return fail(s, "loc not 3 args"_s); if (s._list[0]._type != sexpr::TOKEN) - return fail(s._list[0], "loc cmd not tok"); - if (s._list[0]._str != "@") - return fail(s._list[0], "loc cmd not cmd"); + 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); @@ -389,78 +405,74 @@ namespace magic_v2 case sexpr::INT: { val_t val; - val.ty = TYPE::INT; - val.v.v_int = x._int; - if (val.v.v_int != x._int) - return fail(x, "integer too large"); + val = ValInt{static_cast<int32_t>(x._int)}; + if (val.get_if<ValInt>()->v_int != x._int) + return fail(x, "integer too large"_s); - out = magic_new_expr(EXPR::VAL); - out->e.e_val = val; + out = dumb_ptr<expr_t>::make(std::move(val)); return true; } case sexpr::STRING: { val_t val; - val.ty = TYPE::STRING; - val.v.v_string = dumb_string::copys(x._str); + val = ValString{dumb_string::copys(x._str)}; - out = magic_new_expr(EXPR::VAL); - out->e.e_val = val; + out = dumb_ptr<expr_t>::make(std::move(val)); return true; } case sexpr::TOKEN: { - ZString dirs[8] = { - ZString("S"), ZString("SW"), ZString("W"), ZString("NW"), ZString("N"), ZString("NE"), ZString("E"), ZString("SE"), - }; + 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.ty = TYPE::DIR; - val.v.v_dir = static_cast<DIR>(it - begin); + val = ValDir{static_cast<DIR>(it - begin)}; - out = magic_new_expr(EXPR::VAL); - out->e.e_val = val; + out = dumb_ptr<expr_t>::make(std::move(val)); return true; } } { - if (val_t *val = find_constant(x._str)) + if (const val_t *val = find_constant(x._str)) { - out = magic_new_expr(EXPR::VAL); - out->e.e_val = *val; + val_t copy; + magic_copy_var(©, val); + out = dumb_ptr<expr_t>::make(std::move(copy)); return true; } else { - out = magic_new_expr(EXPR::ID); - out->e.e_id = intern_id(x._str); + ExprId e; + e.e_id = intern_id(x._str); + out = dumb_ptr<expr_t>::make(e); return true; } } break; case sexpr::LIST: if (x._list.empty()) - return fail(x, "empty list"); + return fail(x, "empty list"_s); { if (x._list[0]._type != sexpr::TOKEN) - return fail(x._list[0], "op not token"); + return fail(x._list[0], "op not token"_s); ZString op = x._list[0]._str; // area - if (op == "@") + if (op == "@"_s) { e_location_t loc; if (!parse_loc(x, loc)) return false; - out = magic_new_expr(EXPR::AREA); - out->e.e_area.ty = AREA::LOCATION; - out->e.e_area.a.a_loc = loc; + out = dumb_ptr<expr_t>::make(loc); return true; } - if (op == "@+") + if (op == "@+"_s) { e_location_t loc; dumb_ptr<expr_t> width; @@ -471,14 +483,14 @@ namespace magic_v2 return false; if (!parse_expression(x._list[3], height)) return false; - out = magic_new_expr(EXPR::AREA); - out->e.e_area.ty = AREA::RECT; - out->e.e_area.a.a_rect.loc = loc; - out->e.e_area.a.a_rect.width = width; - out->e.e_area.a.a_rect.height = height; + ExprAreaRect a_rect; + a_rect.loc = loc; + a_rect.width = width; + a_rect.height = height; + out = dumb_ptr<expr_t>::make(a_rect); return true; } - if (op == "TOWARDS") + if (op == "TOWARDS"_s) { e_location_t loc; dumb_ptr<expr_t> dir; @@ -492,41 +504,41 @@ namespace magic_v2 return false; if (!parse_expression(x._list[4], depth)) return false; - out = magic_new_expr(EXPR::AREA); - out->e.e_area.ty = AREA::BAR; - out->e.e_area.a.a_bar.loc = loc; - out->e.e_area.a.a_bar.dir = dir; - out->e.e_area.a.a_bar.width = width; - out->e.e_area.a.a_bar.depth = depth; + ExprAreaBar a_bar; + a_bar.loc = loc; + a_bar.dir = dir; + a_bar.width = width; + a_bar.depth = depth; + out = dumb_ptr<expr_t>::make(a_bar); return true; } - if (op == ".") + if (op == "."_s) { if (x._list.size() != 3) - return fail(x, ". not 2"); + 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"); + 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 + 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"); + 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)) @@ -557,7 +569,7 @@ namespace magic_v2 } static - bool parse_item(const SExpr& s, int& id, int& count) + bool parse_item(const SExpr& s, ItemNameId& id, int& count) { if (s._type == sexpr::STRING) { @@ -565,23 +577,23 @@ namespace magic_v2 item_data *item = itemdb_searchname(s._str); if (!item) - return fail(s, "no such item"); + 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"); + return fail(s, "item not string or list"_s); if (s._list.size() != 2) - return fail(s, "item list is not pair"); + 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"); + 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"); + return fail(s._list[1], "item pair second not name"_s); item_data *item = itemdb_searchname(s._list[1]._str); if (!item) - return fail(s, "no such item"); + return fail(s, "no such item"_s); id = item->nameid; return true; } @@ -590,18 +602,18 @@ namespace magic_v2 bool parse_spellguard(const SExpr& s, dumb_ptr<spellguard_t>& out) { if (s._type != sexpr::LIST) - return fail(s, "not list"); + return fail(s, "not list"_s); if (s._list.empty()) - return fail(s, "empty list"); + return fail(s, "empty list"_s); if (s._list[0]._type != sexpr::TOKEN) - return fail(s._list[0], "not token"); + return fail(s._list[0], "not token"_s); ZString cmd = s._list[0]._str; - if (cmd == "OR") + if (cmd == "OR"_s) { auto begin = s._list.begin() + 1; auto end = s._list.end(); if (begin == end) - return fail(s, "missing arguments"); + return fail(s, "missing arguments"_s); if (!parse_spellguard(*begin, out)) return false; ++begin; @@ -610,21 +622,21 @@ namespace magic_v2 dumb_ptr<spellguard_t> alt; if (!parse_spellguard(*begin, alt)) return false; - dumb_ptr<spellguard_t> choice = new_spellguard(SPELLGUARD::CHOICE); - choice->next = out; - choice->s.s_alt = alt; - out = choice; + GuardChoice choice; + auto next = out; + choice.s_alt = alt; + out = dumb_ptr<spellguard_t>::make(choice, next); } return true; } - if (cmd == "GUARD") + 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"); + return fail(s, "missing arguments"_s); if (!parse_spellguard(end[-1], out)) return false; --end; @@ -639,68 +651,75 @@ namespace magic_v2 } return true; } - if (cmd == "REQUIRE") + if (cmd == "REQUIRE"_s) { if (s._list.size() != 2) - return fail(s, "not one argument"); + return fail(s, "not one argument"_s); dumb_ptr<expr_t> condition; if (!parse_expression(s._list[1], condition)) return false; - out = new_spellguard(SPELLGUARD::CONDITION); - out->s.s_condition = condition; + GuardCondition cond; + cond.s_condition = condition; + out = dumb_ptr<spellguard_t>::make(cond, nullptr); return true; } - if (cmd == "MANA") + if (cmd == "MANA"_s) { if (s._list.size() != 2) - return fail(s, "not one argument"); + return fail(s, "not one argument"_s); dumb_ptr<expr_t> mana; if (!parse_expression(s._list[1], mana)) return false; - out = new_spellguard(SPELLGUARD::MANA); - out->s.s_mana = mana; + GuardMana sp; + sp.s_mana = mana; + out = dumb_ptr<spellguard_t>::make(sp, nullptr); return true; } - if (cmd == "CASTTIME") + if (cmd == "CASTTIME"_s) { if (s._list.size() != 2) - return fail(s, "not one argument"); + return fail(s, "not one argument"_s); dumb_ptr<expr_t> casttime; if (!parse_expression(s._list[1], casttime)) return false; - out = new_spellguard(SPELLGUARD::CASTTIME); - out->s.s_casttime = casttime; + GuardCastTime ct; + ct.s_casttime = casttime; + out = dumb_ptr<spellguard_t>::make(ct, nullptr); return true; } - if (cmd == "CATALYSTS") + if (cmd == "CATALYSTS"_s) { dumb_ptr<component_t> items = nullptr; for (auto it = s._list.begin() + 1, end = s._list.end(); it != end; ++it) { - int id, count; + ItemNameId id; + int count; if (!parse_item(*it, id, count)) return false; magic_add_component(&items, id, count); } - out = new_spellguard(SPELLGUARD::CATALYSTS); - out->s.s_catalysts = items; + GuardCatalysts cat; + cat.s_catalysts = items; + out = dumb_ptr<spellguard_t>::make(cat, nullptr); return true; } - if (cmd == "COMPONENTS") + if (cmd == "COMPONENTS"_s) { dumb_ptr<component_t> items = nullptr; for (auto it = s._list.begin() + 1, end = s._list.end(); it != end; ++it) { - int id, count; + ItemNameId id; + int count; if (!parse_item(*it, id, count)) return false; magic_add_component(&items, id, count); } - out = new_spellguard(SPELLGUARD::COMPONENTS); - out->s.s_components = items; + GuardComponents comp; + comp.s_components = items; + out = dumb_ptr<spellguard_t>::make(comp, nullptr); return true; } - return fail(s._list[0], "unknown guard"); + return fail(s._list[0], "unknown guard"_s); } static @@ -709,7 +728,7 @@ namespace magic_v2 { // these backward lists could be forward by keeping the reference // I know this is true because Linus said so - out = new_effect(EFFECT::SKIP); + out = dumb_ptr<effect_t>::make(EffectSkip{}, nullptr); while (end != begin) { const SExpr& s = *--end; @@ -727,100 +746,102 @@ namespace magic_v2 bool parse_effect(const SExpr& s, dumb_ptr<effect_t>& out) { if (s._type != sexpr::LIST) - return fail(s, "not list"); + return fail(s, "not list"_s); if (s._list.empty()) - return fail(s, "empty list"); + return fail(s, "empty list"_s); if (s._list[0]._type != sexpr::TOKEN) - return fail(s._list[0], "not token"); + return fail(s._list[0], "not token"_s); ZString cmd = s._list[0]._str; - if (cmd == "BLOCK") + if (cmd == "BLOCK"_s) { return build_effect_list(s._list.begin() + 1, s._list.end(), out); } - if (cmd == "SET") + if (cmd == "SET"_s) { if (s._list.size() != 3) - return fail(s, "not 2 args"); + return fail(s, "not 2 args"_s); if (s._list[1]._type != sexpr::TOKEN) - return fail(s._list[1], "not 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"); + return fail(s._list[1], "assigning to constant"_s); dumb_ptr<expr_t> expr; if (!parse_expression(s._list[2], expr)) return false; - out = new_effect(EFFECT::ASSIGN); - out->e.e_assign.id = intern_id(name); - out->e.e_assign.expr = expr; + EffectAssign e_assign; + e_assign.id = intern_id(name); + e_assign.expr = expr; + out = dumb_ptr<effect_t>::make(e_assign, nullptr); return true; } - if (cmd == "SCRIPT") + if (cmd == "SCRIPT"_s) { if (s._list.size() != 2) - return fail(s, "not 1 arg"); + return fail(s, "not 1 arg"_s); if (s._list[1]._type != sexpr::STRING) - return fail(s._list[1], "not string"); + return fail(s._list[1], "not string"_s); ZString body = s._list[1]._str; std::unique_ptr<const ScriptBuffer> script = parse_script(body, s._list[1]._span.begin.line, true); if (!script) - return fail(s._list[1], "script does not compile"); - out = new_effect(EFFECT::SCRIPT); - out->e.e_script = dumb_ptr<const ScriptBuffer>(script.release()); + 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") + if (cmd == "SKIP"_s) { if (s._list.size() != 1) - return fail(s, "not 0 arg"); - out = new_effect(EFFECT::SKIP); + return fail(s, "not 0 arg"_s); + out = dumb_ptr<effect_t>::make(EffectSkip{}, nullptr); return true; } - if (cmd == "ABORT") + if (cmd == "ABORT"_s) { if (s._list.size() != 1) - return fail(s, "not 0 arg"); - out = new_effect(EFFECT::ABORT); + return fail(s, "not 0 arg"_s); + out = dumb_ptr<effect_t>::make(EffectAbort{}, nullptr); return true; } - if (cmd == "END") + if (cmd == "END"_s) { if (s._list.size() != 1) - return fail(s, "not 0 arg"); - out = new_effect(EFFECT::END); + return fail(s, "not 0 arg"_s); + out = dumb_ptr<effect_t>::make(EffectEnd{}, nullptr); return true; } - if (cmd == "BREAK") + if (cmd == "BREAK"_s) { if (s._list.size() != 1) - return fail(s, "not 0 arg"); - out = new_effect(EFFECT::BREAK); + return fail(s, "not 0 arg"_s); + out = dumb_ptr<effect_t>::make(EffectBreak{}, nullptr); return true; } - if (cmd == "FOREACH") + if (cmd == "FOREACH"_s) { if (s._list.size() != 5) - return fail(s, "not 4 arg"); + return fail(s, "not 4 arg"_s); if (s._list[1]._type != sexpr::TOKEN) - return fail(s._list[1], "foreach type not token"); + return fail(s._list[1], "foreach type not token"_s); ZString type = s._list[1]._str; FOREACH_FILTER filter; - if (type == "PC") + if (type == "PC"_s) filter = FOREACH_FILTER::PC; - else if (type == "MOB") + else if (type == "MOB"_s) filter = FOREACH_FILTER::MOB; - else if (type == "ENTITY") + else if (type == "ENTITY"_s) filter = FOREACH_FILTER::ENTITY; - else if (type == "SPELL") + else if (type == "SPELL"_s) filter = FOREACH_FILTER::SPELL; - else if (type == "TARGET") + else if (type == "TARGET"_s) filter = FOREACH_FILTER::TARGET; - else if (type == "NPC") + else if (type == "NPC"_s) filter = FOREACH_FILTER::NPC; else - return fail(s._list[1], "unknown foreach filter"); + 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"); + 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; @@ -828,19 +849,21 @@ namespace magic_v2 return false; if (!parse_effect(s._list[4], effect)) return false; - out = new_effect(EFFECT::FOREACH); - out->e.e_foreach.id = intern_id(var); - out->e.e_foreach.area = area; - out->e.e_foreach.body = effect; - out->e.e_foreach.filter = filter; + + EffectForEach e_foreach; + e_foreach.id = intern_id(var); + e_foreach.area = area; + e_foreach.body = effect; + e_foreach.filter = filter; + out = dumb_ptr<effect_t>::make(e_foreach, nullptr); return true; } - if (cmd == "FOR") + if (cmd == "FOR"_s) { if (s._list.size() != 5) - return fail(s, "not 4 arg"); + return fail(s, "not 4 arg"_s); if (s._list[1]._type != sexpr::TOKEN) - return fail(s._list[1], "for var not 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; @@ -851,17 +874,19 @@ namespace magic_v2 return false; if (!parse_effect(s._list[4], effect)) return false; - out = new_effect(EFFECT::FOR); - out->e.e_for.id = intern_id(var); - out->e.e_for.start = low; - out->e.e_for.stop = high; - out->e.e_for.body = effect; + + EffectFor e_for; + e_for.id = intern_id(var); + e_for.start = low; + e_for.stop = high; + e_for.body = effect; + out = dumb_ptr<effect_t>::make(e_for, nullptr); return true; } - if (cmd == "IF") + if (cmd == "IF"_s) { if (s._list.size() != 3 && s._list.size() != 4) - return fail(s, "not 2 or 3 args"); + 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; @@ -875,30 +900,33 @@ namespace magic_v2 return false; } else - if_false = new_effect(EFFECT::SKIP); - out = new_effect(EFFECT::IF); - out->e.e_if.cond = cond; - out->e.e_if.true_branch = if_true; - out->e.e_if.false_branch = if_false; + if_false = dumb_ptr<effect_t>::make(EffectSkip{}, nullptr); + + EffectIf e_if; + e_if.cond = cond; + e_if.true_branch = if_true; + e_if.false_branch = if_false; + out = dumb_ptr<effect_t>::make(e_if, nullptr); return true; } - if (cmd == "WAIT") + if (cmd == "WAIT"_s) { if (s._list.size() != 2) - return fail(s, "not 1 arg"); + return fail(s, "not 1 arg"_s); dumb_ptr<expr_t> expr; if (!parse_expression(s._list[1], expr)) return false; - out = new_effect(EFFECT::SLEEP); - out->e.e_sleep = expr; + EffectSleep e; + e.e_sleep = expr; + out = dumb_ptr<effect_t>::make(e, nullptr); return true; } - if (cmd == "CALL") + if (cmd == "CALL"_s) { if (s._list.size() < 2) - return fail(s, "call what?"); + return fail(s, "call what?"_s); if (s._list[1]._type != sexpr::TOKEN) - return fail(s._list[1], "call token please"); + 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) @@ -925,16 +953,16 @@ namespace magic_v2 bool parse_spellbody(const SExpr& s, dumb_ptr<spellguard_t>& out) { if (s._type != sexpr::LIST) - return fail(s, "not list"); + return fail(s, "not list"_s); if (s._list.empty()) - return fail(s, "empty list"); + return fail(s, "empty list"_s); if (s._list[0]._type != sexpr::TOKEN) - return fail(s._list[0], "not token"); + return fail(s._list[0], "not token"_s); ZString cmd = s._list[0]._str; - if (cmd == "=>") + if (cmd == "=>"_s) { if (s._list.size() != 3) - return fail(s, "list does not have exactly 2 arguments"); + 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; @@ -944,10 +972,10 @@ namespace magic_v2 out = spellguard_implication(guard, body); return true; } - if (cmd == "|") + if (cmd == "|"_s) { if (s._list.size() == 1) - return fail(s, "spellbody choice empty"); + return fail(s, "spellbody choice empty"_s); auto begin = s._list.begin() + 1; auto end = s._list.end(); if (!parse_spellbody(*begin, out)) @@ -959,13 +987,13 @@ namespace magic_v2 if (!parse_spellbody(*begin, alt)) return false; auto tmp = out; - out = new_spellguard(SPELLGUARD::CHOICE); - out->next = tmp; - out->s.s_alt = alt; + GuardChoice choice; + choice.s_alt = alt; + out = dumb_ptr<spellguard_t>::make(choice, tmp); } return true; } - if (cmd == "EFFECT") + if (cmd == "EFFECT"_s) { auto begin = s._list.begin() + 1; auto end = s._list.end(); @@ -978,7 +1006,7 @@ namespace magic_v2 --end; if (end[-1]._type == sexpr::LIST && !end[-1]._list.empty() && end[-1]._list[0]._type == sexpr::TOKEN - && end[-1]._list[0]._str == "ATEND") + && end[-1]._list[0]._str == "ATEND"_s) { auto atb = end[-1]._list.begin() + 1; auto ate = end[-1]._list.end(); @@ -995,7 +1023,7 @@ namespace magic_v2 } if (end[-1]._type == sexpr::LIST && !end[-1]._list.empty() && end[-1]._list[0]._type == sexpr::TOKEN - && end[-1]._list[0]._str == "ATTRIGGER") + && end[-1]._list[0]._str == "ATTRIGGER"_s) { auto atb = end[-1]._list.begin() + 1; auto ate = end[-1]._list.end(); @@ -1009,26 +1037,27 @@ namespace magic_v2 } if (!build_effect_list(begin, end, effect)) return false; - out = new_spellguard(SPELLGUARD::EFFECT); - out->s.s_effect.effect = effect; - out->s.s_effect.at_trigger = attrig; - out->s.s_effect.at_end = atend; + effect_set_t s_effect; + s_effect.effect = effect; + s_effect.at_trigger = attrig; + s_effect.at_end = atend; + out = dumb_ptr<spellguard_t>::make(s_effect, nullptr); return true; } - return fail(s._list[0], "unknown spellbody"); + 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"); + 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"); + 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; @@ -1037,28 +1066,28 @@ namespace magic_v2 bool parse_const(io::LineSpan span, const std::vector<SExpr>& in) { if (in.size() != 3) - return fail(in[0], "not 2 arguments"); + return fail(in[0], "not 2 arguments"_s); if (in[1]._type != sexpr::TOKEN) - return fail(in[1], "not 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, &tmp); + 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"); + 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"); + return fail(in[1], "not token"_s); anchor->name = in[1]._str; if (in[2]._type != sexpr::STRING) - return fail(in[2], "not string"); + return fail(in[2], "not string"_s); anchor->invocation = in[2]._str; dumb_ptr<expr_t> expr; if (!parse_expression(in[3], expr)) @@ -1070,17 +1099,17 @@ namespace magic_v2 bool parse_proc(io::LineSpan span, const std::vector<SExpr>& in) { if (in.size() < 4) - return fail(in[0], "not at least 3 arguments"); + 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"); + 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"); + 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"); + 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)) @@ -1091,37 +1120,37 @@ namespace magic_v2 bool parse_spell(io::LineSpan span, const std::vector<SExpr>& in) { if (in.size() < 6) - return fail(in[0], "not at least 5 arguments"); + return fail(in[0], "not at least 5 arguments"_s); if (in[1]._type != sexpr::LIST) - return fail(in[1], "flags not 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"); + return fail(s, "flag not token"_s); SPELL_FLAG flag = SPELL_FLAG::ZERO; - if (s._str == "LOCAL") + if (s._str == "LOCAL"_s) flag = SPELL_FLAG::LOCAL; - else if (s._str == "NONMAGIC") + else if (s._str == "NONMAGIC"_s) flag = SPELL_FLAG::NONMAGIC; - else if (s._str == "SILENT") + else if (s._str == "SILENT"_s) flag = SPELL_FLAG::SILENT; else - return fail(s, "unknown flag"); + return fail(s, "unknown flag"_s); if (bool(spell->flags & flag)) - return fail(s, "duplicate flag"); + return fail(s, "duplicate flag"_s); spell->flags |= flag; } if (in[2]._type != sexpr::TOKEN) - return fail(in[2], "name not 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"); + 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"); + return fail(in[4], "spellarg not list"_s); if (in[4]._list.size() == 0) { spell->spellarg_ty = SPELLARG::NONE; @@ -1129,18 +1158,18 @@ namespace magic_v2 else { if (in[4]._list.size() != 2) - return fail(in[4], "spellarg not empty list or pair"); + 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"); + 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"); + return fail(in[4]._list[1], "spellarg name not token"_s); ZString ty = in[4]._list[0]._str; - if (ty == "PC") + if (ty == "PC"_s) spell->spellarg_ty = SPELLARG::PC; - else if (ty == "STRING") + else if (ty == "STRING"_s) spell->spellarg_ty = SPELLARG::STRING; else - return fail(in[4]._list[0], "unknown spellarg type"); + return fail(in[4]._list[0], "unknown spellarg type"_s); ZString an = in[4]._list[1]._str; spell->arg = intern_id(an); } @@ -1148,19 +1177,19 @@ namespace magic_v2 for (;; ++it) { if (it == in.end()) - return fail(it[-1], "end of list scanning LET defs"); + 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") + 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"); + 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"); + return fail(it->_list[1], "constant exists"_s); dumb_ptr<expr_t> expr; if (!parse_expression(it->_list[2], expr)) return false; @@ -1170,7 +1199,7 @@ namespace magic_v2 spell->letdefv.push_back(let); } if (it + 1 != in.end()) - return fail(*it, "expected only one body entry besides LET"); + 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 @@ -1186,23 +1215,23 @@ namespace magic_v2 { if (vs.empty()) { - span.error("Empty list at top"); + span.error("Empty list at top"_s); return false; } if (vs[0]._type != sexpr::TOKEN) - return fail(vs[0], "top not token"); + return fail(vs[0], "top not token"_s); ZString cmd = vs[0]._str; - if (cmd == "CONST") + if (cmd == "CONST"_s) return parse_const(span, vs); - if (cmd == "PROCEDURE") + if (cmd == "PROCEDURE"_s) return parse_proc(span, vs); - if (cmd == "SET") + if (cmd == "SET"_s) return parse_top_set(vs); - if (cmd == "SPELL") + if (cmd == "SPELL"_s) return parse_spell(span, vs); - if (cmd == "TELEPORT-ANCHOR") + if (cmd == "TELEPORT-ANCHOR"_s) return parse_anchor(span, vs); - return fail(vs[0], "Unknown top-level command"); + return fail(vs[0], "Unknown top-level command"_s); } static @@ -1214,14 +1243,14 @@ namespace magic_v2 if (is_comment(s)) continue; if (s._type != sexpr::LIST) - return fail(s, "top-level entity not a list or comment"); + 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"); + in.span().error("parser gave up before end of file"_s); return false; } return true; @@ -1239,7 +1268,9 @@ bool load_magic_file_v2(ZString filename) bool rv = magic_v2::loop(in); if (!rv) { - in.span().error(STRPRINTF("next token: %s '%s'", sexpr::token_name(in.peek()), in.val_string())); + in.span().error(STRPRINTF("next token: %s '%s'"_fmt, sexpr::token_name(in.peek()), in.val_string())); } return rv; } +} // namespace magic +} // namespace tmwa diff --git a/src/map/magic-v2.hpp b/src/map/magic-v2.hpp index 888e183..9ad44a9 100644 --- a/src/map/magic-v2.hpp +++ b/src/map/magic-v2.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_MAGIC_V2_HPP -#define TMWA_MAP_MAGIC_V2_HPP +#pragma once // magic-v2.hpp - second generation magic parser // // Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> @@ -19,12 +18,17 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "../strings/zstring.hpp" +#include "../strings/zstring.hpp" + +namespace tmwa +{ +namespace magic +{ bool magic_init0(); // must be called after itemdb initialization bool load_magic_file_v2(ZString filename); - -#endif // TMWA_MAP_MAGIC_V2_HPP +} // namespace magic +} // namespace tmwa diff --git a/src/map/magic.cpp b/src/map/magic.cpp index 9896b26..a0238b5 100644 --- a/src/map/magic.cpp +++ b/src/map/magic.cpp @@ -1,3 +1,4 @@ +#include "magic.hpp" // magic.cpp - Entry to the magic system. // // Copyright © 2004-2011 The Mana World Development Team @@ -18,25 +19,29 @@ // 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 <cstring> +#include <algorithm> +#include <utility> #include "../strings/xstring.hpp" -#include "../io/cxxstdio.hpp" - -#include "magic-interpreter.hpp" +#include "../generic/dumb_ptr.hpp" -#include "pc.hpp" +#include "../io/cxxstdio.hpp" #include "magic-expr.hpp" +#include "magic-interpreter.hpp" #include "magic-interpreter-base.hpp" #include "magic-stmt.hpp" -#include "magic.hpp" +#include "map.hpp" +#include "pc.hpp" #include "../poison.hpp" -#undef DEBUG +namespace tmwa +{ +namespace magic +{ /// Return a pair of strings, {spellname, parameter} /// Parameter may be empty. static @@ -90,20 +95,15 @@ int magic_message(dumb_ptr<map_session_data> caster, XString source_invocation) int near_miss; dumb_ptr<env_t> env = spell_create_env(&magic_conf, spell, caster, power, parameter); - effect_set_t *effects; + const effect_set_t *effects; if (bool(spell->flags & SPELL_FLAG::NONMAGIC) || (power >= 1)) effects = spell_trigger(spell, caster, env, &near_miss); else - effects = NULL; - -#ifdef DEBUG - FPRINTF(stderr, "Found spell `%s', triggered = %d\n", spell_, - effects != NULL); -#endif + effects = nullptr; - MAP_LOG_PC(caster, "CAST %s %s", - spell->name, effects ? "SUCCESS" : "FAILURE"); + MAP_LOG_PC(caster, "CAST %s %s"_fmt, + spell->name, effects ? "SUCCESS"_s : "FAILURE"_s); if (effects) { @@ -122,3 +122,5 @@ int magic_message(dumb_ptr<map_session_data> caster, XString source_invocation) return 0; /* Not a spell */ } +} // namespace magic +} // namespace tmwa diff --git a/src/map/magic.hpp b/src/map/magic.hpp index a5a966c..a420872 100644 --- a/src/map/magic.hpp +++ b/src/map/magic.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_MAGIC_HPP -#define TMWA_MAP_MAGIC_HPP +#pragma once // magic.hpp - Entry to the magic system. // // Copyright © 2004-2011 The Mana World Development Team @@ -20,17 +19,20 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "../strings/fwd.hpp" +#include "../strings/fwd.hpp" -# include "../mmo/dumb_ptr.hpp" +#include "../generic/fwd.hpp" -# include "map.hpp" -# include "skill.t.hpp" +#include "map.t.hpp" +#include "skill.t.hpp" -struct invocation; /* Spell invocation */ +namespace tmwa +{ +namespace magic +{ /** * Try to cast magic. * @@ -43,62 +45,5 @@ struct invocation; /* Spell invocation */ * message should not be repeated. */ int magic_message(dumb_ptr<map_session_data> caster, XString source_invocation); - -/** - * 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(int invocation, int bl_id, - StatusChange sc_id, int supplanted); - -/** - * 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); - -/** - * 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(int caster, int target); - -void spell_free_invocation(dumb_ptr<invocation> invocation); - -#endif // TMWA_MAP_MAGIC_HPP +} // namespace magic +} // namespace tmwa diff --git a/src/map/main.cpp b/src/map/main.cpp index 2db1408..8e8e9d5 100644 --- a/src/map/main.cpp +++ b/src/map/main.cpp @@ -1,4 +1,3 @@ -#include "map.hpp" // map/main.cpp - dummy file to make Make dependencies work // // Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> @@ -18,4 +17,11 @@ // 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 "map.hpp" + #include "../poison.hpp" + + +namespace tmwa +{ +} // namespace tmwa diff --git a/src/map/map.cpp b/src/map/map.cpp index b49b225..4a25029 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -29,29 +29,34 @@ #include <cassert> #include <cstdlib> -#include <cstring> #include "../compat/nullpo.hpp" #include "../compat/fun.hpp" +#include "../ints/udl.hpp" + #include "../strings/astring.hpp" #include "../strings/zstring.hpp" #include "../strings/xstring.hpp" #include "../strings/vstring.hpp" +#include "../strings/literal.hpp" #include "../generic/db.hpp" #include "../generic/random2.hpp" #include "../io/cxxstdio.hpp" +#include "../io/cxxstdio_enums.hpp" #include "../io/read.hpp" #include "../io/tty.hpp" #include "../io/write.hpp" +#include "../net/socket.hpp" +#include "../net/timer.hpp" + #include "../mmo/config_parse.hpp" #include "../mmo/core.hpp" #include "../mmo/extract.hpp" -#include "../mmo/socket.hpp" -#include "../mmo/timer.hpp" +#include "../mmo/utils.hpp" #include "../mmo/version.hpp" #include "atcommand.hpp" @@ -60,8 +65,8 @@ #include "clif.hpp" #include "grfio.hpp" #include "itemdb.hpp" -#include "magic.hpp" -#include "magic-interpreter.hpp" +#include "magic-interpreter.hpp" // for is_spell inline body +#include "magic-stmt.hpp" #include "magic-v2.hpp" #include "mob.hpp" #include "npc.hpp" @@ -74,7 +79,10 @@ #include "../poison.hpp" -DMap<int, dumb_ptr<block_list>> id_db; + +namespace tmwa +{ +DMap<BlockId, dumb_ptr<block_list>> id_db; UPMap<MapName, map_abstract> maps_db; @@ -88,21 +96,21 @@ struct charid2nick }; static -Map<int, struct charid2nick> charid_db; +Map<CharId, struct charid2nick> charid_db; static int users = 0; static -Array<dumb_ptr<block_list>, MAX_FLOORITEM> object; +Array<dumb_ptr<block_list>, unwrap<BlockId>(MAX_FLOORITEM)> object; static -int first_free_object_id = 0, last_object_id = 0; +BlockId first_free_object_id = BlockId(); interval_t autosave_time = DEFAULT_AUTOSAVE_INTERVAL; int save_settings = 0xFFFF; -AString motd_txt = "conf/motd.txt"; +AString motd_txt = "conf/motd.txt"_s; -CharName wisp_server_name = stringish<CharName>("Server"); // can be modified in char-server configuration file +CharName wisp_server_name = stringish<CharName>("Server"_s); // can be modified in char-server configuration file static void map_delmap(MapName mapname); @@ -112,6 +120,10 @@ void SessionDeleter::operator()(SessionData *sd) really_delete1 static_cast<map_session_data *>(sd); } +VString<49> convert_for_printf(NpcEvent ev) +{ + return STRNPRINTF(50, "%s::%s"_fmt, ev.npc, ev.label); +} bool extract(XString str, NpcEvent *ev) { XString mid; @@ -181,12 +193,12 @@ struct block_list bl_head; */ int map_addblock(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_prev) { if (battle_config.error_log) - PRINTF("map_addblock error : bl->bl_prev!=NULL\n"); + PRINTF("map_addblock error : bl->bl_prev!=nullptr\n"_fmt); return 0; } @@ -226,7 +238,7 @@ int map_addblock(dumb_ptr<block_list> bl) */ int map_delblock(dumb_ptr<block_list> bl) { - nullpo_ret(bl); + nullpo_retz(bl); // 既にblocklistから抜けている if (!bl->bl_prev) @@ -235,7 +247,7 @@ int map_delblock(dumb_ptr<block_list> bl) { // prevがNULLでnextがNULLでないのは有ってはならない if (battle_config.error_log) - PRINTF("map_delblock error : bl->bl_next!=NULL\n"); + PRINTF("map_delblock error : bl->bl_next!=nullptr\n"_fmt); } return 0; } @@ -261,8 +273,8 @@ int map_delblock(dumb_ptr<block_list> bl) { bl->bl_prev->bl_next = bl->bl_next; } - bl->bl_next = NULL; - bl->bl_prev = NULL; + bl->bl_next = nullptr; + bl->bl_prev = nullptr; return 0; } @@ -274,7 +286,7 @@ int map_delblock(dumb_ptr<block_list> bl) int map_count_oncell(map_local *m, int x, int y) { int bx, by; - dumb_ptr<block_list> bl = NULL; + dumb_ptr<block_list> bl = nullptr; int count = 0; if (x < 0 || y < 0 || (x >= m->xs) || (y >= m->ys)) @@ -533,29 +545,27 @@ void map_foreachincell(std::function<void(dumb_ptr<block_list>)> func, * bl->bl_idもこの中で設定して問題無い? *------------------------------------------ */ -int map_addobject(dumb_ptr<block_list> bl) +BlockId map_addobject(dumb_ptr<block_list> bl) { - int i; + BlockId i; if (!bl) { - PRINTF("map_addobject nullpo?\n"); - return 0; + PRINTF("map_addobject nullpo?\n"_fmt); + return BlockId(); } - if (first_free_object_id < 2 || first_free_object_id >= MAX_FLOORITEM) - first_free_object_id = 2; - for (i = first_free_object_id; i < MAX_FLOORITEM; i++) - if (!object[i]) + if (first_free_object_id < wrap<BlockId>(2) || first_free_object_id == MAX_FLOORITEM) + first_free_object_id = wrap<BlockId>(2); + for (i = first_free_object_id; i < MAX_FLOORITEM; i = next(i)) + if (!object[i._value]) break; - if (i >= MAX_FLOORITEM) + if (i == MAX_FLOORITEM) { if (battle_config.error_log) - PRINTF("no free object id\n"); - return 0; + PRINTF("no free object id\n"_fmt); + return BlockId(); } first_free_object_id = i; - if (last_object_id < i) - last_object_id = i; - object[i] = bl; + object[i._value] = bl; id_db.put(i, bl); return i; } @@ -565,32 +575,26 @@ int map_addobject(dumb_ptr<block_list> bl) * map_delobjectのfreeしないバージョン *------------------------------------------ */ -int map_delobjectnofree(int id, BL type) +void map_delobjectnofree(BlockId id, BL type) { assert (id < MAX_FLOORITEM); - if (!object[id]) - return 0; + if (!object[id._value]) + return; - if (object[id]->bl_type != type) + if (object[id._value]->bl_type != type) { - FPRINTF(stderr, "Incorrect type: expected %d, got %d\n", + FPRINTF(stderr, "Incorrect type: expected %d, got %d\n"_fmt, type, - object[id]->bl_type); + object[id._value]->bl_type); abort(); } - map_delblock(object[id]); + map_delblock(object[id._value]); id_db.put(id, dumb_ptr<block_list>()); -// map_freeblock(object[id]); - object[id] = nullptr; + object[id._value] = nullptr; - if (first_free_object_id > id) + if (id < first_free_object_id) first_free_object_id = id; - - while (last_object_id > 2 && object[last_object_id] == NULL) - last_object_id--; - - return 0; } /*========================================== @@ -601,21 +605,19 @@ int map_delobjectnofree(int id, BL type) * addとの対称性が無いのが気になる *------------------------------------------ */ -int map_delobject(int id, BL type) +void map_delobject(BlockId id, BL type) { assert (id < MAX_FLOORITEM); - dumb_ptr<block_list> obj = object[id]; + dumb_ptr<block_list> obj = object[id._value]; - if (obj == NULL) - return 0; + if (obj == nullptr) + return; map_delobjectnofree(id, type); if (obj->bl_type == BL::PC) // [Fate] Not sure where else to put this... I'm not sure where delobject for PCs is called from pc_cleanup(obj->is_player()); MapBlockLock::freeblock(obj); - - return 0; } /*========================================== @@ -626,24 +628,28 @@ int map_delobject(int id, BL type) void map_foreachobject(std::function<void(dumb_ptr<block_list>)> func, BL type) { - assert (last_object_id < MAX_FLOORITEM); std::vector<dumb_ptr<block_list>> bl_list; - for (int i = 2; i <= last_object_id; i++) + for (BlockId i = wrap<BlockId>(2); i < MAX_FLOORITEM; i = next(i)) { - if (!object[i]) + if (!object[i._value]) continue; { - if (type != BL::NUL && object[i]->bl_type != type) + if (type != BL::NUL && object[i._value]->bl_type != type) continue; - bl_list.push_back(object[i]); + bl_list.push_back(object[i._value]); } } MapBlockLock lock; for (dumb_ptr<block_list> bl : bl_list) + { + // TODO figure out if the second branch can happen + // bl_prev is non-null for all that are on a map (see bl_head) + // bl_next is only meaningful for objects that are on a map if (bl->bl_prev || bl->bl_next) func(bl); + } } /*========================================== @@ -656,15 +662,15 @@ void map_foreachobject(std::function<void(dumb_ptr<block_list>)> func, * map.h内で#defineしてある *------------------------------------------ */ -void map_clearflooritem_timer(TimerData *tid, tick_t, int id) +void map_clearflooritem_timer(TimerData *tid, tick_t, BlockId id) { assert (id < MAX_FLOORITEM); - dumb_ptr<block_list> obj = object[id]; + dumb_ptr<block_list> obj = object[id._value]; assert (obj && obj->bl_type == BL::ITEM); dumb_ptr<flooritem_data> fitem = obj->is_item(); if (!tid) fitem->cleartimer.cancel(); - clif_clearflooritem(fitem, 0); + clif_clearflooritem(fitem, nullptr); map_delobject(fitem->bl_id, BL::ITEM); } @@ -678,7 +684,7 @@ std::pair<uint16_t, uint16_t> map_randfreecell(map_local *m, if (!bool(read_gatp(m, x + dx, y + dy) & MapCell::UNWALKABLE)) return {static_cast<uint16_t>(x + dx), static_cast<uint16_t>(y + dy)}; } - return {static_cast<uint16_t>(0), static_cast<uint16_t>(0)}; + return {0_u16, 0_u16}; } /// Return a randomly selected passable cell within a given range. @@ -695,36 +701,36 @@ std::pair<uint16_t, uint16_t> map_searchrandfreecell(map_local *m, int x, int y, * item_dataはamount以外をcopyする *------------------------------------------ */ -int map_addflooritem_any(struct item *item_data, int amount, +BlockId map_addflooritem_any(Item *item_data, int amount, map_local *m, int x, int y, dumb_ptr<map_session_data> *owners, interval_t *owner_protection, interval_t lifetime, int dispersal) { - dumb_ptr<flooritem_data> fitem = NULL; + dumb_ptr<flooritem_data> fitem = nullptr; - nullpo_ret(item_data); + nullpo_retr(BlockId(), item_data); auto xy = map_searchrandfreecell(m, x, y, dispersal); if (xy.first == 0 && xy.second == 0) - return 0; + return BlockId(); fitem.new_(); fitem->bl_type = BL::ITEM; - fitem->bl_prev = fitem->bl_next = NULL; + fitem->bl_prev = fitem->bl_next = nullptr; fitem->bl_m = m; fitem->bl_x = xy.first; fitem->bl_y = xy.second; - fitem->first_get_id = 0; + fitem->first_get_id = BlockId(); fitem->first_get_tick = tick_t(); - fitem->second_get_id = 0; + fitem->second_get_id = BlockId(); fitem->second_get_tick = tick_t(); - fitem->third_get_id = 0; + fitem->third_get_id = BlockId(); fitem->third_get_tick = tick_t(); fitem->bl_id = map_addobject(fitem); - if (fitem->bl_id == 0) + if (!fitem->bl_id) { fitem.delete_(); - return 0; + return BlockId(); } tick_t tick = gettick(); @@ -760,7 +766,7 @@ int map_addflooritem_any(struct item *item_data, int amount, return fitem->bl_id; } -int map_addflooritem(struct item *item_data, int amount, +BlockId map_addflooritem(Item *item_data, int amount, map_local *m, int x, int y, dumb_ptr<map_session_data> first_sd, dumb_ptr<map_session_data> second_sd, @@ -784,10 +790,10 @@ int map_addflooritem(struct item *item_data, int amount, * charid_dbへ追加(返信待ちがあれば返信) *------------------------------------------ */ -void map_addchariddb(int charid, CharName name) +void map_addchariddb(CharId charid, CharName name) { struct charid2nick *p = charid_db.search(charid); - if (p == NULL) + if (p == nullptr) p = charid_db.init(charid); p->nick = name; @@ -840,7 +846,7 @@ void map_quit(dumb_ptr<map_session_data> sd) if (sd->trade_partner) // 取引を中断する trade_tradecancel(sd); - if (sd->party_invite > 0) // パーティ勧誘を拒否する + if (sd->party_invite) // パーティ勧誘を拒否する party_reply_invite(sd, sd->party_invite_account, 0); party_send_logout(sd); // パーティのログアウトメッセージ送信 @@ -883,7 +889,7 @@ void map_quit(dumb_ptr<map_session_data> sd) * id番号のPCを探す。居なければNULL *------------------------------------------ */ -dumb_ptr<map_session_data> map_id2sd(int id) +dumb_ptr<map_session_data> map_id2sd(BlockId id) { // This is bogus. // However, there might be differences for de-auth'ed accounts. @@ -899,7 +905,7 @@ dumb_ptr<map_session_data> map_id2sd(int id) bl=numdb_search(id_db,id); if (bl && bl->bl_type==BL::PC) return (struct map_session_data*)bl; - return NULL; + return nullptr; */ for (io::FD i : iter_fds()) { @@ -914,18 +920,18 @@ dumb_ptr<map_session_data> map_id2sd(int id) } } - return NULL; + return nullptr; } /*========================================== * char_id番号の名前を探す *------------------------------------------ */ -CharName map_charid2nick(int id) +CharName map_charid2nick(CharId id) { struct charid2nick *p = charid_db.search(id); - if (p == NULL) + if (p == nullptr) return CharName(); if (p->req_id != 0) return CharName(); @@ -947,7 +953,7 @@ dumb_ptr<map_session_data> map_get_session(io::FD i) return dumb_ptr<map_session_data>(d); } - return NULL; + return nullptr; } static @@ -960,7 +966,7 @@ dumb_ptr<map_session_data> map_get_session_forward(int start) return d; } - return NULL; + return nullptr; } static @@ -973,7 +979,7 @@ dumb_ptr<map_session_data> map_get_session_backward(int start) return d; } - return NULL; + return nullptr; } dumb_ptr<map_session_data> map_get_first_session(void) @@ -999,7 +1005,7 @@ dumb_ptr<map_session_data> map_get_prev_session(dumb_ptr<map_session_data> d) /*========================================== * Search session data from a nick name * (without sensitive case if necessary) - * return map_session_data pointer or NULL + * return map_session_data pointer or nullptr *------------------------------------------ */ dumb_ptr<map_session_data> map_nick2sd(CharName nick) @@ -1018,7 +1024,7 @@ dumb_ptr<map_session_data> map_nick2sd(CharName nick) } } } - return NULL; + return nullptr; } /*========================================== @@ -1026,11 +1032,11 @@ dumb_ptr<map_session_data> map_nick2sd(CharName nick) * 一時objectの場合は配列を引くのみ *------------------------------------------ */ -dumb_ptr<block_list> map_id2bl(int id) +dumb_ptr<block_list> map_id2bl(BlockId id) { - dumb_ptr<block_list> bl = NULL; - if (id < sizeof(object) / sizeof(object[0])) - bl = object[id]; + dumb_ptr<block_list> bl = nullptr; + if (id < MAX_FLOORITEM) + bl = object[id._value]; else bl = id_db.get(id); @@ -1047,12 +1053,12 @@ int map_addnpc(map_local *m, dumb_ptr<npc_data> nd) if (!m) return -1; for (i = 0; i < m->npc_num && i < MAX_NPC_PER_MAP; i++) - if (m->npc[i] == NULL) + if (m->npc[i] == nullptr) break; if (i == MAX_NPC_PER_MAP) { if (battle_config.error_log) - PRINTF("too many NPCs in one map %s\n", m->name_); + PRINTF("too many NPCs in one map %s\n"_fmt, m->name_); return -1; } if (i == m->npc_num) @@ -1060,7 +1066,7 @@ int map_addnpc(map_local *m, dumb_ptr<npc_data> nd) m->npc_num++; } - nullpo_ret(nd); + nullpo_retz(nd); m->npc[i] = nd; nd->n = i; @@ -1081,7 +1087,7 @@ void map_removenpc(void) map_local *m = static_cast<map_local *>(mitp.second.get()); for (int i = 0; i < m->npc_num && i < MAX_NPC_PER_MAP; i++) { - if (m->npc[i] != NULL) + if (m->npc[i] != nullptr) { clif_clearchar(m->npc[i], BeingRemoveWhy::QUIT); map_delblock(m->npc[i]); @@ -1096,7 +1102,7 @@ void map_removenpc(void) } } } - PRINTF("%d NPCs removed.\n", n); + PRINTF("%d NPCs removed.\n"_fmt, n); } /*========================================== @@ -1106,7 +1112,7 @@ void map_removenpc(void) map_local *map_mapname2mapid(MapName name) { map_abstract *md = maps_db.get(name); - if (md == NULL || md->gat == NULL) + if (md == nullptr || md->gat == nullptr) return nullptr; return static_cast<map_local *>(md); } @@ -1118,7 +1124,7 @@ map_local *map_mapname2mapid(MapName name) int map_mapname2ipport(MapName name, IP4Address *ip, int *port) { map_abstract *md = maps_db.get(name); - if (md == NULL || md->gat) + if (md == nullptr || md->gat) return -1; map_remote *mdos = static_cast<map_remote *>(md); *ip = mdos->ip; @@ -1227,12 +1233,12 @@ void map_setcell(map_local *m, int x, int y, MapCell t) int map_setipport(MapName name, IP4Address ip, int port) { map_abstract *md = maps_db.get(name); - if (md == NULL) + if (md == nullptr) { // not exist -> add new data auto mdos = make_unique<map_remote>(); mdos->name_ = name; - mdos->gat = NULL; + mdos->gat = nullptr; mdos->ip = ip; mdos->port = port; maps_db.put(mdos->name_, std::move(mdos)); @@ -1244,7 +1250,7 @@ int map_setipport(MapName name, IP4Address ip, int port) // local -> check data if (ip != clif_getip() || port != clif_getport()) { - PRINTF("from char server : %s -> %s:%d\n", + PRINTF("from char server : %s -> %s:%d\n"_fmt, name, ip, port); return 1; } @@ -1275,7 +1281,7 @@ bool map_readmap(map_local *m, size_t num, MapName fn) int xs = m->xs = gat_v[0] | gat_v[1] << 8; int ys = m->ys = gat_v[2] | gat_v[3] << 8; - PRINTF("\rLoading Maps [%zu/%zu]: %-30s (%i, %i)", + PRINTF("\rLoading Maps [%zu/%zu]: %-30s (%i, %i)"_fmt, num, maps_db.size(), fn, xs, ys); fflush(stdout); @@ -1328,10 +1334,10 @@ bool map_readallmap(void) } } - PRINTF("\rMaps Loaded: %-65zu\n", maps_db.size()); + PRINTF("\rMaps Loaded: %-65zu\n"_fmt, maps_db.size()); if (maps_removed) { - PRINTF("Cowardly refusing to keep going after removing %d maps.\n", + PRINTF("Cowardly refusing to keep going after removing %d maps.\n"_fmt, maps_removed); return false; } @@ -1346,7 +1352,7 @@ bool map_readallmap(void) static void map_addmap(MapName mapname) { - if (mapname == "clear") + if (mapname == "clear"_s) { maps_db.clear(); return; @@ -1366,7 +1372,7 @@ void map_addmap(MapName mapname) */ void map_delmap(MapName mapname) { - if (mapname == "all") + if (mapname == "all"_s) { maps_db.clear(); return; @@ -1389,13 +1395,13 @@ void map_close_logfile(void) { if (map_logfile) { - AString filename = STRPRINTF("%s.%ld", map_logfile_name, map_logfile_index); + AString filename = STRPRINTF("%s.%ld"_fmt, map_logfile_name, map_logfile_index); const char *args[] = { "gzip", "-f", filename.c_str(), - NULL + nullptr }; char **argv = const_cast<char **>(args); @@ -1406,7 +1412,7 @@ void map_close_logfile(void) execvp("gzip", argv); _exit(1); } - wait(NULL); + wait(nullptr); } } @@ -1416,7 +1422,7 @@ void map_start_logfile(long index) map_logfile_index = index; AString filename_buf = STRPRINTF( - "%s.%ld", + "%s.%ld"_fmt, map_logfile_name, map_logfile_index); map_logfile = make_unique<io::AppendFile>(filename_buf); @@ -1433,11 +1439,11 @@ void map_set_logfile(AString filename) struct timeval tv; map_logfile_name = std::move(filename); - gettimeofday(&tv, NULL); + gettimeofday(&tv, nullptr); map_start_logfile(tv.tv_sec >> LOGFILE_SECONDS_PER_CHUNK_SHIFT); - MAP_LOG("log-start v5"); + MAP_LOG("log-start v5"_fmt); } void map_log(XString line) @@ -1464,12 +1470,12 @@ void map_log(XString line) static bool map_config_read(ZString cfgName) { - struct hostent *h = NULL; + struct hostent *h = nullptr; io::ReadFile in(cfgName); if (!in.is_open()) { - PRINTF("Map configuration file not found at: %s\n", cfgName); + PRINTF("Map configuration file not found at: %s\n"_fmt, cfgName); return false; } @@ -1483,25 +1489,25 @@ bool map_config_read(ZString cfgName) ZString w2; if (!config_split(line, &w1, &w2)) { - PRINTF("Bad config line: %s\n", line); + PRINTF("Bad config line: %s\n"_fmt, line); rv = false; continue; } - if (w1 == "userid") + if (w1 == "userid"_s) { AccountName name = stringish<AccountName>(w2); chrif_setuserid(name); } - else if (w1 == "passwd") + else if (w1 == "passwd"_s) { AccountPass pass = stringish<AccountPass>(w2); chrif_setpasswd(pass); } - else if (w1 == "char_ip") + else if (w1 == "char_ip"_s) { h = gethostbyname(w2.c_str()); IP4Address w2ip; - if (h != NULL) + if (h != nullptr) { w2ip = IP4Address({ static_cast<uint8_t>(h->h_addr[0]), @@ -1509,25 +1515,25 @@ bool map_config_read(ZString cfgName) static_cast<uint8_t>(h->h_addr[2]), static_cast<uint8_t>(h->h_addr[3]), }); - PRINTF("Character server IP address : %s -> %s\n", + PRINTF("Character server IP address : %s -> %s\n"_fmt, w2, w2ip); } else { - PRINTF("Bad IP value: %s\n", line); + PRINTF("Bad IP value: %s\n"_fmt, line); return false; } chrif_setip(w2ip); } - else if (w1 == "char_port") + else if (w1 == "char_port"_s) { chrif_setport(atoi(w2.c_str())); } - else if (w1 == "map_ip") + else if (w1 == "map_ip"_s) { h = gethostbyname(w2.c_str()); IP4Address w2ip; - if (h != NULL) + if (h != nullptr) { w2ip = IP4Address({ static_cast<uint8_t>(h->h_addr[0]), @@ -1535,61 +1541,61 @@ bool map_config_read(ZString cfgName) static_cast<uint8_t>(h->h_addr[2]), static_cast<uint8_t>(h->h_addr[3]), }); - PRINTF("Map server IP address : %s -> %s\n", + PRINTF("Map server IP address : %s -> %s\n"_fmt, w2, w2ip); } else { - PRINTF("Bad IP value: %s\n", line); + PRINTF("Bad IP value: %s\n"_fmt, line); return false; } clif_setip(w2ip); } - else if (w1 == "map_port") + else if (w1 == "map_port"_s) { clif_setport(atoi(w2.c_str())); } - else if (w1 == "map") + else if (w1 == "map"_s) { MapName name = VString<15>(w2); map_addmap(name); } - else if (w1 == "delmap") + else if (w1 == "delmap"_s) { MapName name = VString<15>(w2); map_delmap(name); } - else if (w1 == "npc") + else if (w1 == "npc"_s) { npc_addsrcfile(w2); } - else if (w1 == "delnpc") + else if (w1 == "delnpc"_s) { npc_delsrcfile(w2); } - else if (w1 == "autosave_time") + else if (w1 == "autosave_time"_s) { autosave_time = std::chrono::seconds(atoi(w2.c_str())); if (autosave_time <= interval_t::zero()) autosave_time = DEFAULT_AUTOSAVE_INTERVAL; } - else if (w1 == "motd_txt") + else if (w1 == "motd_txt"_s) { motd_txt = w2; } - else if (w1 == "mapreg_txt") + else if (w1 == "mapreg_txt"_s) { mapreg_txt = w2; } - else if (w1 == "gm_log") + else if (w1 == "gm_log"_s) { gm_log = std::move(w2); } - else if (w1 == "log_file") + else if (w1 == "log_file"_s) { map_set_logfile(w2); } - else if (w1 == "import") + else if (w1 == "import"_s) { rv &= map_config_read(w2); } @@ -1618,7 +1624,7 @@ void cleanup_sub(dumb_ptr<block_list> bl) map_clearflooritem(bl->bl_id); break; case BL::SPELL: - spell_free_invocation(bl->is_spell()); + magic::spell_free_invocation(bl->is_spell()); break; } } @@ -1656,7 +1662,7 @@ void term_func(void) map_close_logfile(); } -int compare_item(struct item *a, struct item *b) +int compare_item(Item *a, Item *b) { return (a->nameid == b->nameid); } @@ -1664,29 +1670,29 @@ int compare_item(struct item *a, struct item *b) static bool map_confs(XString key, ZString value) { - if (key == "map_conf") + if (key == "map_conf"_s) return map_config_read(value); - if (key == "battle_conf") + if (key == "battle_conf"_s) return battle_config_read(value); - if (key == "atcommand_conf") + if (key == "atcommand_conf"_s) return atcommand_config_read(value); - if (key == "item_db") + if (key == "item_db"_s) return itemdb_readdb(value); - if (key == "mob_db") + if (key == "mob_db"_s) return mob_readdb(value); - if (key == "mob_skill_db") + if (key == "mob_skill_db"_s) return mob_readskilldb(value); - if (key == "skill_db") + if (key == "skill_db"_s) return skill_readdb(value); - if (key == "magic_conf") - return load_magic_file_v2(value); + if (key == "magic_conf"_s) + return magic::load_magic_file_v2(value); - if (key == "resnametable") + if (key == "resnametable"_s) return load_resnametable(value); - if (key == "const_db") + if (key == "const_db"_s) return read_constdb(value); - PRINTF("unknown map conf key: %s\n", AString(key)); + PRINTF("unknown map conf key: %s\n"_fmt, AString(key)); return false; } @@ -1697,7 +1703,7 @@ bool map_confs(XString key, ZString value) int do_init(Slice<ZString> argv) { ZString argv0 = argv.pop_front(); - runflag &= magic_init0(); + runflag &= magic::magic_init0(); bool loaded_config_yet = false; while (argv) @@ -1705,22 +1711,22 @@ int do_init(Slice<ZString> argv) ZString argvi = argv.pop_front(); if (argvi.startswith('-')) { - if (argvi == "--help") + if (argvi == "--help"_s) { - PRINTF("Usage: %s [--help] [--version] [--write_atcommand_config outfile] [files...]\n", + PRINTF("Usage: %s [--help] [--version] [--write_atcommand_config outfile] [files...]\n"_fmt, argv0); exit(0); } - else if (argvi == "--version") + else if (argvi == "--version"_s) { - PRINTF("%s\n", CURRENT_VERSION_STRING); + PRINTF("%s\n"_fmt, CURRENT_VERSION_STRING); exit(0); } - else if (argvi == "--write-atcommand-config") + else if (argvi == "--write-atcommand-config"_s) { if (!argv) { - PRINTF("Missing argument\n"); + PRINTF("Missing argument\n"_fmt); exit(1); } ZString filename = argv.pop_front(); @@ -1729,7 +1735,7 @@ int do_init(Slice<ZString> argv) } else { - FPRINTF(stderr, "Unknown argument: %s\n", argvi); + FPRINTF(stderr, "Unknown argument: %s\n"_fmt, argvi); runflag = false; } } @@ -1741,7 +1747,7 @@ int do_init(Slice<ZString> argv) } if (!loaded_config_yet) - runflag &= load_config_file("conf/tmwa-map.conf", map_confs); + runflag &= load_config_file("conf/tmwa-map.conf"_s, map_confs); battle_config_check(); runflag &= map_readallmap(); @@ -1758,15 +1764,15 @@ int do_init(Slice<ZString> argv) npc_event_do_oninit(); // npcのOnInitイベント実行 if (battle_config.pk_mode == 1) - PRINTF("The server is running in " SGR_BOLD SGR_RED "PK Mode" SGR_RESET "\n"); + PRINTF("The server is running in " SGR_BOLD SGR_RED "PK Mode" SGR_RESET "\n"_fmt); - PRINTF("The map-server is " SGR_BOLD SGR_GREEN "ready" SGR_RESET " (Server is listening on the port %d).\n\n", + PRINTF("The map-server is " SGR_BOLD SGR_GREEN "ready" SGR_RESET " (Server is listening on the port %d).\n\n"_fmt, clif_getport()); return 0; } -int map_scriptcont(dumb_ptr<map_session_data> sd, int id) +int map_scriptcont(dumb_ptr<map_session_data> sd, BlockId id) { dumb_ptr<block_list> bl = map_id2bl(id); @@ -1778,9 +1784,10 @@ int map_scriptcont(dumb_ptr<map_session_data> sd, int id) case BL::NPC: return npc_scriptcont(sd, id); case BL::SPELL: - spell_execute_script(bl->is_spell()); + magic::spell_execute_script(bl->is_spell()); break; } return 0; } +} // namespace tmwa diff --git a/src/map/map.hpp b/src/map/map.hpp index 0cec5e8..55f4823 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_MAP_HPP -#define TMWA_MAP_MAP_HPP +#pragma once // map.hpp - Core of the map server. // // Copyright © ????-2004 Athena Dev Teams @@ -21,48 +20,53 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "map.t.hpp" +#include "map.t.hpp" -# include <netinet/in.h> +#include <chrono> +#include <functional> +#include <list> -# include <functional> -# include <list> +#include "../ints/udl.hpp" -# include "../strings/fwd.hpp" -# include "../strings/rstring.hpp" -# include "../strings/astring.hpp" -# include "../strings/vstring.hpp" +#include "../strings/fwd.hpp" +#include "../strings/rstring.hpp" +#include "../strings/astring.hpp" +#include "../strings/vstring.hpp" -# include "../generic/db.hpp" -# include "../generic/matrix.hpp" +#include "../generic/db.hpp" +#include "../generic/dumb_ptr.hpp" +#include "../generic/matrix.hpp" -# include "../io/cxxstdio.hpp" +#include "../net/socket.hpp" +#include "../net/timer.t.hpp" -# include "../mmo/socket.hpp" -# include "../mmo/timer.t.hpp" +#include "../mmo/utils.hpp" -# include "battle.t.hpp" -# include "magic-interpreter.t.hpp" -# include "mapflag.hpp" -# include "mob.t.hpp" -# include "script.hpp" // change to script.t.hpp -# include "skill.t.hpp" +#include "battle.t.hpp" +#include "clif.t.hpp" +#include "mapflag.hpp" +#include "mob.t.hpp" +#include "script.hpp" // change to script.t.hpp +#include "skill.t.hpp" + +namespace tmwa +{ constexpr int MAX_NPC_PER_MAP = 512; constexpr int BLOCK_SIZE = 8; -# define AREA_SIZE battle_config.area_size -constexpr std::chrono::seconds LIFETIME_FLOORITEM = std::chrono::minutes(1); +#define AREA_SIZE battle_config.area_size +constexpr std::chrono::seconds LIFETIME_FLOORITEM = 1_min; constexpr int MAX_SKILL_LEVEL = 100; constexpr int MAX_EVENTTIMER = 32; -constexpr interval_t NATURAL_HEAL_INTERVAL = std::chrono::milliseconds(500); -constexpr int MAX_FLOORITEM = 500000; +constexpr interval_t NATURAL_HEAL_INTERVAL = 500_ms; +constexpr BlockId MAX_FLOORITEM = wrap<BlockId>(500000_u32); constexpr int MAX_LEVEL = 255; constexpr int MAX_WALKPATH = 48; constexpr int MAX_DROP_PER_MAP = 48; -constexpr interval_t DEFAULT_AUTOSAVE_INTERVAL = std::chrono::minutes(1); +constexpr interval_t DEFAULT_AUTOSAVE_INTERVAL = 1_min; // formerly VString<49>, as name::label struct NpcEvent @@ -89,24 +93,14 @@ struct NpcEvent return l.npc < r.npc || (l.npc == r.npc && l.label < r.label); } - friend VString<49> convert_for_printf(NpcEvent ev) - { - return STRNPRINTF(50, "%s::%s", ev.npc, ev.label); - } + friend VString<49> convert_for_printf(NpcEvent ev); }; bool extract(XString str, NpcEvent *ev); -struct map_session_data; -struct npc_data; -struct mob_data; -struct flooritem_data; -struct invocation; -struct map_local; - struct block_list { dumb_ptr<block_list> bl_next, bl_prev; - int bl_id; + BlockId bl_id; map_local *bl_m; short bl_x, bl_y; BL bl_type; @@ -123,13 +117,13 @@ private: dumb_ptr<npc_data> as_npc(); dumb_ptr<mob_data> as_mob(); dumb_ptr<flooritem_data> as_item(); - dumb_ptr<invocation> as_spell(); + 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<invocation> is_spell(); + dumb_ptr<magic::invocation> is_spell(); }; struct walkpath_data @@ -141,14 +135,9 @@ struct status_change { Timer timer; int val1; - int spell_invocation; /* [Fate] If triggered by a spell, record here */ + BlockId spell_invocation; /* [Fate] If triggered by a spell, record here */ }; -struct invocation; - -struct npc_data; -struct item_data; - struct quick_regeneration { // [Fate] int amount; // Amount of HP/SP left to regenerate @@ -190,13 +179,14 @@ struct map_session_data : block_list, SessionData unsigned unbreakable_armor:1; unsigned deaf:1; } special_state; - int char_id, login_id1, login_id2; + CharId char_id_; + int login_id1, login_id2; SEX sex; unsigned char tmw_version; // tmw client version CharKey status_key; CharData status; - Array<struct item_data *, MAX_INVENTORY> inventory_data; - earray<short, EQUIP, EQUIP::COUNT> equip_index_maybe; + GenericArray<struct item_data *, InventoryIndexing<IOff0, MAX_INVENTORY>> inventory_data; + earray<IOff0, EQUIP, EQUIP::COUNT> equip_index_maybe; int weight, max_weight; MapName mapname_; Session *sess; // use this, you idiots! @@ -206,10 +196,9 @@ struct map_session_data : block_list, SessionData Opt2 opt2; Opt3 opt3; DIR dir, head_dir; - tick_t client_tick, server_tick; struct walkpath_data walkpath; Timer walktimer; - int npc_id, areanpc_id, npc_shopid; + BlockId npc_id, areanpc_id, npc_shopid; // this is important int npc_pos; int npc_menu; @@ -226,20 +215,20 @@ struct map_session_data : block_list, SessionData } npc_flags; Timer attacktimer; - int attacktarget; + BlockId attacktarget; ATK attacktarget_lv; tick_t attackabletime; // used by @hugo and @linus - int followtarget; + BlockId followtarget; tick_t cast_tick; // [Fate] Next tick at which spellcasting is allowed - dumb_ptr<invocation> active_spells; // [Fate] Singly-linked list of active spells linked to this PC - int attack_spell_override; // [Fate] When an attack spell is active for this player, they trigger it + dumb_ptr<magic::invocation> active_spells; // [Fate] Singly-linked list of active spells linked to this PC + BlockId attack_spell_override; // [Fate] When an attack spell is active for this player, they trigger it // like a weapon. Check pc_attack_timer() for details. // Weapon equipment slot (slot 4) item override StatusChange attack_spell_icon_override; - short attack_spell_look_override; // Weapon `look' (attack animation) override + ItemNameId attack_spell_look_override; // Weapon `look' (attack animation) override short attack_spell_charges; // [Fate] Remaining number of charges for the attack spell interval_t attack_spell_delay; // [Fate] ms delay after spell attack short attack_spell_range; // [Fate] spell range @@ -296,16 +285,18 @@ struct map_session_data : block_list, SessionData earray<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; short sc_count; - int trade_partner; - Array<int, TRADE_MAX> deal_item_index; + AccountId trade_partner; + Array<IOff2, TRADE_MAX> deal_item_index; Array<int, TRADE_MAX> deal_item_amount; int deal_zeny; short deal_locked; - int party_sended, party_invite, party_invite_account; + int party_sended; + PartyId party_invite; + AccountId party_invite_account; int party_hp, party_x, party_y; - int partyspy; // [Syrus22] + PartyId partyspy; // [Syrus22] int catch_target_class; @@ -349,18 +340,15 @@ struct npc_label_list }; struct npc_item_list { - int nameid, value; + ItemNameId nameid; + int value; }; -class npc_data_script; -class npc_data_shop; -class npc_data_warp; -class npc_data_message; struct npc_data : block_list { NpcSubtype npc_subtype; short n; - short npc_class; + Species npc_class; DIR dir; interval_t speed; NpcName name; @@ -446,7 +434,7 @@ constexpr int MOB_XP_BONUS_SHIFT = 10; struct mob_data : block_list { short n; - short mob_class; + Species mob_class; DIR dir; MobMode mode; struct @@ -472,7 +460,7 @@ struct mob_data : block_list Timer timer; short to_x, to_y; int hp; - int target_id, attacked_id; + BlockId target_id, attacked_id; ATK target_lv; struct walkpath_data walkpath; tick_t next_walktime; @@ -482,12 +470,12 @@ struct mob_data : block_list short move_fail_count; struct DmgLogEntry { - int id; + BlockId id; int dmg; }; // logically a map ... std::vector<DmgLogEntry> dmglogv; - std::vector<struct item> lootitemv; + std::vector<Item> lootitemv; earray<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; short sc_count; @@ -499,14 +487,15 @@ struct mob_data : block_list Timer deletetimer; Timer skilltimer; - int skilltarget; + BlockId skilltarget; short skillx, skilly; SkillID skillid; short skilllv; struct mob_skill *skillidx; std::unique_ptr<tick_t[]> skilldelayup; // [MAX_MOBSKILL]; LevelElement def_ele; - int master_id, master_dist; + BlockId master_id; + int master_dist; int exclusion_src, exclusion_party; NpcEvent npc_event; // [Fate] mob-specific stats @@ -522,7 +511,7 @@ struct BlockLists struct map_abstract { MapName name_; - // gat is NULL for map_remote and non-NULL or map_local + // gat is nullptr for map_remote and non-nullptr or map_local std::unique_ptr<MapCell[]> gat; virtual ~map_abstract() {} @@ -537,8 +526,8 @@ struct map_local : map_abstract int npc_num; int users; MapFlags flag; - struct point save; - struct point resave; + Point save; + Point resave; Array<dumb_ptr<npc_data>, MAX_NPC_PER_MAP> npc; }; @@ -560,9 +549,9 @@ struct flooritem_data : block_list { short subx, suby; Timer cleartimer; - int first_get_id, second_get_id, third_get_id; + BlockId first_get_id, second_get_id, third_get_id; tick_t first_get_tick, second_get_tick, third_get_tick; - struct item item_data; + Item item_data; }; extern interval_t autosave_time; @@ -607,9 +596,9 @@ void map_foreachinmovearea(std::function<void(dumb_ptr<block_list>)>, //block関連に追加 int map_count_oncell(map_local *m, int x, int y); // 一時的object関連 -int map_addobject(dumb_ptr<block_list>); -int map_delobject(int, BL type); -int map_delobjectnofree(int id, BL type); +BlockId map_addobject(dumb_ptr<block_list>); +void map_delobject(BlockId, BL type); +void map_delobjectnofree(BlockId id, BL type); void map_foreachobject(std::function<void(dumb_ptr<block_list>)>, BL); // @@ -618,64 +607,64 @@ void map_quit(dumb_ptr<map_session_data>); int map_addnpc(map_local *, dumb_ptr<npc_data>); void map_log(XString line); -# define MAP_LOG(format, ...) \ +#define MAP_LOG(format, ...) \ map_log(STRPRINTF(format, ## __VA_ARGS__)) -# define MAP_LOG_PC(sd, fmt, ...) \ +#define MAP_LOG_PC(sd, fmt, ...) \ MAP_LOG("PC%d %s:%d,%d " fmt, \ - sd->status_key.char_id, (sd->bl_m ? sd->bl_m->name_ : stringish<MapName>("undefined.gat")), sd->bl_x, sd->bl_y, ## __VA_ARGS__) + sd->status_key.char_id, (sd->bl_m ? sd->bl_m->name_ : stringish<MapName>("undefined.gat"_s)), sd->bl_x, sd->bl_y, ## __VA_ARGS__) // 床アイテム関連 -void map_clearflooritem_timer(TimerData *, tick_t, int); +void map_clearflooritem_timer(TimerData *, tick_t, BlockId); inline -void map_clearflooritem(int id) +void map_clearflooritem(BlockId id) { map_clearflooritem_timer(nullptr, tick_t(), id); } -int map_addflooritem_any(struct item *, int amount, +BlockId map_addflooritem_any(Item *, int amount, map_local *m, int x, int y, dumb_ptr<map_session_data> *owners, interval_t *owner_protection, interval_t lifetime, int dispersal); -int map_addflooritem(struct item *, int, +BlockId map_addflooritem(Item *, int, map_local *, int, int, dumb_ptr<map_session_data>, dumb_ptr<map_session_data>, dumb_ptr<map_session_data>); // キャラid=>キャラ名 変換関連 extern -DMap<int, dumb_ptr<block_list>> id_db; -void map_addchariddb(int charid, CharName name); -CharName map_charid2nick(int); +DMap<BlockId, dumb_ptr<block_list>> id_db; +void map_addchariddb(CharId charid, CharName name); +CharName map_charid2nick(CharId); -dumb_ptr<map_session_data> map_id2sd(int); -dumb_ptr<block_list> map_id2bl(int); +dumb_ptr<map_session_data> map_id2sd(BlockId); +dumb_ptr<block_list> map_id2bl(BlockId); inline -dumb_ptr<map_session_data> map_id_is_player(int id) +dumb_ptr<map_session_data> map_id_is_player(BlockId id) { dumb_ptr<block_list> bl = map_id2bl(id); return bl ? bl->is_player() : nullptr; } inline -dumb_ptr<npc_data> map_id_is_npc(int id) +dumb_ptr<npc_data> map_id_is_npc(BlockId id) { dumb_ptr<block_list> bl = map_id2bl(id); return bl ? bl->is_npc() : nullptr; } inline -dumb_ptr<mob_data> map_id_is_mob(int id) +dumb_ptr<mob_data> map_id_is_mob(BlockId id) { dumb_ptr<block_list> bl = map_id2bl(id); return bl ? bl->is_mob() : nullptr; } inline -dumb_ptr<flooritem_data> map_id_is_item(int id) +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<invocation> map_id_is_spell(int id) +dumb_ptr<magic::invocation> map_id_is_spell(BlockId id) { dumb_ptr<block_list> bl = map_id2bl(id); return bl ? bl->is_spell() : nullptr; @@ -688,9 +677,9 @@ int map_setipport(MapName name, IP4Address ip, int port); void map_addiddb(dumb_ptr<block_list>); void map_deliddb(dumb_ptr<block_list> bl); void map_addnickdb(dumb_ptr<map_session_data>); -int map_scriptcont(dumb_ptr<map_session_data> sd, int id); /* Continues a script either on a spell or on an NPC */ +int map_scriptcont(dumb_ptr<map_session_data> sd, BlockId id); /* Continues a script either on a spell or on an NPC */ dumb_ptr<map_session_data> map_nick2sd(CharName); -int compare_item(struct item *a, struct item *b); +int compare_item(Item *a, Item *b); dumb_ptr<map_session_data> map_get_first_session(void); dumb_ptr<map_session_data> map_get_last_session(void); @@ -733,5 +722,4 @@ inline dumb_ptr<npc_data_script> npc_data::is_script() { return npc_subtype == N inline dumb_ptr<npc_data_shop> npc_data::is_shop() { return npc_subtype == NpcSubtype::SHOP ? as_shop() : nullptr ; } inline dumb_ptr<npc_data_warp> npc_data::is_warp() { return npc_subtype == NpcSubtype::WARP ? as_warp() : nullptr ; } inline dumb_ptr<npc_data_message> npc_data::is_message() { return npc_subtype == NpcSubtype::MESSAGE ? as_message() : nullptr ; } - -#endif // TMWA_MAP_MAP_HPP +} // namespace tmwa diff --git a/src/map/map.t.hpp b/src/map/map.t.hpp index b73cbdd..b475f9b 100644 --- a/src/map/map.t.hpp +++ b/src/map/map.t.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_MAP_T_HPP -#define TMWA_MAP_MAP_T_HPP +#pragma once // map.t.hpp - Core of the map server. // // Copyright © ????-2004 Athena Dev Teams @@ -21,73 +20,20 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "../strings/vstring.hpp" +#include <cstdint> -# include "../mmo/mmo.hpp" +#include "../strings/vstring.hpp" -namespace e -{ -// [Fate] status.option properties. These are persistent status changes. -// IDs that are not listed are not used in the code (to the best of my knowledge) -enum class Option : uint16_t -{ - ZERO = 0x0000, +#include "../generic/enum.hpp" - // [Fate] This is the GM `@hide' flag - HIDE = 0x0040, - // [Fate] Complete invisibility to other clients - INVISIBILITY = 0x1000, +#include "../mmo/ids.hpp" +#include "../mmo/mmo.hpp" - // ? - REAL_ANY_HIDE = HIDE, -}; -enum class Opt1 : uint16_t -{ - ZERO = 0, - _stone1 = 1, - _freeze = 2, - _stan = 3, - _sleep = 4, - _stone6 = 6, -}; -enum class Opt2 : uint16_t -{ - ZERO = 0x0000, - _poison = 0x0001, - _curse = 0x0002, - _silence = 0x0004, - BLIND = 0x0010, - _speedpotion0 = 0x0020, - _signumcrucis = 0x0040, - _atkpot = 0x0080, - _heal = 0x0100, - _slowpoison = 0x0200, -}; -enum class Opt3 : uint16_t -{ - ZERO = 0x0000, - _concentration = 0x0001, - _overthrust = 0x0002, - _energycoat = 0x0004, - _explosionspirits = 0x0008, - _steelbody = 0x0010, - _berserk = 0x0080, - - _marionette = 0x0400, - _assumptio = 0x0800, -}; - -ENUM_BITWISE_OPERATORS(Option) -ENUM_BITWISE_OPERATORS(Opt2) -ENUM_BITWISE_OPERATORS(Opt3) -} -using e::Option; -using e::Opt1; -using e::Opt2; -using e::Opt3; +namespace tmwa +{ enum class BL : uint8_t { NUL, @@ -103,6 +49,8 @@ enum class NpcSubtype : uint8_t SHOP, SCRIPT, MESSAGE, + + COUNT, }; enum class mob_stat @@ -146,325 +94,6 @@ enum class ATK DEF, }; -enum class SP : uint16_t -{ - // sent to client - SPEED = 0, - - // when used as "no stat" - ZERO = 0, - - // sent to client - BASEEXP = 1, - // sent to client - JOBEXP = 2, -# if 0 - KARMA = 3, -# endif - - // sent to client - HP = 5, - // sent to client - MAXHP = 6, - // sent to client - SP = 7, - // sent to client - MAXSP = 8, - // sent to client - STATUSPOINT = 9, - - // sent to client - BASELEVEL = 11, - // sent to client - SKILLPOINT = 12, - // sent to client - STR = 13, - // sent to client - AGI = 14, - // sent to client - VIT = 15, - // sent to client - INT = 16, - // sent to client - DEX = 17, - // sent to client - LUK = 18, - CLASS = 19, - // sent to client - ZENY = 20, - SEX = 21, - // sent to client - NEXTBASEEXP = 22, - // sent to client - NEXTJOBEXP = 23, - // sent to client - WEIGHT = 24, - // sent to client - MAXWEIGHT = 25, - - // sent to client - USTR = 32, - // sent to client - UAGI = 33, - // sent to client - UVIT = 34, - // sent to client - UINT = 35, - // sent to client - UDEX = 36, - // sent to client - ULUK = 37, - - // sent to client - ATK1 = 41, - // sent to client - ATK2 = 42, - // sent to client - MATK1 = 43, - // sent to client - MATK2 = 44, - // sent to client - DEF1 = 45, - // sent to client - DEF2 = 46, - // sent to client - MDEF1 = 47, - // sent to client - MDEF2 = 48, - // sent to client - HIT = 49, - // sent to client - FLEE1 = 50, - // sent to client - FLEE2 = 51, - // sent to client - CRITICAL = 52, - // sent to client - ASPD = 53, - - // sent to client - JOBLEVEL = 55, - -# if 0 - PARTNER = 57, - CART = 58, - FAME = 59, - UNBREAKABLE = 60, -# endif - - DEAF = 70, - - // sent to client - GM = 500, - - // sent to client - ATTACKRANGE = 1000, -# if 0 - ATKELE = 1001, -# endif -# if 0 - DEFELE = 1002, -# endif -# if 0 - CASTRATE = 1003, -# endif - MAXHPRATE = 1004, -# if 0 - MAXSPRATE = 1005, -# endif -# if 0 - SPRATE = 1006, -# endif - -# if 0 - ADDEFF = 1012, -# endif -# if 0 - RESEFF = 1013, -# endif - BASE_ATK = 1014, - ASPD_RATE = 1015, - HP_RECOV_RATE = 1016, -# if 0 - SP_RECOV_RATE = 1017, -# endif -# if 0 - SPEED_RATE = 1018, -# endif - CRITICAL_DEF = 1019, -# if 0 - NEAR_ATK_DEF = 1020, -# endif -# if 0 - LONG_ATK_DEF = 1021, -# endif -# if 0 - DOUBLE_RATE = 1022, -# endif - DOUBLE_ADD_RATE = 1023, -# if 0 - MATK = 1024, -# endif -# if 0 - MATK_RATE = 1025, -# endif -# if 0 - IGNORE_DEF_ELE = 1026, -# endif -# if 0 - IGNORE_DEF_RACE = 1027, -# endif -# if 0 - ATK_RATE = 1028, -# endif - SPEED_ADDRATE = 1029, -# if 0 - ASPD_ADDRATE = 1030, -# endif -# if 0 - MAGIC_ATK_DEF = 1031, -# endif -# if 0 - MISC_ATK_DEF = 1032, -# endif -# if 0 - IGNORE_MDEF_ELE = 1033, -# endif -# if 0 - IGNORE_MDEF_RACE = 1034, -# endif - -# if 0 - PERFECT_HIT_RATE = 1038, -# endif -# if 0 - PERFECT_HIT_ADD_RATE = 1039, -# endif -# if 0 - CRITICAL_RATE = 1040, -# endif -# if 0 - GET_ZENY_NUM = 1041, -# endif -# if 0 - ADD_GET_ZENY_NUM = 1042, -# endif - -# if 0 - ADD_MONSTER_DROP_ITEM = 1047, -# endif -# if 0 - DEF_RATIO_ATK_ELE = 1048, -# endif -# if 0 - DEF_RATIO_ATK_RACE = 1049, -# endif -# if 0 - ADD_SPEED = 1050, -# endif -# if 0 - HIT_RATE = 1051, -# endif -# if 0 - FLEE_RATE = 1052, -# endif -# if 0 - FLEE2_RATE = 1053, -# endif - DEF_RATE = 1054, - DEF2_RATE = 1055, -# if 0 - MDEF_RATE = 1056, -# endif -# if 0 - MDEF2_RATE = 1057, -# endif -# if 0 - SPLASH_RANGE = 1058, -# endif -# if 0 - SPLASH_ADD_RANGE = 1059, -# endif - - HP_DRAIN_RATE = 1061, -# if 0 - SP_DRAIN_RATE = 1062, -# endif -# if 0 - SHORT_WEAPON_DAMAGE_RETURN = 1063, -# endif -# if 0 - LONG_WEAPON_DAMAGE_RETURN = 1064, -# endif - -# if 0 - ADDEFF2 = 1067, -# endif - BREAK_WEAPON_RATE = 1068, - BREAK_ARMOR_RATE = 1069, - ADD_STEAL_RATE = 1070, - MAGIC_DAMAGE_RETURN = 1071, -# if 0 - RANDOM_ATTACK_INCREASE = 1072, -# endif -}; - -constexpr -SP attr_to_sp(ATTR attr) -{ - return SP(uint16_t(attr) + uint16_t(SP::STR)); -} - -constexpr -ATTR sp_to_attr(SP sp) -{ - return ATTR(uint16_t(sp) - uint16_t(SP::STR)); -} - -constexpr -SP attr_to_usp(ATTR attr) -{ - return SP(uint16_t(attr) + uint16_t(SP::USTR)); -} - -constexpr -ATTR usp_to_attr(SP sp) -{ - return ATTR(uint16_t(sp) - uint16_t(SP::USTR)); -} - -constexpr -SP sp_to_usp(SP sp) -{ - return attr_to_usp(sp_to_attr(sp)); -} - -constexpr -SP usp_to_sp(SP sp) -{ - return attr_to_sp(usp_to_attr(sp)); -} - - -enum class LOOK : uint8_t -{ - BASE = 0, - HAIR = 1, - WEAPON = 2, - HEAD_BOTTOM = 3, - HEAD_TOP = 4, - HEAD_MID = 5, - HAIR_COLOR = 6, - CLOTHES_COLOR = 7, - SHIELD = 8, - SHOES = 9, - GLOVES = 10, - CAPE = 11, - MISC1 = 12, - MISC2 = 13, - - COUNT, -}; enum class EQUIP { @@ -514,22 +143,6 @@ EQUIP EQUIPs_noarrow[] = EQUIP::WEAPON, }; -enum class ItemType : uint8_t -{ - USE = 0, // in eA, healing only - _1 = 1, // unused - _2 = 2, // in eA, other usable items - JUNK = 3, // "useless" items (e.g. quests) - WEAPON = 4, // all weapons - ARMOR = 5, // all other equipment - _6 = 6, // in eA, card - _7 = 7, // in eA, pet egg - _8 = 8, // in eA, pet equipment - _9 = 9, // unused - ARROW = 10, // ammo - _11 = 11, // in eA, delayed use (special script) -}; - namespace e { enum class MobMode : uint16_t @@ -583,4 +196,8 @@ struct NpcName : VString<23> {}; struct ScriptLabel : VString<23> {}; struct ItemName : VString<23> {}; -#endif // TMWA_MAP_MAP_T_HPP +inline +BlockId account_to_block(AccountId a) { return wrap<BlockId>(unwrap<AccountId>(a)); } +inline +AccountId block_to_account(BlockId b) { return wrap<AccountId>(unwrap<BlockId>(b)); } +} // namespace tmwa diff --git a/src/map/mapflag.cpp b/src/map/mapflag.cpp index 51af30a..be2ae67 100644 --- a/src/map/mapflag.cpp +++ b/src/map/mapflag.cpp @@ -20,6 +20,9 @@ #include "../poison.hpp" + +namespace tmwa +{ // because bitfields, that's why bool MapFlags::get(MapFlag mf) const @@ -35,46 +38,45 @@ void MapFlags::set(MapFlag mf, bool val) flags &=~ static_cast<unsigned>(mf); } -template<> -bool extract<MapFlag, void, void>(XString str, MapFlag *mf) +bool extract(XString str, MapFlag *mf) { const struct { - ZString str; + LString str; MapFlag id; } flags[] = { - //{ZString("alias"), MapFlag::ALIAS}, - //{ZString("nomemo"), MapFlag::NOMEMO}, - {ZString("noteleport"), MapFlag::NOTELEPORT}, - {ZString("noreturn"), MapFlag::NORETURN}, - {ZString("monster_noteleport"), MapFlag::MONSTER_NOTELEPORT}, - {ZString("nosave"), MapFlag::NOSAVE}, - //{ZString("nobranch"), MapFlag::NOBRANCH}, - {ZString("nopenalty"), MapFlag::NOPENALTY}, - {ZString("pvp"), MapFlag::PVP}, - {ZString("pvp_noparty"), MapFlag::PVP_NOPARTY}, - //{ZString("pvp_noguild"), MapFlag::PVP_NOGUILD}, - //{ZString("pvp_nightmaredrop"), MapFlag::PVP_NIGHTMAREDROP}, - {ZString("pvp_nocalcrank"), MapFlag::PVP_NOCALCRANK}, - //{ZString("gvg"), MapFlag::GVG}, - //{ZString("gvg_noparty"), MapFlag::GVG_NOPARTY}, - //{ZString("nozenypenalty"), MapFlag::NOZENYPENALTY}, - //{ZString("notrade"), MapFlag::NOTRADE}, - //{ZString("noskill"), MapFlag::NOSKILL}, - {ZString("nowarp"), MapFlag::NOWARP}, - {ZString("nowarpto"), MapFlag::NOWARPTO}, - {ZString("nopvp"), MapFlag::NOPVP}, - //{ZString("noicewall"), MapFlag::NOICEWALL}, - {ZString("snow"), MapFlag::SNOW}, - {ZString("fog"), MapFlag::FOG}, - {ZString("sakura"), MapFlag::SAKURA}, - {ZString("leaves"), MapFlag::LEAVES}, - {ZString("rain"), MapFlag::RAIN}, - {ZString("no_player_drops"), MapFlag::NO_PLAYER_DROPS}, - {ZString("town"), MapFlag::TOWN}, - {ZString("outside"), MapFlag::OUTSIDE}, - {ZString("resave"), MapFlag::RESAVE}, + //{"alias"_s, MapFlag::ALIAS}, + //{"nomemo"_s, MapFlag::NOMEMO}, + {"noteleport"_s, MapFlag::NOTELEPORT}, + {"noreturn"_s, MapFlag::NORETURN}, + {"monster_noteleport"_s, MapFlag::MONSTER_NOTELEPORT}, + {"nosave"_s, MapFlag::NOSAVE}, + //{"nobranch"_s, MapFlag::NOBRANCH}, + {"nopenalty"_s, MapFlag::NOPENALTY}, + {"pvp"_s, MapFlag::PVP}, + {"pvp_noparty"_s, MapFlag::PVP_NOPARTY}, + //{"pvp_noguild"_s, MapFlag::PVP_NOGUILD}, + //{"pvp_nightmaredrop"_s, MapFlag::PVP_NIGHTMAREDROP}, + {"pvp_nocalcrank"_s, MapFlag::PVP_NOCALCRANK}, + //{"gvg"_s, MapFlag::GVG}, + //{"gvg_noparty"_s, MapFlag::GVG_NOPARTY}, + //{"nozenypenalty"_s, MapFlag::NOZENYPENALTY}, + //{"notrade"_s, MapFlag::NOTRADE}, + //{"noskill"_s, MapFlag::NOSKILL}, + {"nowarp"_s, MapFlag::NOWARP}, + {"nowarpto"_s, MapFlag::NOWARPTO}, + {"nopvp"_s, MapFlag::NOPVP}, + //{"noicewall"_s, MapFlag::NOICEWALL}, + {"snow"_s, MapFlag::SNOW}, + {"fog"_s, MapFlag::FOG}, + {"sakura"_s, MapFlag::SAKURA}, + {"leaves"_s, MapFlag::LEAVES}, + {"rain"_s, MapFlag::RAIN}, + {"no_player_drops"_s, MapFlag::NO_PLAYER_DROPS}, + {"town"_s, MapFlag::TOWN}, + {"outside"_s, MapFlag::OUTSIDE}, + {"resave"_s, MapFlag::RESAVE}, }; for (auto& pair : flags) if (str == pair.str) @@ -89,3 +91,4 @@ MapFlag map_flag_from_int(int shift) { return static_cast<MapFlag>(1 << shift); } +} // namespace tmwa diff --git a/src/map/mapflag.hpp b/src/map/mapflag.hpp index e3a55f5..6d046fa 100644 --- a/src/map/mapflag.hpp +++ b/src/map/mapflag.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_MAPFLAG_HPP -#define TMWA_MAP_MAPFLAG_HPP +#pragma once // mapflag.hpp - booleans that apply to an entire map // // Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> @@ -19,12 +18,15 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "../mmo/extract.hpp" // TODO remove this (requires specializing the *other* half) +#include <cstdint> -# include "../strings/xstring.hpp" +#include "../mmo/extract.hpp" // TODO remove this (requires specializing the *other* half) + +namespace tmwa +{ // originally from script.cpp // These are part of the script API, so they can't change ever, // even though they are silly. @@ -75,9 +77,7 @@ public: void set(MapFlag, bool); }; -template<> -bool extract<MapFlag, void, void>(XString str, MapFlag *mf); +bool extract(XString str, MapFlag *mf); MapFlag map_flag_from_int(int shift); - -#endif // TMWA_MAP_MAPFLAG_HPP +} // namespace tmwa diff --git a/src/map/mapflag.py b/src/map/mapflag.py index 3bc9f1a..fec8c05 100644 --- a/src/map/mapflag.py +++ b/src/map/mapflag.py @@ -2,7 +2,7 @@ class MapFlags(object): ''' print a set of map flags ''' __slots__ = ('_value') - name = 'MapFlags' + name = 'tmwa::MapFlags' enabled = True def __init__(self, value): diff --git a/src/map/mob.cpp b/src/map/mob.cpp index a96f829..dd061d0 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -23,8 +23,6 @@ #include <cassert> #include <cmath> -#include <cstdlib> -#include <cstring> #include <algorithm> @@ -32,17 +30,21 @@ #include "../compat/nullpo.hpp" #include "../strings/astring.hpp" +#include "../strings/zstring.hpp" #include "../strings/xstring.hpp" #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" +#include "../io/cxxstdio_enums.hpp" #include "../io/read.hpp" +#include "../net/socket.hpp" +#include "../net/timer.hpp" + #include "../mmo/config_parse.hpp" #include "../mmo/extract.hpp" -#include "../mmo/socket.hpp" -#include "../mmo/timer.hpp" +#include "../mmo/extract_enums.hpp" #include "battle.hpp" #include "clif.hpp" @@ -56,14 +58,22 @@ #include "../poison.hpp" -constexpr interval_t MIN_MOBTHINKTIME = std::chrono::milliseconds(100); + +namespace tmwa +{ +constexpr interval_t MIN_MOBTHINKTIME = 100_ms; // Move probability in the negligent mode MOB (rate of 1000 minute) constexpr random_::Fraction MOB_LAZYMOVEPERC {50, 1000}; // Warp probability in the negligent mode MOB (rate of 1000 minute) constexpr random_::Fraction MOB_LAZYWARPPERC {20, 1000}; +static struct mob_db_ mob_db[2001]; +struct mob_db_& get_mob_db(Species s) +{ + return mob_db[unwrap<Species>(s)]; +} /*========================================== * Local prototype declaration (only required thing) @@ -72,9 +82,9 @@ struct mob_db_ mob_db[2001]; static int distance(int, int, int, int); static -int mob_makedummymobdb(int); +int mob_makedummymobdb(Species); static -void mob_timer(TimerData *, tick_t, int, unsigned char); +void mob_timer(TimerData *, tick_t, BlockId, unsigned char); static int mobskill_use_id(dumb_ptr<mob_data> md, dumb_ptr<block_list> target, mob_skill& skill_idx); @@ -83,30 +93,29 @@ int mobskill_use_id(dumb_ptr<mob_data> md, dumb_ptr<block_list> target, * Mob is searched with a name. *------------------------------------------ */ -int mobdb_searchname(MobName str) +Species mobdb_searchname(MobName str) { int i; for (i = 0; i < sizeof(mob_db) / sizeof(mob_db[0]); i++) { if (mob_db[i].name == str || mob_db[i].jname == str) - return i; + return wrap<Species>(i); } - return 0; + return Species(); } /*========================================== * Id Mob is checked. *------------------------------------------ */ -int mobdb_checkid(const int id) +Species mobdb_checkid(Species id) { - if (id <= 0 || id >= (sizeof(mob_db) / sizeof(mob_db[0])) - || !mob_db[id].name) - return 0; - - return id; + // value range is [1001, 2000] + if (wrap<Species>(1000) < id && id < wrap<Species>(2001)) + return id; + return Species(); } static @@ -117,27 +126,27 @@ void mob_init(dumb_ptr<mob_data> md); *------------------------------------------ */ static -void mob_spawn_dataset(dumb_ptr<mob_data> md, MobName mobname, int mob_class) +void mob_spawn_dataset(dumb_ptr<mob_data> md, MobName mobname, Species mob_class) { nullpo_retv(md); if (mobname == ENGLISH_NAME) - md->name = mob_db[mob_class].name; + md->name = get_mob_db(mob_class).name; else if (mobname == JAPANESE_NAME) - md->name = mob_db[mob_class].jname; + md->name = get_mob_db(mob_class).jname; else md->name = mobname; - md->bl_prev = NULL; - md->bl_next = NULL; + md->bl_prev = nullptr; + md->bl_next = nullptr; md->n = 0; md->mob_class = mob_class; md->bl_id = npc_get_new_npc_id(); really_memzero_this(&md->state); // md->timer = nullptr; - md->target_id = 0; - md->attacked_id = 0; + md->target_id = BlockId(); + md->attacked_id = BlockId(); mob_init(md); } @@ -265,12 +274,16 @@ void mob_mutate(dumb_ptr<mob_data> md, mob_stat stat, int intensity) int real_intensity2 = (((new_stat - old_stat) << 8) / mut_base); if (real_intensity < 0) + { if (real_intensity2 > real_intensity) real_intensity = real_intensity2; + } if (real_intensity > 0) + { if (real_intensity2 < real_intensity) real_intensity = real_intensity2; + } } real_intensity *= sign; @@ -322,7 +335,7 @@ int mob_gen_exp(mob_db_ *mob) * static_cast<double>(battle_config.base_exp_rate) / 100.); if (xp < 1) xp = 1; - PRINTF("Exp for mob '%s' generated: %d\n", mob->name, xp); + PRINTF("Exp for mob '%s' generated: %d\n"_fmt, mob->name, xp); return xp; } @@ -330,24 +343,24 @@ static void mob_init(dumb_ptr<mob_data> md) { int i; - const int mob_class = md->mob_class; - const int mutations_nr = mob_db[mob_class].mutations_nr; - const int mutation_power = mob_db[mob_class].mutation_power; - - md->stats[mob_stat::LV] = mob_db[mob_class].lv; - md->stats[mob_stat::MAX_HP] = mob_db[mob_class].max_hp; - md->stats[mob_stat::STR] = mob_db[mob_class].attrs[ATTR::STR]; - md->stats[mob_stat::AGI] = mob_db[mob_class].attrs[ATTR::AGI]; - md->stats[mob_stat::VIT] = mob_db[mob_class].attrs[ATTR::VIT]; - md->stats[mob_stat::INT] = mob_db[mob_class].attrs[ATTR::INT]; - md->stats[mob_stat::DEX] = mob_db[mob_class].attrs[ATTR::DEX]; - md->stats[mob_stat::LUK] = mob_db[mob_class].attrs[ATTR::LUK]; - md->stats[mob_stat::ATK1] = mob_db[mob_class].atk1; - md->stats[mob_stat::ATK2] = mob_db[mob_class].atk2; - md->stats[mob_stat::ADELAY] = mob_db[mob_class].adelay; - md->stats[mob_stat::DEF] = mob_db[mob_class].def; - md->stats[mob_stat::MDEF] = mob_db[mob_class].mdef; - md->stats[mob_stat::SPEED] = mob_db[mob_class].speed; + const Species mob_class = md->mob_class; + const int mutations_nr = get_mob_db(mob_class).mutations_nr; + const int mutation_power = get_mob_db(mob_class).mutation_power; + + md->stats[mob_stat::LV] = get_mob_db(mob_class).lv; + md->stats[mob_stat::MAX_HP] = get_mob_db(mob_class).max_hp; + md->stats[mob_stat::STR] = get_mob_db(mob_class).attrs[ATTR::STR]; + md->stats[mob_stat::AGI] = get_mob_db(mob_class).attrs[ATTR::AGI]; + md->stats[mob_stat::VIT] = get_mob_db(mob_class).attrs[ATTR::VIT]; + md->stats[mob_stat::INT] = get_mob_db(mob_class).attrs[ATTR::INT]; + md->stats[mob_stat::DEX] = get_mob_db(mob_class).attrs[ATTR::DEX]; + md->stats[mob_stat::LUK] = get_mob_db(mob_class).attrs[ATTR::LUK]; + md->stats[mob_stat::ATK1] = get_mob_db(mob_class).atk1; + md->stats[mob_stat::ATK2] = get_mob_db(mob_class).atk2; + md->stats[mob_stat::ADELAY] = get_mob_db(mob_class).adelay; + md->stats[mob_stat::DEF] = get_mob_db(mob_class).def; + md->stats[mob_stat::MDEF] = get_mob_db(mob_class).mdef; + md->stats[mob_stat::SPEED] = get_mob_db(mob_class).speed; md->stats[mob_stat::XP_BONUS] = MOB_XP_BONUS_BASE; for (i = 0; i < mutations_nr; i++) @@ -391,22 +404,22 @@ void mob_init(dumb_ptr<mob_data> md) * The MOB appearance for one time (for scripts) *------------------------------------------ */ -int mob_once_spawn(dumb_ptr<map_session_data> sd, +BlockId mob_once_spawn(dumb_ptr<map_session_data> sd, MapName mapname, int x, int y, - MobName mobname, int mob_class, int amount, + MobName mobname, Species mob_class, int amount, NpcEvent event) { - dumb_ptr<mob_data> md = NULL; + dumb_ptr<mob_data> md = nullptr; map_local *m; - int count, r = mob_class; + int count; if (sd && mapname == MOB_THIS_MAP) m = sd->bl_m; else m = map_mapname2mapid(mapname); - if (m == nullptr || amount <= 0 || (mob_class >= 0 && mob_class <= 1000) || mob_class > 2000) // 値が異常なら召喚を止める - return 0; + if (m == nullptr || amount <= 0 || mobdb_checkid(mob_class) == Species()) + return BlockId(); if (sd) { @@ -417,7 +430,7 @@ int mob_once_spawn(dumb_ptr<map_session_data> sd, } else if (x <= 0 || y <= 0) { - PRINTF("mob_once_spawn: ??\n"); + PRINTF("mob_once_spawn: ??\n"_fmt); } for (count = 0; count < amount; count++) @@ -429,9 +442,6 @@ int mob_once_spawn(dumb_ptr<map_session_data> sd, md->bl_m = m; md->bl_x = x; md->bl_y = y; - if (r < 0 && battle_config.dead_branch_active == 1) - //移動してアクティブで反撃する - md->mode = MobMode::war; md->spawn.m = m; md->spawn.x0 = x; md->spawn.y0 = y; @@ -446,19 +456,20 @@ int mob_once_spawn(dumb_ptr<map_session_data> sd, map_addiddb(md); mob_spawn(md->bl_id); } - return (amount > 0) ? md->bl_id : 0; + return (amount > 0) ? md->bl_id : BlockId(); } /*========================================== * The MOB appearance for one time (& area specification for scripts) *------------------------------------------ */ -int mob_once_spawn_area(dumb_ptr<map_session_data> sd, +BlockId mob_once_spawn_area(dumb_ptr<map_session_data> sd, MapName mapname, int x0, int y0, int x1, int y1, - MobName mobname, int mob_class, int amount, + MobName mobname, Species mob_class, int amount, NpcEvent event) { - int x, y, i, max, lx = -1, ly = -1, id = 0; + int x, y, i, max, lx = -1, ly = -1; + BlockId id; map_local *m; if (mapname == MOB_THIS_MAP) @@ -470,8 +481,8 @@ int mob_once_spawn_area(dumb_ptr<map_session_data> sd, if (max > 1000) max = 1000; - if (m == nullptr || amount <= 0 || (mob_class >= 0 && mob_class <= 1000) || mob_class > 2000) // A summon is stopped if a value is unusual - return 0; + if (m == nullptr || amount <= 0 || (mobdb_checkid(mob_class) == Species())) // A summon is stopped if a value is unusual + return BlockId(); for (i = 0; i < amount; i++) { @@ -491,7 +502,7 @@ int mob_once_spawn_area(dumb_ptr<map_session_data> sd, y = ly; } else - return 0; // Since reference of the place which boils first went wrong, it stops. + return BlockId(); // Since reference of the place which boils first went wrong, it stops. } id = mob_once_spawn(sd, mapname, x, y, mobname, mob_class, 1, event); lx = x; @@ -501,49 +512,49 @@ int mob_once_spawn_area(dumb_ptr<map_session_data> sd, } // TODO: deprecate these -short mob_get_hair(int mob_class) +short mob_get_hair(Species mob_class) { - return mob_db[mob_class].hair; + return get_mob_db(mob_class).hair; } -short mob_get_hair_color(int mob_class) +short mob_get_hair_color(Species mob_class) { - return mob_db[mob_class].hair_color; + return get_mob_db(mob_class).hair_color; } -short mob_get_weapon(int mob_class) +short mob_get_weapon(Species mob_class) { - return mob_db[mob_class].weapon; + return get_mob_db(mob_class).weapon; } -short mob_get_shield(int mob_class) +ItemNameId mob_get_shield(Species mob_class) { - return mob_db[mob_class].shield; + return get_mob_db(mob_class).shield; } -short mob_get_head_top(int mob_class) +ItemNameId mob_get_head_top(Species mob_class) { - return mob_db[mob_class].head_top; + return get_mob_db(mob_class).head_top; } -short mob_get_head_mid(int mob_class) +ItemNameId mob_get_head_mid(Species mob_class) { - return mob_db[mob_class].head_mid; + return get_mob_db(mob_class).head_mid; } -short mob_get_head_buttom(int mob_class) +ItemNameId mob_get_head_buttom(Species mob_class) { - return mob_db[mob_class].head_buttom; + return get_mob_db(mob_class).head_buttom; } -short mob_get_clothes_color(int mob_class) // Add for player monster dye - Valaris +short mob_get_clothes_color(Species mob_class) // Add for player monster dye - Valaris { - return mob_db[mob_class].clothes_color; // End + return get_mob_db(mob_class).clothes_color; // End } -int mob_get_equip(int mob_class) // mob equip [Valaris] +int mob_get_equip(Species mob_class) // mob equip [Valaris] { - return mob_db[mob_class].equip; + return get_mob_db(mob_class).equip; } /*========================================== @@ -553,7 +564,7 @@ int mob_get_equip(int mob_class) // mob equip [Valaris] static int mob_can_move(dumb_ptr<mob_data> md) { - nullpo_ret(md); + nullpo_retz(md); if (md->canmove_tick > gettick() || (bool(md->opt1) && md->opt1 != Opt1::_stone6)) @@ -591,7 +602,7 @@ int mob_walk(dumb_ptr<mob_data> md, tick_t tick, unsigned char data) int moveblock; int x, y, dx, dy; - nullpo_ret(md); + nullpo_retz(md); md->state.state = MS::IDLE; if (md->walkpath.path_pos >= md->walkpath.path_len @@ -667,7 +678,7 @@ int mob_walk(dumb_ptr<mob_data> md, tick_t tick, unsigned char data) { i = i / 2; if (md->walkpath.path_half == 0) - i = std::max(i, std::chrono::milliseconds(1)); + i = std::max(i, 1_ms); md->timer = Timer(tick + i, std::bind(mob_timer, ph::_1, ph::_2, md->bl_id, md->walkpath.path_pos)); @@ -686,14 +697,14 @@ int mob_walk(dumb_ptr<mob_data> md, tick_t tick, unsigned char data) static int mob_check_attack(dumb_ptr<mob_data> md) { - dumb_ptr<block_list> tbl = NULL; - dumb_ptr<map_session_data> tsd = NULL; - dumb_ptr<mob_data> tmd = NULL; + dumb_ptr<block_list> tbl = nullptr; + dumb_ptr<map_session_data> tsd = nullptr; + dumb_ptr<mob_data> tmd = nullptr; MobMode mode; int range; - nullpo_ret(md); + nullpo_retz(md); md->min_chase = 13; md->state.state = MS::IDLE; @@ -705,9 +716,9 @@ int mob_check_attack(dumb_ptr<mob_data> md) if (bool(md->opt1)) return 0; - if ((tbl = map_id2bl(md->target_id)) == NULL) + if ((tbl = map_id2bl(md->target_id)) == nullptr) { - md->target_id = 0; + md->target_id = BlockId(); md->state.attackable = false; return 0; } @@ -722,34 +733,34 @@ int mob_check_attack(dumb_ptr<mob_data> md) if (tsd) { if (pc_isdead(tsd) || tsd->invincible_timer - || pc_isinvisible(tsd) || md->bl_m != tbl->bl_m || tbl->bl_prev == NULL + || pc_isinvisible(tsd) || md->bl_m != tbl->bl_m || tbl->bl_prev == nullptr || distance(md->bl_x, md->bl_y, tbl->bl_x, tbl->bl_y) >= 13) { - md->target_id = 0; + md->target_id = BlockId(); md->state.attackable = false; return 0; } } if (tmd) { - if (md->bl_m != tbl->bl_m || tbl->bl_prev == NULL + if (md->bl_m != tbl->bl_m || tbl->bl_prev == nullptr || distance(md->bl_x, md->bl_y, tbl->bl_x, tbl->bl_y) >= 13) { - md->target_id = 0; + md->target_id = BlockId(); md->state.attackable = false; return 0; } } if (md->mode == MobMode::ZERO) - mode = mob_db[md->mob_class].mode; + mode = get_mob_db(md->mob_class).mode; else mode = md->mode; - Race race = mob_db[md->mob_class].race; + Race race = get_mob_db(md->mob_class).race; if (!bool(mode & MobMode::CAN_ATTACK)) { - md->target_id = 0; + md->target_id = BlockId(); md->state.attackable = false; return 0; } @@ -759,12 +770,12 @@ int mob_check_attack(dumb_ptr<mob_data> md) && race != Race::_insect && race != Race::_demon)) { - md->target_id = 0; + md->target_id = BlockId(); md->state.attackable = false; return 0; } - range = mob_db[md->mob_class].range; + range = get_mob_db(md->mob_class).range; if (bool(mode & MobMode::CAN_MOVE)) range++; if (distance(md->bl_x, md->bl_y, tbl->bl_x, tbl->bl_y) > range) @@ -788,11 +799,11 @@ void mob_ancillary_attack(dumb_ptr<block_list> bl, static int mob_attack(dumb_ptr<mob_data> md, tick_t tick) { - dumb_ptr<block_list> tbl = NULL; + dumb_ptr<block_list> tbl = nullptr; - nullpo_ret(md); + nullpo_retz(md); - if ((tbl = map_id2bl(md->target_id)) == NULL) + if ((tbl = map_id2bl(md->target_id)) == nullptr) return 0; if (!mob_check_attack(md)) @@ -834,7 +845,7 @@ int mob_attack(dumb_ptr<mob_data> md, tick_t tick) *------------------------------------------ */ static -void mob_stopattacked(dumb_ptr<map_session_data> sd, int id) +void mob_stopattacked(dumb_ptr<map_session_data> sd, BlockId id) { nullpo_retv(sd); @@ -849,7 +860,7 @@ void mob_stopattacked(dumb_ptr<map_session_data> sd, int id) static int mob_changestate(dumb_ptr<mob_data> md, MS state, bool type) { - nullpo_ret(md); + nullpo_retz(md); md->timer.cancel(); md->state.state = state; @@ -874,7 +885,7 @@ int mob_changestate(dumb_ptr<mob_data> md, MS state, bool type) { tick_t tick = gettick(); interval_t i = md->attackabletime - tick; - if (i > interval_t::zero() && i < std::chrono::seconds(2)) + if (i > interval_t::zero() && i < 2_s) md->timer = Timer(md->attackabletime, std::bind(mob_timer, ph::_1, ph::_2, md->bl_id, 0)); @@ -887,7 +898,7 @@ int mob_changestate(dumb_ptr<mob_data> md, MS state, bool type) } else { - md->attackabletime = tick + std::chrono::milliseconds(1); + md->attackabletime = tick + 1_ms; md->timer = Timer(md->attackabletime, std::bind(mob_timer, ph::_1, ph::_2, md->bl_id, 0)); @@ -903,7 +914,8 @@ int mob_changestate(dumb_ptr<mob_data> md, MS state, bool type) clif_foreachclient(std::bind(mob_stopattacked, ph::_1, md->bl_id)); skill_status_change_clear(md, 2); // The abnormalities in status are canceled. md->deletetimer.cancel(); - md->hp = md->target_id = md->attacked_id = 0; + md->hp = 0; + md->target_id = md->attacked_id = BlockId(); md->state.attackable = false; } break; @@ -918,12 +930,12 @@ int mob_changestate(dumb_ptr<mob_data> md, MS state, bool type) *------------------------------------------ */ static -void mob_timer(TimerData *, tick_t tick, int id, unsigned char data) +void mob_timer(TimerData *, tick_t tick, BlockId id, unsigned char data) { dumb_ptr<mob_data> md; dumb_ptr<block_list> bl; bl = map_id2bl(id); - if (bl == NULL) + if (bl == nullptr) { //攻撃してきた敵がもういないのは正常のようだ return; } @@ -933,7 +945,7 @@ void mob_timer(TimerData *, tick_t tick, int id, unsigned char data) md = bl->is_mob(); - if (md->bl_prev == NULL || md->state.state == MS::DEAD) + if (md->bl_prev == nullptr || md->state.state == MS::DEAD) return; MapBlockLock lock; @@ -948,7 +960,7 @@ void mob_timer(TimerData *, tick_t tick, int id, unsigned char data) break; default: if (battle_config.error_log == 1) - PRINTF("mob_timer : %d ?\n", + PRINTF("mob_timer : %d ?\n"_fmt, md->state.state); break; } @@ -963,7 +975,7 @@ int mob_walktoxy_sub(dumb_ptr<mob_data> md) { struct walkpath_data wpd; - nullpo_ret(md); + nullpo_retz(md); if (path_search(&wpd, md->bl_m, md->bl_x, md->bl_y, md->to_x, md->to_y, md->state.walk_easy)) @@ -986,7 +998,7 @@ int mob_walktoxy(dumb_ptr<mob_data> md, int x, int y, int easy) { struct walkpath_data wpd; - nullpo_ret(md); + nullpo_retz(md); if (md->state.state == MS::WALK && path_search(&wpd, md->bl_m, md->bl_x, md->bl_y, x, y, easy)) @@ -1012,7 +1024,7 @@ int mob_walktoxy(dumb_ptr<mob_data> md, int x, int y, int easy) *------------------------------------------ */ static -void mob_delayspawn(TimerData *, tick_t, int m) +void mob_delayspawn(TimerData *, tick_t, BlockId m) { mob_spawn(m); } @@ -1022,12 +1034,12 @@ void mob_delayspawn(TimerData *, tick_t, int m) *------------------------------------------ */ static -int mob_setdelayspawn(int id) +int mob_setdelayspawn(BlockId id) { dumb_ptr<mob_data> md; dumb_ptr<block_list> bl; - if ((bl = map_id2bl(id)) == NULL) + if ((bl = map_id2bl(id)) == nullptr) return -1; if (!bl || bl->bl_type == BL::NUL || bl->bl_type != BL::MOB) @@ -1052,7 +1064,7 @@ int mob_setdelayspawn(int id) tick_t spawntime1 = md->last_spawntime + md->spawn.delay1; tick_t spawntime2 = md->last_deadtime + md->spawn.delay2; - tick_t spawntime3 = gettick() + std::chrono::seconds(5); + tick_t spawntime3 = gettick() + 5_s; tick_t spawntime = std::max({spawntime1, spawntime2, spawntime3}); Timer(spawntime, @@ -1066,7 +1078,7 @@ int mob_setdelayspawn(int id) * Mob spawning. Initialization is also variously here. *------------------------------------------ */ -int mob_spawn(int id) +int mob_spawn(BlockId id) { int x = 0, y = 0; tick_t tick = gettick(); @@ -1086,7 +1098,7 @@ int mob_spawn(int id) return -1; md->last_spawntime = tick; - if (md->bl_prev != NULL) + if (md->bl_prev != nullptr) { map_delblock(md); } @@ -1115,9 +1127,7 @@ int mob_spawn(int id) if (i >= 50) { - // if(battle_config.error_log==1) - // PRINTF("MOB spawn error %d @ %s\n",id,map[md->bl_m].name); - Timer(tick + std::chrono::seconds(5), + Timer(tick + 5_s, std::bind(mob_delayspawn, ph::_1, ph::_2, id) ).detach(); @@ -1132,31 +1142,31 @@ int mob_spawn(int id) map_addblock(md); really_memzero_this(&md->state); - md->attacked_id = 0; - md->target_id = 0; + md->attacked_id = BlockId(); + md->target_id = BlockId(); md->move_fail_count = 0; mob_init(md); if (!md->stats[mob_stat::SPEED]) - md->stats[mob_stat::SPEED] = mob_db[md->mob_class].speed; - md->def_ele = mob_db[md->mob_class].element; - md->master_id = 0; + md->stats[mob_stat::SPEED] = get_mob_db(md->mob_class).speed; + md->def_ele = get_mob_db(md->mob_class).element; + md->master_id = BlockId(); md->master_dist = 0; md->state.state = MS::IDLE; md->state.skillstate = MobSkillState::MSS_IDLE; assert (!md->timer); md->last_thinktime = tick; - md->next_walktime = tick + std::chrono::seconds(5) + std::chrono::milliseconds(random_::to(50)); + md->next_walktime = tick + 5_s + std::chrono::milliseconds(random_::to(50)); md->attackabletime = tick; md->canmove_tick = tick; // md->deletetimer = nullptr; // md->skilltimer = nullptr; - md->skilldelayup = make_unique<tick_t[]>(mob_db[md->mob_class].skills.size()); - for (size_t i = 0; i < mob_db[md->mob_class].skills.size(); i++) - md->skilldelayup[i] = tick - std::chrono::hours(10); + md->skilldelayup = make_unique<tick_t[]>(get_mob_db(md->mob_class).skills.size()); + for (size_t i = 0; i < get_mob_db(md->mob_class).skills.size(); i++) + md->skilldelayup[i] = tick - 10_h; md->skillid = SkillID(); md->skilllv = 0; @@ -1206,9 +1216,9 @@ int distance(int x0, int y0, int x1, int y1) */ int mob_stopattack(dumb_ptr<mob_data> md) { - md->target_id = 0; + md->target_id = BlockId(); md->state.attackable = false; - md->attacked_id = 0; + md->attacked_id = BlockId(); return 0; } @@ -1218,7 +1228,7 @@ int mob_stopattack(dumb_ptr<mob_data> md) */ int mob_stop_walking(dumb_ptr<mob_data> md, int type) { - nullpo_ret(md); + nullpo_retz(md); if (md->state.state == MS::WALK || md->state.state == MS::IDLE) { @@ -1271,8 +1281,8 @@ int mob_can_reach(dumb_ptr<mob_data> md, dumb_ptr<block_list> bl, int range) struct walkpath_data wpd; int i; - nullpo_ret(md); - nullpo_ret(bl); + nullpo_retz(md); + nullpo_retz(bl); dx = abs(bl->bl_x - md->bl_x); dy = abs(bl->bl_y - md->bl_y); @@ -1328,16 +1338,16 @@ int mob_target(dumb_ptr<mob_data> md, dumb_ptr<block_list> bl, int dist) eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; MobMode mode; - nullpo_ret(md); - nullpo_ret(bl); + nullpo_retz(md); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); Option *option = battle_get_option(bl); - Race race = mob_db[md->mob_class].race; + Race race = get_mob_db(md->mob_class).race; if (md->mode == MobMode::ZERO) { - mode = mob_db[md->mob_class].mode; + mode = get_mob_db(md->mob_class).mode; } else { @@ -1345,25 +1355,25 @@ int mob_target(dumb_ptr<mob_data> md, dumb_ptr<block_list> bl, int dist) } if (!bool(mode & MobMode::CAN_ATTACK)) { - md->target_id = 0; + md->target_id = BlockId(); return 0; } // Nothing will be carried out if there is no mind of changing TAGE by TAGE ending. - if ((md->target_id > 0 && md->state.attackable) + if ((md->target_id && md->state.attackable) && (!bool(mode & MobMode::AGGRESSIVE) || !random_::chance({25 + 1, 100}))) return 0; // Coercion is exerted if it is MVPMOB. if (bool(mode & MobMode::BOSS) - || (option != NULL + || (option != nullptr || race == Race::_insect || race == Race::_demon)) { if (bl->bl_type == BL::PC) { sd = bl->is_player(); - nullpo_ret(sd); + nullpo_retz(sd); if (sd->invincible_timer || pc_isinvisible(sd)) return 0; if (!bool(mode & MobMode::BOSS) && race != Race::_insect && race != Race::_demon @@ -1391,8 +1401,8 @@ static void mob_ai_sub_hard_activesearch(dumb_ptr<block_list> bl, dumb_ptr<mob_data> smd, int *pcc) { - dumb_ptr<map_session_data> tsd = NULL; - dumb_ptr<mob_data> tmd = NULL; + dumb_ptr<map_session_data> tsd = nullptr; + dumb_ptr<mob_data> tmd = nullptr; MobMode mode; int dist; @@ -1412,14 +1422,14 @@ void mob_ai_sub_hard_activesearch(dumb_ptr<block_list> bl, return; if (smd->mode == MobMode::ZERO) - mode = mob_db[smd->mob_class].mode; + mode = get_mob_db(smd->mob_class).mode; else mode = smd->mode; // アクティブでターゲット射程内にいるなら、ロックする if (bool(mode & MobMode::AGGRESSIVE)) { - Race race = mob_db[smd->mob_class].race; + Race race = get_mob_db(smd->mob_class).race; //対象がPCの場合 if (tsd && !pc_isdead(tsd) && @@ -1479,7 +1489,7 @@ void mob_ai_sub_hard_lootsearch(dumb_ptr<block_list> bl, dumb_ptr<mob_data> md, if (md->mode == MobMode::ZERO) { - mode = mob_db[md->mob_class].mode; + mode = get_mob_db(md->mob_class).mode; } else { @@ -1518,8 +1528,8 @@ void mob_ai_sub_hard_linksearch(dumb_ptr<block_list> bl, dumb_ptr<mob_data> md, nullpo_retv(md); nullpo_retv(target); - if (md->attacked_id > 0 - && bool(mob_db[md->mob_class].mode & MobMode::ASSIST)) + if (md->attacked_id + && bool(get_mob_db(md->mob_class).mode & MobMode::ASSIST)) { if (tmd->mob_class == md->mob_class && tmd->bl_m == md->bl_m @@ -1543,17 +1553,17 @@ void mob_ai_sub_hard_linksearch(dumb_ptr<block_list> bl, dumb_ptr<mob_data> md, static int mob_ai_sub_hard_slavemob(dumb_ptr<mob_data> md, tick_t tick) { - dumb_ptr<mob_data> mmd = NULL; + dumb_ptr<mob_data> mmd = nullptr; dumb_ptr<block_list> bl; MobMode mode; int old_dist; - nullpo_ret(md); + nullpo_retz(md); - if ((bl = map_id2bl(md->master_id)) != NULL) + if ((bl = map_id2bl(md->master_id)) != nullptr) mmd = bl->is_mob(); - mode = mob_db[md->mob_class].mode; + mode = get_mob_db(md->mob_class).mode; // It is not main monster/leader. if (!mmd || mmd->bl_type != BL::MOB || mmd->bl_id != md->master_id) @@ -1636,20 +1646,20 @@ int mob_ai_sub_hard_slavemob(dumb_ptr<mob_data> md, tick_t tick) while (ret && i < 10); } - md->next_walktime = tick + std::chrono::milliseconds(500); + md->next_walktime = tick + 500_ms; md->state.master_check = 1; } // There is the master, the master locks a target and he does not lock. - if ((mmd->target_id > 0 && mmd->state.attackable) + if ((mmd->target_id && mmd->state.attackable) && (!md->target_id || !md->state.attackable)) { dumb_ptr<map_session_data> sd = map_id2sd(mmd->target_id); - if (sd != NULL && !pc_isdead(sd) && !sd->invincible_timer + if (sd != nullptr && !pc_isdead(sd) && !sd->invincible_timer && !pc_isinvisible(sd)) { - Race race = mob_db[md->mob_class].race; + Race race = get_mob_db(md->mob_class).race; if (bool(mode & MobMode::BOSS) || (!sd->state.gangsterparadise || race == Race::_insect @@ -1675,12 +1685,12 @@ int mob_ai_sub_hard_slavemob(dumb_ptr<mob_data> md, tick_t tick) static int mob_unlocktarget(dumb_ptr<mob_data> md, tick_t tick) { - nullpo_ret(md); + nullpo_retz(md); - md->target_id = 0; + md->target_id = BlockId(); md->state.attackable = false; md->state.skillstate = MobSkillState::MSS_IDLE; - md->next_walktime = tick + std::chrono::seconds(3) + std::chrono::milliseconds(random_::to(3000)); + md->next_walktime = tick + 3_s + std::chrono::milliseconds(random_::to(3000)); return 0; } @@ -1693,7 +1703,7 @@ int mob_randomwalk(dumb_ptr<mob_data> md, tick_t tick) { const int retrycount = 20; - nullpo_ret(md); + nullpo_retz(md); interval_t speed = battle_get_speed(md); if (md->next_walktime < tick) @@ -1718,8 +1728,8 @@ int mob_randomwalk(dumb_ptr<mob_data> md, tick_t tick) if (md->move_fail_count > 1000) { if (battle_config.error_log == 1) - PRINTF("MOB cant move. random spawn %d, mob_class = %d\n", - md->bl_id, md->mob_class); + PRINTF("MOB cant move. random spawn %d, mob_class = %d\n"_fmt, + md->bl_id, md->mob_class); md->move_fail_count = 0; mob_spawn(md->bl_id); } @@ -1734,7 +1744,7 @@ int mob_randomwalk(dumb_ptr<mob_data> md, tick_t tick) else c += speed; } - md->next_walktime = tick + std::chrono::seconds(3) + std::chrono::milliseconds(random_::to(3000)) + c; + md->next_walktime = tick + 3_s + std::chrono::milliseconds(random_::to(3000)) + c; md->state.skillstate = MobSkillState::MSS_WALK; return 1; } @@ -1748,9 +1758,9 @@ int mob_randomwalk(dumb_ptr<mob_data> md, tick_t tick) static void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick) { - dumb_ptr<mob_data> md, tmd = NULL; - dumb_ptr<map_session_data> tsd = NULL; - dumb_ptr<block_list> tbl = NULL; + dumb_ptr<mob_data> md, tmd = nullptr; + dumb_ptr<map_session_data> tsd = nullptr; + dumb_ptr<block_list> tbl = nullptr; dumb_ptr<flooritem_data> fitem; int i, dx, dy, ret, dist; int attack_type = 0; @@ -1763,7 +1773,7 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick) return; md->last_thinktime = tick; - if (md->skilltimer || md->bl_prev == NULL) + if (md->skilltimer || md->bl_prev == nullptr) { // Under a skill aria and death if (tick > md->next_walktime + MIN_MOBTHINKTIME) @@ -1772,20 +1782,20 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick) } if (md->mode == MobMode::ZERO) - mode = mob_db[md->mob_class].mode; + mode = get_mob_db(md->mob_class).mode; else mode = md->mode; - Race race = mob_db[md->mob_class].race; + Race race = get_mob_db(md->mob_class).race; // Abnormalities if (bool(md->opt1) && md->opt1 != Opt1::_stone6) return; - if (!bool(mode & MobMode::CAN_ATTACK) && md->target_id > 0) - md->target_id = 0; + if (!bool(mode & MobMode::CAN_ATTACK) && md->target_id) + md->target_id = BlockId(); - if (md->attacked_id > 0 && bool(mode & MobMode::ASSIST)) + if (md->attacked_id && bool(mode & MobMode::ASSIST)) { // Link monster dumb_ptr<map_session_data> asd = map_id2sd(md->attacked_id); if (asd) @@ -1802,28 +1812,28 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick) } // It checks to see it was attacked first (if active, it is target change at 25% of probability). - if (mode != MobMode::ZERO && md->attacked_id > 0 + if (mode != MobMode::ZERO && md->attacked_id && (!md->target_id || !md->state.attackable || (bool(mode & MobMode::AGGRESSIVE) && random_::chance({25, 100})))) { dumb_ptr<block_list> abl = map_id2bl(md->attacked_id); - dumb_ptr<map_session_data> asd = NULL; + dumb_ptr<map_session_data> asd = nullptr; if (abl) { if (abl->bl_type == BL::PC) asd = abl->is_player(); - if (asd == NULL || md->bl_m != abl->bl_m || abl->bl_prev == NULL + if (asd == nullptr || md->bl_m != abl->bl_m || abl->bl_prev == nullptr || asd->invincible_timer || pc_isinvisible(asd) || (dist = distance(md->bl_x, md->bl_y, abl->bl_x, abl->bl_y)) >= 32 || battle_check_target(bl, abl, BCT_ENEMY) == 0) - md->attacked_id = 0; + md->attacked_id = BlockId(); else { md->target_id = md->attacked_id; // set target md->state.attackable = true; attack_type = 1; - md->attacked_id = 0; + md->attacked_id = BlockId(); md->min_chase = dist + 13; if (md->min_chase > 26) md->min_chase = 26; @@ -1833,7 +1843,7 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick) md->state.master_check = 0; // Processing of slave monster - if (md->master_id > 0 && md->state.special_mob_ai == 0) + if (md->master_id && md->state.special_mob_ai == 0) mob_ai_sub_hard_slavemob(md, tick); // アクティヴモンスターの策敵 (?? of a bitter taste TIVU monster) @@ -1874,7 +1884,7 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick) } // It will attack, if the candidate for an attack is. - if (md->target_id > 0) + if (md->target_id) { if ((tbl = map_id2bl(md->target_id))) { @@ -1884,7 +1894,7 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick) tmd = tbl->is_mob(); if (tsd || tmd) { - if (tbl->bl_m != md->bl_m || tbl->bl_prev == NULL + if (tbl->bl_m != md->bl_m || tbl->bl_prev == nullptr || (dist = distance(md->bl_x, md->bl_y, tbl->bl_x, tbl->bl_y)) >= md->min_chase) @@ -1894,7 +1904,7 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick) && race != Race::_insect && race != Race::_demon)) mob_unlocktarget(md, tick); // スキルなどによる策敵妨害 - else if (!battle_check_range(md, tbl, mob_db[md->mob_class].range)) + else if (!battle_check_range(md, tbl, get_mob_db(md->mob_class).range)) { // 攻撃範囲外なので移動 if (!bool(mode & MobMode::CAN_MOVE)) @@ -1915,7 +1925,7 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick) else { // 追跡 - md->next_walktime = tick + std::chrono::milliseconds(500); + md->next_walktime = tick + 500_ms; i = 0; do { @@ -1973,11 +1983,11 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick) } else { // ルートモンスター処理 - if (tbl == NULL || tbl->bl_type != BL::ITEM || tbl->bl_m != md->bl_m + if (tbl == nullptr || tbl->bl_type != BL::ITEM || tbl->bl_m != md->bl_m || (dist = distance(md->bl_x, md->bl_y, tbl->bl_x, tbl->bl_y)) >= md->min_chase - || !bool(mob_db[md->mob_class].mode & MobMode::LOOTER)) + || !bool(get_mob_db(md->mob_class).mode & MobMode::LOOTER)) { // 遠すぎるかアイテムがなくなった mob_unlocktarget(md, tick); @@ -1999,7 +2009,7 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick) && (md->next_walktime < tick || distance(md->to_x, md->to_y, tbl->bl_x, tbl->bl_y) <= 0)) return; // 既に移動中 - md->next_walktime = tick + std::chrono::milliseconds(500); + md->next_walktime = tick + 500_ms; dx = tbl->bl_x - md->bl_x; dy = tbl->bl_y - md->bl_y; ret = mob_walktoxy(md, md->bl_x + dx, md->bl_y + dy, 0); @@ -2036,16 +2046,16 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick) // mobs that are not slaves can random-walk if (bool(mode & MobMode::CAN_MOVE) && mob_can_move(md) - && (md->master_id == 0 || md->state.special_mob_ai + && (!md->master_id || md->state.special_mob_ai || md->master_dist > 10)) { // if walktime is more than 7 seconds in the future, // set it to somewhere between 3 and 5 seconds - if (md->next_walktime > tick + std::chrono::seconds(7) + if (md->next_walktime > tick + 7_s && (md->walkpath.path_len == 0 || md->walkpath.path_pos >= md->walkpath.path_len)) { - md->next_walktime = tick + std::chrono::seconds(3) + md->next_walktime = tick + 3_s + std::chrono::milliseconds(random_::to(2000)); } @@ -2104,7 +2114,7 @@ void mob_ai_sub_lazy(dumb_ptr<block_list> bl, tick_t tick) return; md->last_thinktime = tick; - if (md->bl_prev == NULL || md->skilltimer) + if (md->bl_prev == nullptr || md->skilltimer) { if (tick > md->next_walktime + MIN_MOBTHINKTIME * 10) md->next_walktime = tick; @@ -2112,7 +2122,7 @@ void mob_ai_sub_lazy(dumb_ptr<block_list> bl, tick_t tick) } if (md->next_walktime < tick - && bool(mob_db[md->mob_class].mode & MobMode::CAN_MOVE) + && bool(get_mob_db(md->mob_class).mode & MobMode::CAN_MOVE) && mob_can_move(md)) { @@ -2127,8 +2137,8 @@ void mob_ai_sub_lazy(dumb_ptr<block_list> bl, tick_t tick) // MOB which is not not the summons MOB but BOSS, either sometimes reboils. else if (random_::chance(MOB_LAZYWARPPERC) && md->spawn.x0 <= 0 - && md->master_id != 0 - && !bool(mob_db[md->mob_class].mode & MobMode::BOSS)) + && md->master_id + && !bool(get_mob_db(md->mob_class).mode & MobMode::BOSS)) mob_spawn(md->bl_id); } @@ -2139,12 +2149,12 @@ void mob_ai_sub_lazy(dumb_ptr<block_list> bl, tick_t tick) // MOB which is not BOSS which is not Summons MOB, either -- a case -- sometimes -- leaping if (random_::chance(MOB_LAZYWARPPERC) && md->spawn.x0 <= 0 - && md->master_id != 0 - && !bool(mob_db[md->mob_class].mode & MobMode::BOSS)) + && md->master_id + && !bool(get_mob_db(md->mob_class).mode & MobMode::BOSS)) mob_warp(md, nullptr, -1, -1, BeingRemoveWhy::NEGATIVE1); } - md->next_walktime = tick + std::chrono::seconds(5) + std::chrono::milliseconds(random_::to(10 * 1000)); + md->next_walktime = tick + 5_s + std::chrono::milliseconds(random_::to(10 * 1000)); } } @@ -2169,7 +2179,8 @@ struct delay_item_drop { map_local *m; int x, y; - int nameid, amount; + ItemNameId nameid; + int amount; dumb_ptr<map_session_data> first_sd, second_sd, third_sd; }; @@ -2177,7 +2188,7 @@ struct delay_item_drop2 { map_local *m; int x, y; - struct item item_data; + Item item_data; dumb_ptr<map_session_data> first_sd, second_sd, third_sd; }; @@ -2188,7 +2199,7 @@ struct delay_item_drop2 static void mob_delay_item_drop(TimerData *, tick_t, struct delay_item_drop ditem) { - struct item temp_item {}; + Item temp_item {}; PickupFail flag; temp_item.nameid = ditem.nameid; @@ -2201,7 +2212,7 @@ void mob_delay_item_drop(TimerData *, tick_t, struct delay_item_drop ditem) pc_additem(ditem.first_sd, &temp_item, ditem.amount)) != PickupFail::OKAY) { - clif_additem(ditem.first_sd, 0, 0, flag); + clif_additem(ditem.first_sd, IOff0::from(0), 0, flag); map_addflooritem(&temp_item, 1, ditem.m, ditem.x, ditem.y, ditem.first_sd, ditem.second_sd, ditem.third_sd); @@ -2231,7 +2242,7 @@ void mob_delay_item_drop2(TimerData *, tick_t, struct delay_item_drop2 ditem) ditem.item_data.amount)) != PickupFail::OKAY) { - clif_additem(ditem.first_sd, 0, 0, flag); + clif_additem(ditem.first_sd, IOff0::from(0), 0, flag); map_addflooritem(&ditem.item_data, ditem.item_data.amount, ditem.m, ditem.x, ditem.y, ditem.first_sd, ditem.second_sd, ditem.third_sd); @@ -2252,7 +2263,7 @@ int mob_delete(dumb_ptr<mob_data> md) { nullpo_retr(1, md); - if (md->bl_prev == NULL) + if (md->bl_prev == nullptr) return 1; mob_changestate(md, MS::DEAD, 0); clif_clearchar(md, BeingRemoveWhy::DEAD); @@ -2266,7 +2277,7 @@ int mob_catch_delete(dumb_ptr<mob_data> md, BeingRemoveWhy type) { nullpo_retr(1, md); - if (md->bl_prev == NULL) + if (md->bl_prev == nullptr) return 1; mob_changestate(md, MS::DEAD, 0); clif_clearchar(md, type); @@ -2275,7 +2286,7 @@ int mob_catch_delete(dumb_ptr<mob_data> md, BeingRemoveWhy type) return 0; } -void mob_timer_delete(TimerData *, tick_t, int id) +void mob_timer_delete(TimerData *, tick_t, BlockId id) { dumb_ptr<block_list> bl = map_id2bl(id); dumb_ptr<mob_data> md; @@ -2291,15 +2302,15 @@ void mob_timer_delete(TimerData *, tick_t, int id) *------------------------------------------ */ static -void mob_deleteslave_sub(dumb_ptr<block_list> bl, int id) +void mob_deleteslave_sub(dumb_ptr<block_list> bl, BlockId id) { dumb_ptr<mob_data> md; nullpo_retv(bl); md = bl->is_mob(); - if (md->master_id > 0 && md->master_id == id) - mob_damage(NULL, md, md->hp, 1); + if (md->master_id && md->master_id == id) + mob_damage(nullptr, md, md->hp, 1); } /*========================================== @@ -2308,7 +2319,7 @@ void mob_deleteslave_sub(dumb_ptr<block_list> bl, int id) */ int mob_deleteslave(dumb_ptr<mob_data> md) { - nullpo_ret(md); + nullpo_retz(md); map_foreachinarea(std::bind(mob_deleteslave_sub, ph::_1, md->bl_id), md->bl_m, @@ -2333,18 +2344,18 @@ double damage_bonus_factor[DAMAGE_BONUS_COUNT + 1] = int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, int type) { - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; int max_hp; tick_t tick = gettick(); - dumb_ptr<map_session_data> mvp_sd = NULL, second_sd = NULL, third_sd = NULL; + dumb_ptr<map_session_data> mvp_sd = nullptr, second_sd = nullptr, third_sd = nullptr; - nullpo_ret(md); //srcはNULLで呼ばれる場合もあるので、他でチェック + nullpo_retz(md); //srcはNULLで呼ばれる場合もあるので、他でチェック if (src && src->bl_id == md->master_id && bool(md->mode & MobMode::TURNS_AGAINST_BAD_MASTER)) { /* If the master hits a monster, have the monster turn against him */ - md->master_id = 0; + md->master_id = BlockId(); md->mode = MobMode::war; /* Regular war mode */ md->target_id = src->bl_id; md->attacked_id = src->bl_id; @@ -2358,18 +2369,16 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, mvp_sd = sd; } -// if(battle_config.battle_log) -// PRINTF("mob_damage %d %d %d\n",md->hp,max_hp,damage); - if (md->bl_prev == NULL) + if (md->bl_prev == nullptr) { if (battle_config.error_log == 1) - PRINTF("mob_damage : BlockError!!\n"); + PRINTF("mob_damage : BlockError!!\n"_fmt); return 0; } if (md->state.state == MS::DEAD || md->hp <= 0) { - if (md->bl_prev != NULL) + if (md->bl_prev != nullptr) { mob_changestate(md, MS::DEAD, 0); // It is skill at the time of death. @@ -2395,7 +2404,7 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, if (!(type & 2)) { - if (sd != NULL) + if (sd != nullptr) { for (mob_data::DmgLogEntry& dle : md->dmglogv) { @@ -2414,7 +2423,7 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, } damage_logged_pc: - if (md->attacked_id <= 0 && md->state.special_mob_ai == 0) + if (!md->attacked_id && md->state.special_mob_ai == 0) md->attacked_id = sd->bl_id; } if (src && src->bl_type == BL::MOB @@ -2425,12 +2434,12 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, if (master_bl && master_bl->bl_type == BL::PC) { MAP_LOG_PC(master_bl->is_player(), - "MOB-TO-MOB-DMG FROM MOB%d %d TO MOB%d %d FOR %d", - md2->bl_id, md2->mob_class, md->bl_id, md->mob_class, - damage); + "MOB-TO-MOB-DMG FROM MOB%d %d TO MOB%d %d FOR %d"_fmt, + md2->bl_id, md2->mob_class, md->bl_id, md->mob_class, + damage); } - nullpo_ret(md2); + nullpo_retz(md2); for (mob_data::DmgLogEntry& dle : md->dmglogv) { if (dle.id == md2->master_id) @@ -2446,7 +2455,7 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, app.dmg = damage; md->dmglogv.push_back(app); - if (md->attacked_id <= 0 && md->state.special_mob_ai == 0) + if (!md->attacked_id && md->state.special_mob_ai == 0) md->attacked_id = md2->master_id; } damage_logged_slave: @@ -2461,7 +2470,7 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, return 0; } - MAP_LOG("MOB%d DEAD", md->bl_id); + MAP_LOG("MOB%d DEAD"_fmt, md->bl_id); // ----- ここから死亡処理 ----- @@ -2491,7 +2500,7 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, { struct DmgLogParty { - struct party *p; + PartyPair p; int base_exp, job_exp; }; std::vector<DmgLogParty> ptv; @@ -2501,7 +2510,7 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, { dumb_ptr<map_session_data> tmpsdi = map_id2sd(dle.id); int tmpdmg = dle.dmg; - if (tmpsdi == NULL) + if (tmpsdi == nullptr) continue; if (tmpsdi->bl_m != md->bl_m || pc_isdead(tmpsdi)) continue; @@ -2532,7 +2541,7 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, int base_exp, job_exp, flag = 1; double per; - struct party *p; + PartyPair p; // [Fate] The above is the old formula. We do a more involved computation below. // [o11c] Look in git history for old code, you idiot! @@ -2548,23 +2557,23 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, per = 1; base_exp = - ((mob_db[md->mob_class].base_exp * + ((get_mob_db(md->mob_class).base_exp * md->stats[mob_stat::XP_BONUS]) >> MOB_XP_BONUS_SHIFT) * per / 256; if (base_exp < 1) base_exp = 1; if (sd && md && battle_config.pk_mode == 1 - && (mob_db[md->mob_class].lv - sd->status.base_level >= 20)) + && (get_mob_db(md->mob_class).lv - sd->status.base_level >= 20)) { base_exp *= 1.15; // pk_mode additional exp if monster >20 levels [Valaris] } if (md->state.special_mob_ai >= 1 && battle_config.alchemist_summon_reward != 1) base_exp = 0; // Added [Valaris] - job_exp = mob_db[md->mob_class].job_exp * per / 256; + job_exp = get_mob_db(md->mob_class).job_exp * per / 256; if (job_exp < 1) job_exp = 1; if (sd && md && battle_config.pk_mode == 1 - && (mob_db[md->mob_class].lv - sd->status.base_level >= 20)) + && (get_mob_db(md->mob_class).lv - sd->status.base_level >= 20)) { job_exp *= 1.15; // pk_mode additional exp if monster >20 levels [Valaris] } @@ -2572,19 +2581,19 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, && battle_config.alchemist_summon_reward != 1) job_exp = 0; // Added [Valaris] - int pid = tmpsdi->status.party_id; - if (pid > 0) + PartyId pid = tmpsdi->status.party_id; + if (pid) { std::vector<DmgLogParty>::iterator it = std::find_if(ptv.begin(), ptv.end(), [pid](const DmgLogParty& dlp) { - return dlp.p->party_id == pid; + return dlp.p.party_id == pid; } ); if (it == ptv.end()) { p = party_search(pid); - if (p != NULL && p->exp != 0) + if (p && p->exp != 0) { DmgLogParty pn {}; pn.p = p; @@ -2617,19 +2626,19 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, if (md->state.special_mob_ai >= 1 && battle_config.alchemist_summon_reward != 1) // Added [Valaris] break; // End - if (mob_db[md->mob_class].dropitem[i].nameid <= 0) + if (!get_mob_db(md->mob_class).dropitem[i].nameid) continue; - random_::Fixed<int, 10000> drop_rate = mob_db[md->mob_class].dropitem[i].p; + random_::Fixed<int, 10000> drop_rate = get_mob_db(md->mob_class).dropitem[i].p; if (battle_config.drops_by_luk > 0 && sd && md) drop_rate.num += (sd->status.attrs[ATTR::LUK] * battle_config.drops_by_luk) / 100; // drops affected by luk [Valaris] if (sd && md && battle_config.pk_mode == 1 - && (mob_db[md->mob_class].lv - sd->status.base_level >= 20)) + && (get_mob_db(md->mob_class).lv - sd->status.base_level >= 20)) drop_rate.num *= 1.25; // pk_mode increase drops if 20 level difference [Valaris] if (!random_::chance(drop_rate)) continue; struct delay_item_drop ditem {}; - ditem.nameid = mob_db[md->mob_class].dropitem[i].nameid; + ditem.nameid = get_mob_db(md->mob_class).dropitem[i].nameid; ditem.amount = 1; ditem.m = md->bl_m; ditem.x = md->bl_x; @@ -2637,14 +2646,14 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, ditem.first_sd = mvp_sd; ditem.second_sd = second_sd; ditem.third_sd = third_sd; - Timer(tick + std::chrono::milliseconds(500) + static_cast<interval_t>(i), + Timer(tick + 500_ms + static_cast<interval_t>(i), std::bind(mob_delay_item_drop, ph::_1, ph::_2, ditem) ).detach(); } { int i = 0; - for (struct item lit : md->lootitemv) + for (Item lit : md->lootitemv) { struct delay_item_drop2 ditem {}; ditem.item_data = lit; @@ -2655,7 +2664,7 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, ditem.second_sd = second_sd; ditem.third_sd = third_sd; // ? - Timer(tick + std::chrono::milliseconds(540) + static_cast<interval_t>(i), + Timer(tick + 540_ms + static_cast<interval_t>(i), std::bind(mob_delay_item_drop2, ph::_1, ph::_2, ditem) ).detach(); @@ -2668,9 +2677,9 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, // SCRIPT実行 if (md->npc_event) { - if (sd == NULL) + if (sd == nullptr) { - if (mvp_sd != NULL) + if (mvp_sd != nullptr) sd = mvp_sd; else { @@ -2711,7 +2720,7 @@ int mob_heal(dumb_ptr<mob_data> md, int heal) { int max_hp = battle_get_max_hp(md); - nullpo_ret(md); + nullpo_retz(md); md->hp += heal; if (max_hp < md->hp) @@ -2725,7 +2734,7 @@ int mob_heal(dumb_ptr<mob_data> md, int heal) *------------------------------------------ */ static -void mob_warpslave_sub(dumb_ptr<block_list> bl, int id, int x, int y) +void mob_warpslave_sub(dumb_ptr<block_list> bl, BlockId id, int x, int y) { dumb_ptr<mob_data> md = bl->is_mob(); @@ -2742,7 +2751,6 @@ void mob_warpslave_sub(dumb_ptr<block_list> bl, int id, int x, int y) static int mob_warpslave(dumb_ptr<mob_data> md, int x, int y) { -//PRINTF("warp slave\n"); map_foreachinarea(std::bind(mob_warpslave_sub, ph::_1, md->bl_id, md->bl_x, md->bl_y), md->bl_m, x - AREA_SIZE, y - AREA_SIZE, @@ -2759,9 +2767,9 @@ int mob_warp(dumb_ptr<mob_data> md, map_local *m, int x, int y, BeingRemoveWhy t { int i = 0, xs = 0, ys = 0, bx = x, by = y; - nullpo_ret(md); + nullpo_retz(md); - if (md->bl_prev == NULL) + if (md->bl_prev == nullptr) return 0; if (m == nullptr) @@ -2808,12 +2816,12 @@ int mob_warp(dumb_ptr<mob_data> md, map_local *m, int x, int y, BeingRemoveWhy t else { if (battle_config.error_log == 1) - PRINTF("MOB %d warp failed, mob_class = %d\n", md->bl_id, md->mob_class); + PRINTF("MOB %d warp failed, mob_class = %d\n"_fmt, md->bl_id, md->mob_class); } - md->target_id = 0; // タゲを解除する + md->target_id = BlockId(); // タゲを解除する md->state.attackable = false; - md->attacked_id = 0; + md->attacked_id = BlockId(); md->state.skillstate = MobSkillState::MSS_IDLE; mob_changestate(md, MS::IDLE, 0); @@ -2821,7 +2829,7 @@ int mob_warp(dumb_ptr<mob_data> md, map_local *m, int x, int y, BeingRemoveWhy t && i == 1000) { if (battle_config.battle_log == 1) - PRINTF("MOB %d warp to (%d,%d), mob_class = %d\n", md->bl_id, x, y, + PRINTF("MOB %d warp to (%d,%d), mob_class = %d\n"_fmt, md->bl_id, x, y, md->mob_class); } @@ -2840,7 +2848,7 @@ int mob_warp(dumb_ptr<mob_data> md, map_local *m, int x, int y, BeingRemoveWhy t *------------------------------------------ */ static -void mob_countslave_sub(dumb_ptr<block_list> bl, int id, int *c) +void mob_countslave_sub(dumb_ptr<block_list> bl, BlockId id, int *c) { dumb_ptr<mob_data> md; @@ -2860,7 +2868,7 @@ int mob_countslave(dumb_ptr<mob_data> md) { int c = 0; - nullpo_ret(md); + nullpo_retz(md); map_foreachinarea(std::bind(mob_countslave_sub, ph::_1, md->bl_id, &c), md->bl_m, @@ -2874,36 +2882,38 @@ int mob_countslave(dumb_ptr<mob_data> md) * 手下MOB召喚 *------------------------------------------ */ -int mob_summonslave(dumb_ptr<mob_data> md2, int *value, int amount, int flag) +int mob_summonslave(dumb_ptr<mob_data> md2, int *value_, int amount, int flag) { dumb_ptr<mob_data> md; - int bx, by, count = 0, mob_class, k, a = amount; + int bx, by, count = 0, a = amount; - nullpo_ret(md2); - nullpo_ret(value); + nullpo_retz(md2); + nullpo_retz(value_); bx = md2->bl_x; by = md2->bl_y; map_local *m = md2->bl_m; - if (value[0] <= 1000 || value[0] > 2000) // 値が異常なら召喚を止める - return 0; - while (count < 5 && value[count] > 1000 && value[count] <= 2000) - count++; + Species values[5]; + for (count = 0; count < 5 && values[count] != Species(); ++count) + values[count] = wrap<Species>(value_[count]); if (count < 1) return 0; - for (k = 0; k < count; k++) + for (int k = 0; k < count; k++) { amount = a; - mob_class = value[k]; - if (mob_class <= 1000 || mob_class > 2000) + Species mob_class = values[k]; + if (mobdb_checkid(mob_class) == Species()) + { + PRINTF("Warning: bad slave class %u\n"_fmt, mob_class); continue; + } for (; amount > 0; amount--) { int x = 0, y = 0, i = 0; md.new_(); - if (bool(mob_db[mob_class].mode & MobMode::LOOTER)) + if (bool(get_mob_db(mob_class).mode & MobMode::LOOTER)) md->lootitemv.clear(); while ((x <= 0 @@ -2921,8 +2931,8 @@ int mob_summonslave(dumb_ptr<mob_data> md2, int *value, int amount, int flag) } mob_spawn_dataset(md, JAPANESE_NAME, mob_class); - md->bl_prev = NULL; - md->bl_next = NULL; + md->bl_prev = nullptr; + md->bl_next = nullptr; md->bl_m = m; md->bl_x = x; md->bl_y = y; @@ -2954,7 +2964,7 @@ int mob_summonslave(dumb_ptr<mob_data> md2, int *value, int amount, int flag) */ static void mob_counttargeted_sub(dumb_ptr<block_list> bl, - int id, int *c, dumb_ptr<block_list> src, ATK target_lv) + BlockId id, int *c, dumb_ptr<block_list> src, ATK target_lv) { nullpo_retv(bl); nullpo_retv(c); @@ -2986,7 +2996,7 @@ int mob_counttargeted(dumb_ptr<mob_data> md, dumb_ptr<block_list> src, { int c = 0; - nullpo_ret(md); + nullpo_retz(md); map_foreachinarea(std::bind(mob_counttargeted_sub, ph::_1, md->bl_id, &c, src, target_lv), md->bl_m, @@ -3004,21 +3014,21 @@ int mob_counttargeted(dumb_ptr<mob_data> md, dumb_ptr<block_list> src, * スキル使用(詠唱完了、ID指定) *------------------------------------------ */ -void mobskill_castend_id(TimerData *, tick_t tick, int id) +void mobskill_castend_id(TimerData *, tick_t tick, BlockId id) { - dumb_ptr<mob_data> md = NULL; + dumb_ptr<mob_data> md = nullptr; dumb_ptr<block_list> bl; dumb_ptr<block_list> mbl; int range; - if ((mbl = map_id2bl(id)) == NULL) //詠唱したMobがもういないというのは良くある正常処理 + if ((mbl = map_id2bl(id)) == nullptr) //詠唱したMobがもういないというのは良くある正常処理 return; - if ((md = mbl->is_mob()) == NULL) + if ((md = mbl->is_mob()) == nullptr) { - PRINTF("mobskill_castend_id nullpo mbl->bl_id:%d\n", mbl->bl_id); + PRINTF("mobskill_castend_id nullpo mbl->bl_id:%d\n"_fmt, mbl->bl_id); return; } - if (md->bl_type != BL::MOB || md->bl_prev == NULL) + if (md->bl_type != BL::MOB || md->bl_prev == nullptr) return; if (bool(md->opt1)) @@ -3027,9 +3037,8 @@ void mobskill_castend_id(TimerData *, tick_t tick, int id) if (md->skillid != SkillID::NPC_EMOTION) md->last_thinktime = tick + battle_get_adelay(md); - if ((bl = map_id2bl(md->skilltarget)) == NULL || bl->bl_prev == NULL) + if ((bl = map_id2bl(md->skilltarget)) == nullptr || bl->bl_prev == nullptr) { //スキルターゲットが存在しない - //PRINTF("mobskill_castend_id nullpo\n");//ターゲットがいないときはnullpoじゃなくて普通に終了 return; } if (md->bl_m != bl->bl_m) @@ -3044,10 +3053,10 @@ void mobskill_castend_id(TimerData *, tick_t tick, int id) if (range + battle_config.monster_skill_add_range < distance(md->bl_x, md->bl_y, bl->bl_x, bl->bl_y)) return; - md->skilldelayup[md->skillidx - &mob_db[md->mob_class].skills.front()] = tick; + md->skilldelayup[md->skillidx - &get_mob_db(md->mob_class).skills.front()] = tick; if (battle_config.monster_skill_log == 1) - PRINTF("MOB skill castend skill=%d, mob_class = %d\n", + PRINTF("MOB skill castend skill=%d, mob_class = %d\n"_fmt, md->skillid, md->mob_class); mob_stop_walking(md, 0); @@ -3071,20 +3080,20 @@ void mobskill_castend_id(TimerData *, tick_t tick, int id) * スキル使用(詠唱完了、場所指定) *------------------------------------------ */ -void mobskill_castend_pos(TimerData *, tick_t tick, int id) +void mobskill_castend_pos(TimerData *, tick_t tick, BlockId id) { - dumb_ptr<mob_data> md = NULL; + dumb_ptr<mob_data> md = nullptr; dumb_ptr<block_list> bl; int range; //mobskill_castend_id同様詠唱したMobが詠唱完了時にもういないというのはありそうなのでnullpoから除外 - if ((bl = map_id2bl(id)) == NULL) + if ((bl = map_id2bl(id)) == nullptr) return; md = bl->is_mob(); nullpo_retv(md); - if (md->bl_type != BL::MOB || md->bl_prev == NULL) + if (md->bl_type != BL::MOB || md->bl_prev == nullptr) return; if (bool(md->opt1)) @@ -3095,10 +3104,10 @@ void mobskill_castend_pos(TimerData *, tick_t tick, int id) range = battle_get_range(md) - (range + 1); if (range + battle_config.monster_skill_add_range < distance(md->bl_x, md->bl_y, md->skillx, md->skilly)) return; - md->skilldelayup[md->skillidx - &mob_db[md->mob_class].skills.front()] = tick; + md->skilldelayup[md->skillidx - &get_mob_db(md->mob_class).skills.front()] = tick; if (battle_config.monster_skill_log == 1) - PRINTF("MOB skill castend skill=%d, mob_class = %d\n", + PRINTF("MOB skill castend skill=%d, mob_class = %d\n"_fmt, md->skillid, md->mob_class); mob_stop_walking(md, 0); } @@ -3115,13 +3124,13 @@ int mobskill_use_id(dumb_ptr<mob_data> md, dumb_ptr<block_list> target, SkillID skill_id; int skill_lv; - nullpo_ret(md); + nullpo_retz(md); ms = &skill_idx; - if (target == NULL && (target = map_id2bl(md->target_id)) == NULL) + if (target == nullptr && (target = map_id2bl(md->target_id)) == nullptr) return 0; - if (target->bl_prev == NULL || md->bl_prev == NULL) + if (target->bl_prev == nullptr || md->bl_prev == nullptr) return 0; skill_id = ms->skill_id; @@ -3145,10 +3154,10 @@ int mobskill_use_id(dumb_ptr<mob_data> md, dumb_ptr<block_list> target, interval_t casttime = skill_castfix(md, ms->casttime); md->state.skillcastcancel = ms->cancel; - md->skilldelayup[ms - &mob_db[md->mob_class].skills.front()] = gettick(); + md->skilldelayup[ms - &get_mob_db(md->mob_class).skills.front()] = gettick(); if (battle_config.monster_skill_log == 1) - PRINTF("MOB skill use target_id=%d skill=%d lv=%d cast=%d, mob_class = %d\n", + PRINTF("MOB skill use target_id=%d skill=%d lv=%d cast=%d, mob_class = %d\n"_fmt, target->bl_id, skill_id, skill_lv, static_cast<uint32_t>(casttime.count()), md->mob_class); @@ -3190,10 +3199,10 @@ int mobskill_use_pos(dumb_ptr<mob_data> md, struct block_list bl; int skill_lv; - nullpo_ret(md); + nullpo_retz(md); ms = &skill_idx; - if (md->bl_prev == NULL) + if (md->bl_prev == nullptr) return 0; SkillID skill_id = ms->skill_id; @@ -3215,13 +3224,13 @@ int mobskill_use_pos(dumb_ptr<mob_data> md, // delay=skill_delayfix(sd, skill_get_delay( skill_id,skill_lv) ); interval_t casttime = skill_castfix(md, ms->casttime); - md->skilldelayup[ms - &mob_db[md->mob_class].skills.front()] = gettick(); + md->skilldelayup[ms - &get_mob_db(md->mob_class).skills.front()] = gettick(); md->state.skillcastcancel = ms->cancel; if (battle_config.monster_skill_log == 1) - PRINTF("MOB skill use target_pos= (%d,%d) skill=%d lv=%d cast=%d, mob_class = %d\n", - skill_x, skill_y, skill_id, skill_lv, - static_cast<uint32_t>(casttime.count()), md->mob_class); + PRINTF("MOB skill use target_pos= (%d,%d) skill=%d lv=%d cast=%d, mob_class = %d\n"_fmt, + skill_x, skill_y, skill_id, skill_lv, + static_cast<uint32_t>(casttime.count()), md->mob_class); if (casttime <= interval_t::zero()) // A skill without a cast time wont be cancelled. @@ -3229,7 +3238,7 @@ int mobskill_use_pos(dumb_ptr<mob_data> md, md->skillx = skill_x; md->skilly = skill_y; - md->skilltarget = 0; + md->skilltarget = BlockId(); md->skillid = skill_id; md->skilllv = skill_lv; md->skillidx = &skill_idx; @@ -3257,8 +3266,8 @@ int mobskill_use(dumb_ptr<mob_data> md, tick_t tick, { int max_hp; - nullpo_ret(md); - std::vector<mob_skill>& ms = mob_db[md->mob_class].skills; + nullpo_retz(md); + std::vector<mob_skill>& ms = get_mob_db(md->mob_class).skills; max_hp = battle_get_max_hp(md); @@ -3312,7 +3321,7 @@ int mobskill_use(dumb_ptr<mob_data> md, tick_t tick, if (skill_get_inf(msii.skill_id) & 2) { // 場所指定 - dumb_ptr<block_list> bl = NULL; + dumb_ptr<block_list> bl = nullptr; int x = 0, y = 0; { if (msii.target == MobSkillTarget::MST_TARGET) @@ -3334,7 +3343,7 @@ int mobskill_use(dumb_ptr<mob_data> md, tick_t tick, else { { - dumb_ptr<block_list> bl = NULL; + dumb_ptr<block_list> bl = nullptr; if (msii.target == MobSkillTarget::MST_TARGET) bl = map_id2bl(md->target_id); else @@ -3358,7 +3367,7 @@ int mobskill_use(dumb_ptr<mob_data> md, tick_t tick, */ int mobskill_event(dumb_ptr<mob_data> md, BF flag) { - nullpo_ret(md); + nullpo_retz(md); if (flag == BF::NEGATIVE_1 && mobskill_use(md, gettick(), MobSkillCondition::ANY)) @@ -3380,42 +3389,42 @@ int mobskill_event(dumb_ptr<mob_data> md, BF flag) *------------------------------------------ */ static -int mob_makedummymobdb(int mob_class) +int mob_makedummymobdb(Species mob_class) { int i; - SNPRINTF(mob_db[mob_class].name, 24, "mob%d", mob_class); - SNPRINTF(mob_db[mob_class].jname, 24, "mob%d", mob_class); - mob_db[mob_class].lv = 1; - mob_db[mob_class].max_hp = 1000; - mob_db[mob_class].max_sp = 1; - mob_db[mob_class].base_exp = 2; - mob_db[mob_class].job_exp = 1; - mob_db[mob_class].range = 1; - mob_db[mob_class].atk1 = 7; - mob_db[mob_class].atk2 = 10; - mob_db[mob_class].def = 0; - mob_db[mob_class].mdef = 0; - mob_db[mob_class].attrs[ATTR::STR] = 1; - mob_db[mob_class].attrs[ATTR::AGI] = 1; - mob_db[mob_class].attrs[ATTR::VIT] = 1; - mob_db[mob_class].attrs[ATTR::INT] = 1; - mob_db[mob_class].attrs[ATTR::DEX] = 6; - mob_db[mob_class].attrs[ATTR::LUK] = 2; - mob_db[mob_class].range2 = 10; - mob_db[mob_class].range3 = 10; - mob_db[mob_class].size = 0; // 1 - mob_db[mob_class].race = Race::formless; - mob_db[mob_class].element = LevelElement{0, Element::neutral}; - mob_db[mob_class].mode = MobMode::ZERO; - mob_db[mob_class].speed = 300; - mob_db[mob_class].adelay = 1000; - mob_db[mob_class].amotion = 500; - mob_db[mob_class].dmotion = 500; + SNPRINTF(get_mob_db(mob_class).name, 24, "mob%d"_fmt, mob_class); + SNPRINTF(get_mob_db(mob_class).jname, 24, "mob%d"_fmt, mob_class); + get_mob_db(mob_class).lv = 1; + get_mob_db(mob_class).max_hp = 1000; + get_mob_db(mob_class).max_sp = 1; + get_mob_db(mob_class).base_exp = 2; + get_mob_db(mob_class).job_exp = 1; + get_mob_db(mob_class).range = 1; + get_mob_db(mob_class).atk1 = 7; + get_mob_db(mob_class).atk2 = 10; + get_mob_db(mob_class).def = 0; + get_mob_db(mob_class).mdef = 0; + get_mob_db(mob_class).attrs[ATTR::STR] = 1; + get_mob_db(mob_class).attrs[ATTR::AGI] = 1; + get_mob_db(mob_class).attrs[ATTR::VIT] = 1; + get_mob_db(mob_class).attrs[ATTR::INT] = 1; + get_mob_db(mob_class).attrs[ATTR::DEX] = 6; + get_mob_db(mob_class).attrs[ATTR::LUK] = 2; + get_mob_db(mob_class).range2 = 10; + get_mob_db(mob_class).range3 = 10; + get_mob_db(mob_class).size = 0; // 1 + get_mob_db(mob_class).race = Race::formless; + get_mob_db(mob_class).element = LevelElement{0, Element::neutral}; + get_mob_db(mob_class).mode = MobMode::ZERO; + get_mob_db(mob_class).speed = 300; + get_mob_db(mob_class).adelay = 1000; + get_mob_db(mob_class).amotion = 500; + get_mob_db(mob_class).dmotion = 500; for (i = 0; i < 8; i++) { - mob_db[mob_class].dropitem[i].nameid = 0; - mob_db[mob_class].dropitem[i].p.num = 0; + get_mob_db(mob_class).dropitem[i].nameid = ItemNameId(); + get_mob_db(mob_class).dropitem[i].p.num = 0; } return 0; } @@ -3439,13 +3448,13 @@ bool mob_readdb(ZString filename) io::ReadFile in(filename); if (!in.is_open()) { - PRINTF("Unable to read mob db: %s\n", filename); + PRINTF("Unable to read mob db: %s\n"_fmt, filename); return false; } AString line; while (in.getline(line)) { - int mob_class; + Species mob_class; if (is_comment(line)) continue; @@ -3515,80 +3524,80 @@ bool mob_readdb(ZString filename) ) ); - if (!okay || mob_class <= 1000 || mob_class > 2000) + if (!okay || mobdb_checkid(mob_class) == Species()) { - PRINTF("bad mob line: %s\n", line); + PRINTF("bad mob line: %s\n"_fmt, line); rv = false; continue; } // TODO move this lower - mob_db[mob_class] = std::move(mdbv); + get_mob_db(mob_class) = std::move(mdbv); - if (mob_db[mob_class].base_exp < 0) - mob_db[mob_class].base_exp = 0; - else if (mob_db[mob_class].base_exp > 0 - && (mob_db[mob_class].base_exp * + if (get_mob_db(mob_class).base_exp < 0) + get_mob_db(mob_class).base_exp = 0; + else if (get_mob_db(mob_class).base_exp > 0 + && (get_mob_db(mob_class).base_exp * battle_config.base_exp_rate / 100 > 1000000000 - || mob_db[mob_class].base_exp * + || get_mob_db(mob_class).base_exp * battle_config.base_exp_rate / 100 < 0)) - mob_db[mob_class].base_exp = 1000000000; + get_mob_db(mob_class).base_exp = 1000000000; else - mob_db[mob_class].base_exp = mob_db[mob_class].base_exp * battle_config.base_exp_rate / 100; + get_mob_db(mob_class).base_exp = get_mob_db(mob_class).base_exp * battle_config.base_exp_rate / 100; - if (mob_db[mob_class].job_exp < 0) - mob_db[mob_class].job_exp = 0; - else if (mob_db[mob_class].job_exp > 0 - && (mob_db[mob_class].job_exp * battle_config.job_exp_rate / + if (get_mob_db(mob_class).job_exp < 0) + get_mob_db(mob_class).job_exp = 0; + else if (get_mob_db(mob_class).job_exp > 0 + && (get_mob_db(mob_class).job_exp * battle_config.job_exp_rate / 100 > 1000000000 - || mob_db[mob_class].job_exp * + || get_mob_db(mob_class).job_exp * battle_config.job_exp_rate / 100 < 0)) - mob_db[mob_class].job_exp = 1000000000; + get_mob_db(mob_class).job_exp = 1000000000; else - mob_db[mob_class].job_exp = mob_db[mob_class].job_exp * battle_config.job_exp_rate / 100; + get_mob_db(mob_class).job_exp = get_mob_db(mob_class).job_exp * battle_config.job_exp_rate / 100; for (int i = 0; i < 8; i++) { - int rate = mob_db[mob_class].dropitem[i].p.num; + int rate = get_mob_db(mob_class).dropitem[i].p.num; if (rate < 1) rate = 1; if (rate > 10000) rate = 10000; - mob_db[mob_class].dropitem[i].p.num = rate; + get_mob_db(mob_class).dropitem[i].p.num = rate; } - mob_db[mob_class].skills.clear(); + get_mob_db(mob_class).skills.clear(); - mob_db[mob_class].hair = 0; - mob_db[mob_class].hair_color = 0; - mob_db[mob_class].weapon = 0; - mob_db[mob_class].shield = 0; - mob_db[mob_class].head_top = 0; - mob_db[mob_class].head_mid = 0; - mob_db[mob_class].head_buttom = 0; - mob_db[mob_class].clothes_color = 0; //Add for player monster dye - Valaris + get_mob_db(mob_class).hair = 0; + get_mob_db(mob_class).hair_color = 0; + get_mob_db(mob_class).weapon = 0; + get_mob_db(mob_class).shield = ItemNameId(); + get_mob_db(mob_class).head_top = ItemNameId(); + get_mob_db(mob_class).head_mid = ItemNameId(); + get_mob_db(mob_class).head_buttom = ItemNameId(); + get_mob_db(mob_class).clothes_color = 0; //Add for player monster dye - Valaris - if (mob_db[mob_class].base_exp == 0) - mob_db[mob_class].base_exp = mob_gen_exp(&mob_db[mob_class]); + if (get_mob_db(mob_class).base_exp == 0) + get_mob_db(mob_class).base_exp = mob_gen_exp(&get_mob_db(mob_class)); } - PRINTF("read %s done\n", filename); + PRINTF("read %s done\n"_fmt, filename); } return rv; } -template<> -bool extract<MobSkillCondition, void, void>(XString str, MobSkillCondition *msc) +static +bool extract(XString str, MobSkillCondition *msc) { const struct { - ZString str; + LString str; MobSkillCondition id; } cond1[] = { - {ZString("always"), MobSkillCondition::MSC_ALWAYS}, - {ZString("myhpltmaxrate"), MobSkillCondition::MSC_MYHPLTMAXRATE}, - {ZString("notintown"), MobSkillCondition::MSC_NOTINTOWN}, - {ZString("slavelt"), MobSkillCondition::MSC_SLAVELT}, - {ZString("slavele"), MobSkillCondition::MSC_SLAVELE}, + {"always"_s, MobSkillCondition::MSC_ALWAYS}, + {"myhpltmaxrate"_s, MobSkillCondition::MSC_MYHPLTMAXRATE}, + {"notintown"_s, MobSkillCondition::MSC_NOTINTOWN}, + {"slavelt"_s, MobSkillCondition::MSC_SLAVELT}, + {"slavele"_s, MobSkillCondition::MSC_SLAVELE}, }; for (auto& pair : cond1) if (str == pair.str) @@ -3599,19 +3608,19 @@ bool extract<MobSkillCondition, void, void>(XString str, MobSkillCondition *msc) return false; } -template<> -bool extract<MobSkillState, void, void>(XString str, MobSkillState *mss) +static +bool extract(XString str, MobSkillState *mss) { const struct { - ZString str; + LString str; MobSkillState id; } state[] = { - {ZString("any"), MobSkillState::ANY}, - {ZString("idle"), MobSkillState::MSS_IDLE}, - {ZString("walk"), MobSkillState::MSS_WALK}, - {ZString("attack"), MobSkillState::MSS_ATTACK}, + {"any"_s, MobSkillState::ANY}, + {"idle"_s, MobSkillState::MSS_IDLE}, + {"walk"_s, MobSkillState::MSS_WALK}, + {"attack"_s, MobSkillState::MSS_ATTACK}, }; for (auto& pair : state) if (str == pair.str) @@ -3622,17 +3631,17 @@ bool extract<MobSkillState, void, void>(XString str, MobSkillState *mss) return false; } -template<> -bool extract<MobSkillTarget, void, void>(XString str, MobSkillTarget *mst) +static +bool extract(XString str, MobSkillTarget *mst) { const struct { - ZString str; + LString str; MobSkillTarget id; } target[] = { - {ZString("target"), MobSkillTarget::MST_TARGET}, - {ZString("self"), MobSkillTarget::MST_SELF}, + {"target"_s, MobSkillTarget::MST_TARGET}, + {"self"_s, MobSkillTarget::MST_SELF}, }; for (auto& pair : target) if (str == pair.str) @@ -3650,21 +3659,21 @@ bool mob_readskilldb(ZString filename) io::ReadFile in(filename); if (!in.is_open()) { - PRINTF("can't read %s\n", filename); + PRINTF("can't read %s\n"_fmt, filename); return false; } AString line; while (in.getline(line)) { - int mob_id; + Species mob_id; if (is_comment(line)) continue; XString blah; - if (extract(line, record<','>(&mob_id, &blah)) && mob_id > 0 && blah == "clear") + if (extract(line, record<','>(&mob_id, &blah)) && mobdb_checkid(mob_id) != Species() && blah == "clear"_s) { - mob_db[mob_id].skills.clear(); + get_mob_db(mob_id).skills.clear(); continue; } @@ -3699,9 +3708,9 @@ bool mob_readskilldb(ZString filename) ) ) continue; - if (cancellable == "yes") + if (cancellable == "yes"_s) msv.cancel = true; - else if (cancellable == "no") + else if (cancellable == "no"_s) msv.cancel = false; else { @@ -3712,15 +3721,15 @@ bool mob_readskilldb(ZString filename) msv.casttime = std::chrono::milliseconds(casttime); msv.delay = std::chrono::milliseconds(delay); - if (mob_id <= 0) + if (mobdb_checkid(mob_id) == Species()) { rv = false; continue; } - mob_db[mob_id].skills.push_back(std::move(msv)); + get_mob_db(mob_id).skills.push_back(std::move(msv)); } - PRINTF("read %s done\n", filename); + PRINTF("read %s done\n"_fmt, filename); } return rv; } @@ -3736,3 +3745,4 @@ void do_init_mob2(void) MIN_MOBTHINKTIME * 10 ).detach(); } +} // namespace tmwa diff --git a/src/map/mob.hpp b/src/map/mob.hpp index e7d81bd..d0cc07a 100644 --- a/src/map/mob.hpp +++ b/src/map/mob.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_MOB_HPP -#define TMWA_MAP_MOB_HPP +#pragma once // mob.hpp - Really scary code. // // Copyright © ????-2004 Athena Dev Teams @@ -21,22 +20,27 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "mob.t.hpp" +#include "mob.t.hpp" -# include "../generic/random.t.hpp" +#include "../generic/fwd.hpp" +#include "../generic/enum.hpp" +#include "../generic/random.t.hpp" -# include "../mmo/mmo.hpp" -# include "../mmo/timer.t.hpp" +#include "../net/timer.t.hpp" -# include "clif.t.hpp" -# include "map.hpp" -# include "skill.t.hpp" +#include "battle.t.hpp" +#include "clif.t.hpp" +#include "map.hpp" +#include "skill.t.hpp" -# define ENGLISH_NAME stringish<MobName>("--en--") -# define JAPANESE_NAME stringish<MobName>("--ja--") -# define MOB_THIS_MAP stringish<MapName>("this") + +namespace tmwa +{ +#define ENGLISH_NAME stringish<MobName>("--en--"_s) +#define JAPANESE_NAME stringish<MobName>("--ja--"_s) +#define MOB_THIS_MAP stringish<MapName>("this"_s) struct mob_skill { @@ -72,41 +76,43 @@ struct mob_db_ int mutations_nr, mutation_power; struct { - int nameid; + ItemNameId nameid; random_::Fixed<int, 10000> p; } dropitem[8]; - short hair, hair_color, weapon, shield, head_top, head_mid, head_buttom, option, clothes_color; // [Valaris] + short hair, hair_color, weapon; + ItemNameId shield, head_top, head_mid, head_buttom; + short option, clothes_color; // [Valaris] int equip; // [Valaris] std::vector<struct mob_skill> skills; }; -extern struct mob_db_ mob_db[]; +struct mob_db_& get_mob_db(Species); -int mobdb_searchname(MobName str); -int mobdb_checkid(const int id); -int mob_once_spawn(dumb_ptr<map_session_data> sd, +Species mobdb_searchname(MobName str); +Species mobdb_checkid(Species id); +BlockId mob_once_spawn(dumb_ptr<map_session_data> sd, MapName mapname, int x, int y, - MobName mobname, int class_, int amount, + MobName mobname, Species class_, int amount, NpcEvent event); -int mob_once_spawn_area(dumb_ptr<map_session_data> sd, +BlockId mob_once_spawn_area(dumb_ptr<map_session_data> sd, MapName mapname, int x0, int y0, int x1, int y1, - MobName mobname, int class_, int amount, + MobName mobname, Species class_, int amount, NpcEvent event); int mob_target(dumb_ptr<mob_data> md, dumb_ptr<block_list> bl, int dist); int mob_stop_walking(dumb_ptr<mob_data> md, int type); int mob_stopattack(dumb_ptr<mob_data>); -int mob_spawn(int); +int mob_spawn(BlockId); int mob_damage(dumb_ptr<block_list>, dumb_ptr<mob_data>, int, int); int mob_heal(dumb_ptr<mob_data>, int); -short mob_get_hair(int); -short mob_get_hair_color(int); -short mob_get_weapon(int); -short mob_get_shield(int); -short mob_get_head_top(int); -short mob_get_head_mid(int); -short mob_get_head_buttom(int); -short mob_get_clothes_color(int); //player mob dye [Valaris] -int mob_get_equip(int); // mob equip [Valaris] +short mob_get_hair(Species); +short mob_get_hair_color(Species); +short mob_get_weapon(Species); +ItemNameId mob_get_shield(Species); +ItemNameId mob_get_head_top(Species); +ItemNameId mob_get_head_mid(Species); +ItemNameId mob_get_head_buttom(Species); +short mob_get_clothes_color(Species); //player mob dye [Valaris] +int mob_get_equip(Species); // mob equip [Valaris] bool mob_readdb(ZString filename); bool mob_readskilldb(ZString filename); @@ -114,7 +120,7 @@ void do_init_mob2(void); int mob_delete(dumb_ptr<mob_data> md); int mob_catch_delete(dumb_ptr<mob_data> md, BeingRemoveWhy type); -void mob_timer_delete(TimerData *, tick_t, int); +void mob_timer_delete(TimerData *, tick_t, BlockId); int mob_deleteslave(dumb_ptr<mob_data> md); @@ -125,10 +131,9 @@ int mob_warp(dumb_ptr<mob_data> md, map_local *m, int x, int y, BeingRemoveWhy t int mobskill_use(dumb_ptr<mob_data> md, tick_t tick, MobSkillCondition event); int mobskill_event(dumb_ptr<mob_data> md, BF flag); -void mobskill_castend_id(TimerData *tid, tick_t tick, int id); -void mobskill_castend_pos(TimerData *tid, tick_t tick, int id); +void mobskill_castend_id(TimerData *tid, tick_t tick, BlockId id); +void mobskill_castend_pos(TimerData *tid, tick_t tick, BlockId id); int mob_summonslave(dumb_ptr<mob_data> md2, int *value, int amount, int flag); void mob_reload(void); - -#endif // TMWA_MAP_MOB_HPP +} // namespace tmwa diff --git a/src/map/mob.t.hpp b/src/map/mob.t.hpp index 37fd13e..160a8a3 100644 --- a/src/map/mob.t.hpp +++ b/src/map/mob.t.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_MOB_T_HPP -#define TMWA_MAP_MOB_T_HPP +#pragma once // mob.t.hpp - Really scary code. // // Copyright © ????-2004 Athena Dev Teams @@ -21,10 +20,13 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include <cstdint> +#include <cstdint> + +namespace tmwa +{ enum class MobSkillTarget { MST_TARGET = 0, @@ -59,5 +61,4 @@ enum class MobSkillState : uint8_t MSS_LOOT, MSS_CHASE, }; - -#endif // TMWA_MAP_MOB_T_HPP +} // namespace tmwa diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 7fe13f1..a6427d6 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -21,10 +21,9 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include <cassert> -#include <cstdlib> -#include <cstring> #include <ctime> +#include <algorithm> #include <list> #include "../compat/fun.hpp" @@ -34,16 +33,20 @@ #include "../strings/astring.hpp" #include "../strings/zstring.hpp" #include "../strings/xstring.hpp" +#include "../strings/literal.hpp" #include "../generic/db.hpp" #include "../io/cxxstdio.hpp" #include "../io/read.hpp" +#include "../net/timer.hpp" + #include "../mmo/config_parse.hpp" #include "../mmo/extract.hpp" -#include "../mmo/socket.hpp" -#include "../mmo/timer.hpp" +#include "../mmo/utils.hpp" + +#include "../proto2/map-user.hpp" #include "battle.hpp" #include "clif.hpp" @@ -56,17 +59,22 @@ #include "../poison.hpp" + +namespace tmwa +{ static std::list<AString> npc_srcs; static -int npc_id = START_NPC_NUM; +BlockId npc_id = START_NPC_NUM; static int npc_warp, npc_shop, npc_script, npc_mob; -int npc_get_new_npc_id(void) +BlockId npc_get_new_npc_id(void) { - return npc_id++; + BlockId rv = npc_id; + npc_id = next(npc_id); + return rv; } struct event_data @@ -107,7 +115,7 @@ void npc_enable_sub(dumb_ptr<block_list> bl, dumb_ptr<npc_data> nd) NpcEvent aname; aname.npc = nd->name; - aname.label = stringish<ScriptLabel>("OnTouch"); + aname.label = stringish<ScriptLabel>("OnTouch"_s); if (sd->areanpc_id == nd->bl_id) return; sd->areanpc_id = nd->bl_id; @@ -118,9 +126,9 @@ void npc_enable_sub(dumb_ptr<block_list> bl, dumb_ptr<npc_data> nd) int npc_enable(NpcName name, bool flag) { dumb_ptr<npc_data> nd = npc_name2id(name); - if (nd == NULL) + if (nd == nullptr) { - PRINTF("npc_enable(%s, %s) failed.\n", name, flag ? "true" : "false"); + PRINTF("npc_enable(%s, %s) failed.\n"_fmt, name, flag ? "true"_s : "false"_s); return 0; } @@ -167,15 +175,15 @@ dumb_ptr<npc_data> npc_name2id(NpcName name) */ int npc_event_dequeue(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); - sd->npc_id = 0; + sd->npc_id = BlockId(); if (!sd->eventqueuel.empty()) { - if (!pc_addeventtimer(sd, std::chrono::milliseconds(100), sd->eventqueuel.front())) + if (!pc_addeventtimer(sd, 100_ms, sd->eventqueuel.front())) { - PRINTF("npc_event_dequeue(): Event timer is full.\n"); + PRINTF("npc_event_dequeue(): Event timer is full.\n"_fmt); return 0; } @@ -190,7 +198,7 @@ int npc_delete(dumb_ptr<npc_data> nd) { nullpo_retr(1, nd); - if (nd->bl_prev == NULL) + if (nd->bl_prev == nullptr) return 1; clif_clearchar(nd, BeingRemoveWhy::DEAD); @@ -204,9 +212,9 @@ void npc_timer_event(NpcEvent eventname) dumb_ptr<npc_data_script> nd; // int xs,ys; - if ((ev == NULL || (nd = ev->nd) == NULL)) + if ((ev == nullptr || (nd = ev->nd) == nullptr)) { - PRINTF("npc_event: event not found [%s]\n", + PRINTF("npc_event: event not found [%s]\n"_fmt, eventname); return; } @@ -220,7 +228,7 @@ void npc_timer_event(NpcEvent eventname) */ static void npc_event_doall_sub(NpcEvent key, struct event_data *ev, - int *c, ScriptLabel name, int rid, Slice<argrec_t> argv) + int *c, ScriptLabel name, BlockId rid, Slice<argrec_t> argv) { ScriptLabel p = key.label; @@ -234,7 +242,7 @@ void npc_event_doall_sub(NpcEvent key, struct event_data *ev, } } -int npc_event_doall_l(ScriptLabel name, int rid, Slice<argrec_t> args) +int npc_event_doall_l(ScriptLabel name, BlockId rid, Slice<argrec_t> args) { int c = 0; @@ -245,7 +253,7 @@ int npc_event_doall_l(ScriptLabel name, int rid, Slice<argrec_t> args) static void npc_event_do_sub(NpcEvent key, struct event_data *ev, - int *c, NpcEvent name, int rid, Slice<argrec_t> argv) + int *c, NpcEvent name, BlockId rid, Slice<argrec_t> argv) { nullpo_retv(ev); @@ -257,7 +265,7 @@ void npc_event_do_sub(NpcEvent key, struct event_data *ev, } } -int npc_event_do_l(NpcEvent name, int rid, Slice<argrec_t> args) +int npc_event_do_l(NpcEvent name, BlockId rid, Slice<argrec_t> args) { int c = 0; @@ -283,19 +291,19 @@ void npc_event_do_clock(TimerData *, tick_t) ScriptLabel buf; if (t.tm_min != ev_tm_b.tm_min) { - SNPRINTF(buf, 24, "OnMinute%02d", t.tm_min); + SNPRINTF(buf, 24, "OnMinute%02d"_fmt, t.tm_min); npc_event_doall(buf); - SNPRINTF(buf, 24, "OnClock%02d%02d", t.tm_hour, t.tm_min); + SNPRINTF(buf, 24, "OnClock%02d%02d"_fmt, t.tm_hour, t.tm_min); npc_event_doall(buf); } if (t.tm_hour != ev_tm_b.tm_hour) { - SNPRINTF(buf, 24, "OnHour%02d", t.tm_hour); + SNPRINTF(buf, 24, "OnHour%02d"_fmt, t.tm_hour); npc_event_doall(buf); } if (t.tm_mday != ev_tm_b.tm_mday) { - SNPRINTF(buf, 24, "OnDay%02d%02d", t.tm_mon + 1, t.tm_mday); + SNPRINTF(buf, 24, "OnDay%02d%02d"_fmt, t.tm_mon + 1, t.tm_mday); npc_event_doall(buf); } ev_tm_b = t; @@ -307,12 +315,12 @@ void npc_event_do_clock(TimerData *, tick_t) */ int npc_event_do_oninit(void) { - int c = npc_event_doall(stringish<ScriptLabel>("OnInit")); - PRINTF("npc: OnInit Event done. (%d npc)\n", c); + int c = npc_event_doall(stringish<ScriptLabel>("OnInit"_s)); + PRINTF("npc: OnInit Event done. (%d npc)\n"_fmt, c); - Timer(gettick() + std::chrono::milliseconds(100), + Timer(gettick() + 100_ms, npc_event_do_clock, - std::chrono::seconds(1) + 1_s ).detach(); return 0; @@ -322,10 +330,10 @@ int npc_event_do_oninit(void) /// This will be called later if you call npc_timerevent_start. /// This function may only expire, but not deactivate, the counter. static -void npc_timerevent(TimerData *, tick_t tick, int id, interval_t data) +void npc_timerevent(TimerData *, tick_t tick, BlockId id, interval_t data) { dumb_ptr<npc_data_script> nd = map_id2bl(id)->is_npc()->is_script(); - assert (nd != NULL); + assert (nd != nullptr); assert (nd->npc_subtype == NpcSubtype::SCRIPT); assert (nd->scr.next_event != nd->scr.timer_eventv.end()); @@ -345,7 +353,7 @@ void npc_timerevent(TimerData *, tick_t tick, int id, interval_t data) id, next)); } - run_script(ScriptPointer(nd->scr.script.get(), te->pos), 0, nd->bl_id); + run_script(ScriptPointer(nd->scr.script.get(), te->pos), BlockId(), nd->bl_id); } /// Start (or resume) counting ticks to the next npc_timerevent. @@ -461,15 +469,15 @@ int npc_event(dumb_ptr<map_session_data> sd, NpcEvent eventname, dumb_ptr<npc_data_script> nd; int xs, ys; - if (sd == NULL) + if (sd == nullptr) { - PRINTF("npc_event nullpo?\n"); + PRINTF("npc_event nullpo?\n"_fmt); } - if (ev == NULL && eventname.label == stringish<ScriptLabel>("OnTouch")) + if (ev == nullptr && eventname.label == stringish<ScriptLabel>("OnTouch"_s)) return 1; - if (ev == NULL || (nd = ev->nd) == NULL) + if (ev == nullptr || (nd = ev->nd) == nullptr) { if (mob_kill) { @@ -480,7 +488,7 @@ int npc_event(dumb_ptr<map_session_data> sd, NpcEvent eventname, else { if (battle_config.error_log) - PRINTF("npc_event: event not found [%s]\n", + PRINTF("npc_event: event not found [%s]\n"_fmt, eventname); return 0; } @@ -500,7 +508,7 @@ int npc_event(dumb_ptr<map_session_data> sd, NpcEvent eventname, return 1; } - if (sd->npc_id != 0) + if (sd->npc_id) { sd->eventqueuel.push_back(eventname); return 1; @@ -521,12 +529,12 @@ static void npc_command_sub(NpcEvent key, struct event_data *ev, NpcName npcname, XString command) { if (ev->nd->name == npcname - && key.label.startswith("OnCommand")) + && key.label.startswith("OnCommand"_s)) { XString temp = key.label.xslice_t(9); if (command == temp) - run_script(ScriptPointer(ev->nd->scr.script.get(), ev->pos), 0, ev->nd->bl_id); + run_script(ScriptPointer(ev->nd->scr.script.get(), ev->pos), BlockId(), ev->nd->bl_id); } } @@ -567,7 +575,7 @@ int npc_touch_areanpc(dumb_ptr<map_session_data> sd, map_local *m, int x, int y) ys = m->npc[i]->is_warp()->warp.ys; break; case NpcSubtype::MESSAGE: - assert (0 && "I'm pretty sure these are never put on a map"); + assert (0 && "I'm pretty sure these are never put on a map"_s); xs = 0; ys = 0; break; @@ -589,7 +597,7 @@ int npc_touch_areanpc(dumb_ptr<map_session_data> sd, map_local *m, int x, int y) if (f) { if (battle_config.error_log) - PRINTF("npc_touch_areanpc : some bug \n"); + PRINTF("npc_touch_areanpc : some bug \n"_fmt); } return 1; } @@ -601,13 +609,13 @@ int npc_touch_areanpc(dumb_ptr<map_session_data> sd, map_local *m, int x, int y) m->npc[i]->is_warp()->warp.x, m->npc[i]->is_warp()->warp.y, BeingRemoveWhy::GONE); break; case NpcSubtype::MESSAGE: - assert (0 && "I'm pretty sure these NPCs are never put on a map."); + assert (0 && "I'm pretty sure these NPCs are never put on a map."_s); break; case NpcSubtype::SCRIPT: { NpcEvent aname; aname.npc = m->npc[i]->name; - aname.label = stringish<ScriptLabel>("OnTouch"); + aname.label = stringish<ScriptLabel>("OnTouch"_s); if (sd->areanpc_id == m->npc[i]->bl_id) return 1; @@ -626,20 +634,20 @@ int npc_touch_areanpc(dumb_ptr<map_session_data> sd, map_local *m, int x, int y) *------------------------------------------ */ static -int npc_checknear(dumb_ptr<map_session_data> sd, int id) +int npc_checknear(dumb_ptr<map_session_data> sd, BlockId id) { dumb_ptr<npc_data> nd; - nullpo_ret(sd); + nullpo_retz(sd); nd = map_id_is_npc(id); // this actually happens - if (nd == NULL) + if (nd == nullptr) return 1; if (nd->bl_type != BL::NPC) return 1; - if (nd->npc_class < 0) // イベント系は常にOK + if (nd->npc_class == NEGATIVE_SPECIES) return 0; // エリア判定 @@ -657,16 +665,16 @@ int npc_checknear(dumb_ptr<map_session_data> sd, int id) * クリック時のNPC処理 *------------------------------------------ */ -int npc_click(dumb_ptr<map_session_data> sd, int id) +int npc_click(dumb_ptr<map_session_data> sd, BlockId id) { dumb_ptr<npc_data> nd; nullpo_retr(1, sd); - if (sd->npc_id != 0) + if (sd->npc_id) { if (battle_config.error_log) - PRINTF("npc_click: npc_id != 0\n"); + PRINTF("npc_click: npc_id != 0\n"_fmt); return 1; } @@ -706,7 +714,7 @@ int npc_click(dumb_ptr<map_session_data> sd, int id) * *------------------------------------------ */ -int npc_scriptcont(dumb_ptr<map_session_data> sd, int id) +int npc_scriptcont(dumb_ptr<map_session_data> sd, BlockId id) { dumb_ptr<npc_data> nd; @@ -738,7 +746,7 @@ int npc_scriptcont(dumb_ptr<map_session_data> sd, int id) * *------------------------------------------ */ -int npc_buysellsel(dumb_ptr<map_session_data> sd, int id, int type) +int npc_buysellsel(dumb_ptr<map_session_data> sd, BlockId id, int type) { dumb_ptr<npc_data> nd; @@ -751,8 +759,8 @@ int npc_buysellsel(dumb_ptr<map_session_data> sd, int id, int type) if (nd->npc_subtype != NpcSubtype::SHOP) { if (battle_config.error_log) - PRINTF("no such shop npc : %d\n", id); - sd->npc_id = 0; + PRINTF("no such shop npc : %d\n"_fmt, id); + sd->npc_id = BlockId(); return 1; } if (nd->flag & 1) // 無効化されている @@ -775,15 +783,14 @@ int npc_buysellsel(dumb_ptr<map_session_data> sd, int id, int type) *------------------------------------------ */ // TODO enumify return type -int npc_buylist(dumb_ptr<map_session_data> sd, int n, - const uint16_t *item_list) +int npc_buylist(dumb_ptr<map_session_data> sd, + const std::vector<Packet_Repeat<0x00c8>>& item_list) { dumb_ptr<npc_data> nd; double z; int i, j, w, itemamount = 0, new_stacks = 0; nullpo_retr(3, sd); - nullpo_retr(3, item_list); if (npc_checknear(sd, sd->npc_shopid)) return 3; @@ -792,26 +799,29 @@ int npc_buylist(dumb_ptr<map_session_data> sd, int n, if (nd->npc_subtype != NpcSubtype::SHOP) return 3; - for (i = 0, w = 0, z = 0; i < n; i++) + for (i = 0, w = 0, z = 0; i < item_list.size(); i++) { + const uint16_t& item_l_count = item_list[i].count; + const ItemNameId& item_l_id = item_list[i].name_id; + for (j = 0; j < nd->is_shop()->shop_items.size(); j++) { - if (nd->is_shop()->shop_items[j].nameid == item_list[i * 2 + 1]) + if (nd->is_shop()->shop_items[j].nameid == item_l_id) break; } if (j == nd->is_shop()->shop_items.size()) return 3; - z += static_cast<double>(nd->is_shop()->shop_items[j].value) * item_list[i * 2]; - itemamount += item_list[i * 2]; + z += static_cast<double>(nd->is_shop()->shop_items[j].value) * item_l_count; + itemamount += item_l_count; - switch (pc_checkadditem(sd, item_list[i * 2 + 1], item_list[i * 2])) + switch (pc_checkadditem(sd, item_l_id, item_l_count)) { case ADDITEM::EXIST: break; case ADDITEM::NEW: - if (itemdb_isequip(item_list[i * 2 + 1])) - new_stacks += item_list[i * 2]; + if (itemdb_isequip(item_l_id)) + new_stacks += item_l_count; else new_stacks++; break; @@ -819,7 +829,7 @@ int npc_buylist(dumb_ptr<map_session_data> sd, int n, return 2; } - w += itemdb_weight(item_list[i * 2 + 1]) * item_list[i * 2]; + w += itemdb_weight(item_l_id) * item_l_count; } if (z > static_cast<double>(sd->status.zeny)) @@ -828,18 +838,21 @@ int npc_buylist(dumb_ptr<map_session_data> sd, int n, return 2; // 重量超過 if (pc_inventoryblank(sd) < new_stacks) return 3; // 種類数超過 - if (sd->trade_partner != 0) + if (sd->trade_partner) return 4; // cant buy while trading pc_payzeny(sd, static_cast<int>(z)); - for (i = 0; i < n; i++) + for (i = 0; i < item_list.size(); i++) { + const uint16_t& item_l_count = item_list[i].count; + const ItemNameId& item_l_id = item_list[i].name_id; + struct item_data *item_data; - if ((item_data = itemdb_exists(item_list[i * 2 + 1])) != NULL) + if ((item_data = itemdb_exists(item_l_id)) != nullptr) { - int amount = item_list[i * 2]; - struct item item_tmp {}; + int amount = item_l_count; + Item item_tmp {}; item_tmp.nameid = item_data->nameid; @@ -868,39 +881,37 @@ int npc_buylist(dumb_ptr<map_session_data> sd, int n, * *------------------------------------------ */ -int npc_selllist(dumb_ptr<map_session_data> sd, int n, - const uint16_t *item_list) +int npc_selllist(dumb_ptr<map_session_data> sd, + const std::vector<Packet_Repeat<0x00c9>>& item_list) { double z; int i, itemamount = 0; nullpo_retr(1, sd); - nullpo_retr(1, item_list); if (npc_checknear(sd, sd->npc_shopid)) return 1; - for (i = 0, z = 0; i < n; i++) + for (i = 0, z = 0; i < item_list.size(); i++) { - int nameid; - if (item_list[i * 2] - 2 < 0 || item_list[i * 2] - 2 >= MAX_INVENTORY) + if (!item_list[i].ioff2.ok()) return 1; - nameid = sd->status.inventory[item_list[i * 2] - 2].nameid; - if (nameid == 0 || - sd->status.inventory[item_list[i * 2] - 2].amount < item_list[i * 2 + 1]) + ItemNameId nameid = sd->status.inventory[item_list[i].ioff2.unshift()].nameid; + if (!nameid || + sd->status.inventory[item_list[i].ioff2.unshift()].amount < item_list[i].count) return 1; - if (sd->trade_partner != 0) + if (sd->trade_partner) return 2; // cant sell while trading - z += static_cast<double>(itemdb_value_sell(nameid)) * item_list[i * 2 + 1]; - itemamount += item_list[i * 2 + 1]; + z += static_cast<double>(itemdb_value_sell(nameid)) * item_list[i].count; + itemamount += item_list[i].count; } if (z > MAX_ZENY) z = MAX_ZENY; pc_getzeny(sd, static_cast<int>(z)); - for (i = 0; i < n; i++) + for (i = 0; i < item_list.size(); i++) { - int item_id = item_list[i * 2] - 2; - pc_delitem(sd, item_id, item_list[i * 2 + 1], 0); + IOff0 item_id = item_list[i].ioff2.unshift(); + pc_delitem(sd, item_id, item_list[i].count, 0); } return 0; @@ -927,7 +938,7 @@ void npc_clearsrcfile(void) */ void npc_addsrcfile(AString name) { - if (name == "clear") + if (name == "clear"_s) { npc_clearsrcfile(); return; @@ -942,7 +953,7 @@ void npc_addsrcfile(AString name) */ void npc_delsrcfile(XString name) { - if (name == "all") + if (name == "all"_s) { npc_clearsrcfile(); return; @@ -961,19 +972,19 @@ void npc_delsrcfile(XString name) static void register_npc_name(dumb_ptr<npc_data> nd) { - ZString types[4] = - { - {"WARP"}, - {"SHOP"}, - {"SCRIPT"}, - {"MESSAGE"}, - }; + earray<LString, NpcSubtype, NpcSubtype::COUNT> types //= + {{ + "WARP"_s, + "SHOP"_s, + "SCRIPT"_s, + "MESSAGE"_s, + }}; if (!nd->name) { if (nd->npc_subtype == NpcSubtype::MESSAGE) return; - PRINTF("WARNING: npc with no name:\n%s @ %s,%d,%d\n", - types[static_cast<int>(nd->npc_subtype)], + PRINTF("WARNING: npc with no name:\n%s @ %s,%d,%d\n"_fmt, + types[nd->npc_subtype], nd->bl_m->name_, nd->bl_x, nd->bl_y); return; } @@ -982,12 +993,12 @@ void register_npc_name(dumb_ptr<npc_data> nd) if (nd->npc_subtype != NpcSubtype::WARP || nd_old->npc_subtype != NpcSubtype::WARP) { - PRINTF("WARNING: replacing npc with name: %s\n", nd->name); - PRINTF("old: %s @ %s,%d,%d\n", - types[static_cast<int>(nd_old->npc_subtype)], + PRINTF("WARNING: replacing npc with name: %s\n"_fmt, nd->name); + PRINTF("old: %s @ %s,%d,%d\n"_fmt, + types[nd_old->npc_subtype], nd_old->bl_m->name_, nd_old->bl_x, nd_old->bl_y); - PRINTF("new: %s @ %s,%d,%d\n", - types[static_cast<int>(nd->npc_subtype)], + PRINTF("new: %s @ %s,%d,%d\n"_fmt, + types[nd->npc_subtype], nd->bl_m->name_, nd->bl_x, nd->bl_y); } } @@ -1009,7 +1020,7 @@ int npc_parse_warp(XString w1, XString, NpcName w3, XString w4) if (!extract(w1, record<','>(&mapname, &x, &y)) || !extract(w4, record<','>(&xs, &ys, &to_mapname, &to_x, &to_y))) { - PRINTF("bad warp line : %s\n", w3); + PRINTF("bad warp line : %s\n"_fmt, w3); return 1; } @@ -1019,7 +1030,7 @@ int npc_parse_warp(XString w1, XString, NpcName w3, XString w4) nd->bl_id = npc_get_new_npc_id(); nd->n = map_addnpc(m, nd); - nd->bl_prev = nd->bl_next = NULL; + nd->bl_prev = nd->bl_next = nullptr; nd->bl_m = m; nd->bl_x = x; nd->bl_y = y; @@ -1031,7 +1042,7 @@ int npc_parse_warp(XString w1, XString, NpcName w3, XString w4) nd->npc_class = WARP_CLASS; else nd->npc_class = WARP_DEBUG_CLASS; - nd->speed = std::chrono::milliseconds(200); + nd->speed = 200_ms; nd->option = Option::ZERO; nd->opt1 = Opt1::ZERO; nd->opt2 = Opt2::ZERO; @@ -1059,7 +1070,6 @@ int npc_parse_warp(XString w1, XString, NpcName w3, XString w4) } } -// PRINTF("warp npc %s %d read done\n",mapname,nd->bl_id); npc_warp++; nd->bl_type = BL::NPC; nd->npc_subtype = NpcSubtype::WARP; @@ -1077,11 +1087,11 @@ bool extract(XString xs, npc_item_list *itv) if (!extract(xs, record<':'>(&name_or_id, &itv->value))) return false; struct item_data *id = nullptr; - if (extract(name_or_id, &itv->nameid) && itv->nameid > 0) + if (extract(name_or_id, &itv->nameid) && itv->nameid) goto return_true; id = itemdb_searchname(name_or_id.rstrip()); - if (id == NULL) + if (id == nullptr) return false; itv->nameid = id->nameid; goto return_true; @@ -1089,7 +1099,7 @@ bool extract(XString xs, npc_item_list *itv) return_true: if (itv->value < 0) { - if (id == NULL) + if (id == nullptr) id = itemdb_search(itv->nameid); itv->value = id->value_buy * abs(itv->value); } @@ -1108,7 +1118,7 @@ int npc_parse_shop(XString w1, XString, NpcName w3, ZString w4a) MapName mapname; dumb_ptr<npc_data_shop> nd; ZString::iterator w4comma; - int npc_class; + Species npc_class; int dir_; // TODO use enum directly in extract if (!extract(w1, record<','>(&mapname, &x, &y, &dir_)) @@ -1116,7 +1126,7 @@ int npc_parse_shop(XString w1, XString, NpcName w3, ZString w4a) || (w4comma = std::find(w4a.begin(), w4a.end(), ',')) == w4a.end() || !extract(w4a.xislice_h(w4comma), &npc_class)) { - PRINTF("bad shop line : %s\n", w3); + PRINTF("bad shop line : %s\n"_fmt, w3); return 1; } dir = static_cast<DIR>(dir_); @@ -1127,8 +1137,8 @@ int npc_parse_shop(XString w1, XString, NpcName w3, ZString w4a) if (!extract(w4b, vrec<','>(&nd->shop_items))) { - PRINTF("bad shop items : %s\n", w3); - PRINTF(" somewhere --> %s\n", w4b); + PRINTF("bad shop items : %s\n"_fmt, w3); + PRINTF(" somewhere --> %s\n"_fmt, w4b); nd->shop_items.clear(); } @@ -1138,7 +1148,7 @@ int npc_parse_shop(XString w1, XString, NpcName w3, ZString w4a) return 1; } - nd->bl_prev = nd->bl_next = NULL; + nd->bl_prev = nd->bl_next = nullptr; nd->bl_m = m; nd->bl_x = x; nd->bl_y = y; @@ -1147,7 +1157,7 @@ int npc_parse_shop(XString w1, XString, NpcName w3, ZString w4a) nd->flag = 0; nd->name = w3; nd->npc_class = npc_class; - nd->speed = std::chrono::milliseconds(200); + nd->speed = 200_ms; nd->option = Option::ZERO; nd->opt1 = Opt1::ZERO; nd->opt2 = Opt2::ZERO; @@ -1190,13 +1200,14 @@ int npc_parse_script(XString w1, XString w2, NpcName w3, ZString w4, int x, y; DIR dir = DIR::S; map_local *m; - int xs = 0, ys = 0, npc_class = 0; // [Valaris] thanks to fov + int xs = 0, ys = 0; // [Valaris] thanks to fov + Species npc_class; MapName mapname; - std::unique_ptr<const ScriptBuffer> script = NULL; + std::unique_ptr<const ScriptBuffer> script = nullptr; dumb_ptr<npc_data_script> nd; int evflag = 0; - if (w1 == "-") + if (w1 == "-"_s) { x = 0; y = 0; @@ -1207,16 +1218,16 @@ int npc_parse_script(XString w1, XString w2, NpcName w3, ZString w4, int dir_; // TODO use enum directly in extract if (!extract(w1, record<','>(&mapname, &x, &y, &dir_)) || dir_ < 0 || dir_ >= 8 - || (w2 == "script" && !w4.contains(','))) + || (w2 == "script"_s && !w4.contains(','))) { - PRINTF("bad script line : %s\n", w3); + PRINTF("bad script line : %s\n"_fmt, w3); return 1; } dir = static_cast<DIR>(dir_); m = map_mapname2mapid(mapname); } - if (w2 == "script") + if (w2 == "script"_s) { // may be empty MString srcbuf; @@ -1249,13 +1260,13 @@ int npc_parse_script(XString w1, XString w2, NpcName w3, ZString w4, srcbuf += '\n'; } script = parse_script(AString(srcbuf), startline, false); - if (script == NULL) + if (script == nullptr) // script parse error? return 1; } else { - assert(0 && "duplicate() is no longer supported!\n"); + assert(0 && "duplicate() is no longer supported!\n"_s); return 0; } @@ -1271,7 +1282,7 @@ int npc_parse_script(XString w1, XString w2, NpcName w3, ZString w4, if (ys >= 0) ys = ys * 2 + 1; - if (npc_class >= 0) + if (npc_class != NEGATIVE_SPECIES) { for (int i = 0; i < ys; i++) @@ -1295,26 +1306,31 @@ int npc_parse_script(XString w1, XString w2, NpcName w3, ZString w4, } else { - npc_class = atoi(w4.c_str()); + XString w4x = w4; + if (w4x.endswith(',')) + w4x = w4x.xrslice_h(1); + if (!extract(w4x, &npc_class)) + abort(); nd->scr.xs = 0; nd->scr.ys = 0; } - if (npc_class < 0 && m != nullptr) + if (npc_class == NEGATIVE_SPECIES && m != nullptr) { evflag = 1; } if (w3.contains(':')) { - assert(false && "feature removed"); + assert(false && "feature removed"_s); abort(); } + { nd->name = w3; } - nd->bl_prev = nd->bl_next = NULL; + nd->bl_prev = nd->bl_next = nullptr; nd->bl_m = m; nd->bl_x = x; nd->bl_y = y; @@ -1322,14 +1338,13 @@ int npc_parse_script(XString w1, XString w2, NpcName w3, ZString w4, nd->dir = dir; nd->flag = 0; nd->npc_class = npc_class; - nd->speed = std::chrono::milliseconds(200); + nd->speed = 200_ms; nd->scr.script = std::move(script); nd->option = Option::ZERO; nd->opt1 = Opt1::ZERO; nd->opt2 = Opt2::ZERO; nd->opt3 = Opt3::ZERO; - //PRINTF("script npc %s %d %d read done\n",mapname,nd->bl_id,nd->class); npc_script++; nd->bl_type = BL::NPC; nd->npc_subtype = NpcSubtype::SCRIPT; @@ -1361,7 +1376,7 @@ int npc_parse_script(XString w1, XString w2, NpcName w3, ZString w4, ScriptLabel lname = el.name; int pos = el.pos; - if (lname.startswith("On")) + if (lname.startswith("On"_s)) { struct event_data ev {}; ev.nd = nd; @@ -1380,7 +1395,7 @@ int npc_parse_script(XString w1, XString w2, NpcName w3, ZString w4, int t_ = 0; ScriptLabel lname = el.name; int pos = el.pos; - if (lname.startswith("OnTimer") && extract(lname.xslice_t(7), &t_) && t_ > 0) + if (lname.startswith("OnTimer"_s) && extract(lname.xslice_t(7), &t_) && t_ > 0) { interval_t t = static_cast<interval_t>(t_); @@ -1440,7 +1455,7 @@ int npc_parse_function(XString, XString, XString w3, ZString, srcbuf += '\n'; } std::unique_ptr<const ScriptBuffer> script = parse_script(AString(srcbuf), startline, false); - if (script == NULL) + if (script == nullptr) { // script parse error? return 1; @@ -1458,7 +1473,8 @@ int npc_parse_function(XString, XString, XString w3, ZString, static int npc_parse_mob(XString w1, XString, MobName w3, ZString w4) { - int x, y, xs, ys, mob_class, num; + int x, y, xs, ys, num; + Species mob_class; int i; MapName mapname; NpcEvent eventname; @@ -1469,7 +1485,7 @@ int npc_parse_mob(XString w1, XString, MobName w3, ZString w4) if (!extract(w1, record<',', 3>(&mapname, &x, &y, &xs, &ys)) || !extract(w4, record<',', 2>(&mob_class, &num, &delay1_, &delay2_, &eventname))) { - PRINTF("bad monster line : %s\n", w3); + PRINTF("bad monster line : %s\n"_fmt, w3); return 1; } interval_t delay1 = std::chrono::milliseconds(delay1_); @@ -1487,15 +1503,15 @@ int npc_parse_mob(XString w1, XString, MobName w3, ZString w4) { md.new_(); - md->bl_prev = NULL; - md->bl_next = NULL; + md->bl_prev = nullptr; + md->bl_next = nullptr; md->bl_m = m; md->bl_x = x; md->bl_y = y; if (w3 == ENGLISH_NAME) - md->name = mob_db[mob_class].name; + md->name = get_mob_db(mob_class).name; else if (w3 == JAPANESE_NAME) - md->name = mob_db[mob_class].jname; + md->name = get_mob_db(mob_class).jname; else md->name = w3; @@ -1512,8 +1528,8 @@ int npc_parse_mob(XString w1, XString, MobName w3, ZString w4) really_memzero_this(&md->state); // md->timer = nullptr; - md->target_id = 0; - md->attacked_id = 0; + md->target_id = BlockId(); + md->attacked_id = BlockId(); md->lootitemv.clear(); @@ -1525,7 +1541,6 @@ int npc_parse_mob(XString w1, XString, MobName w3, ZString w4) npc_mob++; } - //PRINTF("warp npc %s %d read done\n",mapname,nd->bl_id); return 0; } @@ -1561,9 +1576,9 @@ int npc_parse_mapflag(XString w1, XString, XString w3, ZString w4) if (mf == MapFlag::NOSAVE) { - if (w4 == "SavePoint") + if (w4 == "SavePoint"_s) { - m->save.map_ = stringish<MapName>("SavePoint"); + m->save.map_ = stringish<MapName>("SavePoint"_s); m->save.x = -1; m->save.y = -1; } @@ -1589,7 +1604,7 @@ int npc_parse_mapflag(XString w1, XString, XString w3, ZString w4) } dumb_ptr<npc_data> npc_spawn_text(map_local *m, int x, int y, - int npc_class, NpcName name, AString message) + Species npc_class, NpcName name, AString message) { dumb_ptr<npc_data_message> retval; retval.new_(); @@ -1605,7 +1620,7 @@ dumb_ptr<npc_data> npc_spawn_text(map_local *m, int x, int y, retval->message = message; retval->npc_class = npc_class; - retval->speed = std::chrono::milliseconds(200); + retval->speed = 200_ms; clif_spawnnpc(retval); map_addblock(retval); @@ -1679,11 +1694,11 @@ bool do_init_npc(void) io::ReadFile fp(nsl); if (!fp.is_open()) { - PRINTF("file not found : %s\n", nsl); + PRINTF("file not found : %s\n"_fmt, nsl); rv = false; continue; } - PRINTF("\rLoading NPCs [%d]: %-54s", npc_id - START_NPC_NUM, + PRINTF("\rLoading NPCs [%d]: %-54s"_fmt, unwrap<BlockId>(npc_id) - unwrap<BlockId>(START_NPC_NUM), nsl); int lines = 0; AString zline; @@ -1698,7 +1713,7 @@ bool do_init_npc(void) if (!extract(zline, record<'|', 3>(&w1, &w2, &w3, &w4x)) || !w1 || !w2 || !w3) { - FPRINTF(stderr, "%s:%d: Broken script line: %s\n", nsl, lines, zline); + FPRINTF(stderr, "%s:%d: Broken script line: %s\n"_fmt, nsl, lines, zline); rv = false; continue; } @@ -1708,7 +1723,7 @@ bool do_init_npc(void) } assert(bool(w4x) == bool(w4z)); - if (w1 != "-" && w1 != "function") + if (w1 != "-"_s && w1 != "function"_s) { auto comma = std::find(w1.begin(), w1.end(), ','); MapName mapname = stringish<MapName>(w1.xislice_h(comma)); @@ -1716,24 +1731,24 @@ bool do_init_npc(void) if (m == nullptr) { // "mapname" is not assigned to this server - FPRINTF(stderr, "%s:%d: Map not found: %s\n", nsl, lines, mapname); + FPRINTF(stderr, "%s:%d: Map not found: %s\n"_fmt, nsl, lines, mapname); rv = false; continue; } } - if (w2 == "warp") + if (w2 == "warp"_s) { NpcName npcname = stringish<NpcName>(w3); npc_parse_warp(w1, w2, npcname, w4z); } - else if (w2 == "shop") + else if (w2 == "shop"_s) { NpcName npcname = stringish<NpcName>(w3); npc_parse_shop(w1, w2, npcname, w4z); } - else if (w2 == "script") + else if (w2 == "script"_s) { - if (w1 == "function") + if (w1 == "function"_s) { npc_parse_function(w1, w2, w3, w4z, w4x, fp, &lines); @@ -1745,30 +1760,31 @@ bool do_init_npc(void) w4x, fp, &lines); } } - else if (w2 == "monster") + else if (w2 == "monster"_s) { MobName mobname = stringish<MobName>(w3); npc_parse_mob(w1, w2, mobname, w4z); } - else if (w2 == "mapflag") + else if (w2 == "mapflag"_s) { npc_parse_mapflag(w1, w2, w3, w4z); } else { - PRINTF("odd script line: %s\n", zline); + PRINTF("odd script line: %s\n"_fmt, zline); script_errors++; } } fflush(stdout); } - PRINTF("\rNPCs Loaded: %d [Warps:%d Shops:%d Scripts:%d Mobs:%d] %20s\n", - npc_id - START_NPC_NUM, npc_warp, npc_shop, npc_script, npc_mob, ""); + PRINTF("\rNPCs Loaded: %d [Warps:%d Shops:%d Scripts:%d Mobs:%d] %20s\n"_fmt, + unwrap<BlockId>(npc_id) - unwrap<BlockId>(START_NPC_NUM), npc_warp, npc_shop, npc_script, npc_mob, ""_s); if (script_errors) { - PRINTF("Cowardly refusing to continue after %d errors\n", script_errors); + PRINTF("Cowardly refusing to continue after %d errors\n"_fmt, script_errors); rv = false; } return rv; } +} // namespace tmwa diff --git a/src/map/npc.hpp b/src/map/npc.hpp index eb9a5eb..33dd378 100644 --- a/src/map/npc.hpp +++ b/src/map/npc.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_NPC_HPP -#define TMWA_MAP_NPC_HPP +#pragma once // npc.hpp - Noncombatants. // // Copyright © ????-2004 Athena Dev Teams @@ -21,47 +20,55 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include <cstddef> -# include <cstdint> +#include <cstdint> -# include "../strings/fwd.hpp" +#include "../strings/fwd.hpp" -# include "../mmo/timer.t.hpp" +#include "../generic/fwd.hpp" -# include "map.hpp" +#include "../net/timer.t.hpp" -constexpr int START_NPC_NUM = 110000000; +#include "../proto2/fwd.hpp" -constexpr int WARP_CLASS = 45; -constexpr int WARP_DEBUG_CLASS = 722; -constexpr int INVISIBLE_CLASS = 32767; +#include "map.hpp" + + +namespace tmwa +{ +constexpr BlockId START_NPC_NUM = wrap<BlockId>(110000000); + +// TODO make these species, see npc_class in npc_data +constexpr Species WARP_CLASS = wrap<Species>(45); +constexpr Species FAKE_NPC_CLASS = wrap<Species>(127); +constexpr Species WARP_DEBUG_CLASS = wrap<Species>(722); +constexpr Species INVISIBLE_CLASS = wrap<Species>(32767); int npc_event_dequeue(dumb_ptr<map_session_data> sd); int npc_event(dumb_ptr<map_session_data> sd, NpcEvent npcname, int); void npc_timer_event(NpcEvent eventname); // Added by RoVeRT int npc_command(dumb_ptr<map_session_data> sd, NpcName npcname, XString command); int npc_touch_areanpc(dumb_ptr<map_session_data>, map_local *, int, int); -int npc_click(dumb_ptr<map_session_data>, int); -int npc_scriptcont(dumb_ptr<map_session_data>, int); -int npc_buysellsel(dumb_ptr<map_session_data>, int, int); -int npc_buylist(dumb_ptr<map_session_data>, int, const uint16_t *); -int npc_selllist(dumb_ptr<map_session_data>, int, const uint16_t *); +int npc_click(dumb_ptr<map_session_data>, BlockId); +int npc_scriptcont(dumb_ptr<map_session_data>, BlockId); +int npc_buysellsel(dumb_ptr<map_session_data>, BlockId, int); +int npc_buylist(dumb_ptr<map_session_data>, const std::vector<Packet_Repeat<0x00c8>>&); +int npc_selllist(dumb_ptr<map_session_data>, const std::vector<Packet_Repeat<0x00c9>>&); int npc_parse_warp(XString w1, XString, NpcName w3, XString w4); int npc_enable(NpcName name, bool flag); dumb_ptr<npc_data> npc_name2id(NpcName name); -int npc_get_new_npc_id(void); +BlockId npc_get_new_npc_id(void); /** * Spawns and installs a talk-only NPC * - * \param message The message to speak. If message is NULL, the NPC will not do anything at all. + * \param message The message to speak. If message is nullptr, the NPC will not do anything at all. */ dumb_ptr<npc_data> npc_spawn_text(map_local *m, int x, int y, - int class_, NpcName name, AString message); + Species class_, NpcName name, AString message); /** * Uninstalls and frees an NPC @@ -73,17 +80,17 @@ void npc_delsrcfile(XString); bool do_init_npc(void); int npc_event_do_oninit(void); -int npc_event_doall_l(ScriptLabel name, int rid, Slice<argrec_t> argv); -int npc_event_do_l(NpcEvent name, int rid, Slice<argrec_t> argv); +int npc_event_doall_l(ScriptLabel name, BlockId rid, Slice<argrec_t> argv); +int npc_event_do_l(NpcEvent name, BlockId rid, Slice<argrec_t> argv); inline int npc_event_doall(ScriptLabel name) { - return npc_event_doall_l(name, 0, nullptr); + return npc_event_doall_l(name, BlockId(), nullptr); } inline int npc_event_do(NpcEvent name) { - return npc_event_do_l(name, 0, nullptr); + return npc_event_do_l(name, BlockId(), nullptr); } void npc_timerevent_start(dumb_ptr<npc_data_script> nd); @@ -91,5 +98,4 @@ void npc_timerevent_stop(dumb_ptr<npc_data_script> nd); interval_t npc_gettimerevent_tick(dumb_ptr<npc_data_script> nd); void npc_settimerevent_tick(dumb_ptr<npc_data_script> nd, interval_t newtimer); int npc_delete(dumb_ptr<npc_data> nd); - -#endif // TMWA_MAP_NPC_HPP +} // namespace tmwa diff --git a/src/map/party.cpp b/src/map/party.cpp index 75c54cf..8713c60 100644 --- a/src/map/party.cpp +++ b/src/map/party.cpp @@ -21,8 +21,6 @@ // 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 <cstring> - #include "../compat/nullpo.hpp" #include "../strings/xstring.hpp" @@ -31,23 +29,27 @@ #include "../io/cxxstdio.hpp" -#include "../mmo/socket.hpp" -#include "../mmo/timer.hpp" +#include "../net/timer.hpp" + +#include "../mmo/ids.hpp" +#include "../mmo/mmo.hpp" #include "battle.hpp" #include "clif.hpp" #include "intif.hpp" #include "map.hpp" #include "pc.hpp" -#include "tmw.hpp" #include "../poison.hpp" + +namespace tmwa +{ // 座標やHP送信の間隔 -constexpr interval_t PARTY_SEND_XYHP_INVERVAL = std::chrono::seconds(1); +constexpr interval_t PARTY_SEND_XYHP_INVERVAL = 1_s; static -Map<int, struct party> party_db; +Map<PartyId, PartyMost> party_db; static void party_check_conflict(dumb_ptr<map_session_data> sd); @@ -64,31 +66,40 @@ void do_init_party(void) } // 検索 -struct party *party_search(int party_id) +PartyPair party_search(PartyId party_id) { - return party_db.search(party_id); + PartyPair p; + p.party_most = party_db.search(party_id); + if (p) + p.party_id = party_id; + return p; } static -void party_searchname_sub(struct party *p, PartyName str, struct party **dst) +void party_searchname_sub(PartyPair p, PartyName str, PartyPair *dst) { if (p->name == str) *dst = p; } // パーティ名検索 -struct party *party_searchname(PartyName str) +PartyPair party_searchname(PartyName str) { - struct party *p = NULL; + PartyPair p; for (auto& pair : party_db) - party_searchname_sub(&pair.second, str, &p); + { + PartyPair tmp; + tmp.party_id = pair.first; + tmp.party_most = &pair.second; + party_searchname_sub(tmp, str, &p); + } return p; } /* Process a party creation request. */ int party_create(dumb_ptr<map_session_data> sd, PartyName name) { - nullpo_ret(sd); + nullpo_retz(sd); name = stringish<PartyName>(name.strip()); @@ -97,7 +108,7 @@ int party_create(dumb_ptr<map_session_data> sd, PartyName name) clif_party_created(sd, 1); /* Make sure the character isn't already in a party. */ - if (sd->status.party_id == 0) + if (!sd->status.party_id) intif_create_party(sd, name); else clif_party_created(sd, 2); @@ -106,10 +117,10 @@ int party_create(dumb_ptr<map_session_data> sd, PartyName name) } /* Relay the result of a party creation request. */ -void party_created(int account_id, int fail, int party_id, PartyName name) +void party_created(AccountId account_id, int fail, PartyId party_id, PartyName name) { dumb_ptr<map_session_data> sd; - sd = map_id2sd(account_id); + sd = map_id2sd(account_to_block(account_id)); nullpo_retv(sd); @@ -118,15 +129,15 @@ void party_created(int account_id, int fail, int party_id, PartyName name) { sd->status.party_id = party_id; - struct party *p = party_db.search(party_id); - if (p != NULL) + PartyPair p = party_search(party_id); + if (p) { - PRINTF("party_created(): ID already exists!\n"); + PRINTF("party_created(): ID already exists!\n"_fmt); exit(1); } - p = party_db.init(party_id); - p->party_id = party_id; + p.party_most = party_db.init(party_id); + p.party_id = party_id; p->name = name; /* The party was created successfully. */ @@ -138,16 +149,16 @@ void party_created(int account_id, int fail, int party_id, PartyName name) } // 情報要求 -void party_request_info(int party_id) +void party_request_info(PartyId party_id) { intif_request_partyinfo(party_id); } // 所属キャラの確認 static -int party_check_member(struct party *p) +int party_check_member(PartyPair p) { - nullpo_ret(p); + nullpo_retz(p); for (io::FD i : iter_fds()) { @@ -157,7 +168,7 @@ int party_check_member(struct party *p) map_session_data *sd = static_cast<map_session_data *>(s->session_data.get()); if (sd && sd->state.auth) { - if (sd->status.party_id == p->party_id) + if (sd->status.party_id == p.party_id) { int j, f = 1; for (j = 0; j < MAX_PARTY; j++) @@ -169,15 +180,15 @@ int party_check_member(struct party *p) else { // I can prove it was already zeroed - // p->member[j].sd = NULL; // 同垢別キャラだった + // p->member[j].sd = nullptr; // 同垢別キャラだった } } } if (f) { - sd->status.party_id = 0; + sd->status.party_id = PartyId(); if (battle_config.error_log) - PRINTF("party: check_member %d[%s] is not member\n", + PRINTF("party: check_member %d[%s] is not member\n"_fmt, sd->status_key.account_id, sd->status_key.name); } } @@ -187,7 +198,7 @@ int party_check_member(struct party *p) } // 情報所得失敗(そのIDのキャラを全部未所属にする) -int party_recv_noinfo(int party_id) +int party_recv_noinfo(PartyId party_id) { for (io::FD i : iter_fds()) { @@ -198,36 +209,36 @@ int party_recv_noinfo(int party_id) if (sd && sd->state.auth) { if (sd->status.party_id == party_id) - sd->status.party_id = 0; + sd->status.party_id = PartyId(); } } return 0; } // 情報所得 -int party_recv_info(const struct party *sp) +int party_recv_info(const PartyPair sp) { int i; - nullpo_ret(sp); + nullpo_retz(sp); - struct party *p = party_db.search(sp->party_id); - if (p == NULL) + PartyPair p = party_search(sp.party_id); + if (!p) { - p = party_db.init(sp->party_id); + p.party_most = party_db.init(sp.party_id); // 最初のロードなのでユーザーのチェックを行う - *p = *sp; + *p.party_most = *sp.party_most; party_check_member(p); } else - *p = *sp; + *p.party_most = *sp.party_most; for (i = 0; i < MAX_PARTY; i++) { // sdの設定 - dumb_ptr<map_session_data> sd = map_id2sd(p->member[i].account_id); - p->member[i].sd = (sd != NULL - && sd->status.party_id == p->party_id) ? sd.operator->() : NULL; + dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(p->member[i].account_id)); + p->member[i].sd = (sd != nullptr + && sd->status.party_id == p.party_id) ? sd.operator->() : nullptr; } clif_party_info(p, nullptr); @@ -236,7 +247,7 @@ int party_recv_info(const struct party *sp) { // 設定情報の送信 // dumb_ptr<map_session_data> sd = map_id2sd(p->member[i].account_id); dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(p->member[i].sd); - if (sd != NULL && sd->party_sended == 0) + if (sd != nullptr && sd->party_sended == 0) { clif_party_option(p, sd, 0x100); sd->party_sended = 1; @@ -247,14 +258,14 @@ int party_recv_info(const struct party *sp) } /* Process party invitation from sd to account_id. */ -int party_invite(dumb_ptr<map_session_data> sd, int account_id) +int party_invite(dumb_ptr<map_session_data> sd, AccountId account_id) { - dumb_ptr<map_session_data> tsd = map_id2sd(account_id); - struct party *p = party_search(sd->status.party_id); + dumb_ptr<map_session_data> tsd = map_id2sd(account_to_block(account_id)); + PartyPair p = party_search(sd->status.party_id); int i; int full = 1; /* Indicates whether or not there's room for one more. */ - nullpo_ret(sd); + nullpo_retz(sd); if (!tsd || !p || !tsd->sess) return 0; @@ -271,7 +282,7 @@ int party_invite(dumb_ptr<map_session_data> sd, int account_id) } /* The target player is already in a party, or has a pending invitation. */ - if (tsd->status.party_id > 0 || tsd->party_invite > 0) + if (tsd->status.party_id || tsd->party_invite) { clif_party_inviteack(sd, tsd->status_key.name, 0); return 0; @@ -311,9 +322,9 @@ int party_invite(dumb_ptr<map_session_data> sd, int account_id) } /* Process response to party invitation. */ -int party_reply_invite(dumb_ptr<map_session_data> sd, int account_id, int flag) +int party_reply_invite(dumb_ptr<map_session_data> sd, AccountId account_id, int flag) { - nullpo_ret(sd); + nullpo_retz(sd); /* There is no pending invitation. */ if (!sd->party_invite || !sd->party_invite_account) @@ -333,48 +344,48 @@ int party_reply_invite(dumb_ptr<map_session_data> sd, int account_id, int flag) else { /* This is the player who sent the invitation. */ - dumb_ptr<map_session_data> tsd = NULL; + dumb_ptr<map_session_data> tsd = nullptr; - sd->party_invite = 0; - sd->party_invite_account = 0; + sd->party_invite = PartyId(); + sd->party_invite_account = AccountId(); - if ((tsd = map_id2sd(account_id))) + if ((tsd = map_id2sd(account_to_block(account_id)))) clif_party_inviteack(tsd, sd->status_key.name, 1); } return 0; } // パーティが追加された -int party_member_added(int party_id, int account_id, int flag) +int party_member_added(PartyId party_id, AccountId account_id, int flag) { - dumb_ptr<map_session_data> sd = map_id2sd(account_id), sd2; - struct party *p = party_search(party_id); + dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(account_id)), sd2; + PartyPair p = party_search(party_id); - if (sd == NULL) + if (sd == nullptr) { if (flag == 0) { if (battle_config.error_log) - PRINTF("party: member added error %d is not online\n", + PRINTF("party: member added error %d is not online\n"_fmt, account_id); intif_party_leave(party_id, account_id); // キャラ側に登録できなかったため脱退要求を出す } return 0; } - sd2 = map_id2sd(sd->party_invite_account); - sd->party_invite = 0; - sd->party_invite_account = 0; + sd2 = map_id2sd(account_to_block(sd->party_invite_account)); + sd->party_invite = PartyId(); + sd->party_invite_account = AccountId(); - if (p == NULL) + if (!p) { - PRINTF("party_member_added: party %d not found.\n", party_id); + PRINTF("party_member_added: party %d not found.\n"_fmt, party_id); intif_party_leave(party_id, account_id); return 0; } if (flag == 1) { // 失敗 - if (sd2 != NULL) + if (sd2 != nullptr) clif_party_inviteack(sd2, sd->status_key.name, 0); return 0; } @@ -383,7 +394,7 @@ int party_member_added(int party_id, int account_id, int flag) sd->party_sended = 0; sd->status.party_id = party_id; - if (sd2 != NULL) + if (sd2 != nullptr) clif_party_inviteack(sd2, sd->status_key.name, 2); // いちおう競合確認 @@ -395,28 +406,30 @@ int party_member_added(int party_id, int account_id, int flag) } // パーティ除名要求 -int party_removemember(dumb_ptr<map_session_data> sd, int account_id) +int party_removemember(dumb_ptr<map_session_data> sd, AccountId account_id) { - struct party *p; + PartyPair p; int i; - nullpo_ret(sd); + nullpo_retz(sd); - if ((p = party_search(sd->status.party_id)) == NULL) + if (!(p = party_search(sd->status.party_id))) return 0; for (i = 0; i < MAX_PARTY; i++) { // リーダーかどうかチェック if (p->member[i].account_id == sd->status_key.account_id) + { if (p->member[i].leader == 0) return 0; + } } for (i = 0; i < MAX_PARTY; i++) { // 所属しているか調べる if (p->member[i].account_id == account_id) { - intif_party_leave(p->party_id, account_id); + intif_party_leave(p.party_id, account_id); return 0; } } @@ -426,19 +439,19 @@ int party_removemember(dumb_ptr<map_session_data> sd, int account_id) // パーティ脱退要求 int party_leave(dumb_ptr<map_session_data> sd) { - struct party *p; + PartyPair p; int i; - nullpo_ret(sd); + nullpo_retz(sd); - if ((p = party_search(sd->status.party_id)) == NULL) + if (!(p = party_search(sd->status.party_id))) return 0; for (i = 0; i < MAX_PARTY; i++) { // 所属しているか if (p->member[i].account_id == sd->status_key.account_id) { - intif_party_leave(p->party_id, sd->status_key.account_id); + intif_party_leave(p.party_id, sd->status_key.account_id); return 0; } } @@ -446,45 +459,45 @@ int party_leave(dumb_ptr<map_session_data> sd) } // パーティメンバが脱退した -int party_member_leaved(int party_id, int account_id, CharName name) +int party_member_leaved(PartyId party_id, AccountId account_id, CharName name) { - dumb_ptr<map_session_data> sd = map_id2sd(account_id); - struct party *p = party_search(party_id); - if (p != NULL) + dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(account_id)); + PartyPair p = party_search(party_id); + if (p) { int i; for (i = 0; i < MAX_PARTY; i++) if (p->member[i].account_id == account_id) { clif_party_leaved(p, sd, account_id, name, 0x00); - p->member[i].account_id = 0; - p->member[i].sd = NULL; + p->member[i].account_id = AccountId(); + p->member[i].sd = nullptr; } } - if (sd != NULL && sd->status.party_id == party_id) + if (sd != nullptr && sd->status.party_id == party_id) { - sd->status.party_id = 0; + sd->status.party_id = PartyId(); sd->party_sended = 0; } return 0; } // パーティ解散通知 -int party_broken(int party_id) +int party_broken(PartyId party_id) { - struct party *p; + PartyPair p; int i; - if ((p = party_search(party_id)) == NULL) + if (!(p = party_search(party_id))) return 0; for (i = 0; i < MAX_PARTY; i++) { - if (p->member[i].sd != NULL) + if (p->member[i].sd != nullptr) { clif_party_leaved(p, dumb_ptr<map_session_data>(p->member[i].sd), p->member[i].account_id, p->member[i].name, 0x10); - p->member[i].sd->status.party_id = 0; + p->member[i].sd->status.party_id = PartyId(); p->member[i].sd->party_sended = 0; } } @@ -495,12 +508,12 @@ int party_broken(int party_id) // パーティの設定変更要求 int party_changeoption(dumb_ptr<map_session_data> sd, int exp, int item) { - struct party *p; + PartyPair p; - nullpo_ret(sd); + nullpo_retz(sd); - if (sd->status.party_id == 0 - || (p = party_search(sd->status.party_id)) == NULL) + if (!sd->status.party_id + || !(p = party_search(sd->status.party_id))) return 0; intif_party_changeoption(sd->status.party_id, sd->status_key.account_id, exp, item); @@ -508,12 +521,12 @@ int party_changeoption(dumb_ptr<map_session_data> sd, int exp, int item) } // パーティの設定変更通知 -int party_optionchanged(int party_id, int account_id, int exp, int item, +int party_optionchanged(PartyId party_id, AccountId account_id, int exp, int item, int flag) { - struct party *p; - dumb_ptr<map_session_data> sd = map_id2sd(account_id); - if ((p = party_search(party_id)) == NULL) + PartyPair p; + dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(account_id)); + if (!(p = party_search(party_id))) return 0; if (!(flag & 0x01)) @@ -525,19 +538,19 @@ int party_optionchanged(int party_id, int account_id, int exp, int item, } // パーティメンバの移動通知 -void party_recv_movemap(int party_id, int account_id, MapName mapname, +void party_recv_movemap(PartyId party_id, AccountId account_id, MapName mapname, int online, int lv) { - struct party *p; + PartyPair p; int i; - if ((p = party_search(party_id)) == NULL) + if (!(p = party_search(party_id))) return; for (i = 0; i < MAX_PARTY; i++) { - struct party_member *m = &p->member[i]; - if (m == NULL) + PartyMember *m = &p->member[i]; + if (m == nullptr) { - PRINTF("party_recv_movemap nullpo?\n"); + PRINTF("party_recv_movemap nullpo?\n"_fmt); return; } if (m->account_id == account_id) @@ -551,16 +564,16 @@ void party_recv_movemap(int party_id, int account_id, MapName mapname, if (i == MAX_PARTY) { if (battle_config.error_log) - PRINTF("party: not found member %d on %d[%s]", account_id, + PRINTF("party: not found member %d on %d[%s]"_fmt, account_id, party_id, p->name); return; } for (i = 0; i < MAX_PARTY; i++) { // sd再設定 - dumb_ptr<map_session_data> sd = map_id2sd(p->member[i].account_id); - p->member[i].sd = (sd != NULL - && sd->status.party_id == p->party_id) ? sd.operator->() : NULL; + dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(p->member[i].account_id)); + p->member[i].sd = (sd != nullptr + && sd->status.party_id == p.party_id) ? sd.operator->() : nullptr; } party_send_xy_clear(p); // 座標再通知要請 @@ -571,11 +584,11 @@ void party_recv_movemap(int party_id, int account_id, MapName mapname, // パーティメンバの移動 int party_send_movemap(dumb_ptr<map_session_data> sd) { - struct party *p; + PartyPair p; - nullpo_ret(sd); + nullpo_retz(sd); - if (sd->status.party_id == 0) + if (!sd->status.party_id) return 0; intif_party_changemap(sd, 1); @@ -586,10 +599,10 @@ int party_send_movemap(dumb_ptr<map_session_data> sd) party_check_conflict(sd); // あるならパーティ情報送信 - if ((p = party_search(sd->status.party_id)) != NULL) + if ((p = party_search(sd->status.party_id))) { party_check_member(p); // 所属を確認する - if (sd->status.party_id == p->party_id) + if (sd->status.party_id == p.party_id) { clif_party_info(p, sd->sess); clif_party_option(p, sd, 0x100); @@ -603,20 +616,20 @@ int party_send_movemap(dumb_ptr<map_session_data> sd) // パーティメンバのログアウト int party_send_logout(dumb_ptr<map_session_data> sd) { - struct party *p; + PartyPair p; - nullpo_ret(sd); + nullpo_retz(sd); - if (sd->status.party_id > 0) + if (sd->status.party_id) intif_party_changemap(sd, 0); // sdが無効になるのでパーティ情報から削除 - if ((p = party_search(sd->status.party_id)) != NULL) + if ((p = party_search(sd->status.party_id))) { int i; for (i = 0; i < MAX_PARTY; i++) if (dumb_ptr<map_session_data>(p->member[i].sd) == sd) - p->member[i].sd = NULL; + p->member[i].sd = nullptr; } return 0; @@ -625,16 +638,16 @@ int party_send_logout(dumb_ptr<map_session_data> sd) // パーティメッセージ送信 void party_send_message(dumb_ptr<map_session_data> sd, XString mes) { - if (sd->status.party_id == 0) + if (!sd->status.party_id) return; intif_party_message(sd->status.party_id, sd->status_key.account_id, mes); } // パーティメッセージ受信 -void party_recv_message(int party_id, int account_id, XString mes) +void party_recv_message(PartyId party_id, AccountId account_id, XString mes) { - struct party *p; - if ((p = party_search(party_id)) == NULL) + PartyPair p; + if (!(p = party_search(party_id))) return; clif_party_message(p, account_id, mes); } @@ -650,7 +663,7 @@ void party_check_conflict(dumb_ptr<map_session_data> sd) // 位置やHP通知用 static -void party_send_xyhp_timer_sub(struct party *p) +void party_send_xyhp_timer_sub(PartyPair p) { int i; @@ -659,7 +672,7 @@ void party_send_xyhp_timer_sub(struct party *p) for (i = 0; i < MAX_PARTY; i++) { dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(p->member[i].sd); - if (sd != NULL) + if (sd != nullptr) { // 座標通知 if (sd->party_x != sd->bl_x || sd->party_y != sd->bl_y) @@ -683,11 +696,16 @@ void party_send_xyhp_timer_sub(struct party *p) void party_send_xyhp_timer(TimerData *, tick_t) { for (auto& pair : party_db) - party_send_xyhp_timer_sub(&pair.second); + { + PartyPair tmp; + tmp.party_id = pair.first; + tmp.party_most = &pair.second; + party_send_xyhp_timer_sub(tmp); + } } // 位置通知クリア -void party_send_xy_clear(struct party *p) +void party_send_xy_clear(PartyPair p) { int i; @@ -696,7 +714,7 @@ void party_send_xy_clear(struct party *p) for (i = 0; i < MAX_PARTY; i++) { dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(p->member[i].sd); - if (sd != NULL) + if (sd != nullptr) { sd->party_x = -1; sd->party_y = -1; @@ -706,7 +724,7 @@ void party_send_xy_clear(struct party *p) } // HP通知の必要性検査用(map_foreachinmoveareaから呼ばれる) -void party_send_hp_check(dumb_ptr<block_list> bl, int party_id, int *flag) +void party_send_hp_check(dumb_ptr<block_list> bl, PartyId party_id, int *flag) { dumb_ptr<map_session_data> sd; @@ -721,17 +739,17 @@ void party_send_hp_check(dumb_ptr<block_list> bl, int party_id, int *flag) } // 経験値公平分配 -int party_exp_share(struct party *p, map_local *mapid, int base_exp, int job_exp) +int party_exp_share(PartyPair p, map_local *mapid, int base_exp, int job_exp) { dumb_ptr<map_session_data> sd; int i, c; - nullpo_ret(p); + nullpo_retz(p); for (i = c = 0; i < MAX_PARTY; i++) { sd = dumb_ptr<map_session_data>(p->member[i].sd); - if (sd != NULL && sd->bl_m == mapid) + if (sd != nullptr && sd->bl_m == mapid) c++; } if (c == 0) @@ -739,7 +757,7 @@ int party_exp_share(struct party *p, map_local *mapid, int base_exp, int job_exp for (i = 0; i < MAX_PARTY; i++) { sd = dumb_ptr<map_session_data>(p->member[i].sd); - if (sd != NULL && sd->bl_m == mapid) + if (sd != nullptr && sd->bl_m == mapid) pc_gainexp_reason(sd, base_exp / c + 1, job_exp / c + 1, PC_GAINEXP_REASON::SHARING); } @@ -752,7 +770,7 @@ int party_exp_share(struct party *p, map_local *mapid, int base_exp, int job_exp void party_foreachsamemap(std::function<void(dumb_ptr<block_list>)> func, dumb_ptr<map_session_data> sd, int type) { - struct party *p; + PartyPair p; int i; int x0, y0, x1, y1; dumb_ptr<map_session_data> list[MAX_PARTY]; @@ -760,7 +778,7 @@ void party_foreachsamemap(std::function<void(dumb_ptr<block_list>)> func, nullpo_retv(sd); - if ((p = party_search(sd->status.party_id)) == NULL) + if (!(p = party_search(sd->status.party_id))) return; x0 = sd->bl_x - AREA_SIZE; @@ -770,8 +788,8 @@ void party_foreachsamemap(std::function<void(dumb_ptr<block_list>)> func, for (i = 0; i < MAX_PARTY; i++) { - struct party_member *m = &p->member[i]; - if (m->sd != NULL) + PartyMember *m = &p->member[i]; + if (m->sd != nullptr) { if (sd->bl_m != m->sd->bl_m) continue; @@ -789,3 +807,4 @@ void party_foreachsamemap(std::function<void(dumb_ptr<block_list>)> func, if (list[i]->bl_prev) // 有効かどうかチェック func(list[i]); } +} // namespace tmwa diff --git a/src/map/party.hpp b/src/map/party.hpp index 007de6b..01a8125 100644 --- a/src/map/party.hpp +++ b/src/map/party.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_PARTY_HPP -#define TMWA_MAP_PARTY_HPP +#pragma once // party.hpp - Small groups of temporary allies. // // Copyright © ????-2004 Athena Dev Teams @@ -21,38 +20,39 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include <functional> +#include <functional> -# include "../strings/fwd.hpp" +#include "../strings/fwd.hpp" -# include "map.hpp" +#include "../generic/fwd.hpp" -struct party; -struct map_session_data; -struct block_list; +#include "../mmo/fwd.hpp" + +namespace tmwa +{ void do_init_party(void); -struct party *party_search(int party_id); -struct party *party_searchname(PartyName str); +PartyPair party_search(PartyId party_id); +PartyPair party_searchname(PartyName str); int party_create(dumb_ptr<map_session_data> sd, PartyName name); -void party_created(int account_id, int fail, int party_id, PartyName name); -void party_request_info(int party_id); -int party_invite(dumb_ptr<map_session_data> sd, int account_id); -int party_member_added(int party_id, int account_id, int flag); +void party_created(AccountId account_id, int fail, PartyId party_id, PartyName name); +void party_request_info(PartyId party_id); +int party_invite(dumb_ptr<map_session_data> sd, AccountId account_id); +int party_member_added(PartyId party_id, AccountId account_id, int flag); int party_leave(dumb_ptr<map_session_data> sd); -int party_removemember(dumb_ptr<map_session_data> sd, int account_id); -int party_member_leaved(int party_id, int account_id, CharName name); -int party_reply_invite(dumb_ptr<map_session_data> sd, int account_id, +int party_removemember(dumb_ptr<map_session_data> sd, AccountId account_id); +int party_member_leaved(PartyId party_id, AccountId account_id, CharName name); +int party_reply_invite(dumb_ptr<map_session_data> sd, AccountId account_id, int flag); -int party_recv_noinfo(int party_id); -int party_recv_info(const struct party *sp); -void party_recv_movemap(int party_id, int account_id, MapName map, +int party_recv_noinfo(PartyId party_id); +int party_recv_info(const PartyPair sp); +void party_recv_movemap(PartyId party_id, AccountId account_id, MapName map, int online, int lv); -int party_broken(int party_id); -int party_optionchanged(int party_id, int account_id, int exp, int item, +int party_broken(PartyId party_id); +int party_optionchanged(PartyId party_id, AccountId account_id, int exp, int item, int flag); int party_changeoption(dumb_ptr<map_session_data> sd, int exp, int item); @@ -60,14 +60,13 @@ int party_send_movemap(dumb_ptr<map_session_data> sd); int party_send_logout(dumb_ptr<map_session_data> sd); void party_send_message(dumb_ptr<map_session_data> sd, XString mes); -void party_recv_message(int party_id, int account_id, XString mes); +void party_recv_message(PartyId party_id, AccountId account_id, XString mes); -void party_send_xy_clear(struct party *p); -void party_send_hp_check(dumb_ptr<block_list> bl, int party_id, int *flag); +void party_send_xy_clear(PartyPair p); +void party_send_hp_check(dumb_ptr<block_list> bl, PartyId party_id, int *flag); -int party_exp_share(struct party *p, map_local *map, int base_exp, int job_exp); +int party_exp_share(PartyPair p, map_local *map, int base_exp, int job_exp); void party_foreachsamemap(std::function<void(dumb_ptr<block_list>)> func, dumb_ptr<map_session_data> sd, int type); - -#endif // TMWA_MAP_PARTY_HPP +} // namespace tmwa diff --git a/src/map/path.cpp b/src/map/path.cpp index f0204a4..6950797 100644 --- a/src/map/path.cpp +++ b/src/map/path.cpp @@ -22,19 +22,23 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include <cassert> +#include <cstddef> +#include <cstdlib> #include "../compat/nullpo.hpp" -#include "../generic/random.hpp" +#include "../strings/literal.hpp" #include "../io/cxxstdio.hpp" -#include "battle.hpp" +#include "clif.t.hpp" +#include "map.hpp" #include "../poison.hpp" -//#define PATH_STANDALONETEST +namespace tmwa +{ constexpr int MAX_HEAP = 150; struct tmp_path { @@ -58,9 +62,9 @@ void push_heap_path(int *heap, struct tmp_path *tp, int index) { int i, h; - if (heap == NULL || tp == NULL) + if (heap == nullptr || tp == nullptr) { - PRINTF("push_heap_path nullpo\n"); + PRINTF("push_heap_path nullpo\n"_fmt); return; } @@ -90,7 +94,7 @@ void update_heap_path(int *heap, struct tmp_path *tp, int index) break; if (h == heap[0]) { - FPRINTF(stderr, "update_heap_path bug\n"); + FPRINTF(stderr, "update_heap_path bug\n"_fmt); exit(1); } for (i = (h - 1) / 2; @@ -144,7 +148,7 @@ int calc_cost(struct tmp_path *p, int x1, int y1) { int xd, yd; - nullpo_ret(p); + nullpo_retz(p); xd = x1 - p->x; if (xd < 0) @@ -165,8 +169,8 @@ int add_path(int *heap, struct tmp_path *tp, int x, int y, int dist, { int i; - nullpo_ret(heap); - nullpo_ret(tp); + nullpo_retz(heap); + nullpo_retz(tp); i = calc_index(x, y); @@ -210,7 +214,7 @@ int add_path(int *heap, struct tmp_path *tp, int x, int y, int dist, static bool can_place(struct map_local *m, int x, int y) { - nullpo_ret(m); + nullpo_retz(m); return !bool(read_gatp(m, x, y) & MapCell::UNWALKABLE); } @@ -222,7 +226,7 @@ bool can_place(struct map_local *m, int x, int y) static int can_move(struct map_local *m, int x0, int y0, int x1, int y1) { - nullpo_ret(m); + nullpo_retz(m); if (x0 - x1 < -1 || x0 - x1 > 1 || y0 - y1 < -1 || y0 - y1 > 1) return 0; @@ -249,7 +253,7 @@ int path_search(struct walkpath_data *wpd, map_local *m, int x0, int y0, int x1, int i, rp, x, y; int dx, dy; - nullpo_ret(wpd); + nullpo_retz(wpd); assert (m->gat); map_local *md = m; @@ -357,3 +361,4 @@ int path_search(struct walkpath_data *wpd, map_local *m, int x0, int y0, int x1, return -1; } } +} // namespace tmwa diff --git a/src/map/path.hpp b/src/map/path.hpp index 47b9814..3619e2e 100644 --- a/src/map/path.hpp +++ b/src/map/path.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_PATH_HPP -#define TMWA_MAP_PATH_HPP +#pragma once // path.hpp - Pathfinding system. // // Copyright © ????-2004 Athena Dev Teams @@ -21,10 +20,10 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "map.hpp" +namespace tmwa +{ int path_search(struct walkpath_data *, map_local *, int, int, int, int, int); - -#endif // TMWA_MAP_PATH_HPP +} // namespace tmwa diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 0256eff..2fa8bb7 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -23,24 +23,28 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include <cassert> -#include <cstdlib> -#include <cstring> -#include "../compat/alg.hpp" +#include <algorithm> + #include "../compat/fun.hpp" #include "../compat/nullpo.hpp" #include "../strings/rstring.hpp" #include "../strings/astring.hpp" #include "../strings/zstring.hpp" +#include "../strings/literal.hpp" #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" +#include "../io/cxxstdio_enums.hpp" #include "../io/read.hpp" -#include "../mmo/socket.hpp" -#include "../mmo/timer.hpp" +#include "../net/timer.hpp" + +#include "../mmo/utils.hpp" + +#include "../proto2/char-map.hpp" #include "atcommand.hpp" #include "battle.hpp" @@ -48,9 +52,8 @@ #include "clif.hpp" #include "intif.hpp" #include "itemdb.hpp" -#include "magic.hpp" +#include "magic-stmt.hpp" #include "map.hpp" -#include "mob.hpp" #include "npc.hpp" #include "party.hpp" #include "path.hpp" @@ -61,9 +64,12 @@ #include "../poison.hpp" + +namespace tmwa +{ // PVP順位計算の間隔 constexpr std::chrono::milliseconds PVP_CALCRANK_INTERVAL = - std::chrono::seconds(1); + 1_s; //define it here, since the ifdef only occurs in this file #define USE_ASTRAL_SOUL_SKILL @@ -86,7 +92,7 @@ constexpr int MAGIC_SKILL_THRESHOLD = 200; MAP_LOG_PC(sd, "XP %d %d JOB %d %d %d ZENY %d + %d " suffix, \ sd->status.base_level, sd->status.base_exp, \ sd->status.job_level, sd->status.job_exp, sd->status.skill_point, \ - sd->status.zeny, pc_readaccountreg(sd, stringish<VarName>("BankAccount"))) + sd->status.zeny, pc_readaccountreg(sd, stringish<VarName>("BankAccount"_s))) #define MAP_LOG_MAGIC(sd, suffix) \ MAP_LOG_PC(sd, "MAGIC %d %d %d %d %d %d EXP %d %d " suffix, \ @@ -96,8 +102,8 @@ constexpr int MAGIC_SKILL_THRESHOLD = 200; sd->status.skill[SkillID::TMW_MAGIC_TRANSMUTE].lv, \ sd->status.skill[SkillID::TMW_MAGIC_NATURE].lv, \ sd->status.skill[SkillID::TMW_MAGIC_ETHER].lv, \ - pc_readglobalreg(sd, stringish<VarName>("MAGIC_EXPERIENCE")) & 0xffff, \ - (pc_readglobalreg(sd, stringish<VarName>("MAGIC_EXPERIENCE")) >> 24) & 0xff) + pc_readglobalreg(sd, stringish<VarName>("MAGIC_EXPERIENCE"_s)) & 0xffff, \ + (pc_readglobalreg(sd, stringish<VarName>("MAGIC_EXPERIENCE"_s)) >> 24) & 0xff) static //const int max_weight_base_0 = 20000; @@ -116,23 +122,23 @@ int sp_coefficient_0 = 100; static //const earray<interval_t, ItemLook, ItemLook::SINGLE_HANDED_COUNT> aspd_base_0 //= {{ -std::chrono::milliseconds(650), -std::chrono::milliseconds(700), -std::chrono::milliseconds(750), -std::chrono::milliseconds(600), -std::chrono::milliseconds(2000), -std::chrono::milliseconds(2000), -std::chrono::milliseconds(800), -std::chrono::milliseconds(2000), -std::chrono::milliseconds(700), -std::chrono::milliseconds(700), -std::chrono::milliseconds(650), -std::chrono::milliseconds(900), -std::chrono::milliseconds(2000), -std::chrono::milliseconds(2000), -std::chrono::milliseconds(2000), -std::chrono::milliseconds(2000), -std::chrono::milliseconds(2000), +650_ms, +700_ms, +750_ms, +600_ms, +2000_ms, +2000_ms, +800_ms, +2000_ms, +700_ms, +700_ms, +650_ms, +900_ms, +2000_ms, +2000_ms, +2000_ms, +2000_ms, +2000_ms, }}; static const int exp_table_0[MAX_LEVEL] = @@ -248,8 +254,9 @@ earray<EPOS, EQUIP, EQUIP::COUNT> equip_pos //= EPOS::ARROW, }}; +// TODO use DMap<> static -std::map<int, uint8_t> gm_accountm; +std::map<AccountId, GmLevel> gm_accountm; static int pc_checkoverhp(dumb_ptr<map_session_data> sd); @@ -265,20 +272,20 @@ void pc_setdead(dumb_ptr<map_session_data> sd) sd->state.dead_sit = 1; } -uint8_t pc_isGM(dumb_ptr<map_session_data> sd) +GmLevel pc_isGM(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retr(GmLevel(), sd); auto it = gm_accountm.find(sd->status_key.account_id); if (it != gm_accountm.end()) return it->second; - return 0; + return GmLevel(); } int pc_iskiller(dumb_ptr<map_session_data> src, dumb_ptr<map_session_data> target) { - nullpo_ret(src); + nullpo_retz(src); if (src->bl_type != BL::PC) return 0; @@ -293,7 +300,7 @@ int pc_iskiller(dumb_ptr<map_session_data> src, return 0; } -void pc_set_gm_level(int account_id, uint8_t level) +void pc_set_gm_level(AccountId account_id, GmLevel level) { if (level) gm_accountm[account_id] = level; @@ -312,17 +319,17 @@ int distance(int x0, int y0, int x1, int y1) } static -void pc_invincible_timer(TimerData *, tick_t, int id) +void pc_invincible_timer(TimerData *, tick_t, BlockId id) { dumb_ptr<map_session_data> sd = map_id2sd(id); - assert (sd != NULL); + assert (sd != nullptr); assert (sd->bl_type == BL::PC); } int pc_setinvincibletimer(dumb_ptr<map_session_data> sd, interval_t val) { - nullpo_ret(sd); + nullpo_retz(sd); sd->invincible_timer = Timer(gettick() + val, std::bind(pc_invincible_timer, ph::_1, ph::_2, @@ -332,7 +339,7 @@ int pc_setinvincibletimer(dumb_ptr<map_session_data> sd, interval_t val) int pc_delinvincibletimer(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); sd->invincible_timer.cancel(); return 0; @@ -340,7 +347,7 @@ int pc_delinvincibletimer(dumb_ptr<map_session_data> sd) int pc_setrestartvalue(dumb_ptr<map_session_data> sd, int type) { - nullpo_ret(sd); + nullpo_retz(sd); { if (battle_config.restart_hp_rate < 50) @@ -380,7 +387,7 @@ int pc_setrestartvalue(dumb_ptr<map_session_data> sd, int type) */ static void pc_counttargeted_sub(dumb_ptr<block_list> bl, - int id, int *c, dumb_ptr<block_list> src, ATK target_lv) + BlockId id, int *c, dumb_ptr<block_list> src, ATK target_lv) { nullpo_retv(bl); @@ -458,7 +465,7 @@ void pc_makesavestatus(dumb_ptr<map_session_data> sd) if (sd->bl_m->flag.get(MapFlag::NOSAVE)) { map_local *m = sd->bl_m; - if (m->save.map_ == "SavePoint") + if (m->save.map_ == "SavePoint"_s) sd->status.last_point = sd->status.save_point; else sd->status.last_point = m->save; @@ -469,16 +476,21 @@ void pc_makesavestatus(dumb_ptr<map_session_data> sd) * 接続時の初期化 *------------------------------------------ */ -int pc_setnewpc(dumb_ptr<map_session_data> sd, int account_id, int char_id, - int login_id1, tick_t client_tick, SEX sex) -{ - nullpo_ret(sd); - - sd->bl_id = account_id; - sd->char_id = char_id; +int pc_setnewpc(dumb_ptr<map_session_data> sd, AccountId account_id, CharId char_id, + int login_id1, uint32_t client_tick, SEX sex) +{ + nullpo_retz(sd); + + // TODO this is the primary surface + sd->bl_id = account_to_block(account_id); + sd->char_id_ = char_id; + // TODO figure out wtf is going on here. + // shouldn't these things be in the .status_key.char_id ? + // My guess is that this stuff happens even for non-auth'ed connections + // Possible fix: char send auth before client is allowed to know my IP? sd->login_id1 = login_id1; sd->login_id2 = 0; // at this point, we can not know the value :( - sd->client_tick = client_tick; + (void)client_tick; sd->sex = sex; sd->state.auth = 0; sd->bl_type = BL::PC; @@ -489,7 +501,7 @@ int pc_setnewpc(dumb_ptr<map_session_data> sd, int account_id, int char_id, return 0; } -EPOS pc_equippoint(dumb_ptr<map_session_data> sd, int n) +EPOS pc_equippoint(dumb_ptr<map_session_data> sd, IOff0 n) { nullpo_retr(EPOS::ZERO, sd); @@ -504,13 +516,11 @@ EPOS pc_equippoint(dumb_ptr<map_session_data> sd, int n) static int pc_setinventorydata(dumb_ptr<map_session_data> sd) { - int i, id; + nullpo_retz(sd); - nullpo_ret(sd); - - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { - id = sd->status.inventory[i].nameid; + ItemNameId id = sd->status.inventory[i].nameid; sd->inventory_data[i] = itemdb_search(id); } return 0; @@ -519,7 +529,7 @@ int pc_setinventorydata(dumb_ptr<map_session_data> sd) static int pc_calcweapontype(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); if (sd->weapontype1 != ItemLook::NONE && sd->weapontype2 == ItemLook::NONE) @@ -562,14 +572,14 @@ int pc_calcweapontype(dumb_ptr<map_session_data> sd) static int pc_setequipindex(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); for (EQUIP i : EQUIPs) - sd->equip_index_maybe[i] = -1; + sd->equip_index_maybe[i] = IOff0::from(-1); - for (int i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { - if (sd->status.inventory[i].nameid <= 0) + if (!sd->status.inventory[i].nameid) continue; if (bool(sd->status.inventory[i].equip)) { @@ -608,22 +618,22 @@ int pc_setequipindex(dumb_ptr<map_session_data> sd) } static -int pc_isequip(dumb_ptr<map_session_data> sd, int n) +int pc_isequip(dumb_ptr<map_session_data> sd, IOff0 n) { struct item_data *item; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; //転生や養子の場合の元の職業を算出する - nullpo_ret(sd); + nullpo_retz(sd); item = sd->inventory_data[n]; sc_data = battle_get_sc_data(sd); - if (battle_config.gm_all_equipment > 0 - && pc_isGM(sd) >= battle_config.gm_all_equipment) + GmLevel gm_all_equipment = GmLevel::from(static_cast<uint32_t>(battle_config.gm_all_equipment)); + if (gm_all_equipment && pc_isGM(sd).satisfies(gm_all_equipment)) return 1; - if (item == NULL) + if (item == nullptr) return 0; if (item->sex != SEX::NEUTRAL && sd->status.sex != item->sex) return 0; @@ -638,16 +648,16 @@ int pc_isequip(dumb_ptr<map_session_data> sd, int n) * char鯖から送られてきたステータスを設定 *------------------------------------------ */ -int pc_authok(int id, int login_id2, TimeT connect_until_time, +int pc_authok(AccountId id, int login_id2, TimeT connect_until_time, short tmw_version, const CharKey *st_key, const CharData *st_data) { - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; - struct party *p; + PartyPair p; tick_t tick = gettick(); - sd = map_id2sd(id); - if (sd == NULL) + sd = map_id2sd(account_to_block(id)); + if (sd == nullptr) return 1; sd->login_id2 = login_id2; @@ -662,14 +672,14 @@ int pc_authok(int id, int login_id2, TimeT connect_until_time, return 1; } - MAP_LOG_STATS(sd, "LOGIN"); - MAP_LOG_XP(sd, "LOGIN"); - MAP_LOG_MAGIC(sd, "LOGIN"); + MAP_LOG_STATS(sd, "LOGIN"_fmt); + MAP_LOG_XP(sd, "LOGIN"_fmt); + MAP_LOG_MAGIC(sd, "LOGIN"_fmt); really_memzero_this(&sd->state); // 基本的な初期化 sd->state.connect_new = 1; - sd->bl_prev = sd->bl_next = NULL; + sd->bl_prev = sd->bl_next = nullptr; sd->weapontype1 = sd->weapontype2 = ItemLook::NONE; sd->speed = DEFAULT_WALK_SPEED; @@ -682,7 +692,7 @@ int pc_authok(int id, int login_id2, TimeT connect_until_time, // sd->invincible_timer = nullptr; sd->deal_locked = 0; - sd->trade_partner = 0; + sd->trade_partner = AccountId(); sd->inchealhptick = interval_t::zero(); sd->inchealsptick = interval_t::zero(); @@ -702,7 +712,7 @@ int pc_authok(int id, int login_id2, TimeT connect_until_time, // 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"); + sd->cast_tick = tick; // + pc_readglobalreg (sd, "MAGIC_CAST_TICK"_s); // アカウント変数の送信要求 intif_request_accountreg(sd); @@ -725,17 +735,17 @@ int pc_authok(int id, int login_id2, TimeT connect_until_time, // This would leak information. // It's better to make it obvious that players can see you. if (false && bool(old_option & Option::INVISIBILITY)) - is_atcommand(sd->sess, sd, "@invisible", 0); + is_atcommand(sd->sess, sd, "@invisible"_s, GmLevel()); if (bool(old_option & Option::HIDE)) - is_atcommand(sd->sess, sd, "@hide", 0); + is_atcommand(sd->sess, sd, "@hide"_s, GmLevel()); // atcommand_hide might already send it, but also might not clif_changeoption(sd); } // パーティー関係の初期化 sd->party_sended = 0; - sd->party_invite = 0; + sd->party_invite = PartyId(); sd->party_x = -1; sd->party_y = -1; sd->party_hp = -1; @@ -748,8 +758,8 @@ int pc_authok(int id, int login_id2, TimeT connect_until_time, sd->status.last_point.y, BeingRemoveWhy::GONE); // パーティ、ギルドデータの要求 - if (sd->status.party_id > 0 - && (p = party_search(sd->status.party_id)) == NULL) + if (sd->status.party_id + && !(p = party_search(sd->status.party_id))) party_request_info(sd->status.party_id); // pvpの設定 @@ -765,19 +775,19 @@ int pc_authok(int id, int login_id2, TimeT connect_until_time, map_addchariddb(sd->status_key.char_id, sd->status_key.name); //スパノビ用死にカウンターのスクリプト変数からの読み出しとsdへのセット - sd->die_counter = pc_readglobalreg(sd, stringish<VarName>("PC_DIE_COUNTER")); + sd->die_counter = pc_readglobalreg(sd, stringish<VarName>("PC_DIE_COUNTER"_s)); // ステータス初期計算など pc_calcstatus(sd, 1); if (pc_isGM(sd)) { - PRINTF("Connection accepted: character '%s' (account: %d; GM level %d).\n", - sd->status_key.name, sd->status_key.account_id, pc_isGM(sd)); + PRINTF("Connection accepted: character '%s' (account: %d; GM level %d).\n"_fmt, + sd->status_key.name, sd->status_key.account_id, pc_isGM(sd)); clif_updatestatus(sd, SP::GM); } else - PRINTF("Connection accepted: Character '%s' (account: %d).\n", + PRINTF("Connection accepted: Character '%s' (account: %d).\n"_fmt, sd->status_key.name, sd->status_key.account_id); sd->auto_ban_info.in_progress = 0; @@ -796,11 +806,11 @@ int pc_authok(int id, int login_id2, TimeT connect_until_time, // message of the limited time of the account if (connect_until_time) { - // don't display if it's unlimited or unknow value - char tmpstr[] = WITH_TIMESTAMP("Your account time limit is: "); - REPLACE_TIMESTAMP(tmpstr, connect_until_time); + timestamp_seconds_buffer buffer; + stamp_time(buffer, &connect_until_time); + AString tmpstr = STRPRINTF("Your account time limit is: %s"_fmt, buffer); - clif_wis_message(sd->sess, wisp_server_name, const_(tmpstr)); + clif_wis_message(sd->sess, wisp_server_name, tmpstr); } pc_calcstatus(sd, 1); @@ -817,7 +827,7 @@ void pc_show_motd(dumb_ptr<map_session_data> sd) // If you remove the sending of this message, // the license does not permit you to publicly use this software. - clif_displaymessage(sd->sess, "This server is Free Software, for details type @source in chat or use the tmwa-source tool"); + clif_displaymessage(sd->sess, "This server is Free Software, for details type @source in chat or use the tmwa-source tool"_s); sd->state.seen_motd = true; io::ReadFile in(motd_txt); @@ -835,12 +845,12 @@ void pc_show_motd(dumb_ptr<map_session_data> sd) * session idに問題ありなので後始末 *------------------------------------------ */ -int pc_authfail(int id) +int pc_authfail(AccountId id) { dumb_ptr<map_session_data> sd; - sd = map_id2sd(id); - if (sd == NULL) + sd = map_id2sd(account_to_block(id)); + if (sd == nullptr) return 1; clif_authfail_fd(sd->sess, 0); @@ -853,7 +863,7 @@ int pc_calc_skillpoint(dumb_ptr<map_session_data> sd) { int i, skill_points = 0; - nullpo_ret(sd); + nullpo_retz(sd); for (i = 0; i < skill_pool_skills_size; i++) { int lv = sd->status.skill[skill_pool_skills[i]].lv; @@ -872,7 +882,7 @@ int pc_checkweighticon(dumb_ptr<map_session_data> sd) { int flag = 0; - nullpo_ret(sd); + nullpo_retz(sd); if (sd->weight * 2 >= sd->max_weight && !sd->sc_data[StatusChange::SC_FLYING_BACKPACK].timer) @@ -907,7 +917,7 @@ void pc_set_weapon_look(dumb_ptr<map_session_data> sd) { if (sd->attack_spell_override) clif_changelook(sd, LOOK::WEAPON, - sd->attack_spell_look_override); + unwrap<ItemNameId>(sd->attack_spell_look_override)); else clif_changelook(sd, LOOK::WEAPON, static_cast<uint16_t>(sd->status.weapon)); @@ -931,7 +941,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) int aspd_rate, refinedef = 0; int str, dstr, dex; - nullpo_ret(sd); + nullpo_retz(sd); interval_t b_speed = sd->speed; b_max_hp = sd->status.max_hp; @@ -942,7 +952,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) b_max_weight = sd->max_weight; earray<int, ATTR, ATTR::COUNT> b_paramb = sd->paramb; earray<int, ATTR, ATTR::COUNT> b_parame = sd->paramc; - earray<skill_value, SkillID, MAX_SKILL> b_skill = sd->status.skill; + earray<SkillValue, SkillID, MAX_SKILL> b_skill = sd->status.skill; b_hit = sd->hit; b_flee = sd->flee; interval_t b_aspd = sd->aspd; @@ -964,10 +974,10 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) if (first & 1) { sd->weight = 0; - for (int i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { - if (sd->status.inventory[i].nameid == 0 - || sd->inventory_data[i] == NULL) + if (!sd->status.inventory[i].nameid + || sd->inventory_data[i] == nullptr) continue; sd->weight += sd->inventory_data[i]->weight * @@ -1035,8 +1045,8 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) for (EQUIP i : EQUIPs_noarrow) { - int index = sd->equip_index_maybe[i]; - if (index < 0) + IOff0 index = sd->equip_index_maybe[i]; + if (!index.ok()) continue; if (i == EQUIP::WEAPON && sd->equip_index_maybe[EQUIP::SHIELD] == index) continue; @@ -1060,7 +1070,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) if (sd->spellpower_bonus_target < 0) sd->spellpower_bonus_target = (sd->spellpower_bonus_target * 256) / - (min(128 + skill_power(sd, SkillID::TMW_ASTRAL_SOUL), 256)); + (std::min(128 + skill_power(sd, SkillID::TMW_ASTRAL_SOUL), 256)); #endif if (sd->spellpower_bonus_target < sd->spellpower_bonus_current) @@ -1071,8 +1081,8 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) // 装備品によるステータス変化はここで実行 for (EQUIP i : EQUIPs_noarrow) { - int index = sd->equip_index_maybe[i]; - if (index < 0) + IOff0 index = sd->equip_index_maybe[i]; + if (!index.ok()) continue; if (i == EQUIP::WEAPON && sd->equip_index_maybe[EQUIP::SHIELD] == index) continue; @@ -1099,11 +1109,11 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) { argrec_t arg[2] = { - {"@slotId", static_cast<int>(i)}, - {"@itemId", sd->inventory_data[index]->nameid}, + {"@slotId"_s, static_cast<int>(i)}, + {"@itemId"_s, unwrap<ItemNameId>(sd->inventory_data[index]->nameid)}, }; run_script_l(ScriptPointer(sd->inventory_data[index]->equip_script.get(), 0), - sd->bl_id, 0, + sd->bl_id, BlockId(), arg); } sd->state.lr_flag = 0; @@ -1113,14 +1123,14 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) //二刀流武器以外 argrec_t arg[2] = { - {"@slotId", static_cast<int>(i)}, - {"@itemId", sd->inventory_data[index]->nameid}, + {"@slotId"_s, static_cast<int>(i)}, + {"@itemId"_s, unwrap<ItemNameId>(sd->inventory_data[index]->nameid)}, }; sd->watk += sd->inventory_data[index]->atk; sd->attackrange += sd->inventory_data[index]->range; run_script_l(ScriptPointer(sd->inventory_data[index]->equip_script.get(), 0), - sd->bl_id, 0, + sd->bl_id, BlockId(), arg); } } @@ -1128,12 +1138,12 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) { argrec_t arg[2] = { - {"@slotId", static_cast<int>(i)}, - {"@itemId", sd->inventory_data[index]->nameid}, + {"@slotId"_s, static_cast<int>(i)}, + {"@itemId"_s, unwrap<ItemNameId>(sd->inventory_data[index]->nameid)}, }; sd->watk += sd->inventory_data[index]->atk; run_script_l(ScriptPointer(sd->inventory_data[index]->equip_script.get(), 0), - sd->bl_id, 0, + sd->bl_id, BlockId(), arg); } } @@ -1147,20 +1157,20 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) sd->watk_2 += skill_power(sd, SkillID::TMW_BRAWLING) >> 3; // +25 for 200 } - int aidx = sd->equip_index_maybe[EQUIP::ARROW]; - if (aidx >= 0) - { // 矢 - int index = aidx; + IOff0 aidx = sd->equip_index_maybe[EQUIP::ARROW]; + if (aidx.ok()) + { + IOff0 index = aidx; if (sd->inventory_data[index]) { //まだ属性が入っていない argrec_t arg[2] = { - {"@slotId", static_cast<int>(EQUIP::ARROW)}, - {"@itemId", sd->inventory_data[index]->nameid}, + {"@slotId"_s, static_cast<int>(EQUIP::ARROW)}, + {"@itemId"_s, unwrap<ItemNameId>(sd->inventory_data[index]->nameid)}, }; sd->state.lr_flag = 2; run_script_l(ScriptPointer(sd->inventory_data[index]->equip_script.get(), 0), - sd->bl_id, 0, + sd->bl_id, BlockId(), arg); sd->state.lr_flag = 0; sd->arrow_atk += sd->inventory_data[index]->atk; @@ -1189,7 +1199,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) sd->aspd_rate = 20; for (ATTR attr : ATTRs) - sd->paramc[attr] = max(0, sd->status.attrs[attr] + sd->paramb[attr] + sd->parame[attr]); + sd->paramc[attr] = std::max(0, sd->status.attrs[attr] + sd->paramb[attr] + sd->parame[attr]); if (sd->status.weapon == ItemLook::BOW || sd->status.weapon == ItemLook::_13 @@ -1206,7 +1216,6 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) } dstr = str / 10; sd->base_atk += str + dstr * dstr + dex / 5 + sd->paramc[ATTR::LUK] / 5; -//FPRINTF(stderr, "baseatk = %d = x + %d + %d + %d + %d\n", sd->base_atk, str, dstr*dstr, dex/5, sd->paramc[ATTR::LUK]/5); sd->matk1 += sd->paramc[ATTR::INT] + (sd->paramc[ATTR::INT] / 5) * (sd->paramc[ATTR::INT] / 5); sd->matk2 += sd->paramc[ATTR::INT] + (sd->paramc[ATTR::INT] / 7) * (sd->paramc[ATTR::INT] / 7); if (sd->matk1 < sd->matk2) @@ -1304,7 +1313,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) if (sd->attackrange > 2) { // [fate] ranged weapon? - sd->attackrange += min(skill_power(sd, SkillID::AC_OWL) / 60, 3); + sd->attackrange += std::min(skill_power(sd, SkillID::AC_OWL) / 60, 3); sd->hit += skill_power(sd, SkillID::AC_OWL) / 10; // 20 for 200 } @@ -1385,7 +1394,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) if (sd->speed_rate != 100) sd->speed = sd->speed * sd->speed_rate / 100; - sd->speed = std::max(sd->speed, std::chrono::milliseconds(1)); + sd->speed = std::max(sd->speed, 1_ms); if (aspd_rate != 100) sd->aspd = sd->aspd * aspd_rate / 100; @@ -1395,7 +1404,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) sd->aspd = std::max(sd->aspd, static_cast<interval_t>(battle_config.max_aspd)); sd->amotion = sd->aspd; sd->dmotion = std::chrono::milliseconds(800 - sd->paramc[ATTR::AGI] * 4); - sd->dmotion = std::max(sd->dmotion, std::chrono::milliseconds(400)); + sd->dmotion = std::max(sd->dmotion, 400_ms); if (sd->status.hp > sd->status.max_hp) sd->status.hp = sd->status.max_hp; @@ -1479,7 +1488,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) */ int pc_bonus(dumb_ptr<map_session_data> sd, SP type, int val) { - nullpo_ret(sd); + nullpo_retz(sd); switch (type) { @@ -1731,7 +1740,7 @@ int pc_bonus(dumb_ptr<map_session_data> sd, SP type, int val) break; default: if (battle_config.error_log) - PRINTF("pc_bonus: unknown type %d %d !\n", + PRINTF("pc_bonus: unknown type %d %d !\n"_fmt, type, val); break; } @@ -1744,7 +1753,7 @@ int pc_bonus(dumb_ptr<map_session_data> sd, SP type, int val) */ int pc_bonus2(dumb_ptr<map_session_data> sd, SP type, int type2, int val) { - nullpo_ret(sd); + nullpo_retz(sd); switch (type) { @@ -1776,7 +1785,7 @@ int pc_bonus2(dumb_ptr<map_session_data> sd, SP type, int type2, int val) #endif default: if (battle_config.error_log) - PRINTF("pc_bonus2: unknown type %d %d %d!\n", + PRINTF("pc_bonus2: unknown type %d %d %d!\n"_fmt, type, type2, val); break; } @@ -1789,12 +1798,12 @@ int pc_bonus2(dumb_ptr<map_session_data> sd, SP type, int type2, int val) */ int pc_skill(dumb_ptr<map_session_data> sd, SkillID id, int level, int flag) { - nullpo_ret(sd); + nullpo_retz(sd); if (level > MAX_SKILL_LEVEL) { if (battle_config.error_log) - PRINTF("support card skill only!\n"); + PRINTF("support card skill only!\n"_fmt); return 0; } if (!flag && (sd->status.skill[id].lv || level == 0)) @@ -1817,16 +1826,14 @@ int pc_skill(dumb_ptr<map_session_data> sd, SkillID id, int level, int flag) * 3万個制限にかかるか確認 *------------------------------------------ */ -ADDITEM pc_checkadditem(dumb_ptr<map_session_data> sd, int nameid, int amount) +ADDITEM pc_checkadditem(dumb_ptr<map_session_data> sd, ItemNameId nameid, int amount) { - int i; - nullpo_retr(ADDITEM::ZERO, sd); if (itemdb_isequip(nameid)) return ADDITEM::NEW; - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { if (sd->status.inventory[i].nameid == nameid) { @@ -1847,13 +1854,13 @@ ADDITEM pc_checkadditem(dumb_ptr<map_session_data> sd, int nameid, int amount) */ int pc_inventoryblank(dumb_ptr<map_session_data> sd) { - int i, b; + int b = 0; - nullpo_ret(sd); + nullpo_retz(sd); - for (i = 0, b = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { - if (sd->status.inventory[i].nameid == 0) + if (!sd->status.inventory[i].nameid) b++; } @@ -1866,7 +1873,7 @@ int pc_inventoryblank(dumb_ptr<map_session_data> sd) */ int pc_payzeny(dumb_ptr<map_session_data> sd, int zeny) { - nullpo_ret(sd); + nullpo_retz(sd); double z = sd->status.zeny; if (sd->status.zeny < zeny || z - zeny > MAX_ZENY) @@ -1883,7 +1890,7 @@ int pc_payzeny(dumb_ptr<map_session_data> sd, int zeny) */ int pc_getzeny(dumb_ptr<map_session_data> sd, int zeny) { - nullpo_ret(sd); + nullpo_retz(sd); double z = sd->status.zeny; if (z + zeny > MAX_ZENY) @@ -1901,30 +1908,27 @@ int pc_getzeny(dumb_ptr<map_session_data> sd, int zeny) * アイテムを探して、インデックスを返す *------------------------------------------ */ -int pc_search_inventory(dumb_ptr<map_session_data> sd, int item_id) +IOff0 pc_search_inventory(dumb_ptr<map_session_data> sd, ItemNameId item_id) { - int i; + nullpo_retr(IOff0::from(-1), sd); - nullpo_retr(-1, sd); - - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { if (sd->status.inventory[i].nameid == item_id && - (sd->status.inventory[i].amount > 0 || item_id == 0)) + (sd->status.inventory[i].amount > 0 || !item_id)) return i; } - return -1; + return IOff0::from(-1); } -int pc_count_all_items(dumb_ptr<map_session_data> player, int item_id) +int pc_count_all_items(dumb_ptr<map_session_data> player, ItemNameId item_id) { - int i; int count = 0; - nullpo_ret(player); + nullpo_retz(player); - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { if (player->status.inventory[i].nameid == item_id) count += player->status.inventory[i].amount; @@ -1933,14 +1937,14 @@ int pc_count_all_items(dumb_ptr<map_session_data> player, int item_id) return count; } -int pc_remove_items(dumb_ptr<map_session_data> player, int item_id, int count) +int pc_remove_items(dumb_ptr<map_session_data> player, ItemNameId item_id, int count) { - int i; - - nullpo_ret(player); + nullpo_retz(player); - for (i = 0; i < MAX_INVENTORY && count; i++) + for (IOff0 i : IOff0::iter()) { + if (!count) + break; if (player->status.inventory[i].nameid == item_id) { int to_delete = count; @@ -1964,29 +1968,30 @@ int pc_remove_items(dumb_ptr<map_session_data> player, int item_id, int count) * アイテム追加。個数のみitem構造体の数字を無視 *------------------------------------------ */ -PickupFail pc_additem(dumb_ptr<map_session_data> sd, struct item *item_data, +PickupFail pc_additem(dumb_ptr<map_session_data> sd, Item *item_data, int amount) { struct item_data *data; - int i, w; + int w; - MAP_LOG_PC(sd, "PICKUP %d %d", item_data->nameid, amount); + MAP_LOG_PC(sd, "PICKUP %d %d"_fmt, item_data->nameid, amount); nullpo_retr(PickupFail::BAD_ITEM, sd); nullpo_retr(PickupFail::BAD_ITEM, item_data); - if (item_data->nameid <= 0 || amount <= 0) + if (!item_data->nameid || amount <= 0) return PickupFail::BAD_ITEM; data = itemdb_search(item_data->nameid); if ((w = data->weight * amount) + sd->weight > sd->max_weight) return PickupFail::TOO_HEAVY; - i = MAX_INVENTORY; + IOff0 i = IOff0::from(MAX_INVENTORY); if (!itemdb_isequip2(data)) { - // 装 備品ではないので、既所有品なら個数のみ変化させる - for (i = 0; i < MAX_INVENTORY; i++) + // TODO see if there's any nicer way to preserve the foreach var + for (i = IOff0::from(0); i != IOff0::from(MAX_INVENTORY); ++i) + { if (sd->status.inventory[i].nameid == item_data->nameid) { if (sd->status.inventory[i].amount + amount > MAX_AMOUNT) @@ -1995,12 +2000,12 @@ PickupFail pc_additem(dumb_ptr<map_session_data> sd, struct item *item_data, clif_additem(sd, i, amount, PickupFail::OKAY); break; } + } } - if (i >= MAX_INVENTORY) + if (!i.ok()) { - // 装 備品か未所有品だったので空き欄へ追加 - i = pc_search_inventory(sd, 0); - if (i >= 0) + i = pc_search_inventory(sd, ItemNameId()); + if (i.ok()) { sd->status.inventory[i] = *item_data; @@ -2024,16 +2029,16 @@ PickupFail pc_additem(dumb_ptr<map_session_data> sd, struct item *item_data, * アイテムを減らす *------------------------------------------ */ -int pc_delitem(dumb_ptr<map_session_data> sd, int n, int amount, int type) +int pc_delitem(dumb_ptr<map_session_data> sd, IOff0 n, int amount, int type) { nullpo_retr(1, sd); - if (sd->trade_partner != 0) + if (sd->trade_partner) trade_tradecancel(sd); - if (sd->status.inventory[n].nameid == 0 || amount <= 0 + if (!sd->status.inventory[n].nameid || amount <= 0 || sd->status.inventory[n].amount < amount - || sd->inventory_data[n] == NULL) + || sd->inventory_data[n] == nullptr) return 1; sd->status.inventory[n].amount -= amount; @@ -2042,8 +2047,8 @@ int pc_delitem(dumb_ptr<map_session_data> sd, int n, int amount, int type) { if (bool(sd->status.inventory[n].equip)) pc_unequipitem(sd, n, CalcStatus::NOW); - sd->status.inventory[n] = item{}; - sd->inventory_data[n] = NULL; + sd->status.inventory[n] = Item{}; + sd->inventory_data[n] = nullptr; } if (!(type & 1)) clif_delitem(sd, n, amount); @@ -2057,14 +2062,14 @@ int pc_delitem(dumb_ptr<map_session_data> sd, int n, int amount, int type) * アイテムを落す *------------------------------------------ */ -int pc_dropitem(dumb_ptr<map_session_data> sd, int n, int amount) +int pc_dropitem(dumb_ptr<map_session_data> sd, IOff0 n, int amount) { nullpo_retr(1, sd); - if (sd->trade_partner != 0 || sd->npc_id != 0 || sd->state.storage_open) + if (sd->trade_partner || sd->npc_id || sd->state.storage_open) return 0; // no dropping while trading/npc/storage - if (n < 0 || n >= MAX_INVENTORY) + if (!n.ok()) return 0; if (amount <= 0) @@ -2072,13 +2077,13 @@ int pc_dropitem(dumb_ptr<map_session_data> sd, int n, int amount) pc_unequipinvyitem(sd, n, CalcStatus::NOW); - if (sd->status.inventory[n].nameid <= 0 || + if (!sd->status.inventory[n].nameid || sd->status.inventory[n].amount < amount || - sd->trade_partner != 0 || sd->status.inventory[n].amount <= 0) + sd->trade_partner || sd->status.inventory[n].amount <= 0) return 1; map_addflooritem(&sd->status.inventory[n], amount, sd->bl_m, sd->bl_x, sd->bl_y, - NULL, NULL, NULL); + nullptr, nullptr, nullptr); pc_delitem(sd, n, amount, 0); return 0; @@ -2090,9 +2095,9 @@ int pc_dropitem(dumb_ptr<map_session_data> sd, int n, int amount) */ static -int can_pick_item_up_from(dumb_ptr<map_session_data> self, int other_id) +int can_pick_item_up_from(dumb_ptr<map_session_data> self, BlockId other_id) { - struct party *p = party_search(self->status.party_id); + PartyPair p = party_search(self->status.party_id); /* From ourselves or from no-one? */ if (!self || self->bl_id == other_id || !other_id) @@ -2133,19 +2138,19 @@ int pc_takeitem(dumb_ptr<map_session_data> sd, dumb_ptr<flooritem_data> fitem) tick_t tick = gettick(); int can_take; - nullpo_ret(sd); - nullpo_ret(fitem); + nullpo_retz(sd); + nullpo_retz(fitem); /* Sometimes the owners reported to us are buggy: */ if (fitem->first_get_id == fitem->third_get_id || fitem->second_get_id == fitem->third_get_id) - fitem->third_get_id = 0; + fitem->third_get_id = BlockId(); if (fitem->first_get_id == fitem->second_get_id) { fitem->second_get_id = fitem->third_get_id; - fitem->third_get_id = 0; + fitem->third_get_id = BlockId(); } can_take = can_pick_item_up_from(sd, fitem->first_get_id); @@ -2167,7 +2172,7 @@ int pc_takeitem(dumb_ptr<map_session_data> sd, dumb_ptr<flooritem_data> fitem) PickupFail flag = pc_additem(sd, &fitem->item_data, fitem->item_data.amount); if (flag != PickupFail::OKAY) // 重量overで取得失敗 - clif_additem(sd, 0, 0, flag); + clif_additem(sd, IOff0::from(0), 0, flag); else { // 取得成功 @@ -2180,22 +2185,22 @@ int pc_takeitem(dumb_ptr<map_session_data> sd, dumb_ptr<flooritem_data> fitem) } /* Otherwise, we can't pick up */ - clif_additem(sd, 0, 0, PickupFail::DROP_STEAL); + clif_additem(sd, IOff0::from(0), 0, PickupFail::DROP_STEAL); return 0; } static -int pc_isUseitem(dumb_ptr<map_session_data> sd, int n) +int pc_isUseitem(dumb_ptr<map_session_data> sd, IOff0 n) { struct item_data *item; - int nameid; + ItemNameId nameid; - nullpo_ret(sd); + nullpo_retz(sd); item = sd->inventory_data[n]; nameid = sd->status.inventory[n].nameid; - if (item == NULL) + if (item == nullptr) return 0; if (itemdb_type(nameid) != ItemType::USE) return 0; @@ -2212,16 +2217,16 @@ int pc_isUseitem(dumb_ptr<map_session_data> sd, int n) * アイテムを使う *------------------------------------------ */ -int pc_useitem(dumb_ptr<map_session_data> sd, int n) +int pc_useitem(dumb_ptr<map_session_data> sd, IOff0 n) { int amount; nullpo_retr(1, sd); - if (n >= 0 && n < MAX_INVENTORY && sd->inventory_data[n]) + if (n.ok() && sd->inventory_data[n]) { amount = sd->status.inventory[n].amount; - if (sd->status.inventory[n].nameid <= 0 + if (!sd->status.inventory[n].nameid || sd->status.inventory[n].amount <= 0 || !pc_isUseitem(sd, n)) { @@ -2233,7 +2238,7 @@ int pc_useitem(dumb_ptr<map_session_data> sd, int n) clif_useitemack(sd, n, amount - 1, 1); pc_delitem(sd, n, 1, 1); - run_script(ScriptPointer(script, 0), sd->bl_id, 0); + run_script(ScriptPointer(script, 0), sd->bl_id, BlockId()); } return 0; @@ -2251,14 +2256,14 @@ int pc_setpos(dumb_ptr<map_session_data> sd, { MapName mapname_; - nullpo_ret(sd); + nullpo_retz(sd); if (sd->trade_partner) // 取引を中断する trade_tradecancel(sd); if (sd->state.storage_open) storage_storage_quit(sd); // 倉庫を開いてるなら保存する - if (sd->party_invite > 0) // パーティ勧誘を拒否する + if (sd->party_invite) // パーティ勧誘を拒否する party_reply_invite(sd, sd->party_invite_account, 0); skill_castcancel(sd, 0); // 詠唱中断 @@ -2314,7 +2319,7 @@ int pc_setpos(dumb_ptr<map_session_data> sd, if (x || y) { if (battle_config.error_log) - PRINTF("stacked (%d,%d)\n", x, y); + PRINTF("stacked (%d,%d)\n"_fmt, x, y); } do { @@ -2324,7 +2329,7 @@ int pc_setpos(dumb_ptr<map_session_data> sd, while (bool(read_gatp(m, x, y) & MapCell::UNWALKABLE)); } - if (sd->mapname_ && sd->bl_prev != NULL) + if (sd->mapname_ && sd->bl_prev != nullptr) { clif_clearchar(sd, clrtype); map_delblock(sd); @@ -2355,7 +2360,7 @@ int pc_randomwarp(dumb_ptr<map_session_data> sd, BeingRemoveWhy type) { int x, y, i = 0; - nullpo_ret(sd); + nullpo_retz(sd); map_local *m = sd->bl_m; @@ -2385,7 +2390,7 @@ int pc_can_reach(dumb_ptr<map_session_data> sd, int x, int y) { struct walkpath_data wpd; - nullpo_ret(sd); + nullpo_retz(sd); if (sd->bl_x == x && sd->bl_y == y) // 同じマス return 1; @@ -2422,14 +2427,14 @@ interval_t calc_next_walk_step(dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void pc_walk(TimerData *, tick_t tick, int id, unsigned char data) +void pc_walk(TimerData *, tick_t tick, BlockId id, unsigned char data) { dumb_ptr<map_session_data> sd; int moveblock; int x, y, dx, dy; sd = map_id2sd(id); - if (sd == NULL) + if (sd == nullptr) return; if (sd->walkpath.path_pos >= sd->walkpath.path_len @@ -2497,10 +2502,10 @@ void pc_walk(TimerData *, tick_t tick, int id, unsigned char data) BL::NUL); // sd->walktimer = nullptr; - if (sd->status.party_id > 0) + if (sd->status.party_id) { // パーティのHP情報通知検査 - struct party *p = party_search(sd->status.party_id); - if (p != NULL) + PartyPair p = party_search(sd->status.party_id); + if (p) { int p_flag = 0; map_foreachinmovearea(std::bind(party_send_hp_check, ph::_1, sd->status.party_id, &p_flag), @@ -2517,14 +2522,14 @@ void pc_walk(TimerData *, tick_t tick, int id, unsigned char data) if (bool(map_getcell(sd->bl_m, x, y) & MapCell::NPC_NEAR)) npc_touch_areanpc(sd, sd->bl_m, x, y); else - sd->areanpc_id = 0; + sd->areanpc_id = BlockId(); } interval_t i = calc_next_walk_step(sd); if (i > interval_t::zero()) { i = i / 2; if (sd->walkpath.path_half == 0) - i = std::max(i, std::chrono::milliseconds(1)); + i = std::max(i, 1_ms); sd->walktimer = Timer(tick + i, std::bind(pc_walk, ph::_1, ph::_2, @@ -2570,7 +2575,7 @@ int pc_walktoxy_sub(dumb_ptr<map_session_data> sd) int pc_walktoxy(dumb_ptr<map_session_data> sd, int x, int y) { - nullpo_ret(sd); + nullpo_retz(sd); sd->to_x = x; sd->to_y = y; @@ -2598,7 +2603,7 @@ int pc_walktoxy(dumb_ptr<map_session_data> sd, int x, int y) */ int pc_stop_walking(dumb_ptr<map_session_data> sd, int type) { - nullpo_ret(sd); + nullpo_retz(sd); sd->walktimer.cancel(); @@ -2623,7 +2628,7 @@ void pc_touch_all_relevant_npcs(dumb_ptr<map_session_data> sd) if (bool(map_getcell(sd->bl_m, sd->bl_x, sd->bl_y) & MapCell::NPC_NEAR)) npc_touch_areanpc(sd, sd->bl_m, sd->bl_x, sd->bl_y); else - sd->areanpc_id = 0; + sd->areanpc_id = BlockId(); } /*========================================== @@ -2637,7 +2642,7 @@ int pc_movepos(dumb_ptr<map_session_data> sd, int dst_x, int dst_y) struct walkpath_data wpd; - nullpo_ret(sd); + nullpo_retz(sd); if (path_search(&wpd, sd->bl_m, sd->bl_x, sd->bl_y, dst_x, dst_y, 0)) return 1; @@ -2671,10 +2676,10 @@ int pc_movepos(dumb_ptr<map_session_data> sd, int dst_x, int dst_y) -dx, -dy, BL::NUL); - if (sd->status.party_id > 0) + if (sd->status.party_id) { // パーティのHP情報通知検査 - struct party *p = party_search(sd->status.party_id); - if (p != NULL) + PartyPair p = party_search(sd->status.party_id); + if (p) { int flag = 0; map_foreachinmovearea(std::bind(party_send_hp_check, ph::_1, sd->status.party_id, &flag), @@ -2701,7 +2706,7 @@ int pc_movepos(dumb_ptr<map_session_data> sd, int dst_x, int dst_y) */ int pc_checkskill(dumb_ptr<map_session_data> sd, SkillID skill_id) { - if (sd == NULL) + if (sd == nullptr) return 0; return sd->status.skill[skill_id].lv; @@ -2711,9 +2716,9 @@ int pc_checkskill(dumb_ptr<map_session_data> sd, SkillID skill_id) * 装 備品のチェック *------------------------------------------ */ -int pc_checkequip(dumb_ptr<map_session_data> sd, EPOS pos) +IOff0 pc_checkequip(dumb_ptr<map_session_data> sd, EPOS pos) { - nullpo_retr(-1, sd); + nullpo_retr(IOff0::from(-1), sd); for (EQUIP i : EQUIPs) { @@ -2721,7 +2726,7 @@ int pc_checkequip(dumb_ptr<map_session_data> sd, EPOS pos) return sd->equip_index_maybe[i]; } - return -1; + return IOff0::from(-1); } /*========================================== @@ -2729,7 +2734,7 @@ int pc_checkequip(dumb_ptr<map_session_data> sd, EPOS pos) *------------------------------------------ */ static -void pc_attack_timer(TimerData *, tick_t tick, int id) +void pc_attack_timer(TimerData *, tick_t tick, BlockId id) { dumb_ptr<map_session_data> sd; dumb_ptr<block_list> bl; @@ -2737,14 +2742,14 @@ void pc_attack_timer(TimerData *, tick_t tick, int id) int dist, range; sd = map_id2sd(id); - if (sd == NULL) + if (sd == nullptr) return; - if (sd->bl_prev == NULL) + if (sd->bl_prev == nullptr) return; bl = map_id2bl(sd->attacktarget); - if (bl == NULL || bl->bl_prev == NULL) + if (bl == nullptr || bl->bl_prev == nullptr) return; if (bl->bl_type == BL::PC && pc_isdead(bl->is_player())) @@ -2760,7 +2765,7 @@ void pc_attack_timer(TimerData *, tick_t tick, int id) return; Option *opt = battle_get_option(bl); - if (opt != NULL && bool(*opt & Option::REAL_ANY_HIDE)) + if (opt != nullptr && bool(*opt & Option::REAL_ANY_HIDE)) return; if (!battle_config.skill_delay_attack_enable) @@ -2777,7 +2782,7 @@ void pc_attack_timer(TimerData *, tick_t tick, int id) interval_t attack_spell_delay = sd->attack_spell_delay; if (sd->attack_spell_override // [Fate] If we have an active attack spell, use that - && spell_attack(id, sd->attacktarget)) + && magic::spell_attack(id, sd->attacktarget)) { // Return if the spell succeeded. If the spell had disspiated, spell_attack() may fail. sd->attackabletime = tick + attack_spell_delay; @@ -2836,19 +2841,19 @@ void pc_attack_timer(TimerData *, tick_t tick, int id) * typeが1なら継続攻撃 *------------------------------------------ */ -int pc_attack(dumb_ptr<map_session_data> sd, int target_id, int type) +int pc_attack(dumb_ptr<map_session_data> sd, BlockId target_id, int type) { dumb_ptr<block_list> bl; - nullpo_ret(sd); + nullpo_retz(sd); bl = map_id2bl(target_id); - if (bl == NULL) + if (bl == nullptr) return 1; if (bl->bl_type == BL::NPC) { // monster npcs [Valaris] - npc_click(sd, RFIFOL(sd->sess, 2)); + npc_click(sd, target_id); return 0; } @@ -2860,7 +2865,7 @@ int pc_attack(dumb_ptr<map_session_data> sd, int target_id, int type) sd->state.attack_continue = type; interval_t d = sd->attackabletime - gettick(); - if (d > interval_t::zero() && d < std::chrono::seconds(2)) + if (d > interval_t::zero() && d < 2_s) { // 攻撃delay中 sd->attacktimer = Timer(sd->attackabletime, std::bind(pc_attack_timer, ph::_1, ph::_2, @@ -2881,11 +2886,11 @@ int pc_attack(dumb_ptr<map_session_data> sd, int target_id, int type) */ int pc_stopattack(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); sd->attacktimer.cancel(); - sd->attacktarget = 0; + sd->attacktarget = BlockId(); sd->state.attack_continue = 0; return 0; @@ -2896,7 +2901,7 @@ int pc_checkbaselevelup(dumb_ptr<map_session_data> sd) { int next = pc_nextbaseexp(sd); - nullpo_ret(sd); + nullpo_retz(sd); if (sd->status.base_exp >= next && next > 0) { @@ -2915,7 +2920,7 @@ int pc_checkbaselevelup(dumb_ptr<map_session_data> sd) //レベルアップしたのでパーティー情報を更新する //(公平範囲チェック) party_send_movemap(sd); - MAP_LOG_XP(sd, "LEVELUP"); + MAP_LOG_XP(sd, "LEVELUP"_fmt); return 1; } @@ -2937,8 +2942,7 @@ int pc_skillpt_potential(dumb_ptr<map_session_data> sd) { int potential = 0; - for (SkillID skill_id = SkillID(); skill_id < MAX_SKILL; - skill_id = SkillID(uint16_t(skill_id) + 1)) + for (SkillID skill_id : erange(SkillID(), MAX_SKILL)) if (sd->status.skill[skill_id].lv && sd->status.skill[skill_id].lv < skill_db[skill_id].max_raise) potential += RAISE_COST(skill_db[skill_id].max_raise) @@ -2952,7 +2956,7 @@ int pc_checkjoblevelup(dumb_ptr<map_session_data> sd) { int next = pc_nextjobexp(sd); - nullpo_ret(sd); + nullpo_retz(sd); if (sd->status.job_exp >= next && next > 0) { @@ -2971,7 +2975,7 @@ int pc_checkjoblevelup(dumb_ptr<map_session_data> sd) clif_updatestatus(sd, SP::SKILLPOINT); pc_calcstatus(sd, 0); - MAP_LOG_PC(sd, "SKILLPOINTS-UP %d", sd->status.skill_point); + MAP_LOG_PC(sd, "SKILLPOINTS-UP %d"_fmt, sd->status.skill_point); if (sd->status.job_level < 250 && sd->status.job_level < sd->status.base_level * 2) @@ -2987,21 +2991,21 @@ int pc_checkjoblevelup(dumb_ptr<map_session_data> sd) int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, PC_GAINEXP_REASON reason) { - nullpo_ret(sd); + nullpo_retz(sd); - if (sd->bl_prev == NULL || pc_isdead(sd)) + if (sd->bl_prev == nullptr || pc_isdead(sd)) return 0; - earray<const char *, PC_GAINEXP_REASON, PC_GAINEXP_REASON::COUNT> reasons //= + earray<LString, PC_GAINEXP_REASON, PC_GAINEXP_REASON::COUNT> reasons //= {{ - "KILLXP", - "HEALXP", - "SCRIPTXP", - "SHAREXP", + "KILLXP"_s, + "HEALXP"_s, + "SCRIPTXP"_s, + "SHAREXP"_s, /* Insert new types here */ - "UNKNOWNXP" + "UNKNOWNXP"_s }}; - MAP_LOG_PC(sd, "GAINXP %d %d %s", base_exp, job_exp, reasons[reason]); + MAP_LOG_PC(sd, "GAINXP %d %d %s"_fmt, base_exp, job_exp, reasons[reason]); if (!battle_config.multi_level_up && pc_nextbaseafter(sd)) { @@ -3029,7 +3033,8 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, if (sd->status.base_exp < 0) sd->status.base_exp = 0; - while (pc_checkbaselevelup(sd)); + while (pc_checkbaselevelup(sd)) + {} clif_updatestatus(sd, SP::BASEEXP); if (!battle_config.multi_level_up && pc_nextjobafter(sd)) @@ -3046,14 +3051,15 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, if (sd->status.job_exp < 0) sd->status.job_exp = 0; - while (pc_checkjoblevelup(sd)); + while (pc_checkjoblevelup(sd)) + {} clif_updatestatus(sd, SP::JOBEXP); if (battle_config.disp_experience) { AString output = STRPRINTF( - "Experienced Gained Base:%d Job:%d", + "Experienced Gained Base:%d Job:%d"_fmt, base_exp, job_exp); clif_displaymessage(sd->sess, output); } @@ -3064,7 +3070,7 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, int pc_extract_healer_exp(dumb_ptr<map_session_data> sd, int max) { int amount; - nullpo_ret(sd); + nullpo_retz(sd); amount = sd->heal_xp; if (max < amount) @@ -3080,7 +3086,7 @@ int pc_extract_healer_exp(dumb_ptr<map_session_data> sd, int max) */ int pc_nextbaseexp(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); if (sd->status.base_level >= MAX_LEVEL || sd->status.base_level <= 0) return 0; @@ -3108,7 +3114,7 @@ int pc_nextjobexp(dumb_ptr<map_session_data> sd) */ int pc_nextbaseafter(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); if (sd->status.base_level >= MAX_LEVEL || sd->status.base_level <= 0) return 0; @@ -3122,7 +3128,7 @@ int pc_nextbaseafter(dumb_ptr<map_session_data> sd) */ int pc_nextjobafter(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); if (sd->status.job_level >= MAX_LEVEL || sd->status.job_level <= 0) return 0; @@ -3156,7 +3162,7 @@ int pc_statusup(dumb_ptr<map_session_data> sd, SP type) { int need, val = 0; - nullpo_ret(sd); + nullpo_retz(sd); if (SP::STR <= type && type <= SP::LUK) val = sd->status.attrs[sp_to_attr(type)]; @@ -3181,7 +3187,7 @@ int pc_statusup(dumb_ptr<map_session_data> sd, SP type) pc_calcstatus(sd, 0); clif_statusupack(sd, type, 1, val); - MAP_LOG_STATS(sd, "STATUP"); + MAP_LOG_STATS(sd, "STATUP"_fmt); return 0; } @@ -3192,7 +3198,7 @@ int pc_statusup(dumb_ptr<map_session_data> sd, SP type) */ int pc_statusup2(dumb_ptr<map_session_data> sd, SP type, int val) { - nullpo_ret(sd); + nullpo_retz(sd); if (type < SP::STR || type > SP::LUK) { @@ -3208,7 +3214,7 @@ int pc_statusup2(dumb_ptr<map_session_data> sd, SP type, int val) clif_updatestatus(sd, type); pc_calcstatus(sd, 0); clif_statusupack(sd, type, 1, val); - MAP_LOG_STATS(sd, "STATUP2"); + MAP_LOG_STATS(sd, "STATUP2"_fmt); return 0; } @@ -3219,7 +3225,7 @@ int pc_statusup2(dumb_ptr<map_session_data> sd, SP type, int val) */ int pc_skillup(dumb_ptr<map_session_data> sd, SkillID skill_num) { - nullpo_ret(sd); + nullpo_retz(sd); if (sd->status.skill[skill_num].lv && sd->status.skill_point >= sd->status.skill[skill_num].lv @@ -3232,7 +3238,7 @@ int pc_skillup(dumb_ptr<map_session_data> sd, SkillID skill_num) clif_skillup(sd, skill_num); clif_updatestatus(sd, SP::SKILLPOINT); clif_skillinfoblock(sd); - MAP_LOG_PC(sd, "SKILLUP %d %d %d", + MAP_LOG_PC(sd, "SKILLUP %d %d %d"_fmt, skill_num, sd->status.skill[skill_num].lv, skill_power(sd, skill_num)); } @@ -3246,7 +3252,7 @@ int pc_skillup(dumb_ptr<map_session_data> sd, SkillID skill_num) */ int pc_resetlvl(dumb_ptr<map_session_data> sd, int type) { - nullpo_ret(sd); + nullpo_retz(sd); for (SkillID i : erange(SkillID(1), MAX_SKILL)) { @@ -3309,13 +3315,13 @@ int pc_resetlvl(dumb_ptr<map_session_data> sd, int type) for (EQUIP i : EQUIPs) { // unequip items that can't be equipped by base 1 [Valaris] - short *idx = &sd->equip_index_maybe[i]; - if (*idx >= 0) + IOff0 *idx = &sd->equip_index_maybe[i]; + if ((*idx).ok()) { if (!pc_isequip(sd, *idx)) { pc_unequipitem(sd, *idx, CalcStatus::LATER); - *idx = -1; + *idx = IOff0::from(-1); } } } @@ -3323,7 +3329,7 @@ int pc_resetlvl(dumb_ptr<map_session_data> sd, int type) clif_skillinfoblock(sd); pc_calcstatus(sd, 0); - MAP_LOG_STATS(sd, "STATRESET"); + MAP_LOG_STATS(sd, "STATRESET"_fmt); return 0; } @@ -3335,7 +3341,7 @@ int pc_resetlvl(dumb_ptr<map_session_data> sd, int type) int pc_resetstate(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); sd->status.status_point = stat_p[sd->status.base_level - 1]; @@ -3361,7 +3367,7 @@ int pc_resetskill(dumb_ptr<map_session_data> sd) { int skill; - nullpo_ret(sd); + nullpo_retz(sd); sd->status.skill_point += pc_calc_skillpoint(sd); @@ -3386,7 +3392,7 @@ int pc_resetskill(dumb_ptr<map_session_data> sd) int pc_damage(dumb_ptr<block_list> src, dumb_ptr<map_session_data> sd, int damage) { - nullpo_ret(sd); + nullpo_retz(sd); // 既に死んでいたら無効 if (pc_isdead(sd)) @@ -3401,17 +3407,17 @@ int pc_damage(dumb_ptr<block_list> src, dumb_ptr<map_session_data> sd, { if (src->bl_type == BL::PC) { - MAP_LOG_PC(sd, "INJURED-BY PC%d FOR %d", - src->is_player()->status_key.char_id, - damage); + MAP_LOG_PC(sd, "INJURED-BY PC%d FOR %d"_fmt, + src->is_player()->status_key.char_id, + damage); } else { - MAP_LOG_PC(sd, "INJURED-BY MOB%d FOR %d", src->bl_id, damage); + MAP_LOG_PC(sd, "INJURED-BY MOB%d FOR %d"_fmt, src->bl_id, damage); } } else - MAP_LOG_PC(sd, "INJURED-BY null FOR %d", damage); + MAP_LOG_PC(sd, "INJURED-BY null FOR %d"_fmt, damage); pc_stop_walking(sd, 3); // 演奏/ダンスの中断 @@ -3427,17 +3433,17 @@ int pc_damage(dumb_ptr<block_list> src, dumb_ptr<map_session_data> sd, sd->canlog_tick = gettick(); - if (sd->status.party_id > 0) + if (sd->status.party_id) { // on-the-fly party hp updates [Valaris] - struct party *p = party_search(sd->status.party_id); - if (p != NULL) + PartyPair p = party_search(sd->status.party_id); + if (p) clif_party_hp(p, sd); } // end addition [Valaris] return 0; } - MAP_LOG_PC(sd, "DEAD%s", ""); + MAP_LOG_PC(sd, "DEAD%s"_fmt, ""_s); // Character is dead! @@ -3452,13 +3458,13 @@ int pc_damage(dumb_ptr<block_list> src, dumb_ptr<map_session_data> sd, pc_stop_walking(sd, 0); skill_castcancel(sd, 0); // 詠唱の中止 clif_clearchar(sd, BeingRemoveWhy::DEAD); - pc_setglobalreg(sd, stringish<VarName>("PC_DIE_COUNTER"), ++sd->die_counter); //死にカウンター書き込み + pc_setglobalreg(sd, stringish<VarName>("PC_DIE_COUNTER"_s), ++sd->die_counter); //死にカウンター書き込み skill_status_change_clear(sd, 0); // ステータス異常を解除する clif_updatestatus(sd, SP::HP); pc_calcstatus(sd, 0); // [Fate] Reset magic sd->cast_tick = gettick(); - magic_stop_completely(sd); + magic::magic_stop_completely(sd); if (battle_config.death_penalty_type > 0 && sd->status.base_level >= 20) { @@ -3544,14 +3550,14 @@ int pc_damage(dumb_ptr<block_list> src, dumb_ptr<map_session_data> sd, // [Fate] PK death, trigger scripts argrec_t arg[3] = { - {"@killerrid", src->bl_id}, - {"@victimrid", sd->bl_id}, - {"@victimlvl", sd->status.base_level}, + {"@killerrid"_s, static_cast<int32_t>(unwrap<BlockId>(src->bl_id))}, + {"@victimrid"_s, static_cast<int32_t>(unwrap<BlockId>(sd->bl_id))}, + {"@victimlvl"_s, sd->status.base_level}, }; - npc_event_doall_l(stringish<ScriptLabel>("OnPCKilledEvent"), sd->bl_id, arg); - npc_event_doall_l(stringish<ScriptLabel>("OnPCKillEvent"), src->bl_id, arg); + npc_event_doall_l(stringish<ScriptLabel>("OnPCKilledEvent"_s), sd->bl_id, arg); + npc_event_doall_l(stringish<ScriptLabel>("OnPCKillEvent"_s), src->bl_id, arg); } - npc_event_doall_l(stringish<ScriptLabel>("OnPCDieEvent"), sd->bl_id, nullptr); + npc_event_doall_l(stringish<ScriptLabel>("OnPCDieEvent"_s), sd->bl_id, nullptr); return 0; } @@ -3567,7 +3573,7 @@ int pc_readparam(dumb_ptr<map_session_data> sd, SP type) { int val = 0; - nullpo_ret(sd); + nullpo_retz(sd); switch (type) { @@ -3587,7 +3593,7 @@ int pc_readparam(dumb_ptr<map_session_data> sd, SP type) val = sd->status.job_level; break; case SP::CLASS: - val = sd->status.species; + val = unwrap<Species>(sd->status.species); break; case SP::SEX: val = static_cast<uint8_t>(sd->sex); @@ -3643,7 +3649,7 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val) { int i = 0, up_level = 50; - nullpo_ret(sd); + nullpo_retz(sd); switch (type) { @@ -3691,7 +3697,7 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val) clif_updatestatus(sd, type); break; case SP::CLASS: - sd->status.species = val; + sd->status.species = wrap<Species>(val); break; case SP::SKILLPOINT: sd->status.skill_point = val; @@ -3762,10 +3768,7 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val) */ int pc_heal(dumb_ptr<map_session_data> sd, int hp, int sp) { -// if(battle_config.battle_log) -// PRINTF("heal %d %d\n",hp,sp); - - nullpo_ret(sd); + nullpo_retz(sd); if (pc_checkoverhp(sd)) { @@ -3786,7 +3789,7 @@ int pc_heal(dumb_ptr<map_session_data> sd, int hp, int sp) if (sd->status.hp <= 0) { sd->status.hp = 0; - pc_damage(NULL, sd, 1); + pc_damage(nullptr, sd, 1); hp = 0; } sd->status.sp += sp; @@ -3797,10 +3800,10 @@ int pc_heal(dumb_ptr<map_session_data> sd, int hp, int sp) if (sp) clif_updatestatus(sd, SP::SP); - if (sd->status.party_id > 0) + if (sd->status.party_id) { // on-the-fly party hp updates [Valaris] - struct party *p = party_search(sd->status.party_id); - if (p != NULL) + PartyPair p = party_search(sd->status.party_id); + if (p) clif_party_hp(p, sd); } // end addition [Valaris] @@ -3847,9 +3850,9 @@ void pc_heal_quick_accumulate(int new_amount, int average_speed = ((new_speed * new_amount) + (current_speed * current_amount)) / (current_amount + new_amount); // new_amount > 0, current_amount >= 0 quick_regen->speed = average_speed; - quick_regen->amount = min(current_amount + new_amount, max); + quick_regen->amount = std::min(current_amount + new_amount, max); - quick_regen->tickdelay = min(quick_regen->speed, quick_regen->tickdelay); + quick_regen->tickdelay = std::min(quick_regen->speed, quick_regen->tickdelay); } int pc_itemheal(dumb_ptr<map_session_data> sd, int hp, int sp) @@ -3884,7 +3887,7 @@ int pc_itemheal(dumb_ptr<map_session_data> sd, int hp, int sp) static int pc_itemheal_effect(dumb_ptr<map_session_data> sd, int hp, int sp) { - nullpo_ret(sd); + nullpo_retz(sd); if (pc_checkoverhp(sd)) { @@ -3914,7 +3917,7 @@ int pc_itemheal_effect(dumb_ptr<map_session_data> sd, int hp, int sp) if (sd->status.hp <= 0) { sd->status.hp = 0; - pc_damage(NULL, sd, 1); + pc_damage(nullptr, sd, 1); hp = 0; } sd->status.sp += sp; @@ -3934,7 +3937,7 @@ int pc_itemheal_effect(dumb_ptr<map_session_data> sd, int hp, int sp) */ int pc_percentheal(dumb_ptr<map_session_data> sd, int hp, int sp) { - nullpo_ret(sd); + nullpo_retz(sd); if (pc_checkoverhp(sd)) { @@ -3955,7 +3958,7 @@ int pc_percentheal(dumb_ptr<map_session_data> sd, int hp, int sp) else if (hp <= -100) { sd->status.hp = 0; - pc_damage(NULL, sd, 1); + pc_damage(nullptr, sd, 1); } else { @@ -3965,7 +3968,7 @@ int pc_percentheal(dumb_ptr<map_session_data> sd, int hp, int sp) if (sd->status.hp <= 0) { sd->status.hp = 0; - pc_damage(NULL, sd, 1); + pc_damage(nullptr, sd, 1); hp = 0; } } @@ -4003,7 +4006,7 @@ int pc_percentheal(dumb_ptr<map_session_data> sd, int hp, int sp) */ int pc_changelook(dumb_ptr<map_session_data> sd, LOOK type, int val) { - nullpo_ret(sd); + nullpo_retz(sd); switch (type) { @@ -4014,13 +4017,13 @@ int pc_changelook(dumb_ptr<map_session_data> sd, LOOK type, int val) sd->status.weapon = static_cast<ItemLook>(static_cast<uint16_t>(val)); break; case LOOK::HEAD_BOTTOM: - sd->status.head_bottom = val; + sd->status.head_bottom = wrap<ItemNameId>(val); break; case LOOK::HEAD_TOP: - sd->status.head_top = val; + sd->status.head_top = wrap<ItemNameId>(val); break; case LOOK::HEAD_MID: - sd->status.head_mid = val; + sd->status.head_mid = wrap<ItemNameId>(val); break; case LOOK::HAIR_COLOR: sd->status.hair_color = val; @@ -4029,7 +4032,7 @@ int pc_changelook(dumb_ptr<map_session_data> sd, LOOK type, int val) sd->status.clothes_color = val; break; case LOOK::SHIELD: - sd->status.shield = val; + sd->status.shield = wrap<ItemNameId>(val); break; case LOOK::SHOES: break; @@ -4045,7 +4048,7 @@ int pc_changelook(dumb_ptr<map_session_data> sd, LOOK type, int val) */ int pc_setoption(dumb_ptr<map_session_data> sd, Option type) { - nullpo_ret(sd); + nullpo_retz(sd); sd->status.option = type; clif_changeoption(sd); @@ -4060,7 +4063,7 @@ int pc_setoption(dumb_ptr<map_session_data> sd, Option type) */ int pc_readreg(dumb_ptr<map_session_data> sd, SIR reg) { - nullpo_ret(sd); + nullpo_retz(sd); return sd->regm.get(reg); } @@ -4116,7 +4119,7 @@ int pc_readglobalreg(dumb_ptr<map_session_data> sd, VarName reg) { int i; - nullpo_ret(sd); + nullpo_retz(sd); assert (sd->status.global_reg_num < GLOBAL_REG_NUM); for (i = 0; i < sd->status.global_reg_num; i++) @@ -4136,10 +4139,10 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val) { int i; - nullpo_ret(sd); + nullpo_retz(sd); //PC_DIE_COUNTERがスクリプトなどで変更された時の処理 - if (reg == stringish<VarName>("PC_DIE_COUNTER") && sd->die_counter != val) + if (reg == stringish<VarName>("PC_DIE_COUNTER"_s) && sd->die_counter != val) { sd->die_counter = val; pc_calcstatus(sd, 0); @@ -4175,7 +4178,7 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val) return 0; } if (battle_config.error_log) - PRINTF("pc_setglobalreg : couldn't set %s (GLOBAL_REG_NUM = %d)\n", + PRINTF("pc_setglobalreg : couldn't set %s (GLOBAL_REG_NUM = %d)\n"_fmt, reg, GLOBAL_REG_NUM); return 1; @@ -4189,7 +4192,7 @@ int pc_readaccountreg(dumb_ptr<map_session_data> sd, VarName reg) { int i; - nullpo_ret(sd); + nullpo_retz(sd); assert (sd->status.account_reg_num < ACCOUNT_REG_NUM); for (i = 0; i < sd->status.account_reg_num; i++) @@ -4209,7 +4212,7 @@ int pc_setaccountreg(dumb_ptr<map_session_data> sd, VarName reg, int val) { int i; - nullpo_ret(sd); + nullpo_retz(sd); if (val == 0) { @@ -4244,7 +4247,7 @@ int pc_setaccountreg(dumb_ptr<map_session_data> sd, VarName reg, int val) return 0; } if (battle_config.error_log) - PRINTF("pc_setaccountreg : couldn't set %s (ACCOUNT_REG_NUM = %d)\n", + PRINTF("pc_setaccountreg : couldn't set %s (ACCOUNT_REG_NUM = %zu)\n"_fmt, reg, ACCOUNT_REG_NUM); return 1; @@ -4258,7 +4261,7 @@ int pc_readaccountreg2(dumb_ptr<map_session_data> sd, VarName reg) { int i; - nullpo_ret(sd); + nullpo_retz(sd); for (i = 0; i < sd->status.account_reg2_num; i++) { @@ -4312,8 +4315,8 @@ int pc_setaccountreg2(dumb_ptr<map_session_data> sd, VarName reg, int val) return 0; } if (battle_config.error_log) - PRINTF("pc_setaccountreg2 : couldn't set %s (ACCOUNT_REG2_NUM = %d)\n", - reg, ACCOUNT_REG2_NUM); + PRINTF("pc_setaccountreg2 : couldn't set %s (ACCOUNT_REG2_NUM = %zu)\n"_fmt, + reg, ACCOUNT_REG2_NUM); return 1; } @@ -4323,10 +4326,10 @@ int pc_setaccountreg2(dumb_ptr<map_session_data> sd, VarName reg, int val) *------------------------------------------ */ static -void pc_eventtimer(TimerData *, tick_t, int id, NpcEvent data) +void pc_eventtimer(TimerData *, tick_t, BlockId id, NpcEvent data) { dumb_ptr<map_session_data> sd = map_id2sd(id); - assert (sd != NULL); + assert (sd != nullptr); npc_event(sd, data, 0); } @@ -4339,7 +4342,7 @@ int pc_addeventtimer(dumb_ptr<map_session_data> sd, interval_t tick, NpcEvent na { int i; - nullpo_ret(sd); + nullpo_retz(sd); for (i = 0; i < MAX_EVENTTIMER; i++) if (!sd->eventtimer[i]) @@ -4362,7 +4365,7 @@ int pc_addeventtimer(dumb_ptr<map_session_data> sd, interval_t tick, NpcEvent na */ int pc_cleareventtimer(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); for (int i = 0; i < MAX_EVENTTIMER; i++) sd->eventtimer[i].cancel(); @@ -4378,7 +4381,7 @@ int pc_cleareventtimer(dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -int pc_signal_advanced_equipment_change(dumb_ptr<map_session_data> sd, int n) +int pc_signal_advanced_equipment_change(dumb_ptr<map_session_data> sd, IOff0 n) { if (bool(sd->status.inventory[n].equip & EPOS::SHOES)) clif_changelook(sd, LOOK::SHOES, 0); @@ -4393,17 +4396,17 @@ int pc_signal_advanced_equipment_change(dumb_ptr<map_session_data> sd, int n) return 0; } -int pc_equipitem(dumb_ptr<map_session_data> sd, int n, EPOS) +int pc_equipitem(dumb_ptr<map_session_data> sd, IOff0 n, EPOS) { - int nameid; + ItemNameId nameid; struct item_data *id; //ソス]ソスソスソスソスソス{ソスqソスフ場合ソスフ鯉ソスソスフ職ソスニゑソスソスZソスoソスソスソスソス - nullpo_ret(sd); + nullpo_retz(sd); - if (n < 0 || n >= MAX_INVENTORY) + if (!n.ok()) { - clif_equipitemack(sd, 0, EPOS::ZERO, 0); + clif_equipitemack(sd, IOff0::from(0), EPOS::ZERO, 0); return 0; } @@ -4414,7 +4417,7 @@ int pc_equipitem(dumb_ptr<map_session_data> sd, int n, EPOS) EPOS pos = pc_equippoint(sd, n); if (battle_config.battle_log) - PRINTF("equip %d (%d) %x:%x\n", + PRINTF("equip %d (%d) %x:%x\n"_fmt, nameid, n, id->equip, pos); if (!pc_isequip(sd, n) || pos == EPOS::ZERO) { @@ -4428,11 +4431,11 @@ int pc_equipitem(dumb_ptr<map_session_data> sd, int n, EPOS) { // アクセサリ用例外処理 EPOS epor = EPOS::ZERO; - int midx = sd->equip_index_maybe[EQUIP::MISC2]; - int cidx = sd->equip_index_maybe[EQUIP::CAPE]; - if (midx >= 0) + IOff0 midx = sd->equip_index_maybe[EQUIP::MISC2]; + IOff0 cidx = sd->equip_index_maybe[EQUIP::CAPE]; + if (midx.ok()) epor |= sd->status.inventory[midx].equip; - if (cidx >= 0) + if (cidx.ok()) epor |= sd->status.inventory[cidx].equip; epor &= (EPOS::MISC2 | EPOS::CAPE); pos = (epor == EPOS::CAPE ? EPOS::MISC2 : EPOS::CAPE); @@ -4442,8 +4445,8 @@ int pc_equipitem(dumb_ptr<map_session_data> sd, int n, EPOS) { if (bool(pos & equip_pos[i])) { - short *idx = &sd->equip_index_maybe[i]; - if (*idx >= 0) //Slot taken, remove item from there. + IOff0 *idx = &sd->equip_index_maybe[i]; + if ((*idx).ok()) //Slot taken, remove item from there. pc_unequipitem(sd, *idx, CalcStatus::LATER); *idx = n; } @@ -4468,7 +4471,7 @@ int pc_equipitem(dumb_ptr<map_session_data> sd, int n, EPOS) } sd->status.inventory[n].equip = pos; - int view_i = 0; + ItemNameId view_i; ItemLook view_l = ItemLook::NONE; // TODO: This is ugly. if (sd->inventory_data[n]) @@ -4495,7 +4498,7 @@ int pc_equipitem(dumb_ptr<map_session_data> sd, int n, EPOS) { if (sd->inventory_data[n]->type == ItemType::WEAPON) { - sd->status.shield = 0; + sd->status.shield = ItemNameId(); if (sd->status.inventory[n].equip == EPOS::SHIELD) sd->weapontype2 = view_l; } @@ -4507,26 +4510,26 @@ int pc_equipitem(dumb_ptr<map_session_data> sd, int n, EPOS) } else { - sd->status.shield = 0; + sd->status.shield = ItemNameId(); sd->weapontype2 = ItemLook::NONE; } pc_calcweapontype(sd); - clif_changelook(sd, LOOK::SHIELD, sd->status.shield); + clif_changelook(sd, LOOK::SHIELD, unwrap<ItemNameId>(sd->status.shield)); } if (bool(sd->status.inventory[n].equip & EPOS::LEGS)) { sd->status.head_bottom = view_i; - clif_changelook(sd, LOOK::HEAD_BOTTOM, sd->status.head_bottom); + clif_changelook(sd, LOOK::HEAD_BOTTOM, unwrap<ItemNameId>(sd->status.head_bottom)); } if (bool(sd->status.inventory[n].equip & EPOS::HAT)) { sd->status.head_top = view_i; - clif_changelook(sd, LOOK::HEAD_TOP, sd->status.head_top); + clif_changelook(sd, LOOK::HEAD_TOP, unwrap<ItemNameId>(sd->status.head_top)); } if (bool(sd->status.inventory[n].equip & EPOS::TORSO)) { sd->status.head_mid = view_i; - clif_changelook(sd, LOOK::HEAD_MID, sd->status.head_mid); + clif_changelook(sd, LOOK::HEAD_MID, unwrap<ItemNameId>(sd->status.head_mid)); } pc_signal_advanced_equipment_change(sd, n); @@ -4539,14 +4542,14 @@ int pc_equipitem(dumb_ptr<map_session_data> sd, int n, EPOS) * 装 備した物を外す *------------------------------------------ */ -int pc_unequipitem(dumb_ptr<map_session_data> sd, int n, CalcStatus type) +int pc_unequipitem(dumb_ptr<map_session_data> sd, IOff0 n, CalcStatus type) { - nullpo_ret(sd); + nullpo_retz(sd); // -- moonsoul (if player is berserk then cannot unequip) // if (battle_config.battle_log) - PRINTF("unequip %d %x:%x\n", + PRINTF("unequip %d %x:%x\n"_fmt, n, pc_equippoint(sd, n), sd->status.inventory[n].equip); if (bool(sd->status.inventory[n].equip)) @@ -4554,7 +4557,7 @@ int pc_unequipitem(dumb_ptr<map_session_data> sd, int n, CalcStatus type) for (EQUIP i : EQUIPs) { if (bool(sd->status.inventory[n].equip & equip_pos[i])) - sd->equip_index_maybe[i] = -1; + sd->equip_index_maybe[i] = IOff0::from(-1); } if (bool(sd->status.inventory[n].equip & EPOS::WEAPON)) { @@ -4565,26 +4568,25 @@ int pc_unequipitem(dumb_ptr<map_session_data> sd, int n, CalcStatus type) } if (bool(sd->status.inventory[n].equip & EPOS::SHIELD)) { - sd->status.shield = 0; + sd->status.shield = ItemNameId(); sd->weapontype2 = ItemLook::NONE; pc_calcweapontype(sd); - clif_changelook(sd, LOOK::SHIELD, sd->status.shield); + clif_changelook(sd, LOOK::SHIELD, unwrap<ItemNameId>(sd->status.shield)); } if (bool(sd->status.inventory[n].equip & EPOS::LEGS)) { - sd->status.head_bottom = 0; - clif_changelook(sd, LOOK::HEAD_BOTTOM, - sd->status.head_bottom); + sd->status.head_bottom = ItemNameId(); + clif_changelook(sd, LOOK::HEAD_BOTTOM, unwrap<ItemNameId>(sd->status.head_bottom)); } if (bool(sd->status.inventory[n].equip & EPOS::HAT)) { - sd->status.head_top = 0; - clif_changelook(sd, LOOK::HEAD_TOP, sd->status.head_top); + sd->status.head_top = ItemNameId(); + clif_changelook(sd, LOOK::HEAD_TOP, unwrap<ItemNameId>(sd->status.head_top)); } if (bool(sd->status.inventory[n].equip & EPOS::TORSO)) { - sd->status.head_mid = 0; - clif_changelook(sd, LOOK::HEAD_MID, sd->status.head_mid); + sd->status.head_mid = ItemNameId(); + clif_changelook(sd, LOOK::HEAD_MID, unwrap<ItemNameId>(sd->status.head_mid)); } pc_signal_advanced_equipment_change(sd, n); @@ -4603,7 +4605,7 @@ int pc_unequipitem(dumb_ptr<map_session_data> sd, int n, CalcStatus type) return 0; } -int pc_unequipinvyitem(dumb_ptr<map_session_data> sd, int n, CalcStatus type) +int pc_unequipinvyitem(dumb_ptr<map_session_data> sd, IOff0 n, CalcStatus type) { nullpo_retr(1, sd); @@ -4615,7 +4617,7 @@ int pc_unequipinvyitem(dumb_ptr<map_session_data> sd, int n, CalcStatus type) { //Slot taken, remove item from there. pc_unequipitem(sd, sd->equip_index_maybe[i], type); - sd->equip_index_maybe[i] = -1; + sd->equip_index_maybe[i] = IOff0::from(-1); } } @@ -4629,30 +4631,31 @@ int pc_unequipinvyitem(dumb_ptr<map_session_data> sd, int n, CalcStatus type) */ int pc_checkitem(dumb_ptr<map_session_data> sd) { - int i, j, k, id, calc_flag = 0; + int calc_flag = 0; - nullpo_ret(sd); + nullpo_retz(sd); - // 所持品空き詰め - for (i = j = 0; i < MAX_INVENTORY; i++) + IOff0 j = IOff0::from(0); + for (IOff0 i : IOff0::iter()) { - if ((id = sd->status.inventory[i].nameid) == 0) + if (!(sd->status.inventory[i].nameid)) continue; - if (i > j) + if (i != j) { sd->status.inventory[j] = sd->status.inventory[i]; sd->inventory_data[j] = sd->inventory_data[i]; } - j++; + ++j; + } + for (IOff0 k = j; k != IOff0::from(MAX_INVENTORY); ++k) + { + sd->status.inventory[k] = Item{}; + sd->inventory_data[k] = nullptr; } - for (k = j; k < MAX_INVENTORY; ++k) - sd->status.inventory[k] = item{}; - for (k = j; k < MAX_INVENTORY; k++) - sd->inventory_data[k] = NULL; - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { - if (sd->status.inventory[i].nameid == 0) + if (!sd->status.inventory[i].nameid) continue; if (bool(sd->status.inventory[i].equip & ~pc_equippoint(sd, i))) { @@ -4670,7 +4673,7 @@ int pc_checkitem(dumb_ptr<map_session_data> sd) int pc_checkoverhp(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); if (sd->status.hp == sd->status.max_hp) return 1; @@ -4686,7 +4689,7 @@ int pc_checkoverhp(dumb_ptr<map_session_data> sd) int pc_checkoversp(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); if (sd->status.sp == sd->status.max_sp) return 1; @@ -4723,9 +4726,9 @@ void pc_calc_pvprank_sub(dumb_ptr<block_list> bl, dumb_ptr<map_session_data> sd2 */ int pc_calc_pvprank(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); map_local *m = sd->bl_m; - nullpo_ret(m); + nullpo_retz(m); if (!(m->flag.get(MapFlag::PVP))) return 0; @@ -4742,20 +4745,22 @@ int pc_calc_pvprank(dumb_ptr<map_session_data> sd) * PVP順位計算(timer) *------------------------------------------ */ -void pc_calc_pvprank_timer(TimerData *, tick_t, int id) +void pc_calc_pvprank_timer(TimerData *, tick_t, BlockId id) { - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; if (battle_config.pk_mode) // disable pvp ranking if pk_mode on [Valaris] return; sd = map_id2sd(id); - if (sd == NULL) + if (sd == nullptr) return; sd->pvp_timer.cancel(); if (pc_calc_pvprank(sd) > 0) + { sd->pvp_timer = Timer(gettick() + PVP_CALCRANK_INTERVAL, std::bind(pc_calc_pvprank_timer, ph::_1, ph::_2, id)); + } } /*========================================== @@ -4763,14 +4768,14 @@ void pc_calc_pvprank_timer(TimerData *, tick_t, int id) *------------------------------------------ */ static -int pc_ismarried(dumb_ptr<map_session_data> sd) +CharId pc_ismarried(dumb_ptr<map_session_data> sd) { - if (sd == NULL) - return -1; - if (sd->status.partner_id > 0) + if (sd == nullptr) + return CharId(); + if (sd->status.partner_id) return sd->status.partner_id; else - return 0; + return CharId(); } /*========================================== @@ -4779,8 +4784,8 @@ int pc_ismarried(dumb_ptr<map_session_data> sd) */ int pc_marriage(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> dstsd) { - if (sd == NULL || dstsd == NULL || sd->status.partner_id > 0 - || dstsd->status.partner_id > 0) + if (sd == nullptr || dstsd == nullptr || sd->status.partner_id + || dstsd->status.partner_id) return -1; sd->status.partner_id = dstsd->status_key.char_id; dstsd->status.partner_id = sd->status_key.char_id; @@ -4793,23 +4798,23 @@ int pc_marriage(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> dstsd) */ int pc_divorce(dumb_ptr<map_session_data> sd) { - dumb_ptr<map_session_data> p_sd = NULL; - if (sd == NULL || !pc_ismarried(sd)) + dumb_ptr<map_session_data> p_sd = nullptr; + if (sd == nullptr || !pc_ismarried(sd)) return -1; // If both are on map server we don't need to bother the char server if ((p_sd = - map_nick2sd(map_charid2nick(sd->status.partner_id))) != NULL) + map_nick2sd(map_charid2nick(sd->status.partner_id))) != nullptr) { if (p_sd->status.partner_id != sd->status_key.char_id || sd->status.partner_id != p_sd->status_key.char_id) { - PRINTF("pc_divorce: Illegal partner_id sd=%d p_sd=%d\n", + PRINTF("pc_divorce: Illegal partner_id sd=%d p_sd=%d\n"_fmt, sd->status.partner_id, p_sd->status.partner_id); return -1; } - p_sd->status.partner_id = 0; - sd->status.partner_id = 0; + p_sd->status.partner_id = CharId(); + sd->status.partner_id = CharId(); if (sd->npc_flags.divorce) { @@ -4829,17 +4834,17 @@ int pc_divorce(dumb_ptr<map_session_data> sd) */ dumb_ptr<map_session_data> pc_get_partner(dumb_ptr<map_session_data> sd) { - dumb_ptr<map_session_data> p_sd = NULL; - if (sd == NULL || !pc_ismarried(sd)) - return NULL; + dumb_ptr<map_session_data> p_sd = nullptr; + if (sd == nullptr || !pc_ismarried(sd)) + return nullptr; CharName nick = map_charid2nick(sd->status.partner_id); if (!nick.to__actual()) - return NULL; + return nullptr; - if ((p_sd = map_nick2sd(nick)) == NULL) - return NULL; + if ((p_sd = map_nick2sd(nick)) == nullptr) + return nullptr; return p_sd; } @@ -4890,7 +4895,7 @@ int pc_natural_heal_hp(dumb_ptr<map_session_data> sd) int bhp; int bonus; - nullpo_ret(sd); + nullpo_retz(sd); if (pc_checkoverhp(sd)) { @@ -4962,7 +4967,7 @@ int pc_natural_heal_sp(dumb_ptr<map_session_data> sd) int bsp; int bonus; - nullpo_ret(sd); + nullpo_retz(sd); if (pc_checkoversp(sd)) { @@ -5035,7 +5040,7 @@ int pc_quickregenerate_effect(struct quick_regeneration *quick_regen, if (!(quick_regen->tickdelay--)) { int bonus = - min(heal_speed * battle_config.itemheal_regeneration_factor, + std::min(heal_speed * battle_config.itemheal_regeneration_factor, quick_regen->amount); quick_regen->amount -= bonus; @@ -5171,21 +5176,20 @@ void pc_autosave(TimerData *, tick_t) interval_t interval = autosave_time / (clif_countusers() + 1); if (interval <= interval_t::zero()) - interval = std::chrono::milliseconds(1); + interval = 1_ms; Timer(gettick() + interval, pc_autosave ).detach(); } -int pc_read_gm_account(Session *s) +int pc_read_gm_account(Session *, const std::vector<Packet_Repeat<0x2b15>>& repeat) { gm_accountm.clear(); - // (RFIFOW(fd, 2) - 4) / 5 - for (int i = 4; i < RFIFOW(s, 2); i += 5) + for (const auto& i : repeat) { - int account_id = RFIFOL(s, i); - uint8_t level = RFIFOB(s, i + 4); + AccountId account_id = i.account_id; + GmLevel level = i.gm_level; gm_accountm[account_id] = level; } return gm_accountm.size(); @@ -5230,7 +5234,7 @@ void do_init_pc(void) void pc_cleanup(dumb_ptr<map_session_data> sd) { - magic_stop_completely(sd); + magic::magic_stop_completely(sd); } void pc_invisibility(dumb_ptr<map_session_data> sd, int enabled) @@ -5265,13 +5269,14 @@ int pc_logout(dumb_ptr<map_session_data> sd) // [fate] Player logs out // Removed because it's buggy, see above. if (sd->cast_tick > tick) { - if (pc_setglobalreg(sd, "MAGIC_CAST_TICK", sd->cast_tick - tick)) + if (pc_setglobalreg(sd, "MAGIC_CAST_TICK"_s, sd->cast_tick - tick)) sd->status.sp = 1; } else #endif - pc_setglobalreg(sd, stringish<VarName>("MAGIC_CAST_TICK"), 0); + pc_setglobalreg(sd, stringish<VarName>("MAGIC_CAST_TICK"_s), 0); - MAP_LOG_STATS(sd, "LOGOUT"); + MAP_LOG_STATS(sd, "LOGOUT"_fmt); return 0; } +} // namespace tmwa diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 35d9c70..3187cd9 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_PC_HPP -#define TMWA_MAP_PC_HPP +#pragma once // pc.hpp - Player state changes. // // Copyright © ????-2004 Athena Dev Teams @@ -21,15 +20,24 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "pc.t.hpp" +#include "pc.t.hpp" -# include "../strings/fwd.hpp" +#include "../strings/fwd.hpp" -# include "clif.t.hpp" -# include "map.hpp" +#include "../generic/dumb_ptr.hpp" +#include "../mmo/utils.hpp" + +#include "../proto2/fwd.hpp" + +#include "clif.t.hpp" +#include "map.hpp" + + +namespace tmwa +{ inline void pc_setsit(dumb_ptr<map_session_data> sd) { @@ -66,7 +74,7 @@ bool pc_is90overweight(dumb_ptr<map_session_data> sd) // should do something with the specified player. void pc_touch_all_relevant_npcs(dumb_ptr<map_session_data> sd); -uint8_t pc_isGM(dumb_ptr<map_session_data> sd); +GmLevel pc_isGM(dumb_ptr<map_session_data> sd); int pc_iskiller(dumb_ptr<map_session_data> src, dumb_ptr<map_session_data> target); // [MouseJstr] void pc_invisibility(dumb_ptr<map_session_data> sd, int enabled); // [Fate] @@ -74,14 +82,14 @@ int pc_counttargeted(dumb_ptr<map_session_data> sd, dumb_ptr<block_list> src, ATK target_lv); int pc_setrestartvalue(dumb_ptr<map_session_data> sd, int type); void pc_makesavestatus(dumb_ptr<map_session_data>); -int pc_setnewpc(dumb_ptr<map_session_data>, int, int, int, tick_t, SEX); -int pc_authok(int, int, TimeT, short tmw_version, const CharKey *, const CharData *); -int pc_authfail(int accid); +int pc_setnewpc(dumb_ptr<map_session_data>, AccountId, CharId, int, uint32_t /*tick_t*/, SEX); +int pc_authok(AccountId, int, TimeT, short tmw_version, const CharKey *, const CharData *); +int pc_authfail(AccountId accid); -EPOS pc_equippoint(dumb_ptr<map_session_data> sd, int n); +EPOS pc_equippoint(dumb_ptr<map_session_data> sd, IOff0 n); int pc_checkskill(dumb_ptr<map_session_data> sd, SkillID skill_id); -int pc_checkequip(dumb_ptr<map_session_data> sd, EPOS pos); +IOff0 pc_checkequip(dumb_ptr<map_session_data> sd, EPOS pos); int pc_walktoxy(dumb_ptr<map_session_data>, int, int); int pc_stop_walking(dumb_ptr<map_session_data>, int); @@ -90,20 +98,20 @@ int pc_setpos(dumb_ptr<map_session_data>, MapName, int, int, BeingRemoveWhy); void pc_setsavepoint(dumb_ptr<map_session_data>, MapName, int, int); int pc_randomwarp(dumb_ptr<map_session_data> sd, BeingRemoveWhy type); -ADDITEM pc_checkadditem(dumb_ptr<map_session_data>, int, int); +ADDITEM pc_checkadditem(dumb_ptr<map_session_data>, ItemNameId, int); int pc_inventoryblank(dumb_ptr<map_session_data>); -int pc_search_inventory(dumb_ptr<map_session_data> sd, int item_id); +IOff0 pc_search_inventory(dumb_ptr<map_session_data> sd, ItemNameId item_id); int pc_payzeny(dumb_ptr<map_session_data>, int); -PickupFail pc_additem(dumb_ptr<map_session_data>, struct item *, int); +PickupFail pc_additem(dumb_ptr<map_session_data>, Item *, int); int pc_getzeny(dumb_ptr<map_session_data>, int); -int pc_delitem(dumb_ptr<map_session_data>, int, int, int); +int pc_delitem(dumb_ptr<map_session_data>, IOff0, int, int); int pc_checkitem(dumb_ptr<map_session_data>); -int pc_count_all_items(dumb_ptr<map_session_data> player, int item_id); +int pc_count_all_items(dumb_ptr<map_session_data> player, ItemNameId item_id); int pc_remove_items(dumb_ptr<map_session_data> player, - int item_id, int count); + ItemNameId item_id, int count); int pc_takeitem(dumb_ptr<map_session_data>, dumb_ptr<flooritem_data>); -int pc_dropitem(dumb_ptr<map_session_data>, int, int); +int pc_dropitem(dumb_ptr<map_session_data>, IOff0, int); int pc_checkweighticon(dumb_ptr<map_session_data> sd); @@ -112,7 +120,7 @@ int pc_bonus(dumb_ptr<map_session_data>, SP, int); int pc_bonus2(dumb_ptr<map_session_data> sd, SP, int, int); int pc_skill(dumb_ptr<map_session_data>, SkillID, int, int); -int pc_attack(dumb_ptr<map_session_data>, int, int); +int pc_attack(dumb_ptr<map_session_data>, BlockId, int); int pc_stopattack(dumb_ptr<map_session_data>); int pc_gainexp_reason(dumb_ptr<map_session_data>, int, int, @@ -128,10 +136,10 @@ int pc_skillup(dumb_ptr<map_session_data>, SkillID); int pc_resetlvl(dumb_ptr<map_session_data>, int type); int pc_resetstate(dumb_ptr<map_session_data>); int pc_resetskill(dumb_ptr<map_session_data>); -int pc_equipitem(dumb_ptr<map_session_data>, int, EPOS); -int pc_unequipitem(dumb_ptr<map_session_data>, int, CalcStatus); -int pc_unequipinvyitem(dumb_ptr<map_session_data>, int, CalcStatus); -int pc_useitem(dumb_ptr<map_session_data>, int); +int pc_equipitem(dumb_ptr<map_session_data>, IOff0, EPOS); +int pc_unequipitem(dumb_ptr<map_session_data>, IOff0, CalcStatus); +int pc_unequipinvyitem(dumb_ptr<map_session_data>, IOff0, CalcStatus); +int pc_useitem(dumb_ptr<map_session_data>, IOff0); int pc_damage(dumb_ptr<block_list>, dumb_ptr<map_session_data>, int); int pc_heal(dumb_ptr<map_session_data>, int, int); @@ -158,17 +166,17 @@ int pc_addeventtimer(dumb_ptr<map_session_data> sd, interval_t tick, int pc_cleareventtimer(dumb_ptr<map_session_data> sd); int pc_calc_pvprank(dumb_ptr<map_session_data> sd); -void pc_calc_pvprank_timer(TimerData *, tick_t, int); +void pc_calc_pvprank_timer(TimerData *, tick_t, BlockId); int pc_marriage(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> dstsd); int pc_divorce(dumb_ptr<map_session_data> sd); dumb_ptr<map_session_data> pc_get_partner(dumb_ptr<map_session_data> sd); -void pc_set_gm_level(int account_id, uint8_t level); +void pc_set_gm_level(AccountId account_id, GmLevel level); void pc_setstand(dumb_ptr<map_session_data> sd); void pc_cleanup(dumb_ptr<map_session_data> sd); // [Fate] Clean up after a logged-out PC -int pc_read_gm_account(Session *); +int pc_read_gm_account(Session *, const std::vector<Packet_Repeat<0x2b15>>&); int pc_setinvincibletimer(dumb_ptr<map_session_data> sd, interval_t); int pc_delinvincibletimer(dumb_ptr<map_session_data> sd); int pc_logout(dumb_ptr<map_session_data> sd); // [fate] Player logs out @@ -176,5 +184,4 @@ int pc_logout(dumb_ptr<map_session_data> sd); // [fate] Player logs out void pc_show_motd(dumb_ptr<map_session_data> sd); void do_init_pc(void); - -#endif // TMWA_MAP_PC_HPP +} // namespace tmwa diff --git a/src/map/pc.t.hpp b/src/map/pc.t.hpp index 65e1046..427e8c3 100644 --- a/src/map/pc.t.hpp +++ b/src/map/pc.t.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_PC_T_HPP -#define TMWA_MAP_PC_T_HPP +#pragma once // pc.t.hpp - Player state changes. // // Copyright © ????-2004 Athena Dev Teams @@ -22,10 +21,13 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include <cstdint> +#include <cstdint> + +namespace tmwa +{ enum class PC_GAINEXP_REASON { KILLING = 0, @@ -50,18 +52,6 @@ enum class ADDITEM enum class CalcStatus { NOW, - LATER , -}; - -enum class PickupFail : uint8_t -{ - OKAY = 0, - BAD_ITEM = 1, - TOO_HEAVY = 2, - TOO_FAR = 3, - INV_FULL = 4, - STACK_FULL = 5, - DROP_STEAL = 6, + LATER, }; - -#endif // TMWA_MAP_PC_T_HPP +} // namespace tmwa diff --git a/src/map/script.cpp b/src/map/script.cpp index 93f9d31..329b47f 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -23,12 +23,11 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include <cassert> -#include <cctype> #include <cmath> #include <cstdlib> -#include <cstring> #include <ctime> +#include <algorithm> #include <set> #include "../compat/fun.hpp" @@ -38,21 +37,25 @@ #include "../strings/astring.hpp" #include "../strings/zstring.hpp" #include "../strings/xstring.hpp" +#include "../strings/literal.hpp" #include "../generic/db.hpp" #include "../generic/intern-pool.hpp" #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" +#include "../io/cxxstdio_enums.hpp" #include "../io/lock.hpp" #include "../io/read.hpp" +#include "../io/write.hpp" + +#include "../net/socket.hpp" +#include "../net/timer.hpp" -#include "../mmo/config_parse.hpp" #include "../mmo/core.hpp" #include "../mmo/extract.hpp" -#include "../mmo/socket.hpp" +#include "../mmo/human_time_diff.hpp" #include "../mmo/utils.hpp" -#include "../mmo/timer.hpp" #include "atcommand.hpp" #include "battle.hpp" @@ -60,7 +63,7 @@ #include "clif.hpp" #include "intif.hpp" #include "itemdb.hpp" -#include "magic.hpp" +#include "magic-interpreter-base.hpp" #include "map.hpp" #include "mob.hpp" #include "npc.hpp" @@ -71,6 +74,9 @@ #include "../poison.hpp" + +namespace tmwa +{ constexpr bool DEBUG_DISP = false; constexpr bool DEBUG_RUN = false; @@ -93,8 +99,8 @@ static Map<SIR, RString> mapregstr_db; static int mapreg_dirty = -1; -AString mapreg_txt = "save/mapreg.txt"; -constexpr std::chrono::milliseconds MAPREG_AUTOSAVE_INTERVAL = std::chrono::seconds(10); +AString mapreg_txt = "save/mapreg.txt"_s; +constexpr std::chrono::milliseconds MAPREG_AUTOSAVE_INTERVAL = 10_s; Map<ScriptLabel, int> scriptlabel_db; static @@ -102,19 +108,19 @@ std::set<ScriptLabel> probable_labels; UPMap<RString, const ScriptBuffer> userfunc_db; static -Array<ZString, 11> pos_str //= +Array<LString, 11> pos_str //= {{ - ZString("Head"), - ZString("Body"), - ZString("Left hand"), - ZString("Right hand"), - ZString("Robe"), - ZString("Shoes"), - ZString("Accessory 1"), - ZString("Accessory 2"), - ZString("Head 2"), - ZString("Head 3"), - ZString("Not Equipped"), + "Head"_s, + "Body"_s, + "Left hand"_s, + "Right hand"_s, + "Robe"_s, + "Shoes"_s, + "Accessory 1"_s, + "Accessory 2"_s, + "Head 2"_s, + "Head 3"_s, + "Not Equipped"_s, }}; static @@ -150,8 +156,9 @@ void mapreg_setregstr(SIR num, XString str); struct BuiltinFunction { void (*func)(ScriptState *); - ZString name; - ZString arg; + LString name; + LString arg; + char ret; }; // defined later extern BuiltinFunction builtin_functions[]; @@ -382,15 +389,15 @@ void disp_error_message(ZString mes, ZString::iterator pos_) ZString::iterator lineend = std::find(p, startptr.end(), '\n'); if (pos_ < lineend) { - PRINTF("\n%s\nline %d : ", mes, line); + PRINTF("\n%s\nline %d : "_fmt, mes, line); for (int i = 0; linestart + i != lineend; i++) { if (linestart + i != pos_) - PRINTF("%c", linestart[i]); + PRINTF("%c"_fmt, linestart[i]); else - PRINTF("\'%c\'", linestart[i]); + PRINTF("\'%c\'"_fmt, linestart[i]); } - PRINTF("\a\n"); + PRINTF("\a\n"_fmt); return; } p = lineend + 1; @@ -407,7 +414,7 @@ ZString::iterator ScriptBuffer::parse_simpleexpr(ZString::iterator p) if (*p == ';' || *p == ',') { - disp_error_message("unexpected expr end", p); + disp_error_message("unexpected expr end"_s, p); exit(1); } if (*p == '(') @@ -417,7 +424,7 @@ ZString::iterator ScriptBuffer::parse_simpleexpr(ZString::iterator p) p = skip_space(p); if ((*p++) != ')') { - disp_error_message("unmatch ')'", p); + disp_error_message("unmatch ')'"_s, p); exit(1); } } @@ -438,14 +445,14 @@ ZString::iterator ScriptBuffer::parse_simpleexpr(ZString::iterator p) p++; else if (*p == '\n') { - disp_error_message("unexpected newline @ string", p); + disp_error_message("unexpected newline @ string"_s, p); exit(1); } add_scriptb(*p++); } if (!*p) { - disp_error_message("unexpected eof @ string", p); + disp_error_message("unexpected eof @ string"_s, p); exit(1); } add_scriptb(0); @@ -457,35 +464,35 @@ ZString::iterator ScriptBuffer::parse_simpleexpr(ZString::iterator p) ZString::iterator p2 = skip_word(p); if (p2 == p) { - disp_error_message("unexpected character", p); + disp_error_message("unexpected character"_s, p); exit(1); } XString word(&*p, &*p2, nullptr); - if (word.startswith("On") || word.startswith("L_") || word.startswith("S_")) + if (word.startswith("On"_s) || word.startswith("L_"_s) || word.startswith("S_"_s)) probable_labels.insert(stringish<ScriptLabel>(word)); - if (parse_cmd_if && (word == "callsub" || word == "callfunc" || word == "return")) + if (parse_cmd_if && (word == "callsub"_s || word == "callfunc"_s || word == "return"_s)) { - disp_error_message("Sorry, callsub/callfunc/return have never worked properly in an if statement.", p); + disp_error_message("Sorry, callsub/callfunc/return have never worked properly in an if statement."_s, p); } str_data_t *ld = add_strp(word); parse_cmdp = ld; // warn_*_mismatch_paramnumのために必要 - // why not just check l->str == "if" or std::string(p, p2) == "if"? - if (ld == search_strp("if")) // warn_cmd_no_commaのために必要 + // why not just check l->str == "if"_s or std::string(p, p2) == "if"_s? + if (ld == search_strp("if"_s)) // warn_cmd_no_commaのために必要 parse_cmd_if++; p = p2; if (ld->type != ByteCode::FUNC_ && *p == '[') { // array(name[i] => getelementofarray(name,i) ) - add_scriptl(search_strp("getelementofarray")); + add_scriptl(search_strp("getelementofarray"_s)); add_scriptc(ByteCode::ARG); add_scriptl(ld); p = parse_subexpr(p + 1, -1); p = skip_space(p); if (*p != ']') { - disp_error_message("unmatch ']'", p); + disp_error_message("unmatch ']'"_s, p); exit(1); } p++; @@ -515,7 +522,7 @@ ZString::iterator ScriptBuffer::parse_subexpr(ZString::iterator p, int limit) ZString::iterator tmpp = skip_space(p + 1); if (*tmpp == ';' || *tmpp == ',') { - --script_errors; disp_error_message("deprecated: implicit 'next statement' label", p); + --script_errors; disp_error_message("deprecated: implicit 'next statement' label"_s, p); add_scriptl(&LABEL_NEXTLINE_); p++; return p; @@ -560,7 +567,7 @@ ZString::iterator ScriptBuffer::parse_subexpr(ZString::iterator p, int limit) if (funcp->type != ByteCode::FUNC_) { - disp_error_message("expect function", tmpp); + disp_error_message("expect function"_s, tmpp); exit(0); } @@ -574,7 +581,7 @@ ZString::iterator ScriptBuffer::parse_subexpr(ZString::iterator p, int limit) p++; else if (*p != ')' && script_config.warn_func_no_comma) { - disp_error_message("expect ',' or ')' at func params", + disp_error_message("expect ',' or ')' at func params"_s, p); } p = skip_space(p); @@ -583,7 +590,7 @@ ZString::iterator ScriptBuffer::parse_subexpr(ZString::iterator p, int limit) plist[i] = p; if (*p != ')') { - disp_error_message("func request '(' ')'", p); + disp_error_message("func request '(' ')'"_s, p); exit(1); } p++; @@ -593,14 +600,19 @@ ZString::iterator ScriptBuffer::parse_subexpr(ZString::iterator p, int limit) { ZString arg = builtin_functions[funcp->val].arg; int j = 0; + // TODO handle ? and multiple * correctly for (j = 0; arg[j]; j++) - if (arg[j] == '*') + if (arg[j] == '*' || arg[j] == '?') break; - if ((arg[j] == 0 && i != j) || (arg[j] == '*' && i < j)) + if ((arg[j] == 0 && i != j) || ((arg[j] == '*' || arg[j] == '?') && i < j)) { - disp_error_message("illegal number of parameters", + disp_error_message("illegal number of parameters"_s, plist[std::min(i, j)]); } + if (!builtin_functions[funcp->val].ret) + { + disp_error_message("statement in function context"_s, tmpp); + } } } else // not op == ByteCode::FUNC @@ -627,7 +639,7 @@ ZString::iterator ScriptBuffer::parse_expr(ZString::iterator p) case '[': case ']': case '}': - disp_error_message("unexpected char", p); + disp_error_message("unexpected char"_s, p); exit(1); } p = parse_subexpr(p, -1); @@ -657,21 +669,22 @@ ZString::iterator ScriptBuffer::parse_line(ZString::iterator p, bool *can_step) str_data_t *cmd = parse_cmdp; if (cmd->type != ByteCode::FUNC_) { - disp_error_message("expect command", p2); + disp_error_message("expect command"_s, p2); // exit(0); } { + // TODO should be LString, but no heterogenous lookup yet static std::set<ZString> terminators = { - "goto", - "return", - "close", - "menu", - "end", - "mapexit", - "shop", + "goto"_s, + "return"_s, + "close"_s, + "menu"_s, + "end"_s, + "mapexit"_s, + "shop"_s, }; *can_step = terminators.count(cmd->strs) == 0; } @@ -689,7 +702,7 @@ ZString::iterator ScriptBuffer::parse_line(ZString::iterator p, bool *can_step) else if (*p != ';' && script_config.warn_cmd_no_comma && parse_cmd_if * 2 <= i) { - disp_error_message("expect ',' or ';' at cmd params", p); + disp_error_message("expect ',' or ';' at cmd params"_s, p); } p = skip_space(p); i++; @@ -697,7 +710,7 @@ ZString::iterator ScriptBuffer::parse_line(ZString::iterator p, bool *can_step) plist[i] = p; if (*(p++) != ';') { - disp_error_message("need ';'", p); + disp_error_message("need ';'"_s, p); exit(1); } add_scriptc(ByteCode::FUNC_); @@ -707,14 +720,19 @@ ZString::iterator ScriptBuffer::parse_line(ZString::iterator p, bool *can_step) { ZString arg = builtin_functions[cmd->val].arg; int j = 0; + // TODO see above for (j = 0; arg[j]; j++) - if (arg[j] == '*') + if (arg[j] == '*' || arg[j] == '?') break; - if ((arg[j] == 0 && i != j) || (arg[j] == '*' && i < j)) + if ((arg[j] == 0 && i != j) || ((arg[j] == '*' || arg[j] == '?') && i < j)) { - disp_error_message("illegal number of parameters", + disp_error_message("illegal number of parameters"_s, plist[std::min(i, j)]); } + if (builtin_functions[cmd->val].ret) + { + disp_error_message("function in statement context"_s, p2); + } } return p; @@ -740,24 +758,50 @@ bool read_constdb(ZString filename) io::ReadFile in(filename); if (!in.is_open()) { - PRINTF("can't read %s\n", filename); + PRINTF("can't read %s\n"_fmt, filename); return false; } bool rv = true; - AString line; - while (in.getline(line)) - { - if (is_comment(line)) + AString line_; + while (in.getline(line_)) + { + // is_comment only works for whole-line comments + // that could change once the Z dependency is dropped ... + LString comment = "//"_s; + XString line = line_.xislice_h(std::search(line_.begin(), line_.end(), comment.begin(), comment.end())).rstrip(); + if (!line) continue; + // "%m[A-Za-z0-9_] %i %i" + + // TODO promote either qsplit() or asplit() + auto _it = std::find(line.begin(), line.end(), ' '); + auto name = line.xislice_h(_it); + auto _rest = line.xislice_t(_it); + while (_rest.startswith(' ')) + _rest = _rest.xslice_t(1); + auto _it2 = std::find(_rest.begin(), _rest.end(), ' '); + auto val_ = _rest.xislice_h(_it2); + auto type_ = _rest.xislice_t(_it2); + while (type_.startswith(' ')) + type_ = type_.xslice_t(1); + // yes, the above actually DTRT even for underlength input - AString name; int val; - int type = 0; // if not provided - // TODO get rid of SSCANF - this is the last serious use - if (SSCANF(line, "%m[A-Za-z0-9_] %i %i", &name, &val, &type) < 2) + int type = 0; + // Note for future archeaologists: this code is indented correctly + if (std::find_if_not(name.begin(), name.end(), + [](char c) + { + return ('0' <= c && c <= '9') + || ('A' <= c && c <= 'Z') + || ('a' <= c && c <= 'z') + || (c == '_'); + }) != name.end() + || !extract(val_, &val) + || (!extract(type_, &type) && type_)) { - PRINTF("Bad const line: %s\n", line); + PRINTF("Bad const line: %s\n"_fmt, line_); rv = false; continue; } @@ -815,7 +859,7 @@ void ScriptBuffer::parse_script(ZString src, int line, bool implicit_end) p = skip_space(p); if (*p != '{') { - disp_error_message("not found '{'", p); + disp_error_message("not found '{'"_s, p); abort(); } for (p++; *p && *p != '}';) @@ -825,7 +869,7 @@ void ScriptBuffer::parse_script(ZString src, int line, bool implicit_end) { if (can_step) { - --script_errors; disp_error_message("deprecated: implicit fallthrough", p); + --script_errors; disp_error_message("deprecated: implicit fallthrough"_s, p); } can_step = true; @@ -838,7 +882,7 @@ void ScriptBuffer::parse_script(ZString src, int line, bool implicit_end) assert (e1 == e2 && e2 == e3); if (e3) { - disp_error_message("dup label ", p); + disp_error_message("dup label "_s, p); exit(1); } set_label(ld, script_buf.size()); @@ -849,7 +893,7 @@ void ScriptBuffer::parse_script(ZString src, int line, bool implicit_end) if (!can_step) { - --script_errors; disp_error_message("deprecated: unreachable statement", p); + --script_errors; disp_error_message("deprecated: unreachable statement"_s, p); } // 他は全部一緒くた p = parse_line(p, &can_step); @@ -864,7 +908,7 @@ void ScriptBuffer::parse_script(ZString src, int line, bool implicit_end) if (can_step && !implicit_end) { - --script_errors; disp_error_message("deprecated: implicit end", p); + --script_errors; disp_error_message("deprecated: implicit end"_s, p); } add_scriptc(ByteCode::NOP); @@ -893,17 +937,17 @@ void ScriptBuffer::parse_script(ZString src, int line, bool implicit_end) for (const auto& pair : scriptlabel_db) { ScriptLabel key = pair.first; - if (key.startswith("On")) + if (key.startswith("On"_s)) continue; - if (!(key.startswith("L_") || key.startswith("S_"))) - PRINTF("Warning: ugly label: %s\n", key); + if (!(key.startswith("L_"_s) || key.startswith("S_"_s))) + PRINTF("Warning: ugly label: %s\n"_fmt, key); else if (!probable_labels.count(key)) - PRINTF("Warning: unused label: %s\n", key); + PRINTF("Warning: unused label: %s\n"_fmt, key); } for (ScriptLabel used : probable_labels) { if (!scriptlabel_db.search(used)) - PRINTF("Warning: no such label: %s\n", used); + PRINTF("Warning: no such label: %s\n"_fmt, used); } probable_labels.clear(); @@ -912,12 +956,12 @@ void ScriptBuffer::parse_script(ZString src, int line, bool implicit_end) for (size_t i = 0; i < script_buf.size(); i++) { if ((i & 15) == 0) - PRINTF("%04zx : ", i); - PRINTF("%02x ", script_buf[i]); + PRINTF("%04zx : "_fmt, i); + PRINTF("%02x "_fmt, script_buf[i]); if ((i & 15) == 15) - PRINTF("\n"); + PRINTF("\n"_fmt); } - PRINTF("\n"); + PRINTF("\n"_fmt); } // @@ -943,7 +987,7 @@ dumb_ptr<map_session_data> script_rid2sd(ScriptState *st) dumb_ptr<map_session_data> sd = map_id2sd(st->rid); if (!sd) { - PRINTF("script_rid2sd: fatal error ! player not attached!\n"); + PRINTF("script_rid2sd: fatal error ! player not attached!\n"_fmt); } return sd; } @@ -957,8 +1001,8 @@ void get_val(dumb_ptr<map_session_data> sd, struct script_data *data) { if (data->type == ByteCode::PARAM_) { - if (sd == NULL) - PRINTF("get_val error param SP::%d\n", data->u.reg.sp()); + if (sd == nullptr) + PRINTF("get_val error param SP::%d\n"_fmt, data->u.reg.sp()); data->type = ByteCode::INT; if (sd) data->u.numi = pc_readparam(sd, data->u.reg.sp()); @@ -972,8 +1016,8 @@ void get_val(dumb_ptr<map_session_data> sd, struct script_data *data) if (prefix != '$') { - if (sd == NULL) - PRINTF("get_val error name?:%s\n", name); + if (sd == nullptr) + PRINTF("get_val error name?:%s\n"_fmt, name); } if (postfix == '$') { @@ -990,11 +1034,11 @@ void get_val(dumb_ptr<map_session_data> sd, struct script_data *data) } else { - PRINTF("script: get_val: illegal scope string variable.\n"); - data->u.str = dumb_string::fake("!!ERROR!!"); + PRINTF("script: get_val: illegal scope string variable.\n"_fmt); + data->u.str = dumb_string::fake("!!ERROR!!"_s); } if (!data->u.str) - data->u.str = dumb_string::fake(""); + data->u.str = dumb_string::fake(""_s); } else { @@ -1085,7 +1129,7 @@ void set_reg(dumb_ptr<map_session_data> sd, ByteCode type, SIR reg, struct scrip } else { - PRINTF("script: set_reg: illegal scope string variable !"); + PRINTF("script: set_reg: illegal scope string variable !"_fmt); } } else @@ -1143,7 +1187,7 @@ dumb_string conv_str(ScriptState *st, struct script_data *data) assert (data->type != ByteCode::RETINFO); if (data->type == ByteCode::INT) { - AString buf = STRPRINTF("%d", data->u.numi); + AString buf = STRPRINTF("%d"_fmt, data->u.numi); data->type = ByteCode::STR; data->u.str = dumb_string::copys(buf); } @@ -1285,7 +1329,7 @@ void builtin_goto(ScriptState *st) { if (AARGO2(2).type != ByteCode::POS) { - PRINTF("script: goto: not label !\n"); + PRINTF("script: goto: not label !\n"_fmt); st->state = ScriptEndState::END; return; } @@ -1324,7 +1368,7 @@ void builtin_callfunc(ScriptState *st) } else { - PRINTF("script:callfunc: function not found! [%s]\n", str); + PRINTF("script:callfunc: function not found! [%s]\n"_fmt, str); st->state = ScriptEndState::END; } } @@ -1442,7 +1486,7 @@ void builtin_menu(ScriptState *st) // not just the displayed number that ends with the "". // (Would it be better to pop the stack before rerunning?) int menu_choices = (st->end - (st->start + 2)) / 2; - pc_setreg(sd, SIR::from(variable_names.intern("@menu")), sd->npc_menu); + pc_setreg(sd, SIR::from(variable_names.intern("@menu"_s)), sd->npc_menu); sd->state.menu_or_input = 0; if (sd->npc_menu > 0 && sd->npc_menu <= menu_choices) { @@ -1481,23 +1525,6 @@ void builtin_rand(ScriptState *st) } /*========================================== - * - *------------------------------------------ - */ -static -void builtin_pow(ScriptState *st) -{ - int a, b; - - a = conv_num(st, &AARGO2(2)); - b = conv_num(st, &AARGO2(3)); - -#warning "This is silly" - push_int(st->stack, ByteCode::INT, static_cast<int>(pow(a * 0.001, b))); - -} - -/*========================================== * Check whether the PC is at the specified location *------------------------------------------ */ @@ -1532,9 +1559,9 @@ void builtin_warp(ScriptState *st) MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); x = conv_num(st, &AARGO2(3)); y = conv_num(st, &AARGO2(4)); - if (str == "Random") + if (str == "Random"_s) pc_randomwarp(sd, BeingRemoveWhy::WARPED); - else if (str == "SavePoint" or str == "Save") + else if (str == "SavePoint"_s or str == "Save"_s) { if (sd->bl_m->flag.get(MapFlag::NORETURN)) return; @@ -1554,7 +1581,7 @@ static void builtin_areawarp_sub(dumb_ptr<block_list> bl, MapName mapname, int x, int y) { dumb_ptr<map_session_data> sd = bl->is_player(); - if (mapname == "Random") + if (mapname == "Random"_s) pc_randomwarp(sd, BeingRemoveWhy::WARPED); else pc_setpos(sd, mapname, x, y, BeingRemoveWhy::GONE); @@ -1635,7 +1662,7 @@ void builtin_percentheal(ScriptState *st) static void builtin_input(ScriptState *st) { - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; script_data& scrd = AARGO2(2); ByteCode type = scrd.type; assert (type == ByteCode::VARIABLE); @@ -1712,7 +1739,7 @@ void builtin_if (ScriptState *st) static void builtin_set(ScriptState *st) { - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; SIR reg = AARGO2(2).u.reg; if (AARGO2(2).type == ByteCode::PARAM_) { @@ -1753,7 +1780,7 @@ void builtin_set(ScriptState *st) static void builtin_setarray(ScriptState *st) { - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; assert (AARGO2(2).type == ByteCode::VARIABLE); SIR reg = AARGO2(2).u.reg; ZString name = variable_names.outtern(reg.base()); @@ -1762,7 +1789,7 @@ void builtin_setarray(ScriptState *st) if (prefix != '$' && prefix != '@') { - PRINTF("builtin_setarray: illegal scope !\n"); + PRINTF("builtin_setarray: illegal scope !\n"_fmt); return; } if (prefix != '$') @@ -1784,7 +1811,7 @@ void builtin_setarray(ScriptState *st) static void builtin_cleararray(ScriptState *st) { - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; assert (AARGO2(2).type == ByteCode::VARIABLE); SIR reg = AARGO2(2).u.reg; ZString name = variable_names.outtern(reg.base()); @@ -1794,7 +1821,7 @@ void builtin_cleararray(ScriptState *st) if (prefix != '$' && prefix != '@') { - PRINTF("builtin_cleararray: illegal scope !\n"); + PRINTF("builtin_cleararray: illegal scope !\n"_fmt); return; } if (prefix != '$') @@ -1839,7 +1866,7 @@ void builtin_getarraysize(ScriptState *st) if (prefix != '$' && prefix != '@') { - PRINTF("builtin_copyarray: illegal scope !\n"); + PRINTF("builtin_copyarray: illegal scope !\n"_fmt); return; } @@ -1858,8 +1885,8 @@ void builtin_getelementofarray(ScriptState *st) int i = conv_num(st, &AARGO2(3)); if (i > 255 || i < 0) { - PRINTF("script: getelementofarray (operator[]): param2 illegal number %d\n", - i); + PRINTF("script: getelementofarray (operator[]): param2 illegal number %d\n"_fmt, + i); push_int(st->stack, ByteCode::INT, 0); } else @@ -1870,7 +1897,7 @@ void builtin_getelementofarray(ScriptState *st) } else { - PRINTF("script: getelementofarray (operator[]): param1 not name !\n"); + PRINTF("script: getelementofarray (operator[]): param1 not name !\n"_fmt); push_int(st->stack, ByteCode::INT, 0); } } @@ -1896,7 +1923,8 @@ void builtin_setlook(ScriptState *st) static void builtin_countitem(ScriptState *st) { - int nameid = 0, count = 0, i; + ItemNameId nameid; + int count = 0; dumb_ptr<map_session_data> sd; struct script_data *data; @@ -1909,22 +1937,24 @@ void builtin_countitem(ScriptState *st) { ZString name = ZString(conv_str(st, data)); struct item_data *item_data = itemdb_searchname(name); - if (item_data != NULL) + if (item_data != nullptr) nameid = item_data->nameid; } else - nameid = conv_num(st, data); + nameid = wrap<ItemNameId>(conv_num(st, data)); - if (nameid >= 500) //if no such ID then skip this iteration - for (i = 0; i < MAX_INVENTORY; i++) + if (nameid) + { + for (IOff0 i : IOff0::iter()) { if (sd->status.inventory[i].nameid == nameid) count += sd->status.inventory[i].amount; } + } else { if (battle_config.error_log) - PRINTF("wrong item ID : countitem (%i)\n", nameid); + PRINTF("wrong item ID : countitem (%i)\n"_fmt, nameid); } push_int(st->stack, ByteCode::INT, count); @@ -1937,7 +1967,8 @@ void builtin_countitem(ScriptState *st) static void builtin_checkweight(ScriptState *st) { - int nameid = 0, amount; + ItemNameId nameid; + int amount; dumb_ptr<map_session_data> sd; struct script_data *data; @@ -1953,10 +1984,10 @@ void builtin_checkweight(ScriptState *st) nameid = item_data->nameid; } else - nameid = conv_num(st, data); + nameid = wrap<ItemNameId>(conv_num(st, data)); amount = conv_num(st, &AARGO2(3)); - if (amount <= 0 || nameid < 500) + if (amount <= 0 || !nameid) { //if get wrong item ID or amount<=0, don't count weight of non existing items push_int(st->stack, ByteCode::INT, 0); @@ -1981,7 +2012,8 @@ void builtin_checkweight(ScriptState *st) static void builtin_getitem(ScriptState *st) { - int nameid, amount; + ItemNameId nameid; + int amount; dumb_ptr<map_session_data> sd; struct script_data *data; @@ -1993,12 +2025,11 @@ void builtin_getitem(ScriptState *st) { ZString name = ZString(conv_str(st, data)); struct item_data *item_data = itemdb_searchname(name); - nameid = 727; //Default to iten - if (item_data != NULL) + if (item_data != nullptr) nameid = item_data->nameid; } else - nameid = conv_num(st, data); + nameid = wrap<ItemNameId>(conv_num(st, data)); if ((amount = conv_num(st, &AARGO2(3))) <= 0) @@ -2006,21 +2037,21 @@ void builtin_getitem(ScriptState *st) return; //return if amount <=0, skip the useles iteration } - if (nameid > 0) + if (nameid) { - struct item item_tmp {}; + Item item_tmp {}; item_tmp.nameid = nameid; if (HARGO2(5)) //アイテムを指定したIDに渡す - sd = map_id2sd(conv_num(st, &AARGO2(5))); - if (sd == NULL) //アイテムを渡す相手がいなかったらお帰り + sd = map_id2sd(wrap<BlockId>(conv_num(st, &AARGO2(5)))); + if (sd == nullptr) //アイテムを渡す相手がいなかったらお帰り return; PickupFail flag; if ((flag = pc_additem(sd, &item_tmp, amount)) != PickupFail::OKAY) { - clif_additem(sd, 0, 0, flag); + clif_additem(sd, IOff0::from(0), 0, flag); map_addflooritem(&item_tmp, amount, sd->bl_m, sd->bl_x, sd->bl_y, - NULL, NULL, NULL); + nullptr, nullptr, nullptr); } } @@ -2033,7 +2064,8 @@ void builtin_getitem(ScriptState *st) static void builtin_makeitem(ScriptState *st) { - int nameid, amount; + ItemNameId nameid; + int amount; int x, y; dumb_ptr<map_session_data> sd; struct script_data *data; @@ -2046,12 +2078,11 @@ void builtin_makeitem(ScriptState *st) { ZString name = ZString(conv_str(st, data)); struct item_data *item_data = itemdb_searchname(name); - nameid = 512; //Apple Item ID if (item_data) nameid = item_data->nameid; } else - nameid = conv_num(st, data); + nameid = wrap<ItemNameId>(conv_num(st, data)); amount = conv_num(st, &AARGO2(3)); MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(4)))); @@ -2064,12 +2095,12 @@ void builtin_makeitem(ScriptState *st) else m = map_mapname2mapid(mapname); - if (nameid > 0) + if (nameid) { - struct item item_tmp {}; + Item item_tmp {}; item_tmp.nameid = nameid; - map_addflooritem(&item_tmp, amount, m, x, y, NULL, NULL, NULL); + map_addflooritem(&item_tmp, amount, m, x, y, nullptr, nullptr, nullptr); } } @@ -2080,7 +2111,8 @@ void builtin_makeitem(ScriptState *st) static void builtin_delitem(ScriptState *st) { - int nameid = 0, amount, i; + ItemNameId nameid; + int amount; dumb_ptr<map_session_data> sd; struct script_data *data; @@ -2092,31 +2124,21 @@ void builtin_delitem(ScriptState *st) { ZString name = ZString(conv_str(st, data)); struct item_data *item_data = itemdb_searchname(name); - //nameid=512; if (item_data) nameid = item_data->nameid; } else - nameid = conv_num(st, data); + nameid = wrap<ItemNameId>(conv_num(st, data)); amount = conv_num(st, &AARGO2(3)); - if (nameid < 500 || amount <= 0) + if (!nameid || amount <= 0) { //by Lupus. Don't run FOR if u got wrong item ID or amount<=0 - //PRINTF("wrong item ID or amount<=0 : delitem %i,\n",nameid,amount); return; } - for (i = 0; i < MAX_INVENTORY; i++) - { - if (sd->status.inventory[i].nameid <= 0 - || sd->inventory_data[i] == NULL - || sd->inventory_data[i]->type != ItemType::_7 - || sd->status.inventory[i].amount <= 0) - continue; - } - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { if (sd->status.inventory[i].nameid == nameid) { @@ -2153,7 +2175,7 @@ void builtin_readparam(ScriptState *st) else sd = script_rid2sd(st); - if (sd == NULL) + if (sd == nullptr) { push_int(st->stack, ByteCode::INT, -1); return; @@ -2178,19 +2200,19 @@ void builtin_getcharid(ScriptState *st) sd = map_nick2sd(stringish<CharName>(ZString(conv_str(st, &AARGO2(3))))); else sd = script_rid2sd(st); - if (sd == NULL) + if (sd == nullptr) { push_int(st->stack, ByteCode::INT, -1); return; } if (num == 0) - push_int(st->stack, ByteCode::INT, sd->status_key.char_id); + push_int(st->stack, ByteCode::INT, unwrap<CharId>(sd->status_key.char_id)); if (num == 1) - push_int(st->stack, ByteCode::INT, sd->status.party_id); + push_int(st->stack, ByteCode::INT, unwrap<PartyId>(sd->status.party_id)); if (num == 2) push_int(st->stack, ByteCode::INT, 0/*guild_id*/); if (num == 3) - push_int(st->stack, ByteCode::INT, sd->status_key.account_id); + push_int(st->stack, ByteCode::INT, unwrap<AccountId>(sd->status_key.account_id)); } /*========================================== @@ -2198,9 +2220,9 @@ void builtin_getcharid(ScriptState *st) *------------------------------------------ */ static -dumb_string builtin_getpartyname_sub(int party_id) +dumb_string builtin_getpartyname_sub(PartyId party_id) { - struct party *p = party_search(party_id); + PartyPair p = party_search(party_id); if (p) return dumb_string::copys(p->name); @@ -2231,12 +2253,12 @@ void builtin_strcharinfo(ScriptState *st) if (buf) push_str(st->stack, ByteCode::STR, buf); else - push_str(st->stack, ByteCode::CONSTSTR, dumb_string::fake("")); + push_str(st->stack, ByteCode::CONSTSTR, dumb_string::fake(""_s)); } if (num == 2) { // was: guild name - push_str(st->stack, ByteCode::CONSTSTR, dumb_string::fake("")); + push_str(st->stack, ByteCode::CONSTSTR, dumb_string::fake(""_s)); } } @@ -2266,23 +2288,23 @@ Array<EPOS, 11> equip //= static void builtin_getequipid(ScriptState *st) { - int i, num; + int num; dumb_ptr<map_session_data> sd; struct item_data *item; sd = script_rid2sd(st); - if (sd == NULL) + if (sd == nullptr) { - PRINTF("getequipid: sd == NULL\n"); + PRINTF("getequipid: sd == nullptr\n"_fmt); return; } num = conv_num(st, &AARGO2(2)); - i = pc_checkequip(sd, equip[num - 1]); - if (i >= 0) + IOff0 i = pc_checkequip(sd, equip[num - 1]); + if (i.ok()) { item = sd->inventory_data[i]; if (item) - push_int(st->stack, ByteCode::INT, item->nameid); + push_int(st->stack, ByteCode::INT, unwrap<ItemNameId>(item->nameid)); else push_int(st->stack, ByteCode::INT, 0); } @@ -2299,7 +2321,7 @@ void builtin_getequipid(ScriptState *st) static void builtin_getequipname(ScriptState *st) { - int i, num; + int num; dumb_ptr<map_session_data> sd; struct item_data *item; @@ -2307,18 +2329,18 @@ void builtin_getequipname(ScriptState *st) sd = script_rid2sd(st); num = conv_num(st, &AARGO2(2)); - i = pc_checkequip(sd, equip[num - 1]); - if (i >= 0) + IOff0 i = pc_checkequip(sd, equip[num - 1]); + if (i.ok()) { item = sd->inventory_data[i]; if (item) - buf = STRPRINTF("%s-[%s]", pos_str[num - 1], item->jname); + buf = STRPRINTF("%s-[%s]"_fmt, pos_str[num - 1], item->jname); else - buf = STRPRINTF("%s-[%s]", pos_str[num - 1], pos_str[10]); + buf = STRPRINTF("%s-[%s]"_fmt, pos_str[num - 1], pos_str[10]); } else { - buf = STRPRINTF("%s-[%s]", pos_str[num - 1], pos_str[10]); + buf = STRPRINTF("%s-[%s]"_fmt, pos_str[num - 1], pos_str[10]); } push_str(st->stack, ByteCode::STR, dumb_string::copys(buf)); @@ -2423,7 +2445,7 @@ void builtin_getskilllv(ScriptState *st) static void builtin_getgmlevel(ScriptState *st) { - push_int(st->stack, ByteCode::INT, pc_isGM(script_rid2sd(st))); + push_int(st->stack, ByteCode::INT, pc_isGM(script_rid2sd(st)).get_all_bits()); } /*========================================== @@ -2448,7 +2470,7 @@ void builtin_getopt2(ScriptState *st) sd = script_rid2sd(st); - push_int(st->stack, ByteCode::INT, uint16_t(sd->opt2)); + push_int(st->stack, ByteCode::INT, static_cast<uint16_t>(sd->opt2)); } @@ -2613,14 +2635,15 @@ void builtin_getexp(ScriptState *st) static void builtin_monster(ScriptState *st) { - int mob_class, amount, x, y; + Species mob_class; + int amount, x, y; NpcEvent event; MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); x = conv_num(st, &AARGO2(3)); y = conv_num(st, &AARGO2(4)); MobName str = stringish<MobName>(ZString(conv_str(st, &AARGO2(5)))); - mob_class = conv_num(st, &AARGO2(6)); + mob_class = wrap<Species>(conv_num(st, &AARGO2(6))); amount = conv_num(st, &AARGO2(7)); if (HARGO2(8)) extract(ZString(conv_str(st, &AARGO2(8))), &event); @@ -2636,7 +2659,8 @@ void builtin_monster(ScriptState *st) static void builtin_areamonster(ScriptState *st) { - int mob_class, amount, x0, y0, x1, y1; + Species mob_class; + int amount, x0, y0, x1, y1; NpcEvent event; MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); @@ -2645,7 +2669,7 @@ void builtin_areamonster(ScriptState *st) x1 = conv_num(st, &AARGO2(5)); y1 = conv_num(st, &AARGO2(6)); MobName str = stringish<MobName>(ZString(conv_str(st, &AARGO2(7)))); - mob_class = conv_num(st, &AARGO2(8)); + mob_class = wrap<Species>(conv_num(st, &AARGO2(8))); amount = conv_num(st, &AARGO2(9)); if (HARGO2(10)) extract(ZString(conv_str(st, &AARGO2(10))), &event); @@ -2683,7 +2707,7 @@ void builtin_killmonster(ScriptState *st) MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); ZString event_ = ZString(conv_str(st, &AARGO2(3))); NpcEvent event; - if (event_ != "All") + if (event_ != "All"_s) extract(event_, &event); map_local *m = map_mapname2mapid(mapname); @@ -2997,7 +3021,7 @@ void builtin_getareausers(ScriptState *st) *------------------------------------------ */ static -void builtin_getareadropitem_sub(dumb_ptr<block_list> bl, int item, int *amount) +void builtin_getareadropitem_sub(dumb_ptr<block_list> bl, ItemNameId item, int *amount) { dumb_ptr<flooritem_data> drop = bl->is_item(); @@ -3007,14 +3031,14 @@ void builtin_getareadropitem_sub(dumb_ptr<block_list> bl, int item, int *amount) } static -void builtin_getareadropitem_sub_anddelete(dumb_ptr<block_list> bl, int item, int *amount) +void builtin_getareadropitem_sub_anddelete(dumb_ptr<block_list> bl, ItemNameId item, int *amount) { dumb_ptr<flooritem_data> drop = bl->is_item(); if (drop->item_data.nameid == item) { (*amount) += drop->item_data.amount; - clif_clearflooritem(drop, 0); + clif_clearflooritem(drop, nullptr); map_delobject(drop->bl_id, drop->bl_type); } } @@ -3022,7 +3046,8 @@ void builtin_getareadropitem_sub_anddelete(dumb_ptr<block_list> bl, int item, in static void builtin_getareadropitem(ScriptState *st) { - int x0, y0, x1, y1, item, amount = 0, delitems = 0; + ItemNameId item; + int x0, y0, x1, y1, amount = 0, delitems = 0; struct script_data *data; MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); @@ -3037,12 +3062,11 @@ void builtin_getareadropitem(ScriptState *st) { ZString name = ZString(conv_str(st, data)); struct item_data *item_data = itemdb_searchname(name); - item = 512; if (item_data) item = item_data->nameid; } else - item = conv_num(st, data); + item = wrap<ItemNameId>(conv_num(st, data)); if (HARGO2(8)) delitems = conv_num(st, &AARGO2(8)); @@ -3102,7 +3126,7 @@ void builtin_sc_start(ScriptState *st) int val1; StatusChange type = static_cast<StatusChange>(conv_num(st, &AARGO2(2))); interval_t tick = static_cast<interval_t>(conv_num(st, &AARGO2(3))); - if (tick < std::chrono::seconds(1)) + if (tick < 1_s) // work around old behaviour of: // speed potion // atk potion @@ -3113,7 +3137,7 @@ void builtin_sc_start(ScriptState *st) tick *= 1000; val1 = conv_num(st, &AARGO2(4)); if (HARGO2(5)) //指定したキャラを状態異常にする - bl = map_id2bl(conv_num(st, &AARGO2(5))); + bl = map_id2bl(wrap<BlockId>(conv_num(st, &AARGO2(5)))); else bl = map_id2bl(st->rid); skill_status_change_start(bl, type, val1, tick); @@ -3151,7 +3175,7 @@ static void builtin_debugmes(ScriptState *st) { dumb_string mes = conv_str(st, &AARGO2(2)); - PRINTF("script debug : %d %d : %s\n", + PRINTF("script debug : %d %d : %s\n"_fmt, st->rid, st->oid, mes); } @@ -3174,10 +3198,10 @@ void builtin_resetstatus(ScriptState *st) static void builtin_changesex(ScriptState *st) { - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; sd = script_rid2sd(st); - chrif_char_ask_name(-1, sd->status_key.name, 5, HumanTimeDiff()); // type: 5 - changesex + chrif_char_ask_name(AccountId(), sd->status_key.name, 5, HumanTimeDiff()); // type: 5 - changesex chrif_save(sd); } @@ -3188,8 +3212,8 @@ void builtin_changesex(ScriptState *st) static void builtin_attachrid(ScriptState *st) { - st->rid = conv_num(st, &AARGO2(2)); - push_int(st->stack, ByteCode::INT, (map_id2sd(st->rid) != NULL)); + st->rid = wrap<BlockId>(conv_num(st, &AARGO2(2))); + push_int(st->stack, ByteCode::INT, (map_id2sd(st->rid) != nullptr)); } /*========================================== @@ -3199,7 +3223,7 @@ void builtin_attachrid(ScriptState *st) static void builtin_detachrid(ScriptState *st) { - st->rid = 0; + st->rid = BlockId(); } /*========================================== @@ -3210,8 +3234,7 @@ static void builtin_isloggedin(ScriptState *st) { push_int(st->stack, ByteCode::INT, - map_id2sd(conv_num(st, - &AARGO2(2))) != NULL); + map_id2sd(wrap<BlockId>(conv_num(st, &AARGO2(2)))) != nullptr); } static @@ -3279,7 +3302,7 @@ void builtin_pvpon(ScriptState *st) { if (m == pl_sd->bl_m && !pl_sd->pvp_timer) { - pl_sd->pvp_timer = Timer(gettick() + std::chrono::milliseconds(200), + pl_sd->pvp_timer = Timer(gettick() + 200_ms, std::bind(pc_calc_pvprank_timer, ph::_1, ph::_2, pl_sd->bl_id)); pl_sd->pvp_rank = 0; @@ -3411,7 +3434,7 @@ void builtin_marriage(ScriptState *st) dumb_ptr<map_session_data> sd = script_rid2sd(st); dumb_ptr<map_session_data> p_sd = map_nick2sd(partner); - if (sd == NULL || p_sd == NULL || pc_marriage(sd, p_sd) < 0) + if (sd == nullptr || p_sd == nullptr || pc_marriage(sd, p_sd) < 0) { push_int(st->stack, ByteCode::INT, 0); return; @@ -3428,7 +3451,7 @@ void builtin_divorce(ScriptState *st) sd->npc_flags.divorce = 1; - if (sd == NULL || pc_divorce(sd) < 0) + if (sd == nullptr || pc_divorce(sd) < 0) { push_int(st->stack, ByteCode::INT, 0); return; @@ -3456,7 +3479,7 @@ void builtin_getitemname(ScriptState *st) } else { - int item_id = conv_num(st, data); + ItemNameId item_id = wrap<ItemNameId>(conv_num(st, data)); i_data = itemdb_search(item_id); } @@ -3464,7 +3487,7 @@ void builtin_getitemname(ScriptState *st) if (i_data) item_name = dumb_string::copys(i_data->jname); else - item_name = dumb_string::copys("Unknown Item"); + item_name = dumb_string::copys("Unknown Item"_s); push_str(st->stack, ByteCode::STR, item_name); } @@ -3474,9 +3497,9 @@ void builtin_getspellinvocation(ScriptState *st) { dumb_string name = conv_str(st, &AARGO2(2)); - AString invocation = magic_find_invocation(name.str()); + AString invocation = magic::magic_find_invocation(name.str()); if (!invocation) - invocation = "..."; + invocation = "..."_s; push_str(st->stack, ByteCode::STR, dumb_string::copys(invocation)); } @@ -3486,7 +3509,7 @@ void builtin_getpartnerid2(ScriptState *st) { dumb_ptr<map_session_data> sd = script_rid2sd(st); - push_int(st->stack, ByteCode::INT, sd->status.partner_id); + push_int(st->stack, ByteCode::INT, unwrap<CharId>(sd->status.partner_id)); } /*========================================== @@ -3497,24 +3520,24 @@ static void builtin_getinventorylist(ScriptState *st) { dumb_ptr<map_session_data> sd = script_rid2sd(st); - int i, j = 0; + int j = 0; if (!sd) return; - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { - if (sd->status.inventory[i].nameid > 0 + if (sd->status.inventory[i].nameid && sd->status.inventory[i].amount > 0) { - pc_setreg(sd, SIR::from(variable_names.intern("@inventorylist_id"), j), - sd->status.inventory[i].nameid); - pc_setreg(sd, SIR::from(variable_names.intern("@inventorylist_amount"), j), + pc_setreg(sd, SIR::from(variable_names.intern("@inventorylist_id"_s), j), + unwrap<ItemNameId>(sd->status.inventory[i].nameid)); + pc_setreg(sd, SIR::from(variable_names.intern("@inventorylist_amount"_s), j), sd->status.inventory[i].amount); - pc_setreg(sd, SIR::from(variable_names.intern("@inventorylist_equip"), j), + pc_setreg(sd, SIR::from(variable_names.intern("@inventorylist_equip"_s), j), static_cast<uint16_t>(sd->status.inventory[i].equip)); j++; } } - pc_setreg(sd, SIR::from(variable_names.intern("@inventorylist_count")), j); + pc_setreg(sd, SIR::from(variable_names.intern("@inventorylist_count"_s)), j); } static @@ -3534,18 +3557,18 @@ void builtin_getactivatedpoolskilllist(ScriptState *st) if (sd->status.skill[skill_id].lv) { - pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_id"), count), + pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_id"_s), count), static_cast<uint16_t>(skill_id)); - pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_lv"), count), + pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_lv"_s), count), sd->status.skill[skill_id].lv); - pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_flag"), count), + pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_flag"_s), count), static_cast<uint16_t>(sd->status.skill[skill_id].flags)); - pc_setregstr(sd, SIR::from(variable_names.intern("@skilllist_name$"), count), + pc_setregstr(sd, SIR::from(variable_names.intern("@skilllist_name$"_s), count), skill_name(skill_id)); ++count; } } - pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_count")), count); + pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_count"_s)), count); } @@ -3565,18 +3588,18 @@ void builtin_getunactivatedpoolskilllist(ScriptState *st) if (sd->status.skill[skill_id].lv && !bool(sd->status.skill[skill_id].flags & SkillFlags::POOL_ACTIVATED)) { - pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_id"), count), + pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_id"_s), count), static_cast<uint16_t>(skill_id)); - pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_lv"), count), + pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_lv"_s), count), sd->status.skill[skill_id].lv); - pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_flag"), count), + pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_flag"_s), count), static_cast<uint16_t>(sd->status.skill[skill_id].flags)); - pc_setregstr(sd, SIR::from(variable_names.intern("@skilllist_name$"), count), + pc_setregstr(sd, SIR::from(variable_names.intern("@skilllist_name$"_s), count), skill_name(skill_id)); ++count; } } - pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_count")), count); + pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_count"_s)), count); } static @@ -3616,9 +3639,9 @@ static void builtin_misceffect(ScriptState *st) { int type; - int id = 0; + BlockId id; CharName name; - dumb_ptr<block_list> bl = NULL; + dumb_ptr<block_list> bl = nullptr; type = conv_num(st, &AARGO2(2)); @@ -3631,7 +3654,7 @@ void builtin_misceffect(ScriptState *st) if (sdata->type == ByteCode::STR || sdata->type == ByteCode::CONSTSTR) name = stringish<CharName>(ZString(conv_str(st, sdata))); else - id = conv_num(st, sdata); + id = wrap<BlockId>(conv_num(st, sdata)); } if (name.to__actual()) @@ -3665,7 +3688,7 @@ void builtin_specialeffect(ScriptState *st) { dumb_ptr<block_list> bl = map_id2bl(st->oid); - if (bl == NULL) + if (bl == nullptr) return; clif_specialeffect(bl, @@ -3680,7 +3703,7 @@ void builtin_specialeffect2(ScriptState *st) { dumb_ptr<map_session_data> sd = script_rid2sd(st); - if (sd == NULL) + if (sd == nullptr) return; clif_specialeffect(sd, @@ -3700,13 +3723,13 @@ void builtin_nude(ScriptState *st) { dumb_ptr<map_session_data> sd = script_rid2sd(st); - if (sd == NULL) + if (sd == nullptr) return; for (EQUIP i : EQUIPs) { - int idx = sd->equip_index_maybe[i]; - if (idx >= 0) + IOff0 idx = sd->equip_index_maybe[i]; + if (idx.ok()) pc_unequipitem(sd, idx, CalcStatus::LATER); } pc_calcstatus(sd, 0); @@ -3722,15 +3745,15 @@ static void builtin_unequipbyid(ScriptState *st) { dumb_ptr<map_session_data> sd = script_rid2sd(st); - if (sd == NULL) + if (sd == nullptr) return; EQUIP slot_id = EQUIP(conv_num(st, &AARGO2(2))); if (slot_id >= EQUIP() && slot_id < EQUIP::COUNT) { - int idx = sd->equip_index_maybe[slot_id]; - if (idx >= 0) + IOff0 idx = sd->equip_index_maybe[slot_id]; + if (idx.ok()) pc_unequipitem(sd, idx, CalcStatus::LATER); } @@ -3753,7 +3776,7 @@ void builtin_gmcommand(ScriptState *st) sd = script_rid2sd(st); dumb_string cmd = conv_str(st, &AARGO2(2)); - is_atcommand(sd->sess, sd, cmd, 99); + is_atcommand(sd->sess, sd, cmd, GmLevel::from(-1U)); } @@ -3766,7 +3789,7 @@ static void builtin_npcwarp(ScriptState *st) { int x, y; - dumb_ptr<npc_data> nd = NULL; + dumb_ptr<npc_data> nd = nullptr; x = conv_num(st, &AARGO2(2)); y = conv_num(st, &AARGO2(3)); @@ -3775,7 +3798,7 @@ void builtin_npcwarp(ScriptState *st) if (!nd) { - PRINTF("builtin_npcwarp: no such npc: %s\n", npc); + PRINTF("builtin_npcwarp: no such npc: %s\n"_fmt, npc); return; } @@ -3808,7 +3831,7 @@ void builtin_message(ScriptState *st) ZString msg = ZString(conv_str(st, &AARGO2(3))); dumb_ptr<map_session_data> pl_sd = map_nick2sd(player); - if (pl_sd == NULL) + if (pl_sd == nullptr) return; clif_displaymessage(pl_sd->sess, msg); @@ -3828,11 +3851,7 @@ void builtin_npctalk(ScriptState *st) if (nd) { - MString message; - message += nd->name; - message += " : "; - message += ZString(str); - clif_message(nd, AString(message)); + clif_message(nd, XString(str)); } } @@ -3856,13 +3875,13 @@ void builtin_getlook(ScriptState *st) val = static_cast<uint16_t>(sd->status.weapon); break; case LOOK::HEAD_BOTTOM: //3 - val = sd->status.head_bottom; + val = unwrap<ItemNameId>(sd->status.head_bottom); break; case LOOK::HEAD_TOP: //4 - val = sd->status.head_top; + val = unwrap<ItemNameId>(sd->status.head_top); break; case LOOK::HEAD_MID: //5 - val = sd->status.head_mid; + val = unwrap<ItemNameId>(sd->status.head_mid); break; case LOOK::HAIR_COLOR: //6 val = sd->status.hair_color; @@ -3871,7 +3890,7 @@ void builtin_getlook(ScriptState *st) val = sd->status.clothes_color; break; case LOOK::SHIELD: //8 - val = sd->status.shield; + val = unwrap<ItemNameId>(sd->status.shield); break; case LOOK::SHOES: //9 break; @@ -3988,7 +4007,7 @@ void builtin_shop(ScriptState *st) nd = npc_name2id(name); if (!nd) { - PRINTF("builtin_shop: no such npc: %s\n", name); + PRINTF("builtin_shop: no such npc: %s\n"_fmt, name); return; } @@ -4017,11 +4036,11 @@ void builtin_fakenpcname(ScriptState *st) { NpcName name = stringish<NpcName>(ZString(conv_str(st, &AARGO2(2)))); NpcName newname = stringish<NpcName>(ZString(conv_str(st, &AARGO2(3)))); - int newsprite = conv_num(st, &AARGO2(4)); + Species newsprite = wrap<Species>(static_cast<uint16_t>(conv_num(st, &AARGO2(4)))); dumb_ptr<npc_data> nd = npc_name2id(name); if (!nd) { - PRINTF("builtin_fakenpcname: no such npc: %s\n", name); + PRINTF("builtin_fakenpcname: no such npc: %s\n"_fmt, name); return; } nd->name = newname; @@ -4205,7 +4224,7 @@ void op_2str(ScriptState *st, ByteCode op, dumb_string s1_, dumb_string s2_) a = s1 <= s2; break; default: - PRINTF("illegal string operater\n"); + PRINTF("illegal string operater\n"_fmt); break; } @@ -4308,7 +4327,7 @@ void op_2(ScriptState *st, ByteCode op) else { // si,is => error - PRINTF("script: op_2: int&str, str&int not allow.\n"); + PRINTF("script: op_2: int&str, str&int not allow.\n"_fmt); push_int(st->stack, ByteCode::INT, 0); } } @@ -4351,7 +4370,7 @@ void run_func(ScriptState *st) if (start_sp == 0) { if (battle_config.error_log) - PRINTF("function not found\n"); + PRINTF("function not found\n"_fmt); st->state = ScriptEndState::END; return; } @@ -4364,52 +4383,52 @@ void run_func(ScriptState *st) size_t func = st->stack->stack_datav[st->start].u.numi; if (st->stack->stack_datav[st->start].type != ByteCode::FUNC_REF) { - PRINTF("run_func: not function and command! \n"); + PRINTF("run_func: not function and command! \n"_fmt); st->state = ScriptEndState::END; return; } if (DEBUG_RUN && battle_config.etc_log) { - PRINTF("run_func : %s\n", + PRINTF("run_func : %s\n"_fmt, builtin_functions[func].name); - PRINTF("stack dump :"); + PRINTF("stack dump :"_fmt); for (script_data& d : st->stack->stack_datav) { switch (d.type) { case ByteCode::INT: - PRINTF(" int(%d)", d.u.numi); + PRINTF(" int(%d)"_fmt, d.u.numi); break; case ByteCode::RETINFO: - PRINTF(" retinfo(%p)", static_cast<const void *>(d.u.script)); + PRINTF(" retinfo(%p)"_fmt, static_cast<const void *>(d.u.script)); break; case ByteCode::PARAM_: - PRINTF(" param(%d)", d.u.reg.sp()); + PRINTF(" param(%d)"_fmt, d.u.reg.sp()); break; case ByteCode::VARIABLE: - PRINTF(" name(%s)[%d]", variable_names.outtern(d.u.reg.base()), d.u.reg.index()); + PRINTF(" name(%s)[%d]"_fmt, variable_names.outtern(d.u.reg.base()), d.u.reg.index()); break; case ByteCode::ARG: - PRINTF(" arg"); + PRINTF(" arg"_fmt); break; case ByteCode::POS: - PRINTF(" pos(%d)", d.u.numi); + PRINTF(" pos(%d)"_fmt, d.u.numi); break; case ByteCode::STR: - PRINTF(" str(%s)", d.u.str); + PRINTF(" str(%s)"_fmt, d.u.str); break; case ByteCode::CONSTSTR: - PRINTF(" cstr(%s)", d.u.str); + PRINTF(" cstr(%s)"_fmt, d.u.str); break; case ByteCode::FUNC_REF: - PRINTF(" func(%s)", builtin_functions[d.u.numi].name); + PRINTF(" func(%s)"_fmt, builtin_functions[d.u.numi].name); break; default: - PRINTF(" %d,%d", d.type, d.u.numi); + PRINTF(" %d,%d"_fmt, d.type, d.u.numi); } } - PRINTF("\n"); + PRINTF("\n"_fmt); } builtin_functions[func].func(st); @@ -4424,7 +4443,7 @@ void run_func(ScriptState *st) if (st->defsp < 4 || st->stack->stack_datav[st->defsp - 1].type != ByteCode::RETINFO) { - PRINTF("script:run_func (return) return without callfunc or callsub!\n"); + PRINTF("script:run_func (return) return without callfunc or callsub!\n"_fmt); st->state = ScriptEndState::END; return; } @@ -4449,15 +4468,15 @@ void dump_script(const ScriptBuffer *script) ScriptPointer scriptp(script, 0); while (scriptp.pos < reinterpret_cast<const std::vector<ByteCode> *>(script)->size()) { - PRINTF("%6zu: ", scriptp.pos); + PRINTF("%6zu: "_fmt, scriptp.pos); switch (ByteCode c = get_com(&scriptp)) { case ByteCode::EOL: - PRINTF("EOL\n"); // extra newline between functions + PRINTF("EOL\n"_fmt); // extra newline between functions break; case ByteCode::INT: // synthesized! - PRINTF("INT %d", get_num(&scriptp)); + PRINTF("INT %d"_fmt, get_num(&scriptp)); break; case ByteCode::POS: @@ -4472,103 +4491,103 @@ void dump_script(const ScriptBuffer *script) switch(c) { case ByteCode::POS: - PRINTF("POS %d", arg); + PRINTF("POS %d"_fmt, arg); break; case ByteCode::VARIABLE: - PRINTF("VARIABLE %s", variable_names.outtern(arg)); + PRINTF("VARIABLE %s"_fmt, variable_names.outtern(arg)); break; case ByteCode::FUNC_REF: - PRINTF("FUNC_REF %s", builtin_functions[arg].name); + PRINTF("FUNC_REF %s"_fmt, builtin_functions[arg].name); break; case ByteCode::PARAM_: - PRINTF("PARAM SP::#%d (sorry)", arg); + PRINTF("PARAM SP::#%d (sorry)"_fmt, arg); break; } } break; case ByteCode::ARG: - PRINTF("ARG"); + PRINTF("ARG"_fmt); break; case ByteCode::STR: - PRINTF("STR \"%s\"", scriptp.pops()); + PRINTF("STR \"%s\""_fmt, scriptp.pops()); break; case ByteCode::FUNC_: - PRINTF("FUNC_"); + PRINTF("FUNC_"_fmt); break; case ByteCode::ADD: - PRINTF("ADD"); + PRINTF("ADD"_fmt); break; case ByteCode::SUB: - PRINTF("SUB"); + PRINTF("SUB"_fmt); break; case ByteCode::MUL: - PRINTF("MUL"); + PRINTF("MUL"_fmt); break; case ByteCode::DIV: - PRINTF("DIV"); + PRINTF("DIV"_fmt); break; case ByteCode::MOD: - PRINTF("MOD"); + PRINTF("MOD"_fmt); break; case ByteCode::EQ: - PRINTF("EQ"); + PRINTF("EQ"_fmt); break; case ByteCode::NE: - PRINTF("NE"); + PRINTF("NE"_fmt); break; case ByteCode::GT: - PRINTF("GT"); + PRINTF("GT"_fmt); break; case ByteCode::GE: - PRINTF("GE"); + PRINTF("GE"_fmt); break; case ByteCode::LT: - PRINTF("LT"); + PRINTF("LT"_fmt); break; case ByteCode::LE: - PRINTF("LE"); + PRINTF("LE"_fmt); break; case ByteCode::AND: - PRINTF("AND"); + PRINTF("AND"_fmt); break; case ByteCode::OR: - PRINTF("OR"); + PRINTF("OR"_fmt); break; case ByteCode::XOR: - PRINTF("XOR"); + PRINTF("XOR"_fmt); break; case ByteCode::LAND: - PRINTF("LAND"); + PRINTF("LAND"_fmt); break; case ByteCode::LOR: - PRINTF("LOR"); + PRINTF("LOR"_fmt); break; case ByteCode::R_SHIFT: - PRINTF("R_SHIFT"); + PRINTF("R_SHIFT"_fmt); break; case ByteCode::L_SHIFT: - PRINTF("L_SHIFT"); + PRINTF("L_SHIFT"_fmt); break; case ByteCode::NEG: - PRINTF("NEG"); + PRINTF("NEG"_fmt); break; case ByteCode::NOT: - PRINTF("NOT"); + PRINTF("NOT"_fmt); break; case ByteCode::LNOT: - PRINTF("LNOT"); + PRINTF("LNOT"_fmt); break; case ByteCode::NOP: - PRINTF("NOP"); + PRINTF("NOP"_fmt); break; default: - PRINTF("??? %d", c); + PRINTF("??? %d"_fmt, c); break; } - PRINTF("\n"); + PRINTF("\n"_fmt); } } @@ -4595,7 +4614,7 @@ void run_script_main(ScriptState *st, const ScriptBuffer *rootscript) if (stack->stack_datav.size() != st->defsp) { if (battle_config.error_log) - PRINTF("stack.sp (%zu) != default (%d)\n", + PRINTF("stack.sp (%zu) != default (%d)\n"_fmt, stack->stack_datav.size(), st->defsp); stack->stack_datav.resize(st->defsp); @@ -4650,7 +4669,7 @@ void run_script_main(ScriptState *st, const ScriptBuffer *rootscript) st->state = ScriptEndState::ZERO; if (gotocount > 0 && (--gotocount) <= 0) { - PRINTF("run_script: infinity loop !\n"); + PRINTF("run_script: infinity loop !\n"_fmt); st->state = ScriptEndState::END; } } @@ -4692,14 +4711,14 @@ void run_script_main(ScriptState *st, const ScriptBuffer *rootscript) default: if (battle_config.error_log) - PRINTF("unknown command : %d @ %zu\n", + PRINTF("unknown command : %d @ %zu\n"_fmt, c, st->scriptp.pos); st->state = ScriptEndState::END; break; } if (cmdcount > 0 && (--cmdcount) <= 0) { - PRINTF("run_script: infinity loop !\n"); + PRINTF("run_script: infinity loop !\n"_fmt); st->state = ScriptEndState::END; } } @@ -4739,12 +4758,12 @@ void run_script_main(ScriptState *st, const ScriptBuffer *rootscript) * スクリプトの実行 *------------------------------------------ */ -int run_script(ScriptPointer sp, int rid, int oid) +int run_script(ScriptPointer sp, BlockId rid, BlockId oid) { return run_script_l(sp, rid, oid, nullptr); } -int run_script_l(ScriptPointer sp, int rid, int oid, +int run_script_l(ScriptPointer sp, BlockId rid, BlockId oid, Slice<argrec_t> args) { struct script_stack stack; @@ -4752,7 +4771,7 @@ int run_script_l(ScriptPointer sp, int rid, int oid, dumb_ptr<map_session_data> sd = map_id2sd(rid); const ScriptBuffer *rootscript = sp.code; int i; - if (sp.code == NULL || sp.pos >> 24) + if (sp.code == nullptr || sp.pos >> 24) return -1; if (sd && !sd->npc_stackbuf.empty() && sd->npc_scriptroot == rootscript) @@ -4846,7 +4865,7 @@ void script_load_mapreg(void) else { borken: - PRINTF("%s: %s broken data !\n", mapreg_txt, AString(buf1)); + PRINTF("%s: %s broken data !\n"_fmt, mapreg_txt, AString(buf1)); continue; } } @@ -4865,9 +4884,9 @@ void script_save_mapreg_intsub(SIR key, int data, io::WriteFile& fp) if (name[1] != '@') { if (i == 0) - FPRINTF(fp, "%s\t%d\n", name, data); + FPRINTF(fp, "%s\t%d\n"_fmt, name, data); else - FPRINTF(fp, "%s,%d\t%d\n", name, i, data); + FPRINTF(fp, "%s,%d\t%d\n"_fmt, name, i, data); } } @@ -4879,9 +4898,9 @@ void script_save_mapreg_strsub(SIR key, ZString data, io::WriteFile& fp) if (name[1] != '@') { if (i == 0) - FPRINTF(fp, "%s\t%s\n", name, data); + FPRINTF(fp, "%s\t%s\n"_fmt, name, data); else - FPRINTF(fp, "%s,%d\t%s\n", name, i, data); + FPRINTF(fp, "%s,%d\t%s\n"_fmt, name, i, data); } } @@ -4932,129 +4951,128 @@ void do_init_script(void) ).detach(); } -#define BUILTIN(func, args) \ -{builtin_##func, {#func}, {args}} +#define BUILTIN(func, args, ret) \ +{builtin_##func, #func ## _s, args, ret} BuiltinFunction builtin_functions[] = { - BUILTIN(mes, "s"), - BUILTIN(next, ""), - BUILTIN(close, ""), - BUILTIN(close2, ""), - BUILTIN(menu, "sL*"), - BUILTIN(goto, "L"), - BUILTIN(callsub, "L"), - BUILTIN(callfunc, "F"), - BUILTIN(return, ""), - BUILTIN(input, "N"), - BUILTIN(warp, "Mxy"), - BUILTIN(isat, "Mxy"), - BUILTIN(areawarp, "MxyxyMxy"), - BUILTIN(setlook, "ii"), - BUILTIN(set, "Ne"), - BUILTIN(setarray, "Ne*"), - BUILTIN(cleararray, "Nei"), - BUILTIN(getarraysize, "N"), - BUILTIN(getelementofarray, "Ni"), - BUILTIN(if, "iF*"), - BUILTIN(getitem, "Ii**"), - BUILTIN(makeitem, "IiMxy"), - BUILTIN(delitem, "Ii"), - BUILTIN(heal, "ii"), - BUILTIN(itemheal, "ii"), - BUILTIN(percentheal, "ii"), - BUILTIN(rand, "i*"), - BUILTIN(pow, "ii"), - BUILTIN(countitem, "I"), - BUILTIN(checkweight, "Ii"), - BUILTIN(readparam, "i*"), - BUILTIN(getcharid, "i*"), - BUILTIN(strcharinfo, "i"), - BUILTIN(getequipid, "i"), - BUILTIN(getequipname, "i"), - BUILTIN(statusup2, "ii"), - BUILTIN(bonus, "ii"), - BUILTIN(bonus2, "iii"), - BUILTIN(skill, "ii*"), - BUILTIN(setskill, "ii"), - BUILTIN(getskilllv, "i"), - BUILTIN(getgmlevel, ""), - BUILTIN(end, ""), - BUILTIN(getopt2, ""), - BUILTIN(setopt2, "i"), - BUILTIN(savepoint, "Mxy"), - BUILTIN(gettimetick, "i"), - BUILTIN(gettime, "i"), - BUILTIN(openstorage, "*"), - BUILTIN(monster, "Mxysmi*"), - BUILTIN(areamonster, "Mxyxysmi*"), - BUILTIN(killmonster, "ME"), - BUILTIN(killmonsterall, "M"), - BUILTIN(donpcevent, "E"), - BUILTIN(addtimer, "tE"), - BUILTIN(initnpctimer, ""), - BUILTIN(stopnpctimer, ""), - BUILTIN(startnpctimer, "*"), - BUILTIN(setnpctimer, "i"), - BUILTIN(getnpctimer, "i"), - BUILTIN(announce, "si"), - BUILTIN(mapannounce, "Msi"), - BUILTIN(getusers, "i"), - BUILTIN(getmapusers, "M"), - BUILTIN(getareausers, "Mxyxy*"), - BUILTIN(getareadropitem, "Mxyxyi*"), - BUILTIN(enablenpc, "s"), - BUILTIN(disablenpc, "s"), - BUILTIN(sc_start, "iTi*"), - BUILTIN(sc_end, "i"), - BUILTIN(sc_check, "i"), - BUILTIN(debugmes, "s"), - BUILTIN(resetstatus, ""), - BUILTIN(changesex, ""), - BUILTIN(attachrid, "i"), - BUILTIN(detachrid, ""), - BUILTIN(isloggedin, "i"), - BUILTIN(setmapflag, "Mi"), - BUILTIN(removemapflag, "Mi"), - BUILTIN(getmapflag, "Mi"), - BUILTIN(pvpon, "M"), - BUILTIN(pvpoff, "M"), - BUILTIN(emotion, "i"), - BUILTIN(marriage, "P"), - BUILTIN(divorce, ""), - BUILTIN(getitemname, "I"), - BUILTIN(getspellinvocation, "s"), - BUILTIN(getpartnerid2, ""), - BUILTIN(getexp, "ii"), - BUILTIN(getinventorylist, ""), - BUILTIN(getactivatedpoolskilllist, ""), - BUILTIN(getunactivatedpoolskilllist, ""), - BUILTIN(poolskill, "i"), - BUILTIN(unpoolskill, "i"), - BUILTIN(misceffect, "i*"), - BUILTIN(specialeffect, "i"), - BUILTIN(specialeffect2, "i"), - BUILTIN(nude, ""), - BUILTIN(mapwarp, "MMxy"), - BUILTIN(cmdothernpc, "ss"), - BUILTIN(gmcommand, "s"), - BUILTIN(npcwarp, "xys"), - BUILTIN(message, "Ps"), - BUILTIN(npctalk, "s"), - BUILTIN(mobcount, "ME"), - BUILTIN(getlook, "i"), - BUILTIN(getsavepoint, "i"), - BUILTIN(areatimer, "MxyxytE"), - BUILTIN(isin, "Mxyxy"), - BUILTIN(shop, "s"), - BUILTIN(isdead, ""), - BUILTIN(unequipbyid, "i"), - BUILTIN(fakenpcname, "ssi"), - BUILTIN(getx, ""), - BUILTIN(gety, ""), - BUILTIN(getmap, ""), - BUILTIN(mapexit, ""), - {nullptr, ZString(), ZString()}, + BUILTIN(mes, "s"_s, '\0'), + BUILTIN(goto, "L"_s, '\0'), + BUILTIN(callfunc, "F"_s, '\0'), + BUILTIN(callsub, "L"_s, '\0'), + BUILTIN(return, ""_s, '\0'), + BUILTIN(next, ""_s, '\0'), + BUILTIN(close, ""_s, '\0'), + BUILTIN(close2, ""_s, '\0'), + BUILTIN(menu, "sL**"_s, '\0'), + BUILTIN(rand, "i?"_s, 'i'), + BUILTIN(isat, "Mxy"_s, 'i'), + BUILTIN(warp, "Mxy"_s, '\0'), + BUILTIN(areawarp, "MxyxyMxy"_s, '\0'), + BUILTIN(heal, "ii"_s, '\0'), + BUILTIN(itemheal, "ii"_s, '\0'), + BUILTIN(percentheal, "ii"_s, '\0'), + BUILTIN(input, "N"_s, '\0'), + BUILTIN(if, "iF*"_s, '\0'), + BUILTIN(set, "Ne"_s, '\0'), + BUILTIN(setarray, "Ne*"_s, '\0'), + BUILTIN(cleararray, "Nei"_s, '\0'), + BUILTIN(getarraysize, "N"_s, 'i'), + BUILTIN(getelementofarray, "Ni"_s, '.'), + BUILTIN(setlook, "ii"_s, '\0'), + BUILTIN(countitem, "I"_s, 'i'), + BUILTIN(checkweight, "Ii"_s, 'i'), + BUILTIN(getitem, "Ii??"_s, '\0'), + BUILTIN(makeitem, "IiMxy"_s, '\0'), + BUILTIN(delitem, "Ii"_s, '\0'), + BUILTIN(readparam, "i?"_s, 'i'), + BUILTIN(getcharid, "i?"_s, 'i'), + BUILTIN(strcharinfo, "i"_s, 's'), + BUILTIN(getequipid, "i"_s, 'i'), + BUILTIN(getequipname, "i"_s, 's'), + BUILTIN(statusup2, "ii"_s, '\0'), + BUILTIN(bonus, "ii"_s, '\0'), + BUILTIN(bonus2, "iii"_s, '\0'), + BUILTIN(skill, "ii?"_s, '\0'), + BUILTIN(setskill, "ii"_s, '\0'), + BUILTIN(getskilllv, "i"_s, 'i'), + BUILTIN(getgmlevel, ""_s, 'i'), + BUILTIN(end, ""_s, '\0'), + BUILTIN(getopt2, ""_s, 'i'), + BUILTIN(setopt2, "i"_s, '\0'), + BUILTIN(savepoint, "Mxy"_s, '\0'), + BUILTIN(gettimetick, "i"_s, 'i'), + BUILTIN(gettime, "i"_s, 'i'), + BUILTIN(openstorage, ""_s, '\0'), + BUILTIN(getexp, "ii"_s, '\0'), + BUILTIN(monster, "Mxysmi?"_s, '\0'), + BUILTIN(areamonster, "Mxyxysmi?"_s, '\0'), + BUILTIN(killmonster, "ME"_s, '\0'), + BUILTIN(killmonsterall, "M"_s, '\0'), + BUILTIN(donpcevent, "E"_s, '\0'), + BUILTIN(addtimer, "tE"_s, '\0'), + BUILTIN(initnpctimer, ""_s, '\0'), + BUILTIN(startnpctimer, "?"_s, '\0'), + BUILTIN(stopnpctimer, ""_s, '\0'), + BUILTIN(getnpctimer, "i"_s, 'i'), + BUILTIN(setnpctimer, "i"_s, '\0'), + BUILTIN(announce, "si"_s, '\0'), + BUILTIN(mapannounce, "Msi"_s, '\0'), + BUILTIN(getusers, "i"_s, 'i'), + BUILTIN(getmapusers, "M"_s, 'i'), + BUILTIN(getareausers, "Mxyxy?"_s, 'i'), + BUILTIN(getareadropitem, "Mxyxyi?"_s, 'i'), + BUILTIN(enablenpc, "s"_s, '\0'), + BUILTIN(disablenpc, "s"_s, '\0'), + BUILTIN(sc_start, "iTi?"_s, '\0'), + BUILTIN(sc_end, "i"_s, '\0'), + BUILTIN(sc_check, "i"_s, 'i'), + BUILTIN(debugmes, "s"_s, '\0'), + BUILTIN(resetstatus, ""_s, '\0'), + BUILTIN(changesex, ""_s, '\0'), + BUILTIN(attachrid, "i"_s, 'i'), + BUILTIN(detachrid, ""_s, '\0'), + BUILTIN(isloggedin, "i"_s, 'i'), + BUILTIN(setmapflag, "Mi"_s, '\0'), + BUILTIN(removemapflag, "Mi"_s, '\0'), + BUILTIN(getmapflag, "Mi"_s, 'i'), + BUILTIN(pvpon, "M"_s, '\0'), + BUILTIN(pvpoff, "M"_s, '\0'), + BUILTIN(emotion, "i"_s, '\0'), + BUILTIN(mapwarp, "MMxy"_s, '\0'), + BUILTIN(cmdothernpc, "ss"_s, '\0'), + BUILTIN(mobcount, "ME"_s, 'i'), + BUILTIN(marriage, "P"_s, 'i'), + BUILTIN(divorce, ""_s, 'i'), + BUILTIN(getitemname, "I"_s, 's'), + BUILTIN(getspellinvocation, "s"_s, 's'), + BUILTIN(getpartnerid2, ""_s, 'i'), + BUILTIN(getinventorylist, ""_s, '\0'), + BUILTIN(getactivatedpoolskilllist, ""_s, '\0'), + BUILTIN(getunactivatedpoolskilllist, ""_s, '\0'), + BUILTIN(poolskill, "i"_s, '\0'), + BUILTIN(unpoolskill, "i"_s, '\0'), + BUILTIN(misceffect, "i?"_s, '\0'), + BUILTIN(specialeffect, "i"_s, '\0'), + BUILTIN(specialeffect2, "i"_s, '\0'), + BUILTIN(nude, ""_s, '\0'), + BUILTIN(unequipbyid, "i"_s, '\0'), + BUILTIN(gmcommand, "s"_s, '\0'), + BUILTIN(npcwarp, "xys"_s, '\0'), + BUILTIN(message, "Ps"_s, '\0'), + BUILTIN(npctalk, "s"_s, '\0'), + BUILTIN(getlook, "i"_s, 'i'), + BUILTIN(getsavepoint, "i"_s, '.'), + BUILTIN(areatimer, "MxyxytE"_s, '\0'), + BUILTIN(isin, "Mxyxy"_s, 'i'), + BUILTIN(shop, "s"_s, '\0'), + BUILTIN(isdead, ""_s, 'i'), + BUILTIN(fakenpcname, "ssi"_s, '\0'), + BUILTIN(getx, ""_s, 'i'), + BUILTIN(gety, ""_s, 'i'), + BUILTIN(getmap, ""_s, 's'), + BUILTIN(mapexit, ""_s, '\0'), + {nullptr, ""_s, ""_s, '\0'}, }; void set_script_var_i(dumb_ptr<map_session_data> sd, VarName var, int e, int val) @@ -5079,7 +5097,7 @@ int get_script_var_i(dumb_ptr<map_session_data> sd, VarName var, int e) get_val(sd, &dat); if (dat.type == ByteCode::INT) return dat.u.numi; - PRINTF("Warning: you lied about the type and I'm too lazy to fix it!"); + PRINTF("Warning: you lied about the type and I'm too lazy to fix it!"_fmt); return 0; } ZString get_script_var_s(dumb_ptr<map_session_data> sd, VarName var, int e) @@ -5092,6 +5110,7 @@ ZString get_script_var_s(dumb_ptr<map_session_data> sd, VarName var, int e) get_val(sd, &dat); if (dat.type == ByteCode::CONSTSTR) return dat.u.str; - PRINTF("Warning: you lied about the type and I can't fix it!"); + PRINTF("Warning: you lied about the type and I can't fix it!"_fmt); return ZString(); } +} // namespace tmwa diff --git a/src/map/script.hpp b/src/map/script.hpp index 9ae893d..ee9a5a9 100644 --- a/src/map/script.hpp +++ b/src/map/script.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_SCRIPT_HPP -#define TMWA_MAP_SCRIPT_HPP +#pragma once // script.hpp - EAthena script frontend, engine, and library. // // Copyright © ????-2004 Athena Dev Teams @@ -21,26 +20,27 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include <cstdint> -# include <cstring> // for inlined get_str - TODO remove +#include <cstdint> -# include <vector> +#include <vector> -# include "../range/slice.hpp" +#include "../range/slice.hpp" -# include "../strings/rstring.hpp" -# include "../strings/astring.hpp" -# include "../strings/zstring.hpp" +#include "../strings/zstring.hpp" -# include "../generic/db.hpp" +#include "../generic/db.hpp" +#include "../generic/dumb_ptr.hpp" -# include "../mmo/dumb_ptr.hpp" -# include "../mmo/utils.hpp" +#include "../mmo/ids.hpp" -# include "map.t.hpp" +#include "clif.t.hpp" +#include "map.t.hpp" + +namespace tmwa +{ enum class ByteCode : uint8_t; struct str_data_t; @@ -155,7 +155,7 @@ public: struct script_stack *stack; int start, end; ScriptEndState state; - int rid, oid; + BlockId rid, oid; ScriptPointer scriptp, new_scriptp; int defsp, new_defsp; }; @@ -177,10 +177,9 @@ struct argrec_t argrec_t(ZString n, int i) : name(n), v(i) {} argrec_t(ZString n, ZString z) : name(n), v(z) {} }; -int run_script_l(ScriptPointer, int, int, Slice<argrec_t> args); -int run_script(ScriptPointer, int, int); +int run_script_l(ScriptPointer, BlockId, BlockId, Slice<argrec_t> args); +int run_script(ScriptPointer, BlockId, BlockId); -struct ScriptLabel; extern Map<ScriptLabel, int> scriptlabel_db; extern @@ -200,5 +199,4 @@ void set_script_var_s(dumb_ptr<map_session_data> sd, VarName var, int e, XString int get_script_var_i(dumb_ptr<map_session_data> sd, VarName var, int e); ZString get_script_var_s(dumb_ptr<map_session_data> sd, VarName var, int e); - -#endif // TMWA_MAP_SCRIPT_HPP +} // namespace tmwa diff --git a/src/map/script.py b/src/map/script.py index 068307a..dcde08d 100644 --- a/src/map/script.py +++ b/src/map/script.py @@ -3,7 +3,7 @@ class ByteCode: (workaround for gcc bug 58150) ''' __slots__ = ('_value') - name = 'ByteCode' + name = 'tmwa::ByteCode' enabled = True def __init__(self, value): @@ -34,7 +34,7 @@ class script_data(object): ''' print a script_data ''' __slots__ = ('_value') - name = 'script_data' + name = 'tmwa::script_data' enabled = True def __init__(self, value): diff --git a/src/map/skill-pools.cpp b/src/map/skill-pools.cpp index 6b46d79..89bf426 100644 --- a/src/map/skill-pools.cpp +++ b/src/map/skill-pools.cpp @@ -1,3 +1,4 @@ +#include "skill-pools.hpp" #include "skill.hpp" // skill-pools.cpp - Additional support for focusable skills. // @@ -20,12 +21,16 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include "../io/cxxstdio.hpp" +#include "../io/cxxstdio_enums.hpp" #include "battle.hpp" #include "pc.hpp" #include "../poison.hpp" + +namespace tmwa +{ Array<SkillID, MAX_POOL_SKILLS> skill_pool_skills; int skill_pool_skills_size = 0; @@ -34,7 +39,7 @@ void skill_pool_register(SkillID id) if (skill_pool_skills_size + 1 >= MAX_POOL_SKILLS) { FPRINTF(stderr, - "Too many pool skills! Increase MAX_POOL_SKILLS and recompile."); + "Too many pool skills! Increase MAX_POOL_SKILLS and recompile."_fmt); return; } @@ -61,7 +66,7 @@ int skill_pool(dumb_ptr<map_session_data> sd, SkillID *skills) int skill_pool_size(dumb_ptr<map_session_data> sd) { - return skill_pool(sd, NULL); + return skill_pool(sd, nullptr); } int skill_pool_max(dumb_ptr<map_session_data> sd) @@ -78,7 +83,7 @@ int skill_pool_activate(dumb_ptr<map_session_data> sd, SkillID skill_id) { sd->status.skill[skill_id].flags |= SkillFlags::POOL_ACTIVATED; pc_calcstatus(sd, 0); - MAP_LOG_PC(sd, "SKILL-ACTIVATE %d %d %d", + MAP_LOG_PC(sd, "SKILL-ACTIVATE %d %d %d"_fmt, skill_id, sd->status.skill[skill_id].lv, skill_power(sd, skill_id)); return 0; @@ -97,7 +102,7 @@ int skill_pool_deactivate(dumb_ptr<map_session_data> sd, SkillID skill_id) if (bool(sd->status.skill[skill_id].flags & SkillFlags::POOL_ACTIVATED)) { sd->status.skill[skill_id].flags &= ~SkillFlags::POOL_ACTIVATED; - MAP_LOG_PC(sd, "SKILL-DEACTIVATE %d", skill_id); + MAP_LOG_PC(sd, "SKILL-DEACTIVATE %d"_fmt, skill_id); pc_calcstatus(sd, 0); return 0; } @@ -142,3 +147,4 @@ int skill_power_bl(dumb_ptr<block_list> bl, SkillID skill) else return 0; } +} // namespace tmwa diff --git a/src/map/skill-pools.hpp b/src/map/skill-pools.hpp index 6781907..c8890e8 100644 --- a/src/map/skill-pools.hpp +++ b/src/map/skill-pools.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_SKILL_POOLS_HPP -#define TMWA_MAP_SKILL_POOLS_HPP +#pragma once // skill-pools.hpp - dummy header to make Make dependencies work. // // Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> @@ -19,6 +18,9 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -#endif // TMWA_MAP_SKILL_POOLS_HPP + +namespace tmwa +{ +} // namespace tmwa diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 37a3b44..add6a42 100644 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -22,9 +22,8 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include <cassert> -#include <cstdlib> -#include <cstring> -#include <ctime> + +#include <algorithm> #include "../compat/attr.hpp" #include "../compat/fun.hpp" @@ -32,56 +31,63 @@ #include "../strings/mstring.hpp" #include "../strings/rstring.hpp" +#include "../strings/astring.hpp" +#include "../strings/zstring.hpp" #include "../strings/xstring.hpp" +#include "../strings/literal.hpp" #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" +#include "../io/cxxstdio_enums.hpp" #include "../io/read.hpp" +#include "../net/timer.hpp" + #include "../mmo/extract.hpp" -#include "../mmo/socket.hpp" -#include "../mmo/timer.hpp" +#include "../mmo/extract_enums.hpp" #include "battle.hpp" #include "clif.hpp" -#include "magic.hpp" -#include "map.hpp" +#include "magic-stmt.hpp" #include "mob.hpp" #include "pc.hpp" #include "../poison.hpp" + +namespace tmwa +{ struct skill_name_db skill_names[] = { - {SkillID::AC_OWL, "OWL", "Owl's_Eye"}, - - {SkillID::NPC_EMOTION, "EMOTION", "NPC_EMOTION"}, - {SkillID::NPC_POISON, "POISON", "NPC_POISON"}, - {SkillID::NPC_SELFDESTRUCTION, "SELFDESTRUCTION", "Kabooooom!"}, - {SkillID::NPC_SUMMONSLAVE, "SUMMONSLAVE", "NPC_SUMMONSLAVE"}, - - {SkillID::NV_EMOTE, "EMOTE", "Emote_Skill"}, - {SkillID::NV_TRADE, "TRADE", "Trade_Skill"}, - {SkillID::NV_PARTY, "PARTY", "Party_Skill"}, - - {SkillID::TMW_MAGIC, "MAGIC", "General Magic"}, - {SkillID::TMW_MAGIC_LIFE, "MAGIC_LIFE", "Life Magic"}, - {SkillID::TMW_MAGIC_WAR, "MAGIC_WAR", "War Magic"}, - {SkillID::TMW_MAGIC_TRANSMUTE, "MAGIC_TRANSMUTE", "Transmutation Magic"}, - {SkillID::TMW_MAGIC_NATURE, "MAGIC_NATURE", "Nature Magic"}, - {SkillID::TMW_MAGIC_ETHER, "MAGIC_ETHER", "Astral Magic"}, - {SkillID::TMW_MAGIC_DARK, "MAGIC_DARK", "Dark Magic"}, - {SkillID::TMW_MAGIC_LIGHT, "MAGIC_LIGHT", "Light Magic"}, - - {SkillID::TMW_BRAWLING, "BRAWLING", "Brawling"}, - {SkillID::TMW_LUCKY_COUNTER, "LUCKY_COUNTER", "Lucky Counter"}, - {SkillID::TMW_SPEED, "SPEED", "Speed"}, - {SkillID::TMW_RESIST_POISON, "RESIST_POISON", "Resist Poison"}, - {SkillID::TMW_ASTRAL_SOUL, "ASTRAL_SOUL", "Astral Soul"}, - {SkillID::TMW_RAGING, "RAGING", "Raging"}, - - {SkillID::ZERO, "", ""} + {SkillID::AC_OWL, "OWL"_s, "Owl's_Eye"_s}, + + {SkillID::NPC_EMOTION, "EMOTION"_s, "NPC_EMOTION"_s}, + {SkillID::NPC_POISON, "POISON"_s, "NPC_POISON"_s}, + {SkillID::NPC_SELFDESTRUCTION, "SELFDESTRUCTION"_s, "Kabooooom!"_s}, + {SkillID::NPC_SUMMONSLAVE, "SUMMONSLAVE"_s, "NPC_SUMMONSLAVE"_s}, + + {SkillID::NV_EMOTE, "EMOTE"_s, "Emote_Skill"_s}, + {SkillID::NV_TRADE, "TRADE"_s, "Trade_Skill"_s}, + {SkillID::NV_PARTY, "PARTY"_s, "Party_Skill"_s}, + + {SkillID::TMW_MAGIC, "MAGIC"_s, "General Magic"_s}, + {SkillID::TMW_MAGIC_LIFE, "MAGIC_LIFE"_s, "Life Magic"_s}, + {SkillID::TMW_MAGIC_WAR, "MAGIC_WAR"_s, "War Magic"_s}, + {SkillID::TMW_MAGIC_TRANSMUTE, "MAGIC_TRANSMUTE"_s, "Transmutation Magic"_s}, + {SkillID::TMW_MAGIC_NATURE, "MAGIC_NATURE"_s, "Nature Magic"_s}, + {SkillID::TMW_MAGIC_ETHER, "MAGIC_ETHER"_s, "Astral Magic"_s}, + {SkillID::TMW_MAGIC_DARK, "MAGIC_DARK"_s, "Dark Magic"_s}, + {SkillID::TMW_MAGIC_LIGHT, "MAGIC_LIGHT"_s, "Light Magic"_s}, + + {SkillID::TMW_BRAWLING, "BRAWLING"_s, "Brawling"_s}, + {SkillID::TMW_LUCKY_COUNTER, "LUCKY_COUNTER"_s, "Lucky Counter"_s}, + {SkillID::TMW_SPEED, "SPEED"_s, "Speed"_s}, + {SkillID::TMW_RESIST_POISON, "RESIST_POISON"_s, "Resist Poison"_s}, + {SkillID::TMW_ASTRAL_SOUL, "ASTRAL_SOUL"_s, "Astral Soul"_s}, + {SkillID::TMW_RAGING, "RAGING"_s, "Raging"_s}, + + {SkillID::ZERO, ""_s, ""_s} }; earray<skill_db_, SkillID, SkillID::MAX_SKILL_DB> skill_db; @@ -94,7 +100,7 @@ int skill_attack(BF attack_type, dumb_ptr<block_list> src, static void skill_status_change_timer(TimerData *tid, tick_t tick, - int id, StatusChange type); + BlockId id, StatusChange type); int skill_get_hit(SkillID id) { @@ -169,16 +175,16 @@ int skill_get_castnodex(SkillID id, int lv) int skill_additional_effect(dumb_ptr<block_list> src, dumb_ptr<block_list> bl, SkillID skillid, int skilllv) { - dumb_ptr<map_session_data> sd = NULL; - dumb_ptr<mob_data> md = NULL; + dumb_ptr<map_session_data> sd = nullptr; + dumb_ptr<mob_data> md = nullptr; int luk; int sc_def_mdef, sc_def_vit, sc_def_int, sc_def_luk; int sc_def_phys_shield_spell; - nullpo_ret(src); - nullpo_ret(bl); + nullpo_retz(src); + nullpo_retz(bl); if (skilllv < 0) return 0; @@ -256,16 +262,16 @@ int skill_attack(BF attack_type, dumb_ptr<block_list> src, eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; int type, lv, damage; - nullpo_ret(src); - nullpo_ret(dsrc); - nullpo_ret(bl); + nullpo_retz(src); + nullpo_retz(dsrc); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); //何もしない判定ここから if (dsrc->bl_m != bl->bl_m) //対象が同じマップにいなければ何もしない return 0; - if (src->bl_prev == NULL || dsrc->bl_prev == NULL || bl->bl_prev == NULL) //prevよくわからない※ + if (src->bl_prev == nullptr || dsrc->bl_prev == nullptr || bl->bl_prev == nullptr) //prevよくわからない※ return 0; if (src->bl_type == BL::PC && pc_isdead(src->is_player())) //術者?がPCですでに死んでいたら何もしない return 0; @@ -304,7 +310,7 @@ int skill_attack(BF attack_type, dumb_ptr<block_list> src, battle_damage(src, bl, damage, 0); /* ダメージがあるなら追加効果判定 */ - if (bl->bl_prev != NULL) + if (bl->bl_prev != nullptr) { dumb_ptr<map_session_data> sd = bl->is_player(); if (bl->bl_type != BL::PC || !pc_isdead(sd)) @@ -316,8 +322,7 @@ int skill_attack(BF attack_type, dumb_ptr<block_list> src, dumb_ptr<mob_data> md = bl->is_mob(); if (battle_config.mob_changetarget_byskill == 1) { - int target; - target = md->target_id; + BlockId target = md->target_id; if (src->bl_type == BL::PC) md->target_id = src->bl_id; mobskill_use(md, tick, MobSkillCondition::ANY); @@ -389,7 +394,9 @@ void skill_area_sub(dumb_ptr<block_list> bl, // these variables are set in the 'else' branches, // and used in the (recursive) 'if' branch -static int skill_area_temp_id, skill_area_temp_hp; +// TODO kill it, kill it with fire. +static BlockId skill_area_temp_id; +static int skill_area_temp_hp; /*========================================== @@ -401,7 +408,7 @@ int skill_castend_damage_id(dumb_ptr<block_list> src, dumb_ptr<block_list> bl, SkillID skillid, int skilllv, tick_t tick, BCT flag) { - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; nullpo_retr(1, src); nullpo_retr(1, bl); @@ -411,7 +418,7 @@ int skill_castend_damage_id(dumb_ptr<block_list> src, dumb_ptr<block_list> bl, if (sd && pc_isdead(sd)) return 1; - if (bl->bl_prev == NULL) + if (bl->bl_prev == nullptr) return 1; if (bl->bl_type == BL::PC && pc_isdead(bl->is_player())) return 1; @@ -496,10 +503,10 @@ int skill_castend_damage_id(dumb_ptr<block_list> src, dumb_ptr<block_list> bl, int skill_castend_nodamage_id(dumb_ptr<block_list> src, dumb_ptr<block_list> bl, SkillID skillid, int skilllv) { - dumb_ptr<map_session_data> sd = NULL; - dumb_ptr<map_session_data> dstsd = NULL; - dumb_ptr<mob_data> md = NULL; - dumb_ptr<mob_data> dstmd = NULL; + dumb_ptr<map_session_data> sd = nullptr; + dumb_ptr<map_session_data> dstsd = nullptr; + dumb_ptr<mob_data> md = nullptr; + dumb_ptr<mob_data> dstmd = nullptr; int sc_def_vit, sc_def_mdef, strip_fix; nullpo_retr(1, src); @@ -534,7 +541,7 @@ int skill_castend_nodamage_id(dumb_ptr<block_list> src, dumb_ptr<block_list> bl, if (strip_fix < 0) strip_fix = 0; - if (bl == NULL || bl->bl_prev == NULL) + if (bl == nullptr || bl->bl_prev == nullptr) return 1; if (sd && pc_isdead(sd)) return 1; @@ -594,7 +601,7 @@ interval_t skill_castfix(dumb_ptr<block_list> bl, interval_t interval) sc_data = battle_get_sc_data(bl); dex = battle_get_dex(bl); - if (skill > SkillID::MAX_SKILL_DB /*|| skill < SkillID()*/) + if (skill >= SkillID::MAX_SKILL_DB /*|| skill < SkillID()*/) return interval_t::zero(); castnodex = skill_get_castnodex(skill, lv); @@ -649,7 +656,7 @@ interval_t skill_delayfix(dumb_ptr<block_list> bl, interval_t interval) */ int skill_castcancel(dumb_ptr<block_list> bl, int) { - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::PC) { @@ -686,11 +693,11 @@ int skill_status_change_active(dumb_ptr<block_list> bl, StatusChange type) { eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type != BL::PC && bl->bl_type != BL::MOB) { if (battle_config.error_log) - PRINTF("skill_status_change_active: neither MOB nor PC !\n"); + PRINTF("skill_status_change_active: neither MOB nor PC !\n"_fmt); return 0; } @@ -715,7 +722,7 @@ void skill_status_change_end(dumb_ptr<block_list> bl, StatusChange type, TimerDa if (bl->bl_type != BL::PC && bl->bl_type != BL::MOB) { if (battle_config.error_log) - PRINTF("skill_status_change_end: neither MOB nor PC !\n"); + PRINTF("skill_status_change_end: neither MOB nor PC !\n"_fmt); return; } sc_data = battle_get_sc_data(bl); @@ -804,7 +811,7 @@ int skill_update_heal_animation(dumb_ptr<map_session_data> sd) { const Opt2 mask = Opt2::_heal; - nullpo_ret(sd); + nullpo_retz(sd); bool wis_active = bool(sd->opt2 & mask); bool is_active = sd->quick_regeneration_hp.amount > 0; @@ -823,14 +830,14 @@ int skill_update_heal_animation(dumb_ptr<map_session_data> sd) * ステータス異常終了タイマー *------------------------------------------ */ -void skill_status_change_timer(TimerData *tid, tick_t tick, int id, StatusChange type) +void skill_status_change_timer(TimerData *tid, tick_t tick, BlockId id, StatusChange type) { dumb_ptr<block_list> bl; - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; //short *sc_count; //使ってない? - if ((bl = map_id2bl(id)) == NULL) + if ((bl = map_id2bl(id)) == nullptr) return; //該当IDがすでに消滅しているというのはいかにもありそうなのでスルーしてみる sc_data = battle_get_sc_data(bl); @@ -844,9 +851,9 @@ void skill_status_change_timer(TimerData *tid, tick_t tick, int id, StatusChange if (sc_data[type].spell_invocation) { // Must report termination - spell_effect_report_termination(sc_data[type].spell_invocation, + magic::spell_effect_report_termination(sc_data[type].spell_invocation, bl->bl_id, type, 0); - sc_data[type].spell_invocation = 0; + sc_data[type].spell_invocation = BlockId(); } switch (type) @@ -878,7 +885,7 @@ void skill_status_change_timer(TimerData *tid, tick_t tick, int id, StatusChange md->hp -= hp; } } - sc_data[type].timer = Timer(tick + std::chrono::seconds(1), + sc_data[type].timer = Timer(tick + 1_s, std::bind(skill_status_change_timer, ph::_1, ph::_2, bl->bl_id, type)); return; @@ -886,7 +893,7 @@ void skill_status_change_timer(TimerData *tid, tick_t tick, int id, StatusChange } else { - sc_data[type].timer = Timer(tick + std::chrono::seconds(2), + sc_data[type].timer = Timer(tick + 2_s, std::bind(skill_status_change_timer, ph::_1, ph::_2, bl->bl_id, type)); return; @@ -898,7 +905,7 @@ void skill_status_change_timer(TimerData *tid, tick_t tick, int id, StatusChange /* 時間切れ無し?? */ case StatusChange::SC_WEIGHT50: case StatusChange::SC_WEIGHT90: - sc_data[type].timer = Timer(tick + std::chrono::minutes(10), + sc_data[type].timer = Timer(tick + 10_min, std::bind(skill_status_change_timer, ph::_1, ph::_2, bl->bl_id, type)); return; @@ -920,14 +927,14 @@ int skill_status_change_start(dumb_ptr<block_list> bl, StatusChange type, int val1, interval_t tick) { - return skill_status_effect(bl, type, val1, tick, 0); + return skill_status_effect(bl, type, val1, tick, BlockId()); } int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, int val1, - interval_t tick, int spell_invocation) + interval_t tick, BlockId spell_invocation) { - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; short *sc_count; Option *option; @@ -938,20 +945,20 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, SP updateflag = SP::ZERO; int scdef = 0; - nullpo_ret(bl); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); if (not sc_data) return 0; sc_count = battle_get_sc_count(bl); - nullpo_ret(sc_count); + nullpo_retz(sc_count); option = battle_get_option(bl); - nullpo_ret(option); + nullpo_retz(option); opt1 = battle_get_opt1(bl); - nullpo_ret(opt1); + nullpo_retz(opt1); opt2 = battle_get_opt2(bl); - nullpo_ret(opt2); + nullpo_retz(opt2); opt3 = battle_get_opt3(bl); - nullpo_ret(opt3); + nullpo_retz(opt3); switch (type) { @@ -971,7 +978,7 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, else { if (battle_config.error_log) - PRINTF("skill_status_change_start: neither MOB nor PC !\n"); + PRINTF("skill_status_change_start: neither MOB nor PC !\n"_fmt); return 0; } @@ -1024,12 +1031,12 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, } // huh? - tick = std::chrono::seconds(1); + tick = 1_s; break; case StatusChange::SC_WEIGHT50: case StatusChange::SC_WEIGHT90: - tick = std::chrono::minutes(10); + tick = 10_min; break; case StatusChange::SC_HASTE: @@ -1045,7 +1052,7 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, break; default: if (battle_config.error_log) - PRINTF("UnknownStatusChange [%d]\n", type); + PRINTF("UnknownStatusChange [%d]\n"_fmt, type); return 0; } @@ -1077,7 +1084,7 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, sc_data[type].val1 = val1; if (sc_data[type].spell_invocation) // Supplant by newer spell - spell_effect_report_termination(sc_data[type].spell_invocation, + magic::spell_effect_report_termination(sc_data[type].spell_invocation, bl->bl_id, type, 1); sc_data[type].spell_invocation = spell_invocation; @@ -1109,20 +1116,20 @@ int skill_status_change_clear(dumb_ptr<block_list> bl, int type) Opt2 *opt2; Opt3 *opt3; - nullpo_ret(bl); + nullpo_retz(bl); sc_data = battle_get_sc_data(bl); if (not sc_data) return 0; sc_count = battle_get_sc_count(bl); - nullpo_ret(sc_count); + nullpo_retz(sc_count); option = battle_get_option(bl); - nullpo_ret(option); + nullpo_retz(option); opt1 = battle_get_opt1(bl); - nullpo_ret(opt1); + nullpo_retz(opt1); opt2 = battle_get_opt2(bl); - nullpo_ret(opt2); + nullpo_retz(opt2); opt3 = battle_get_opt3(bl); - nullpo_ret(opt3); + nullpo_retz(opt3); if (*sc_count == 0) return 0; @@ -1175,22 +1182,22 @@ void skill_unit_timer_sub_ondelete(dumb_ptr<block_list> bl, static SP scan_stat(XString statname) { - if (statname == "str") + if (statname == "str"_s) return SP::STR; - if (statname == "dex") + if (statname == "dex"_s) return SP::DEX; - if (statname == "agi") + if (statname == "agi"_s) return SP::AGI; - if (statname == "vit") + if (statname == "vit"_s) return SP::VIT; - if (statname == "int") + if (statname == "int"_s) return SP::INT; - if (statname == "luk") + if (statname == "luk"_s) return SP::LUK; - if (statname == "none") + if (statname == "none"_s) return SP::ZERO; - FPRINTF(stderr, "Unknown stat `%s'\n", AString(statname)); + FPRINTF(stderr, "Unknown stat `%s'\n"_fmt, AString(statname)); return SP::ZERO; } @@ -1199,7 +1206,7 @@ bool skill_readdb(ZString filename) io::ReadFile in(filename); if (!in.is_open()) { - PRINTF("can't read %s\n", filename); + PRINTF("can't read %s\n"_fmt, filename); return false; } @@ -1209,7 +1216,7 @@ bool skill_readdb(ZString filename) { // is_comment only works for whole-line comments // that could change once the Z dependency is dropped ... - XString comment = "//"; + LString comment = "//"_s; XString line = line_.xislice_h(std::search(line_.begin(), line_.end(), comment.begin(), comment.end())).rstrip(); if (!line) continue; @@ -1245,15 +1252,15 @@ bool skill_readdb(ZString filename) rv = false; continue; } - if (/*i < SkillID() ||*/ i > SkillID::MAX_SKILL_DB) + if (/*i < SkillID() ||*/ i >= SkillID::MAX_SKILL_DB) { rv = false; continue; } - if (castcancel == "yes") + if (castcancel == "yes"_s) skdb.castcancel = true; - else if (castcancel == "no") + else if (castcancel == "no"_s) skdb.castcancel = false; else { @@ -1261,17 +1268,17 @@ bool skill_readdb(ZString filename) continue; } - if (flags == "passive") + if (flags == "passive"_s) { skill_pool_register(i); skdb.poolflags = SkillFlags::POOL_FLAG; } - else if (flags == "active") + else if (flags == "active"_s) { skill_pool_register(i); skdb.poolflags = SkillFlags::POOL_FLAG | SkillFlags::POOL_ACTIVE; } - else if (flags == "no") + else if (flags == "no"_s) skdb.poolflags = SkillFlags::ZERO; else { @@ -1290,7 +1297,7 @@ bool skill_readdb(ZString filename) skill_db[i] = skdb; skill_lookup_by_id(i).desc = RString(tmp); } - PRINTF("read %s done\n", filename); + PRINTF("read %s done\n"_fmt, filename); return rv; } @@ -1312,3 +1319,4 @@ skill_name_db& skill_lookup_by_name(XString name) return ner; return skill_names[num_names - 1]; } +} // namespace tmwa diff --git a/src/map/skill.hpp b/src/map/skill.hpp index 1a615c1..ec353ce 100644 --- a/src/map/skill.hpp +++ b/src/map/skill.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_SKILL_HPP -#define TMWA_MAP_SKILL_HPP +#pragma once // skill.hpp - Old-style skills. // // Copyright © ????-2004 Athena Dev Teams @@ -21,17 +20,23 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "skill.t.hpp" -# include "skill-pools.hpp" +#include "skill.t.hpp" +#include "skill-pools.hpp" -# include "../strings/fwd.hpp" -# include "../strings/rstring.hpp" -# include "../strings/astring.hpp" +#include "../strings/fwd.hpp" +#include "../strings/rstring.hpp" +#include "../strings/literal.hpp" -# include "map.hpp" +#include "../generic/fwd.hpp" +#include "../generic/array.hpp" +#include "map.hpp" + + +namespace tmwa +{ constexpr int MAX_SKILL_PRODUCE_DB = 150; constexpr int MAX_SKILL_ARROW_DB = 150; constexpr int MAX_SKILL_ABRA_DB = 350; @@ -61,11 +66,11 @@ earray<skill_db_, SkillID, SkillID::MAX_SKILL_DB> skill_db; struct skill_name_db { SkillID id; // skill id - RString name; // search strings + LString name; // search strings RString desc; // description that shows up for searches // this makes const char(&)[] not decay into const char * in {} - skill_name_db(SkillID i, RString n, RString d) + skill_name_db(SkillID i, LString n, LString d) : id(i), name(n), desc(d) {} }; @@ -76,9 +81,6 @@ extern struct skill_name_db skill_names[]; skill_name_db& skill_lookup_by_id(SkillID id); skill_name_db& skill_lookup_by_name(XString name); -struct block_list; -struct map_session_data; - bool skill_readdb(ZString filename); // スキルデータベースへのアクセサ @@ -110,7 +112,7 @@ int skill_castcancel(dumb_ptr<block_list> bl, int type); // ステータス異常 int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, int val1, - interval_t tick, int spell_invocation); + interval_t tick, BlockId spell_invocation); int skill_status_change_start(dumb_ptr<block_list> bl, StatusChange type, int val1, interval_t tick); @@ -164,4 +166,4 @@ int skill_power_bl(dumb_ptr<block_list> bl, SkillID skill); // [Fate] Remember that a certain skill ID belongs to a pool skill void skill_pool_register(SkillID id); -#endif // TMWA_MAP_SKILL_HPP +} // namespace tmwa diff --git a/src/map/skill.t.hpp b/src/map/skill.t.hpp index 4e30cba..d0e3926 100644 --- a/src/map/skill.t.hpp +++ b/src/map/skill.t.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_SKILL_T_HPP -#define TMWA_MAP_SKILL_T_HPP +#pragma once // skill.t.hpp - Old-style skills. // // Copyright © ????-2004 Athena Dev Teams @@ -21,12 +20,15 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include <cstdint> +#include <cstdint> -# include "../generic/enum.hpp" +#include "../generic/enum.hpp" + +namespace tmwa +{ // TODO remove most of these as their corresponding SkillIDs get deleted. enum class StatusChange : uint16_t { @@ -131,5 +133,4 @@ enum class SkillFlags : uint16_t ENUM_BITWISE_OPERATORS(SkillFlags) } using e::SkillFlags; - -#endif // TMWA_MAP_SKILL_T_HPP +} // namespace tmwa diff --git a/src/map/storage.cpp b/src/map/storage.cpp index 89357b9..a6e6a0d 100644 --- a/src/map/storage.cpp +++ b/src/map/storage.cpp @@ -1,14 +1,32 @@ #include "storage.hpp" -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see COPYING in the main folder - -#include <cstdlib> -#include <cstring> +// storage.cpp - Storage handling. +// +// Copyright © ????-2004 Athena Dev Teams +// 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 "../compat/nullpo.hpp" #include "../generic/db.hpp" +#include "../mmo/ids.hpp" +#include "../mmo/mmo.hpp" + #include "chrif.hpp" #include "clif.hpp" #include "intif.hpp" @@ -18,18 +36,21 @@ #include "../poison.hpp" + +namespace tmwa +{ static -Map<int, struct storage> storage_db; +Map<AccountId, Storage> storage_db; void do_final_storage(void) { storage_db.clear(); } -struct storage *account2storage(int account_id) +Storage *account2storage(AccountId account_id) { - struct storage *stor = storage_db.search(account_id); - if (stor == NULL) + Storage *stor = storage_db.search(account_id); + if (stor == nullptr) { stor = storage_db.init(account_id); stor->account_id = account_id; @@ -38,13 +59,13 @@ struct storage *account2storage(int account_id) } // Just to ask storage, without creation -struct storage *account2storage2(int account_id) +Storage *account2storage2(AccountId account_id) { return storage_db.search(account_id); } static -void storage_delete(int account_id) +void storage_delete(AccountId account_id) { storage_db.erase(account_id); } @@ -55,13 +76,13 @@ void storage_delete(int account_id) */ int storage_storageopen(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); if (sd->state.storage_open) return 1; //Already open? - struct storage *stor = storage_db.search(sd->status_key.account_id); - if (stor == NULL) + Storage *stor = storage_db.search(sd->status_key.account_id); + if (stor == nullptr) { //Request storage. intif_request_storage(sd->status_key.account_id); return 1; @@ -83,20 +104,19 @@ int storage_storageopen(dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -int storage_additem(dumb_ptr<map_session_data> sd, struct storage *stor, - struct item *item_data, int amount) +int storage_additem(dumb_ptr<map_session_data> sd, Storage *stor, + Item *item_data, int amount) { struct item_data *data; - int i; - if (item_data->nameid <= 0 || amount <= 0) + if (!item_data->nameid || amount <= 0) return 1; data = itemdb_search(item_data->nameid); if (!itemdb_isequip2(data)) { //Stackable - for (i = 0; i < MAX_STORAGE; i++) + for (SOff0 i : SOff0::iter()) { if (compare_item(&stor->storage_[i], item_data)) { @@ -110,9 +130,12 @@ int storage_additem(dumb_ptr<map_session_data> sd, struct storage *stor, } } //Add item - for (i = 0; i < MAX_STORAGE && stor->storage_[i].nameid; i++); - - if (i >= MAX_STORAGE) + SOff0 i = *std::find_if(SOff0::iter().begin(), SOff0::iter().end(), + [&stor](SOff0 i_) + { + return !stor->storage_[i_].nameid; + }); + if (!i.ok()) return 1; stor->storage_[i] = *item_data; @@ -129,17 +152,17 @@ int storage_additem(dumb_ptr<map_session_data> sd, struct storage *stor, *------------------------------------------ */ static -int storage_delitem(dumb_ptr<map_session_data> sd, struct storage *stor, - int n, int amount) +int storage_delitem(dumb_ptr<map_session_data> sd, Storage *stor, + SOff0 n, int amount) { - if (stor->storage_[n].nameid == 0 || stor->storage_[n].amount < amount) + if (!stor->storage_[n].nameid || stor->storage_[n].amount < amount) return 1; stor->storage_[n].amount -= amount; if (stor->storage_[n].amount == 0) { - stor->storage_[n] = item{}; + stor->storage_[n] = Item{}; stor->storage_amount--; clif_updatestorageamount(sd, stor); } @@ -153,21 +176,21 @@ int storage_delitem(dumb_ptr<map_session_data> sd, struct storage *stor, * Add an item to the storage from the inventory. *------------------------------------------ */ -int storage_storageadd(dumb_ptr<map_session_data> sd, int index, int amount) +int storage_storageadd(dumb_ptr<map_session_data> sd, IOff0 index, int amount) { - struct storage *stor; + Storage *stor; - nullpo_ret(sd); + nullpo_retz(sd); stor = account2storage2(sd->status_key.account_id); - nullpo_ret(stor); + nullpo_retz(stor); if ((stor->storage_amount > MAX_STORAGE) || !stor->storage_status) return 0; // storage full / storage closed - if (index < 0 || index >= MAX_INVENTORY) + if (!index.ok()) return 0; - if (sd->status.inventory[index].nameid <= 0) + if (!sd->status.inventory[index].nameid) return 0; //No item on that spot if (amount < 1 || amount > sd->status.inventory[index].amount) @@ -188,19 +211,19 @@ int storage_storageadd(dumb_ptr<map_session_data> sd, int index, int amount) * Retrieve an item from the storage. *------------------------------------------ */ -int storage_storageget(dumb_ptr<map_session_data> sd, int index, int amount) +int storage_storageget(dumb_ptr<map_session_data> sd, SOff0 index, int amount) { - struct storage *stor; + Storage *stor; PickupFail flag; - nullpo_ret(sd); + nullpo_retz(sd); stor = account2storage2(sd->status_key.account_id); - nullpo_ret(stor); + nullpo_retz(stor); - if (index < 0 || index >= MAX_STORAGE) + if (!index.ok()) return 0; - if (stor->storage_[index].nameid <= 0) + if (!stor->storage_[index].nameid) return 0; //Nothing there if (amount < 1 || amount > stor->storage_[index].amount) @@ -209,7 +232,7 @@ int storage_storageget(dumb_ptr<map_session_data> sd, int index, int amount) if ((flag = pc_additem(sd, &stor->storage_[index], amount)) == PickupFail::OKAY) storage_delitem(sd, stor, index, amount); else - clif_additem(sd, 0, 0, flag); + clif_additem(sd, IOff0::from(0), 0, flag); // log_fromstorage(sd, index, 0); return 1; } @@ -220,11 +243,11 @@ int storage_storageget(dumb_ptr<map_session_data> sd, int index, int amount) */ int storage_storageclose(dumb_ptr<map_session_data> sd) { - struct storage *stor; + Storage *stor; - nullpo_ret(sd); + nullpo_retz(sd); stor = account2storage2(sd->status_key.account_id); - nullpo_ret(stor); + nullpo_retz(stor); clif_storageclose(sd); if (stor->storage_status) @@ -252,9 +275,9 @@ int storage_storageclose(dumb_ptr<map_session_data> sd) */ int storage_storage_quit(dumb_ptr<map_session_data> sd) { - struct storage *stor; + Storage *stor; - nullpo_ret(sd); + nullpo_retz(sd); stor = account2storage2(sd->status_key.account_id); if (stor) @@ -267,9 +290,9 @@ int storage_storage_quit(dumb_ptr<map_session_data> sd) return 0; } -int storage_storage_save(int account_id, int final) +int storage_storage_save(AccountId account_id, int final) { - struct storage *stor; + Storage *stor; stor = account2storage2(account_id); if (!stor) @@ -295,9 +318,9 @@ int storage_storage_save(int account_id, int final) } //Ack from Char-server indicating the storage was saved. [Skotlex] -int storage_storage_saved(int account_id) +int storage_storage_saved(AccountId account_id) { - struct storage *stor = account2storage2(account_id); + Storage *stor = account2storage2(account_id); if (stor) { @@ -311,3 +334,4 @@ int storage_storage_saved(int account_id) } return 0; } +} // namespace tmwa diff --git a/src/map/storage.hpp b/src/map/storage.hpp index 702c908..f3875c8 100644 --- a/src/map/storage.hpp +++ b/src/map/storage.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_STORAGE_HPP -#define TMWA_MAP_STORAGE_HPP +#pragma once // storage.hpp - Storage handling. // // Copyright © ????-2004 Athena Dev Teams @@ -21,19 +20,25 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "map.hpp" +#include "../generic/fwd.hpp" +#include "../mmo/fwd.hpp" + +#include "clif.t.hpp" + + +namespace tmwa +{ int storage_storageopen(dumb_ptr<map_session_data> sd); -int storage_storageadd(dumb_ptr<map_session_data> sd, int index, int amount); -int storage_storageget(dumb_ptr<map_session_data> sd, int index, int amount); +int storage_storageadd(dumb_ptr<map_session_data> sd, IOff0 index, int amount); +int storage_storageget(dumb_ptr<map_session_data> sd, SOff0 index, int amount); int storage_storageclose(dumb_ptr<map_session_data> sd); void do_final_storage(void); -struct storage *account2storage(int account_id); -struct storage *account2storage2(int account_id); +Storage *account2storage(AccountId account_id); +Storage *account2storage2(AccountId account_id); int storage_storage_quit(dumb_ptr<map_session_data> sd); -int storage_storage_save(int account_id, int final); -int storage_storage_saved(int account_id); - -#endif // TMWA_MAP_STORAGE_HPP +int storage_storage_save(AccountId account_id, int final); +int storage_storage_saved(AccountId account_id); +} // namespace tmwa diff --git a/src/map/tmw.cpp b/src/map/tmw.cpp index 46128d1..60b5027 100644 --- a/src/map/tmw.cpp +++ b/src/map/tmw.cpp @@ -19,17 +19,18 @@ // 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 <cctype> -#include <cstring> - #include "../compat/nullpo.hpp" #include "../strings/astring.hpp" #include "../strings/zstring.hpp" #include "../strings/xstring.hpp" +#include "../strings/literal.hpp" #include "../io/cxxstdio.hpp" +#include "../mmo/human_time_diff.hpp" +#include "../mmo/utils.hpp" + #include "atcommand.hpp" #include "battle.hpp" #include "chrif.hpp" @@ -40,6 +41,9 @@ #include "../poison.hpp" + +namespace tmwa +{ static void tmw_AutoBan(dumb_ptr<map_session_data> sd, ZString reason, int length); static @@ -91,7 +95,7 @@ int tmw_CheckChatSpam(dumb_ptr<map_session_data> sd, XString message) { sd->chat_lines_in = sd->chat_total_repeats = 0; - tmw_AutoBan(sd, "chat", battle_config.chat_spam_ban); + tmw_AutoBan(sd, "chat"_s, battle_config.chat_spam_ban); return 1; } @@ -100,8 +104,8 @@ int tmw_CheckChatSpam(dumb_ptr<map_session_data> sd, XString message) (sd->chat_lines_in >= battle_config.chat_spam_warn || sd->chat_total_repeats >= battle_config.chat_spam_warn)) { - clif_displaymessage(sd->sess, "WARNING: You are about to be automatically banned for spam!"); - clif_displaymessage(sd->sess, "WARNING: Please slow down, do not repeat, and do not SHOUT!"); + clif_displaymessage(sd->sess, "WARNING: You are about to be automatically banned for spam!"_s); + clif_displaymessage(sd->sess, "WARNING: Please slow down, do not repeat, and do not SHOUT!"_s); } return 0; @@ -114,23 +118,23 @@ void tmw_AutoBan(dumb_ptr<map_session_data> sd, ZString reason, int length) sd->auto_ban_info.in_progress = 1; - AString hack_msg = STRPRINTF("[GM] %s has been autobanned for %s spam", + AString hack_msg = STRPRINTF("[GM] %s has been autobanned for %s spam"_fmt, sd->status_key.name, reason); tmw_GmHackMsg(hack_msg); - AString fake_command = STRPRINTF("@autoban %s %dh (%s spam)", + AString fake_command = STRPRINTF("@autoban %s %dh (%s spam)"_fmt, sd->status_key.name, length, reason); log_atcommand(sd, fake_command); - AString anotherbuf = STRPRINTF("You have been banned for %s spamming. Please do not spam.", + AString anotherbuf = STRPRINTF("You have been banned for %s spamming. Please do not spam."_fmt, reason); clif_displaymessage(sd->sess, anotherbuf); /* type: 2 - ban(year, month, day, hour, minute, second) */ HumanTimeDiff ban_len {}; ban_len.hour = length; - chrif_char_ask_name(-1, sd->status_key.name, 2, ban_len); + chrif_char_ask_name(AccountId(), sd->status_key.name, 2, ban_len); clif_setwaitclose(sd->sess); } @@ -159,6 +163,7 @@ bool tmw_CheckChatLameness(dumb_ptr<map_session_data>, XString message) void tmw_GmHackMsg(ZString line) { intif_wis_message_to_gm(wisp_server_name, - battle_config.hack_info_GM_level, + GmLevel::from(static_cast<uint32_t>(battle_config.hack_info_GM_level)), line); } +} // namespace tmwa diff --git a/src/map/tmw.hpp b/src/map/tmw.hpp index 670599e..ffd6f7f 100644 --- a/src/map/tmw.hpp +++ b/src/map/tmw.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_TMW_HPP -#define TMWA_MAP_TMW_HPP +#pragma once // tmw.hpp - Some random functions added by TMW. // // Copyright © 2004-2011 The Mana World Development Team @@ -20,15 +19,15 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "../strings/fwd.hpp" +#include "../strings/fwd.hpp" -# include "../mmo/dumb_ptr.hpp" +#include "../generic/fwd.hpp" -# include "map.hpp" +namespace tmwa +{ int tmw_CheckChatSpam(dumb_ptr<map_session_data> sd, XString message); void tmw_GmHackMsg(ZString line); - -#endif // TMWA_MAP_TMW_HPP +} // namespace tmwa diff --git a/src/map/trade.cpp b/src/map/trade.cpp index c877d00..c52377d 100644 --- a/src/map/trade.cpp +++ b/src/map/trade.cpp @@ -34,21 +34,24 @@ #include "../poison.hpp" + +namespace tmwa +{ /*========================================== * 取引要請を相手に送る *------------------------------------------ */ -void trade_traderequest(dumb_ptr<map_session_data> sd, int target_id) +void trade_traderequest(dumb_ptr<map_session_data> sd, BlockId target_id) { dumb_ptr<map_session_data> target_sd; nullpo_retv(sd); - if ((target_sd = map_id2sd(target_id)) != NULL) + if ((target_sd = map_id2sd(target_id)) != nullptr) { if (!battle_config.invite_request_check) { - if (target_sd->party_invite > 0) + if (target_sd->party_invite) { clif_tradestart(sd, 2); // 相手はPT要請中かGuild要請中 return; @@ -60,7 +63,7 @@ void trade_traderequest(dumb_ptr<map_session_data> sd, int target_id) clif_tradestart(sd, 2); return; } - if ((target_sd->trade_partner != 0) || (sd->trade_partner != 0)) + if ((target_sd->trade_partner) || (sd->trade_partner)) { trade_tradecancel(sd); //person is in another trade } @@ -97,20 +100,20 @@ void trade_tradeack(dumb_ptr<map_session_data> sd, int type) dumb_ptr<map_session_data> target_sd; nullpo_retv(sd); - if ((target_sd = map_id2sd(sd->trade_partner)) != NULL) + if ((target_sd = map_id2sd(account_to_block(sd->trade_partner))) != nullptr) { clif_tradestart(target_sd, type); clif_tradestart(sd, type); if (type == 4) { // Cancel sd->deal_locked = 0; - sd->trade_partner = 0; + sd->trade_partner = AccountId(); target_sd->deal_locked = 0; - target_sd->trade_partner = 0; + target_sd->trade_partner = AccountId(); } - if (sd->npc_id != 0) + if (sd->npc_id) npc_event_dequeue(sd); - if (target_sd->npc_id != 0) + if (target_sd->npc_id) npc_event_dequeue(target_sd); //close STORAGE window if it's open. It protects from spooffing packets [Lupus] @@ -123,7 +126,7 @@ void trade_tradeack(dumb_ptr<map_session_data> sd, int type) * アイテム追加 *------------------------------------------ */ -void trade_tradeadditem(dumb_ptr<map_session_data> sd, int index, int amount) +void trade_tradeadditem(dumb_ptr<map_session_data> sd, IOff2 index, int amount) { dumb_ptr<map_session_data> target_sd; struct item_data *id; @@ -131,30 +134,29 @@ void trade_tradeadditem(dumb_ptr<map_session_data> sd, int index, int amount) int trade_weight = 0; int free_ = 0; int c; - int i; nullpo_retv(sd); - if (((target_sd = map_id2sd(sd->trade_partner)) != NULL) + if (((target_sd = map_id2sd(account_to_block(sd->trade_partner))) != nullptr) && (sd->deal_locked < 1)) { - if (index < 2 || index >= MAX_INVENTORY + 2) + if (!index.ok()) { - if (index == 0 && amount > 0 && amount <= sd->status.zeny) + if (index.index == 0 && amount > 0 && amount <= sd->status.zeny) { sd->deal_zeny = amount; - clif_tradeadditem(sd, target_sd, 0, amount); + clif_tradeadditem(sd, target_sd, index, amount); } } // note: amount is overridden below! - else if (amount <= sd->status.inventory[index - 2].amount + else if (amount <= sd->status.inventory[index.unshift()].amount && amount > 0) { // determine free slots of receiver - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { - if (target_sd->status.inventory[i].nameid == 0 - && target_sd->inventory_data[i] == NULL) + if (!target_sd->status.inventory[i].nameid + && target_sd->inventory_data[i] == nullptr) free_++; } for (trade_i = 0; trade_i < TRADE_MAX; trade_i++) @@ -163,14 +165,14 @@ void trade_tradeadditem(dumb_ptr<map_session_data> sd, int index, int amount) { // calculate trade weight trade_weight += - sd->inventory_data[index - 2]->weight * amount; + sd->inventory_data[index.unshift()]->weight * amount; // determine if item is a stackable already in receivers inventory, and up free count - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { if (target_sd->status.inventory[i].nameid == - sd->status.inventory[index - 2].nameid - && target_sd->inventory_data[i] != NULL) + sd->status.inventory[index.unshift()].nameid + && target_sd->inventory_data[i] != nullptr) { id = target_sd->inventory_data[i]; if (id->type != ItemType::WEAPON @@ -205,7 +207,7 @@ void trade_tradeadditem(dumb_ptr<map_session_data> sd, int index, int amount) return; } } - pc_unequipinvyitem(sd, index - 2, CalcStatus::NOW); + pc_unequipinvyitem(sd, index.unshift(), CalcStatus::NOW); sd->deal_item_index[trade_i] = index; sd->deal_item_amount[trade_i] += amount; clif_tradeitemok(sd, index, amount, 0); //success to add item @@ -217,16 +219,16 @@ void trade_tradeadditem(dumb_ptr<map_session_data> sd, int index, int amount) { // calculate weight for stored deal trade_weight += - sd->inventory_data[sd->deal_item_index[trade_i] - - 2]->weight * + sd->inventory_data[sd->deal_item_index[trade_i].unshift() + ]->weight * sd->deal_item_amount[trade_i]; // count free stackables in stored deal - for (i = 0; i < MAX_INVENTORY; i++) + for (IOff0 i : IOff0::iter()) { if (target_sd->status.inventory[i].nameid == sd->status. - inventory[sd->deal_item_index[trade_i] - 2].nameid - && target_sd->inventory_data[i] != NULL) + inventory[sd->deal_item_index[trade_i].unshift()].nameid + && target_sd->inventory_data[i] != nullptr) { id = target_sd->inventory_data[i]; if (id->type != ItemType::WEAPON @@ -260,11 +262,11 @@ void trade_tradeok(dumb_ptr<map_session_data> sd) for (trade_i = 0; trade_i < TRADE_MAX; trade_i++) { - int index = sd->deal_item_index[trade_i]; - if (index < 2 || index >= MAX_INVENTORY + 2) + IOff2 index = sd->deal_item_index[trade_i]; + if (!index.ok()) continue; if (sd->deal_item_amount[trade_i] > - sd->status.inventory[index - 2].amount + sd->status.inventory[index.unshift()].amount || sd->deal_item_amount[trade_i] < 0) { trade_tradecancel(sd); @@ -273,10 +275,10 @@ void trade_tradeok(dumb_ptr<map_session_data> sd) } - if ((target_sd = map_id2sd(sd->trade_partner)) != NULL) + if ((target_sd = map_id2sd(account_to_block(sd->trade_partner))) != nullptr) { sd->deal_locked = 1; - clif_tradeitemok(sd, 0, 0, 0); + clif_tradeitemok(sd, IOff2::from(0), 0, 0); clif_tradedeal_lock(sd, 0); clif_tradedeal_lock(target_sd, 1); } @@ -293,26 +295,28 @@ void trade_tradecancel(dumb_ptr<map_session_data> sd) nullpo_retv(sd); - if ((target_sd = map_id2sd(sd->trade_partner)) != NULL) + if ((target_sd = map_id2sd(account_to_block(sd->trade_partner))) != nullptr) { for (trade_i = 0; trade_i < TRADE_MAX; trade_i++) { //give items back (only virtual) if (sd->deal_item_amount[trade_i] != 0) { + assert (sd->deal_item_index[trade_i].ok()); clif_additem(sd, - sd->deal_item_index[trade_i] - 2, + sd->deal_item_index[trade_i].unshift(), sd->deal_item_amount[trade_i], PickupFail::OKAY); - sd->deal_item_index[trade_i] = 0; + sd->deal_item_index[trade_i] = IOff2::from(0); sd->deal_item_amount[trade_i] = 0; } if (target_sd->deal_item_amount[trade_i] != 0) { + assert (target_sd->deal_item_index[trade_i].ok()); clif_additem(target_sd, - target_sd->deal_item_index[trade_i] - 2, + target_sd->deal_item_index[trade_i].unshift(), target_sd->deal_item_amount[trade_i], PickupFail::OKAY); - target_sd->deal_item_index[trade_i] = 0; + target_sd->deal_item_index[trade_i] = IOff2::from(0); target_sd->deal_item_amount[trade_i] = 0; } } @@ -327,9 +331,9 @@ void trade_tradecancel(dumb_ptr<map_session_data> sd) target_sd->deal_zeny = 0; } sd->deal_locked = 0; - sd->trade_partner = 0; + sd->trade_partner = AccountId(); target_sd->deal_locked = 0; - target_sd->trade_partner = 0; + target_sd->trade_partner = AccountId(); clif_tradecancelled(sd); clif_tradecancelled(target_sd); } @@ -346,11 +350,11 @@ void trade_tradecommit(dumb_ptr<map_session_data> sd) nullpo_retv(sd); - if ((target_sd = map_id2sd(sd->trade_partner)) != NULL) + if ((target_sd = map_id2sd(account_to_block(sd->trade_partner))) != nullptr) { - MAP_LOG_PC(sd, " TRADECOMMIT WITH %d GIVE %d GET %d", - target_sd->status_key.char_id, sd->deal_zeny, - target_sd->deal_zeny); + MAP_LOG_PC(sd, " TRADECOMMIT WITH %d GIVE %d GET %d"_fmt, + target_sd->status_key.char_id, sd->deal_zeny, + target_sd->deal_zeny); if ((sd->deal_locked >= 1) && (target_sd->deal_locked >= 1)) { // both have pressed 'ok' if (sd->deal_locked < 2) @@ -363,23 +367,24 @@ void trade_tradecommit(dumb_ptr<map_session_data> sd) { sd->deal_zeny = 0; trade_tradecancel(sd); - MAP_LOG_PC(sd, " TRADECANCEL"); + MAP_LOG_PC(sd, " TRADECANCEL"_fmt); return; } if (target_sd->deal_zeny > target_sd->status.zeny) { target_sd->deal_zeny = 0; trade_tradecancel(sd); - MAP_LOG_PC(sd, " TRADECANCEL"); + MAP_LOG_PC(sd, " TRADECANCEL"_fmt); return; } - sd->trade_partner = 0; - target_sd->trade_partner = 0; + sd->trade_partner = AccountId(); + target_sd->trade_partner = AccountId(); for (trade_i = 0; trade_i < TRADE_MAX; trade_i++) { if (sd->deal_item_amount[trade_i] != 0) { - int n = sd->deal_item_index[trade_i] - 2; + assert (sd->deal_item_index[trade_i].ok()); + IOff0 n = sd->deal_item_index[trade_i].unshift(); PickupFail flag = pc_additem(target_sd, &sd->status.inventory[n], sd->deal_item_amount[trade_i]); @@ -390,12 +395,13 @@ void trade_tradecommit(dumb_ptr<map_session_data> sd) clif_additem(sd, n, sd->deal_item_amount[trade_i], PickupFail::OKAY); - sd->deal_item_index[trade_i] = 0; + sd->deal_item_index[trade_i] = IOff2::from(0); sd->deal_item_amount[trade_i] = 0; } if (target_sd->deal_item_amount[trade_i] != 0) { - int n = target_sd->deal_item_index[trade_i] - 2; + assert (target_sd->deal_item_index[trade_i].ok()); + IOff0 n = target_sd->deal_item_index[trade_i].unshift(); PickupFail flag = pc_additem(sd, &target_sd->status.inventory[n], target_sd->deal_item_amount[trade_i]); @@ -405,10 +411,9 @@ void trade_tradecommit(dumb_ptr<map_session_data> sd) 1); else clif_additem(target_sd, n, - target_sd->deal_item_amount[trade_i], PickupFail::OKAY); - target_sd->deal_item_index[trade_i] = 0; + target_sd->deal_item_index[trade_i] = IOff2::from(0); target_sd->deal_item_amount[trade_i] = 0; } } @@ -434,7 +439,7 @@ void trade_tradecommit(dumb_ptr<map_session_data> sd) target_sd->deal_locked = 0; clif_tradecompleted(sd, 0); clif_tradecompleted(target_sd, 0); - MAP_LOG_PC(sd, " TRADEOK"); + MAP_LOG_PC(sd, " TRADEOK"_fmt); } } } @@ -449,14 +454,15 @@ void trade_verifyzeny(dumb_ptr<map_session_data> sd) nullpo_retv(sd); - if ((target_sd = map_id2sd(sd->trade_partner)) != NULL) + if ((target_sd = map_id2sd(account_to_block(sd->trade_partner))) != nullptr) { if (sd->deal_zeny > sd->status.zeny) { if (sd->deal_locked < 1) - trade_tradeadditem(sd, 0, sd->status.zeny); // Fix money ammount + trade_tradeadditem(sd, IOff2::from(0), sd->status.zeny); // Fix money ammount else trade_tradecancel(sd); // Or cancel the trade if we can't fix it } } } +} // namespace tmwa diff --git a/src/map/trade.hpp b/src/map/trade.hpp index dc81c54..91ed954 100644 --- a/src/map/trade.hpp +++ b/src/map/trade.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_MAP_TRADE_HPP -#define TMWA_MAP_TRADE_HPP +#pragma once // trade.hpp - Inter-player item and money transactions. // // Copyright © ????-2004 Athena Dev Teams @@ -21,16 +20,20 @@ // 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 "../sanity.hpp" +#include "fwd.hpp" -# include "map.hpp" +#include "../generic/fwd.hpp" -void trade_traderequest(dumb_ptr<map_session_data> sd, int target_id); +#include "clif.t.hpp" + + +namespace tmwa +{ +void trade_traderequest(dumb_ptr<map_session_data> sd, BlockId target_id); void trade_tradeack(dumb_ptr<map_session_data> sd, int type); -void trade_tradeadditem(dumb_ptr<map_session_data> sd, int index, int amount); +void trade_tradeadditem(dumb_ptr<map_session_data> sd, IOff2 index, int amount); void trade_tradeok(dumb_ptr<map_session_data> sd); void trade_tradecancel(dumb_ptr<map_session_data> sd); void trade_tradecommit(dumb_ptr<map_session_data> sd); void trade_verifyzeny(dumb_ptr<map_session_data> sd); - -#endif // TMWA_MAP_TRADE_HPP +} // namespace tmwa |