From 3164dc756547766c067799d43abd8e1c831f44dd Mon Sep 17 00:00:00 2001 From: Emistry Haoyan Date: Wed, 15 May 2019 01:36:14 +0800 Subject: [PATCH] Add *duplicate/remove npc script command - `npc_duplicate()` duplicate any existing duplicated NPC. - `npc_duplicate_remove()` will remove any existing NPC other than source NPC. --- doc/script_commands.txt | 14 ++++++ src/map/script.c | 96 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 516454365c2..d3ae30c1006 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -6828,6 +6828,20 @@ NPCs talking while hidden then revealing... you can wonder around =P). --------------------------------------- +*npc_duplicate("", "", "", "", , , {, {, , }}); + +Duplicate any existing NPC based on . +Return 1 on success, 0 if failed. + +--------------------------------------- + +*npc_duplicate_remove({""}); + +Remove any duplicated NPC from source NPC or depend on if specified. +If are source NPC, it will only remove all duplicated NPC. + +--------------------------------------- + *doevent("::") This command will start a new execution thread in a specified NPC object diff --git a/src/map/script.c b/src/map/script.c index 5843ac29299..56b796afdcd 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -12183,6 +12183,100 @@ static BUILDIN(hideonnpc) return true; } +static BUILDIN(npc_duplicate) +{ + int txs = -1, tys = -1; + + if (script_hasdata(st, 10)) + txs = (script_getnum(st, 10) < -1) ? -1 : script_getnum(st, 10); + if (script_hasdata(st, 11)) + tys = (script_getnum(st, 11) < -1) ? -1 : script_getnum(st, 10); + + if (txs == -1 && tys != -1) + txs = 0; + if (txs != -1 && tys == -1) + tys = 0; + + const char *npc_name = script_getstr(st, 2); + const char *dup_name = script_getstr(st, 3); + const char *dup_hidden_name = script_getstr(st, 4); + + char targetname[NAME_LENGTH] = ""; + strcat(targetname, dup_name); + if (strcmp(dup_hidden_name, "") != 0) { + strncat(targetname, "#", 1); + strncat(targetname, dup_hidden_name, strlen(dup_hidden_name)); + } + + if (strlen(dup_name) + strlen(dup_hidden_name) > NAME_LENGTH) { + ShowError("buildin_npc_duplicate: %s is to long (max %d chars).\n", npc_name, NAME_LENGTH); + script_pushint(st, 0); + return false; + } else if (npc->name2id(targetname) != NULL) { + ShowError("buildin_npc_duplicate: NPC named '%s' already exists.\n", targetname, NAME_LENGTH); + script_pushint(st, 0); + return false; + } + + struct npc_data *nd_source = npc->name2id(npc_name); + int tclass_; + if (script_hasdata(st, 9)) + tclass_ = (script_getnum(st, 9) < -1) ? -1 : script_getnum(st, 9); + else + tclass_ = nd_source->class_; + + if (nd_source == NULL) { + ShowError("buildin_npc_duplicate: original npc not found for duplicate. (%s)\n", npc_name); + script_pushint(st, 0); + return false; + } + + const char *tmap = script_getstr(st, 5); + int tmapid = map->mapname2mapid(tmap); + if (tmapid < 0) { + ShowError("buildin_npc_duplicate: target map not found. (%s)\n", tmap); + script_pushint(st, 0); + return false; + } + + int tx = script_getnum(st, 6); + int ty = script_getnum(st, 7); + int tdir = script_getnum(st, 8); + struct npc_data *nd_target = npc->create_npc(nd_source->subtype, tmapid, tx, ty, tdir, tclass_); + + safestrncpy(nd_target->name, targetname, sizeof(nd_target->name)); + safestrncpy(nd_target->exname, targetname, sizeof(nd_target->exname)); + + script_pushint(st, npc->duplicate_sub(nd_target, nd_source, txs, tys, NPO_ONINIT)); + return true; +} + +static BUILDIN(npc_duplicate_remove) +{ + struct npc_data *nd; + + if (script_hasdata(st, 2)) { + nd = npc->name2id(script_getstr(st, 2)); + if (nd == NULL) { + ShowError("buildin_npc_duplicate_remove: Duplicate NPC not found. (%s)\n", script_getstr(st, 2)); + script_pushint(st, 0); + return false; + } + } + else + nd = map->id2nd(st->oid); + + if (nd != NULL) { + if (nd->src_id == 0) //remove all dupicates for this source npc + map->foreachnpc(npc->unload_dup_sub, nd->bl.id); + else // just remove this duplicate + npc->unload(nd, true); + } + + script_pushint(st, 1); + return true; +} + /* Starts a status effect on the target unit or on the attached player. * * sc_start ,,{,,,{}}; @@ -25623,6 +25717,8 @@ static void script_parse_builtin(void) BUILDIN_DEF(disablenpc,"s"), BUILDIN_DEF(hideoffnpc,"s"), BUILDIN_DEF(hideonnpc,"s"), + BUILDIN_DEF(npc_duplicate, "ssssiii???"), + BUILDIN_DEF(npc_duplicate_remove, "?"), BUILDIN_DEF(sc_start,"iii???"), BUILDIN_DEF2(sc_start,"sc_start2","iiii???"), BUILDIN_DEF2(sc_start,"sc_start4","iiiiii???"),