Browse Source

- Added bonusautoscript and bonusautoscript2. These are used to attach a script to a player which gets executed on attack (or when attacked). Required for several of the more recent items.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@11519 54d463be-8e91-2dee-dedb-b68131a5f0ec
skotlex 17 years ago
parent
commit
a1becae58f
9 changed files with 184 additions and 2 deletions
  1. 6 0
      Changelog-Trunk.txt
  2. 39 0
      doc/script_commands.txt
  3. 6 0
      src/map/map.h
  4. 30 0
      src/map/pc.c
  5. 3 0
      src/map/pc.h
  6. 57 0
      src/map/script.c
  7. 34 0
      src/map/skill.c
  8. 5 2
      src/map/status.c
  9. 4 0
      src/map/unit.c

+ 6 - 0
Changelog-Trunk.txt

@@ -4,6 +4,12 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO
 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/10/19
 2007/10/19
+	* Added bonusautoscript and bonusautoscript2. These are used to attach a
+	  script to a player which gets executed on attack (or when attacked). This
+	  is very similar to the autospell bonuses, except that a script is executed
+	  instead of a spell. See doc/script_commands for indepth description and
+	  usage. NOTE that I am unable to test ingame, and even though I proofread
+	  the code it could have bugs. Feel free to test and report. [Skotlex]
 	* Applied some cleanups that should correct "Infinite Endure" ending
 	* Applied some cleanups that should correct "Infinite Endure" ending
 	  sometimes. [Skotlex]
 	  sometimes. [Skotlex]
 2007/10/18
 2007/10/18

+ 39 - 0
doc/script_commands.txt

@@ -4285,6 +4285,45 @@ kind in 'doc/item_bonus.txt'.
 
 
 ---------------------------------------
 ---------------------------------------
 
 
+*bonusautoscript <script>,<rate>{,<flag>}
+*bonusautoscript2 <script>,<rate>{,<flag>}
+
+These commands are meant to be used in item scripts. They will probably work 
+outside item scripts, but the bonus will not persist for long. They, as 
+expected, refer only to an invoking character.
+
+What these commands do is 'attach' a script to the player which will get
+executed on attack (or when attacked in the case of bonusautoscript2). Rate is
+the trigger rate of the script (1000 = 100%). The optional argument flag is
+used to classify the type of attack where the script can trigger (it shares
+the same flags as the bAutoSpell bonus script):
+
+Range criteria:
+	BF_SHORT: Trigger on melee attack
+	BF_LONG: Trigger on ranged attack
+	Default: BF_SHORT+BF_LONG
+Attack type criteria:
+	BF_WEAPON: Trigger on weapon skills 
+	BF_MAGIC: Trigger on magic skills 
+	BF_MISC: Trigger on misc skills
+	Default: BF_WEAPON
+Skill criteria:
+	BF_NORMAL: Trigger on normal attacks
+	BF_SKILL: Trigger on skills
+	default: If the attack type is BF_WEAPON (only) BF_NORMAL is used, otherwise
+		BF_SKILL+BF_NORMAL is used.
+
+In both cases, when the script triggers, the attached player will be the one
+who holds the bonus. There is currently no way of knowing within this script
+who was the other character (the attacker in autoscript2, or the target in
+autoscript).
+
+//Grants a 1% chance of starting the state "all stats +10" for 10 seconds when
+//using weapon or misc attacks (both melee and ranged skills).
+	bonusautoscript "sc_start SC_INCALLSTATUS, 10, 10000;", 10, BF_WEAPON|BF_MISC;
+
+---------------------------------------
+
 *skill <skill id>,<level>{,<flag>};
 *skill <skill id>,<level>{,<flag>};
 *addtoskill <skill id>,<level>{,<flag>}
 *addtoskill <skill id>,<level>{,<flag>}
 
 

+ 6 - 0
src/map/map.h

@@ -692,6 +692,12 @@ struct map_session_data {
 		int rate;
 		int rate;
 	} itemhealrate[MAX_PC_BONUS];
 	} itemhealrate[MAX_PC_BONUS];
 	// zeroed structures end here
 	// zeroed structures end here
