瀏覽代碼

* Fixed script command sc_end not supporting the extra argument as stated in script_commands.txt.
* Script command getarg supports an extra argument with a default value that is returned if the requested argument doesn't exist.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@10773 54d463be-8e91-2dee-dedb-b68131a5f0ec

FlavioJS 18 年之前
父節點
當前提交
2d1ad607c3
共有 4 個文件被更改,包括 162 次插入107 次删除
  1. 5 0
      Changelog-Trunk.txt
  2. 8 1
      doc/script_commands.txt
  3. 147 104
      src/map/script.c
  4. 2 2
      src/map/status.c

+ 5 - 0
Changelog-Trunk.txt

@@ -3,6 +3,11 @@ Date	Added
 AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
 AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 
+2007/06/15
+	* Fixed script command sc_end not supporting the extra argument as stated 
+	  in script_commands.txt.
+	* Script command getarg supports an extra argument with a default value 
+	  that is returned if the requested argument doesn't exist. [FlavioJS]
 2007/06/11
 2007/06/11
 	* Fixed NPC_PROVOCATION (now the casting mob doesn't keep attacking)
 	* Fixed NPC_PROVOCATION (now the casting mob doesn't keep attacking)
 	* accumulated clif.c fixes [ultramage]
 	* accumulated clif.c fixes [ultramage]

+ 8 - 1
doc/script_commands.txt

@@ -1402,7 +1402,7 @@ script.
 
 
 ---------------------------------------
 ---------------------------------------
 
 
-*getarg(<number>)
+*getarg(<index>{,<default_value>})
 
 
 This function is used when you use the 'callsub' or 'callfunc' commands. In the 
 This function is used when you use the 'callsub' or 'callfunc' commands. In the 
 call you can specify variables that will make that call different from another 
 call you can specify variables that will make that call different from another 
@@ -1446,6 +1446,13 @@ You can pass multiple arguments in a function call:
 
 
 getarg(0) would be 5, getarg(1) would be 4 and getarg(2) would be 3.
 getarg(0) would be 5, getarg(1) would be 4 and getarg(2) would be 3.
 
 
+Getarg has an optional argument since trunk r10773.
+If the target argument exists, it is returned.
+Otherwise, if <default_value> is present it is returned instead, 
+if not the script terminates immediately.
+
+in the previous example getarg(2,-1) would be 3 and getarg(3,-1) would be -1
+
 ---------------------------------------
 ---------------------------------------
 
 
 *return {<value>};
 *return {<value>};

+ 147 - 104
src/map/script.c

@@ -51,6 +51,16 @@
 #include <time.h>
 #include <time.h>
 #include <setjmp.h>
 #include <setjmp.h>
 
 
+///////////////////////////////////////////////////////////////////////////////
+//## TODO possible enhancements:
+// - 'callfunc' supporting labels in the current npc "::LabelName"
+// - 'callfunc' supporting labels in other npcs "NpcName::LabelName"
+// - 'function FuncName;' function declarations reverting to global functions 
+//   if local label isn't found
+// - join callfunc and callsub's functionality
+
+
+
 //
 //
 // struct script_state* st;
 // struct script_state* st;
 //
 //
@@ -3910,7 +3920,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(callsub,"i*"),
 	BUILDIN_DEF(callsub,"i*"),
 	BUILDIN_DEF(callfunc,"s*"),
 	BUILDIN_DEF(callfunc,"s*"),
 	BUILDIN_DEF(return,"?"),
 	BUILDIN_DEF(return,"?"),
-	BUILDIN_DEF(getarg,"i"),
+	BUILDIN_DEF(getarg,"i?"),
 	BUILDIN_DEF(jobchange,"i*"),
 	BUILDIN_DEF(jobchange,"i*"),
 	BUILDIN_DEF(jobname,"i"),
 	BUILDIN_DEF(jobname,"i"),
 	BUILDIN_DEF(input,"v"),
 	BUILDIN_DEF(input,"v"),
@@ -4031,10 +4041,10 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(disablearena,""),	// Added by RoVeRT
 	BUILDIN_DEF(disablearena,""),	// Added by RoVeRT
 	BUILDIN_DEF(hideoffnpc,"s"),
 	BUILDIN_DEF(hideoffnpc,"s"),
 	BUILDIN_DEF(hideonnpc,"s"),
 	BUILDIN_DEF(hideonnpc,"s"),
-	BUILDIN_DEF(sc_start,"iii*"),
-	BUILDIN_DEF(sc_start2,"iiii*"),
-	BUILDIN_DEF(sc_start4,"iiiiii*"),
-	BUILDIN_DEF(sc_end,"i"),
+	BUILDIN_DEF(sc_start,"iii?"),
+	BUILDIN_DEF(sc_start2,"iiii?"),
+	BUILDIN_DEF(sc_start4,"iiiiii?"),
+	BUILDIN_DEF(sc_end,"i?"),
 	BUILDIN_DEF(getscrate,"ii*"),
 	BUILDIN_DEF(getscrate,"ii*"),
 	BUILDIN_DEF(debugmes,"s"),
 	BUILDIN_DEF(debugmes,"s"),
 	BUILDIN_DEF2(catchpet,"pet","i"),
 	BUILDIN_DEF2(catchpet,"pet","i"),
@@ -4685,26 +4695,38 @@ BUILDIN_FUNC(callsub)
 	return 0;
 	return 0;
 }
 }
 
 
