diff options
Diffstat (limited to 'src/map/npc.c')
-rw-r--r-- | src/map/npc.c | 175 |
1 files changed, 93 insertions, 82 deletions
diff --git a/src/map/npc.c b/src/map/npc.c index e66888a74..7a3fa9c3f 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -389,7 +389,10 @@ static int npc_event_export(struct npc_data *nd, int i) Assert_ret(i >= 0 && i < nd->u.scr.label_list_num); lname = nd->u.scr.label_list[i].name; pos = nd->u.scr.label_list[i].pos; - if ((lname[0] == 'O' || lname[0] == 'o') && (lname[1] == 'N' || lname[1] == 'n')) { + + if ((nd->u.scr.label_list[i].flags & LABEL_IS_EXTERN) != 0 + && ((nd->u.scr.label_list[i].flags & LABEL_IS_USERFUNC) == 0 + || script->config.functions_as_events)) { struct event_data *ev; struct linkdb_node **label_linkdb = NULL; char buf[EVENT_NAME_LENGTH]; @@ -1799,6 +1802,7 @@ static void npc_expanded_barter_fromsql(void) ) { SqlStmt_ShowDebug(stmt); SQL->StmtFree(stmt); + StrBuf->Destroy(&buf); return; } @@ -2711,43 +2715,47 @@ static int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_l char card_slot[NAME_LENGTH]; char opt_index_str[NAME_LENGTH]; char opt_value_str[NAME_LENGTH]; - int i, j; + char opt_param_str[NAME_LENGTH]; + int i = 0; + int j = 0; int key_nameid = 0; int key_amount = 0; int key_refine = 0; - int key_attribute = 0; + int key_attribute = ATTR_NONE; int key_identify = 0; int key_card[MAX_SLOTS]; int key_opt_idx[MAX_ITEM_OPTIONS]; int key_opt_value[MAX_ITEM_OPTIONS]; + int key_opt_param[MAX_ITEM_OPTIONS]; nullpo_ret(sd); nullpo_ret(item_list); nullpo_ret(nd); // discard old contents - script->cleararray_pc(sd, "@sold_nameid", (void*)0); - script->cleararray_pc(sd, "@sold_quantity", (void*)0); - script->cleararray_pc(sd, "@sold_refine", (void*)0); - script->cleararray_pc(sd, "@sold_attribute", (void*)0); - script->cleararray_pc(sd, "@sold_identify", (void*)0); - - for( j = 0; j < MAX_SLOTS; j++ ) - {// clear each of the card slot entries + script->cleararray_pc(sd, "@sold_nameid", (void *)0); + script->cleararray_pc(sd, "@sold_quantity", (void *)0); + script->cleararray_pc(sd, "@sold_refine", (void *)0); + script->cleararray_pc(sd, "@sold_attribute", (void *)0); + script->cleararray_pc(sd, "@sold_identify", (void *)0); + + for (j = 0; j < MAX_SLOTS; j++) { // clear each of the card slot entries key_card[j] = 0; snprintf(card_slot, sizeof(card_slot), "@sold_card%d", j + 1); - script->cleararray_pc(sd, card_slot, (void*)0); + script->cleararray_pc(sd, card_slot, (void *)0); } for (j = 0; j < MAX_ITEM_OPTIONS; j++) { // Clear Each item option entry key_opt_idx[j] = 0; key_opt_value[j] = 0; + key_opt_param[j] = 0; - snprintf(opt_index_str, sizeof(opt_index_str), "@slot_opt_idx%d", j + 1); - script->cleararray_pc(sd, opt_index_str, (void*)0); - - snprintf(opt_value_str, sizeof(opt_value_str), "@slot_opt_val%d", j + 1); - script->cleararray_pc(sd, opt_value_str, (void*)0); + snprintf(opt_index_str, sizeof(opt_index_str), "@sold_opt_idx%d", j + 1); + script->cleararray_pc(sd, opt_index_str, (void *)0); + snprintf(opt_value_str, sizeof(opt_value_str), "@sold_opt_val%d", j + 1); + script->cleararray_pc(sd, opt_value_str, (void *)0); + snprintf(opt_param_str, sizeof(opt_param_str), "@sold_opt_param%d", j + 1); + script->cleararray_pc(sd, opt_param_str, (void *)0); } // save list of to be sold items @@ -2760,32 +2768,31 @@ static int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_l intptr_t attribute = item->attribute; intptr_t identify = item->identify; - script->setarray_pc(sd, "@sold_nameid", i, (void*)nameid, &key_nameid); - script->setarray_pc(sd, "@sold_quantity", i, (void*)amount, &key_amount); - // process item based information into the arrays - script->setarray_pc(sd, "@sold_refine", i, (void*)refine, &key_refine); - script->setarray_pc(sd, "@sold_attribute", i, (void*)attribute, &key_attribute); - script->setarray_pc(sd, "@sold_identify", i, (void*)identify, &key_identify); + script->setarray_pc(sd, "@sold_nameid", i, (void *)nameid, &key_nameid); + script->setarray_pc(sd, "@sold_quantity", i, (void *)amount, &key_amount); + script->setarray_pc(sd, "@sold_refine", i, (void *)refine, &key_refine); + script->setarray_pc(sd, "@sold_attribute", i, (void *)attribute, &key_attribute); + script->setarray_pc(sd, "@sold_identify", i, (void *)identify, &key_identify); for (j = 0; j < MAX_SLOTS; j++) { intptr_t card = item->card[j]; - // store each of the cards/special info from the item in the array snprintf(card_slot, sizeof(card_slot), "@sold_card%d", j + 1); - script->setarray_pc(sd, card_slot, i, (void*)card, &key_card[j]); + script->setarray_pc(sd, card_slot, i, (void *)card, &key_card[j]); } for (j = 0; j < MAX_ITEM_OPTIONS; j++) { intptr_t opt_idx = item->option[j].index; intptr_t opt_value = item->option[j].value; + intptr_t opt_param = item->option[j].param; - snprintf(opt_index_str, sizeof(opt_index_str), "@slot_opt_idx%d", j + 1); - script->setarray_pc(sd, opt_index_str, i, (void*)opt_idx, &key_opt_idx[j]); - - snprintf(opt_value_str, sizeof(opt_value_str), "@slot_opt_val%d", j + 1); - script->setarray_pc(sd, opt_value_str, i, (void*)opt_value, &key_opt_value[j]); + snprintf(opt_index_str, sizeof(opt_index_str), "@sold_opt_idx%d", j + 1); + script->setarray_pc(sd, opt_index_str, i, (void *)opt_idx, &key_opt_idx[j]); + snprintf(opt_value_str, sizeof(opt_value_str), "@sold_opt_val%d", j + 1); + script->setarray_pc(sd, opt_value_str, i, (void *)opt_value, &key_opt_value[j]); + snprintf(opt_param_str, sizeof(opt_param_str), "@sold_opt_param%d", j + 1); + script->setarray_pc(sd, opt_param_str, i, (void *)opt_param, &key_opt_param[j]); } - } // invoke event @@ -2794,104 +2801,102 @@ static int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_l return 0; } -/// Player item selling to npc shop. -/// -/// @param item_list 'n' pairs <index,amount> -/// @return result code for clif->parse_NpcSellListSend +/** + * Processes a character's request to sell items to a NPC shop. + * + * @param sd The character who wants to sell the items. + * @param item_list The list of items and respective amounts which should be sold. + * @return 1 on failure, 0 on success. + * + **/ static int npc_selllist(struct map_session_data *sd, struct itemlist *item_list) { - int64 z; - int i,skill_t, skill_idx = skill->get_index(MC_OVERCHARGE); - struct npc_data *nd; - bool duplicates[MAX_INVENTORY] = { 0 }; - nullpo_retr(1, sd); nullpo_retr(1, item_list); - if( ( nd = npc->checknear(sd, map->id2bl(sd->npc_shopid)) ) == NULL ) { + struct npc_data *nd = npc->checknear(sd, map->id2bl(sd->npc_shopid)); + + if (nd == NULL) return 1; - } - if( nd->subtype != SHOP ) { - if (!(nd->subtype == SCRIPT && nd->u.scr.shop && (nd->u.scr.shop->type == NST_ZENY || nd->u.scr.shop->type == NST_MARKET))) + if (nd->subtype != SHOP) { + if (nd->subtype != SCRIPT || nd->u.scr.shop == NULL || (nd->u.scr.shop->type != NST_ZENY && nd->u.scr.shop->type != NST_MARKET)) return 1; } - z = 0; - if (sd->status.zeny >= MAX_ZENY && nd->master_nd == NULL) return 1; - // verify the sell list - for (i = 0; i < VECTOR_LENGTH(*item_list); i++) { + bool duplicates[MAX_INVENTORY] = { false }; + int64 z = 0; + + // Verify the sell list. + for (int i = 0; i < VECTOR_LENGTH(*item_list); i++) { struct itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); - int nameid, value, idx = entry->id; + int idx = entry->id; - if (idx >= sd->status.inventorySize || idx < 0 || entry->amount < 0) { + if (idx >= sd->status.inventorySize || idx < 0 || entry->amount < 0) return 1; - } - if (duplicates[idx]) { - // Sanity check. The client sends each inventory index at most once [Haru] + if (duplicates[idx]) // Sanity check. The client sends each inventory index at most once. [Haru] return 1; - } + duplicates[idx] = true; - nameid = sd->status.inventory[idx].nameid; + int nameid = sd->status.inventory[idx].nameid; - if (!nameid || !sd->inventory_data[idx] || sd->status.inventory[idx].amount < entry->amount) { + if (nameid == 0 || sd->inventory_data[idx] == NULL || sd->status.inventory[idx].amount < entry->amount) return 1; - } - if (nd->master_nd) { - // Script-controlled shops decide by themselves, what can be sold and at what price. + if (nd->master_nd != NULL) // Script-controlled shops decide by themselves, what can be sold and at what price. continue; - } - value = pc->modifysellvalue(sd, sd->inventory_data[idx]->value_sell); + int value = pc->modifysellvalue(sd, sd->inventory_data[idx]->value_sell); z += (int64)value * entry->amount; } - if( nd->master_nd ) { // Script-controlled shops + if (nd->master_nd != NULL) // Script-controlled shops. return npc->selllist_sub(sd, item_list, nd->master_nd); - } - // delete items - for (i = 0; i < VECTOR_LENGTH(*item_list); i++) { + if (z + sd->status.zeny > MAX_ZENY) + return 1; + + // Delete items. + for (int i = 0; i < VECTOR_LENGTH(*item_list); i++) { struct itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); int idx = entry->id; if (sd->inventory_data[idx]->type == IT_PETEGG && sd->status.inventory[idx].card[0] == CARD0_PET) { - if (pet->search_petDB_index(sd->status.inventory[idx].nameid, PET_EGG) >= 0) { + if (pet->search_petDB_index(sd->status.inventory[idx].nameid, PET_EGG) >= 0) intif->delete_petdata(MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2])); - } } - // Achievements [Smokexyz/Hercules] + // Achievements. [Smokexyz/Hercules] achievement->validate_item_sell(sd, sd->status.inventory[idx].nameid, entry->amount); pc->delitem(sd, idx, entry->amount, 0, DELITEM_SOLD, LOG_TYPE_NPC); - } - if (z + sd->status.zeny > MAX_ZENY && nd->master_nd == NULL) - return 1; - if (z > MAX_ZENY) z = MAX_ZENY; pc->getzeny(sd, (int)z, LOG_TYPE_NPC, NULL); - // custom merchant shop exp bonus - if( battle_config.shop_exp > 0 && z > 0 && ( skill_t = pc->checkskill2(sd,skill_idx) ) > 0) { - if( sd->status.skill[skill_idx].flag >= SKILL_FLAG_REPLACED_LV_0 ) + int skill_t; + int skill_idx = skill->get_index(MC_OVERCHARGE); + + // Custom merchant shop exp bonus. + if (battle_config.shop_exp > 0 && z > 0 && (skill_t = pc->checkskill2(sd, skill_idx)) > 0) { + if (sd->status.skill[skill_idx].flag >= SKILL_FLAG_REPLACED_LV_0) skill_t = sd->status.skill[skill_idx].flag - SKILL_FLAG_REPLACED_LV_0; - if( skill_t > 0 ) { + if (skill_t > 0) { z = apply_percentrate64(z, skill_t * battle_config.shop_exp, 10000); + if (z < 1) z = 1; + pc->gainexp(sd, NULL, 0, (int)z, false); } } @@ -3053,11 +3058,11 @@ static int npc_unload(struct npc_data *nd, bool single, bool unload_mobs) aFree(nd->u.shop.shop_item); /// src check for duplicate shops. [Orcao] } else if (nd->subtype == SCRIPT) { char evname[EVENT_NAME_LENGTH]; - + snprintf(evname, ARRAYLENGTH(evname), "%s::OnNPCUnload", nd->exname); struct event_data *ev = strdb_get(npc->ev_db, evname); - + if (ev != NULL) script->run_npc(nd->u.scr.script, ev->pos, 0, nd->bl.id); /// Run OnNPCUnload. @@ -3391,7 +3396,7 @@ static bool npc_viewisid(const char *viewid) * @param class_ The NPC view class. * @return A pointer to the created NPC data (ownership passed to the caller). */ -static struct npc_data *npc_create_npc(enum npc_subtype subtype, int m, int x, int y, uint8 dir, int class_) +static struct npc_data *npc_create_npc(enum npc_subtype subtype, int m, int x, int y, enum unit_dir dir, int class_) { struct npc_data *nd; @@ -3664,6 +3669,7 @@ static void npc_convertlabel_db(struct npc_label_list *label_list, const char *f for( i = 0; i < script->label_count; i++ ) { const char* lname = script->get_str(script->labels[i].key); int lpos = script->labels[i].pos; + enum script_label_flags flags = script->labels[i].flags; struct npc_label_list* label; const char *p; size_t len; @@ -3685,6 +3691,7 @@ static void npc_convertlabel_db(struct npc_label_list *label_list, const char *f safestrncpy(label->name, lname, sizeof(label->name)); label->pos = lpos; + label->flags = flags; } } @@ -5098,7 +5105,7 @@ static const char *npc_parse_mapflag(const char *w1, const char *w2, const char else if (modifier[0] == '\0') { ShowWarning("npc_parse_mapflag: Missing 5th param for 'adjust_unit_duration' flag! removing flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); if (retval) *retval = EXIT_FAILURE; - } else if( !( skill_id = skill->name2id(skill_name) ) || !skill->get_unit_id( skill->name2id(skill_name), 0) ) { + } else if ((skill_id = skill->name2id(skill_name)) == 0 || skill->get_unit_id(skill->name2id(skill_name), 1, 0) == 0) { ShowWarning("npc_parse_mapflag: Unknown skill (%s) for 'adjust_unit_duration' flag! removing flag from %s in file '%s', line '%d'.\n",skill_name, map->list[m].name, filepath, strline(buffer,start-buffer)); if (retval) *retval = EXIT_FAILURE; } else if ( atoi(modifier) < 1 || atoi(modifier) > USHRT_MAX ) { @@ -5235,6 +5242,8 @@ static const char *npc_parse_mapflag(const char *w1, const char *w2, const char map->list[m].flag.nostorage = (state) ? cap_value(atoi(w4), 1, 3) : 0; } else if (!strcmpi(w3, "nogstorage")) { map->list[m].flag.nogstorage = (state) ? cap_value(atoi(w4), 1, 3) : 0; + } else if (strcmpi(w3, "nopet") == 0) { + map->list[m].flag.nopet = (state != 0) ? 1 : 0; } else { npc->parse_unknown_mapflag(mapname, w3, w4, start, buffer, filepath, retval); } @@ -5605,7 +5614,7 @@ static int npc_reload(void) npc->npc_last_npd = NULL; npc->npc_last_path = NULL; npc->npc_last_ref = NULL; - + const int npc_new_min = npc->npc_id; struct s_mapiterator *iter = mapit_geteachiddb(); @@ -5722,8 +5731,10 @@ static bool npc_unloadfile(const char *filepath, bool unload_mobs) dbi_destroy(iter); - if (found) /// Refresh event cache. + if (found) { /// Refresh event cache. + npc->motd = npc->name2id("HerculesMOTD"); npc->read_event_script(); + } return found; } |