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.c811
1 files changed, 491 insertions, 320 deletions
diff --git a/src/map/script.c b/src/map/script.c
index 6c09bc6c9..41f21cd72 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -613,6 +613,18 @@ static int script_add_str(const char *p)
return script->str_num++;
}
+static int script_add_variable(const char *varname)
+{
+ int key = script->search_str(varname);
+
+ if (key < 0) {
+ key = script->add_str(varname);
+ script->str_data[key].type = C_NAME;
+ }
+
+ return key;
+}
+
/**
* Appends 1 byte to the script buffer.
*
@@ -1366,6 +1378,11 @@ static const char *parse_simpleexpr_name(const char *p)
disp_error_message("parse_simpleexpr: unmatched ']'", p);
++p;
script->addc(C_FUNC);
+ } else if (script->str_data[l].type == C_INT) {
+ script->addc(C_NAME);
+ script->addb(l);
+ script->addb(l >> 8);
+ script->addb(l >> 16);
} else {
script->addl(l);
}
@@ -2886,8 +2903,7 @@ static struct script_data *get_val(struct script_state *st, struct script_data *
return data;
}
- //##TODO use reference_tovariable(data) when it's confirmed that it works [FlavioJS]
- if (!reference_toconstant(data) && not_server_variable(prefix) && reference_getref(data) == NULL) {
+ if (((reference_tovariable(data) && not_server_variable(prefix)) || reference_toparam(data)) && reference_getref(data) == NULL) {
sd = script->rid2sd(st);
if (sd == NULL) {// needs player attached
if (postfix == '$') {// string variable
@@ -3032,6 +3048,10 @@ static const void *get_val2(struct script_state *st, int64 uid, struct reg_db *r
script->get_val(st, data);
if (data->type == C_INT) // u.num is int32 because it comes from script->get_val
return (const void *)h64BPTRSIZE((int32)data->u.num);
+ else if (data_isreference(data) && reference_toconstant(data))
+ return (const void *)h64BPTRSIZE((int32)reference_getconstant(data));
+ else if (data_isreference(data) && reference_toparam(data))
+ return (const void *)h64BPTRSIZE((int32)reference_getparamtype(data));
else
return (const void *)h64BPTRSIZE(data->u.str);
}
@@ -3296,95 +3316,28 @@ static void set_reg_npcscope_str(struct script_state *st, struct reg_db *n, int6
static void set_reg_pc_ref_str(struct script_state *st, struct reg_db *n, int64 num, const char *name, const char *str)
{
- struct script_reg_str *p = NULL;
- unsigned int index = script_getvaridx(num);
-
- nullpo_retv(n);
-
- if ((p = i64db_get(n->vars, num)) != NULL) {
- if (str[0]) {
- if (p->value) {
- aFree(p->value);
- } else if (index) {
- script->array_update(n, num, false);
- }
- p->value = aStrdup(str);
- } else {
- p->value = NULL;
- if (index) {
- script->array_update(n, num, true);
- }
- }
-
- if (!pc->reg_load) {
- p->flag.update = 1;
- }
- } else if (str[0]) {
- struct DBData prev;
- if (index) {
- script->array_update(n, num, false);
- }
-
- p = ers_alloc(pc->str_reg_ers, struct script_reg_str);
- p->value = aStrdup(str);
+ struct DBIterator *iter = db_iterator(map->pc_db);
- if (!pc->reg_load) {
- p->flag.update = 1;
- }
- p->flag.type = 1;
-
- if(n->vars->put(n->vars, DB->i642key(num), DB->ptr2data(p), &prev)) {
- p = DB->data2ptr(&prev);
- if (p->value) {
- aFree(p->value);
- }
- ers_free(pc->str_reg_ers, p);
+ for (struct map_session_data *sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter)) {
+ if (sd != NULL && n == &sd->regs) {
+ pc->setregistry_str(sd, num, str);
+ break;
}
}
+ dbi_destroy(iter);
}
static void set_reg_pc_ref_num(struct script_state *st, struct reg_db *n, int64 num, const char *name, int val)
{
- struct script_reg_num *p = NULL;
- unsigned int index = script_getvaridx(num);
-
- nullpo_retv(n);
-
- if ((p = i64db_get(n->vars, num)) != NULL) {
- if (val) {
- if (!p->value && index) {
- script->array_update(n, num, false);
- }
- p->value = val;
- } else {
- p->value = 0;
- if (index) {
- script->array_update(n, num, true);
- }
- }
-
- if (!pc->reg_load) {
- p->flag.update = 1;
- }
- } else if (val) {
- struct DBData prev;
- if (index) {
- script->array_update(n, num, false);
- }
-
- p = ers_alloc(pc->num_reg_ers, struct script_reg_num);
- p->value = val;
-
- if (!pc->reg_load) {
- p->flag.update = 1;
- }
- p->flag.type = 1;
+ struct DBIterator *iter = db_iterator(map->pc_db);
- if(n->vars->put(n->vars, DB->i642key(num), DB->ptr2data(p), &prev)) {
- p = DB->data2ptr(&prev);
- ers_free(pc->num_reg_ers, p);
+ for (struct map_session_data *sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter)) {
+ if (sd != NULL && n == &sd->regs) {
+ pc->setregistry(sd, num, val);
+ break;
}
}
+ dbi_destroy(iter);
}
static void set_reg_npcscope_num(struct script_state *st, struct reg_db *n, int64 num, const char *name, int val)
@@ -3460,6 +3413,19 @@ static int set_reg(struct script_state *st, struct map_session_data *sd, int64 n
nullpo_ret(name);
prefix = name[0];
+ if (script->str_data[script_getvarid(num)].type != C_NAME && script->str_data[script_getvarid(num)].type != C_PARAM) {
+ ShowError("script:set_reg: not a variable! '%s'\n", name);
+
+ // to avoid this don't do script->add_str(") without setting its type.
+ // either use script->add_variable() or manually set the type
+
+ if (st) {
+ script->reportsrc(st);
+ st->state = END;
+ }
+ return 0;
+ }
+
if (strlen(name) > SCRIPT_VARNAME_LENGTH) {
ShowError("script:set_reg: variable name too long. '%s'\n", name);
if (st) {
@@ -3579,12 +3545,26 @@ static int set_reg(struct script_state *st, struct map_session_data *sd, int64 n
static int set_var(struct map_session_data *sd, char *name, void *val)
{
- return script->set_reg(NULL, sd, reference_uid(script->add_str(name),0), name, val, NULL);
+ int key = script->add_variable(name);
+
+ if (script->str_data[key].type != C_NAME) {
+ ShowError("script:setd_sub: `%s` is already used by something that is not a variable.\n", name);
+ return -1;
+ }
+
+ return script->set_reg(NULL, sd, reference_uid(key, 0), name, val, NULL);
}
static void setd_sub(struct script_state *st, struct map_session_data *sd, const char *varname, int elem, const void *value, struct reg_db *ref)
{
- script->set_reg(st, sd, reference_uid(script->add_str(varname),elem), varname, value, ref);
+ int key = script->add_variable(varname);
+
+ if (script->str_data[key].type != C_NAME) {
+ ShowError("script:setd_sub: `%s` is already used by something that is not a variable.\n", varname);
+ return;
+ }
+
+ script->set_reg(st, sd, reference_uid(key, elem), varname, value, ref);
}
/// Converts the data to a string
@@ -4119,10 +4099,10 @@ static void op_2str(struct script_state *st, int op, const char *s1, const char
int i;
for (i = 0; i < offsetcount; i++) {
libpcre->get_substring(s1, offsets, offsetcount, i, &pcre_match);
- mapreg->setregstr(reference_uid(script->add_str("$@regexmatch$"), i), pcre_match);
+ mapreg->setregstr(reference_uid(script->add_variable("$@regexmatch$"), i), pcre_match);
libpcre->free_substring(pcre_match);
}
- mapreg->setreg(script->add_str("$@regexmatchcount"), i);
+ mapreg->setreg(script->add_variable("$@regexmatchcount"), i);
a = offsetcount;
} else { // C_RE_NE
a = (offsetcount == 0);
@@ -4905,7 +4885,12 @@ static void script_cleararray_pc(struct map_session_data *sd, const char *varnam
unsigned int i, *list = NULL, size = 0;
int key;
- key = script->add_str(varname);
+ key = script->add_variable(varname);
+
+ if (script->str_data[key].type != C_NAME) {
+ ShowError("script:cleararray_pc: `%s` is already used by something that is not a variable.\n", varname);
+ return;
+ }
if( !(src = script->array_src(NULL,sd,varname,NULL) ) )
return;
@@ -4935,7 +4920,12 @@ static void script_setarray_pc(struct map_session_data *sd, const char *varname,
return;
}
- key = ( refcache && refcache[0] ) ? refcache[0] : script->add_str(varname);
+ key = ( refcache && refcache[0] ) ? refcache[0] : script->add_variable(varname);
+
+ if (script->str_data[key].type != C_NAME) {
+ ShowError("script:setarray_pc: `%s` is already used by something that is not a variable.\n", varname);
+ return;
+ }
script->set_reg(NULL,sd,reference_uid(key, idx),varname,value,NULL);
@@ -5908,10 +5898,14 @@ static bool script_sprintf_helper(struct script_state *st, int start, struct Str
static BUILDIN(mes)
{
struct map_session_data *sd = script->rid2sd(st);
+
if (sd == NULL)
return true;
- clif->scriptmes(sd, st->oid, script_getstr(st, 2));
+ if (script_hasdata(st, 2))
+ clif->scriptmes(sd, st->oid, script_getstr(st, 2));
+ else
+ clif->scriptmes(sd, st->oid, "");
return true;
}
@@ -6105,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);
@@ -6118,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;
@@ -6162,7 +6156,7 @@ static BUILDIN(menu)
st->state = END;
return false;
}
- pc->setreg(sd, script->add_str("@menu"), menu);
+ pc->setreg(sd, script->add_variable("@menu"), menu);
st->pos = script_getnum(st, i + 1);
st->state = GOTO;
}
@@ -6206,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);
@@ -6218,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_str("@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_str("@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_str("@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;
}
@@ -6937,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;
}
/*==========================================
@@ -8780,32 +8698,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;
@@ -8857,19 +8766,19 @@ static BUILDIN(getpartymember)
if(p->party.member[i].account_id) {
switch (type) {
case 2:
- mapreg->setreg(reference_uid(script->add_str("$@partymemberaid"), j),p->party.member[i].account_id);
+ mapreg->setreg(reference_uid(script->add_variable("$@partymemberaid"), j),p->party.member[i].account_id);
break;
case 1:
- mapreg->setreg(reference_uid(script->add_str("$@partymembercid"), j),p->party.member[i].char_id);
+ mapreg->setreg(reference_uid(script->add_variable("$@partymembercid"), j),p->party.member[i].char_id);
break;
default:
- mapreg->setregstr(reference_uid(script->add_str("$@partymembername$"), j),p->party.member[i].name);
+ mapreg->setregstr(reference_uid(script->add_variable("$@partymembername$"), j),p->party.member[i].name);
}
j++;
}
}
}
- mapreg->setreg(script->add_str("$@partymembercount"),j);
+ mapreg->setreg(script->add_variable("$@partymembercount"),j);
return true;
}
@@ -8999,20 +8908,20 @@ static BUILDIN(getguildmember)
if ( g->member[i].account_id ) {
switch (type) {
case 2:
- mapreg->setreg(reference_uid(script->add_str("$@guildmemberaid"), j),g->member[i].account_id);
+ mapreg->setreg(reference_uid(script->add_variable("$@guildmemberaid"), j),g->member[i].account_id);
break;
case 1:
- mapreg->setreg(reference_uid(script->add_str("$@guildmembercid"), j), g->member[i].char_id);
+ mapreg->setreg(reference_uid(script->add_variable("$@guildmembercid"), j), g->member[i].char_id);
break;
default:
- mapreg->setregstr(reference_uid(script->add_str("$@guildmembername$"), j), g->member[i].name);
+ mapreg->setregstr(reference_uid(script->add_variable("$@guildmembername$"), j), g->member[i].name);
break;
}
j++;
}
}
}
- mapreg->setreg(script->add_str("$@guildmembercount"), j);
+ mapreg->setreg(script->add_variable("$@guildmembercount"), j);
return true;
}
@@ -9304,7 +9213,7 @@ static BUILDIN(repair)
if(num==repaircounter) {
sd->status.inventory[i].attribute |= ATTR_BROKEN;
sd->status.inventory[i].attribute ^= ATTR_BROKEN;
- clif->equiplist(sd);
+ clif->equipList(sd);
clif->produce_effect(sd, 0, sd->status.inventory[i].nameid);
clif->misceffect(&sd->bl, 3);
break;
@@ -9341,7 +9250,7 @@ static BUILDIN(repairall)
if(repaircounter)
{
clif->misceffect(&sd->bl, 3);
- clif->equiplist(sd);
+ clif->equipList(sd);
}
return true;
@@ -10917,13 +10826,13 @@ static BUILDIN(getmobdrops)
if( itemdb->exists(monster->dropitem[i].nameid) == NULL )
continue;
- mapreg->setreg(reference_uid(script->add_str("$@MobDrop_item"), j), monster->dropitem[i].nameid);
- mapreg->setreg(reference_uid(script->add_str("$@MobDrop_rate"), j), monster->dropitem[i].p);
+ mapreg->setreg(reference_uid(script->add_variable("$@MobDrop_item"), j), monster->dropitem[i].nameid);
+ mapreg->setreg(reference_uid(script->add_variable("$@MobDrop_rate"), j), monster->dropitem[i].p);
j++;
}
- mapreg->setreg(script->add_str("$@MobDrop_count"), j);
+ mapreg->setreg(script->add_variable("$@MobDrop_count"), j);
script_pushint(st, 1);
return true;
@@ -11382,7 +11291,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)
@@ -11454,18 +11363,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 {
@@ -12274,7 +12175,9 @@ static BUILDIN(sc_end)
}
//This should help status_change_end force disabling the SC in case it has no limit.
- sce->val1 = sce->val2 = sce->val3 = sce->val4 = 0;
+ if (type != SC_BERSERK)
+ sce->val1 = 0; // SC_BERSERK requires skill_lv that's stored in sce->val1 when being removed [KirieZ]
+ sce->val2 = sce->val3 = sce->val4 = 0;
status_change_end(bl, (sc_type)type, INVALID_TIMER);
}
else
@@ -12361,9 +12264,18 @@ static BUILDIN(getstatus)
*------------------------------------------*/
static BUILDIN(debugmes)
{
- const char *str;
- str=script_getstr(st,2);
- ShowDebug("script debug : %d %d : %s\n",st->rid,st->oid,str);
+ struct StringBuf buf;
+ StrBuf->Init(&buf);
+
+ if (!script->sprintf_helper(st, 2, &buf)) {
+ StrBuf->Destroy(&buf);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ ShowDebug("script debug : %d %d : %s\n", st->rid, st->oid, StrBuf->Value(&buf));
+ StrBuf->Destroy(&buf);
+ script_pushint(st, 1);
return true;
}
@@ -12854,7 +12766,7 @@ static BUILDIN(getwaitingroomstate)
for (i = 0; i < cd->users; i++) {
struct map_session_data *sd = cd->usersd[i];
nullpo_retr(false, sd);
- mapreg->setreg(reference_uid(script->add_str("$@chatmembers"), i), sd->bl.id);
+ mapreg->setreg(reference_uid(script->add_variable("$@chatmembers"), i), sd->bl.id);
}
script_pushint(st, cd->users);
break;
@@ -12924,7 +12836,7 @@ static BUILDIN(warpwaitingpc)
pc->payzeny(sd, cd->zeny, LOG_TYPE_NPC, NULL);
}
- mapreg->setreg(reference_uid(script->add_str("$@warpwaitingpc"), i), sd->bl.id);
+ mapreg->setreg(reference_uid(script->add_variable("$@warpwaitingpc"), i), sd->bl.id);
if( strcmp(map_name,"Random") == 0 )
pc->randomwarp(sd,CLR_TELEPORT);
@@ -12933,7 +12845,7 @@ static BUILDIN(warpwaitingpc)
else
pc->setpos(sd, script->mapindexname2id(st,map_name), x, y, CLR_OUTSIGHT);
}
- mapreg->setreg(script->add_str("$@warpwaitingpcnum"), i);
+ mapreg->setreg(script->add_variable("$@warpwaitingpcnum"), i);
return true;
}
@@ -14410,6 +14322,9 @@ static BUILDIN(getiteminfo)
case ITEMINFO_VIEWSPRITE:
script_pushint(st, it->view_sprite);
break;
+ case ITEMINFO_TRADE:
+ script_pushint(st, it->flag.trade_restriction);
+ break;
default:
ShowError("buildin_getiteminfo: Invalid item type %d.\n", n);
script_pushint(st,-1);
@@ -14676,6 +14591,9 @@ static BUILDIN(setiteminfo)
case ITEMINFO_VIEWSPRITE:
it->view_sprite = value;
break;
+ case ITEMINFO_TRADE:
+ it->flag.trade_restriction = value;
+ break;
default:
ShowError("buildin_setiteminfo: invalid type %d.\n", n);
script_pushint(st,-1);
@@ -14809,34 +14727,34 @@ static BUILDIN(getinventorylist)
for(i=0;i<MAX_INVENTORY;i++) {
if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0) {
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_id"), j),sd->status.inventory[i].nameid);
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_amount"), j),sd->status.inventory[i].amount);
+ 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);
if(sd->status.inventory[i].equip) {
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_equip"), j),pc->equippoint(sd,i));
+ pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_equip"), j),pc->equippoint(sd,i));
} else {
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_equip"), j),0);
+ pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_equip"), j),0);
}
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_refine"), j),sd->status.inventory[i].refine);
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_identify"), j),sd->status.inventory[i].identify);
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_attribute"), j),sd->status.inventory[i].attribute);
+ pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_refine"), j),sd->status.inventory[i].refine);
+ pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_identify"), j),sd->status.inventory[i].identify);
+ pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_attribute"), j),sd->status.inventory[i].attribute);
for (k = 0; k < MAX_SLOTS; k++) {
sprintf(card_var, "@inventorylist_card%d",k+1);
- pc->setreg(sd,reference_uid(script->add_str(card_var), j),sd->status.inventory[i].card[k]);
+ pc->setreg(sd,reference_uid(script->add_variable(card_var), j),sd->status.inventory[i].card[k]);
}
for (k = 0; k < MAX_ITEM_OPTIONS; k++) {
sprintf(card_var, "@inventorylist_opt_id%d", k + 1);
- pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.inventory[i].option[k].index);
+ pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.inventory[i].option[k].index);
sprintf(card_var, "@inventorylist_opt_val%d", k + 1);
- pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.inventory[i].option[k].value);
+ pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.inventory[i].option[k].value);
sprintf(card_var, "@inventorylist_opt_param%d", k + 1);
- pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.inventory[i].option[k].param);
+ pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.inventory[i].option[k].param);
}
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time);
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_bound"), j),sd->status.inventory[i].bound);
+ pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_expire"), j),sd->status.inventory[i].expire_time);
+ pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_bound"), j),sd->status.inventory[i].bound);
j++;
}
}
- pc->setreg(sd,script->add_str("@inventorylist_count"),j);
+ pc->setreg(sd,script->add_variable("@inventorylist_count"),j);
return true;
}
@@ -14850,30 +14768,30 @@ static BUILDIN(getcartinventorylist)
for(i=0;i<MAX_CART;i++) {
if(sd->status.cart[i].nameid > 0 && sd->status.cart[i].amount > 0) {
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_id"), j),sd->status.cart[i].nameid);
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_amount"), j),sd->status.cart[i].amount);
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_equip"), j),sd->status.cart[i].equip);
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_refine"), j),sd->status.cart[i].refine);
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_identify"), j),sd->status.cart[i].identify);
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_attribute"), j),sd->status.cart[i].attribute);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_id"), j),sd->status.cart[i].nameid);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_amount"), j),sd->status.cart[i].amount);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_equip"), j),sd->status.cart[i].equip);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_refine"), j),sd->status.cart[i].refine);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_identify"), j),sd->status.cart[i].identify);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_attribute"), j),sd->status.cart[i].attribute);
for (k = 0; k < MAX_SLOTS; k++) {
sprintf(card_var, "@cartinventorylist_card%d",k+1);
- pc->setreg(sd,reference_uid(script->add_str(card_var), j),sd->status.cart[i].card[k]);
+ pc->setreg(sd,reference_uid(script->add_variable(card_var), j),sd->status.cart[i].card[k]);
}
for (k = 0; k < MAX_ITEM_OPTIONS; k++) {
sprintf(card_var, "@cartinventorylist_opt_id%d", k + 1);
- pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.cart[i].option[k].index);
+ pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.cart[i].option[k].index);
sprintf(card_var, "@cartinventorylist_opt_val%d", k + 1);
- pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.cart[i].option[k].value);
+ pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.cart[i].option[k].value);
sprintf(card_var, "@cartinventorylist_opt_param%d", k + 1);
- pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.cart[i].option[k].param);
+ pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.cart[i].option[k].param);
}
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_expire"), j),sd->status.cart[i].expire_time);
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_bound"), j),sd->status.cart[i].bound);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_expire"), j),sd->status.cart[i].expire_time);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_bound"), j),sd->status.cart[i].bound);
j++;
}
}
- pc->setreg(sd,script->add_str("@cartinventorylist_count"),j);
+ pc->setreg(sd,script->add_variable("@cartinventorylist_count"),j);
return true;
}
@@ -14885,13 +14803,13 @@ static BUILDIN(getskilllist)
return true;
for (i = 0; i < MAX_SKILL_DB; i++) {
if(sd->status.skill[i].id > 0 && sd->status.skill[i].lv > 0) {
- pc->setreg(sd,reference_uid(script->add_str("@skilllist_id"), j),sd->status.skill[i].id);
- pc->setreg(sd,reference_uid(script->add_str("@skilllist_lv"), j),sd->status.skill[i].lv);
- pc->setreg(sd,reference_uid(script->add_str("@skilllist_flag"), j),sd->status.skill[i].flag);
+ pc->setreg(sd,reference_uid(script->add_variable("@skilllist_id"), j),sd->status.skill[i].id);
+ pc->setreg(sd,reference_uid(script->add_variable("@skilllist_lv"), j),sd->status.skill[i].lv);
+ pc->setreg(sd,reference_uid(script->add_variable("@skilllist_flag"), j),sd->status.skill[i].flag);
j++;
}
}
- pc->setreg(sd,script->add_str("@skilllist_count"),j);
+ pc->setreg(sd,script->add_variable("@skilllist_count"),j);
return true;
}
@@ -15358,6 +15276,50 @@ static BUILDIN(specialeffect2)
return true;
}
+static BUILDIN(removespecialeffect)
+{
+ struct block_list *bl = NULL;
+ int type = script_getnum(st, 2);
+ enum send_target target = AREA;
+
+ if (script_hasdata(st, 3)) {
+ target = script_getnum(st, 3);
+ }
+
+ if (script_hasdata(st, 4)) {
+ if (script_isstringtype(st, 4)) {
+ struct npc_data *nd = npc->name2id(script_getstr(st, 4));
+ if (nd != NULL) {
+ bl = &nd->bl;
+ }
+ } else {
+ bl = map->id2bl(script_getnum(st, 4));
+ }
+ } else {
+ bl = map->id2bl(st->oid);
+ }
+
+ if (bl == NULL) {
+ return true;
+ }
+
+ if (target == SELF) {
+ struct map_session_data *sd;
+ if (script_hasdata(st, 5)) {
+ sd = map->id2sd(script_getnum(st, 5));
+ } else {
+ sd = script->rid2sd(st);
+ }
+ if (sd != NULL) {
+ clif->removeSpecialEffect_single(bl, type, &sd->bl);
+ }
+ } else {
+ clif->removeSpecialEffect(bl, type, target);
+ }
+
+ return true;
+}
+
/*==========================================
* Nude [Valaris]
*------------------------------------------*/
@@ -16746,6 +16708,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>
//-------------------------------------------------------
@@ -17798,12 +17817,11 @@ static BUILDIN(getd)
if (sscanf(buffer, "%99[^[][%d]", varname, &elem) < 2)
elem = 0;
- id = script->search_str(varname);
+ id = script->add_variable(varname);
- if (id < 0) {
- id = script->add_str(varname);
- script->str_data[id].type = C_NAME;
- } else if (script->str_data[id].type != C_NAME) {
+ if (script->str_data[id].type != C_NAME && // variable
+ script->str_data[id].type != C_PARAM && // param
+ script->str_data[id].type != C_INT) { // constant
ShowError("script:getd: `%s` is already used by something that is not a variable.\n", varname);
st->state = END;
return false;
@@ -18763,7 +18781,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:
@@ -18771,7 +18789,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;
@@ -18932,13 +18950,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;
@@ -19071,13 +19089,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;
@@ -19205,13 +19223,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;
@@ -19339,13 +19357,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;
@@ -19471,13 +19489,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;
@@ -20631,7 +20649,7 @@ static BUILDIN(getvariableofpc)
}
if (!sd->regs.vars)
- sd->regs.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
+ sd->regs.vars = i64db_alloc(DB_OPT_BASE);
script->push_val(st->stack, C_NAME, reference_getuid(data), &sd->regs);
return true;
@@ -20788,7 +20806,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;
}
@@ -21051,17 +21069,26 @@ static BUILDIN(setquestinfo)
}
case QINFO_ITEM:
{
- struct item item = { 0 };
+ struct questinfo_itemreq item = { 0 };
item.nameid = script_getnum(st, 3);
- item.amount = script_getnum(st, 4);
+ item.min = script_hasdata(st, 4) ? script_getnum(st, 4) : 0;
+ item.max = script_hasdata(st, 5) ? script_getnum(st, 5) : 0;
if (itemdb->exists(item.nameid) == NULL) {
ShowWarning("buildin_setquestinfo: non existing item (%d) have been given.\n", item.nameid);
return false;
}
- if (item.amount <= 0 || item.amount > MAX_AMOUNT) {
- ShowWarning("buildin_setquestinfo: given amount (%d) must be bigger than 0 and smaller than %d.\n", item.amount, MAX_AMOUNT + 1);
+ if (item.min > item.max) {
+ ShowWarning("buildin_setquestinfo: minimal amount (%d) is bigger than the maximal amount (%d).\n", item.min, item.max);
+ return false;
+ }
+ if (item.min < 0 || item.min > MAX_AMOUNT) {
+ ShowWarning("buildin_setquestinfo: given amount (%d) must be bigger than or equal to 0 and smaller than %d.\n", item.min, MAX_AMOUNT + 1);
+ return false;
+ }
+ if (item.max < 0 || item.max > MAX_AMOUNT) {
+ ShowWarning("buildin_setquestinfo: given amount (%d) must be bigger than or equal to 0 and smaller than %d.\n", item.max, MAX_AMOUNT + 1);
return false;
}
if (VECTOR_LENGTH(qi->items) == 0)
@@ -21114,6 +21141,17 @@ static BUILDIN(setquestinfo)
VECTOR_PUSH(qi->quest_requirement, quest_req);
break;
}
+ case QINFO_MERCENARY_CLASS:
+ {
+ int mer_class = script_getnum(st, 3);
+
+ if (!mercenary->class(mer_class)) {
+ ShowWarning("buildin_setquestinfo: invalid mercenary class given (%d).\n", mer_class);
+ return false;
+ }
+ qi->mercenary_class = mer_class;
+ break;
+ }
default:
ShowWarning("buildin_setquestinfo: invalid type given (%u).\n", type);
return false;
@@ -21267,18 +21305,7 @@ static BUILDIN(showevent)
}
}
-#if PACKETVER >= 20170315
- if (icon < 0 || (icon > 10 && icon != 9999))
- icon = 9999;
-#elif PACKETVER >= 20120410
- if (icon < 0 || (icon > 8 && icon != 9999) || icon == 7)
- icon = 9999; // Default to nothing if icon id is invalid.
-#else
- if (icon < 0 || icon > 7)
- icon = 0;
- else
- icon = icon + 1;
-#endif
+ icon = quest->questinfo_validate_icon(icon);
clif->quest_show_event(sd, &nd->bl, icon, color);
return true;
@@ -21404,12 +21431,12 @@ static BUILDIN(waitingroom2bg)
for (i = 0; i < n && i < MAX_BG_MEMBERS; i++) {
struct map_session_data *sd = cd->usersd[i];
if (sd != NULL && bg->team_join(bg_id, sd))
- mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), sd->bl.id);
+ mapreg->setreg(reference_uid(script->add_variable("$@arenamembers"), i), sd->bl.id);
else
- mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), 0);
+ mapreg->setreg(reference_uid(script->add_variable("$@arenamembers"), i), 0);
}
- mapreg->setreg(script->add_str("$@arenamembersnum"), i);
+ mapreg->setreg(script->add_variable("$@arenamembersnum"), i);
script_pushint(st,bg_id);
return true;
}
@@ -22471,18 +22498,52 @@ static BUILDIN(getcharip)
return true;
}
+enum function_type {
+ FUNCTION_IS_NONE = 0,
+ FUNCTION_IS_COMMAND,
+ FUNCTION_IS_GLOBAL,
+ FUNCTION_IS_LOCAL,
+ FUNCTION_IS_LABEL,
+};
+
/**
- * is_function(<function name>) -> 1 if function exists, 0 otherwise
+ * is_function(<function name>)
**/
static BUILDIN(is_function)
{
- const char* str = script_getstr(st,2);
+ const char *str = script_getstr(st, 2);
+ enum function_type type = FUNCTION_IS_NONE;
- if( strdb_exists(script->userfunc_db, str) )
- script_pushint(st,1);
- else
- script_pushint(st,0);
+ // TODO: add support for exported functions (#2142)
+
+ if (strdb_exists(script->userfunc_db, str)) {
+ type = FUNCTION_IS_GLOBAL;
+ } else {
+ int n = script->search_str(str);
+
+ if (n >= 0) {
+ switch (script->str_data[n].type) {
+ case C_FUNC:
+ type = FUNCTION_IS_COMMAND;
+ break;
+ case C_USERFUNC:
+ case C_USERFUNC_POS:
+ type = FUNCTION_IS_LOCAL;
+ break;
+ case C_POS:
+ type = FUNCTION_IS_LABEL;
+ break;
+ case C_NAME:
+ if (script->str_data[n].label >= 0) {
+ // WTF... ?
+ // for some reason local functions can have type C_NAME
+ type = FUNCTION_IS_LOCAL;
+ }
+ }
+ }
+ }
+ script_pushint(st, type);
return true;
}
@@ -23587,7 +23648,7 @@ static BUILDIN(countbound)
(!type && sd->status.inventory[i].bound > 0) ||
(type && sd->status.inventory[i].bound == type)
)) {
- pc->setreg(sd,reference_uid(script->add_str("@bound_items"), k),sd->status.inventory[i].nameid);
+ pc->setreg(sd,reference_uid(script->add_variable("@bound_items"), k),sd->status.inventory[i].nameid);
k++;
j += sd->status.inventory[i].amount;
}
@@ -24655,6 +24716,80 @@ static BUILDIN(openstylist)
return true;
}
+static BUILDIN(msgtable)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+
+ const enum clif_messages msgId = script_getnum(st, 2);
+ if (script_hasdata(st, 3)) {
+ clif->msgtable_color(sd, msgId, script_getnum(st, 3));
+ } else {
+ clif->msgtable(sd, msgId);
+ }
+
+ return true;
+}
+
+static BUILDIN(msgtable2)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+
+ const enum clif_messages msgId = script_getnum(st, 2);
+ if (script_isstringtype(st, 3)) {
+ const char *value = script_getstr(st, 3);
+ if (script_hasdata(st, 4)) {
+ clif->msgtable_str_color(sd, msgId, value, script_getnum(st, 4));
+ } else {
+ clif->msgtable_str(sd, msgId, value);
+ }
+ } else {
+ const int value = script_getnum(st, 3);
+ clif->msgtable_num(sd, msgId, value);
+ }
+
+ return true;
+}
+
+// show/hide camera info
+static BUILDIN(camerainfo)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+
+ clif->camera_showWindow(sd);
+ return true;
+}
+
+// allow change some camera parameters
+static BUILDIN(changecamera)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+
+ enum send_target target = SELF;
+ if (script_hasdata(st, 5)) {
+ target = script_getnum(st, 5);
+ }
+ clif->camera_change(sd, (float)script_getnum(st, 2), (float)script_getnum(st, 3), (float)script_getnum(st, 4), target);
+ return true;
+}
+
+// update preview window to given item
+static BUILDIN(itempreview)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+ clif->item_preview(sd, script_getnum(st, 2));
+ return true;
+}
+
/**
* Adds a built-in script function.
*
@@ -24816,14 +24951,14 @@ static void script_parse_builtin(void)
BUILDIN_DEF(__setr,"rv?"),
// NPC interaction
- BUILDIN_DEF(mes,"s"),
- BUILDIN_DEF(mesf,"s*"),
+ BUILDIN_DEF(mes, "?"),
+ BUILDIN_DEF(mesf, "s*"),
BUILDIN_DEF(next,""),
BUILDIN_DEF(close,""),
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*"),
@@ -24872,7 +25007,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?"),
@@ -24975,7 +25110,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(sc_end,"i?"),
BUILDIN_DEF(getstatus, "i?"),
BUILDIN_DEF(getscrate,"ii?"),
- BUILDIN_DEF(debugmes,"v"),
+ BUILDIN_DEF(debugmes,"v*"),
BUILDIN_DEF2(catchpet,"pet","i"),
BUILDIN_DEF2(birthpet,"bpet",""),
BUILDIN_DEF(resetlvl,"i"),
@@ -25051,6 +25186,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(skilleffect,"vi"), // skill effect [Celest]
BUILDIN_DEF(npcskilleffect,"viii"), // npc skill effect [Valaris]
BUILDIN_DEF(specialeffect,"i???"), // npc skill effect [Valaris]
+ BUILDIN_DEF(removespecialeffect,"i???"),
BUILDIN_DEF_DEPRECATED(specialeffect2,"i??"), // skill effect on players[Valaris]
BUILDIN_DEF(nude,""), // nude command [Valaris]
BUILDIN_DEF(mapwarp,"ssii??"), // Added by RoVeRT
@@ -25103,6 +25239,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"),
@@ -25231,6 +25369,8 @@ static void script_parse_builtin(void)
BUILDIN_DEF(buyingstore,"i"),
BUILDIN_DEF(searchstores,"ii"),
BUILDIN_DEF(showdigit,"i?"),
+ BUILDIN_DEF(msgtable, "i?"),
+ BUILDIN_DEF(msgtable2, "iv?"),
// WoE SE
BUILDIN_DEF(agitstart2,""),
BUILDIN_DEF(agitend2,""),
@@ -25310,7 +25450,7 @@ static void script_parse_builtin(void)
//Quest Log System [Inkfish]
BUILDIN_DEF(questinfo, "i?"),
- BUILDIN_DEF(setquestinfo, "i??"),
+ BUILDIN_DEF(setquestinfo, "i???"),
BUILDIN_DEF(setquest, "i?"),
BUILDIN_DEF(erasequest, "i?"),
BUILDIN_DEF(completequest, "i?"),
@@ -25382,6 +25522,12 @@ static void script_parse_builtin(void)
// -- HatEffect
BUILDIN_DEF(hateffect, "ii"),
+
+ // camera
+ BUILDIN_DEF(camerainfo, ""),
+ BUILDIN_DEF(changecamera, "iii?"),
+
+ BUILDIN_DEF(itempreview, "i"),
};
int i, len = ARRAYLENGTH(BUILDIN);
RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up
@@ -25428,6 +25574,8 @@ static void script_hardcoded_constants(void)
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);
@@ -25697,6 +25845,7 @@ static void script_hardcoded_constants(void)
script->set_constant("ITEMINFO_VIEWID", ITEMINFO_VIEWID, false, false);
script->set_constant("ITEMINFO_MATK", ITEMINFO_MATK, false, false);
script->set_constant("ITEMINFO_VIEWSPRITE", ITEMINFO_VIEWSPRITE, false, false);
+ script->set_constant("ITEMINFO_TRADE", ITEMINFO_TRADE, false, false);
script->constdb_comment("monster skill states");
script->set_constant("MSS_ANY", MSS_ANY, false, false);
@@ -25780,6 +25929,27 @@ static void script_hardcoded_constants(void)
script->set_constant("QINFO_HOMUN_LEVEL", QINFO_HOMUN_LEVEL, false, false);
script->set_constant("QINFO_HOMUN_TYPE", QINFO_HOMUN_TYPE, false, false);
script->set_constant("QINFO_QUEST", QINFO_QUEST, false, false);
+ script->set_constant("QINFO_MERCENARY_CLASS", QINFO_MERCENARY_CLASS, false, false);
+
+ script->constdb_comment("function types");
+ script->set_constant("FUNCTION_IS_COMMAND", FUNCTION_IS_COMMAND, false, false);
+ script->set_constant("FUNCTION_IS_GLOBAL", FUNCTION_IS_GLOBAL, false, false);
+ script->set_constant("FUNCTION_IS_LOCAL", FUNCTION_IS_LOCAL, false, false);
+ script->set_constant("FUNCTION_IS_LABEL", FUNCTION_IS_LABEL, false, false);
+
+ script->constdb_comment("item trade restrictions");
+ script->set_constant("ITR_NONE", ITR_NONE, false, false);
+ script->set_constant("ITR_NODROP", ITR_NODROP, false, false);
+ script->set_constant("ITR_NOTRADE", ITR_NOTRADE, false, false);
+ script->set_constant("ITR_PARTNEROVERRIDE", ITR_PARTNEROVERRIDE, false, false);
+ script->set_constant("ITR_NOSELLTONPC", ITR_NOSELLTONPC, false, false);
+ script->set_constant("ITR_NOCART", ITR_NOCART, false, false);
+ script->set_constant("ITR_NOSTORAGE", ITR_NOSTORAGE, false, false);
+ script->set_constant("ITR_NOGSTORAGE", ITR_NOGSTORAGE, false, false);
+ script->set_constant("ITR_NOMAIL", ITR_NOMAIL, false, false);
+ script->set_constant("ITR_NOAUCTION", ITR_NOAUCTION, false, false);
+ script->set_constant("ITR_ALL", ITR_ALL, false, false);
+
script->constdb_comment("Renewal");
#ifdef RENEWAL
@@ -25962,6 +26132,7 @@ void script_defaults(void)
script->setarray_pc = script_setarray_pc;
script->config_read = script_config_read;
script->add_str = script_add_str;
+ script->add_variable = script_add_variable;
script->get_str = script_get_str;
script->search_str = script_search_str;
script->setd_sub = setd_sub;