summaryrefslogtreecommitdiff
path: root/src/map/npc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/npc.c')
-rw-r--r--src/map/npc.c175
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;
}