- 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
This commit is contained in:
skotlex 2007-10-19 20:31:57 +00:00
parent 8d0ac1d316
commit a1becae58f
9 changed files with 184 additions and 2 deletions

View File

@ -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.
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
sometimes. [Skotlex]
2007/10/18

View File

@ -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>};
*addtoskill <skill id>,<level>{,<flag>}

View File

@ -692,6 +692,12 @@ struct map_session_data {
int rate;
} itemhealrate[MAX_PC_BONUS];
// 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.
int arrow_atk,arrow_ele,arrow_cri,arrow_hit;
int nsshealhp,nsshealsp;

View File

@ -1219,6 +1219,36 @@ int pc_disguise(struct map_session_data *sd, int class_)
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)
{
int i, j;

View File

@ -167,6 +167,9 @@ int pc_dropitem(struct map_session_data*,int,int);
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_bonus2(struct map_session_data *sd,int,int,int);
int pc_bonus3(struct map_session_data *sd,int,int,int,int);

View File

@ -3802,6 +3802,8 @@ BUILDIN_FUNC(bonus2);
BUILDIN_FUNC(bonus3);
BUILDIN_FUNC(bonus4);
BUILDIN_FUNC(bonus5);
BUILDIN_FUNC(bonusautoscript);
BUILDIN_FUNC(bonusautoscript2);
BUILDIN_FUNC(skill);
BUILDIN_FUNC(addtoskill); // [Valaris]
BUILDIN_FUNC(guildskill);
@ -4134,6 +4136,8 @@ struct script_function buildin_func[] = {
BUILDIN_DEF2(bonus,"bonus3","iiii"),
BUILDIN_DEF2(bonus,"bonus4","iiiii"),
BUILDIN_DEF2(bonus,"bonus5","iiiiii"),
BUILDIN_DEF(bonusautoscript,"si?"),
BUILDIN_DEF(bonusautoscript2,"si?"),
BUILDIN_DEF(skill,"ii?"),
BUILDIN_DEF(addtoskill,"ii?"), // [Valaris]
BUILDIN_DEF(guildskill,"ii"),
@ -7192,6 +7196,59 @@ BUILDIN_FUNC(bonus)
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.
/// <flag> defaults to 1
/// <flag>=0 : set the level of the skill

View File

@ -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
if(sd && sd->classchange && attack_type&BF_WEAPON &&
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.
}
}
//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;
}
/*=========================================================================

View File

@ -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->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]
memset (sd->param_bonus, 0, sizeof(sd->param_bonus)
+ 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->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.
memset (&sd->arrow_atk, 0,sizeof(sd->arrow_atk)
+ sizeof(sd->arrow_ele)

View File

@ -1805,6 +1805,10 @@ int unit_free(struct block_list *bl, int clrtype)
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)
pc_stop_following(sd);
// Force exiting from duel and rejecting all duel invitations when player quit [LuzZza]