+	// manually zeroed structures start here.
+	struct s_autoscript {
+		unsigned short rate, flag;
+		struct script_code *script;
+	} autoscript[5], autoscript2[5]; //Auto script on attack, when attacked
+	// manually zeroed structures end here.
 	// zeroed vars start here.
 	// zeroed vars start here.
 	int arrow_atk,arrow_ele,arrow_cri,arrow_hit;
 	int arrow_atk,arrow_ele,arrow_cri,arrow_hit;
 	int nsshealhp,nsshealsp;
 	int nsshealhp,nsshealsp;

+ 30 - 0
src/map/pc.c

@@ -1219,6 +1219,36 @@ int pc_disguise(struct map_session_data *sd, int class_)
 	return 1;
 	return 1;
 }
 }
 
 
+int pc_autoscript_add(struct s_autoscript *scripts, int max, short rate, short flag, struct script_code *script)
+{
+	int i;
+	ARR_FIND(0, max, i, scripts[i].script == NULL);
+	if (i == max) {
+		if (battle_config.error_log)
+			ShowWarning("pc_autoscript_bonus: Reached max (%d) number of autoscripts per character!\n", max);
+		return 0;
+	}
+	scripts[i].script = script;
+	scripts[i].rate = rate;
+	//Auto-update flag value.
+	if (!(flag&BF_RANGEMASK)) flag|=BF_SHORT|BF_LONG; //No range defined? Use both.
+	if (!(flag&BF_WEAPONMASK)) flag|=BF_WEAPON; //No attack type defined? Use weapon.
+	if (!(flag&BF_SKILLMASK)) {
+		if (flag&(BF_MAGIC|BF_MISC)) flag|=BF_SKILL; //These two would never trigger without BF_SKILL
+		if (flag&BF_WEAPON) flag|=BF_NORMAL;
+	}
+	scripts[i].flag = flag;
+	return 1;
+}
+
+void pc_autoscript_clear(struct s_autoscript *scripts, int max)
+{
+	int i;
+	for (i = 0; i < max && scripts[i].script; i++)
+		script_free_code(scripts[i].script);
+	memset(scripts, 0, i*sizeof(struct s_autoscript));
+}
+
 static int pc_bonus_autospell_del(struct s_autospell *spell, int max, short id, short lv, short rate, short card_id)
 static int pc_bonus_autospell_del(struct s_autospell *spell, int max, short id, short lv, short rate, short card_id)
 {
 {
 	int i, j;
 	int i, j;

+ 3 - 0
src/map/pc.h

@@ -167,6 +167,9 @@ int pc_dropitem(struct map_session_data*,int,int);
 
 
 int pc_updateweightstatus(struct map_session_data *sd);
 int pc_updateweightstatus(struct map_session_data *sd);
 
 
+int pc_autoscript_add(struct s_autoscript *scripts, int max, short rate, short flag, struct script_code *script);
+void pc_autoscript_clear(struct s_autoscript *scripts, int max);
+
 int pc_bonus(struct map_session_data*,int,int);
 int pc_bonus(struct map_session_data*,int,int);
 int pc_bonus2(struct map_session_data *sd,int,int,int);
 int pc_bonus2(struct map_session_data *sd,int,int,int);
 int pc_bonus3(struct map_session_data *sd,int,int,int,int);
 int pc_bonus3(struct map_session_data *sd,int,int,int,int);

+ 57 - 0
src/map/script.c

@@ -3802,6 +3802,8 @@ BUILDIN_FUNC(bonus2);
 BUILDIN_FUNC(bonus3);
 BUILDIN_FUNC(bonus3);
 BUILDIN_FUNC(bonus4);
 BUILDIN_FUNC(bonus4);
 BUILDIN_FUNC(bonus5);
 BUILDIN_FUNC(bonus5);
+BUILDIN_FUNC(bonusautoscript);
+BUILDIN_FUNC(bonusautoscript2);
 BUILDIN_FUNC(skill);
 BUILDIN_FUNC(skill);
 BUILDIN_FUNC(addtoskill); // [Valaris]
 BUILDIN_FUNC(addtoskill); // [Valaris]
 BUILDIN_FUNC(guildskill);
 BUILDIN_FUNC(guildskill);
@@ -4134,6 +4136,8 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF2(bonus,"bonus3","iiii"),
 	BUILDIN_DEF2(bonus,"bonus3","iiii"),
 	BUILDIN_DEF2(bonus,"bonus4","iiiii"),
 	BUILDIN_DEF2(bonus,"bonus4","iiiii"),
 	BUILDIN_DEF2(bonus,"bonus5","iiiiii"),
 	BUILDIN_DEF2(bonus,"bonus5","iiiiii"),
+	BUILDIN_DEF(bonusautoscript,"si?"),
+	BUILDIN_DEF(bonusautoscript2,"si?"),
 	BUILDIN_DEF(skill,"ii?"),
 	BUILDIN_DEF(skill,"ii?"),
 	BUILDIN_DEF(addtoskill,"ii?"), // [Valaris]
 	BUILDIN_DEF(addtoskill,"ii?"), // [Valaris]
 	BUILDIN_DEF(guildskill,"ii"),
 	BUILDIN_DEF(guildskill,"ii"),
@@ -7192,6 +7196,59 @@ BUILDIN_FUNC(bonus)
 	return 0;
 	return 0;
 }
 }
 
 
