diff options
Diffstat (limited to 'src/map/npc.cpp')
-rw-r--r-- | src/map/npc.cpp | 571 |
1 files changed, 261 insertions, 310 deletions
diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 68b5ad7..41f0966 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -9,6 +9,7 @@ #include "../common/cxxstdio.hpp" #include "../common/db.hpp" +#include "../common/extract.hpp" #include "../common/nullpo.hpp" #include "../common/socket.hpp" #include "../common/timer.hpp" @@ -25,7 +26,7 @@ #include "../poison.hpp" static -std::list<std::string> npc_srcs; +std::list<FString> npc_srcs; static int npc_id = START_NPC_NUM; @@ -43,9 +44,9 @@ struct event_data int pos; }; static -Map<std::string, struct event_data> ev_db; +Map<NpcEvent, struct event_data> ev_db; static -DMap<std::string, dumb_ptr<npc_data>> npcname_db; +DMap<NpcName, dumb_ptr<npc_data>> npcname_db; // used for clock-based event triggers // only tm_min, tm_hour, and tm_mday are used @@ -62,7 +63,6 @@ static void npc_enable_sub(dumb_ptr<block_list> bl, dumb_ptr<npc_data> nd) { dumb_ptr<map_session_data> sd; - char aname[50] {}; nullpo_retv(bl); @@ -74,16 +74,17 @@ void npc_enable_sub(dumb_ptr<block_list> bl, dumb_ptr<npc_data> nd) if (nd->flag & 1) return; - strzcpy(aname, nd->name, sizeof(nd->name)); + NpcEvent aname; + aname.npc = nd->name; + aname.label = stringish<ScriptLabel>("OnTouch"); if (sd->areanpc_id == nd->bl_id) return; sd->areanpc_id = nd->bl_id; - strcat(aname, "::OnTouch"); npc_event(sd, aname, 0); } } -int npc_enable(const char *name, bool flag) +int npc_enable(NpcName name, bool flag) { dumb_ptr<npc_data> nd = npcname_db.get(name); if (nd == NULL) @@ -121,7 +122,7 @@ int npc_enable(const char *name, bool flag) * NPCを名前で探す *------------------------------------------ */ -dumb_ptr<npc_data> npc_name2id(const char *name) +dumb_ptr<npc_data> npc_name2id(NpcName name) { return npcname_db.get(name); } @@ -138,7 +139,7 @@ int npc_event_dequeue(dumb_ptr<map_session_data> sd) if (!sd->eventqueuel.empty()) { - if (!pc_addeventtimer(sd, std::chrono::milliseconds(100), sd->eventqueuel.front().c_str())) + if (!pc_addeventtimer(sd, std::chrono::milliseconds(100), sd->eventqueuel.front())) { PRINTF("npc_event_dequeue(): Event timer is full.\n"); return 0; @@ -163,7 +164,7 @@ int npc_delete(dumb_ptr<npc_data> nd) return 0; } -int npc_timer_event(const char *eventname) // Added by RoVeRT +void npc_timer_event(NpcEvent eventname) { struct event_data *ev = ev_db.search(eventname); dumb_ptr<npc_data_script> nd; @@ -171,13 +172,12 @@ int npc_timer_event(const char *eventname) // Added by RoVeRT if ((ev == NULL || (nd = ev->nd) == NULL)) { - PRINTF("npc_event: event not found [%s]\n", eventname); - return 0; + PRINTF("npc_event: event not found [%s]\n", + eventname); + return; } run_script(ScriptPointer(nd->scr.script.get(), ev->pos), nd->bl_id, nd->bl_id); - - return 0; } /*========================================== @@ -185,55 +185,51 @@ int npc_timer_event(const char *eventname) // Added by RoVeRT *------------------------------------------ */ static -void npc_event_doall_sub(const std::string& key, struct event_data *ev, - int *c, const char *name, int rid, int argc, argrec_t *argv) +void npc_event_doall_sub(NpcEvent key, struct event_data *ev, + int *c, ScriptLabel name, int rid, int argc, argrec_t *argv) { - const char *p = key.c_str(); + ScriptLabel p = key.label; nullpo_retv(ev); - if ((p = strchr(p, ':')) && p && strcasecmp(name, p) == 0) + if (name == p) { - run_script_l(ScriptPointer(ev->nd->scr.script.get(), ev->pos), rid, ev->nd->bl_id, argc, - argv); + run_script_l(ScriptPointer(ev->nd->scr.script.get(), ev->pos), rid, ev->nd->bl_id, + argc, argv); (*c)++; } } -int npc_event_doall_l(const char *name, int rid, int argc, argrec_t *args) +int npc_event_doall_l(ScriptLabel name, int rid, int argc, argrec_t *args) { int c = 0; - char buf[64] = "::"; - strzcpy(buf + 2, name, 62); for (auto& pair : ev_db) - npc_event_doall_sub(pair.first, &pair.second, &c, buf, rid, argc, args); + npc_event_doall_sub(pair.first, &pair.second, &c, name, rid, argc, args); return c; } static -void npc_event_do_sub(const std::string& key, struct event_data *ev, - int *c, const char *name, int rid, int argc, argrec_t *argv) +void npc_event_do_sub(NpcEvent key, struct event_data *ev, + int *c, NpcEvent name, int rid, int argc, argrec_t *argv) { - const char *p = key.c_str(); - nullpo_retv(ev); - if (p && strcasecmp(name, p) == 0) + if (name == key) { - run_script_l(ScriptPointer(ev->nd->scr.script.get(), ev->pos), rid, ev->nd->bl_id, argc, - argv); + run_script_l(ScriptPointer(ev->nd->scr.script.get(), ev->pos), rid, ev->nd->bl_id, + argc, argv); (*c)++; } } -int npc_event_do_l(const char *name, int rid, int argc, argrec_t *args) +int npc_event_do_l(NpcEvent name, int rid, int argc, argrec_t *args) { int c = 0; - if (*name == ':' && name[1] == ':') + if (!name.npc) { - return npc_event_doall_l(name + 2, rid, argc, args); + return npc_event_doall_l(name.label, rid, argc, args); } for (auto& pair : ev_db) @@ -250,25 +246,23 @@ void npc_event_do_clock(TimerData *, tick_t) { struct tm t = TimeT::now(); + ScriptLabel buf; if (t.tm_min != ev_tm_b.tm_min) { - std::string buf; - buf = STRPRINTF("OnMinute%02d", t.tm_min); - npc_event_doall(buf.c_str()); - buf = STRPRINTF("OnClock%02d%02d", t.tm_hour, t.tm_min); - npc_event_doall(buf.c_str()); + SNPRINTF(buf, 24, "OnMinute%02d", t.tm_min); + npc_event_doall(buf); + SNPRINTF(buf, 24, "OnClock%02d%02d", t.tm_hour, t.tm_min); + npc_event_doall(buf); } if (t.tm_hour != ev_tm_b.tm_hour) { - std::string buf; - buf = STRPRINTF("OnHour%02d", t.tm_hour); - npc_event_doall(buf.c_str()); + SNPRINTF(buf, 24, "OnHour%02d", t.tm_hour); + npc_event_doall(buf); } if (t.tm_mday != ev_tm_b.tm_mday) { - std::string buf; - buf = STRPRINTF("OnDay%02d%02d", t.tm_mon + 1, t.tm_mday); - npc_event_doall(buf.c_str()); + SNPRINTF(buf, 24, "OnDay%02d%02d", t.tm_mon + 1, t.tm_mday); + npc_event_doall(buf); } ev_tm_b = t; } @@ -279,7 +273,7 @@ void npc_event_do_clock(TimerData *, tick_t) */ int npc_event_do_oninit(void) { - int c = npc_event_doall("OnInit"); + int c = npc_event_doall(stringish<ScriptLabel>("OnInit")); PRINTF("npc: OnInit Event done. (%d npc)\n", c); Timer(gettick() + std::chrono::milliseconds(100), @@ -414,41 +408,34 @@ void npc_settimerevent_tick(dumb_ptr<npc_data_script> nd, interval_t newtimer) * イベント型のNPC処理 *------------------------------------------ */ -int npc_event(dumb_ptr<map_session_data> sd, const char *eventname, - int mob_kill) +int npc_event(dumb_ptr<map_session_data> sd, NpcEvent eventname, + int mob_kill) { struct event_data *ev = ev_db.search(eventname); dumb_ptr<npc_data_script> nd; int xs, ys; - char mobevent[100]; if (sd == NULL) { PRINTF("npc_event nullpo?\n"); } - if (ev == NULL && eventname - && strcmp(((eventname) + strlen(eventname) - 9), "::OnTouch") == 0) + if (ev == NULL && eventname.label == stringish<ScriptLabel>("OnTouch")) return 1; if (ev == NULL || (nd = ev->nd) == NULL) { - if (mob_kill && (ev == NULL || (nd = ev->nd) == NULL)) + if (mob_kill) { - strcpy(mobevent, eventname); - strcat(mobevent, "::OnMyMobDead"); - ev = ev_db.search(mobevent); - if (ev == NULL || (nd = ev->nd) == NULL) { - if (strncasecmp(eventname, "GM_MONSTER", 10) != 0) - PRINTF("npc_event: event not found [%s]\n", mobevent); return 0; } } else { if (battle_config.error_log) - PRINTF("npc_event: event not found [%s]\n", eventname); + PRINTF("npc_event: event not found [%s]\n", + eventname); return 0; } } @@ -485,22 +472,19 @@ int npc_event(dumb_ptr<map_session_data> sd, const char *eventname, } static -void npc_command_sub(const std::string& key, struct event_data *ev, const char *npcname, const char *command) +void npc_command_sub(NpcEvent key, struct event_data *ev, NpcName npcname, XString command) { - const char *p = key.c_str(); - char temp[100]; - - if (strcmp(ev->nd->name, npcname) == 0 && (p = strchr(p, ':')) && p - && strncasecmp("::OnCommand", p, 10) == 0) + if (ev->nd->name == npcname + && key.label.startswith("OnCommand")) { - sscanf(&p[11], "%s", temp); + XString temp = key.label.xslice_t(9); - if (strcmp(command, temp) == 0) + if (command == temp) run_script(ScriptPointer(ev->nd->scr.script.get(), ev->pos), 0, ev->nd->bl_id); } } -int npc_command(dumb_ptr<map_session_data>, const char *npcname, const char *command) +int npc_command(dumb_ptr<map_session_data>, NpcName npcname, XString command) { for (auto& pair : ev_db) npc_command_sub(pair.first, &pair.second, npcname, command); @@ -575,14 +559,14 @@ int npc_touch_areanpc(dumb_ptr<map_session_data> sd, map_local *m, int x, int y) break; case NpcSubtype::SCRIPT: { - char aname[50] {}; - strzcpy(aname, m->npc[i]->name, 24); + NpcEvent aname; + aname.npc = m->npc[i]->name; + aname.label = stringish<ScriptLabel>("OnTouch"); if (sd->areanpc_id == m->npc[i]->bl_id) return 1; sd->areanpc_id = m->npc[i]->bl_id; - strcat(aname, "::OnTouch"); if (npc_event(sd, aname, 0) > 0) npc_click(sd, m->npc[i]->bl_id); break; @@ -658,9 +642,9 @@ int npc_click(dumb_ptr<map_session_data> sd, int id) sd->npc_pos = run_script(ScriptPointer(nd->as_script()->scr.script.get(), 0), sd->bl_id, id); break; case NpcSubtype::MESSAGE: - if (!nd->as_message()->message.empty()) + if (nd->as_message()->message) { - clif_scriptmes(sd, id, nd->as_message()->message.c_str()); + clif_scriptmes(sd, id, nd->as_message()->message); clif_scriptclose(sd, id); } break; @@ -893,9 +877,9 @@ void npc_clearsrcfile(void) * 読み込むnpcファイルの追加 *------------------------------------------ */ -void npc_addsrcfile(const char *name) +void npc_addsrcfile(FString name) { - if (strcasecmp(name, "clear") == 0) + if (name == "clear") { npc_clearsrcfile(); return; @@ -908,9 +892,9 @@ void npc_addsrcfile(const char *name) * 読み込むnpcファイルの削除 *------------------------------------------ */ -void npc_delsrcfile(const char *name) +void npc_delsrcfile(FString name) { - if (strcasecmp(name, "all") == 0) + if (name == "all") { npc_clearsrcfile(); return; @@ -930,17 +914,15 @@ void npc_delsrcfile(const char *name) * warp行解析 *------------------------------------------ */ -int npc_parse_warp(const char *w1, const char *, const char *w3, const char *w4) +int npc_parse_warp(XString w1, XString, NpcName w3, XString w4) { int x, y, xs, ys, to_x, to_y; int i, j; - char mapname[24], to_mapname[24]; + MapName mapname, to_mapname; dumb_ptr<npc_data_warp> nd; - // 引数の個数チェック - if (sscanf(w1, "%[^,],%d,%d", mapname, &x, &y) != 3 || - sscanf(w4, "%d,%d,%[^,],%d,%d", &xs, &ys, to_mapname, &to_x, - &to_y) != 5) + 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); return 1; @@ -958,8 +940,7 @@ int npc_parse_warp(const char *w1, const char *, const char *w3, const char *w4) nd->bl_y = y; nd->dir = DIR::S; nd->flag = 0; - strzcpy(nd->name, w3, 24); - strzcpy(nd->exname, w3, 24); + nd->name = w3; if (!battle_config.warp_point_debug) nd->npc_class = WARP_CLASS; @@ -970,7 +951,7 @@ int npc_parse_warp(const char *w1, const char *, const char *w3, const char *w4) nd->opt1 = Opt1::ZERO; nd->opt2 = Opt2::ZERO; nd->opt3 = Opt3::ZERO; - strzcpy(nd->warp.name, to_mapname, 16); + nd->warp.name = to_mapname; xs += 2; ys += 2; nd->warp.x = to_x; @@ -1004,24 +985,51 @@ int npc_parse_warp(const char *w1, const char *, const char *w3, const char *w4) return 0; } +static +bool extract(XString xs, npc_item_list *itv) +{ + XString name_or_id; + 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) + goto return_true; + + id = itemdb_searchname(stringish<ItemName>(name_or_id.rstrip())); + if (id == NULL) + return false; + itv->nameid = id->nameid; + goto return_true; + +return_true: + if (itv->value < 0) + { + if (id == NULL) + id = itemdb_search(itv->nameid); + itv->value = id->value_buy * abs(itv->value); + } + return true; +} + /*========================================== * shop行解析 *------------------------------------------ */ static -int npc_parse_shop(char *w1, char *, char *w3, char *w4) +int npc_parse_shop(XString w1, XString, NpcName w3, ZString w4a) { - char *p; int x, y; DIR dir; - char mapname[24]; + MapName mapname; dumb_ptr<npc_data_shop> nd; + ZString::iterator w4comma; + int npc_class; - // 引数の個数チェック - int dir_; // TODO use SSCANF or extract - if (sscanf(w1, "%[^,],%d,%d,%d", mapname, &x, &y, &dir_) != 4 + int dir_; // TODO use enum directly in extract + if (!extract(w1, record<','>(&mapname, &x, &y, &dir_)) || dir_ < 0 || dir_ >= 8 - || strchr(w4, ',') == NULL) + || (w4comma = std::find(w4a.begin(), w4a.end(), ',')) == w4a.end() + || !extract(w4a.xislice_h(w4comma), &npc_class)) { PRINTF("bad shop line : %s\n", w3); return 1; @@ -1030,44 +1038,15 @@ int npc_parse_shop(char *w1, char *, char *w3, char *w4) map_local *m = map_mapname2mapid(mapname); nd.new_(); - p = strchr(w4, ','); + ZString w4b = w4a.xislice_t(w4comma + 1); - while (p) + if (!extract(w4b, vrec<','>(&nd->shop_items))) { - int nameid, value; - char name[24]; - struct item_data *id = NULL; - p++; - if (sscanf(p, "%d:%d", &nameid, &value) == 2) - { - } - else if (sscanf(p, "%s :%d", name, &value) == 2) - { - id = itemdb_searchname(name); - if (id == NULL) - nameid = -1; - else - nameid = id->nameid; - } - else - break; - - if (nameid > 0) - { - npc_item_list sh_it; - sh_it.nameid = nameid; - if (value < 0) - { - if (id == NULL) - id = itemdb_search(nameid); - value = id->value_buy * abs(value); - - } - sh_it.value = value; - nd->shop_items.push_back(sh_it); - } - p = strchr(p, ','); + PRINTF("bad shop items : %s\n", w3); + PRINTF(" somewhere --> %s\n", w4b); + nd->shop_items.clear(); } + if (nd->shop_items.empty()) { nd.delete_(); @@ -1081,15 +1060,14 @@ int npc_parse_shop(char *w1, char *, char *w3, char *w4) nd->bl_id = npc_get_new_npc_id(); nd->dir = dir; nd->flag = 0; - strzcpy(nd->name, w3, 24); - nd->npc_class = atoi(w4); + nd->name = w3; + nd->npc_class = npc_class; nd->speed = std::chrono::milliseconds(200); nd->option = Option::ZERO; nd->opt1 = Opt1::ZERO; nd->opt2 = Opt2::ZERO; nd->opt3 = Opt3::ZERO; - //PRINTF("shop npc %s %d read done\n",mapname,nd->bl_id); npc_shop++; nd->bl_type = BL::NPC; nd->npc_subtype = NpcSubtype::SHOP; @@ -1106,12 +1084,12 @@ int npc_parse_shop(char *w1, char *, char *w3, char *w4) *------------------------------------------ */ static -void npc_convertlabel_db(const std::string& lname, int pos, dumb_ptr<npc_data_script> nd) +void npc_convertlabel_db(ScriptLabel lname, int pos, dumb_ptr<npc_data_script> nd) { nullpo_retv(nd); struct npc_label_list eln {}; - strzcpy(eln.name, lname.c_str(), sizeof(eln.name)); + eln.name = lname; eln.pos = pos; nd->scr.label_listv.push_back(std::move(eln)); } @@ -1121,20 +1099,19 @@ void npc_convertlabel_db(const std::string& lname, int pos, dumb_ptr<npc_data_sc *------------------------------------------ */ static -int npc_parse_script(char *w1, char *w2, char *w3, char *w4, - const char *first_line, FILE * fp, int *lines) +int npc_parse_script(XString w1, XString w2, NpcName w3, ZString w4, + XString first_line, FILE *fp, int *lines) { int x, y; DIR dir = DIR::S; map_local *m; int xs = 0, ys = 0, npc_class = 0; // [Valaris] thanks to fov - char mapname[24]; + MapName mapname; std::unique_ptr<const ScriptBuffer> script = NULL; dumb_ptr<npc_data_script> nd; int evflag = 0; - char *p; - if (strcmp(w1, "-") == 0) + if (w1 == "-") { x = 0; y = 0; @@ -1142,11 +1119,10 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, } else { - // 引数の個数チェック - int dir_; // TODO use SSCANF or extract - if (sscanf(w1, "%[^,],%d,%d,%d", mapname, &x, &y, &dir_) != 4 + int dir_; // TODO use enum directly in extract + if (!extract(w1, record<','>(&mapname, &x, &y, &dir_)) || dir_ < 0 || dir_ >= 8 - || (strcmp(w2, "script") == 0 && strchr(w4, ',') == NULL)) + || (w2 == "script" && !w4.contains(','))) { PRINTF("bad script line : %s\n", w3); return 1; @@ -1155,29 +1131,33 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, m = map_mapname2mapid(mapname); } - if (strcmp(w2, "script") == 0) + if (w2 == "script") { // may be empty - std::string srcbuf = strchrnul(first_line, '{'); + MString srcbuf; + srcbuf += first_line.xislice_t(std::find(first_line.begin(), first_line.end(), '{')); // Note: it was a bug that this was missing. I think. int startline = *lines; - while (1) + // while (!srcbuf.rstrip().endswith('}')) + while (true) { - size_t i = srcbuf.find_last_not_of(" \t\n\r\f\v"); - if (i != std::string::npos && srcbuf[i] == '}') + auto it = std::find_if_not(srcbuf.rbegin(), srcbuf.rend(), [](char c){ return c == ' ' || c == '\n'; }); + if (it != srcbuf.rend() && *it == '}') break; - char line[1024]; - if (!fgets(line, 1020, fp)) + + char line_[1024]; + if (!fgets(line_, 1020, fp)) // eof break; (*lines)++; if (feof(fp)) break; - if (srcbuf.empty()) + ZString line(ZString::really_construct_from_a_pointer, line_, nullptr); + if (!srcbuf) { // may be a no-op - srcbuf = strchrnul(line, '{'); + srcbuf += line.xislice_t(std::find(line.begin(), line.end(), '{')); // safe to execute more than once // But will usually only happen once startline = *lines; @@ -1185,7 +1165,7 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, else srcbuf += line; } - script = parse_script(srcbuf.c_str(), startline); + script = parse_script(FString(srcbuf), startline); if (script == NULL) // script parse error? return 1; @@ -1200,13 +1180,9 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, if (m == nullptr) { - // スクリプトコピー用のダミーNPC } - else if (sscanf(w4, "%d,%d,%d", &npc_class, &xs, &ys) == 3) + else if (extract(w4, record<','>(&npc_class, &xs, &ys))) { - // 接触型NPC - int i, j; - if (xs >= 0) xs = xs * 2 + 1; if (ys >= 0) @@ -1215,9 +1191,9 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, if (npc_class >= 0) { - for (i = 0; i < ys; i++) + for (int i = 0; i < ys; i++) { - for (j = 0; j < xs; j++) + for (int j = 0; j < xs; j++) { int x_lo = x - xs / 2; int y_lo = y - ys / 2; @@ -1235,32 +1211,24 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, nd->scr.ys = ys; } else - { // クリック型NPC - npc_class = atoi(w4); + { + npc_class = atoi(w4.c_str()); nd->scr.xs = 0; nd->scr.ys = 0; } if (npc_class < 0 && m != nullptr) - { // イベント型NPC + { evflag = 1; } - while ((p = strchr(w3, ':'))) - { - if (p[1] == ':') - break; - } - if (p) + if (w3.contains(':')) { - *p = 0; - strzcpy(nd->name, w3, 24); - strzcpy(nd->exname, p + 2, 24); + assert(false && "feature removed"); + abort(); } - else { - strzcpy(nd->name, w3, 24); - strzcpy(nd->exname, w3, 24); + nd->name = w3; } nd->bl_prev = nd->bl_next = NULL; @@ -1288,37 +1256,36 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, map_addblock(nd); if (evflag) - { // イベント型 + { struct event_data ev {}; ev.nd = nd; ev.pos = 0; - ev_db.insert(nd->exname, ev); + NpcEvent npcev; + npcev.npc = nd->name; + npcev.label = ScriptLabel(); + ev_db.insert(npcev, ev); } else clif_spawnnpc(nd); } - npcname_db.put(nd->exname, nd); + npcname_db.put(nd->name, nd); for (auto& pair : scriptlabel_db) npc_convertlabel_db(pair.first, pair.second, nd); for (npc_label_list& el : nd->scr.label_listv) { - char *lname = el.name; + ScriptLabel lname = el.name; int pos = el.pos; - if ((lname[0] == 'O' || lname[0] == 'o') - && (lname[1] == 'N' || lname[1] == 'n')) + if (lname.startswith("On")) { - if (strlen(lname) > 24) - { - PRINTF("npc_parse_script: label name error !\n"); - exit(1); - } struct event_data ev {}; ev.nd = nd; ev.pos = pos; - std::string buf = STRPRINTF("%s::%s", nd->exname, lname); + NpcEvent buf; + buf.npc = nd->name; + buf.label = lname; ev_db.insert(buf, ev); } } @@ -1327,10 +1294,10 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, // ラベルデータからタイマーイベント取り込み for (npc_label_list& el : nd->scr.label_listv) { - int t_ = 0, n = 0; - char *lname = el.name; + int t_ = 0; + ScriptLabel lname = el.name; int pos = el.pos; - if (sscanf(lname, "OnTimer%d%n", &t_, &n) == 1 && lname[n] == '\0') + if (lname.startswith("OnTimer") && extract(lname.xslice_t(7), &t_)) { interval_t t = static_cast<interval_t>(t_); @@ -1360,40 +1327,41 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, *------------------------------------------ */ static -int npc_parse_function(char *, char *, char *w3, char *, - char *first_line, FILE * fp, int *lines) +int npc_parse_function(XString, XString, XString w3, ZString, + XString first_line, FILE *fp, int *lines) { - std::string srcbuf = strchrnul(first_line, '{'); + MString srcbuf; + srcbuf += first_line.xislice_t(std::find(first_line.begin(), first_line.end(), '{')); int startline = *lines; - while (1) + while (true) { - size_t i = srcbuf.find_last_not_of(" \t\n\r\f\v"); - if (i != std::string::npos && srcbuf[i] == '}') + auto it = std::find_if_not(srcbuf.rbegin(), srcbuf.rend(), [](char c){ return c == ' ' || c == '\n'; }); + if (it != srcbuf.rend() && *it == '}') break; - char line[1024]; - if (!fgets(line, 1020, fp)) + char line_[1024]; + if (!fgets(line_, 1020, fp)) break; (*lines)++; if (feof(fp)) break; - if (srcbuf.empty()) + ZString line(ZString::really_construct_from_a_pointer, line_, nullptr); + if (!srcbuf) { - srcbuf = strchrnul(line, '{'); + srcbuf += line.xislice_t(std::find(line.begin(), line.end(), '{')); startline = *lines; } else srcbuf += line; } - std::unique_ptr<const ScriptBuffer> script = parse_script(srcbuf.c_str(), startline); + std::unique_ptr<const ScriptBuffer> script = parse_script(FString(srcbuf), startline); if (script == NULL) { // script parse error? return 1; } - std::string p = w3; - userfunc_db.put(p, std::move(script)); + userfunc_db.put(w3, std::move(script)); return 0; } @@ -1403,20 +1371,18 @@ int npc_parse_function(char *, char *, char *w3, char *, *------------------------------------------ */ static -int npc_parse_mob(const char *w1, const char *, const char *w3, const char *w4) +int npc_parse_mob(XString w1, XString, MobName w3, ZString w4) { int x, y, xs, ys, mob_class, num; int i; - char mapname[24]; - char eventname[24] = ""; + MapName mapname; + NpcEvent eventname; dumb_ptr<mob_data> md; xs = ys = 0; int delay1_ = 0, delay2_ = 0; - // 引数の個数チェック - if (sscanf(w1, "%[^,],%d,%d,%d,%d", mapname, &x, &y, &xs, &ys) < 3 || - sscanf(w4, "%d,%d,%d,%d,%s", &mob_class, &num, &delay1_, &delay2_, - eventname) < 2) + 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); return 1; @@ -1441,12 +1407,12 @@ int npc_parse_mob(const char *w1, const char *, const char *w3, const char *w4) md->bl_m = m; md->bl_x = x; md->bl_y = y; - if (strcmp(w3, "--en--") == 0) - strzcpy(md->name, mob_db[mob_class].name, 24); - else if (strcmp(w3, "--ja--") == 0) - strzcpy(md->name, mob_db[mob_class].jname, 24); + if (w3 == ENGLISH_NAME) + md->name = mob_db[mob_class].name; + else if (w3 == JAPANESE_NAME) + md->name = mob_db[mob_class].jname; else - strzcpy(md->name, w3, 24); + md->name = w3; md->n = i; md->mob_class = mob_class; @@ -1466,10 +1432,7 @@ int npc_parse_mob(const char *w1, const char *, const char *w3, const char *w4) md->lootitemv.clear(); - if (strlen(eventname) >= 4) - strzcpy(md->npc_event, eventname, 24); - else - strzcpy(md->npc_event, "", 24); + md->npc_event = eventname; md->bl_type = BL::MOB; map_addiddb(md); @@ -1487,123 +1450,121 @@ int npc_parse_mob(const char *w1, const char *, const char *w3, const char *w4) *------------------------------------------ */ static -int npc_parse_mapflag(char *w1, char *, char *w3, char *w4) +int npc_parse_mapflag(XString w1, XString, XString w3, ZString w4) { - char mapname[24], savemap[16]; + MapName mapname, savemap; int savex, savey; - // 引数の個数チェック -// if ( sscanf(w1,"%[^,],%d,%d,%d",mapname,&x,&y,&dir) != 4 ) - if (sscanf(w1, "%[^,]", mapname) != 1) + mapname = stringish<MapName>(w1); + if (!mapname) return 1; map_local *m = map_mapname2mapid(mapname); if (m == nullptr) return 1; -//マップフラグ - if (strcasecmp(w3, "nosave") == 0) + if (w3 == "nosave") { - if (strcmp(w4, "SavePoint") == 0) + if (w4 == "SavePoint") { - strzcpy(m->save.map_, "SavePoint", 16); + m->save.map_ = stringish<MapName>("SavePoint"); m->save.x = -1; m->save.y = -1; } - else if (sscanf(w4, "%[^,],%d,%d", savemap, &savex, &savey) == 3) + else if (extract(w4, record<','>(&savemap, &savex, &savey))) { - strzcpy(m->save.map_, savemap, 16); + m->save.map_ = savemap; m->save.x = savex; m->save.y = savey; } m->flag.nosave = 1; } - else if (strcasecmp(w3, "nomemo") == 0) + else if (w3 == "nomemo") { m->flag.nomemo = 1; } - else if (strcasecmp(w3, "noteleport") == 0) + else if (w3 == "noteleport") { m->flag.noteleport = 1; } - else if (strcasecmp(w3, "nowarp") == 0) + else if (w3 == "nowarp") { m->flag.nowarp = 1; } - else if (strcasecmp(w3, "nowarpto") == 0) + else if (w3 == "nowarpto") { m->flag.nowarpto = 1; } - else if (strcasecmp(w3, "noreturn") == 0) + else if (w3 == "noreturn") { m->flag.noreturn = 1; } - else if (strcasecmp(w3, "monster_noteleport") == 0) + else if (w3 == "monster_noteleport") { m->flag.monster_noteleport = 1; } - else if (strcasecmp(w3, "nobranch") == 0) + else if (w3 == "nobranch") { m->flag.nobranch = 1; } - else if (strcasecmp(w3, "nopenalty") == 0) + else if (w3 == "nopenalty") { m->flag.nopenalty = 1; } - else if (strcasecmp(w3, "pvp") == 0) + else if (w3 == "pvp") { m->flag.pvp = 1; } - else if (strcasecmp(w3, "pvp_noparty") == 0) + else if (w3 == "pvp_noparty") { m->flag.pvp_noparty = 1; } - else if (strcasecmp(w3, "pvp_nocalcrank") == 0) + else if (w3 == "pvp_nocalcrank") { m->flag.pvp_nocalcrank = 1; } - else if (strcasecmp(w3, "nozenypenalty") == 0) + else if (w3 == "nozenypenalty") { m->flag.nozenypenalty = 1; } - else if (strcasecmp(w3, "notrade") == 0) + else if (w3 == "notrade") { m->flag.notrade = 1; } - else if (battle_config.pk_mode && strcasecmp(w3, "nopvp") == 0) + else if (battle_config.pk_mode && w3 == "nopvp") { // nopvp for pk mode [Valaris] m->flag.nopvp = 1; m->flag.pvp = 0; } - else if (strcasecmp(w3, "noicewall") == 0) + else if (w3 == "noicewall") { // noicewall [Valaris] m->flag.noicewall = 1; } - else if (strcasecmp(w3, "snow") == 0) + else if (w3 == "snow") { // snow [Valaris] m->flag.snow = 1; } - else if (strcasecmp(w3, "fog") == 0) + else if (w3 == "fog") { // fog [Valaris] m->flag.fog = 1; } - else if (strcasecmp(w3, "sakura") == 0) + else if (w3 == "sakura") { // sakura [Valaris] m->flag.sakura = 1; } - else if (strcasecmp(w3, "leaves") == 0) + else if (w3 == "leaves") { // leaves [Valaris] m->flag.leaves = 1; } - else if (strcasecmp(w3, "rain") == 0) + else if (w3 == "rain") { // rain [Valaris] m->flag.rain = 1; } - else if (strcasecmp(w3, "no_player_drops") == 0) + else if (w3 == "no_player_drops") { // no player drops [Jaxad0127] m->flag.no_player_drops = 1; } - else if (strcasecmp(w3, "town") == 0) + else if (w3 == "town") { // town/safe zone [remoitnane] m->flag.town = 1; } @@ -1612,7 +1573,7 @@ int npc_parse_mapflag(char *w1, char *, char *w3, char *w4) } dumb_ptr<npc_data> npc_spawn_text(map_local *m, int x, int y, - int npc_class, const char *name, const char *message) + int npc_class, NpcName name, FString message) { dumb_ptr<npc_data_message> retval; retval.new_(); @@ -1623,8 +1584,7 @@ dumb_ptr<npc_data> npc_spawn_text(map_local *m, int x, int y, retval->bl_type = BL::NPC; retval->npc_subtype = NpcSubtype::MESSAGE; - strzcpy(retval->name, name, 24); - strzcpy(retval->exname, name, 24); + retval->name = name; if (message) retval->message = message; @@ -1656,7 +1616,7 @@ void npc_free_internal(dumb_ptr<npc_data> nd_) else if (nd_->npc_subtype == NpcSubtype::MESSAGE) { dumb_ptr<npc_data_message> nd = nd_->as_message(); - nd->message.clear(); + nd->message = FString(); } nd_.delete_(); } @@ -1699,100 +1659,91 @@ int do_init_npc(void) for (; !npc_srcs.empty(); npc_srcs.pop_front()) { - std::string& nsl = npc_srcs.front(); - FILE *fp = fopen_(nsl.c_str(), "r"); + FString nsl = npc_srcs.front(); + FILE *fp = fopen(nsl.c_str(), "r"); if (fp == NULL) { PRINTF("file not found : %s\n", nsl); exit(1); } int lines = 0; - char line[1024]; - while (fgets(line, 1020, fp)) + char line_[1024]; + while (fgets(line_, 1020, fp)) { - char w1[1024], w2[1024], w3[1024], w4[1024], mapname[1024]; - int i, j, w4pos, count; + // because it's still fgets + line_[strlen(line_) - 1] = '\0'; + ZString zline(ZString::really_construct_from_a_pointer, line_, nullptr); + XString w1, w2, w3, w4x; + ZString w4z; lines++; - if (line[0] == '/' && line[1] == '/') + if (!zline) + continue; + if (zline.startswith("//")) continue; - // 不要なスペースやタブの連続は詰める - for (i = j = 0; line[i]; i++) + + if (!extract(zline, record<'|', 3>(&w1, &w2, &w3, &w4x)) || !w1 || !w2 || !w3) { - if (line[i] == ' ') - { - if (! - ((line[i + 1] - && (isspace(line[i + 1]) || line[i + 1] == ',')) - || (j && line[j - 1] == ','))) - line[j++] = ' '; - } - else if (line[i] == '\t' || line[i] == '|') - { - if (!(j && (line[j - 1] == '\t' || line[j - 1] == '|'))) - line[j++] = '\t'; - } - else - line[j++] = line[i]; + FPRINTF(stderr, "%s:%d: Broken script line: %s\n", nsl, lines, zline); + continue; } - // 最初はタブ区切りでチェックしてみて、ダメならスペース区切りで確認 - if ((count = - sscanf(line, "%[^\t]\t%[^\t]\t%[^\t\r\n]\t%n%[^\t\r\n]", w1, - w2, w3, &w4pos, w4)) < 3 - && (count = - sscanf(line, "%s%s%s%n%s", w1, w2, w3, &w4pos, w4)) < 3) + if (&*w4x.end() == &*zline.end()) { - continue; + w4z = zline.xrslice_t(w4x.size()); } - // マップの存在確認 - if (strcmp(w1, "-") != 0 && strcasecmp(w1, "function") != 0) + assert(bool(w4x) == bool(w4z)); + + if (w1 != "-" && w1 != "function") { - sscanf(w1, "%[^,]", mapname); + auto comma = std::find(w1.begin(), w1.end(), ','); + MapName mapname = stringish<MapName>(w1.xislice_h(comma)); map_local *m = map_mapname2mapid(mapname); - if (strlen(mapname) > 16 || m == nullptr) + if (m == nullptr) { // "mapname" is not assigned to this server + FPRINTF(stderr, "%s:%d: Map not found: %s\n", nsl, lines, mapname); continue; } } - if (strcasecmp(w2, "warp") == 0 && count > 3) + if (w2 == "warp") { - npc_parse_warp(w1, w2, w3, w4); + NpcName npcname = stringish<NpcName>(w3); + npc_parse_warp(w1, w2, npcname, w4z); } - else if (strcasecmp(w2, "shop") == 0 && count > 3) + else if (w2 == "shop") { - npc_parse_shop(w1, w2, w3, w4); + NpcName npcname = stringish<NpcName>(w3); + npc_parse_shop(w1, w2, npcname, w4z); } - else if (strcasecmp(w2, "script") == 0 && count > 3) + else if (w2 == "script") { - if (strcasecmp(w1, "function") == 0) + if (w1 == "function") { - npc_parse_function(w1, w2, w3, w4, line + w4pos, fp, - &lines); + npc_parse_function(w1, w2, w3, w4z, + w4x, fp, &lines); } else { - npc_parse_script(w1, w2, w3, w4, line + w4pos, fp, - &lines); + NpcName npcname = stringish<NpcName>(w3); + npc_parse_script(w1, w2, npcname, w4z, + w4x, fp, &lines); } } - else if ((i = - 0, sscanf(w2, "duplicate%n", &i), (i > 0 - && w2[i] == '(')) - && count > 3) + else if (w2 == "monster") { - npc_parse_script(w1, w2, w3, w4, line + w4pos, fp, &lines); + MobName mobname = stringish<MobName>(w3); + npc_parse_mob(w1, w2, mobname, w4z); } - else if (strcasecmp(w2, "monster") == 0 && count > 3) + else if (w2 == "mapflag") { - npc_parse_mob(w1, w2, w3, w4); + npc_parse_mapflag(w1, w2, w3, w4z); } - else if (strcasecmp(w2, "mapflag") == 0 && count >= 3) + else { - npc_parse_mapflag(w1, w2, w3, w4); + PRINTF("odd script line: %s\n", zline); } } - fclose_(fp); + fclose(fp); PRINTF("\rLoading NPCs [%d]: %-54s", npc_id - START_NPC_NUM, nsl); fflush(stdout); |