From 9b4bfd9a667133563219cb44a4f50ea663bcec2e 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. Edited by Jesusalva for ease of use in Moubootaur Legends context See also https://github.com/HerculesWS/Hercules/pull/2473 --- src/emap/init.c | 2 + src/emap/script_buildins.c | 163 +++++++++++++++++++++++++++++++++++++++++++++ src/emap/script_buildins.h | 2 + 3 files changed, 167 insertions(+) diff --git a/src/emap/init.c b/src/emap/init.c index ccbe8b0..a9f8686 100644 --- a/src/emap/init.c +++ b/src/emap/init.c @@ -248,6 +248,8 @@ HPExport void plugin_init (void) addScriptCommand("getskillname", "i", getskillname); addScriptCommand("bgnew", "siiss", bgnew); addScriptCommand("bgjoin", "isii?", bgjoin); + addScriptCommand("npc_duplicate", "sssii????", npc_duplicate); + addScriptCommand("npc_duplicate_remove", "?", npc_duplicate_remove); addScriptCommand("apicall", "is", apicall); addScriptCommand("apiasync", "ss", apiasync); diff --git a/src/emap/script_buildins.c b/src/emap/script_buildins.c index b01d100..9acbf7c 100644 --- a/src/emap/script_buildins.c +++ b/src/emap/script_buildins.c @@ -3699,6 +3699,169 @@ BUILDIN(bgjoin) return true; } +// Constants for the next function (from db/constants.conf) +#define UNIT_DIR_UNDEFINED -1 +#define UNIT_DIR_MAX 8 +/* + * Create a duplicate of source NPC. + * npc_duplicate("", "", "", , , {, {, , }}); + * Return 1 on success, 0 if failed. + */ +BUILDIN(npc_duplicate) +{ + int txs = -1; + int tys = -1; + int tdir = 0; + + if (script_hasdata(st, 9)) + txs = script_getnum(st, 9); + if (script_hasdata(st, 10)) + tys = script_getnum(st, 10); + + if (txs < -1) + txs = -1; + if (tys < -1) + tys = -1; + + if (txs == -1 && tys != -1) + txs = 0; + if (txs != -1 && tys == -1) + tys = 0; + + const char *targetname = script_getstr(st, 3); + + size_t len_dup = strlen(targetname); + + if (len_dup > NAME_LENGTH - 1) { + ShowError("buildin_npc_duplicate: NPC name '%s' is too long (max %d chars).\n", targetname, NAME_LENGTH - 1); + script_pushint(st, 0); + return false; + } + if (strlen(targetname) > NAME_LENGTH) { + ShowError("buildin_npc_duplicate: NPC name '%s' is too long (max %d chars).\n", targetname, 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); + script_pushint(st, 0); + return false; + } + + const char *npc_name = script_getstr(st, 2); + struct npc_data *nd_source = npc->name2id(npc_name); + + if (nd_source == NULL) { + ShowError("buildin_npc_duplicate: Source NPC '%s' not found.\n", npc_name); + script_pushint(st, 0); + return false; + } + + int tclass_ = nd_source->class_; + + if (script_hasdata(st, 7)) + tclass_ = script_getnum(st, 7); + if (tclass_ < -1) + tclass_ = FAKE_NPC; + + ShowDebug("Dupe %s as %s; Class %d\n", npc_name, targetname, tclass_); + if (nd_source->src_id != 0) { + ShowError("buildin_npc_duplicate: Source NPC '%s' is a duplicated NPC of %d.\n", nd_source->name, nd_source->src_id); + script_pushint(st, 0); + return false; + } + + const char *tmap = script_getstr(st, 4); + ShowDebug("Dupe %s in %s as %s; Class %d\n", npc_name, tmap, targetname, tclass_); + int tmapid = map->mapname2mapid(tmap); + if (tmapid < 0) { + ShowError("buildin_npc_duplicate: Target map '%s' not found.\n", tmap); + script_pushint(st, 0); + return false; + } + + if (map->list[tmapid].npc_num >= MAX_NPC_PER_MAP) { + ShowError("buildin_npc_duplicate: Exceeded MAX NPC per map (%d).\n", MAX_NPC_PER_MAP); + return false; + } + + int tx = script_getnum(st, 5); + int ty = script_getnum(st, 6); + if (script_hasdata(st, 8)) + tdir = script_getnum(st, 8); + + ShowDebug("Dir %d at (%d,%d)\n", tdir, tx, ty); +#if 0 + if (tclass_ != FAKE_NPC && tclass_ != HIDDEN_WARP_CLASS) { + if (map->getcell(tmapid, NULL, tx, ty, CELL_CHKNOPASS) > 0) { + ShowError("buildin_npc_duplicate: Invalid NPC Location. %s,%d,%d\n", tmap, tx, ty); + script_pushint(st, 0); + return false; + } + } +#endif + + if (tdir >= UNIT_DIR_MAX) { + ShowWarning("buildin_npc_duplicate: Invalid NPC direction %d. Default to %d.\n", tdir, (tdir % UNIT_DIR_MAX)); + tdir %= UNIT_DIR_MAX; // trim spin-over + } else if (tdir <= UNIT_DIR_UNDEFINED) { + ShowWarning("buildin_npc_duplicate: Invalid NPC direction %d. Default to %d.\n", tdir, 0); + tdir = 0; + } + + struct npc_data *nd_target = npc->create_npc(nd_source->subtype, tmapid, tx, ty, tdir, tclass_); + + if (nd_target == NULL) { + ShowError("buildin_npc_duplicate: Failed to duplicate NPC.\n"); + return false; + } + + safestrncpy(nd_target->name, targetname, sizeof(nd_target->name)); + safestrncpy(nd_target->exname, targetname, sizeof(nd_target->exname)); + + if (npc->duplicate_sub(nd_target, nd_source, txs, tys, NPO_ONINIT) == true) + script_pushint(st, 1); + else + script_pushint(st, 0); + + return true; +} + +/* + * npc_duplicate_remove({""}); + * Return 1 on success, 0 if failed. + */ +BUILDIN(npc_duplicate_remove) +{ + struct npc_data *nd = map->id2nd(st->oid); + + if (script_hasdata(st, 2)) + nd = npc->name2id(script_getstr(st, 2)); + + if (nd == NULL) { + if (script_hasdata(st, 2)) { + ShowError("buildin_npc_duplicate_remove: NPC '%s' not found.\n", script_getstr(st, 2)); + } else { + ShowError("buildin_npc_duplicate_remove: NPC not found.\n"); + } + script_pushint(st, 0); + return false; + } + + if (nd->src_id == 0) { // remove all dupicates for this source npc + npc->unload_duplicates(nd); + } else if (nd != map->id2nd(st->oid)) { // just remove this duplicate NPC + npc->unload(nd, true); + } else { + // Same as "else if (!script_hasdata(st, 2))" + ShowError("buildin_npc_duplicate_remove: Cannot remove yourself.\n"); + script_pushint(st, 0); + return false; + } + + script_pushint(st, 1); + return true; +} + /*========================================== * Sends something over PyLog diff --git a/src/emap/script_buildins.h b/src/emap/script_buildins.h index 29eefe0..3d0fdde 100644 --- a/src/emap/script_buildins.h +++ b/src/emap/script_buildins.h @@ -132,6 +132,8 @@ BUILDIN(resetrng); BUILDIN(getskillname); BUILDIN(bgnew); BUILDIN(bgjoin); +BUILDIN(npc_duplicate); +BUILDIN(npc_duplicate_remove); BUILDIN(apicall); BUILDIN(apiasync); -- cgit v1.2.3-70-g09d2