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