@@ -12572,6 +12572,155 @@ static BUILDIN(cloakoffnpc)
1257212572 return true;
1257312573}
1257412574
12575+
12576+ /*
12577+ * Create a duplicate of source NPC.
12578+ * npc_duplicate("<source_npc_name>", "<new_npc_name>", "<new_npc_hidden_name>", "<mapname>", <map_x>, <map_y>, <dir>{, <sprite_id>{, <map_xs>, <map_ys>}});
12579+ * Return 1 on success, 0 if failed.
12580+ */
12581+ static BUILDIN(npc_duplicate)
12582+ {
12583+ int txs = -1, tys = -1;
12584+
12585+ if (script_hasdata(st, 10))
12586+ txs = script_getnum(st, 10);
12587+ if (script_hasdata(st, 11))
12588+ tys = script_getnum(st, 11);
12589+
12590+ if (txs < -1)
12591+ txs = -1;
12592+ if (tys < -1)
12593+ tys = -1;
12594+
12595+ if (txs == -1 && tys != -1)
12596+ txs = 0;
12597+ if (txs != -1 && tys == -1)
12598+ tys = 0;
12599+
12600+ const char *dup_name = script_getstr(st, 3);
12601+ const char *dup_hidden_name = script_getstr(st, 4);
12602+
12603+ char targetname[NAME_LENGTH] = "";
12604+ strcat(targetname, dup_name);
12605+
12606+ if (strlen(dup_hidden_name) != 0) {
12607+ strncat(targetname, "#", 1);
12608+ strncat(targetname, dup_hidden_name, strlen(dup_hidden_name));
12609+ }
12610+
12611+ if (strlen(targetname) > NAME_LENGTH) {
12612+ ShowError("buildin_npc_duplicate: NPC name '%s' is to long (max %d chars).\n", targetname, NAME_LENGTH);
12613+ script_pushint(st, 0);
12614+ return false;
12615+ } else if (npc->name2id(targetname) != NULL) {
12616+ ShowError("buildin_npc_duplicate: NPC named '%s' already exists.\n", targetname);
12617+ script_pushint(st, 0);
12618+ return false;
12619+ }
12620+
12621+ const char *npc_name = script_getstr(st, 2);
12622+ struct npc_data *nd_source = npc->name2id(npc_name);
12623+ int tclass_ = nd_source->class_;
12624+
12625+ if (script_hasdata(st, 9))
12626+ tclass_ = script_getnum(st, 9);
12627+ if (tclass_ < -1)
12628+ tclass_ = FAKE_NPC;
12629+
12630+ if (nd_source == NULL) {
12631+ ShowError("buildin_npc_duplicate: Source NPC '%s' not found.\n", npc_name);
12632+ script_pushint(st, 0);
12633+ return false;
12634+ }
12635+
12636+ if (nd_source->src_id != 0) {
12637+ ShowError("buildin_npc_duplicate: Source NPC '%s' is a duplicated NPC.\n", nd_source->name);
12638+ script_pushint(st, 0);
12639+ return false;
12640+ }
12641+
12642+ const char *tmap = script_getstr(st, 5);
12643+ int tmapid = map->mapname2mapid(tmap);
12644+ if (tmapid < 0) {
12645+ ShowError("buildin_npc_duplicate: Target map '%s' not found.\n", tmap);
12646+ script_pushint(st, 0);
12647+ return false;
12648+ }
12649+
12650+ if (map->list[tmapid].npc_num >= MAX_NPC_PER_MAP) {
12651+ ShowError("buildin_npc_duplicate: Exceeded MAX NPC per map (%d).\n", MAX_NPC_PER_MAP);
12652+ return false;
12653+ }
12654+
12655+ int tx = script_getnum(st, 6);
12656+ int ty = script_getnum(st, 7);
12657+ int tdir = script_getnum(st, 8);
12658+
12659+ if (tclass_ != FAKE_NPC && tclass_ != HIDDEN_WARP_CLASS) {
12660+ if (map->getcell(tmapid, NULL, tx, ty, CELL_CHKNOPASS) > 0) {
12661+ ShowError("buildin_npc_duplicate: Invalid NPC Location. %s,%d,%d\n", tmap, tx, ty);
12662+ script_pushint(st, 0);
12663+ return false;
12664+ }
12665+ }
12666+
12667+ if (tdir >= UNIT_DIR_MAX) {
12668+ ShowWarning("buildin_npc_duplicate: Invalid NPC direction %d. Default to %d.\n", tdir, (tdir % UNIT_DIR_MAX));
12669+ tdir %= UNIT_DIR_MAX; // trim spin-over
12670+ }
12671+ else if (tdir <= UNIT_DIR_UNDEFINED) {
12672+ ShowWarning("buildin_npc_duplicate: Invalid NPC direction %d. Default to %d.\n", tdir, UNIT_DIR_SOUTH);
12673+ tdir = UNIT_DIR_SOUTH;
12674+ }
12675+
12676+ struct npc_data *nd_target = npc->create_npc(nd_source->subtype, tmapid, tx, ty, tdir, tclass_);
12677+
12678+ safestrncpy(nd_target->name, targetname, sizeof(nd_target->name));
12679+ safestrncpy(nd_target->exname, targetname, sizeof(nd_target->exname));
12680+
12681+ if (npc->duplicate_sub(nd_target, nd_source, txs, tys, NPO_ONINIT) == true)
12682+ script_pushint(st, 1);
12683+ else
12684+ script_pushint(st, 0);
12685+
12686+ return true;
12687+ }
12688+
12689+ /*
12690+ * npc_duplicate_remove({"<npc_name>", {<flag>}});
12691+ * Return 1 on success, 0 if failed.
12692+ */
12693+ static BUILDIN(npc_duplicate_remove)
12694+ {
12695+ struct npc_data *nd = map->id2nd(st->oid);
12696+
12697+ if (script_hasdata(st, 2))
12698+ nd = npc->name2id(script_getstr(st, 2));
12699+
12700+ if (nd == NULL) {
12701+ if (script_hasdata(st, 2)) {
12702+ ShowError("buildin_npc_duplicate_remove: NPC '%s' not found.\n", script_getstr(st, 2));
12703+ }
12704+ else {
12705+ ShowError("buildin_npc_duplicate_remove: NPC not found.\n");
12706+ }
12707+ script_pushint(st, 0);
12708+ return false;
12709+ }
12710+
12711+ int flag = 1;
12712+ if (script_hasdata(st, 3))
12713+ flag = script_getnum(st, 3);
12714+
12715+ if (nd->src_id == 0) // remove all dupicates for this source npc
12716+ npc->unload_duplicates(nd, (flag != 0));
12717+ else // just remove this duplicate NPC
12718+ npc->unload(nd, true, (flag != 0));
12719+
12720+ script_pushint(st, 1);
12721+ return true;
12722+ }
12723+
1257512724/* Starts a status effect on the target unit or on the attached player.
1257612725 *
1257712726 * sc_start <effect_id>,<duration>,<val1>{,<rate>,<flag>,{<unit_id>}};
@@ -26938,6 +27087,8 @@ static void script_parse_builtin(void)
2693827087 BUILDIN_DEF(hideonnpc,"s"),
2693927088 BUILDIN_DEF(cloakonnpc,"s?"),
2694027089 BUILDIN_DEF(cloakoffnpc,"s?"),
27090+ BUILDIN_DEF(npc_duplicate, "ssssiii???"),
27091+ BUILDIN_DEF(npc_duplicate_remove, "??"),
2694127092 BUILDIN_DEF(sc_start,"iii???"),
2694227093 BUILDIN_DEF2(sc_start,"sc_start2","iiii???"),
2694327094 BUILDIN_DEF2(sc_start,"sc_start4","iiiiii???"),
0 commit comments