diff options
-rw-r--r-- | src/map/mob.c | 9 | ||||
-rw-r--r-- | src/map/npc.c | 557 | ||||
-rw-r--r-- | src/map/npc.h | 12 |
3 files changed, 314 insertions, 264 deletions
diff --git a/src/map/mob.c b/src/map/mob.c index 2b519462d..6cbbd3a2a 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -142,17 +142,11 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time) if ( md->tomb_nid ) mob->mvptomb_destroy(md); - nd = npc->create_npc(md->bl.m, md->bl.x, md->bl.y); + nd = npc->create_npc(TOMB, md->bl.m, md->bl.x, md->bl.y, md->ud.dir, MOB_TOMB); md->tomb_nid = nd->bl.id; - nd->dir = md->ud.dir; - nd->bl.type = BL_NPC; safestrncpy(nd->name, msg_txt(856), sizeof(nd->name)); // "Tomb" - nd->class_ = 565; - nd->speed = 200; - nd->subtype = TOMB; - nd->u.tomb.md = md; nd->u.tomb.kill_time = time; @@ -165,7 +159,6 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time) map->addblock(&nd->bl); status->set_viewdata(&nd->bl, nd->class_); clif->spawn(&nd->bl); - } void mvptomb_destroy(struct mob_data *md) { diff --git a/src/map/npc.c b/src/map/npc.c index 7044fefcf..17a8b9414 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -53,8 +53,8 @@ static int npc_mob=0; static int npc_delay_mob=0; static int npc_cache_mob=0; -static char *npc_last_path; -static char *npc_last_ref; +static const char *npc_last_path; +static const char *npc_last_ref; struct npc_path_data *npc_last_npd; //For holding the view data of npc classes. [Skotlex] @@ -2244,16 +2244,9 @@ int npc_unload(struct npc_data* nd, bool single) npc_chat->finalize(nd); // deallocate npc PCRE data structures #endif - if( single && nd->path ) { - struct npc_path_data* npd = NULL; - if( nd->path && nd->path != npc_last_ref ) { - npd = strdb_get(npc->path_db, nd->path); - } - - if( npd && --npd->references == 0 ) { - strdb_remove(npc->path_db, nd->path);/* remove from db */ - aFree(nd->path);/* remove now that no other instances exist */ - } + if (single && nd->path != NULL) { + npc->releasepathreference(nd->path); + nd->path = NULL; } if( single && nd->bl.m != -1 ) @@ -2404,6 +2397,64 @@ void npc_delsrcfile(const char* name) } } +/** + * Retains a reference to filepath, for use in nd->path + * + * @param filepath The file path to retain. + * @return A retained reference to filepath. + */ +const char *npc_retainpathreference(const char *filepath) +{ + struct npc_path_data * npd = NULL; + nullpo_ret(filepath); + + if (npc_last_path == filepath) { + if (npc_last_npd != NULL) + npc_last_npd->references++; + return npc_last_ref; + } + + if ((npd = strdb_get(npc->path_db,filepath)) == NULL) { + CREATE(npd, struct npc_path_data, 1); + strdb_put(npc->path_db, filepath, npd); + + CREATE(npd->path, char, strlen(filepath)+1); + safestrncpy(npd->path, filepath, strlen(filepath)+1); + + npd->references = 0; + } + + npd->references++; + + npc_last_npd = npd; + npc_last_ref = npd->path; + npc_last_path = filepath; + + return npd->path; +} + +/** + * Releases a previously retained filepath. + * + * @param filepath The file path to release. + */ +void npc_releasepathreference(const char *filepath) +{ + struct npc_path_data* npd = NULL; + + nullpo_retv(filepath); + + if (filepath != npc_last_ref) { + npd = strdb_get(npc->path_db, filepath); + } + + if (npd != NULL && --npd->references == 0) { + char *npcpath = npd->path; + strdb_remove(npc->path_db, filepath);/* remove from db */ + aFree(npcpath); + } +} + /// Parses and sets the name and exname of a npc. /// Assumes that m, x and y are already set in nd. void npc_parsename(struct npc_data* nd, const char* name, const char* start, const char* buffer, const char* filepath) { @@ -2458,31 +2509,6 @@ void npc_parsename(struct npc_data* nd, const char* name, const char* start, con ShowDebug("other npc in '%s' :\n display name '%s'\n unique name '%s'\n map=%s, x=%d, y=%d\n",dnd->path, dnd->name, dnd->exname, other_mapname, dnd->bl.x, dnd->bl.y); safestrncpy(nd->exname, newname, sizeof(nd->exname)); } - - if( npc_last_path != filepath ) { - struct npc_path_data * npd = NULL; - - if( !(npd = strdb_get(npc->path_db,filepath) ) ) { - CREATE(npd, struct npc_path_data, 1); - strdb_put(npc->path_db, filepath, npd); - - CREATE(npd->path, char, strlen(filepath)+1); - safestrncpy(npd->path, filepath, strlen(filepath)+1); - - npd->references = 0; - } - - nd->path = npd->path; - npd->references++; - - npc_last_npd = npd; - npc_last_ref = npd->path; - npc_last_path = (char*) filepath; - } else { - nd->path = npc_last_ref; - if( npc_last_npd ) - npc_last_npd->references++; - } } // Parse View @@ -2534,17 +2560,39 @@ bool npc_viewisid(const char * viewid) return true; } -struct npc_data* npc_create_npc(int m, int x, int y) +/** + * Creates a new NPC. + * + * @remark + * When creating a npc with subtype TOMB, no ID is assigned. The caller + * must assign the dead mob ID after the NPC is created. + * + * @param subtype The NPC subtype. + * @param m The map id. + * @param x The x coordinate on map. + * @param y The y coordinate on map. + * @param dir The facing direction. + * @param class_ The NPC view class. + * @return A pointer to the created NPC data (ownership passed to the caller). + */ +struct npc_data *npc_create_npc(enum npc_subtype subtype, int m, int x, int y, uint8 dir, int16 class_) { struct npc_data *nd; CREATE(nd, struct npc_data, 1); - nd->bl.id = npc->get_new_npc_id(); + nd->subtype = subtype; + nd->bl.type = BL_NPC; + if (subtype != TOMB) { + nd->bl.id = npc->get_new_npc_id(); + } nd->bl.prev = nd->bl.next = NULL; nd->bl.m = m; nd->bl.x = x; nd->bl.y = y; + nd->dir = dir; nd->area_size = AREA_SIZE + 1; + nd->class_ = class_; + nd->speed = 200; return nd; } @@ -2554,8 +2602,7 @@ struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short int i, flag = 0; struct npc_data *nd; - nd = npc->create_npc(from_mapid, from_x, from_y); - map->addnpc(from_mapid, nd); + nd = npc->create_npc(WARP, from_mapid, from_x, from_y, 0, battle_config.warp_point_debug ? WARP_DEBUG_CLASS : WARP_CLASS); safestrncpy(nd->exname, name, ARRAYLENGTH(nd->exname)); if (npc->name2id(nd->exname) != NULL) @@ -2568,26 +2615,13 @@ struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short snprintf(nd->exname, ARRAYLENGTH(nd->exname), "warp%d_%d_%d_%d", i, from_mapid, from_x, from_y); safestrncpy(nd->name, nd->exname, ARRAYLENGTH(nd->name)); - if( battle_config.warp_point_debug ) - nd->class_ = WARP_DEBUG_CLASS; - else - nd->class_ = WARP_CLASS; - nd->speed = 200; - nd->u.warp.mapindex = to_mapindex; nd->u.warp.x = to_x; nd->u.warp.y = to_y; nd->u.warp.xs = xs; nd->u.warp.ys = xs; - nd->bl.type = BL_NPC; - nd->subtype = WARP; - npc->setcells(nd); - map->addblock(&nd->bl); - status->set_viewdata(&nd->bl, nd->class_); - nd->ud = &npc->base_ud; - if( map->list[nd->bl.m].users ) - clif->spawn(&nd->bl); - strdb_put(npc->name_db, nd->exname, nd); + + npc->add_to_location(nd); return nd; } @@ -2623,15 +2657,9 @@ const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* s return strchr(start,'\n');;//try next } - nd = npc->create_npc(m, x, y); - map->addnpc(m, nd); + nd = npc->create_npc(WARP, m, x, y, 0, battle_config.warp_point_debug ? WARP_DEBUG_CLASS : WARP_CLASS); npc->parsename(nd, w3, start, buffer, filepath); - - if (!battle_config.warp_point_debug) - nd->class_ = WARP_CLASS; - else - nd->class_ = WARP_DEBUG_CLASS; - nd->speed = 200; + nd->path = npc->retainpathreference(filepath); nd->u.warp.mapindex = i; nd->u.warp.x = to_x; @@ -2639,15 +2667,8 @@ const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* s nd->u.warp.xs = xs; nd->u.warp.ys = ys; npc_warp++; - nd->bl.type = BL_NPC; - nd->subtype = WARP; - npc->setcells(nd); - map->addblock(&nd->bl); - status->set_viewdata(&nd->bl, nd->class_); - nd->ud = &npc->base_ud; - if( map->list[nd->bl.m].users ) - clif->spawn(&nd->bl); - strdb_put(npc->name_db, nd->exname, nd); + + npc->add_to_location(nd); return strchr(start,'\n');// continue } @@ -2666,7 +2687,7 @@ const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* s size_t items_count = 40; // Starting items size char *p; - int x, y, dir, m, i; + int x, y, dir, m, i, class_; struct npc_data *nd; enum npc_subtype type; @@ -2765,31 +2786,18 @@ const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* s return strchr(start,'\n');// continue } - nd = npc->create_npc(m, x, y); + class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath); + nd = npc->create_npc(type, m, x, y, dir, class_); CREATE(nd->u.shop.shop_item, struct npc_item_list, i); memcpy(nd->u.shop.shop_item, items, sizeof(items[0])*i); aFree(items); nd->u.shop.count = i; npc->parsename(nd, w3, start, buffer, filepath); - nd->class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath); - nd->speed = 200; + nd->path = npc->retainpathreference(filepath); ++npc_shop; - nd->bl.type = BL_NPC; - nd->subtype = type; - if( m >= 0 ) {// normal shop npc - map->addnpc(m,nd); - map->addblock(&nd->bl); - status->set_viewdata(&nd->bl, nd->class_); - nd->ud = &npc->base_ud; - nd->dir = dir; - if( map->list[nd->bl.m].users ) - clif->spawn(&nd->bl); - } else {// 'floating' shop - map->addiddb(&nd->bl); - } - strdb_put(npc->name_db, nd->exname, nd); + npc->add_to_location(nd); return strchr(start,'\n');// continue } @@ -2889,7 +2897,7 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* { int x, y, dir = 0, m, xs = 0, ys = 0; // [Valaris] thanks to fov struct script_code *scriptroot; - int i; + int i, class_; const char* end; const char* script_start; @@ -2946,39 +2954,74 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* npc->convertlabel_db(label_list,filepath); } - nd = npc->create_npc(m, x, y); - if( sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2 ) - {// OnTouch area defined + class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath); + nd = npc->create_npc(SCRIPT, m, x, y, dir, class_); + if (sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2) { + // OnTouch area defined nd->u.scr.xs = xs; nd->u.scr.ys = ys; - } - else - {// no OnTouch area + } else { + // no OnTouch area nd->u.scr.xs = -1; nd->u.scr.ys = -1; } npc->parsename(nd, w3, start, buffer, filepath); - nd->class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath); - nd->speed = 200; + nd->path = npc->retainpathreference(filepath); nd->u.scr.script = scriptroot; nd->u.scr.label_list = label_list; nd->u.scr.label_list_num = label_list_num; if( options&NPO_TRADER ) nd->u.scr.trader = true; nd->u.scr.shop = NULL; - ++npc_script; - nd->bl.type = BL_NPC; - nd->subtype = SCRIPT; + npc->add_to_location(nd); - if( m >= 0 ) { - map->addnpc(m, nd); - nd->ud = &npc->base_ud; - nd->dir = dir; + //----------------------------------------- + // Loop through labels to export them as necessary + for (i = 0; i < nd->u.scr.label_list_num; i++) { + if (npc->event_export(nd, i)) { + ShowWarning("npc_parse_script: duplicate event %s::%s in file '%s'.\n", + nd->exname, nd->u.scr.label_list[i].name, filepath); + if (retval) *retval = EXIT_FAILURE; + } + npc->timerevent_export(nd, i); + } + + nd->u.scr.timerid = INVALID_TIMER; + + if( options&NPO_ONINIT ) { + char evname[EVENT_NAME_LENGTH]; + struct event_data *ev; + + snprintf(evname, ARRAYLENGTH(evname), "%s::OnInit", nd->exname); + + if( ( ev = (struct event_data*)strdb_get(npc->ev_db, evname) ) ) { + + //Execute OnInit + script->run_npc(nd->u.scr.script,ev->pos,0,nd->bl.id); + + } + } + + return end; +} + +/** + * Registers the NPC and adds it to its location (on map or floating). + * + * @param nd The NPC to register. + */ +void npc_add_to_location(struct npc_data *nd) +{ + nullpo_retv(nd); + + if (nd->bl.m > 0) { + map->addnpc(nd->bl.m, nd); npc->setcells(nd); map->addblock(&nd->bl); - if( nd->class_ >= 0 ) { + nd->ud = &npc->base_ud; + if (nd->class_ >= 0) { status->set_viewdata(&nd->bl, nd->class_); if( map->list[nd->bl.m].users ) clif->spawn(&nd->bl); @@ -2988,35 +3031,120 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* map->addiddb(&nd->bl); } strdb_put(npc->name_db, nd->exname, nd); +} + +/** + * Duplicates a script (@see npc_duplicate_sub) + */ +bool npc_duplicate_script_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options) +{ + int i; + bool retval = true; + + ++npc_script; + nd->u.scr.xs = xs; + nd->u.scr.ys = ys; + nd->u.scr.script = snd->u.scr.script; + nd->u.scr.label_list = snd->u.scr.label_list; + nd->u.scr.label_list_num = snd->u.scr.label_list_num; + nd->u.scr.shop = snd->u.scr.shop; + nd->u.scr.trader = snd->u.scr.trader; + + //add the npc to its location + npc->add_to_location(nd); - //----------------------------------------- // Loop through labels to export them as necessary for (i = 0; i < nd->u.scr.label_list_num; i++) { if (npc->event_export(nd, i)) { - ShowWarning("npc_parse_script: duplicate event %s::%s in file '%s'.\n", - nd->exname, nd->u.scr.label_list[i].name, filepath); - if (retval) *retval = EXIT_FAILURE; + ShowWarning("npc_parse_duplicate: duplicate event %s::%s in file '%s'.\n", + nd->exname, nd->u.scr.label_list[i].name, nd->path); + retval = false; } npc->timerevent_export(nd, i); } nd->u.scr.timerid = INVALID_TIMER; - if( options&NPO_ONINIT ) { + if (options&NPO_ONINIT) { + // From npc_parse_script char evname[EVENT_NAME_LENGTH]; struct event_data *ev; snprintf(evname, ARRAYLENGTH(evname), "%s::OnInit", nd->exname); - if( ( ev = (struct event_data*)strdb_get(npc->ev_db, evname) ) ) { - + if ((ev = (struct event_data*)strdb_get(npc->ev_db, evname)) != NULL) { //Execute OnInit script->run_npc(nd->u.scr.script,ev->pos,0,nd->bl.id); - } } + return retval; +} - return end; +/** + * Duplicates a shop or cash shop (@see npc_duplicate_sub) + */ +bool npc_duplicate_shop_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options) +{ + ++npc_shop; + nd->u.shop.shop_item = snd->u.shop.shop_item; + nd->u.shop.count = snd->u.shop.count; + + //add the npc to its location + npc->add_to_location(nd); + + return true; +} + +/** + * Duplicates a warp (@see npc_duplicate_sub) + */ +bool npc_duplicate_warp_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options) +{ + ++npc_warp; + nd->u.warp.xs = xs; + nd->u.warp.ys = ys; + nd->u.warp.mapindex = snd->u.warp.mapindex; + nd->u.warp.x = snd->u.warp.x; + nd->u.warp.y = snd->u.warp.y; + + //Add the npc to its location + npc->add_to_location(nd); + + return true; +} + +/** + * Duplicates a warp, shop, cashshop or script. + * + * @param nd An already initialized NPC data. Expects bl->m, bl->x, bl->y, + * name, exname, path, dir, class_, speed, subtype to be already + * filled. + * @param snd The source NPC to duplicate. + * @param class_ The npc view class. + * @param dir The facing direction. + * @param xs The x-span, if any. + * @param ys The y-span, if any. + * @param options The NPC options. + * @retval false if there were any issues while creating and validating the NPC. + */ +bool npc_duplicate_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options) +{ + nd->src_id = snd->bl.id; + switch (nd->subtype) { + case SCRIPT: + return npc->duplicate_script_sub(nd, snd, xs, ys, options); + + case SHOP: + case CASHSHOP: + return npc->duplicate_shop_sub(nd, snd, xs, ys, options); + + case WARP: + return npc->duplicate_warp_sub(nd, snd, xs, ys, options); + + case TOMB: + return false; + } + return false; } /// Duplicate a warp, shop, cashshop or script. [Orcao] @@ -3029,12 +3157,10 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options, int *retval) { int x, y, dir, m, xs = -1, ys = -1; char srcname[128]; - int i; - const char* end; + const char *end; size_t length; - int src_id; - int type; + int class_; struct npc_data* nd; struct npc_data* dnd; @@ -3056,18 +3182,16 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch if (retval) *retval = EXIT_FAILURE; return end;// next line, try to continue } - src_id = dnd->bl.id; - type = dnd->subtype; // get placement - if ((type==SHOP || type==CASHSHOP || type==SCRIPT) && strcmp(w1, "-") == 0) { + if ((dnd->subtype==SHOP || dnd->subtype==CASHSHOP || dnd->subtype==SCRIPT) && strcmp(w1, "-") == 0) { // floating shop/chashshop/script x = y = dir = 0; m = -1; } else { char mapname[32]; int fields = sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir); - if (type == WARP && fields == 3) { + if (dnd->subtype == WARP && fields == 3) { // <map name>,<x>,<y> dir = 0; } else if (fields != 4) { @@ -3090,107 +3214,40 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch return end;//try next } - if( type == WARP && sscanf(w4, "%d,%d", &xs, &ys) == 2 );// <spanx>,<spany> - else if( type == SCRIPT && sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2);// <sprite id>,<triggerX>,<triggerY> - else if( type == WARP ) { + if (dnd->subtype == WARP && sscanf(w4, "%d,%d", &xs, &ys) == 2) { // <spanx>,<spany> + ; + } else if (dnd->subtype == SCRIPT && sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2) { // <sprite id>,<triggerX>,<triggerY> + ; + } else if (dnd->subtype == WARP) { ShowError("npc_parse_duplicate: Invalid span format for duplicate warp in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); if (retval) *retval = EXIT_FAILURE; return end;// next line, try to continue } - nd = npc->create_npc(m, x, y); + class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath); + nd = npc->create_npc(dnd->subtype, m, x, y, dir, class_); npc->parsename(nd, w3, start, buffer, filepath); - nd->class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath); - nd->speed = 200; - nd->src_id = src_id; - nd->bl.type = BL_NPC; - nd->subtype = (enum npc_subtype)type; - switch( type ) { - case SCRIPT: - ++npc_script; - nd->u.scr.xs = xs; - nd->u.scr.ys = ys; - nd->u.scr.script = dnd->u.scr.script; - nd->u.scr.label_list = dnd->u.scr.label_list; - nd->u.scr.label_list_num = dnd->u.scr.label_list_num; - nd->u.scr.shop = dnd->u.scr.shop; - nd->u.scr.trader = dnd->u.scr.trader; - break; - - case SHOP: - case CASHSHOP: - ++npc_shop; - nd->u.shop.shop_item = dnd->u.shop.shop_item; - nd->u.shop.count = dnd->u.shop.count; - break; - - case WARP: - ++npc_warp; - if( !battle_config.warp_point_debug ) - nd->class_ = WARP_CLASS; - else - nd->class_ = WARP_DEBUG_CLASS; - nd->u.warp.xs = xs; - nd->u.warp.ys = ys; - nd->u.warp.mapindex = dnd->u.warp.mapindex; - nd->u.warp.x = dnd->u.warp.x; - nd->u.warp.y = dnd->u.warp.y; - break; - } - - //Add the npc to its location - if( m >= 0 ) { - map->addnpc(m, nd); - nd->ud = &npc->base_ud; - nd->dir = dir; - npc->setcells(nd); - map->addblock(&nd->bl); - if( nd->class_ >= 0 ) { - status->set_viewdata(&nd->bl, nd->class_); - if( map->list[nd->bl.m].users ) - clif->spawn(&nd->bl); - } - } else { - // we skip map->addnpc, but still add it to the list of ID's - map->addiddb(&nd->bl); - } - strdb_put(npc->name_db, nd->exname, nd); - - if( type != SCRIPT ) - return end; - - //----------------------------------------- - // Loop through labels to export them as necessary - for (i = 0; i < nd->u.scr.label_list_num; i++) { - if (npc->event_export(nd, i)) { - ShowWarning("npc_parse_duplicate: duplicate event %s::%s in file '%s'.\n", - nd->exname, nd->u.scr.label_list[i].name, filepath); - if (retval) *retval = EXIT_FAILURE; - } - npc->timerevent_export(nd, i); + nd->path = npc->retainpathreference(filepath); + if (!npc->duplicate_sub(nd, dnd, xs, ys, options)) { + if (retval) *retval = EXIT_FAILURE; } - nd->u.scr.timerid = INVALID_TIMER; - - if (options&NPO_ONINIT) { - // From npc_parse_script - char evname[EVENT_NAME_LENGTH]; - struct event_data *ev; - - snprintf(evname, ARRAYLENGTH(evname), "%s::OnInit", nd->exname); - - if( ( ev = (struct event_data*)strdb_get(npc->ev_db, evname) ) ) { - - //Execute OnInit - script->run_npc(nd->u.scr.script,ev->pos,0,nd->bl.id); - - } - } return end; } -int npc_duplicate4instance(struct npc_data *snd, int16 m) { +/** + * Duplicates an NPC for instancing purposes. + * + * @param snd The NPC to duplicate. + * @param m The instanced map ID. + * @return success state. + * @retval 0 in case of successful creation. + */ +int npc_duplicate4instance(struct npc_data *snd, int16 m) +{ char newname[NAME_LENGTH]; + int dm = -1, im = -1, xs = -1, ys = -1; + struct npc_data *nd = NULL; if( m == -1 || map->list[m].instance_id == -1 ) return 1; @@ -3201,50 +3258,35 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) { return 1; } - if( snd->subtype == WARP ) { // Adjust destination, if instanced - struct npc_data *wnd = NULL; // New NPC - int dm = map->mapindex2mapid(snd->u.warp.mapindex), im; - if( dm < 0 ) return 1; - - if( ( im = instance->mapid2imapid(dm, map->list[m].instance_id) ) == -1 ) { + switch (snd->subtype) { + case SCRIPT: + xs = snd->u.scr.xs; + ys = snd->u.scr.ys; + break; + case WARP: + xs = snd->u.warp.xs; + ys = snd->u.warp.ys; + // Adjust destination, if instanced + if ((dm = map->mapindex2mapid(snd->u.warp.mapindex)) < 0) { + return 1; + } + if ((im = instance->mapid2imapid(dm, map->list[m].instance_id)) == -1) { ShowError("npc_duplicate4instance: warp (%s) leading to instanced map (%s), but instance map is not attached to current instance.\n", map->list[dm].name, snd->exname); return 1; } + break; + default: // Other types have no xs/ys + break; + } - wnd = npc->create_npc(m, snd->bl.x, snd->bl.y); - map->addnpc(m, wnd); - safestrncpy(wnd->name, "", ARRAYLENGTH(wnd->name)); - safestrncpy(wnd->exname, newname, ARRAYLENGTH(wnd->exname)); - wnd->class_ = WARP_CLASS; - wnd->speed = 200; - wnd->u.warp.mapindex = map_id2index(im); - wnd->u.warp.x = snd->u.warp.x; - wnd->u.warp.y = snd->u.warp.y; - wnd->u.warp.xs = snd->u.warp.xs; - wnd->u.warp.ys = snd->u.warp.ys; - wnd->bl.type = BL_NPC; - wnd->subtype = WARP; - npc->setcells(wnd); - map->addblock(&wnd->bl); - status->set_viewdata(&wnd->bl, wnd->class_); - wnd->ud = &npc->base_ud; - if( map->list[wnd->bl.m].users ) - clif->spawn(&wnd->bl); - strdb_put(npc->name_db, wnd->exname, wnd); - } else { - static char w1[50], w2[50], w3[50], w4[50]; - const char* stat_buf = "- call from instancing subsystem -\n"; - - snprintf(w1, sizeof(w1), "%s,%d,%d,%d", map->list[m].name, snd->bl.x, snd->bl.y, snd->dir); - snprintf(w2, sizeof(w2), "duplicate(%s)", snd->exname); - snprintf(w3, sizeof(w3), "%s::%s", snd->name, newname); - - if( snd->u.scr.xs >= 0 && snd->u.scr.ys >= 0 ) - snprintf(w4, sizeof(w4), "%d,%d,%d", snd->class_, snd->u.scr.xs, snd->u.scr.ys); // Touch Area - else - snprintf(w4, sizeof(w4), "%d", snd->class_); - - npc->parse_duplicate(w1, w2, w3, w4, stat_buf, stat_buf, "INSTANCING", NPO_NONE, NULL); + nd = npc->create_npc(snd->subtype, m, snd->bl.x, snd->bl.y, snd->dir, snd->class_); + safestrncpy(nd->name, snd->name, sizeof(nd->name)); + safestrncpy(nd->exname, newname, sizeof(nd->exname)); + nd->path = npc->retainpathreference("INSTANCING"); + npc->duplicate_sub(nd, snd, xs, ys, NPO_NONE); + if (nd->subtype == WARP) { + // Adjust destination, if instanced + nd->u.warp.mapindex = map_id2index(im); } return 0; @@ -4732,6 +4774,8 @@ void npc_defaults(void) { npc->clearsrcfile = npc_clearsrcfile; npc->addsrcfile = npc_addsrcfile; npc->delsrcfile = npc_delsrcfile; + npc->retainpathreference = npc_retainpathreference; + npc->releasepathreference = npc_releasepathreference; npc->parsename = npc_parsename; npc->parseview = npc_parseview; npc->viewisid = npc_viewisid; @@ -4742,6 +4786,11 @@ void npc_defaults(void) { npc->convertlabel_db = npc_convertlabel_db; npc->skip_script = npc_skip_script; npc->parse_script = npc_parse_script; + npc->add_to_location = npc_add_to_location; + npc->duplicate_script_sub = npc_duplicate_script_sub; + npc->duplicate_shop_sub = npc_duplicate_shop_sub; + npc->duplicate_warp_sub = npc_duplicate_warp_sub; + npc->duplicate_sub = npc_duplicate_sub; npc->parse_duplicate = npc_parse_duplicate; npc->duplicate4instance = npc_duplicate4instance; npc->setcells = npc_setcells; diff --git a/src/map/npc.h b/src/map/npc.h index bf3d1494d..de403fe76 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -70,7 +70,7 @@ struct npc_data { unsigned short stat_point; struct npc_parse *chatdb; - char* path;/* path dir */ + const char *path; ///< Source path reference enum npc_subtype subtype; int src_id; union { @@ -111,6 +111,7 @@ struct npc_data { enum actor_classes { WARP_CLASS = 45, HIDDEN_WARP_CLASS = 139, + MOB_TOMB = 565, WARP_DEBUG_CLASS = 722, FLAG_CLASS = 722, INVISIBLE_CLASS = 32767, @@ -225,10 +226,12 @@ struct npc_interface { void (*clearsrcfile) (void); void (*addsrcfile) (const char *name); void (*delsrcfile) (const char *name); + const char *(*retainpathreference) (const char *filepath); + void (*releasepathreference) (const char *filepath); void (*parsename) (struct npc_data *nd, const char *name, const char *start, const char *buffer, const char *filepath); int (*parseview) (const char *w4, const char *start, const char *buffer, const char *filepath); bool (*viewisid) (const char *viewid); - struct npc_data* (*create_npc) (int m, int x, int y); + struct npc_data *(*create_npc) (enum npc_subtype subtype, int m, int x, int y, uint8 dir, int16 class_); struct npc_data* (*add_warp) (char *name, short from_mapid, short from_x, short from_y, short xs, short ys, unsigned short to_mapindex, short to_x, short to_y); const char* (*parse_warp) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval); const char* (*parse_shop) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval); @@ -236,6 +239,11 @@ struct npc_interface { void (*convertlabel_db) (struct npc_label_list *label_list, const char *filepath); const char* (*skip_script) (const char *start, const char *buffer, const char *filepath, int *retval); const char* (*parse_script) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int options, int *retval); + void (*add_to_location) (struct npc_data *nd); + bool (*duplicate_script_sub) (struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options); + bool (*duplicate_shop_sub) (struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options); + bool (*duplicate_warp_sub) (struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options); + bool (*duplicate_sub) (struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options); const char* (*parse_duplicate) (char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options, int *retval); int (*duplicate4instance) (struct npc_data *snd, int16 m); void (*setcells) (struct npc_data *nd); |