+/// Bonus script that has a chance of being executed on attack.
+BUILDIN_FUNC(bonusautoscript)
+{
+	int rate, flag = 0;
+	const char *str;
+	struct script_code *script;
+	TBL_PC* sd;
+
+	sd = script_rid2sd(st);
+	if( sd == NULL )
+		return 1;// no player attached, report source
+
+	str  = script_getstr(st,2);
+	rate = script_getnum(st,3);
+	if( script_hasdata(st,4) )
+		flag = script_getnum(st,4);
+	script = parse_script(str, "autoscript bonus", 0, 0);
+	if (!script)
+		return 1;
+	if (!pc_autoscript_add(sd->autoscript, ARRAYLENGTH(sd->autoscript), rate, flag, script))
+	{
+		script_free_code(script);
+		return 1;
+	}
+	return 0;	
+}
+/// Bonus script that has a chance of being executed when attacked.
+BUILDIN_FUNC(bonusautoscript2)
+{
+	int rate, flag = 0;
+	const char *str;
+	struct script_code *script;
+	TBL_PC* sd;
+
+	sd = script_rid2sd(st);
+	if( sd == NULL )
+		return 1;// no player attached, report source
+
+	str  = script_getstr(st,2);
+	rate = script_getnum(st,3);
+	if( script_hasdata(st,4) )
+		flag = script_getnum(st,4);
+	script = parse_script(str, "autoscript2 bonus", 0, 0);
+	if (!script)
+		return 1;
+	if (!pc_autoscript_add(sd->autoscript2, ARRAYLENGTH(sd->autoscript2), rate, flag, script))
+	{
+		script_free_code(script);
+		return 1;
+	}
+	return 0;	
+}
+
 /// Changes the level of a player skill.
 /// Changes the level of a player skill.
 /// <flag> defaults to 1
 /// <flag> defaults to 1
 /// <flag>=0 : set the level of the skill
 /// <flag>=0 : set the level of the skill

+ 34 - 0
src/map/skill.c

@@ -1508,6 +1508,22 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int
 		}
 		}
 	}
 	}
 
 
+	//Auto-script when attacking
+	if(sd && src != bl && sd->autoscript[0].script) {
+		int i;
+		for (i = 0; i < ARRAYLENGTH(sd->autoscript) && sd->autoscript[i].script; i++) {
+
+			if(!(sd->autoscript[i].flag&attack_type&BF_WEAPONMASK &&
+				 sd->autoscript[i].flag&attack_type&BF_RANGEMASK &&
+				 sd->autoscript[i].flag&attack_type&BF_SKILLMASK))
+				continue; // one or more trigger conditions were not fulfilled
+			if (rand()%1000 > sd->autoscript[i].rate)
+				continue;
+			run_script(sd->autoscript[i].script,0,sd->bl.id,0);
+			break; //Have only one script execute at a time.
+		}
+	}
+
 	//Polymorph
 	//Polymorph
 	if(sd && sd->classchange && attack_type&BF_WEAPON &&
 	if(sd && sd->classchange && attack_type&BF_WEAPON &&
 		dstmd && !(tstatus->mode&MD_BOSS) &&
 		dstmd && !(tstatus->mode&MD_BOSS) &&
@@ -1683,6 +1699,24 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list *
 			break; //trigger only one auto-spell per hit.
 			break; //trigger only one auto-spell per hit.
 		}
 		}
 	}
 	}
