* Fixed bugreport:9211. Basilica causes map-server crashed when caster changing map

* Some source docs for skill.c/h

Signed-off-by: Cydh Ramdh <house.bad@gmail.com>
This commit is contained in:
Cydh Ramdh 2014-08-17 00:00:19 +07:00
parent adabedba23
commit d270047312
8 changed files with 393 additions and 254 deletions

View File

@ -507,7 +507,7 @@
//****
// High Priest
361,9,6,16,0,0x1,1,5,1,yes,0,0,0,magic,0,0x0, HP_ASSUMPTIO,Assumptio
362,4,6,4,0,0x1,0,5,1,yes,0,0,0,magic,2,0x0, HP_BASILICA,Basilica
362,4,6,4,0,0x1,0,5,1,yes,0,0,1,magic,2,0x0, HP_BASILICA,Basilica
363,0,0,0,0,0,0,10,0,no,0,0,0,magic,0,0x0, HP_MEDITATIO,Meditatio
//****

View File

@ -83,7 +83,7 @@
330,0xaf, , 3, 0, -1,all, 0x140 //DC_SERVICEFORYOU
336,0xb2, , 0,-1, -1,noone, 0x000 //WE_CALLPARTNER
339,0x86, , -1, 0, 300,enemy, 0x000 //NPC_DARKGRANDCROSS
362,0xb4, , 0, 2, 300,all, 0x000 //HP_BASILICA
362,0xb4, , 2, 0, 300,all, 0x2000 //HP_BASILICA
369,0xb3, , -1, 0,10000,all, 0x008 //PA_GOSPEL
395,0xb5, , 4, 0, -1,all, 0x200 //CG_MOONLIT
404,0xb6, , -1, 0, -1,all, 0x8000 //PF_FOGWALL

View File

@ -507,7 +507,7 @@
//****
// High Priest
361,9,6,16,0,0x1,1,5,1,yes,0,0,0,magic,0,0x0, HP_ASSUMPTIO,Assumptio
362,4,6,4,0,0x1,0,5,1,yes,0,0,0,magic,2,0x0, HP_BASILICA,Basilica
362,4,6,4,0,0x1,0,5,1,yes,0,0,1,magic,2,0x0, HP_BASILICA,Basilica
363,0,0,0,0,0,0,10,0,no,0,0,0,magic,0,0x0, HP_MEDITATIO,Meditatio
//****

View File

@ -83,7 +83,7 @@
330,0xaf, , 3, 0, -1,all, 0x140 //DC_SERVICEFORYOU
336,0xb2, , 0,-1, -1,noone, 0x000 //WE_CALLPARTNER
339,0x86, , -1, 0, 300,enemy, 0x000 //NPC_DARKGRANDCROSS
362,0xb4, , 0, 2, 300,all, 0x000 //HP_BASILICA
362,0xb4, , 2, 0, 300,all, 0x2000 //HP_BASILICA
369,0xb3, , -1, 0,10000,all, 0x008 //PA_GOSPEL
395,0xb5, , 4, 0, -1,all, 0x200 //CG_MOONLIT
404,0xb6, , -1, 0, -1,all, 0x8000 //PF_FOGWALL

View File

