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.c356
1 files changed, 283 insertions, 73 deletions
diff --git a/src/map/script.c b/src/map/script.c
index 10f9c9f00..24faa6756 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -83,12 +83,15 @@
struct script_interface script_s;
struct script_interface *script;
+static inline int GETVALUE(const struct script_buf *buf, int i) __attribute__((nonnull (1)));
static inline int GETVALUE(const struct script_buf *buf, int i)
{
Assert_ret(VECTOR_LENGTH(*buf) > i + 2);
return (int)MakeDWord(MakeWord(VECTOR_INDEX(*buf, i), VECTOR_INDEX(*buf, i+1)),
MakeWord(VECTOR_INDEX(*buf, i+2), 0));
}
+
+static inline void SETVALUE(struct script_buf *buf, int i, int n) __attribute__((nonnull (1)));
static inline void SETVALUE(struct script_buf *buf, int i, int n)
{
Assert_retv(VECTOR_LENGTH(*buf) > i + 2);
@@ -158,6 +161,7 @@ const char* script_op2name(int op) {
static void script_dump_stack(struct script_state* st)
{
int i;
+ nullpo_retv(st);
ShowMessage("\tstart = %d\n", st->start);
ShowMessage("\tend = %d\n", st->end);
ShowMessage("\tdefsp = %d\n", st->stack->defsp);
@@ -200,6 +204,7 @@ static void script_dump_stack(struct script_state* st)
void script_reportsrc(struct script_state *st) {
struct block_list* bl;
+ nullpo_retv(st);
if( st->oid == 0 )
return; //Can't report source.
@@ -304,7 +309,7 @@ void script_reportfunc(struct script_state* st)
/*==========================================
* Output error message
*------------------------------------------*/
-static void disp_error_message2(const char *mes,const char *pos,int report) analyzer_noreturn;
+static void disp_error_message2(const char *mes,const char *pos,int report) __attribute__((nonnull (1))) analyzer_noreturn;
static void disp_error_message2(const char *mes,const char *pos,int report) {
script->error_msg = aStrdup(mes);
script->error_pos = pos;
@@ -333,6 +338,7 @@ void check_event(struct script_state *st, const char *evt)
unsigned int calc_hash(const char* p) {
unsigned int h;
+ nullpo_ret(p);
#if defined(SCRIPT_HASH_DJB2)
h = 5381;
while( *p ) // hash*33 + c
@@ -368,6 +374,7 @@ unsigned int calc_hash_ci(const char* p) {
unsigned int h = 0;
#ifdef ENABLE_CASE_CHECK
+ nullpo_ret(p);
#if defined(SCRIPT_HASH_DJB2)
h = 5381;
while( *p ) // hash*33 + c
@@ -422,8 +429,10 @@ int script_search_str(const char* p)
return -1;
}
-void script_casecheck_clear_sub(struct casecheck_data *ccd) {
+void script_casecheck_clear_sub(struct casecheck_data *ccd)
+{
#ifdef ENABLE_CASE_CHECK
+ nullpo_retv(ccd);
if (ccd->str_data) {
aFree(ccd->str_data);
ccd->str_data = NULL;
@@ -453,6 +462,7 @@ const char *script_casecheck_add_str_sub(struct casecheck_data *ccd, const char
#ifdef ENABLE_CASE_CHECK
int len;
int h = script->calc_hash_ci(p);
+ nullpo_retr(NULL, ccd);
if (ccd->str_hash[h] == 0) {
//empty bucket, add new node here
ccd->str_hash[h] = ccd->str_num;
@@ -744,7 +754,9 @@ const char* script_skip_space(const char* p)
/// Skips a word.
/// A word consists of undercores and/or alphanumeric characters,
/// and valid variable prefixes/postfixes.
-const char* skip_word(const char* p) {
+const char* skip_word(const char* p)
+{
+ nullpo_retr(NULL, p);
// prefix
switch( *p ) {
case '@':// temporary char variable
@@ -759,7 +771,7 @@ const char* skip_word(const char* p) {
p += ( p[1] == '@' ? 2 : 1 ); break;
}
- while( ISALNUM(*p) || *p == '_' || *p == '\'' )
+ while (ISALNUM(*p) || *p == '_')
++p;
// postfix
@@ -775,6 +787,7 @@ int add_word(const char* p) {
size_t len;
int i;
+ nullpo_retr(0, p);
// Check for a word
len = script->skip_word(p) - p;
if( len == 0 )
@@ -805,6 +818,7 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom)
int func;
bool macro = false;
+ nullpo_retr(NULL, p);
// is need add check for arg null pointer below?
func = script->add_word(p);
if (script->str_data[func].type == C_FUNC) {
@@ -983,6 +997,7 @@ const char* parse_variable(const char* p)
const char *p2 = NULL;
const char *var = p;
+ nullpo_retr(NULL, p);
if( ( p[0] == '+' && p[1] == '+' && (type = C_ADD_PRE, true) ) // pre ++
|| ( p[0] == '-' && p[1] == '-' && (type = C_SUB_PRE, true) ) // pre --
) {
@@ -1162,9 +1177,12 @@ bool is_number(const char *p) {
*/
int script_string_dup(char *str)
{
- int len = (int)strlen(str);
+ int len;
int pos = script->string_list_pos;
+ nullpo_retr(pos, str);
+ len = (int)strlen(str);
+
while (pos+len+1 >= script->string_list_size) {
script->string_list_size += (1024*1024)/2;
RECREATE(script->string_list,char,script->string_list_size);
@@ -1183,6 +1201,7 @@ const char *parse_simpleexpr(const char *p)
{
p=script->skip_space(p);
+ nullpo_retr(NULL, p);
if (*p == ';' || *p == ',')
disp_error_message("parse_simpleexpr: unexpected end of expression",p);
if (*p == '(') {
@@ -1199,6 +1218,7 @@ const char *parse_simpleexpr(const char *p)
const char *parse_simpleexpr_paren(const char *p)
{
int i = script->syntax.curly_count - 1;
+ nullpo_retr(NULL, p);
if (i >= 0 && script->syntax.curly[i].type == TYPE_ARGLIST)
++script->syntax.curly[i].count;
@@ -1227,6 +1247,7 @@ const char *parse_simpleexpr_number(const char *p)
char *np = NULL;
long long lli;
+ nullpo_retr(NULL, p);
while (*p == '0' && ISDIGIT(p[1]))
p++; // Skip leading zeros, we don't support octal literals
@@ -1247,6 +1268,7 @@ const char *parse_simpleexpr_string(const char *p)
{
const char *start_point = p;
+ nullpo_retr(NULL, p);
do {
p++;
while (*p != '\0' && *p != '"') {
@@ -1337,6 +1359,7 @@ void script_add_translatable_string(const struct script_string_buf *string, cons
{
struct string_translation *st = NULL;
+ nullpo_retv(string);
if (script->syntax.translation_db == NULL
|| (st = strdb_get(script->syntax.translation_db, VECTOR_DATA(*string))) == NULL) {
script->addc(C_STR);
@@ -1376,6 +1399,7 @@ const char* script_parse_subexpr(const char* p,int limit)
{
int op,opl,len;
+ nullpo_retr(NULL, p);
p=script->skip_space(p);
if( *p == '-' ) {
@@ -1441,6 +1465,7 @@ const char* script_parse_subexpr(const char* p,int limit)
*------------------------------------------*/
const char* parse_expr(const char *p)
{
+ nullpo_retr(NULL, p);
switch(*p) {
case ')': case ';': case ':': case '[': case ']':
case '}':
@@ -1457,6 +1482,7 @@ const char* parse_line(const char* p)
{
const char* p2;
+ nullpo_retr(NULL, p);
p=script->skip_space(p);
if(*p==';') {
//Close decision for if(); for(); while();
@@ -1517,6 +1543,7 @@ const char* parse_line(const char* p)
// { ... } Closing process
const char* parse_curly_close(const char* p)
{
+ nullpo_retr(NULL, p);
if(script->syntax.curly_count <= 0) {
disp_error_message("parse_curly_close: unexpected string",p);
return p + 1;
@@ -1577,6 +1604,7 @@ const char* parse_syntax(const char* p)
{
const char *p2 = script->skip_word(p);
+ nullpo_retr(NULL, p);
switch(*p) {
case 'B':
case 'b':
@@ -2006,6 +2034,7 @@ const char* parse_syntax_close(const char *p) {
// If (...) for (...) hoge (); as to make sure closed closed once again
int flag;
+ nullpo_retr(NULL, p);
do {
p = script->parse_syntax_close_sub(p,&flag);
} while(flag);
@@ -2192,6 +2221,7 @@ bool script_get_constant(const char* name, int* value)
{
int n = script->search_str(name);
+ nullpo_retr(false, value);
if( n == -1 || script->str_data[n].type != C_INT )
{// not found or not a constant
return false;
@@ -2261,7 +2291,7 @@ void read_constdb(void)
struct config_setting_t *t;
int i = 0;
- sprintf(filepath, "%s/constants.conf", map->db_path);
+ snprintf(filepath, 256, "%s/constants.conf", map->db_path);
if (!libconfig->load_file(&constants_conf, filepath))
return;
@@ -2706,6 +2736,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
struct map_session_data *script_rid2sd(struct script_state *st)
{
struct map_session_data *sd;
+ nullpo_retr(NULL, st);
if( !( sd = map->id2sd(st->rid) ) ) {
ShowError("script_rid2sd: fatal error ! player not attached!\n");
script->reportfunc(st);
@@ -2756,6 +2787,7 @@ char *get_val_npcscope_str(struct script_state* st, struct reg_db *n, struct scr
}
char *get_val_instance_str(struct script_state* st, const char* name, struct script_data* data) {
+ nullpo_retr(NULL, st);
if (st->instance_id >= 0) {
return (char*)i64db_get(instance->list[st->instance_id].regs.vars, reference_getuid(data));
} else {
@@ -2923,6 +2955,7 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) {
const void *get_val2(struct script_state *st, int64 uid, struct reg_db *ref)
{
struct script_data* data;
+ nullpo_retr(NULL, st);
script->push_val(st->stack, C_NAME, uid, ref);
data = script_getdatatop(st, -1);
script->get_val(st, data);
@@ -2937,14 +2970,18 @@ const void *get_val2(struct script_state *st, int64 uid, struct reg_db *ref)
**/
void script_array_ensure_zero(struct script_state *st, struct map_session_data *sd, int64 uid, struct reg_db *ref) {
const char *name = script->get_str(script_getvarid(uid));
- // is here st can be null pointer and st->rid is wrong?
- struct reg_db *src = script->array_src(st, sd ? sd : st->rid ? map->id2sd(st->rid) : NULL, name, ref);
+ struct reg_db *src = NULL;
bool insert = false;
- if (sd && !st) {
- /* when sd comes, st isn't available */
+ if (st == NULL) {
+ // Special case with no st available, only sd
+ nullpo_retv(sd);
+ src = script->array_src(NULL, sd, name, ref);
insert = true;
} else {
+ if (sd == NULL && st->rid != 0)
+ sd = map->id2sd(st->rid); // Retrieve the missing sd
+ src = script->array_src(st, sd, name, ref);
if( is_string_variable(name) ) {
const char *str = script->get_val2(st, uid, ref);
if (str != NULL && *str != '\0')
@@ -3022,6 +3059,8 @@ int script_free_array_db(union DBKey key, struct DBData *data, va_list ap)
* Clears script_array and removes it from script->array_db
**/
void script_array_delete(struct reg_db *src, struct script_array *sa) {
+ nullpo_retv(src);
+ nullpo_retv(sa);
aFree(sa->members);
idb_remove(src->arrays, sa->id);
ers_free(script->array_ers, sa);
@@ -3034,6 +3073,7 @@ void script_array_delete(struct reg_db *src, struct script_array *sa) {
void script_array_remove_member(struct reg_db *src, struct script_array *sa, unsigned int idx) {
unsigned int i, cursor;
+ nullpo_retv(sa);
/* its the only member left, no need to do anything other than delete the array data */
if( sa->size == 1 ) {
script->array_delete(src,sa);
@@ -3058,8 +3098,8 @@ void script_array_remove_member(struct reg_db *src, struct script_array *sa, uns
* @param idx the index of the array member being inserted
**/
void script_array_add_member(struct script_array *sa, unsigned int idx) {
+ nullpo_retv(sa);
RECREATE(sa->members, unsigned int, ++sa->size);
-
sa->members[sa->size - 1] = idx;
}
/**
@@ -3069,23 +3109,28 @@ void script_array_add_member(struct script_array *sa, unsigned int idx) {
struct reg_db *script_array_src(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref) {
struct reg_db *src = NULL;
+ nullpo_retr(NULL, name);
switch( name[0] ) {
/* from player */
default: /* char reg */
case '@':/* temp char reg */
case '#':/* account reg */
+ nullpo_retr(NULL, sd);
src = &sd->regs;
break;
case '$':/* map reg */
src = &mapreg->regs;
break;
case '.':/* npc/script */
- if( ref )
+ if (ref != NULL) {
src = ref;
- else
+ } else {
+ nullpo_retr(NULL, st);
src = (name[1] == '@') ? &st->stack->scope : &st->script->local;
+ }
break;
case '\'':/* instance */
+ nullpo_retr(NULL, st);
if( st->instance_id >= 0 ) {
src = &instance->list[st->instance_id].regs;
}
@@ -3112,6 +3157,7 @@ void script_array_update(struct reg_db *src, int64 num, bool empty) {
int id = script_getvarid(num);
unsigned int index = script_getvaridx(num);
+ nullpo_retv(src);
if (!src->arrays) {
src->arrays = idb_alloc(DB_OPT_BASE);
} else {
@@ -3151,6 +3197,7 @@ void set_reg_npcscope_str(struct script_state* st, struct reg_db *n, int64 num,
{
if (n)
{
+ nullpo_retv(str);
if (str[0]) {
i64db_put(n->vars, num, aStrdup(str));
if (script_getvaridx(num))
@@ -3180,6 +3227,7 @@ void set_reg_npcscope_num(struct script_state* st, struct reg_db *n, int64 num,
void set_reg_instance_str(struct script_state* st, int64 num, const char* name, const char *str)
{
+ nullpo_retv(st);
if (st->instance_id >= 0) {
if (str[0]) {
i64db_put(instance->list[st->instance_id].regs.vars, num, aStrdup(str));
@@ -3198,6 +3246,7 @@ void set_reg_instance_str(struct script_state* st, int64 num, const char* name,
void set_reg_instance_num(struct script_state* st, int64 num, const char* name, int val)
{
+ nullpo_retv(st);
if (st->instance_id >= 0) {
if (val != 0) {
i64db_iput(instance->list[st->instance_id].regs.vars, num, val);
@@ -3230,12 +3279,16 @@ void set_reg_instance_num(struct script_state* st, int64 num, const char* name,
*------------------------------------------*/
int set_reg(struct script_state *st, struct map_session_data *sd, int64 num, const char *name, const void *value, struct reg_db *ref)
{
- char prefix = name[0];
+ char prefix;
+ nullpo_ret(name);
+ prefix = name[0];
if (strlen(name) > SCRIPT_VARNAME_LENGTH) {
ShowError("script:set_reg: variable name too long. '%s'\n", name);
- script->reportsrc(st);
- st->state = END;
+ if (st) {
+ script->reportsrc(st);
+ st->state = END;
+ }
return 0;
}
@@ -3418,6 +3471,7 @@ int conv_num(struct script_state *st, struct script_data *data)
/// Increases the size of the stack
void stack_expand(struct script_stack* stack) {
+ nullpo_retv(stack);
stack->sp_max += 64;
stack->stack_data = (struct script_data*)aRealloc(stack->stack_data,
stack->sp_max * sizeof(stack->stack_data[0]) );
@@ -3427,6 +3481,7 @@ void stack_expand(struct script_stack* stack) {
/// Pushes a value into the stack (with reference)
struct script_data* push_val(struct script_stack* stack, enum c_op type, int64 val, struct reg_db *ref) {
+ nullpo_retr(NULL, stack);
if( stack->sp >= stack->sp_max )
script->stack_expand(stack);
stack->stack_data[stack->sp].type = type;
@@ -3439,6 +3494,7 @@ struct script_data* push_val(struct script_stack* stack, enum c_op type, int64 v
/// Pushes a string into the stack
struct script_data *push_str(struct script_stack *stack, char *str)
{
+ nullpo_retr(NULL, stack);
if( stack->sp >= stack->sp_max )
script->stack_expand(stack);
stack->stack_data[stack->sp].type = C_STR;
@@ -3451,6 +3507,7 @@ struct script_data *push_str(struct script_stack *stack, char *str)
/// Pushes a constant string into the stack
struct script_data *push_conststr(struct script_stack *stack, const char *str)
{
+ nullpo_retr(NULL, stack);
if( stack->sp >= stack->sp_max )
script->stack_expand(stack);
stack->stack_data[stack->sp].type = C_CONSTSTR;
@@ -3462,6 +3519,7 @@ struct script_data *push_conststr(struct script_stack *stack, const char *str)
/// Pushes a retinfo into the stack
struct script_data* push_retinfo(struct script_stack* stack, struct script_retinfo* ri, struct reg_db *ref) {
+ nullpo_retr(NULL, stack);
if( stack->sp >= stack->sp_max )
script->stack_expand(stack);
stack->stack_data[stack->sp].type = C_RETINFO;
@@ -3473,6 +3531,7 @@ struct script_data* push_retinfo(struct script_stack* stack, struct script_retin
/// Pushes a copy of the target position into the stack
struct script_data* push_copy(struct script_stack* stack, int pos) {
+ nullpo_retr(NULL, stack);
switch( stack->stack_data[pos].type ) {
case C_CONSTSTR:
return script->push_conststr(stack, stack->stack_data[pos].u.str);
@@ -3497,10 +3556,13 @@ struct script_data* push_copy(struct script_stack* stack, int pos) {
/// Removes the values in indexes [start,end[ from the stack.
/// Adjusts all stack pointers.
void pop_stack(struct script_state* st, int start, int end) {
- struct script_stack* stack = st->stack;
+ struct script_stack* stack;
struct script_data* data;
int i;
+ nullpo_retv(st);
+ stack = st->stack;
+
if( start < 0 )
start = 0;
if( end > stack->sp )
@@ -3636,6 +3698,7 @@ struct script_state* script_alloc_state(struct script_code* rootscript, int pos,
///
/// @param st Script state
void script_free_state(struct script_state* st) {
+ nullpo_retv(st);
if( idb_exists(script->st_db,st->id) ) {
struct map_session_data *sd = st->rid ? map->id2sd(st->rid) : NULL;
@@ -3697,6 +3760,7 @@ void script_free_state(struct script_state* st) {
* @param ref[in] Reference to be added.
*/
void script_add_pending_ref(struct script_state *st, struct reg_db *ref) {
+ nullpo_retv(st);
RECREATE(st->pending_refs, struct reg_db*, ++st->pending_ref_count);
st->pending_refs[st->pending_ref_count-1] = ref;
}
@@ -4133,6 +4197,7 @@ int run_func(struct script_state *st)
struct script_data* data;
int i,start_sp,end_sp,func;
+ nullpo_retr(1, st);
end_sp = st->stack->sp;// position after the last argument
for( i = end_sp-1; i > 0 ; --i )
if( st->stack->stack_data[i].type == C_ARG )
@@ -4280,6 +4345,7 @@ int run_script_timer(int tid, int64 tick, int id, intptr_t data) {
void script_detach_state(struct script_state* st, bool dequeue_event) {
struct map_session_data* sd;
+ nullpo_retv(st);
if(st->rid && (sd = map->id2sd(st->rid))!=NULL) {
sd->st = st->bk_st;
sd->npc_id = st->bk_npcid;
@@ -4313,6 +4379,7 @@ void script_detach_state(struct script_state* st, bool dequeue_event) {
void script_attach_state(struct script_state* st) {
struct map_session_data* sd;
+ nullpo_retv(st);
if(st->rid && (sd = map->id2sd(st->rid))!=NULL)
{
if(st!=sd->st)
@@ -4348,6 +4415,7 @@ void run_script_main(struct script_state *st) {
struct script_stack *stack = st->stack;
struct npc_data *nd;
+ nullpo_retv(st);
script->attach_state(st);
nd = map->id2nd(st->oid);
@@ -4656,6 +4724,7 @@ int script_reg_destroy(union DBKey key, struct DBData *data, va_list ap)
{
struct script_reg_state *src;
+ nullpo_ret(data);
if( data->type != DB_DATA_PTR )/* got no need for those! */
return 0;
@@ -4677,6 +4746,8 @@ int script_reg_destroy(union DBKey key, struct DBData *data, va_list ap)
* Clears a single persistent variable
**/
void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct script_reg_state *data) {
+ nullpo_retv(sd);
+ nullpo_retv(data);
i64db_remove(sd->regs.vars, reg);
if( data->type ) {
@@ -4691,6 +4762,7 @@ void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct sc
}
}
unsigned int *script_array_cpy_list(struct script_array *sa) {
+ nullpo_retr(NULL, sa);
if( sa->size > script->generic_ui_array_size )
script->generic_ui_array_expand(sa->size);
memcpy(script->generic_ui_array, sa->members, sizeof(unsigned int)*sa->size);
@@ -4838,6 +4910,7 @@ void do_final_script(void)
**/
uint8 script_add_language(const char *name) {
uint8 lang_id = script->max_lang_id;
+ nullpo_ret(name);
RECREATE(script->languages, char *, ++script->max_lang_id);
script->languages[lang_id] = aStrdup(name);
@@ -5052,6 +5125,8 @@ int script_load_translation(const char *file, uint8 lang_id)
int lineno = 0;
struct script_string_buf msgid, msgstr;
+ nullpo_ret(file);
+
if ((fp = fopen(file,"rb")) == NULL) {
ShowError("load_translation: failed to open '%s' for reading\n",file);
return 0;
@@ -5343,6 +5418,7 @@ int script_reload(void)
const char *script_getfuncname(struct script_state *st) {
struct script_data *data;
+ nullpo_retr(NULL, st);
data = &st->stack->stack_data[st->start];
if( data->type == C_NAME && script->str_data[data->u.num].type == C_FUNC )
@@ -5372,6 +5448,7 @@ bool script_sprintf(struct script_state *st, int start, struct StringBuf *out)
int lastarg = start;
int argc = script_lastdata(st) + 1;
+ nullpo_retr(-1, out);
Assert_retr(-1, start >= 2 && start <= argc);
Assert_retr(-1, script_hasdata(st, start));
@@ -5405,8 +5482,6 @@ bool script_sprintf(struct script_state *st, int start, struct StringBuf *out)
safestrncpy(buf, p, len);
StrBuf->AppendStr(out, buf);
}
-
- p = np;
np++;
// placeholder = "%%" ; (special case)
@@ -5692,6 +5767,7 @@ int menu_countoptions(const char* str, int max_count, int* total)
int count = 0;
int bogus_total;
+ nullpo_ret(str);
if( total == NULL )
total = &bogus_total;
++(*total);
@@ -6315,6 +6391,9 @@ int buildin_areawarp_sub(struct block_list *bl, va_list ap)
pc->randomwarp(sd, CLR_TELEPORT);
} else if (x3 != 0 && y3 != 0) {
int max, tx, ty, j = 0;
+ int16 m;
+
+ m = map->mapindex2mapid(index);
// choose a suitable max number of attempts
if( (max = (y3-y2+1)*(x3-x2+1)*3) > 1000 )
@@ -6325,7 +6404,7 @@ int buildin_areawarp_sub(struct block_list *bl, va_list ap)
tx = rnd()%(x3-x2+1)+x2;
ty = rnd()%(y3-y2+1)+y2;
j++;
- } while (map->getcell(index, bl, tx, ty, CELL_CHKNOPASS) && j < max);
+ } while (map->getcell(m, bl, tx, ty, CELL_CHKNOPASS) && j < max);
pc->setpos(sd, index, tx, ty, CLR_OUTSIGHT);
} else {
@@ -6622,7 +6701,8 @@ BUILDIN(itemheal)
}
sd = script->rid2sd(st);
- if (!sd) return true;
+ if (sd == NULL)
+ return true;
pc->itemheal(sd,sd->itemid,hp,sp);
return true;
}
@@ -6644,13 +6724,16 @@ BUILDIN(percentheal)
}
sd = script->rid2sd(st);
- if( sd == NULL )
+ if (sd == NULL)
return true;
#ifdef RENEWAL
if( sd->sc.data[SC_EXTREMITYFIST2] )
sp = 0;
#endif
- pc->percentheal(sd,hp,sp);
+ if (sd->sc.data[SC_BITESCAR]) {
+ hp = 0;
+ }
+ pc->percentheal(sd, hp, sp);
return true;
}
@@ -8023,7 +8106,11 @@ BUILDIN(makeitem2)
void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, bool delete_items)
{
int delamount;
- struct item* inv = &sd->status.inventory[idx];
+ struct item* inv;
+
+ nullpo_retv(sd);
+ nullpo_retv(amount);
+ inv = &sd->status.inventory[idx];
delamount = ( amount[0] < inv->amount ) ? amount[0] : inv->amount;
@@ -8050,6 +8137,8 @@ bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool e
int i, amount;
struct item* inv;
+ nullpo_retr(false, sd);
+ nullpo_retr(false, it);
// prefer always non-equipped items
it->equip = 0;
@@ -9268,7 +9357,7 @@ BUILDIN(bonus) {
val1 = skill->name2id(script_getstr(st, 3));
break;
}
- // else fall through
+ FALLTHROUGH
default:
val1 = script_getnum(st,3);
break;
@@ -9316,7 +9405,8 @@ BUILDIN(bonus) {
return true;
}
-BUILDIN(autobonus) {
+BUILDIN(autobonus)
+{
unsigned int dur;
short rate;
short atk_type = 0;
@@ -9325,7 +9415,7 @@ BUILDIN(autobonus) {
if (sd == NULL)
return true; // no player attached
- if( sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip )
+ if (status->current_equip_item_index < 0 || sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip)
return true;
rate = script_getnum(st,3);
@@ -9350,7 +9440,8 @@ BUILDIN(autobonus) {
return true;
}
-BUILDIN(autobonus2) {
+BUILDIN(autobonus2)
+{
unsigned int dur;
short rate;
short atk_type = 0;
@@ -9359,7 +9450,7 @@ BUILDIN(autobonus2) {
if (sd == NULL)
return true; // no player attached
- if( sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip )
+ if (status->current_equip_item_index < 0 || sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip)
return true;
rate = script_getnum(st,3);
@@ -9384,7 +9475,8 @@ BUILDIN(autobonus2) {
return true;
}
-BUILDIN(autobonus3) {
+BUILDIN(autobonus3)
+{
unsigned int dur;
short rate,atk_type;
const char *bonus_script, *other_script = NULL;
@@ -9392,7 +9484,7 @@ BUILDIN(autobonus3) {
if (sd == NULL)
return true; // no player attached
- if( sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip )
+ if (status->current_equip_item_index < 0 || sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip)
return true;
rate = script_getnum(st,3);
@@ -9489,6 +9581,9 @@ BUILDIN(guildskill) {
skill_id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) );
level = script_getnum(st,3);
+ if (skill_id < GD_SKILLBASE || skill_id >= GD_MAX)
+ return true; // not guild skill
+
id = skill_id - GD_SKILLBASE;
max_points = guild->skill_get_max(skill_id);
@@ -11173,6 +11268,7 @@ BUILDIN(getmapusers) {
int buildin_getareausers_sub(struct block_list *bl,va_list ap)
{
int *users=va_arg(ap,int *);
+ nullpo_ret(users);
(*users)++;
return 0;
}
@@ -12003,6 +12099,7 @@ BUILDIN(getwaitingroomstate)
case 0:
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);
}
script_pushint(st, cd->users);
@@ -12058,6 +12155,7 @@ BUILDIN(warpwaitingpc)
for (i = 0; i < n && cd->users > 0; i++) {
struct map_session_data *sd = cd->usersd[0];
+ nullpo_retr(false, sd);
if (strcmp(map_name,"SavePoint") == 0 && map->list[sd->bl.m].flag.noteleport) {
// can't teleport on this map
break;
@@ -13802,6 +13900,7 @@ int playbgm_foreachpc_sub(struct map_session_data* sd, va_list args)
{
const char* name = va_arg(args, const char*);
+ nullpo_ret(name);
clif->playBGM(sd, name);
return 0;
}
@@ -15119,7 +15218,10 @@ BUILDIN(getrefine)
if (sd == NULL)
return true;
- script_pushint(st,sd->status.inventory[status->current_equip_item_index].refine);
+ if (status->current_equip_item_index < 0)
+ script_pushint(st, 0);
+ else
+ script_pushint(st, sd->status.inventory[status->current_equip_item_index].refine);
return true;
}
@@ -16070,6 +16172,10 @@ BUILDIN(sqrt) //[zBuffer]
{
double i, a;
i = script_getnum(st,2);
+ if (i < 0) {
+ ShowError("sqrt from negative value\n");
+ return false;
+ }
a = sqrt(i);
script_pushint(st,(int)a);
return true;
@@ -18127,7 +18233,8 @@ BUILDIN(bg_getareausers)
return true;
}
-BUILDIN(bg_updatescore) {
+BUILDIN(bg_updatescore)
+{
const char *str;
int16 m;
@@ -18169,7 +18276,8 @@ BUILDIN(bg_get_data)
* Instancing Script Commands
*------------------------------------------*/
-BUILDIN(instance_create) {
+BUILDIN(instance_create)
+{
const char *name;
int owner_id, res;
int type = IOT_PARTY;
@@ -18205,7 +18313,8 @@ BUILDIN(instance_create) {
return true;
}
-BUILDIN(instance_destroy) {
+BUILDIN(instance_destroy)
+{
int instance_id = -1;
if( script_hasdata(st, 2) )
@@ -18304,7 +18413,8 @@ BUILDIN(instance_set_timeout)
return true;
}
-BUILDIN(instance_init) {
+BUILDIN(instance_init)
+{
int instance_id = script_getnum(st, 2);
if( !instance->valid(instance_id) ) {
@@ -18352,7 +18462,8 @@ BUILDIN(instance_announce)
return true;
}
-BUILDIN(instance_npcname) {
+BUILDIN(instance_npcname)
+{
const char *str;
int instance_id = -1;
struct npc_data *nd;
@@ -18376,7 +18487,8 @@ BUILDIN(instance_npcname) {
return true;
}
-BUILDIN(has_instance) {
+BUILDIN(has_instance)
+{
struct map_session_data *sd;
const char *str;
int16 m;
@@ -18465,7 +18577,9 @@ int buildin_instance_warpall_sub(struct block_list *bl, va_list ap)
return 0;
}
-BUILDIN(instance_warpall) {
+
+BUILDIN(instance_warpall)
+{
int16 m;
int instance_id = -1;
const char *mapn;
@@ -18673,10 +18787,12 @@ int buildin_mobuseskill_sub(struct block_list *bl, va_list ap)
return 0;
}
+
/*==========================================
* areamobuseskill "Map Name",<x>,<y>,<range>,<Mob ID>,"Skill Name"/<Skill ID>,<Skill Lv>,<Cast Time>,<Cancelable>,<Emotion>,<Target Type>;
*------------------------------------------*/
-BUILDIN(areamobuseskill) {
+BUILDIN(areamobuseskill)
+{
struct block_list center;
int16 m;
int range,mobid,skill_id,skill_lv,casttime,emotion,target,cancel;
@@ -18741,8 +18857,7 @@ BUILDIN(pushpc)
dir = script_getnum(st,2);
cells = script_getnum(st,3);
- if(dir>7)
- {
+ if (dir > 7) {
ShowWarning("buildin_pushpc: Invalid direction %d specified.\n", dir);
script->reportsrc(st);
@@ -18897,7 +19012,8 @@ BUILDIN(setcashmount)
* Retrieves quantity of arguments provided to callfunc/callsub.
* getargcount() -> amount of arguments received in a function
**/
-BUILDIN(getargcount) {
+BUILDIN(getargcount)
+{
struct script_retinfo* ri;
if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO ) {
@@ -18911,10 +19027,12 @@ BUILDIN(getargcount) {
return true;
}
+
/**
* getcharip(<account ID>/<character ID>/<character name>)
**/
-BUILDIN(getcharip) {
+BUILDIN(getcharip)
+{
struct map_session_data* sd = NULL;
/* check if a character name is specified */
@@ -18937,7 +19055,7 @@ BUILDIN(getcharip) {
return false;
}
- if (sd->fd == 0 || sockt->session[sd->fd] == NULL || sockt->session[sd->fd]->client_addr == 0) {
+ if (sd->fd <= 0 || sockt->session[sd->fd] == NULL || sockt->session[sd->fd]->client_addr == 0) {
script_pushconststr(st, "");
} else {
uint32 ip = sockt->session[sd->fd]->client_addr;
@@ -18947,10 +19065,12 @@ BUILDIN(getcharip) {
return true;
}
+
/**
* is_function(<function name>) -> 1 if function exists, 0 otherwise
**/
-BUILDIN(is_function) {
+BUILDIN(is_function)
+{
const char* str = script_getstr(st,2);
if( strdb_exists(script->userfunc_db, str) )
@@ -18960,11 +19080,12 @@ BUILDIN(is_function) {
return true;
}
+
/**
* freeloop(<toggle>) -> toggles this script instance's looping-check ability
**/
-BUILDIN(freeloop) {
-
+BUILDIN(freeloop)
+{
if( script_getnum(st,2) )
st->freeloop = 1;
else
@@ -18975,7 +19096,8 @@ BUILDIN(freeloop) {
return true;
}
-BUILDIN(sit) {
+BUILDIN(sit)
+{
struct map_session_data *sd = NULL;
if (script_hasdata(st, 2))
@@ -18995,7 +19117,8 @@ BUILDIN(sit) {
return true;
}
-BUILDIN(stand) {
+BUILDIN(stand)
+{
struct map_session_data *sd = NULL;
if (script_hasdata(st, 2))
@@ -19015,7 +19138,8 @@ BUILDIN(stand) {
return true;
}
-BUILDIN(issit) {
+BUILDIN(issit)
+{
struct map_session_data *sd = NULL;
if (script_hasdata(st, 2))
@@ -19036,7 +19160,8 @@ BUILDIN(issit) {
/**
* @commands (script based)
**/
-BUILDIN(bindatcmd) {
+BUILDIN(bindatcmd)
+{
const char* atcmd;
const char* eventName;
int i, group_lv = 0, group_lv_char = 99;
@@ -19086,7 +19211,8 @@ BUILDIN(bindatcmd) {
return true;
}
-BUILDIN(unbindatcmd) {
+BUILDIN(unbindatcmd)
+{
const char* atcmd;
int i = 0;
@@ -19127,7 +19253,8 @@ BUILDIN(unbindatcmd) {
return true;
}
-BUILDIN(useatcmd) {
+BUILDIN(useatcmd)
+{
struct map_session_data *sd, *dummy_sd = NULL;
int fd;
const char* cmd;
@@ -19165,7 +19292,8 @@ BUILDIN(useatcmd) {
}
/* getrandgroupitem <container_item_id>,<quantity> */
-BUILDIN(getrandgroupitem) {
+BUILDIN(getrandgroupitem)
+{
struct item_data *data = NULL;
struct map_session_data *sd = NULL;
int nameid = script_getnum(st, 2);
@@ -19218,8 +19346,8 @@ BUILDIN(getrandgroupitem) {
/* cleanmap <map_name>;
* cleanarea <map_name>, <x0>, <y0>, <x1>, <y1>; */
-int script_cleanfloor_sub(struct block_list *bl, va_list ap) {
- nullpo_ret(bl);
+int script_cleanfloor_sub(struct block_list *bl, va_list ap)
+{
map->clearflooritem(bl);
return 0;
@@ -19250,6 +19378,7 @@ BUILDIN(cleanmap)
return true;
}
+
/* Cast a skill on the attached player.
* npcskill <skill id>, <skill lvl>, <stat point>, <NPC level>;
* npcskill "<skill name>", <skill lvl>, <stat point>, <NPC level>; */
@@ -19299,7 +19428,8 @@ BUILDIN(npcskill)
/* Turns a player into a monster and grants SC attribute effect. [malufett/Hercules]
* montransform <monster name/id>, <duration>, <sc type>, <val1>, <val2>, <val3>, <val4>; */
-BUILDIN(montransform) {
+BUILDIN(montransform)
+{
int tick;
enum sc_type type;
struct block_list* bl;
@@ -20022,7 +20152,8 @@ BUILDIN(bg_match_over)
return true;
}
-BUILDIN(instance_mapname) {
+BUILDIN(instance_mapname)
+{
const char *map_name;
int m;
short instance_id = -1;
@@ -20042,10 +20173,12 @@ BUILDIN(instance_mapname) {
return true;
}
+
/* modify an instances' reload-spawn point */
/* instance_set_respawn <map_name>,<x>,<y>{,<instance_id>} */
/* returns 1 when successful, 0 otherwise. */
-BUILDIN(instance_set_respawn) {
+BUILDIN(instance_set_respawn)
+{
const char *map_name;
short instance_id = -1;
short mid;
@@ -20086,6 +20219,7 @@ BUILDIN(instance_set_respawn) {
}
return true;
}
+
/**
* @call openshop({NPC Name});
*
@@ -20121,13 +20255,15 @@ BUILDIN(openshop)
return true;
}
+
/**
* @call sellitem <Item_ID>,{,price{,qty}};
*
* adds <Item_ID> (or modifies if present) to shop
* if price not provided (or -1) uses the item's value_sell
**/
-BUILDIN(sellitem) {
+BUILDIN(sellitem)
+{
struct npc_data *nd;
struct item_data *it;
int i = 0, id = script_getnum(st,2);
@@ -20194,6 +20330,7 @@ BUILDIN(sellitem) {
return true;
}
+
/**
* @call stopselling <Item_ID>;
*
@@ -20201,7 +20338,8 @@ BUILDIN(sellitem) {
*
* @return 1 on success, 0 otherwise
**/
-BUILDIN(stopselling) {
+BUILDIN(stopselling)
+{
struct npc_data *nd;
int i, id = script_getnum(st,2);
@@ -20244,6 +20382,7 @@ BUILDIN(stopselling) {
return true;
}
+
/**
* @call setcurrency <Val1>{,<Val2>};
*
@@ -20266,6 +20405,7 @@ BUILDIN(setcurrency)
return true;
}
+
/**
* @call tradertype(<type>);
*
@@ -20273,7 +20413,8 @@ BUILDIN(setcurrency)
* check enum npc_shop_types for list
* cleans shop list on use
**/
-BUILDIN(tradertype) {
+BUILDIN(tradertype)
+{
int type = script_getnum(st, 2);
struct npc_data *nd;
@@ -20309,12 +20450,14 @@ BUILDIN(tradertype) {
return true;
}
+
/**
* @call purchaseok();
*
* signs the transaction can proceed
**/
-BUILDIN(purchaseok) {
+BUILDIN(purchaseok)
+{
struct npc_data *nd;
if( !(nd = map->id2nd(st->oid)) || !nd->u.scr.shop ) {
@@ -20326,12 +20469,14 @@ BUILDIN(purchaseok) {
return true;
}
+
/**
* @call shopcount(<Item_ID>);
*
* @return number of available items in the script's attached shop
**/
-BUILDIN(shopcount) {
+BUILDIN(shopcount)
+{
struct npc_data *nd;
int id = script_getnum(st, 2);
unsigned short i;
@@ -20389,7 +20534,8 @@ BUILDIN(channelmes)
Display script message
showscript "<message>"{,<GID>};
*/
-BUILDIN(showscript) {
+BUILDIN(showscript)
+{
struct block_list *bl = NULL;
const char *msg = script_getstr(st, 2);
int id = 0;
@@ -20426,8 +20572,10 @@ BUILDIN(mergeitem)
return true;
}
+
/** place holder for the translation macro **/
-BUILDIN(_) {
+BUILDIN(_)
+{
return true;
}
@@ -20437,7 +20585,8 @@ BUILDIN(activatepset);
BUILDIN(deactivatepset);
BUILDIN(deletepset);
-BUILDIN(pcre_match) {
+BUILDIN(pcre_match)
+{
const char *input = script_getstr(st, 2);
const char *regex = script_getstr(st, 3);
@@ -20446,6 +20595,48 @@ BUILDIN(pcre_match) {
}
/**
+ * navigateto("<map>"{,<x>,<y>,<flag>,<hide_window>,<monster_id>,<char_id>});
+ */
+BUILDIN(navigateto)
+{
+#if PACKETVER >= 20111010
+ struct map_session_data* sd;
+ const char *mapname;
+ uint16 x = 0;
+ uint16 y = 0;
+ uint16 monster_id = 0;
+ uint8 flag = NAV_KAFRA_AND_AIRSHIP;
+ bool hideWindow = true;
+
+ mapname = script_getstr(st, 2);
+
+ if (script_hasdata(st, 3))
+ x = script_getnum(st, 3);
+ if (script_hasdata(st, 4))
+ y = script_getnum(st, 4);
+ if (script_hasdata(st, 5))
+ flag = (uint8)script_getnum(st, 5);
+ if (script_hasdata(st, 6))
+ hideWindow = script_getnum(st, 6) ? true : false;
+ if (script_hasdata(st, 7))
+ monster_id = script_getnum(st, 7);
+
+ if (script_hasdata(st, 8)) {
+ sd = map->charid2sd(script_getnum(st, 8));
+ } else {
+ sd = script->rid2sd(st);
+ }
+
+ clif->navigate_to(sd, mapname, x, y, flag, hideWindow, monster_id);
+
+ return true;
+#else
+ ShowError("Navigation system works only with packet version >= 20111010");
+ return false;
+#endif
+}
+
+/**
* Adds a built-in script function.
*
* @param buildin Script function data
@@ -20453,7 +20644,8 @@ BUILDIN(pcre_match) {
* (i.e. a plugin overriding a built-in function)
* @return Whether the function was successfully added.
*/
-bool script_add_builtin(const struct script_function *buildin, bool override) {
+bool script_add_builtin(const struct script_function *buildin, bool override)
+{
int n = 0, offset = 0;
size_t slen;
if( !buildin ) {
@@ -20534,7 +20726,8 @@ bool script_add_builtin(const struct script_function *buildin, bool override) {
return true;
}
-bool script_hp_add(char *name, char *args, bool (*func)(struct script_state *st), bool isDeprecated) {
+bool script_hp_add(char *name, char *args, bool (*func)(struct script_state *st), bool isDeprecated)
+{
struct script_function buildin;
buildin.name = name;
buildin.arg = args;
@@ -20554,6 +20747,7 @@ void script_run_use_script(struct map_session_data *sd, struct item_data *data,
*/
void script_run_use_script(struct map_session_data *sd, struct item_data *data, int oid)
{
+ nullpo_retv(data);
script->current_item_id = data->nameid;
script->run(data->script, 0, sd->bl.id, oid);
script->current_item_id = 0;
@@ -21112,6 +21306,9 @@ void script_parse_builtin(void) {
BUILDIN_DEF(purchaseok,""),
BUILDIN_DEF(shopcount, "i"),
+ /* Navigation */
+ BUILDIN_DEF(navigateto, "s??????"),
+
BUILDIN_DEF(channelmes, "ss"),
BUILDIN_DEF(showscript, "s?"),
BUILDIN_DEF(mergeitem,""),
@@ -21128,7 +21325,8 @@ void script_parse_builtin(void) {
#undef BUILDIN_DEF
#undef BUILDIN_DEF2
-void script_label_add(int key, int pos) {
+void script_label_add(int key, int pos)
+{
int idx = script->label_count;
if( script->labels_size == script->label_count ) {
@@ -21265,6 +21463,16 @@ void script_hardcoded_constants(void)
script->set_constant("EQP_SHADOW_ACC_R", EQP_SHADOW_ACC_R, false, false);
script->set_constant("EQP_SHADOW_ACC_L", EQP_SHADOW_ACC_L, false, false);
+ script->constdb_comment("Navigation constants, use with *navigateto*");
+ script->set_constant("NAV_NONE", NAV_NONE, false, false);
+ script->set_constant("NAV_AIRSHIP_ONLY", NAV_AIRSHIP_ONLY, false, false);
+ script->set_constant("NAV_SCROLL_ONLY", NAV_SCROLL_ONLY, false, false);
+ script->set_constant("NAV_AIRSHIP_AND_SCROLL", NAV_AIRSHIP_AND_SCROLL, false, false);
+ script->set_constant("NAV_KAFRA_ONLY", NAV_KAFRA_ONLY, false, false);
+ script->set_constant("NAV_KAFRA_AND_AIRSHIP", NAV_KAFRA_AND_AIRSHIP, false, false);
+ script->set_constant("NAV_KAFRA_AND_SCROLL", NAV_KAFRA_AND_SCROLL, false, false);
+ script->set_constant("NAV_ALL", NAV_ALL, false, false);
+
script->constdb_comment("Renewal");
#ifdef RENEWAL
script->set_constant("RENEWAL", 1, false, false);
@@ -21307,7 +21515,8 @@ void script_hardcoded_constants(void)
/**
* a mapindex_name2id wrapper meant to help with invalid name handling
**/
-unsigned short script_mapindexname2id (struct script_state *st, const char* name) {
+unsigned short script_mapindexname2id (struct script_state *st, const char* name)
+{
unsigned short index;
if( !(index=mapindex->name2id(name)) ) {
@@ -21317,7 +21526,8 @@ unsigned short script_mapindexname2id (struct script_state *st, const char* name
return index;
}
-void script_defaults(void) {
+void script_defaults(void)
+{
// aegis->athena slot position conversion table
unsigned int equip[SCRIPT_EQUIP_TABLE_SIZE] = {EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_GARMENT,EQP_SHOES,EQP_ACC_L,EQP_ACC_R,EQP_HEAD_MID,EQP_HEAD_LOW,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_GARMENT,EQP_SHADOW_ARMOR, EQP_SHADOW_WEAPON, EQP_SHADOW_SHIELD, EQP_SHADOW_SHOES, EQP_SHADOW_ACC_R, EQP_SHADOW_ACC_L};