-/*==========================================
- * 引数の所得
- *------------------------------------------*/
+/// Retrieves an argument provided to callfunc/callsub.
+/// If the argument doesn't exist
+///
+/// getarg(<index>{,<default_value>}) -> <value>
 BUILDIN_FUNC(getarg)
 BUILDIN_FUNC(getarg)
 {
 {
-	int num=script_getnum(st,2);
-	int max,stsp;
-	if( st->stack->defsp<5 || st->stack->stack_data[st->stack->defsp-1].type!=C_RETINFO ){
-		ShowWarning("script:getarg without callfunc or callsub!\n");
-		st->state=END;
+	int idx;
+	int count;
+	int stsp;
+
+	if( st->stack->defsp < 5 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO )
+	{
+		ShowWarning("script:getarg: no callfunc or callsub!\n");
+		st->state = END;
 		return 1;
 		return 1;
 	}
 	}
-	max=conv_num(st,& (st->stack->stack_data[st->stack->defsp-5]));
-	stsp=st->stack->defsp - max -5;
-	if( num >= max ){
-		ShowWarning("script:getarg arg1(%d) out of range(%d) !\n",num,max);
-		st->state=END;
+	count = conv_num(st, &(st->stack->stack_data[st->stack->defsp - 5]));
+	stsp = st->stack->defsp - count - 5;
+
+	idx = script_getnum(st,2);
+
+	if( idx < count )
+		push_copy(st->stack, stsp + idx);
+	else if( script_hasdata(st,3) )
+		script_pushcopy(st, 3);
+	else
+	{
+		ShowWarning("script:getarg: index (idx=%d) out of range (count=%d) and no default value found\n", idx, count);
+		st->state = END;
 		return 1;
 		return 1;
 	}
 	}
-	push_copy(st->stack,stsp+num);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -8175,133 +8197,153 @@ BUILDIN_FUNC(hideonnpc)
 	npc_enable(str,4);
 	npc_enable(str,4);
 	return 0;
 	return 0;
 }
 }
-/*==========================================
- * 状態異常にかかる
- *------------------------------------------*/
+
+/// Starts a status effect on the target unit or on the attached player.
+///
+/// sc_start <effect_id>,<duration>,<val1>{,<unit_id>};
 BUILDIN_FUNC(sc_start)
 BUILDIN_FUNC(sc_start)
 {
 {
-	struct block_list *bl;
-	int type,tick,val1,val4=0;
-	type=script_getnum(st,2);
-	tick=script_getnum(st,3);
-	val1=script_getnum(st,4);
-	if( script_hasdata(st,5) ) //指定したキャラを状態異常にする
+	struct block_list* bl;
+	int type;
+	int tick;
+	int val1;
+	int val4 = 0;
+
+	type = script_getnum(st,2);
+	tick = script_getnum(st,3);
+	val1 = script_getnum(st,4);
+	if( script_hasdata(st,5) )
 		bl = map_id2bl(script_getnum(st,5));
 		bl = map_id2bl(script_getnum(st,5));
 	else
 	else
 		bl = map_id2bl(st->rid);
 		bl = map_id2bl(st->rid);
 
 
-	if (potion_flag==1 && potion_target) {
-		bl = map_id2bl(potion_target);
-		tick/=2; //Thrown potions only last half.
-		val4 = 1; //Mark that this was a thrown sc_effect
+	if( tick == 0 && val1 > 0 && type >= 0 && type < SC_MAX && StatusSkillChangeTable[type] != 0 )
+	{// When there isn't a duration specified, try to get it from the skill_db
+		tick = skill_get_time(StatusSkillChangeTable[type], val1);
 	}
 	}
-	if (type >= 0 && type < SC_MAX && val1 && !tick)
-	{	//When there isn't a duration specified, try to get it from the skill_db
-		tick = StatusSkillChangeTable[type];
-		if (tick)
-			tick = skill_get_time(tick,val1);
-		else	//Failed to retrieve duration, reset to what it was.
-			tick = 0;
+
+	if( potion_flag == 1 && potion_target )
+	{//##TODO how does this work [FlavioJS]
+		bl = map_id2bl(potion_target);
+		tick /= 2;// Thrown potions only last half.
+		val4 = 1;// Mark that this was a thrown sc_effect
 	}
 	}
-	if (bl)
-		status_change_start(bl,type,10000,val1,0,0,val4,tick,11);
+
+	if( bl )
+		status_change_start(bl, type, 10000, val1, 0, 0, val4, tick, 1|2|8);
 	return 0;
 	return 0;
 }
 }
 
 