@ -8418,6 +8418,9 @@ bool pc_candrop(struct map_session_data *sd, struct item *item)
bool pc_can_attack( struct map_session_data *sd, int target_id ) {
nullpo_retr(false, sd);
if (!&sd->sc)
return true;
if( sd->sc.data[SC_BASILICA] ||
sd->sc.data[SC__SHADOWFORM] ||
sd->sc.data[SC__MANHOLE] ||
@ -9394,7 +9397,7 @@ bool pc_unequipitem(struct map_session_data *sd,int n,int flag) {
if((sd->status.inventory[n].equip & EQP_ARMS) &&
sd->weapontype1 == 0 && sd->weapontype2 == 0 && (!sd->sc.data[SC_SEVENWIND] || sd->sc.data[SC_ASPERSIO])) //Check for seven wind (but not level seven!)
skill_enchant_elemental_end(&sd->bl,-1);
skill_enchant_elemental_end(&sd->bl,SC_NONE);
if(sd->status.inventory[n].equip & EQP_ARMOR) {
// On Armor Change...

View File

@ -10974,8 +10974,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
return 0;
}
skill_clear_unitgroup(src);
if( skill_unitsetting(src,skill_id,skill_lv,x,y,0) )
sc_start4(src,src,type,100,skill_lv,0,0,src->id,skill_get_time(skill_id,skill_lv));
skill_unitsetting(src,skill_id,skill_lv,x,y,0);
flag|=1;
}
break;
@ -11805,20 +11804,26 @@ static int skill_icewall_block(struct block_list *bl,va_list ap) {
return 0;
}
/*==========================================
* Initializes and sets a ground skill.
* flag&1 is used to determine when the skill 'morphs' (Warp portal becomes active, or Fire Pillar becomes active)
* Initializes and sets a ground skill / skill unit. Usually called after skill_casted_pos() or skill_castend_map()
* @param src Object that triggers the skill
* @param skill_id Skill ID
* @param skill_lv Skill level of used skill
* @param x Position x
* @param y Position y
* @param flag &1: Used to determine when the skill 'morphs' (Warp portal becomes active, or Fire Pillar becomes active)
* @return skill_unit_group
*------------------------------------------*/
struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill_id, uint16 skill_lv, int16 x, int16 y, int flag)
{
struct skill_unit_group *group;
int i,limit,val1=0,val2=0,val3=0;
int target,interval,range,unit_flag,req_item=0;
int i, limit, val1 = 0, val2 = 0, val3 = 0;
int target, interval, range, unit_flag, req_item = 0;
struct s_skill_unit_layout *layout;
struct map_session_data *sd;
struct status_data *status;
struct status_change *sc;
int active_flag=1;
int subunt=0;
int active_flag = 1;
int subunt = 0;
nullpo_retr(NULL, src);
@ -11848,7 +11853,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill
case MG_FIREWALL:
if(sc && sc->data[SC_VIOLENTGALE])
limit = limit*3/2;
val2=4+skill_lv;
val2 = 4+skill_lv;
break;
case AL_WARP:
@ -12133,21 +12138,23 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill
break;
}
nullpo_retr(NULL, group=skill_initunitgroup(src,layout->count,skill_id,skill_lv,skill_get_unit_id(skill_id,flag&1)+subunt, limit, interval));
group->val1=val1;
group->val2=val2;
group->val3=val3;
group->target_flag=target;
group->bl_flag= skill_get_unit_bl_target(skill_id);
// Init skill unit group
nullpo_retr(NULL, (group = skill_initunitgroup(src,layout->count,skill_id,skill_lv,skill_get_unit_id(skill_id,flag&1)+subunt, limit, interval)));
group->val1 = val1;
group->val2 = val2;
group->val3 = val3;
group->target_flag = target;
group->bl_flag = skill_get_unit_bl_target(skill_id);
group->state.ammo_consume = (sd && sd->state.arrow_atk && skill_id != GS_GROUNDDRIFT); //Store if this skill needs to consume ammo.
group->state.song_dance = (unit_flag&(UF_DANCE|UF_SONG)?1:0)|(unit_flag&UF_ENSEMBLE?2:0); //Signals if this is a song/dance/duet
group->state.guildaura = ( skill_id >= GD_LEADERSHIP && skill_id <= GD_HAWKEYES )?1:0;
group->item_id = req_item;
//if tick is greater than current, do not invoke onplace function just yet. [Skotlex]
// If tick is greater than current, do not invoke onplace function just yet. [Skotlex]
if (DIFF_TICK(group->tick, gettick()) > SKILLUNITTIMER_INTERVAL)
active_flag = 0;
if(skill_id==HT_TALKIEBOX || skill_id==RG_GRAFFITI){
// Put message for Talkie Box & Graffiti
if (skill_id == HT_TALKIEBOX || skill_id == RG_GRAFFITI) {
group->valstr=(char *) aMalloc(MESSAGE_SIZE*sizeof(char));
if (sd)
safestrncpy(group->valstr, sd->message, MESSAGE_SIZE);
@ -12155,22 +12162,22 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill
safestrncpy(group->valstr, "Boo!", MESSAGE_SIZE);
}
// Dance skill
if (group->state.song_dance) {
if(sd){
if(sd) {
sd->skill_id_dance = skill_id;
sd->skill_lv_dance = skill_lv;
}
if (
sc_start4(src, src, SC_DANCING, 100, skill_id, group->group_id, skill_lv,
(group->state.song_dance&2?BCT_SELF:0), limit+1000) &&
sc_start4(src, src, SC_DANCING, 100, skill_id, group->group_id, skill_lv, (group->state.song_dance&2?BCT_SELF:0), limit+1000) &&
sd && group->state.song_dance&2 && skill_id != CG_HERMODE //Hermod is a encore with a warp!
)
skill_check_pc_partner(sd, skill_id, &skill_lv, 1, 1);
}
// Set skill unit
limit = group->limit;
for( i = 0; i < layout->count; i++ )
{
for( i = 0; i < layout->count; i++ ) {
struct skill_unit *unit;
int ux = x + layout->dx[i];
int uy = y + layout->dy[i];
@ -12188,11 +12195,10 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill
if( battle_config.skill_wall_check && unit_flag&UF_PATHCHECK && !path_search_long(NULL,src->m,ux,uy,x,y,CELL_CHKWALL) )
continue; // no path between cell and center of casting.
switch( skill_id )
{
switch( skill_id ) {
case MG_FIREWALL:
case NJ_KAENSIN:
val2_2=group->val2;
val2_2 = group->val2;
break;
case WZ_ICEWALL:
val1_2 = (skill_lv <= 1) ? 500 : 200 + 200*skill_lv;
@ -12254,14 +12260,15 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill
if( sd && map_getcell(src->m, ux, uy, CELL_CHKMAELSTROM) ) //Does not recover SP from monster skills
map_foreachincell(skill_maelstrom_suction,src->m,ux,uy,BL_SKILL,skill_id,skill_lv);
// Check active cell to failing or remove current unit
if( range <= 0 )
map_foreachincell(skill_cell_overlap,src->m,ux,uy,BL_SKILL,skill_id, &alive, src);
if( !alive )
continue;
nullpo_retr(NULL, unit=skill_initunit(group,i,ux,uy,val1_2,val2_2));
unit->limit=limit;
unit->range=range;
nullpo_retr(NULL, (unit = skill_initunit(group,i,ux,uy,val1_2,val2_2)));
unit->limit = limit;
unit->range = range;
if (skill_id == PF_FOGWALL && alive == 2)
{ //Double duration of cells on top of Deluge/Suiton
@ -12269,8 +12276,8 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill
group->limit = unit->limit;
}
// execute on all targets standing on this cell
if (range==0 && active_flag)
// Execute on all targets standing on this cell
if (range == 0 && active_flag)
map_foreachincell(skill_unit_effect,unit->bl.m,unit->bl.x,unit->bl.y,group->bl_flag,&unit->bl,gettick(),1);
}
@ -12297,10 +12304,17 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill
*
*------------------------------------------*/
void ext_skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, unsigned int tick){skill_unit_onplace(unit, bl, tick);}
/**
* Triggeres when 'target' (based on skill unit target) is step in unit area.
* As a follow of skill_unit_effect flag &1
* @param unit
* @param bl Target
* @param tick
*/
static int skill_unit_onplace (struct skill_unit *unit, struct block_list *bl, unsigned int tick)
{
struct skill_unit_group *sg;
struct block_list *ss;
struct block_list *ss; // Actual source that cast the skill unit
struct status_change *sc;
struct status_change_entry *sce;
enum sc_type type;
@ -12478,6 +12492,20 @@ static int skill_unit_onplace (struct skill_unit *unit, struct block_list *bl, u
sc_start4(ss, bl,type,100,sg->skill_lv,0,BCT_ENEMY,sg->group_id,sg->limit);
break;
case UNT_BASILICA:
{
int i = battle_check_target(bl, bl, BCT_ENEMY);
if( i > 0 && !(status_get_mode(bl)&MD_BOSS) )
{ // knock-back any enemy except Boss
skill_blown(ss, bl, skill_get_blewcount(skill_id, sg->skill_lv), unit_getdir(bl), 0);
clif_fixpos(bl);
break;
}
if (!sce && i <= 0)
sc_start4(ss, bl, type, 100, 0, 0, sg->group_id, ss->id, sg->limit);
}
break;
// officially, icewall has no problems existing on occupied cells [ultramage]
// case UNT_ICEWALL: //Destroy the cell. [Skotlex]
// unit->val1 = 0;
@ -12522,7 +12550,10 @@ static int skill_unit_onplace (struct skill_unit *unit, struct block_list *bl, u
}
/*==========================================
*
* Process skill unit each interval (sg->interval, see interval field of skill_unit_db.txt)
* @param src Skill unit
* @param bl Valid 'target' above the unit, that has been check in skill_unit_timer_sub_onplace
* @param tick
*------------------------------------------*/
int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, unsigned int tick)
{
@ -12959,12 +12990,12 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
int i = battle_check_target(&src->bl, bl, BCT_ENEMY);
if( i > 0 && !(status_get_mode(bl)&MD_BOSS) )
{ // knock-back any enemy except Boss
skill_blown(&src->bl, bl, 2, unit_getdir(bl), 0);
skill_blown(&src->bl, bl, skill_get_blewcount(skill_id, sg->skill_lv), unit_getdir(bl), 0);
clif_fixpos(bl);
break;
}
if( sg->src_id != bl->id && i <= 0 )
sc_start4(ss, bl, type, 100, 0, 0, 0, src->bl.id, sg->interval + 100);
if (i <= 0 && (!tsc || !tsc->data[SC_BASILICA]))
sc_start4(ss, bl, type, 100, 0, 0, sg->group_id, ss->id, sg->limit);
}
break;
@ -12995,7 +13026,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
**/
case UNT_POISONSMOKE:
if( battle_check_target(ss,bl,BCT_ENEMY) > 0 && !(tsc && tsc->data[sg->val2]) && rnd()%100 < 20 )
sc_start(ss, bl,sg->val2,100,sg->val3,skill_get_time2(GC_POISONINGWEAPON, 1));
sc_start(ss,bl,(sc_type)sg->val2,100,sg->val3,skill_get_time2(GC_POISONINGWEAPON, 1));
break;
case UNT_EPICLESIS:
@ -13040,7 +13071,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
case UNT_DIMENSIONDOOR:
if( tsd && !map[bl->m].flag.noteleport )
pc_randomwarp(tsd,3);
pc_randomwarp(tsd,CLR_TELEPORT);
else if( bl->type == BL_MOB && battle_config.mob_warp&8 )
unit_warp(bl,-1,-1,-1,CLR_TELEPORT);
break;
@ -13260,7 +13291,10 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
return skill_id;
}
/*==========================================
* Triggered when a char steps out of a skill cell
* Triggered when a char steps out of a skill unit
* @param src Skill unit from char moved out
* @param bl Char
* @param tick
*------------------------------------------*/
int skill_unit_onout (struct skill_unit *src, struct block_list *bl, unsigned int tick)
{
@ -13290,9 +13324,10 @@ int skill_unit_onout (struct skill_unit *src, struct block_list *bl, unsigned in
break;
case UNT_BASILICA:
if (sce)
if (sce && sce->val4 != bl->id)
status_change_end(bl, type, INVALID_TIMER);
break;
case UNT_HERMODE: //Clear Hermode if the owner moved.
if (sce && sce->val3 == BCT_SELF && sce->val4 == sg->group_id)
status_change_end(bl, type, INVALID_TIMER);
@ -13337,6 +13372,9 @@ int skill_unit_onout (struct skill_unit *src, struct block_list *bl, unsigned in
/*==========================================
* Triggered when a char steps out of a skill group (entirely) [Skotlex]
* @param skill_id Skill ID
* @param bl A char
* @param tick
*------------------------------------------*/
int skill_unit_onleft (uint16 skill_id, struct block_list *bl, unsigned int tick)
{
@ -13516,9 +13554,13 @@ static int skill_unit_effect (struct block_list* bl, va_list ap)
}
/*==========================================
*
* Check skill unit while receiving damage
* @param unit Skill unit
* @param bl Attacker
* @param damage Received damage
* @return Damage
*------------------------------------------*/
int64 skill_unit_ondamaged (struct skill_unit *unit, struct block_list *bl, int64 damage, unsigned int tick)
int64 skill_unit_ondamaged (struct skill_unit *unit, struct block_list *bl, int64 damage)
{
struct skill_unit_group *sg;
@ -13550,7 +13592,12 @@ int64 skill_unit_ondamaged (struct skill_unit *unit, struct block_list *bl, int6
}
/*==========================================
*
* Check char condition around the skill caster
* @param bl Char around area
* @param *c Counter for 'valid' condition found
* @param *p_sd Stores 'rid' of char found
* @param skill_id Skill ID
* @param skill_lv Level of used skill
*------------------------------------------*/
int skill_check_condition_char_sub (struct block_list *bl, va_list ap)
{
@ -13639,6 +13686,12 @@ int skill_check_condition_char_sub (struct block_list *bl, va_list ap)
/*==========================================
* Checks and stores partners for ensemble skills [Skotlex]
* Max partners is 2.
* @param sd Caster
* @param skill_id
* @param skill_lv
* @param range Area range to check
* @param cast_flag Special handle
*------------------------------------------*/
int skill_check_pc_partner (struct map_session_data *sd, uint16 skill_id, uint16 *skill_lv, int range, int cast_flag)
{
@ -13699,9 +13752,12 @@ int skill_check_pc_partner (struct map_session_data *sd, uint16 skill_id, uint16
}
/*==========================================
* Sub function to count how many spawned mob is around
* return :
* x : numbers of mob of class with special ai
* Sub function to count how many spawned mob is around.
* Some skills check with matched AI.
* @param rid Source ID
* @param mob_class Monster ID
* @param skill_id Used skill
* @param *c Counter for found monster
*------------------------------------------*/
static int skill_check_condition_mob_master_sub (struct block_list *bl, va_list ap)
{
@ -13728,16 +13784,19 @@ static int skill_check_condition_mob_master_sub (struct block_list *bl, va_list
/*==========================================
* Determines if a given skill should be made to consume ammo
* when used by the player. [Skotlex]
* @param sd Player
* @param skill Skill ID
* @return True if skill is need ammo; False otherwise.
*------------------------------------------*/
int skill_isammotype (struct map_session_data *sd, int skill)
int skill_isammotype (struct map_session_data *sd, unsigned short skill_id)
{
return (
battle_config.arrow_decrement==2 &&
(sd->status.weapon == W_BOW || (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE)) &&
skill != HT_PHANTASMIC &&
skill_get_type(skill) == BF_WEAPON &&
!(skill_get_nk(skill)&NK_NO_DAMAGE) &&
!skill_get_spiritball(skill,1) //Assume spirit spheres are used as ammo instead.
skill_id != HT_PHANTASMIC &&
skill_get_type(skill_id) == BF_WEAPON &&
!(skill_get_nk(skill_id)&NK_NO_DAMAGE) &&
!skill_get_spiritball(skill_id,1) //Assume spirit spheres are used as ammo instead.
);
}
@ -14062,7 +14121,8 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i
case HP_BASILICA:
if( !sc || (sc && !sc->data[SC_BASILICA])) {
if( sd ) {
int s,range = skill_get_unit_range(skill_id,skill_lv)+1;
// When castbegin, needs 7x7 clear area
int s,range = skill_get_unit_layout_type(skill_id,skill_lv)+1;
int size = range*2+1;
for( s=0;s<size*size;s++ ) {
int x = sd->bl.x+(s%size-range);
@ -15973,7 +16033,7 @@ int skill_sit (struct map_session_data *sd, int type)
}
/*==========================================
*
* Do Forstjoke/Scream effect
*------------------------------------------*/
int skill_frostjoke_scream (struct block_list *bl, va_list ap)
{
@ -15982,12 +16042,13 @@ int skill_frostjoke_scream (struct block_list *bl, va_list ap)
unsigned int tick;
nullpo_ret(bl);
nullpo_ret(src=va_arg(ap,struct block_list*));
nullpo_ret(src = va_arg(ap,struct block_list*));
skill_id=va_arg(ap,int);
skill_lv=va_arg(ap,int);
if(!skill_lv) return 0;
tick=va_arg(ap,unsigned int);
skill_id = va_arg(ap,int);
skill_lv = va_arg(ap,int);
if(!skill_lv)
return 0;
tick = va_arg(ap,unsigned int);
if (src == bl || status_isdead(bl))
return 0;
@ -16027,7 +16088,12 @@ int skill_check_target_c_marker(struct block_list *bl, va_list ap) {
}
/*==========================================
*
* Set map cell flag as skill unit effect
* @param src Skill unit
* @param skill_id
* @param skill_lv
* @param cell Cell type cell_t
* @param flag 0/1
*------------------------------------------*/
static void skill_unitsetmapcell (struct skill_unit *src, uint16 skill_id, uint16 skill_lv, cell_t cell, bool flag)
{
@ -16040,7 +16106,9 @@ static void skill_unitsetmapcell (struct skill_unit *src, uint16 skill_id, uint1
}
/*==========================================
*
* Do skill attack area (such splash effect) around the 'first' target.
* First target will skill skill condition, always receive damage. But,
* around it, still need target/condition validation
*------------------------------------------*/
int skill_attack_area (struct block_list *bl, va_list ap)
{
@ -16052,13 +16120,13 @@ int skill_attack_area (struct block_list *bl, va_list ap)
return 0;
atk_type = va_arg(ap,int);
src=va_arg(ap,struct block_list*);
dsrc=va_arg(ap,struct block_list*);
skill_id=va_arg(ap,int);
skill_lv=va_arg(ap,int);
tick=va_arg(ap,unsigned int);
flag=va_arg(ap,int);
type=va_arg(ap,int);
src = va_arg(ap,struct block_list*);
dsrc = va_arg(ap,struct block_list*);
skill_id = va_arg(ap,int);
skill_lv = va_arg(ap,int);
tick = va_arg(ap,unsigned int);
flag = va_arg(ap,int);
type = va_arg(ap,int);
if (skill_area_temp[1] == bl->id) //This is the target of the skill, do a full attack and skip target checks.
@ -16082,21 +16150,24 @@ int skill_attack_area (struct block_list *bl, va_list ap)
return (int)skill_attack(atk_type,src,dsrc,bl,skill_id,skill_lv,tick,flag|SD_ANIMATION);
}
}
/*==========================================
*
* Clear skill unit group
* @param bl
* @param flag &1
*------------------------------------------*/
int skill_clear_group (struct block_list *bl, int flag)
{
struct unit_data *ud = unit_bl2ud(bl);
struct unit_data *ud;
struct skill_unit_group *group[MAX_SKILLUNITGROUP];
int i, count=0;
int i, count = 0;
nullpo_ret(bl);
if (!ud) return 0;
if (!(ud = unit_bl2ud(bl)))
return 0;
//All groups to be deleted are first stored on an array since the array elements shift around when you delete them. [Skotlex]
for (i=0;i<MAX_SKILLUNITGROUP && ud->skillunit[i];i++)
{
// All groups to be deleted are first stored on an array since the array elements shift around when you delete them. [Skotlex]
for (i = 0; i < MAX_SKILLUNITGROUP && ud->skillunit[i]; i++) {
switch (ud->skillunit[i]->skill_id) {
case SA_DELUGE:
case SA_VOLCANO:
@ -16122,22 +16193,25 @@ int skill_clear_group (struct block_list *bl, int flag)
}
}
for (i=0;i<count;i++)
for (i = 0; i < count; i++)
skill_delunitgroup(group[i]);
return count;
}
/*==========================================
* Returns the first element field found [Skotlex]
* @param bl
* @return skill_unit_group
*------------------------------------------*/
struct skill_unit_group *skill_locate_element_field(struct block_list *bl)
{
struct unit_data *ud = unit_bl2ud(bl);
struct unit_data *ud;
int i;
nullpo_ret(bl);
if (!ud) return NULL;
if (!(ud = unit_bl2ud(bl)))
return NULL;
for (i=0;i<MAX_SKILLUNITGROUP && ud->skillunit[i];i++) {
for (i = 0; i < MAX_SKILLUNITGROUP && ud->skillunit[i];i++) {
switch (ud->skillunit[i]->skill_id) {
case SA_DELUGE:
case SA_VOLCANO:
@ -16152,7 +16226,7 @@ struct skill_unit_group *skill_locate_element_field(struct block_list *bl)
return NULL;
}
// for graffiti cleaner [Valaris]
/// Graffiti cleaner [Valaris]
int skill_graffitiremover (struct block_list *bl, va_list ap) {
struct skill_unit *unit=NULL;
@ -16168,6 +16242,7 @@ int skill_graffitiremover (struct block_list *bl, va_list ap) {
return 0;
}
/// Greed effect
int skill_greed (struct block_list *bl, va_list ap) {
struct block_list *src;
struct map_session_data *sd=NULL;
@ -16181,7 +16256,8 @@ int skill_greed (struct block_list *bl, va_list ap) {
return 0;
}
//For Ranger's Detonator [Jobbie/3CeAM]
/// Ranger's Detonator [Jobbie/3CeAM]
int skill_detonator(struct block_list *bl, va_list ap)
{
struct skill_unit *unit=NULL;
@ -16230,7 +16306,9 @@ int skill_detonator(struct block_list *bl, va_list ap)
}
/*==========================================
*
* Check new skill unit cell when overlapping in other skill unit cell.
* Catched skill in cell value pushed to *unit pointer.
* Set (*alive) to 0 will ends 'new unit' check
*------------------------------------------*/
static int skill_cell_overlap(struct block_list *bl, va_list ap)
{
@ -16351,7 +16429,8 @@ int skill_changetarget(struct block_list *bl, va_list ap)
}
/*==========================================
*
* Splash effect for skill unit 'trap type'.
* Chance triggered when damaged, timeout, or char step on it.
*------------------------------------------*/
static int skill_trap_splash (struct block_list *bl, va_list ap)
{
@ -16490,25 +16569,31 @@ int skill_maelstrom_suction(struct block_list *bl, va_list ap)
}
/*==========================================
*
* Remove current enchanted element for new element
* @param bl Char
* @param type New element
*------------------------------------------*/
int skill_enchant_elemental_end (struct block_list *bl, int type)
{
void skill_enchant_elemental_end (struct block_list *bl, int type) {
struct status_change *sc;
const enum sc_type scs[] = { SC_ENCPOISON, SC_ASPERSIO, SC_FIREWEAPON, SC_WATERWEAPON, SC_WINDWEAPON, SC_EARTHWEAPON, SC_SHADOWWEAPON, SC_GHOSTWEAPON, SC_ENCHANTARMS };
int i;
nullpo_ret(bl);
nullpo_ret(sc= status_get_sc(bl));
nullpo_retv(bl);
nullpo_retv(sc= status_get_sc(bl));
if (!sc->count) return 0;
if (!sc->count)
return;
for (i = 0; i < ARRAYLENGTH(scs); i++)
if (type != scs[i] && sc->data[scs[i]])
status_change_end(bl, scs[i], INVALID_TIMER);
return 0;
}
/**
* Check camouflage condition
* @param bl
* @param sce
* @return True if near wall; False otherwise
**/
bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce)
{
bool wall = true;
@ -16585,6 +16670,13 @@ bool skill_check_shadowform(struct block_list *bl, int64 damage, int hit) {
return false;
}
/**
* Check camouflage condition
* @param bl
* @param sce
* @return True if near wall; False otherwise
* @TODO: Seems wrong
**/
bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *sce)
{
bool wall = true;
@ -16610,7 +16702,14 @@ bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *s
}
/*==========================================
*
* Initialize new skill unit for skill unit group.
* Overall, Skill Unit makes skill unit group which each group holds their cell datas (skill unit)
* @param group Skill unit group
* @param idx
* @param x
* @param y
* @param val1
* @param val2
*------------------------------------------*/
struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int x, int y, int val1, int val2)
{
@ -16618,7 +16717,7 @@ struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int
nullpo_retr(NULL, group);
nullpo_retr(NULL, group->unit); // crash-protection against poor coding
nullpo_retr(NULL, unit=&group->unit[idx]);
nullpo_retr(NULL, (unit = &group->unit[idx]));
if( map_getcell(map_id2bl(group->src_id)->m, x, y, CELL_CHKMAELSTROM) )
return unit;
@ -16626,22 +16725,23 @@ struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int
if(!unit->alive)
group->alive_count++;
unit->bl.id=map_get_new_object_id();
unit->bl.type=BL_SKILL;
unit->bl.m=group->map;
unit->bl.x=x;
unit->bl.y=y;
unit->group=group;
unit->alive=1;
unit->val1=val1;
unit->val2=val2;
unit->bl.id = map_get_new_object_id();
unit->bl.type = BL_SKILL;
unit->bl.m = group->map;
unit->bl.x = x;
unit->bl.y = y;
unit->group = group;
unit->alive = 1;
unit->val1 = val1;
unit->val2 = val2;
// Stores new skill unit
idb_put(skillunit_db, unit->bl.id, unit);
map_addiddb(&unit->bl);
if(map_addblock(&unit->bl))
return NULL;
// perform oninit actions
// Perform oninit actions
switch (group->skill_id) {
case WZ_ICEWALL:
map_setgatcell(unit->bl.m,unit->bl.x,unit->bl.y,5);
@ -16665,12 +16765,12 @@ struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int
}
clif_getareachar_skillunit(&unit->bl, unit, AREA);
return unit;
}
/*==========================================
*
* Remove unit
* @param unit
*------------------------------------------*/
int skill_delunit (struct skill_unit* unit) {
struct skill_unit_group *group;
@ -16709,8 +16809,6 @@ int skill_delunit (struct skill_unit* unit) {
break;
case HP_BASILICA:
skill_unitsetmapcell(unit,HP_BASILICA,group->skill_lv,CELL_BASILICA,false);
// Because of Basilica's range we need to specifically update the players inside when it's cancelled prematurely
map_foreachincell(skill_unit_effect,unit->bl.m,unit->bl.x,unit->bl.y,group->bl_flag,&unit->bl,0,4);
break;
case RA_ELECTRICSHOCKER: {
struct block_list* target = map_id2bl(group->val2);
@ -16742,22 +16840,20 @@ int skill_delunit (struct skill_unit* unit) {
return 0;
}
/*==========================================
*
*------------------------------------------*/
static DBMap* group_db = NULL;// int group_id -> struct skill_unit_group*
static DBMap* skillunit_group_db = NULL; /// Skill unit group DB. Key int group_id -> struct skill_unit_group*
/// Returns the target skill_unit_group or NULL if not found.
struct skill_unit_group* skill_id2group(int group_id)
{
return (struct skill_unit_group*)idb_get(group_db, group_id);
struct skill_unit_group* skill_id2group(int group_id) {
return (struct skill_unit_group*)idb_get(skillunit_group_db, group_id);
}
static int skill_unit_group_newid = MAX_SKILL_DB; /// Skill Unit Group ID
static int skill_unit_group_newid = MAX_SKILL_DB;
/// Returns a new group_id that isn't being used in group_db.
/// Fatal error if nothing is available.
/**
* Returns a new group_id that isn't being used in skillunit_group_db.
* Fatal error if nothing is available.
**/
static int skill_get_new_group_id(void)
{
if( skill_unit_group_newid >= MAX_SKILL_DB && skill_id2group(skill_unit_group_newid) == NULL )
@ -16777,6 +16873,17 @@ static int skill_get_new_group_id(void)
}
}
/**
* Initialize skill unit group called while setting new unit (skill unit/ground skill) in skill_unitsetting()
* @param src Object that cast the skill
* @param count How many 'cells' used that needed. Related with skill layout
* @param skill_id ID of used skill
* @param skill_lv Skill level of used skill
* @param unit_id Unit ID (look at skill_unit_db.txt)
* @param limit Lifetime for skill unit, uses skill_get_time(skill_id, skill_lv)
* @param interval Time interval
* @return skill_unit_group
**/
struct skill_unit_group* skill_initunitgroup (struct block_list* src, int count, uint16 skill_id, uint16 skill_lv, int unit_id, int limit, int interval)
{
struct unit_data* ud = unit_bl2ud( src );
@ -16788,21 +16895,22 @@ struct skill_unit_group* skill_initunitgroup (struct block_list* src, int count,
nullpo_retr(NULL, src);
nullpo_retr(NULL, ud);
// find a free spot to store the new unit group
// Find a free spot to store the new unit group
// TODO: Make this flexible maybe by changing this fixed array?
ARR_FIND( 0, MAX_SKILLUNITGROUP, i, ud->skillunit[i] == NULL );
if(i == MAX_SKILLUNITGROUP) {
// array is full, make room by discarding oldest group
int j=0;
unsigned maxdiff=0,tick=gettick();
for(i=0;i<MAX_SKILLUNITGROUP && ud->skillunit[i];i++){
unsigned int x=DIFF_TICK(tick,ud->skillunit[i]->tick);
if(x>maxdiff){
maxdiff=x;
j=i;
// Array is full, make room by discarding oldest group
int j = 0;
unsigned maxdiff = 0, tick = gettick();
for(i = 0; i < MAX_SKILLUNITGROUP && ud->skillunit[i];i++){
unsigned int x = DIFF_TICK(tick,ud->skillunit[i]->tick);
if(x > maxdiff){
maxdiff = x;
j = i;
}
}
skill_delunitgroup(ud->skillunit[j]);
//Since elements must have shifted, we use the last slot.
// Since elements must have shifted, we use the last slot.
i = MAX_SKILLUNITGROUP-1;
}
@ -16832,12 +16940,17 @@ struct skill_unit_group* skill_initunitgroup (struct block_list* src, int count,
if (skill_id == PR_SANCTUARY) //Sanctuary starts healing +1500ms after casted. [Skotlex]
group->tick += 1500;
idb_put(group_db, group->group_id, group);
// Stores this new group to DBMap
idb_put(skillunit_group_db, group->group_id, group);
return group;
}
/*==========================================
*
* Remove skill unit group
* @param group
* @param file
* @param line
* @param *func
*------------------------------------------*/
int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int line, const char* func)
{
@ -16895,6 +17008,14 @@ int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int li
}
}
if (group->unit_id == UNT_BASILICA) {
struct status_change *sc = status_get_sc(src);
if(sc && sc->data[SC_BASILICA]) {
sc->data[SC_BASILICA]->val3 = 0;
status_change_end(src, SC_BASILICA, INVALID_TIMER);
}
}
switch( group->skill_id ) {
case SG_SUN_WARM:
case SG_MOON_WARM:
@ -16952,11 +17073,11 @@ int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int li
group->valstr = NULL;
}
idb_remove(group_db, group->group_id);
idb_remove(skillunit_group_db, group->group_id);
map_freeblock(&group->unit->bl); // schedules deallocation of whole array (HACK)
group->unit=NULL;
group->group_id=0;
group->unit_count=0;
group->unit = NULL;
group->group_id = 0;
group->unit_count = 0;
// locate this group, swap with the last entry and delete it
ARR_FIND( 0, MAX_SKILLUNITGROUP, i, ud->skillunit[i] == group );
@ -16973,34 +17094,38 @@ int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int li
}
/*==========================================
*
* Clear all Skill Unit Group from an Object, example usage when player logged off or dead
* @param src
*------------------------------------------*/
int skill_clear_unitgroup (struct block_list *src)
{
struct unit_data *ud = unit_bl2ud(src);
void skill_clear_unitgroup (struct block_list *src) {
struct unit_data *ud;
nullpo_ret(ud);
nullpo_retv(src);
nullpo_retv((ud = unit_bl2ud(src)));
while (ud->skillunit[0])
skill_delunitgroup(ud->skillunit[0]);
return 1;
}
/*==========================================
*
* Search tickset for skill unit in skill unit group
* @param bl Block List for skill_unit
* @param group Skill unit group
* @param tick
* @return skill_unit_group_tickset if found
*------------------------------------------*/
struct skill_unit_group_tickset *skill_unitgrouptickset_search (struct block_list *bl, struct skill_unit_group *group, int tick) {
int i,j=-1,s,id;
int i, j = -1, s, id;
struct unit_data *ud;
struct skill_unit_group_tickset *set;
nullpo_ret(bl);
if (group->interval==-1)
if (group->interval == -1)
return NULL;
ud = unit_bl2ud(bl);
if (!ud) return NULL;
if (!ud)
return NULL;
set = ud->skillunittick;
@ -17028,7 +17153,8 @@ struct skill_unit_group_tickset *skill_unitgrouptickset_search (struct block_lis
}
/*==========================================
*
* Check for validity skill unit that triggered by skill_unit_timer_sub
* And trigger skill_unit_onplace_timer for object that maybe stands there (catched object is *bl)
*------------------------------------------*/
int skill_unit_timer_sub_onplace (struct block_list* bl, va_list ap) {
struct skill_unit* unit = va_arg(ap,struct skill_unit *);
@ -17047,12 +17173,12 @@ int skill_unit_timer_sub_onplace (struct block_list* bl, va_list ap) {
return 0;
skill_unit_onplace_timer(unit,bl,tick);
return 1;
}
/**
* @see DBApply
* Sub function of skill_unit_timer for executing each skill unit from skillunit_db
*/
static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
{
@ -17067,7 +17193,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
nullpo_ret(group);
// check for expiration
// Check for expiration
if( !group->state.guildaura && (DIFF_TICK(tick,group->tick) >= group->limit || DIFF_TICK(tick,group->tick) >= unit->limit) )
{// skill unit expired (inlined from skill_unit_onlimit())
switch( group->unit_id )
@ -17271,7 +17397,8 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
}
}
if( dissonance ) skill_dance_switch(unit, 1);
if( dissonance )
skill_dance_switch(unit, 1);
return 0;
}
@ -17284,7 +17411,6 @@ int skill_unit_timer(int tid, unsigned int tick, int id, intptr_t data) {
skillunit_db->foreach(skillunit_db, skill_unit_timer_sub, tick);
map_freeblock_unlock();
return 0;
}
@ -17933,7 +18059,6 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, unsigned sh
if(make_per < 1) make_per = 1;
if(rnd()%10000 < make_per || qty > 1){ //Success, or crafting multiple items.
struct item tmp_item;
memset(&tmp_item,0,sizeof(tmp_item));
@ -19963,7 +20088,7 @@ void do_init_skill (void){
skilldb_name2id = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, 0);
skill_readdb();
group_db = idb_alloc(DB_OPT_BASE);
skillunit_group_db = idb_alloc(DB_OPT_BASE);
skillunit_db = idb_alloc(DB_OPT_BASE);
skillusave_db = idb_alloc(DB_OPT_RELEASE_DATA);
bowling_db = idb_alloc(DB_OPT_BASE);
@ -19982,7 +20107,7 @@ void do_init_skill (void){
void do_final_skill(void){
skill_destroy_requirement();
db_destroy(skilldb_name2id);
db_destroy(group_db);
db_destroy(skillunit_group_db);
db_destroy(skillunit_db);
db_destroy(skillusave_db);
db_destroy(bowling_db);

View File

@ -211,38 +211,43 @@ struct skill_timerskill {
int flag;
};
#define MAX_SKILLUNITGROUP 25
#define MAX_SKILLUNITGROUP 25 /// Maximum skill unit group (for same skill each source)
/// Skill unit group
struct skill_unit_group {
int src_id;
int party_id;
int guild_id;
int bg_id;
int map;
int target_flag; //Holds BCT_* flag for battle_check_target
int bl_flag; //Holds BL_* flag for map_foreachin* functions
unsigned int tick;
int limit,interval;
uint16 skill_id,skill_lv;
int val1,val2,val3;
char *valstr;
int unit_id;
int group_id;
int unit_count,alive_count;
int item_id; //store item used.
struct skill_unit *unit;
int src_id; /// Caster ID/RID, if player is account_id
int party_id; /// Party ID
int guild_id; /// Guild ID
int bg_id; /// Battleground ID
int map; /// Map
int target_flag; /// Holds BCT_* flag for battle_check_target
int bl_flag; /// Holds BL_* flag for map_foreachin* functions
unsigned int tick; /// Tick when skill unit initialized
int limit, /// Life time
interval; /// Timer interval
uint16 skill_id, /// Skill ID
skill_lv; /// Skill level
int val1, val2, val3; /// Values
char *valstr; /// String value, used for HT_TALKIEBOX & RG_GRAFFITI
int unit_id; /// Unit ID (for client effect)
int group_id; /// Skill Group ID
int unit_count, /// Number of unit at this group
alive_count; /// Number of alive unit
int item_id; /// Store item used.
struct skill_unit *unit; /// Skill Unit
struct {
unsigned ammo_consume : 1;
unsigned ammo_consume : 1; // Need to consume ammo
unsigned song_dance : 2; //0x1 Song/Dance, 0x2 Ensemble
unsigned guildaura : 1;
unsigned guildaura : 1; // Guild Aura
} state;
};
/// Skill unit
struct skill_unit {
struct block_list bl;
struct skill_unit_group *group;
struct skill_unit_group *group; /// Skill group reference
int limit;
int val1,val2;
short alive,range;
int val1, val2;
short alive, range;
};
#define MAX_SKILLUNITGROUPTICKSET 25
@ -358,7 +363,7 @@ int skill_get_itemqty( uint16 skill_id, int idx );
int skill_name2id(const char* name);
int skill_isammotype(struct map_session_data *sd, int skill);
int skill_isammotype(struct map_session_data *sd, unsigned short skill_id);
int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data);
int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data);
int skill_castend_map( struct map_session_data *sd,uint16 skill_id, const char *map);
@ -380,10 +385,10 @@ int skill_delunit(struct skill_unit *unit);
struct skill_unit_group *skill_initunitgroup(struct block_list* src, int count, uint16 skill_id, uint16 skill_lv, int unit_id, int limit, int interval);
int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int line, const char* func);
#define skill_delunitgroup(group) skill_delunitgroup_(group,__FILE__,__LINE__,__func__)
int skill_clear_unitgroup(struct block_list *src);
void skill_clear_unitgroup(struct block_list *src);
int skill_clear_group(struct block_list *bl, int flag);
void ext_skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, unsigned int tick);
int64 skill_unit_ondamaged(struct skill_unit *unit,struct block_list *bl,int64 damage,unsigned int tick);
int64 skill_unit_ondamaged(struct skill_unit *unit,struct block_list *bl,int64 damage);
int skill_castfix( struct block_list *bl, uint16 skill_id, uint16 skill_lv);
int skill_castfix_sc( struct block_list *bl, int time);
@ -425,7 +430,7 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk
bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce);
// Abnormal status
int skill_enchant_elemental_end(struct block_list *bl, int type);
void skill_enchant_elemental_end(struct block_list *bl, int type);
bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd);
bool skill_isNotOk_hom(uint16 skill_id, struct homun_data *hd);
bool skill_isNotOk_mercenary(uint16 skill_id, struct mercenary_data *md);

View File

@ -1196,7 +1196,6 @@ void initChangeTables(void)
/* StatusChangeState (SCS_) NOCAST (skills) */
StatusChangeStateTable[SC_SILENCE] |= SCS_NOCAST;
StatusChangeStateTable[SC_STEELBODY] |= SCS_NOCAST;
StatusChangeStateTable[SC_BASILICA] |= SCS_NOCAST;
StatusChangeStateTable[SC_BERSERK] |= SCS_NOCAST;
StatusChangeStateTable[SC__BLOODYLUST] |= SCS_NOCAST;
StatusChangeStateTable[SC_DEATHBOUND] |= SCS_NOCAST;
@ -1353,7 +1352,7 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in
}
if (target->type == BL_SKILL)
return (int)skill_unit_ondamaged((struct skill_unit *)target, src, hp, gettick());
return (int)skill_unit_ondamaged((struct skill_unit *)target, src, hp);
status = status_get_status_data(target);
if(!status || status == &dummy_status )
@ -1866,6 +1865,7 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin
) { // Skills blocked through status changes...
if (!flag && ( // Blocked only from using the skill (stuff like autospell may still go through
sc->cant.cast ||
(sc->data[SC_BASILICA] && (sc->data[SC_BASILICA]->val4 != src->id || skill_id != HP_BASILICA)) || // Only Basilica caster that can cast, and only Basilica to cancel it
(sc->data[SC_MARIONETTE] && skill_id != CG_MARIONETTE) || // Only skill you can use is marionette again to cancel it
(sc->data[SC_MARIONETTE2] && skill_id == CG_MARIONETTE) || // Cannot use marionette if you are being buffed by another
(sc->data[SC_STASIS] && skill_block_check(src, SC_STASIS, skill_id)) ||
@ -10729,6 +10729,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
if (sce->val3) { // Clear the group.
struct skill_unit_group* group = skill_id2group(sce->val3);
sce->val3 = 0;
if (group)
skill_delunitgroup(group);
}
break;
@ -10737,7 +10738,12 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
skill_clear_unitgroup(bl);
break;
case SC_BASILICA: // Clear the skill area. [Skotlex]
skill_clear_unitgroup(bl);
if (sce->val3 && sce->val4 == bl->id) {
struct skill_unit_group* group = skill_id2group(sce->val3);
sce->val3 = 0;
if (group)
skill_delunitgroup(group);
}
break;
case SC_TRICKDEAD:
if (vd) vd->dead_sit = 0;