-- bonus_script "<script code>",<duration>{,<flag>{,<type>{,<char_id>}}};
-- see 'doc/script_commands.txt' for more details.
-- Thank everyone who discussed it

Signed-off-by: Cahyadi Ramadhan Togihon <house.bad@gmail.com>
This commit is contained in:
Cahyadi Ramadhan Togihon
2013-11-10 00:49:13 +07:00
parent 9744ba49d4
commit 99098c19bc
9 changed files with 280 additions and 33 deletions

View File

@@ -5059,6 +5059,30 @@ autobonus and autobonus3).
---------------------------------------
*bonus_script "<script code>",<duration>{,<flag>{,<type>{,<char_id>}}};
This command attachs script to player within specified 'duration' in second.
flag:
&1: Remove when dead
&2: Removable by dispell
&4: Removable by clearance
[TODO] &8: Save script when player logout and continue when player login back
type:
0 = Buff
1 = Debuff
NOTE:
- Cannot stack same bonus
- Max. bonus_script for a player is 10 (pc.h MAX_PC_BONUS_SCRIPT)
Example:
- Apple gives you +5 Str bonus for 1 minute when it's consumed.
512,Apple,Apple,0,15,,20,,,,,0xFFFFFFFF,63,2,,,,,,{ bonus_script "{ bonus bStr,5; }",60; },{},{}
---------------------------------------
*skill <skill id>,<level>{,<flag>};
*skill "<skill name>",<level>{,<flag>};
*addtoskill <skill id>,<level>{,<flag>};

View File