+	//Auto-script when attacked
+	if(dstsd && !status_isdead(bl) && src != bl && dstsd->autoscript2[0].script &&
+		!(skillid && skill_get_nk(skillid)&NK_NO_DAMAGE)) 
+	{
+		int i;
+		for (i = 0; i < ARRAYLENGTH(dstsd->autoscript2) && dstsd->autoscript2[i].script; i++) {
+
+			if(!(dstsd->autoscript2[i].flag&attack_type&BF_WEAPONMASK &&
+				 dstsd->autoscript2[i].flag&attack_type&BF_RANGEMASK &&
+				 dstsd->autoscript2[i].flag&attack_type&BF_SKILLMASK))
+				continue; // one or more trigger conditions were not fulfilled
+			if (rand()%1000 > dstsd->autoscript2[i].rate)
+				continue;
+			run_script(dstsd->autoscript2[i].script,0,dstsd->bl.id,0);
+			break; //Have only one script execute at a time.
+		}
+	}
+
 	return 0;
 	return 0;
 }
 }
 /*=========================================================================
 /*=========================================================================

+ 5 - 2
src/map/status.c

@@ -1642,7 +1642,7 @@ int status_calc_pc(struct map_session_data* sd,int first)
 	sd->def_rate = sd->def2_rate = sd->mdef_rate = sd->mdef2_rate = 100;
 	sd->def_rate = sd->def2_rate = sd->mdef_rate = sd->mdef2_rate = 100;
 	sd->regen.state.block = 0;
 	sd->regen.state.block = 0;
 
 
-	// zeroed arays, order follows the order in map.h.
+	// zeroed arrays, order follows the order in map.h.
 	// add new arrays to the end of zeroed area in map.h (see comments) and size here. [zzo]
 	// add new arrays to the end of zeroed area in map.h (see comments) and size here. [zzo]
 	memset (sd->param_bonus, 0, sizeof(sd->param_bonus)
 	memset (sd->param_bonus, 0, sizeof(sd->param_bonus)
 		+ sizeof(sd->param_equip)
 		+ sizeof(sd->param_equip)
@@ -1715,7 +1715,10 @@ int status_calc_pc(struct map_session_data* sd,int first)
 		+ sizeof(sd->add_drop)
 		+ sizeof(sd->add_drop)
 		+ sizeof(sd->itemhealrate)
 		+ sizeof(sd->itemhealrate)
 	);
 	);
-
+	// clear autoscripts...
+	pc_autoscript_clear(sd->autoscript, ARRAYLENGTH(sd->autoscript));
+	pc_autoscript_clear(sd->autoscript2, ARRAYLENGTH(sd->autoscript2));
+	
 	// vars zeroing. ints, shorts, chars. in that order.
 	// vars zeroing. ints, shorts, chars. in that order.
 	memset (&sd->arrow_atk, 0,sizeof(sd->arrow_atk)
 	memset (&sd->arrow_atk, 0,sizeof(sd->arrow_atk)
 		+ sizeof(sd->arrow_ele)
 		+ sizeof(sd->arrow_ele)

+ 4 - 0
src/map/unit.c

@@ -1805,6 +1805,10 @@ int unit_free(struct block_list *bl, int clrtype)
 					status_change_end(bl,SC_STEELBODY,-1);
 					status_change_end(bl,SC_STEELBODY,-1);
 			}
 			}
 		}
 		}
+	
+		pc_autoscript_clear(sd->autoscript, ARRAYLENGTH(sd->autoscript));
+		pc_autoscript_clear(sd->autoscript2, ARRAYLENGTH(sd->autoscript2));
+
 		if (sd->followtimer != -1)
 		if (sd->followtimer != -1)
 			pc_stop_following(sd);
 			pc_stop_following(sd);
 		// Force exiting from duel and rejecting all duel invitations when player quit [LuzZza]
 		// Force exiting from duel and rejecting all duel invitations when player quit [LuzZza]