diff options
Diffstat (limited to 'src/map/script.c')
-rw-r--r-- | src/map/script.c | 622 |
1 files changed, 408 insertions, 214 deletions
diff --git a/src/map/script.c b/src/map/script.c index e104cd891..14623bac7 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -6099,11 +6099,11 @@ static BUILDIN(menu) sd->state.menu_or_input = 1; /* menus beyond this length crash the client (see bugreport:6402) */ - if( StrBuf->Length(&buf) >= 2047 ) { + if( StrBuf->Length(&buf) >= MAX_MENU_LENGTH - 1 ) { struct npc_data * nd = map->id2nd(st->oid); char* menu; - CREATE(menu, char, 2048); - safestrncpy(menu, StrBuf->Value(&buf), 2047); + CREATE(menu, char, MAX_MENU_LENGTH); + safestrncpy(menu, StrBuf->Value(&buf), MAX_MENU_LENGTH - 1); ShowWarning("NPC Menu too long! (source:%s / length:%d)\n",nd?nd->name:"Unknown",StrBuf->Length(&buf)); clif->scriptmenu(sd, st->oid, menu); aFree(menu); @@ -6112,13 +6112,13 @@ static BUILDIN(menu) StrBuf->Destroy(&buf); - if( sd->npc_menu >= 0xff ) + if( sd->npc_menu >= MAX_MENU_OPTIONS ) {// client supports only up to 254 entries; 0 is not used and 255 is reserved for cancel; excess entries are displayed but cause 'uint8' overflow - ShowWarning("buildin_menu: Too many options specified (current=%d, max=254).\n", sd->npc_menu); + ShowWarning("buildin_menu: Too many options specified (current=%d, max=%d).\n", sd->npc_menu, MAX_MENU_OPTIONS - 1); script->reportsrc(st); } } - else if( sd->npc_menu == 0xff ) + else if( sd->npc_menu == MAX_MENU_OPTIONS ) {// Cancel was pressed sd->state.menu_or_input = 0; st->state = END; @@ -6200,11 +6200,11 @@ static BUILDIN(select) sd->state.menu_or_input = 1; /* menus beyond this length crash the client (see bugreport:6402) */ - if( StrBuf->Length(&buf) >= 2047 ) { + if( StrBuf->Length(&buf) >= MAX_MENU_LENGTH - 1 ) { struct npc_data * nd = map->id2nd(st->oid); char* menu; - CREATE(menu, char, 2048); - safestrncpy(menu, StrBuf->Value(&buf), 2047); + CREATE(menu, char, MAX_MENU_LENGTH); + safestrncpy(menu, StrBuf->Value(&buf), MAX_MENU_LENGTH - 1); ShowWarning("NPC Menu too long! (source:%s / length:%d)\n",nd?nd->name:"Unknown",StrBuf->Length(&buf)); clif->scriptmenu(sd, st->oid, menu); aFree(menu); @@ -6212,107 +6212,31 @@ static BUILDIN(select) clif->scriptmenu(sd, st->oid, StrBuf->Value(&buf)); StrBuf->Destroy(&buf); - if( sd->npc_menu >= 0xff ) { - ShowWarning("buildin_select: Too many options specified (current=%d, max=254).\n", sd->npc_menu); + if( sd->npc_menu >= MAX_MENU_OPTIONS ) { + ShowWarning("buildin_select: Too many options specified (current=%d, max=%d).\n", sd->npc_menu, MAX_MENU_OPTIONS - 1); script->reportsrc(st); } - } else if( sd->npc_menu == 0xff ) {// Cancel was pressed + } else if(sd->npc_menu == MAX_MENU_OPTIONS) { // Cancel was pressed sd->state.menu_or_input = 0; - st->state = END; - } else {// return selected option - int menu = 0; - - sd->state.menu_or_input = 0; - for( i = 2; i <= script_lastdata(st); ++i ) { - text = script_getstr(st, i); - sd->npc_menu -= script->menu_countoptions(text, sd->npc_menu, &menu); - if( sd->npc_menu <= 0 ) - break;// entry found - } - pc->setreg(sd, script->add_variable("@menu"), menu); - script_pushint(st, menu); - st->state = RUN; - } - return true; -} - -/// Displays a menu with options and returns the selected option. -/// Behaves like 'menu' without the target labels, except when cancel is -/// pressed. -/// When cancel is pressed, the script continues and 255 is returned. -/// -/// prompt(<option_text>{,<option_text>,...}) -> <selected_option> -/// -/// @see menu -static BUILDIN(prompt) -{ - int i; - const char *text; - struct map_session_data *sd = script->rid2sd(st); - if (sd == NULL) - return true; - -#ifdef SECURE_NPCTIMEOUT - sd->npc_idle_type = NPCT_MENU; -#endif - - if( sd->state.menu_or_input == 0 ) - { - struct StringBuf buf; - StrBuf->Init(&buf); - sd->npc_menu = 0; - for( i = 2; i <= script_lastdata(st); ++i ) - { - text = script_getstr(st, i); - if( sd->npc_menu > 0 ) - StrBuf->AppendStr(&buf, ":"); - StrBuf->AppendStr(&buf, text); - sd->npc_menu += script->menu_countoptions(text, 0, NULL); - } - - st->state = RERUNLINE; - sd->state.menu_or_input = 1; - - /* menus beyond this length crash the client (see bugreport:6402) */ - if( StrBuf->Length(&buf) >= 2047 ) { - struct npc_data * nd = map->id2nd(st->oid); - char* menu; - CREATE(menu, char, 2048); - safestrncpy(menu, StrBuf->Value(&buf), 2047); - ShowWarning("NPC Menu too long! (source:%s / length:%d)\n",nd?nd->name:"Unknown",StrBuf->Length(&buf)); - clif->scriptmenu(sd, st->oid, menu); - aFree(menu); - } else - clif->scriptmenu(sd, st->oid, StrBuf->Value(&buf)); - StrBuf->Destroy(&buf); - - if( sd->npc_menu >= 0xff ) - { - ShowWarning("buildin_prompt: Too many options specified (current=%d, max=254).\n", sd->npc_menu); - script->reportsrc(st); + if (strncmp(get_buildin_name(st), "prompt", 6) == 0) { + pc->setreg(sd, script->add_variable("@menu"), MAX_MENU_OPTIONS); + script_pushint(st, MAX_MENU_OPTIONS); // XXX: we should really be pushing -1 instead + st->state = RUN; + } else { + st->state = END; } - } - else if( sd->npc_menu == 0xff ) - {// Cancel was pressed - sd->state.menu_or_input = 0; - pc->setreg(sd, script->add_variable("@menu"), 0xff); - script_pushint(st, 0xff); - st->state = RUN; - } - else - {// return selected option + } else {// return selected option int menu = 0; sd->state.menu_or_input = 0; - for( i = 2; i <= script_lastdata(st); ++i ) - { + for( i = 2; i <= script_lastdata(st); ++i ) { text = script_getstr(st, i); sd->npc_menu -= script->menu_countoptions(text, sd->npc_menu, &menu); if( sd->npc_menu <= 0 ) break;// entry found } - pc->setreg(sd, script->add_variable("@menu"), menu); + pc->setreg(sd, script->add_variable("@menu"), menu); // TODO: throw a deprecation warning for scripts using @menu script_pushint(st, menu); st->state = RUN; } @@ -6931,7 +6855,7 @@ static BUILDIN(heal) hp=script_getnum(st,2); sp=script_getnum(st,3); - status->heal(&sd->bl, hp, sp, 1); + status->heal(&sd->bl, hp, sp, STATUS_HEAL_FORCED); return true; } /*========================================== @@ -7629,7 +7553,6 @@ static BUILDIN(viewpoint) *------------------------------------------*/ static BUILDIN(countitem) { - int nameid, i; int count = 0; struct item_data* id = NULL; @@ -7651,11 +7574,12 @@ static BUILDIN(countitem) return false; } - nameid = id->nameid; + int nameid = id->nameid; - for(i = 0; i < MAX_INVENTORY; i++) - if(sd->status.inventory[i].nameid == nameid) + for (int i = 0; i < sd->status.inventorySize; i++) { + if (sd->status.inventory[i].nameid == nameid) count += sd->status.inventory[i].amount; + } script_pushint(st,count); return true; @@ -7669,7 +7593,6 @@ static BUILDIN(countitem2) { int nameid, iden, ref, attr, c1, c2, c3, c4; int count = 0; - int i; struct item_data* id = NULL; struct map_session_data *sd = script->rid2sd(st); @@ -7699,7 +7622,7 @@ static BUILDIN(countitem2) c3 = script_getnum(st,8); c4 = script_getnum(st,9); - for(i = 0; i < MAX_INVENTORY; i++) + for (int i = 0; i < sd->status.inventorySize; i++) if (sd->status.inventory[i].nameid > 0 && sd->inventory_data[i] != NULL && sd->status.inventory[i].amount > 0 && sd->status.inventory[i].nameid == nameid && sd->status.inventory[i].identify == iden && sd->status.inventory[i].refine == ref && @@ -8833,32 +8756,23 @@ static BUILDIN(getcharid) return true; } + /*========================================== * returns the GID of an NPC *------------------------------------------*/ static BUILDIN(getnpcid) { - int num = script_getnum(st,2); - struct npc_data* nd = NULL; - - if( script_hasdata(st,3) ) - {// unique npc name - if( ( nd = npc->name2id(script_getstr(st,3)) ) == NULL ) - { - ShowError("buildin_getnpcid: No such NPC '%s'.\n", script_getstr(st,3)); - script_pushint(st,0); - return false; + if (script_hasdata(st, 2)) { + if (script_isinttype(st, 2)) { + // Deprecate old form - getnpcid(<type>{, <"npc name">}) + ShowWarning("buildin_getnpcid: Use of type is deprecated. Format - getnpcid({<\"npc name\">})\n"); + script_pushint(st, 0); + } else { + struct npc_data *nd = npc->name2id(script_getstr(st, 2)); + script_pushint(st, (nd != NULL) ? nd->bl.id : 0); } - } - - switch (num) { - case 0: - script_pushint(st,nd ? nd->bl.id : st->oid); - break; - default: - ShowError("buildin_getnpcid: invalid parameter (%d).\n", num); - script_pushint(st,0); - return false; + } else { + script_pushint(st, st->oid); } return true; @@ -9292,13 +9206,13 @@ static BUILDIN(getequipname) *------------------------------------------*/ static BUILDIN(getbrokenid) { - int i,num,id=0,brokencounter=0; + int num,id=0,brokencounter=0; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; num=script_getnum(st,2); - for(i=0; i<MAX_INVENTORY; i++) { + for (int i = 0; i < sd->status.inventorySize; i++) { if (sd->status.inventory[i].card[0] == CARD0_PET) continue; if ((sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) { @@ -9325,7 +9239,7 @@ static BUILDIN(getbrokencount) if (sd == NULL) return true; - for (i = 0; i < MAX_INVENTORY; i++) { + for (i = 0; i < sd->status.inventorySize; i++) { if (sd->status.inventory[i].card[0] == CARD0_PET) continue; if ((sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) @@ -9342,14 +9256,13 @@ static BUILDIN(getbrokencount) *------------------------------------------*/ static BUILDIN(repair) { - int i,num; int repaircounter=0; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; - num=script_getnum(st,2); - for(i=0; i<MAX_INVENTORY; i++) { + int num = script_getnum(st, 2); + for(int i = 0; i < sd->status.inventorySize; i++) { if (sd->status.inventory[i].card[0] == CARD0_PET) continue; if ((sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) { @@ -9373,12 +9286,12 @@ static BUILDIN(repair) *------------------------------------------*/ static BUILDIN(repairall) { - int i, repaircounter = 0; + int repaircounter = 0; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; - for(i = 0; i < MAX_INVENTORY; i++) + for (int i = 0; i < sd->status.inventorySize; i++) { if (sd->status.inventory[i].card[0] == CARD0_PET) continue; @@ -9801,6 +9714,25 @@ static BUILDIN(statusup2) return true; } + +/*========================================== +* Returns the number of stat points needed to change the specified stat by val. +* needed_status_point(<type>,<val>{,<char id>}); [secretdataz] +*------------------------------------------*/ +static BUILDIN(needed_status_point) +{ + int type = script_getnum(st, 2); + int val = script_getnum(st, 3);; + struct map_session_data *sd = script->rid2sd(st); + + if (sd == NULL) + script_pushint(st, 0); + else + script_pushint(st, pc->need_status_point(sd, type, val)); + + return true; +} + /// See 'doc/item_bonus.txt' /// /// bonus <bonus type>,<val1>; @@ -11435,7 +11367,7 @@ static int buildin_getunits_sub(struct block_list *bl, va_list ap) (const void *)h64BPTRSIZE(bl->id), ref); (*count)++; - return 0; + return 1; } static int buildin_getunits_sub_pc(struct map_session_data *sd, va_list ap) @@ -11507,18 +11439,10 @@ static BUILDIN(getunits) int16 x2 = script_getnum(st, 8); int16 y2 = script_getnum(st, 9); - // FIXME: map_foreachinarea does NOT stop iterating when the callback - // function returns -1. we still limit the array size, but - // this doesn't break the loop. We need a foreach function - // that behaves like map_foreachiddb, but for areas - map->foreachinarea(buildin_getunits_sub, m, x1, y1, x2, y2, type, + map->forcountinarea(buildin_getunits_sub, m, x1, y1, x2, y2, limit, type, st, sd, id, start, &count, limit, name, ref, type); } else { - // FIXME: map_foreachinmap does NOT stop iterating when the callback - // function returns -1. we still limit the array size, but - // this doesn't break the loop. We need a foreach function - // that behaves like map_foreachiddb, but for maps - map->foreachinmap(buildin_getunits_sub, m, type, + map->forcountinmap(buildin_getunits_sub, m, limit, type, st, sd, id, start, &count, limit, name, ref, type); } } else { @@ -14874,10 +14798,10 @@ static BUILDIN(getinventorylist) struct map_session_data *sd = script->rid2sd(st); char card_var[SCRIPT_VARNAME_LENGTH]; - int i,j=0,k; + int j=0,k; if(!sd) return true; - for(i=0;i<MAX_INVENTORY;i++) { + for (int i = 0;i < sd->status.inventorySize; i++) { if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0) { pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_id"), j),sd->status.inventory[i].nameid); pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_amount"), j),sd->status.inventory[i].amount); @@ -14968,10 +14892,9 @@ static BUILDIN(getskilllist) static BUILDIN(clearitem) { struct map_session_data *sd = script->rid2sd(st); - int i; if (sd == NULL) return true; - for (i=0; i<MAX_INVENTORY; i++) { + for (int i = 0; i < sd->status.inventorySize; i++) { if (sd->status.inventory[i].amount) { pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_SCRIPT); } @@ -15742,19 +15665,18 @@ static BUILDIN(getmercinfo) *------------------------------------------*/ static BUILDIN(checkequipedcard) { - int n,i,c=0; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; - c = script_getnum(st,2); + int c = script_getnum(st,2); - for( i=0; i<MAX_INVENTORY; i++) { + for (int i = 0; i < sd->status.inventorySize; i++) { if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount && sd->inventory_data[i]) { if (itemdb_isspecial(sd->status.inventory[i].card[0])) continue; - for(n=0;n<sd->inventory_data[i]->slot;n++) { + for (int n = 0; n < sd->inventory_data[i]->slot; n++) { if(sd->status.inventory[i].card[n]==c) { script_pushint(st,1); return true; @@ -15830,6 +15752,29 @@ static BUILDIN(message) return true; } +static BUILDIN(servicemessage) +{ + struct map_session_data *sd = NULL; + + if (script_hasdata(st, 4)) { + if (script_isstringtype(st, 4)) + sd = script->nick2sd(st, script_getstr(st, 4)); + else + sd = script->id2sd(st, script_getnum(st, 4)); + } else { + sd = script->rid2sd(st); + } + + if (sd == NULL) + return true; + + const char *message = script_getstr(st, 2); + const int color = script_getnum(st, 3); + clif->serviceMessageColor(sd, color, message); + + return true; +} + /*========================================== * npctalk (sends message to surrounding area) * usage: npctalk("<message>"{, "<npc name>"{, <show_name>}}); @@ -16599,9 +16544,9 @@ static BUILDIN(equip) ShowError("wrong item ID : equipitem(%d)\n",nameid); return false; } - ARR_FIND( 0, MAX_INVENTORY, i, sd->status.inventory[i].nameid == nameid && sd->status.inventory[i].equip == 0 ); - if( i < MAX_INVENTORY ) - pc->equipitem(sd,i,item_data->equip); + ARR_FIND(0, sd->status.inventorySize, i, sd->status.inventory[i].nameid == nameid && sd->status.inventory[i].equip == 0); + if (i < sd->status.inventorySize) + pc->equipitem(sd, i, item_data->equip); return true; } @@ -16659,21 +16604,21 @@ static BUILDIN(equip2) c2 = script_getnum(st, 7); c3 = script_getnum(st, 8); - ARR_FIND( 0, MAX_INVENTORY, i,( sd->status.inventory[i].equip == 0 && + ARR_FIND(0, sd->status.inventorySize, i, (sd->status.inventory[i].equip == 0 && sd->status.inventory[i].nameid == nameid && sd->status.inventory[i].refine == ref && sd->status.inventory[i].attribute == attr && sd->status.inventory[i].card[0] == c0 && sd->status.inventory[i].card[1] == c1 && sd->status.inventory[i].card[2] == c2 && - sd->status.inventory[i].card[3] == c3 ) ); + sd->status.inventory[i].card[3] == c3)); - if( i < MAX_INVENTORY ) { + if (i < sd->status.inventorySize) { script_pushint(st,1); pc->equipitem(sd,i,item_data->equip); - } - else + } else { script_pushint(st,0); + } return true; } @@ -16860,6 +16805,63 @@ static BUILDIN(getdatatype) return true; } +static BUILDIN(data_to_string) +{ + if (script_hasdata(st, 2)) { + struct script_data *data = script_getdata(st, 2); + + if (data_isstring(data)) { + script_pushcopy(st, 2); + } else if (data_isint(data)) { + char *str = NULL; + + CREATE(str, char, 20); + safesnprintf(str, 20, "%"PRId64"", data->u.num); + script_pushstr(st, str); + } else if (data_islabel(data)) { + const char *str = ""; + + // XXX: because all we have is the label pos we can't be sure which + // one is the correct label if more than one has the same pos. + // We might want to store both the pos and str_data index in + // data->u.num, similar to how C_NAME stores both the array + // index and str_data index in u.num with bitmasking. This + // would also avoid the awkward for() loops as we could + // directly access the string with script->get_str(). + + if (st->oid) { + struct npc_data *nd = map->id2nd(st->oid); + + for (int i = 0; i < nd->u.scr.label_list_num; ++i) { + if (nd->u.scr.label_list[i].pos == data->u.num) { + str = nd->u.scr.label_list[i].name; + break; + } + } + } else { + for (int i = LABEL_START; script->str_data[i].next != 0; i = script->str_data[i].next) { + if (script->str_data[i].label == data->u.num) { + str = script->get_str(i); + break; + } + } + } + + script_pushconststr(st, str); + } else if (data_isreference(data)) { + script_pushstrcopy(st, reference_getname(data)); + } else { + ShowWarning("script:data_to_string: unknown data type!\n"); + script->reportdata(data); + script_pushconststr(st, ""); + } + } else { + script_pushconststr(st, ""); // NIL + } + + return true; +} + //======================================================= // chr <int> //------------------------------------------------------- @@ -18876,7 +18878,7 @@ static BUILDIN(setunitdata) md->level = val; break; case UDT_HP: - status->set_hp(bl, (unsigned int) val, 0); + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); clif->charnameack(0, &md->bl); break; case UDT_MAXHP: @@ -18884,7 +18886,7 @@ static BUILDIN(setunitdata) clif->charnameack(0, &md->bl); break; case UDT_SP: - status->set_sp(bl, (unsigned int) val, 0); + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXSP: md->status.max_sp = (unsigned int) val; @@ -19045,13 +19047,13 @@ static BUILDIN(setunitdata) hd->homunculus.level = (short) val; break; case UDT_HP: - status->set_hp(bl, (unsigned int) val, 0); + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXHP: hd->homunculus.max_hp = val; break; case UDT_SP: - status->set_sp(bl, (unsigned int) val, 0); + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXSP: hd->homunculus.max_sp = val; @@ -19184,13 +19186,13 @@ static BUILDIN(setunitdata) pd->pet.level = (short) val; break; case UDT_HP: - status->set_hp(bl, (unsigned int) val, 0); + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXHP: pd->status.max_hp = (unsigned int) val; break; case UDT_SP: - status->set_sp(bl, (unsigned int) val, 0); + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXSP: pd->status.max_sp = (unsigned int) val; @@ -19318,13 +19320,13 @@ static BUILDIN(setunitdata) mc->base_status.size = (unsigned char) val; break; case UDT_HP: - status->set_hp(bl, (unsigned int) val, 0); + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXHP: mc->base_status.max_hp = (unsigned int) val; break; case UDT_SP: - status->set_sp(bl, (unsigned int) val, 0); + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXSP: mc->base_status.max_sp = (unsigned int) val; @@ -19452,13 +19454,13 @@ static BUILDIN(setunitdata) ed->base_status.size = (unsigned char) val; break; case UDT_HP: - status->set_hp(bl, (unsigned int) val, 0); + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXHP: ed->base_status.max_hp = (unsigned int) val; break; case UDT_SP: - status->set_sp(bl, (unsigned int) val, 0); + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXSP: ed->base_status.max_sp = (unsigned int) val; @@ -19584,13 +19586,13 @@ static BUILDIN(setunitdata) nd->level = (unsigned short) val; break; case UDT_HP: - status->set_hp(bl, (unsigned int) val, 0); + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXHP: nd->status.max_hp = (unsigned int) val; break; case UDT_SP: - status->set_sp(bl, (unsigned int) val, 0); + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXSP: nd->status.max_sp = (unsigned int) val; @@ -20901,7 +20903,7 @@ static BUILDIN(mercenary_heal) hp = script_getnum(st,2); sp = script_getnum(st,3); - status->heal(&sd->md->bl, hp, sp, 0); + status->heal(&sd->md->bl, hp, sp, STATUS_HEAL_DEFAULT); return true; } @@ -23730,7 +23732,7 @@ static BUILDIN(bg_join_team) *------------------------------------------*/ static BUILDIN(countbound) { - int i, type, j=0, k=0; + int type, j=0, k=0; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -23738,7 +23740,7 @@ static BUILDIN(countbound) type = script_hasdata(st,2)?script_getnum(st,2):0; - for(i=0;i<MAX_INVENTORY;i++) { + for (int i = 0; i < sd->status.inventorySize; i++) { if(sd->status.inventory[i].nameid > 0 && ( (!type && sd->status.inventory[i].bound > 0) || (type && sd->status.inventory[i].bound == type) @@ -23784,20 +23786,21 @@ static BUILDIN(checkbound) ShowError("script_checkbound: Not a valid bind type! Type=%d\n", bound_type); } - ARR_FIND( 0, MAX_INVENTORY, i, (sd->status.inventory[i].nameid == nameid && + ARR_FIND(0, sd->status.inventorySize, i, (sd->status.inventory[i].nameid == nameid && ( sd->status.inventory[i].refine == (script_hasdata(st,4)? script_getnum(st,4) : sd->status.inventory[i].refine) ) && ( sd->status.inventory[i].attribute == (script_hasdata(st,5)? script_getnum(st,5) : sd->status.inventory[i].attribute) ) && ( sd->status.inventory[i].card[0] == (script_hasdata(st,6)? script_getnum(st,6) : sd->status.inventory[i].card[0]) ) && ( sd->status.inventory[i].card[1] == (script_hasdata(st,7)? script_getnum(st,7) : sd->status.inventory[i].card[1]) ) && ( sd->status.inventory[i].card[2] == (script_hasdata(st,8)? script_getnum(st,8) : sd->status.inventory[i].card[2]) ) && ( sd->status.inventory[i].card[3] == (script_hasdata(st,9)? script_getnum(st,9) : sd->status.inventory[i].card[3]) ) && - ((sd->status.inventory[i].bound > 0 && !bound_type) || sd->status.inventory[i].bound == bound_type )) ); + ((sd->status.inventory[i].bound > 0 && !bound_type) || sd->status.inventory[i].bound == bound_type))); - if( i < MAX_INVENTORY ){ + if (i < sd->status.inventorySize) { script_pushint(st, sd->status.inventory[i].bound); return true; - } else + } else { script_pushint(st,0); + } return true; } @@ -23934,6 +23937,7 @@ static BUILDIN(sellitem) struct item_data *it; int i = 0, id = script_getnum(st,2); int value = 0; + int value2 = 0; int qty = 0; if( !(nd = map->id2nd(st->oid)) ) { @@ -23944,17 +23948,43 @@ static BUILDIN(sellitem) return false; } - value = script_hasdata(st,3) ? script_getnum(st, 3) : it->value_buy; - if( value == -1 ) - value = it->value_buy; - - if( !nd->u.scr.shop ) - npc->trader_update(nd->src_id?nd->src_id:nd->bl.id); - else {/* no need to run this if its empty */ - for( i = 0; i < nd->u.scr.shop->items; i++ ) { - if( nd->u.scr.shop->item[i].nameid == id ) - break; + if (!nd->u.scr.shop) { + npc->trader_update(nd->src_id ? nd->src_id : nd->bl.id); + if (nd->u.scr.shop->type == NST_BARTER) { + if (!script_hasdata(st, 5)) { + ShowError("buildin_sellitem: invalid number of parameters for barter-type shop!\n"); + return false; + } + value = script_getnum(st, 4); + value2 = script_getnum(st, 5); } + } else {/* no need to run this if its empty */ + if (nd->u.scr.shop->type == NST_BARTER) { + if (!script_hasdata(st, 5)) { + ShowError("buildin_sellitem: invalid number of parameters for barter-type shop!\n"); + return false; + } + value = script_getnum(st, 4); + value2 = script_getnum(st, 5); + for (i = 0; i < nd->u.scr.shop->items; i++) { + const struct npc_item_list *const item = &nd->u.scr.shop->item[i]; + if (item->nameid == id && item->value == value && item->value2 == value2) { + break; + } + } + } else { + for (i = 0; i < nd->u.scr.shop->items; i++) { + if (nd->u.scr.shop->item[i].nameid == id) { + break; + } + } + } + } + + if (nd->u.scr.shop->type != NST_BARTER) { + value = script_hasdata(st,3) ? script_getnum(st, 3) : it->value_buy; + if( value == -1 ) + value = it->value_buy; } if( nd->u.scr.shop->type == NST_MARKET ) { @@ -23969,19 +23999,29 @@ static BUILDIN(sellitem) it->name, id, value, (int)(value*0.75), it->value_sell, (int)(it->value_sell*1.24), nd->exname, nd->path); } - if( i != nd->u.scr.shop->items ) { + if (nd->u.scr.shop->type == NST_BARTER) { + qty = script_getnum(st, 3); + if (qty < -1 || value <= 0 || value2 <= 0) { + ShowError("buildin_sellitem: invalid parameters for barter-type shop!\n"); + return false; + } + } + + if (i != nd->u.scr.shop->items) { nd->u.scr.shop->item[i].value = value; nd->u.scr.shop->item[i].qty = qty; - if( nd->u.scr.shop->type == NST_MARKET ) /* has been manually updated, make it reflect on sql */ - npc->market_tosql(nd,i); + if (nd->u.scr.shop->type == NST_MARKET) /* has been manually updated, make it reflect on sql */ + npc->market_tosql(nd, i); + else if (nd->u.scr.shop->type == NST_BARTER) /* has been manually updated, make it reflect on sql */ + npc->barter_tosql(nd, i); } else { - for( i = 0; i < nd->u.scr.shop->items; i++ ) { - if( nd->u.scr.shop->item[i].nameid == 0 ) + for (i = 0; i < nd->u.scr.shop->items; i++) { + if (nd->u.scr.shop->item[i].nameid == 0) break; } - if( i == nd->u.scr.shop->items ) { - if( nd->u.scr.shop->items == USHRT_MAX ) { + if (i == nd->u.scr.shop->items) { + if (nd->u.scr.shop->items == USHRT_MAX) { ShowWarning("buildin_sellitem: Can't add %s (%s/%s), shop list is full!\n", it->name, nd->exname, nd->path); return false; } @@ -23991,6 +24031,7 @@ static BUILDIN(sellitem) nd->u.scr.shop->item[i].nameid = it->nameid; nd->u.scr.shop->item[i].value = value; + nd->u.scr.shop->item[i].value2 = value2; nd->u.scr.shop->item[i].qty = qty; } @@ -24007,35 +24048,55 @@ static BUILDIN(sellitem) static BUILDIN(stopselling) { struct npc_data *nd; - int i, id = script_getnum(st,2); + int i, id = script_getnum(st, 2); - if( !(nd = map->id2nd(st->oid)) || !nd->u.scr.shop ) { + if (!(nd = map->id2nd(st->oid)) || !nd->u.scr.shop) { ShowWarning("buildin_stopselling: trying to run without a proper NPC!\n"); return false; } - for( i = 0; i < nd->u.scr.shop->items; i++ ) { - if( nd->u.scr.shop->item[i].nameid == id ) - break; + if (nd->u.scr.shop->type == NST_BARTER) { + if (!script_hasdata(st, 4)) { + ShowError("buildin_stopselling: called with wrong number of arguments\n"); + return false; + } + const int id2 = script_getnum(st, 3); + const int amount2 = script_getnum(st, 4); + for (i = 0; i < nd->u.scr.shop->items; i++) { + const struct npc_item_list *const item = &nd->u.scr.shop->item[i]; + if (item->nameid == id && item->value == id2 && item->value2 == amount2) { + break; + } + } + } else { + for (i = 0; i < nd->u.scr.shop->items; i++) { + if (nd->u.scr.shop->item[i].nameid == id) { + break; + } + } } - if( i != nd->u.scr.shop->items ) { + if (i != nd->u.scr.shop->items) { int cursor; - if( nd->u.scr.shop->type == NST_MARKET ) - npc->market_delfromsql(nd,i); + if (nd->u.scr.shop->type == NST_MARKET) + npc->market_delfromsql(nd, i); + if (nd->u.scr.shop->type == NST_BARTER) + npc->barter_delfromsql(nd, i); nd->u.scr.shop->item[i].nameid = 0; nd->u.scr.shop->item[i].value = 0; + nd->u.scr.shop->item[i].value2 = 0; nd->u.scr.shop->item[i].qty = 0; - for( i = 0, cursor = 0; i < nd->u.scr.shop->items; i++ ) { - if( nd->u.scr.shop->item[i].nameid == 0 ) + for (i = 0, cursor = 0; i < nd->u.scr.shop->items; i++) { + if (nd->u.scr.shop->item[i].nameid == 0) continue; - if( cursor != i ) { + if (cursor != i) { nd->u.scr.shop->item[cursor].nameid = nd->u.scr.shop->item[i].nameid; nd->u.scr.shop->item[cursor].value = nd->u.scr.shop->item[i].value; + nd->u.scr.shop->item[cursor].value2 = nd->u.scr.shop->item[i].value2; nd->u.scr.shop->item[cursor].qty = nd->u.scr.shop->item[i].qty; } @@ -24101,7 +24162,8 @@ static BUILDIN(tradertype) nd->u.scr.shop->item[i].value = 0; nd->u.scr.shop->item[i].qty = 0; } - npc->market_delfromsql(nd,USHRT_MAX); + npc->market_delfromsql(nd, INT_MAX); + npc->barter_delfromsql(nd, INT_MAX); } #if PACKETVER < 20131223 @@ -24110,6 +24172,12 @@ static BUILDIN(tradertype) script->reportsrc(st); } #endif +#if PACKETVER_ZERO_NUM < 20181226 + if (type == NST_BARTER) { + ShowWarning("buildin_tradertype: NST_BARTER is only available with PACKETVER_ZERO_NUM 20181226 or newer!\n"); + script->reportsrc(st); + } +#endif if( nd->u.scr.shop ) nd->u.scr.shop->type = type; @@ -24153,8 +24221,8 @@ static BUILDIN(shopcount) } else if ( !nd->u.scr.shop || !nd->u.scr.shop->items ) { ShowWarning("buildin_shopcount(%d): trying to use without any items!\n",id); return false; - } else if ( nd->u.scr.shop->type != NST_MARKET ) { - ShowWarning("buildin_shopcount(%d): trying to use on a non-NST_MARKET shop!\n",id); + } else if (nd->u.scr.shop->type != NST_MARKET && nd->u.scr.shop->type != NST_BARTER) { + ShowWarning("buildin_shopcount(%d): trying to use on a non-NST_MARKET and non-NST_BARTER shop!\n",id); return false; } @@ -24885,6 +24953,100 @@ static BUILDIN(itempreview) return true; } +// insert or remove card into equipped item +static BUILDIN(enchantitem) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + const int pos = script_getnum(st, 2); + if ((pos < EQI_ACC_L || pos > EQI_HAND_R) && pos != EQI_AMMO) { + ShowError("Wrong equip position: %d\n", pos); + script->reportfunc(st); + script->reportsrc(st); + script_pushint(st, false); + return true; + } + const int cardId = script_getnum(st, 4); + struct item_data *it = itemdb->exists(cardId); + if (it == NULL || it->type != IT_CARD) { + ShowError("Item id is not card or not exists: %d\n", cardId); + script->reportfunc(st); + script->reportsrc(st); + script_pushint(st, false); + return true; + } + const int n = sd->equip_index[pos]; + if (n < 0) { + ShowError("Item in equipment slot %d is not equipped\n", pos); + script->reportfunc(st); + script->reportsrc(st); + script_pushint(st, false); + return true; + } + const int cardSlot = script_getnum(st, 3); + if (cardSlot < 0 || cardSlot >= MAX_SLOTS) { + ShowError("Wrong card slot %d. Must be in range 0-3.\n", cardSlot); + script->reportfunc(st); + script->reportsrc(st); + script_pushint(st, false); + return true; + } + const bool res = clif->enchant_equipment(sd, pc->equip_pos[pos], cardSlot, cardId); + if (res) { + logs->pick_pc(sd, LOG_TYPE_CARD, -1, &sd->status.inventory[n],sd->inventory_data[n]); + sd->status.inventory[n].card[cardSlot] = cardId; + logs->pick_pc(sd, LOG_TYPE_CARD, 1, &sd->status.inventory[n],sd->inventory_data[n]); + status_calc_pc(sd, SCO_NONE); + } + script_pushint(st, res); + return true; +} + +// send ack to inventory expand request +static BUILDIN(expandInventoryAck) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + int itemId = 0; + if (script_hasdata(st, 3)) { + itemId = script_getnum(st, 3); + } + clif->inventoryExpandAck(sd, script_getnum(st, 2), itemId); + return true; +} + +// send final ack to inventory expand request +static BUILDIN(expandInventoryResult) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + clif->inventoryExpandResult(sd, script_getnum(st, 2)); + return true; +} + +// adjust player inventory size to given value positive or negative +static BUILDIN(expandInventory) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + script_pushint(st, pc->expandInventory(sd, script_getnum(st, 2))); + return true; +} + +// return current player inventory size +static BUILDIN(getInventorySize) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + script_pushint(st, sd->status.inventorySize); + return true; +} + /** * Adds a built-in script function. * @@ -25053,7 +25215,7 @@ static void script_parse_builtin(void) BUILDIN_DEF(close2,""), BUILDIN_DEF(menu,"sl*"), BUILDIN_DEF(select,"s*"), //for future jA script compatibility - BUILDIN_DEF(prompt,"s*"), + BUILDIN_DEF2(select, "prompt", "s*"), // BUILDIN_DEF(goto,"l"), BUILDIN_DEF(callsub,"l*"), @@ -25103,7 +25265,7 @@ static void script_parse_builtin(void) BUILDIN_DEF(readparam,"i?"), BUILDIN_DEF(setparam,"ii?"), BUILDIN_DEF(getcharid,"i?"), - BUILDIN_DEF(getnpcid,"i?"), + BUILDIN_DEF(getnpcid, "?"), BUILDIN_DEF(getpartyname,"i"), BUILDIN_DEF(getpartymember,"i?"), BUILDIN_DEF(getpartyleader,"i?"), @@ -25131,6 +25293,7 @@ static void script_parse_builtin(void) BUILDIN_DEF(downrefitem,"i?"), BUILDIN_DEF(statusup,"i"), BUILDIN_DEF(statusup2,"ii"), + BUILDIN_DEF(needed_status_point,"ii?"), BUILDIN_DEF(bonus,"iv"), BUILDIN_DEF2(bonus,"bonus2","ivi"), BUILDIN_DEF2(bonus,"bonus3","ivii"), @@ -25290,6 +25453,7 @@ static void script_parse_builtin(void) BUILDIN_DEF2(atcommand,"charcommand","s"), // [MouseJstr] BUILDIN_DEF(movenpc,"sii?"), // [MouseJstr] BUILDIN_DEF(message,"vs"), // [MouseJstr] + BUILDIN_DEF(servicemessage, "si?"), BUILDIN_DEF(npctalk,"s??"), // [Valaris][Murilo BiO] BUILDIN_DEF(mobcount,"ss"), BUILDIN_DEF(getlook,"i"), @@ -25335,6 +25499,8 @@ static void script_parse_builtin(void) BUILDIN_DEF(charat,"si"), BUILDIN_DEF(isstr,"v"), BUILDIN_DEF(getdatatype, "?"), + BUILDIN_DEF(data_to_string, "?"), + BUILDIN_DEF2(getd, "string_to_data", "?"), BUILDIN_DEF(chr,"i"), BUILDIN_DEF(ord,"s"), BUILDIN_DEF(setchar,"ssi"), @@ -25582,8 +25748,8 @@ static void script_parse_builtin(void) /* New Shop Support */ BUILDIN_DEF(openshop,"?"), - BUILDIN_DEF(sellitem,"i??"), - BUILDIN_DEF(stopselling,"i"), + BUILDIN_DEF(sellitem,"i???"), + BUILDIN_DEF(stopselling,"i??"), BUILDIN_DEF(setcurrency,"i?"), BUILDIN_DEF(tradertype,"i"), BUILDIN_DEF(purchaseok,""), @@ -25622,6 +25788,11 @@ static void script_parse_builtin(void) BUILDIN_DEF(changecamera, "iii?"), BUILDIN_DEF(itempreview, "i"), + BUILDIN_DEF(enchantitem, "iii"), + BUILDIN_DEF(expandInventoryAck, "i?"), + BUILDIN_DEF(expandInventoryResult, "i"), + BUILDIN_DEF(expandInventory, "i"), + BUILDIN_DEF(getInventorySize, ""), }; int i, len = ARRAYLENGTH(BUILDIN); RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up @@ -25661,13 +25832,16 @@ static void script_hardcoded_constants(void) script->set_constant("MAX_LEVEL",MAX_LEVEL,false, false); script->set_constant("MAX_STORAGE",MAX_STORAGE,false, false); script->set_constant("MAX_GUILD_STORAGE",MAX_GUILD_STORAGE,false, false); - script->set_constant("MAX_CART",MAX_INVENTORY,false, false); + script->set_constant("MAX_CART", MAX_CART, false, false); script->set_constant("MAX_INVENTORY",MAX_INVENTORY,false, false); + script->set_constant("FIXED_INVENTORY_SIZE", FIXED_INVENTORY_SIZE, false, false); script->set_constant("MAX_ZENY",MAX_ZENY,false, false); script->set_constant("MAX_BANK_ZENY", MAX_BANK_ZENY, false, false); script->set_constant("MAX_BG_MEMBERS",MAX_BG_MEMBERS,false, false); script->set_constant("MAX_CHAT_USERS",MAX_CHAT_USERS,false, false); script->set_constant("MAX_REFINE",MAX_REFINE,false, false); + script->set_constant("MAX_MENU_OPTIONS", MAX_MENU_OPTIONS, false, false); + script->set_constant("MAX_MENU_LENGTH", MAX_MENU_LENGTH, false, false); script->constdb_comment("status options"); script->set_constant("Option_Nothing",OPTION_NOTHING,false, false); @@ -26042,6 +26216,26 @@ static void script_hardcoded_constants(void) script->set_constant("ITR_NOAUCTION", ITR_NOAUCTION, false, false); script->set_constant("ITR_ALL", ITR_ALL, false, false); + script->constdb_comment("inventory expand ack responds"); + script->set_constant("EXPAND_INV_ASK_CONFIRMATION", EXPAND_INVENTORY_ASK_CONFIRMATION, false, false); + script->set_constant("EXPAND_INV_FAILED", EXPAND_INVENTORY_FAILED, false, false); + script->set_constant("EXPAND_INV_OTHER_WORK", EXPAND_INVENTORY_OTHER_WORK, false, false); + script->set_constant("EXPAND_INV_MISSING_ITEM", EXPAND_INVENTORY_MISSING_ITEM, false, false); + script->set_constant("EXPAND_INV_MAX_SIZE", EXPAND_INVENTORY_MAX_SIZE, false, false); + + script->constdb_comment("inventory expand final responds"); + script->set_constant("EXPAND_INV_RESULT_SUCCESS", EXPAND_INVENTORY_RESULT_SUCCESS, false, false); + script->set_constant("EXPAND_INV_RESULT_FAILED", EXPAND_INVENTORY_RESULT_FAILED, false, false); + script->set_constant("EXPAND_INV_RESULT_OTHER_WORK", EXPAND_INVENTORY_RESULT_OTHER_WORK, false, false); + script->set_constant("EXPAND_INV_RESULT_MISSING_ITEM", EXPAND_INVENTORY_RESULT_MISSING_ITEM, false, false); + script->set_constant("EXPAND_INV_RESULT_MAX_SIZE", EXPAND_INVENTORY_RESULT_MAX_SIZE, false, false); + + script->constdb_comment("trader type"); + script->set_constant("NST_ZENY", NST_ZENY, false, false); + script->set_constant("NST_CASH", NST_CASH, false, false); + script->set_constant("NST_MARKET", NST_MARKET, false, false); + script->set_constant("NST_CUSTOM", NST_CUSTOM, false, false); + script->set_constant("NST_BARTER", NST_BARTER, false, false); script->constdb_comment("Renewal"); #ifdef RENEWAL |