@@ -9877,6 +9877,7 @@ void clif_parse_QuitGame(int fd, struct map_session_data *sd)
{
set_eof(fd);
pc_damage_log_clear(sd,0);
pc_bonus_script_clear(sd);
clif_disconnect_ack(sd, 0);
} else {
clif_disconnect_ack(sd, 1);
@@ -10247,6 +10248,7 @@ void clif_parse_Restart(int fd, struct map_session_data *sd)
(!battle_config.prevent_logout || DIFF_TICK(gettick(), sd->canlog_tick) > battle_config.prevent_logout) )
{ //Send to char-server for character selection.
pc_damage_log_clear(sd,0);
pc_bonus_script_clear(sd);
chrif_charselectreq(sd, session[fd]->client_addr);
} else {
clif_disconnect_ack(sd, 1);

View File

@@ -1716,7 +1716,7 @@ int map_quit(struct map_session_data *sd) {
elemental_clean_effect(sd->ed);
unit_remove_map(&sd->ed->bl,CLR_RESPAWN);
}
unit_remove_map_pc(sd,CLR_RESPAWN);
if( map[sd->bl.m].instance_id ) { // Avoid map conflicts and warnings on next login

View File

@@ -6920,6 +6920,9 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
item_tmp.card[3]=GetWord(sd->status.char_id,1);
map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0);
}
//Remove bonus_script when dead
pc_bonus_script_check(sd,BSF_REM_ON_DEAD);
// changed penalty options, added death by player if pk_mode [Valaris]
if(battle_config.death_penalty_type
@@ -7044,7 +7047,6 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
}
}
//Reset "can log out" tick.
if( battle_config.prevent_logout )
sd->canlog_tick = gettick() - battle_config.prevent_logout;
@@ -10224,65 +10226,79 @@ void pc_itemcd_do(struct map_session_data *sd, bool load) {
return;
}
/**
* Clear the dmglog data from player
* @param sd
* @param md
**/
void pc_clear_log_damage_sub(int char_id, struct mob_data *md)
{
int i;
uint8 i;
ARR_FIND(0,DAMAGELOG_SIZE,i,md->dmglog[i].id == char_id);
if( i < DAMAGELOG_SIZE )
{
if (i < DAMAGELOG_SIZE) {
md->dmglog[i].id=0;
md->dmglog[i].dmg=0;
md->dmglog[i].flag=0;
}
}
/**
* Add log to player's dmglog
* @param sd
* @param id Monster's id
**/
void pc_damage_log_add(struct map_session_data *sd, int id)
{
int i = 0;
uint8 i = 0;
if( !sd )
if (!sd)
return;
for(i = 0; i < DAMAGELOG_SIZE_PC && sd->dmglog[i].id != id; i++)
if( !sd->dmglog[i].id )
{
for (i = 0; i < DAMAGELOG_SIZE_PC && sd->dmglog[i].id != id; i++)
if (!sd->dmglog[i].id) {
sd->dmglog[i].id = id;
break;
}
return;
}
/**
* Clear dmglog data from player
* @param sd
* @param id Monster's id
**/
void pc_damage_log_clear(struct map_session_data *sd, int id)
{
int i;
uint8 i;
struct mob_data *md = NULL;
if( !sd )
if (!sd)
return;
if( !id )
{
for(i = 0; i < DAMAGELOG_SIZE_PC; i++) // track every id
{
if (!id) {
for (i = 0; i < DAMAGELOG_SIZE_PC; i++) {
if( !sd->dmglog[i].id ) //skip the empty value
continue;
if( (md = map_id2md(sd->dmglog[i].id)) )
if ((md = map_id2md(sd->dmglog[i].id)))
pc_clear_log_damage_sub(sd->status.char_id,md);
}
memset(sd->dmglog,0,sizeof(sd->dmglog)); // clear all
}
else
{
if( (md = map_id2md(id)) )
else {
if ((md = map_id2md(id)))
pc_clear_log_damage_sub(sd->status.char_id,md);
ARR_FIND(0,DAMAGELOG_SIZE_PC,i,sd->dmglog[i].id == id); // find the id position
if( i < DAMAGELOG_SIZE_PC )
if (i < DAMAGELOG_SIZE_PC)
sd->dmglog[i].id = 0;
}
}
/**
* Deposit some money to bank
* @param sd
* @param money Amount of money to deposit
**/
enum e_BANKING_DEPOSIT_ACK pc_bank_deposit(struct map_session_data *sd, int money) {
unsigned int limit_check = money+sd->status.bank_vault;
@@ -10301,6 +10317,11 @@ enum e_BANKING_DEPOSIT_ACK pc_bank_deposit(struct map_session_data *sd, int mone
return BDA_SUCCESS;
}
/**
* Withdraw money from bank
* @param sd
* @param money Amount of money that will be withdrawn
**/
enum e_BANKING_WITHDRAW_ACK pc_bank_withdraw(struct map_session_data *sd, int money) {
unsigned int limit_check = money+sd->status.zeny;
@@ -10323,6 +10344,10 @@ enum e_BANKING_WITHDRAW_ACK pc_bank_withdraw(struct map_session_data *sd, int mo
return BWA_SUCCESS;
}
/**
* Clear Cirmson Marker data from caster
* @param sd
**/
void pc_crimson_marker_clear(struct map_session_data *sd) {
uint8 i;
@@ -10336,6 +10361,10 @@ void pc_crimson_marker_clear(struct map_session_data *sd) {
}
}
/**
* Show version to player
* @param sd
**/
void pc_show_version(struct map_session_data *sd) {
const char* svn = get_svn_revision();
const char* git = get_git_hash();
@@ -10350,6 +10379,83 @@ void pc_show_version(struct map_session_data *sd) {
clif_displaymessage(sd->fd,buf);
}
/** [Cydh]
* Timer for bonus_script
* @param tid
* @param tick
* @param id
* @param data
**/
int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data) {
uint8 i = (uint8)data;
struct map_session_data *sd;
sd = map_id2sd(id);
if (!sd) {
ShowDebug("pc_bonus_script_timer: Null pointer id: %d data: %d\n",id,data);
return 0;
}
if (i > MAX_PC_BONUS_SCRIPT|| !(&sd->bonus_script[i]) || !sd->bonus_script[i].script) {
ShowDebug("pc_bonus_script_timer: Invalid index %d\n",i);
return 0;
}
pc_bonus_script_remove(sd,i);
status_calc_pc(sd,false);
return 0;
}
/** [Cydh]
* Remove bonus_script data from sd
* @param sd target
* @param i script index
**/
void pc_bonus_script_remove(struct map_session_data *sd, uint8 i) {
if (!sd || i < 0 || i >= MAX_PC_BONUS_SCRIPT)
return;
memset(&sd->bonus_script[i].script,0,sizeof(sd->bonus_script[i].script));
sd->bonus_script[i].script_str = NULL;
sd->bonus_script[i].tick = 0;
sd->bonus_script[i].tid = 0;
sd->bonus_script[i].flag = 0;
}
/** [Cydh]
* Clear all active timer(s) of bonus_script data from sd
* @param sd target
* @param flag reason to remove the bonus_script
**/
void pc_bonus_script_check(struct map_session_data *sd, enum e_bonus_script_flag flag) {
uint8 i, count = 0;
if (!sd)
return;
for (i = 0; i < MAX_PC_BONUS_SCRIPT; i++) {
if (&sd->bonus_script[i] && sd->bonus_script[i].script && sd->bonus_script[i].flag&flag) {
delete_timer(sd->bonus_script[i].tid,pc_bonus_script_timer);
pc_bonus_script_remove(sd,i);
count++;
}
}
if (count)
status_calc_pc(sd,false);
}
/** [Cydh]
* Clear all active timer(s) of bonus_script data from sd
* @param sd target
**/
void pc_bonus_script_clear(struct map_session_data *sd) {
uint8 i;
if (!sd)
return;
for (i = 0; i < MAX_PC_BONUS_SCRIPT; i++)
if (&sd->bonus_script[i] && sd->bonus_script[i].tid)
delete_timer(sd->bonus_script[i].tid,pc_bonus_script_timer);
}
/*==========================================
* pc Init/Terminate
*------------------------------------------*/

View File

@@ -24,6 +24,7 @@
#define MAX_PC_SKILL_REQUIRE 5
#define MAX_PC_FEELHATE 3
#define DAMAGELOG_SIZE_PC 100 // Any idea for this value?
#define MAX_PC_BONUS_SCRIPT 10
//Update this max as necessary. 55 is the value needed for Super Baby currently
//Raised to 84 since Expanded Super Novice needs it.
@@ -551,8 +552,17 @@ struct map_session_data {
uint8 count; //Count of target for skill like RL_D_TAIL
} c_marker;
bool flicker;
};
//Timed bonus 'bonus_script' struct [Cydh]
struct s_script {
struct script_code *script;
const char *script_str; //Used for comparing and storing on table
uint32 tick;
uint8 flag;
bool isBuff; //Can be used for deciding which bonus that buff or debuff
int tid;
} bonus_script[MAX_PC_BONUS_SCRIPT];
};
enum weapon_type {
W_FIST, //Bare hands
@@ -1025,6 +1035,11 @@ void pc_crimson_marker_clear(struct map_session_data *sd);
void pc_show_version(struct map_session_data *sd);
int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data);
void pc_bonus_script_remove(struct map_session_data *sd, uint8 i);
void pc_bonus_script_check(struct map_session_data *sd, enum e_bonus_script_flag flag);
void pc_bonus_script_clear(struct map_session_data *sd);
#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP)
int pc_level_penalty_mod(struct map_session_data *sd, int mob_level, uint32 mob_race, uint32 mob_mode, int type);
#endif

View File

@@ -17966,7 +17966,7 @@ BUILDIN_FUNC(party_destroy)
* 1 - check by date
* @return true/false
*------------------------------------------*/
BUILDIN_FUNC(is_clientver){
BUILDIN_FUNC(is_clientver) {
TBL_PC *sd = NULL;
int type = script_getnum(st,2);
int data = script_getnum(st,3);
@@ -17997,7 +17997,7 @@ BUILDIN_FUNC(is_clientver){
* Retrieves server definitions.
* (see @type in const.txt)
*------------------------------------------*/
BUILDIN_FUNC(getserverdef){
BUILDIN_FUNC(getserverdef) {
int type = script_getnum(st,2);
switch(type){
case 0: script_pushint(st,PACKETVER); break;
@@ -18094,6 +18094,70 @@ BUILDIN_FUNC(montransform) {
return 0;
}
/** [Cydh]
* bonus_script "<script code>",<duration>{,<flag>{,<type>{,<char_id>}}};
* @param "script code"
* @param duration
* @param flag
* @param char_id
**/
BUILDIN_FUNC(bonus_script) {
uint8 i, flag = 0;
uint32 dur;
bool isBuff = true;
TBL_PC* sd;
const char *script_str = NULL;
struct script_code *script = NULL;
if (script_hasdata(st,6))
sd = map_charid2sd(script_getnum(st,6));
else
sd = script_rid2sd(st);
if (sd == NULL)
return 0;
script_str = script_getstr(st,2);
dur = 1000 * abs(script_getnum(st,3));
FETCH(4,flag);
if (script_getnum(st,5) == 1)
isBuff = false;
if (!strlen(script_str) || !dur) {
//ShowWarning("buildin_bonus_script: Invalid value(s). Skipping...\n");
return 0;
}
//Skip duplicate entry
ARR_FIND(0,MAX_PC_BONUS_SCRIPT,i,&sd->bonus_script[i] && sd->bonus_script[i].script_str && strcmp(sd->bonus_script[i].script_str,script_str) == 0);
if (i < MAX_PC_BONUS_SCRIPT) {
//ShowWarning("buildin_bonus_script: Duplicate entry with bonus '%d'. Skipping...\n",i);
return 0;
}
if (!(script = parse_script(script_str,"bonus_script",0,1))) {
//ShowWarning("buildin_bonus_script: Failed to parse script '%s'. Skipping...\n",script_str);
return 0;
}
//Find the empty slot
ARR_FIND(0,MAX_PC_BONUS_SCRIPT,i,!sd->bonus_script[i].script);
if (i >= MAX_PC_BONUS_SCRIPT) {
ShowWarning("buildin_itemscript: Maximum script_bonus is reached (max: %d). Skipping...\n",MAX_PC_BONUS_SCRIPT);
return 0;
}
//Add the script data
sd->bonus_script[i].script_str = script_str;
sd->bonus_script[i].script = script;
sd->bonus_script[i].tick = gettick() + dur;
sd->bonus_script[i].flag = flag;
sd->bonus_script[i].isBuff = isBuff;
status_calc_pc(sd,false);
return 0;
}
#include "../custom/script.inc"
// declarations that were supposed to be exported from npc_chat.c
@@ -18543,9 +18607,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(breakequip,"i"),
BUILDIN_DEF(sit,"?"),
BUILDIN_DEF(stand,"?"),
/**
* @commands (script based)
**/
//@commands (script based)
BUILDIN_DEF(bindatcmd, "ss??"),
BUILDIN_DEF(unbindatcmd, "s"),
BUILDIN_DEF(useatcmd, "s"),
@@ -18573,8 +18635,8 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(is_clientver,"ii?"),
BUILDIN_DEF(getserverdef,"i"),
BUILDIN_DEF2(montransform, "transform", "vii????"), // Monster Transform [malufett/Hercules]
BUILDIN_DEF(bonus_script,"si???"),
#include "../custom/script_def.inc"

View File

@@ -6822,7 +6822,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
break;
}
if(status_isimmune(bl) || !tsc || !tsc->count)
if(status_isimmune(bl))
break;
//Remove bonus_script when dispelled
if (dstsd)
pc_bonus_script_check(dstsd,BSF_REM_ON_DISPELL);
if(!tsc || !tsc->count)
break;
if( sd && dstsd && !map_flag_vs(sd->bl.m) && sd->status.guild_id == dstsd->status.guild_id ) {
@@ -6830,8 +6837,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
break;
}
for(i=0;i<SC_MAX;i++)
{
for(i=0;i<SC_MAX;i++) {
if (!tsc->data[i])
continue;
switch (i) {
@@ -6912,6 +6918,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
}
break;
}
//Affect all targets on splash area.
map_foreachinrange(skill_area_sub, bl, i, BL_CHAR,
src, skill_id, skill_lv, tick, flag|1,
@@ -8316,7 +8323,15 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
break;
}
if(status_isimmune(bl) || !tsc || !tsc->count)
if(status_isimmune(bl))
break;
//Remove bonus_script when cleared
if (dstsd)
pc_bonus_script_check(dstsd,BSF_REM_ON_CLEARANCE);
if(!tsc || !tsc->count)
break;
for( i = 0; i < SC_MAX; i++ ) {
if (!tsc->data[i])
@@ -8383,6 +8398,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
}
break;
}
map_foreachinrange(skill_area_sub, bl, i, BL_CHAR, src, skill_id, skill_lv, tick, flag|1, skill_castend_damage_id);
break;

View File

@@ -2787,6 +2787,14 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
run_script(data->script,0,sd->bl.id,0);
}
for (i = 0; i < MAX_PC_BONUS_SCRIPT; i++) { // Script Bonus
if (!(&sd->bonus_script[i]) || !sd->bonus_script[i].script)
continue;
if (!sd->bonus_script[i].tid) //Just add timer only for new attached script
sd->bonus_script[i].tid = add_timer(sd->bonus_script[i].tick,pc_bonus_script_timer,sd->bl.id,i);
run_script(sd->bonus_script[i].script,0,sd->bl.id,0);
}
if( sd->pd ) { // Pet Bonus
struct pet_data *pd = sd->pd;
if( pd && pd->petDB && pd->petDB->equip_script && pd->pet.intimate >= battle_config.pet_equip_min_friendly )

View File

@@ -1670,6 +1670,20 @@ enum scb_flag
SCB_ALL = 0x3FFFFFFF
};
///Enum for bonus_script's flag
enum e_bonus_script_flag {
BSF_REM_ON_DEAD = 0x1,
BSF_REM_ON_DISPELL = 0x2,
BSF_REM_ON_CLEARANCE = 0x4,
//BSF_DB_SAVE = 0x8, //TODO!
};
///Enum for bonus_script's type
enum e_bonus_script_type {
BST_BUFF = 0,
BST_DEBUFF = 1,
};
//Define to determine who gets HP/SP consumed on doing skills/etc. [Skotlex]
#define BL_CONSUME (BL_PC|BL_HOM|BL_MER|BL_ELEM)
//Define to determine who has regen