-/*==========================================
- * 状態異常にかかる(確率指定)
- *------------------------------------------*/
+/// Starts a status effect on the target unit or on the attached player.
+///
+/// sc_start2 <effect_id>,<duration>,<val1>,<percent chance>{,<unit_id>};
 BUILDIN_FUNC(sc_start2)
 BUILDIN_FUNC(sc_start2)
 {
 {
-	struct block_list *bl;
-	int type,tick,val1,val4=0,per;
-	type=script_getnum(st,2);
-	tick=script_getnum(st,3);
-	val1=script_getnum(st,4);
-	per=script_getnum(st,5);
-	if( script_hasdata(st,6) ) //指定したキャラを状態異常にする
+	struct block_list* bl;
+	int type;
+	int tick;
+	int val1;
+	int val4 = 0;
+	int rate;
+
+	type = script_getnum(st,2);
+	tick = script_getnum(st,3);
+	val1 = script_getnum(st,4);
+	rate = script_getnum(st,5);
+	if( script_hasdata(st,6) )
 		bl = map_id2bl(script_getnum(st,6));
 		bl = map_id2bl(script_getnum(st,6));
 	else
 	else
 		bl = map_id2bl(st->rid);
 		bl = map_id2bl(st->rid);
 
 
-	if (type >= 0 && type < SC_MAX && val1 && !tick)
-	{	//When there isn't a duration specified, try to get it from the skill_db
-		tick = StatusSkillChangeTable[type];
-		if (tick)
-			tick = skill_get_time(tick,val1);
-		else	//Failed to retrieve duration, reset to what it was.
-			tick = 0;
+	if( tick == 0 && val1 > 0 && type >= 0 && type < SC_MAX && StatusSkillChangeTable[type] != 0 )
+	{// When there isn't a duration specified, try to get it from the skill_db
+		tick = skill_get_time(StatusSkillChangeTable[type], val1);
 	}
 	}
 
 
-	if (potion_flag==1 && potion_target) {
+	if( potion_flag == 1 && potion_target )
+	{//##TODO how does this work [FlavioJS]
 		bl = map_id2bl(potion_target);
 		bl = map_id2bl(potion_target);
-		tick/=2;
-		val4 = 1;
+		tick /= 2;// Thrown potions only last half.
+		val4 = 1;// Mark that this was a thrown sc_effect
 	}
 	}
 
 
-	if(bl)
-		status_change_start(bl,type,per,val1,0,0,val4,tick,11);
+	if( bl )
+		status_change_start(bl, type, rate, val1, 0, 0, val4, tick, 1|2|8);
+
 	return 0;
 	return 0;
 }
 }
 
 
-/*==========================================
- * Starts a SC_ change with the four values passed. [Skotlex]
- * Final optional argument is the ID of player to affect.
- * sc_start4 type, duration, val1, val2, val3, val4, <id>;
- *------------------------------------------*/
+/// Starts a status effect on the target unit or on the attached player.
+///
+/// sc_start4 <effect_id>,<duration>,<val1>,<val2>,<val3>,<val4>{,<unit_id>};
 BUILDIN_FUNC(sc_start4)
 BUILDIN_FUNC(sc_start4)
 {
 {
-	struct block_list *bl;
-	int type,tick,val1,val2,val3,val4;
-	type=script_getnum(st,2);
-	tick=script_getnum(st,3);
-	val1=script_getnum(st,4);
-	val2=script_getnum(st,5);
-	val3=script_getnum(st,6);
-	val4=script_getnum(st,7);
+	struct block_list* bl;
+	int type;
+	int tick;
+	int val1;
+	int val2;
+	int val3;
+	int val4;
+
+	type = script_getnum(st,2);
+	tick = script_getnum(st,3);
+	val1 = script_getnum(st,4);
+	val2 = script_getnum(st,5);
+	val3 = script_getnum(st,6);
+	val4 = script_getnum(st,7);
 	if( script_hasdata(st,8) )
 	if( script_hasdata(st,8) )
 		bl = map_id2bl(script_getnum(st,8));
 		bl = map_id2bl(script_getnum(st,8));
 	else
 	else
 		bl = map_id2bl(st->rid);
 		bl = map_id2bl(st->rid);
 
 
-	if (type >= 0 && type < SC_MAX && val1 && !tick)
-	{	//When there isn't a duration specified, try to get it from the skill_db
-		tick = StatusSkillChangeTable[type];
-		if (tick)
-			tick = skill_get_time(tick,val1);
-		else	//Failed to retrieve duration, reset to what it was.
-			tick = 0;
+	if( tick == 0 && val1 > 0 && type >= 0 && type < SC_MAX && StatusSkillChangeTable[type] != 0 )
+	{// When there isn't a duration specified, try to get it from the skill_db
+		tick = skill_get_time(StatusSkillChangeTable[type], val1);
 	}
 	}
 
 
-	if (potion_flag==1 && potion_target) {
+	if( potion_flag == 1 && potion_target )
+	{//##TODO how does this work [FlavioJS]
 		bl = map_id2bl(potion_target);
 		bl = map_id2bl(potion_target);
-		tick/=2;
+		tick /= 2;// Thrown potions only last half.
 	}
 	}
-	if (bl)
-		status_change_start(bl,type,10000,val1,val2,val3,val4,tick,11);
+
+	if( bl )
+		status_change_start(bl, type, 10000, val1, val2, val3, val4, tick, 1|2|8);
+
 	return 0;
 	return 0;
 }
 }
 
 
