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.c127
1 files changed, 86 insertions, 41 deletions
diff --git a/src/map/script.c b/src/map/script.c
index 59a9b5448..f842b614a 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -70,6 +70,7 @@
// - remove dynamic allocation in add_word()
// - remove GETVALUE / SETVALUE
// - clean up the set_reg / set_val / setd_sub mess
+// - detect invalid label references at parse-time
//
// struct script_state* st;
@@ -977,6 +978,23 @@ const char* parse_callfunc(const char* p, int require_paren)
return p;
}
+/// Processes end of logical script line.
+/// @param first When true, only fix up scheduling data is initialized
+/// @param p Script position for error reporting in set_label
+static void parse_nextline(bool first, const char* p)
+{
+ if( !first )
+ {
+ add_scriptc(C_EOL); // mark end of line for stack cleanup
+ set_label(LABEL_NEXTLINE, script_pos, p); // fix up '-' labels
+ }
+
+ // initialize data for new '-' label fix up scheduling
+ str_data[LABEL_NEXTLINE].type = C_NOP;
+ str_data[LABEL_NEXTLINE].backpatch = -1;
+ str_data[LABEL_NEXTLINE].label = -1;
+}
+
/*==========================================
* 項の解析
*------------------------------------------*/
@@ -1541,12 +1559,17 @@ const char* parse_syntax(const char* p)
// function declaration - just register the name
int l;
l = add_word(func_name);
- if( str_data[l].type == C_NOP )// set type only if the name did not exist before
+ if( str_data[l].type == C_NOP )// register only, if the name was not used by something else
str_data[l].type = C_USERFUNC;
+ else if( str_data[l].type == C_USERFUNC )
+ ; // already registered
+ else
+ disp_error_message("parse_syntax:function: function name is invalid", func_name);
// if, for , while の閉じ判定
p = parse_syntax_close(p2 + 1);
- return p; }
+ return p;
+ }
else if(*p2 == '{')
{// function <name> <line/block of code>
char label[256];
@@ -1567,11 +1590,16 @@ const char* parse_syntax(const char* p)
// Set the position of the function (label)
l=add_word(func_name);
- if( str_data[l].type == C_NOP )// set type only if the name did not exist before
+ if( str_data[l].type == C_NOP || str_data[l].type == C_USERFUNC )// register only, if the name was not used by something else
+ {
str_data[l].type = C_USERFUNC;
- set_label(l, script_pos, p);
- if( parse_options&SCRIPT_USE_LABEL_DB )
- strdb_put(scriptlabel_db, get_str(l), (void*)script_pos);
+ set_label(l, script_pos, p);
+ if( parse_options&SCRIPT_USE_LABEL_DB )
+ strdb_put(scriptlabel_db, get_str(l), (void*)script_pos);
+ }
+ else
+ disp_error_message("parse_syntax:function: function name is invalid", func_name);
+
return skip_space(p);
}
else
@@ -1691,6 +1719,10 @@ const char* parse_syntax_close_sub(const char* p,int* flag)
} else if(syntax.curly[pos].type == TYPE_IF) {
const char *bp = p;
const char *p2;
+
+ // if-block and else-block end is a new line
+ parse_nextline(false, p);
+
// if 最終場所へ飛ばす
sprintf(label,"goto __IF%x_FIN;",syntax.curly[pos].index);
syntax.curly[syntax.curly_count++].type = TYPE_NULL;
@@ -1766,6 +1798,10 @@ const char* parse_syntax_close_sub(const char* p,int* flag)
if(*p != '(') {
disp_error_message("need '('",p);
}
+
+ // do-block end is a new line
+ parse_nextline(false, p);
+
sprintf(label,"__DO%x_FIN",syntax.curly[pos].index);
add_scriptl(add_str("jump_zero"));
add_scriptc(C_ARG);
@@ -1793,6 +1829,9 @@ const char* parse_syntax_close_sub(const char* p,int* flag)
syntax.curly_count--;
return p;
} else if(syntax.curly[pos].type == TYPE_FOR) {
+ // for-block end is a new line
+ parse_nextline(false, p);
+
// 次のループに飛ばす
sprintf(label,"goto __FR%x_NXT;",syntax.curly[pos].index);
syntax.curly[syntax.curly_count++].type = TYPE_NULL;
@@ -1806,6 +1845,9 @@ const char* parse_syntax_close_sub(const char* p,int* flag)
syntax.curly_count--;
return p;
} else if(syntax.curly[pos].type == TYPE_WHILE) {
+ // while-block end is a new line
+ parse_nextline(false, p);
+
// while 条件判断へ飛ばす
sprintf(label,"goto __WL%x_NXT;",syntax.curly[pos].index);
syntax.curly[syntax.curly_count++].type = TYPE_NULL;
@@ -1974,6 +2016,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
struct script_code* code = NULL;
static int first=1;
char end;
+ bool unresolved_names = false;
if( src == NULL )
return NULL;// empty script
@@ -1988,9 +2031,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
script_buf=(unsigned char *)aMalloc(SCRIPT_BLOCK_SIZE*sizeof(unsigned char));
script_pos=0;
script_size=SCRIPT_BLOCK_SIZE;
- str_data[LABEL_NEXTLINE].type=C_NOP;
- str_data[LABEL_NEXTLINE].backpatch=-1;
- str_data[LABEL_NEXTLINE].label=-1;
+ parse_nextline(true, NULL);
// who called parse_script is responsible for clearing the database after using it, but just in case... lets clear it here
if( options&SCRIPT_USE_LABEL_DB )
@@ -2077,12 +2118,8 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
// 他は全部一緒くた
p=parse_line(p);
p=skip_space(p);
- add_scriptc(C_EOL);
- set_label(LABEL_NEXTLINE,script_pos,p);
- str_data[LABEL_NEXTLINE].type=C_NOP;
- str_data[LABEL_NEXTLINE].backpatch=-1;
- str_data[LABEL_NEXTLINE].label=-1;
+ parse_nextline(false, p);
}
add_scriptc(C_NOP);
@@ -2103,13 +2140,23 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
j=next;
}
}
+ else if( str_data[i].type == C_USERFUNC )
+ {// 'function name;' without follow-up code
+ ShowError("parse_script: function '%s' declared but not defined.\n", str_buf+str_data[i].str);
+ unresolved_names = true;
+ }
+ }
+
+ if( unresolved_names )
+ {
+ disp_error_message("parse_script: unresolved function references", p);
}
#ifdef DEBUG_DISP
for(i=0;i<script_pos;i++){
- if((i&15)==0) printf("%04x : ",i);
+ if((i&15)==0) ShowMessage("%04x : ",i);
ShowMessage("%02x ",script_buf[i]);
- if((i&15)==15) printf("\n");
+ if((i&15)==15) ShowMessage("\n");
}
ShowMessage("\n");
#endif
@@ -3235,7 +3282,7 @@ int run_script_timer(int tid, unsigned int tick, int id, intptr data)
st->rid = 0;
st->state = END;
}
- while( node && st->sleep.timer != -1 ) {
+ while( node && st->sleep.timer != INVALID_TIMER ) {
if( (int)node->key == st->oid && ((struct script_state *)node->data)->sleep.timer == st->sleep.timer ) {
script_erase_sleepdb(node);
st->sleep.timer = INVALID_TIMER;
@@ -4882,8 +4929,8 @@ BUILDIN_FUNC(setarray)
}
end = start + script_lastdata(st) - 2;
- if( end >= SCRIPT_MAX_ARRAYSIZE )
- end = SCRIPT_MAX_ARRAYSIZE-1;
+ if( end > SCRIPT_MAX_ARRAYSIZE )
+ end = SCRIPT_MAX_ARRAYSIZE;
if( is_string_variable(name) )
{// string array
@@ -4945,10 +4992,10 @@ BUILDIN_FUNC(cleararray)
v = (void*)script_getnum(st, 3);
end = start + script_getnum(st, 4);
- if( end >= SCRIPT_MAX_ARRAYSIZE )
- end = SCRIPT_MAX_ARRAYSIZE-1;
+ if( end > SCRIPT_MAX_ARRAYSIZE )
+ end = SCRIPT_MAX_ARRAYSIZE;
- for( ; start <= end; ++start )
+ for( ; start < end; ++start )
set_reg(st, sd, reference_uid(id, start), name, v, script_getref(st,2));
return 0;
}
@@ -5015,8 +5062,8 @@ BUILDIN_FUNC(copyarray)
}
count = script_getnum(st, 4);
- if( count >= SCRIPT_MAX_ARRAYSIZE - idx1 )
- count = (SCRIPT_MAX_ARRAYSIZE-1) - idx1;
+ if( count > SCRIPT_MAX_ARRAYSIZE - idx1 )
+ count = SCRIPT_MAX_ARRAYSIZE - idx1;
if( count <= 0 || (id1 == id2 && idx1 == idx2) )
return 0;// nothing to copy
@@ -5121,7 +5168,8 @@ BUILDIN_FUNC(deletearray)
return 0;// no player attached
}
- end = getarraysize(st, id, start, is_string_variable(name), reference_getref(data));
+ end = SCRIPT_MAX_ARRAYSIZE;
+
if( start >= end )
return 0;// nothing to free
@@ -6191,7 +6239,7 @@ BUILDIN_FUNC(readparam)
if( script_hasdata(st,3) )
sd=map_nick2sd(script_getstr(st,3));
else
- sd=script_rid2sd(st);
+ sd=script_rid2sd(st);
if(sd==NULL){
script_pushint(st,-1);
@@ -8321,10 +8369,10 @@ BUILDIN_FUNC(getnpctimer)
ShowError("buildin_getnpctimer: Attached player not found!\n");
break;
}
- val = (sd->npc_timer_id != -1);
+ val = (sd->npc_timer_id != INVALID_TIMER);
}
else
- val = (nd->u.scr.timerid !=-1);
+ val = (nd->u.scr.timerid != INVALID_TIMER);
break;
case 2: val = nd->u.scr.timeramount; break;
}
@@ -9705,7 +9753,7 @@ BUILDIN_FUNC(pvpon)
iter = mapit_getallusers();
for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
{
- if( sd->bl.m != m || sd->pvp_timer != -1 )
+ if( sd->bl.m != m || sd->pvp_timer != INVALID_TIMER )
continue; // not applicable
sd->pvp_timer = add_timer(gettick()+200,pc_calc_pvprank_timer,sd->bl.id,0);
@@ -9724,7 +9772,7 @@ static int buildin_pvpoff_sub(struct block_list *bl,va_list ap)
{
TBL_PC* sd = (TBL_PC*)bl;
clif_pvpset(sd, 0, 0, 2);
- if (sd->pvp_timer != -1) {
+ if (sd->pvp_timer != INVALID_TIMER) {
delete_timer(sd->pvp_timer, pc_calc_pvprank_timer);
sd->pvp_timer = INVALID_TIMER;
}
@@ -10809,7 +10857,7 @@ BUILDIN_FUNC(petskillbonus)
pd=sd->pd;
if (pd->bonus)
{ //Clear previous bonus
- if (pd->bonus->timer != -1)
+ if (pd->bonus->timer != INVALID_TIMER)
delete_timer(pd->bonus->timer, pet_skill_bonus_timer);
} else //init
pd->bonus = (struct pet_bonus *) aMalloc(sizeof(struct pet_bonus));
@@ -11162,7 +11210,7 @@ BUILDIN_FUNC(petrecovery)
if (pd->recovery)
{ //Halt previous bonus
- if (pd->recovery->timer != -1)
+ if (pd->recovery->timer != INVALID_TIMER)
delete_timer(pd->recovery->timer, pet_recovery_timer);
} else //Init
pd->recovery = (struct pet_recovery *)aMalloc(sizeof(struct pet_recovery));
@@ -11188,7 +11236,7 @@ BUILDIN_FUNC(petheal)
pd=sd->pd;
if (pd->s_skill)
{ //Clear previous skill
- if (pd->s_skill->timer != -1)
+ if (pd->s_skill->timer != INVALID_TIMER)
{
if (pd->s_skill->id)
delete_timer(pd->s_skill->timer, pet_skill_support_timer);
@@ -11282,7 +11330,7 @@ BUILDIN_FUNC(petskillsupport)
pd=sd->pd;
if (pd->s_skill)
{ //Clear previous skill
- if (pd->s_skill->timer != -1)
+ if (pd->s_skill->timer != INVALID_TIMER)
{
if (pd->s_skill->id)
delete_timer(pd->s_skill->timer, pet_skill_support_timer);
@@ -11636,9 +11684,6 @@ BUILDIN_FUNC(jump_zero)
pos=script_getnum(st,3);
st->pos=pos;
st->state=GOTO;
- // printf("script: jump_zero: jumpto : %d\n",pos);
- } else {
- // printf("script: jump_zero: fail\n");
}
return 0;
}
@@ -12312,7 +12357,7 @@ BUILDIN_FUNC(autoequip)
struct item_data *item_data;
nameid=script_getnum(st,2);
flag=script_getnum(st,3);
- if(nameid>=500 && (item_data = itemdb_search(nameid)) != NULL){
+ if(nameid>=500 && (item_data = itemdb_exists(nameid)) != NULL){
item_data->flag.autoequip = flag>0?1:0;
}
return 0;
@@ -12362,7 +12407,7 @@ BUILDIN_FUNC(charisalpha)
const char *str=script_getstr(st,2);
int pos=script_getnum(st,3);
- int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISALPHA( str[pos] ) : 0;
+ int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISALPHA( str[pos] ) != 0 : 0;
script_pushint(st,val);
return 0;
@@ -13557,7 +13602,7 @@ BUILDIN_FUNC(awake)
struct script_state* tst = (struct script_state*)node->data;
TBL_PC* sd = map_id2sd(tst->rid);
- if( tst->sleep.timer == -1 )
+ if( tst->sleep.timer == INVALID_TIMER )
{// already awake ???
node = node->next;
continue;
@@ -14590,7 +14635,7 @@ static int buildin_mobuseskill_sub(struct block_list *bl,va_list ap)
if( md->class_ != mobid )
return 0;
- if( md->ud.skilltimer != -1 ) // Cancel the casting skill.
+ if( md->ud.skilltimer != INVALID_TIMER ) // Cancel the casting skill.
unit_skillcastcancel(bl,0);
// 0:self, 1:target, 2:master, default:random