summaryrefslogtreecommitdiff
path: root/src/emap/script_buildins.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emap/script_buildins.c')
-rw-r--r--src/emap/script_buildins.c163
1 files changed, 163 insertions, 0 deletions
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("<source_npc_name>", "<new_npc_name>", "<mapname>", <map_x>, <map_y>, {<sprite_id>, <dir>{, <map_xs>, <map_ys>}});
+ * 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({"<npc_name>"});
+ * 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