-/*==========================================
- * 状態異常が直る
- *------------------------------------------*/
+/// Ends one or all status effects on the target unit or on the attached player.
+///
+/// sc_end <effect_id>{,<unit_id>};
 BUILDIN_FUNC(sc_end)
 BUILDIN_FUNC(sc_end)
 {
 {
-	struct block_list *bl;
+	struct block_list* bl;
 	int type;
 	int type;
-	type=script_getnum(st,2);
-	bl = map_id2bl(st->rid);
+
+	type = script_getnum(st,2);
+	if( script_hasdata(st,3) )
+		bl = map_id2bl(script_getnum(st,3));
+	else
+		bl = map_id2bl(st->rid);
 	
 	
-	if (potion_flag==1 && potion_target)
+	if( potion_flag==1 && potion_target )
+	{//##TODO how does this work [FlavioJS]
 		bl = map_id2bl(potion_target);
 		bl = map_id2bl(potion_target);
+	}
+
+	if( bl )
+	{
+		if( type >= 0 )
+			status_change_end(bl, type, INVALID_TIMER);
+		else
+			status_change_clear(bl, 2);// remove all effects
+	}
 
 
-	if (!bl) return 0;
-	if (type >= 0)
-		status_change_end(bl,type,-1);
-	else
-		status_change_clear(bl, 2);
 	return 0;
 	return 0;
 }
 }
+
 /*==========================================
 /*==========================================
  * 状態異常耐性を計算した確率を返す
  * 状態異常耐性を計算した確率を返す
  *------------------------------------------*/
  *------------------------------------------*/
@@ -13050,12 +13092,13 @@ BUILDIN_FUNC(unittalk)
 	bl = map_id2bl(unit_id);
 	bl = map_id2bl(unit_id);
 	if( bl != NULL )
 	if( bl != NULL )
 	{
 	{
-		struct StringBuf* buf = StringBuf_Malloc();
-		StringBuf_Printf(buf, "%s : %s", status_get_name(bl), message);
-		clif_message(bl, StringBuf_Value(buf));
+		struct StringBuf sbuf;
+		StringBuf_Init(&sbuf);
+		StringBuf_Printf(&sbuf, "%s : %s", status_get_name(bl), message);
+		clif_message(bl, StringBuf_Value(&sbuf));
 		if( bl->type == BL_PC )
 		if( bl->type == BL_PC )
-			clif_displaymessage(((TBL_PC*)bl)->fd, StringBuf_Value(buf));
-		StringBuf_Free(buf);
+			clif_displaymessage(((TBL_PC*)bl)->fd, StringBuf_Value(&sbuf));
+		StringBuf_Destroy(&sbuf);
 	}
 	}
 
 
 	return 0;
 	return 0;

+ 2 - 2
src/map/status.c

@@ -6072,9 +6072,9 @@ int status_change_clear(struct block_list *bl,int type)
 		case SC_JAILED:
 		case SC_JAILED:
 			continue;
 			continue;
 		}
 		}
-		status_change_end(bl, i, -1);
+		status_change_end(bl, i, INVALID_TIMER);
 
 
-		if (type == 1 && sc->data[i].timer != -1)
+		if( type == 1 && sc->data[i].timer != INVALID_TIMER )
 		{	//If for some reason status_change_end decides to still keep the status when quitting. [Skotlex]
 		{	//If for some reason status_change_end decides to still keep the status when quitting. [Skotlex]
 			(sc->count)--;
 			(sc->count)--;
 			delete_timer(sc->data[i].timer, status_change_timer);
 			delete_timer(sc->data[i].timer, status_change_timer);