* 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 // High Priest
361,9,6,16,0,0x1,1,5,1,yes,0,0,0,magic,0,0x0, HP_ASSUMPTIO,Assumptio 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 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 330,0xaf, , 3, 0, -1,all, 0x140 //DC_SERVICEFORYOU
336,0xb2, , 0,-1, -1,noone, 0x000 //WE_CALLPARTNER 336,0xb2, , 0,-1, -1,noone, 0x000 //WE_CALLPARTNER
339,0x86, , -1, 0, 300,enemy, 0x000 //NPC_DARKGRANDCROSS 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 369,0xb3, , -1, 0,10000,all, 0x008 //PA_GOSPEL
395,0xb5, , 4, 0, -1,all, 0x200 //CG_MOONLIT 395,0xb5, , 4, 0, -1,all, 0x200 //CG_MOONLIT
404,0xb6, , -1, 0, -1,all, 0x8000 //PF_FOGWALL 404,0xb6, , -1, 0, -1,all, 0x8000 //PF_FOGWALL

View File

@ -507,7 +507,7 @@
//**** //****
// High Priest // High Priest
361,9,6,16,0,0x1,1,5,1,yes,0,0,0,magic,0,0x0, HP_ASSUMPTIO,Assumptio 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 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 330,0xaf, , 3, 0, -1,all, 0x140 //DC_SERVICEFORYOU
336,0xb2, , 0,-1, -1,noone, 0x000 //WE_CALLPARTNER 336,0xb2, , 0,-1, -1,noone, 0x000 //WE_CALLPARTNER
339,0x86, , -1, 0, 300,enemy, 0x000 //NPC_DARKGRANDCROSS 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 369,0xb3, , -1, 0,10000,all, 0x008 //PA_GOSPEL
395,0xb5, , 4, 0, -1,all, 0x200 //CG_MOONLIT 395,0xb5, , 4, 0, -1,all, 0x200 //CG_MOONLIT
404,0xb6, , -1, 0, -1,all, 0x8000 //PF_FOGWALL 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 ) { bool pc_can_attack( struct map_session_data *sd, int target_id ) {
nullpo_retr(false, sd); nullpo_retr(false, sd);
if (!&sd->sc)
return true;
if( sd->sc.data[SC_BASILICA] || if( sd->sc.data[SC_BASILICA] ||
sd->sc.data[SC__SHADOWFORM] || sd->sc.data[SC__SHADOWFORM] ||
sd->sc.data[SC__MANHOLE] || 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) && 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!) 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) { if(sd->status.inventory[n].equip & EQP_ARMOR) {
// On Armor Change... // 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; return 0;
} }
skill_clear_unitgroup(src); skill_clear_unitgroup(src);
if( skill_unitsetting(src,skill_id,skill_lv,x,y,0) ) 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));
flag|=1; flag|=1;
} }
break; break;
@ -11805,8 +11804,14 @@ static int skill_icewall_block(struct block_list *bl,va_list ap) {
return 0; return 0;
} }
/*========================================== /*==========================================
* Initializes and sets a ground skill. * Initializes and sets a ground skill / skill unit. Usually called after skill_casted_pos() or skill_castend_map()
* flag&1 is used to determine when the skill 'morphs' (Warp portal becomes active, or Fire Pillar becomes active) * @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* skill_unitsetting (struct block_list *src, uint16 skill_id, uint16 skill_lv, int16 x, int16 y, int flag)
{ {
@ -12133,7 +12138,8 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill
break; 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)); // 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->val1 = val1;
group->val2 = val2; group->val2 = val2;
group->val3 = val3; group->val3 = val3;
@ -12143,10 +12149,11 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill
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.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->state.guildaura = ( skill_id >= GD_LEADERSHIP && skill_id <= GD_HAWKEYES )?1:0;
group->item_id = req_item; 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) if (DIFF_TICK(group->tick, gettick()) > SKILLUNITTIMER_INTERVAL)
active_flag = 0; active_flag = 0;
// Put message for Talkie Box & Graffiti
if (skill_id == HT_TALKIEBOX || skill_id == RG_GRAFFITI) { if (skill_id == HT_TALKIEBOX || skill_id == RG_GRAFFITI) {
group->valstr=(char *) aMalloc(MESSAGE_SIZE*sizeof(char)); group->valstr=(char *) aMalloc(MESSAGE_SIZE*sizeof(char));
if (sd) if (sd)
@ -12155,22 +12162,22 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill
safestrncpy(group->valstr, "Boo!", MESSAGE_SIZE); safestrncpy(group->valstr, "Boo!", MESSAGE_SIZE);
} }
// Dance skill
if (group->state.song_dance) { if (group->state.song_dance) {
if(sd) { if(sd) {
sd->skill_id_dance = skill_id; sd->skill_id_dance = skill_id;
sd->skill_lv_dance = skill_lv; sd->skill_lv_dance = skill_lv;
} }
if ( if (
sc_start4(src, src, SC_DANCING, 100, skill_id, group->group_id, skill_lv, sc_start4(src, src, SC_DANCING, 100, skill_id, group->group_id, skill_lv, (group->state.song_dance&2?BCT_SELF:0), limit+1000) &&
(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! 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); skill_check_pc_partner(sd, skill_id, &skill_lv, 1, 1);
} }
// Set skill unit
limit = group->limit; limit = group->limit;
for( i = 0; i < layout->count; i++ ) for( i = 0; i < layout->count; i++ ) {
{
struct skill_unit *unit; struct skill_unit *unit;
int ux = x + layout->dx[i]; int ux = x + layout->dx[i];
int uy = y + layout->dy[i]; int uy = y + layout->dy[i];
@ -12188,8 +12195,7 @@ 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) ) 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. continue; // no path between cell and center of casting.
switch( skill_id ) switch( skill_id ) {
{
case MG_FIREWALL: case MG_FIREWALL:
case NJ_KAENSIN: case NJ_KAENSIN:
val2_2 = group->val2; val2_2 = group->val2;
@ -12254,12 +12260,13 @@ 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 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); 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 ) if( range <= 0 )
map_foreachincell(skill_cell_overlap,src->m,ux,uy,BL_SKILL,skill_id, &alive, src); map_foreachincell(skill_cell_overlap,src->m,ux,uy,BL_SKILL,skill_id, &alive, src);
if( !alive ) if( !alive )
continue; continue;
nullpo_retr(NULL, unit=skill_initunit(group,i,ux,uy,val1_2,val2_2)); nullpo_retr(NULL, (unit = skill_initunit(group,i,ux,uy,val1_2,val2_2)));
unit->limit = limit; unit->limit = limit;
unit->range = range; unit->range = range;
@ -12269,7 +12276,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill
group->limit = unit->limit; group->limit = unit->limit;
} }
// execute on all targets standing on this cell // Execute on all targets standing on this cell
if (range == 0 && active_flag) 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); 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);} 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) static int skill_unit_onplace (struct skill_unit *unit, struct block_list *bl, unsigned int tick)
{ {
struct skill_unit_group *sg; 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 *sc;
struct status_change_entry *sce; struct status_change_entry *sce;
enum sc_type type; 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); sc_start4(ss, bl,type,100,sg->skill_lv,0,BCT_ENEMY,sg->group_id,sg->limit);
break; 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] // officially, icewall has no problems existing on occupied cells [ultramage]
// case UNT_ICEWALL: //Destroy the cell. [Skotlex] // case UNT_ICEWALL: //Destroy the cell. [Skotlex]
// unit->val1 = 0; // 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) 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); int i = battle_check_target(&src->bl, bl, BCT_ENEMY);
if( i > 0 && !(status_get_mode(bl)&MD_BOSS) ) if( i > 0 && !(status_get_mode(bl)&MD_BOSS) )
{ // knock-back any enemy except 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); clif_fixpos(bl);
break;
} }
if (i <= 0 && (!tsc || !tsc->data[SC_BASILICA]))
if( sg->src_id != bl->id && i <= 0 ) sc_start4(ss, bl, type, 100, 0, 0, sg->group_id, ss->id, sg->limit);
sc_start4(ss, bl, type, 100, 0, 0, 0, src->bl.id, sg->interval + 100);
} }
break; break;
@ -12995,7 +13026,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
**/ **/
case UNT_POISONSMOKE: case UNT_POISONSMOKE:
if( battle_check_target(ss,bl,BCT_ENEMY) > 0 && !(tsc && tsc->data[sg->val2]) && rnd()%100 < 20 ) 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; break;
case UNT_EPICLESIS: case UNT_EPICLESIS:
@ -13040,7 +13071,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
case UNT_DIMENSIONDOOR: case UNT_DIMENSIONDOOR:
if( tsd && !map[bl->m].flag.noteleport ) 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 ) else if( bl->type == BL_MOB && battle_config.mob_warp&8 )
unit_warp(bl,-1,-1,-1,CLR_TELEPORT); unit_warp(bl,-1,-1,-1,CLR_TELEPORT);
break; break;
@ -13260,7 +13291,10 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
return skill_id; 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) 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; break;
case UNT_BASILICA: case UNT_BASILICA:
if (sce) if (sce && sce->val4 != bl->id)
status_change_end(bl, type, INVALID_TIMER); status_change_end(bl, type, INVALID_TIMER);
break; break;
case UNT_HERMODE: //Clear Hermode if the owner moved. case UNT_HERMODE: //Clear Hermode if the owner moved.
if (sce && sce->val3 == BCT_SELF && sce->val4 == sg->group_id) if (sce && sce->val3 == BCT_SELF && sce->val4 == sg->group_id)
status_change_end(bl, type, INVALID_TIMER); 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] * 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) 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; 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) 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] * 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) 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 * Sub function to count how many spawned mob is around.
* return : * Some skills check with matched AI.
* x : numbers of mob of class with special 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) 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 * Determines if a given skill should be made to consume ammo
* when used by the player. [Skotlex] * 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 ( return (
battle_config.arrow_decrement==2 && battle_config.arrow_decrement==2 &&
(sd->status.weapon == W_BOW || (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE)) && (sd->status.weapon == W_BOW || (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE)) &&
skill != HT_PHANTASMIC && skill_id != HT_PHANTASMIC &&
skill_get_type(skill) == BF_WEAPON && skill_get_type(skill_id) == BF_WEAPON &&
!(skill_get_nk(skill)&NK_NO_DAMAGE) && !(skill_get_nk(skill_id)&NK_NO_DAMAGE) &&
!skill_get_spiritball(skill,1) //Assume spirit spheres are used as ammo instead. !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: case HP_BASILICA:
if( !sc || (sc && !sc->data[SC_BASILICA])) { if( !sc || (sc && !sc->data[SC_BASILICA])) {
if( sd ) { 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; int size = range*2+1;
for( s=0;s<size*size;s++ ) { for( s=0;s<size*size;s++ ) {
int x = sd->bl.x+(s%size-range); 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) int skill_frostjoke_scream (struct block_list *bl, va_list ap)
{ {
@ -15986,7 +16046,8 @@ int skill_frostjoke_scream (struct block_list *bl, va_list ap)
skill_id = va_arg(ap,int); skill_id = va_arg(ap,int);
skill_lv = va_arg(ap,int); skill_lv = va_arg(ap,int);
if(!skill_lv) return 0; if(!skill_lv)
return 0;
tick = va_arg(ap,unsigned int); tick = va_arg(ap,unsigned int);
if (src == bl || status_isdead(bl)) if (src == bl || status_isdead(bl))
@ -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) 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) int skill_attack_area (struct block_list *bl, va_list ap)
{ {
@ -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); 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) 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]; struct skill_unit_group *group[MAX_SKILLUNITGROUP];
int i, count = 0; int i, count = 0;
nullpo_ret(bl); 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] // 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++) for (i = 0; i < MAX_SKILLUNITGROUP && ud->skillunit[i]; i++) {
{
switch (ud->skillunit[i]->skill_id) { switch (ud->skillunit[i]->skill_id) {
case SA_DELUGE: case SA_DELUGE:
case SA_VOLCANO: case SA_VOLCANO:
@ -16129,13 +16200,16 @@ int skill_clear_group (struct block_list *bl, int flag)
/*========================================== /*==========================================
* Returns the first element field found [Skotlex] * 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 skill_unit_group *skill_locate_element_field(struct block_list *bl)
{ {
struct unit_data *ud = unit_bl2ud(bl); struct unit_data *ud;
int i; int i;
nullpo_ret(bl); 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) { switch (ud->skillunit[i]->skill_id) {
@ -16152,7 +16226,7 @@ struct skill_unit_group *skill_locate_element_field(struct block_list *bl)
return NULL; return NULL;
} }
// for graffiti cleaner [Valaris] /// Graffiti cleaner [Valaris]
int skill_graffitiremover (struct block_list *bl, va_list ap) { int skill_graffitiremover (struct block_list *bl, va_list ap) {
struct skill_unit *unit=NULL; struct skill_unit *unit=NULL;
@ -16168,6 +16242,7 @@ int skill_graffitiremover (struct block_list *bl, va_list ap) {
return 0; return 0;
} }
/// Greed effect
int skill_greed (struct block_list *bl, va_list ap) { int skill_greed (struct block_list *bl, va_list ap) {
struct block_list *src; struct block_list *src;
struct map_session_data *sd=NULL; struct map_session_data *sd=NULL;
@ -16181,7 +16256,8 @@ int skill_greed (struct block_list *bl, va_list ap) {
return 0; return 0;
} }
//For Ranger's Detonator [Jobbie/3CeAM]
/// Ranger's Detonator [Jobbie/3CeAM]
int skill_detonator(struct block_list *bl, va_list ap) int skill_detonator(struct block_list *bl, va_list ap)
{ {
struct skill_unit *unit=NULL; 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) 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) 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; 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 }; 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; int i;
nullpo_ret(bl); nullpo_retv(bl);
nullpo_ret(sc= status_get_sc(bl)); nullpo_retv(sc= status_get_sc(bl));
if (!sc->count) return 0; if (!sc->count)
return;
for (i = 0; i < ARRAYLENGTH(scs); i++) for (i = 0; i < ARRAYLENGTH(scs); i++)
if (type != scs[i] && sc->data[scs[i]]) if (type != scs[i] && sc->data[scs[i]])
status_change_end(bl, scs[i], INVALID_TIMER); 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 skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce)
{ {
bool wall = true; bool wall = true;
@ -16585,6 +16670,13 @@ bool skill_check_shadowform(struct block_list *bl, int64 damage, int hit) {
return false; 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 skill_check_camouflage(struct block_list *bl, struct status_change_entry *sce)
{ {
bool wall = true; 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) 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);
nullpo_retr(NULL, group->unit); // crash-protection against poor coding 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) ) if( map_getcell(map_id2bl(group->src_id)->m, x, y, CELL_CHKMAELSTROM) )
return unit; return unit;
@ -16636,12 +16735,13 @@ struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int
unit->val1 = val1; unit->val1 = val1;
unit->val2 = val2; unit->val2 = val2;
// Stores new skill unit
idb_put(skillunit_db, unit->bl.id, unit); idb_put(skillunit_db, unit->bl.id, unit);
map_addiddb(&unit->bl); map_addiddb(&unit->bl);
if(map_addblock(&unit->bl)) if(map_addblock(&unit->bl))
return NULL; return NULL;
// perform oninit actions // Perform oninit actions
switch (group->skill_id) { switch (group->skill_id) {
case WZ_ICEWALL: case WZ_ICEWALL:
map_setgatcell(unit->bl.m,unit->bl.x,unit->bl.y,5); 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); clif_getareachar_skillunit(&unit->bl, unit, AREA);
return unit; return unit;
} }
/*========================================== /*==========================================
* * Remove unit
* @param unit
*------------------------------------------*/ *------------------------------------------*/
int skill_delunit (struct skill_unit* unit) { int skill_delunit (struct skill_unit* unit) {
struct skill_unit_group *group; struct skill_unit_group *group;
@ -16709,8 +16809,6 @@ int skill_delunit (struct skill_unit* unit) {
break; break;
case HP_BASILICA: case HP_BASILICA:
skill_unitsetmapcell(unit,HP_BASILICA,group->skill_lv,CELL_BASILICA,false); 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; break;
case RA_ELECTRICSHOCKER: { case RA_ELECTRICSHOCKER: {
struct block_list* target = map_id2bl(group->val2); struct block_list* target = map_id2bl(group->val2);
@ -16742,22 +16840,20 @@ int skill_delunit (struct skill_unit* unit) {
return 0; return 0;
} }
/*==========================================
* static DBMap* skillunit_group_db = NULL; /// Skill unit group DB. Key int group_id -> struct skill_unit_group*
*------------------------------------------*/
static DBMap* group_db = NULL;// int group_id -> struct skill_unit_group*
/// Returns the target skill_unit_group or NULL if not found. /// Returns the target skill_unit_group or NULL if not found.
struct skill_unit_group* skill_id2group(int group_id) struct skill_unit_group* skill_id2group(int group_id) {
{ return (struct skill_unit_group*)idb_get(skillunit_group_db, group_id);
return (struct skill_unit_group*)idb_get(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 skillunit_group_db.
/// Returns a new group_id that isn't being used in group_db. * Fatal error if nothing is available.
/// Fatal error if nothing is available. **/
static int skill_get_new_group_id(void) static int skill_get_new_group_id(void)
{ {
if( skill_unit_group_newid >= MAX_SKILL_DB && skill_id2group(skill_unit_group_newid) == NULL ) 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 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 ); struct unit_data* ud = unit_bl2ud( src );
@ -16788,10 +16895,11 @@ struct skill_unit_group* skill_initunitgroup (struct block_list* src, int count,
nullpo_retr(NULL, src); nullpo_retr(NULL, src);
nullpo_retr(NULL, ud); 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 ); ARR_FIND( 0, MAX_SKILLUNITGROUP, i, ud->skillunit[i] == NULL );
if(i == MAX_SKILLUNITGROUP) { if(i == MAX_SKILLUNITGROUP) {
// array is full, make room by discarding oldest group // Array is full, make room by discarding oldest group
int j = 0; int j = 0;
unsigned maxdiff = 0, tick = gettick(); unsigned maxdiff = 0, tick = gettick();
for(i = 0; i < MAX_SKILLUNITGROUP && ud->skillunit[i];i++){ for(i = 0; i < MAX_SKILLUNITGROUP && ud->skillunit[i];i++){
@ -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] if (skill_id == PR_SANCTUARY) //Sanctuary starts healing +1500ms after casted. [Skotlex]
group->tick += 1500; 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; 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) 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 ) { switch( group->skill_id ) {
case SG_SUN_WARM: case SG_SUN_WARM:
case SG_MOON_WARM: case SG_MOON_WARM:
@ -16952,7 +17073,7 @@ int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int li
group->valstr = NULL; 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) map_freeblock(&group->unit->bl); // schedules deallocation of whole array (HACK)
group->unit = NULL; group->unit = NULL;
group->group_id = 0; group->group_id = 0;
@ -16973,22 +17094,25 @@ 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) void skill_clear_unitgroup (struct block_list *src) {
{ struct unit_data *ud;
struct unit_data *ud = unit_bl2ud(src);
nullpo_ret(ud); nullpo_retv(src);
nullpo_retv((ud = unit_bl2ud(src)));
while (ud->skillunit[0]) while (ud->skillunit[0])
skill_delunitgroup(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) { 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;
@ -17000,7 +17124,8 @@ struct skill_unit_group_tickset *skill_unitgrouptickset_search (struct block_lis
return NULL; return NULL;
ud = unit_bl2ud(bl); ud = unit_bl2ud(bl);
if (!ud) return NULL; if (!ud)
return NULL;
set = ud->skillunittick; 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) { int skill_unit_timer_sub_onplace (struct block_list* bl, va_list ap) {
struct skill_unit* unit = va_arg(ap,struct skill_unit *); 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; return 0;
skill_unit_onplace_timer(unit,bl,tick); skill_unit_onplace_timer(unit,bl,tick);
return 1; return 1;
} }
/** /**
* @see DBApply * @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) 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); 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) ) 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()) {// skill unit expired (inlined from skill_unit_onlimit())
switch( group->unit_id ) 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; 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); skillunit_db->foreach(skillunit_db, skill_unit_timer_sub, tick);
map_freeblock_unlock(); map_freeblock_unlock();
return 0; 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(make_per < 1) make_per = 1;
if(rnd()%10000 < make_per || qty > 1){ //Success, or crafting multiple items. if(rnd()%10000 < make_per || qty > 1){ //Success, or crafting multiple items.
struct item tmp_item; struct item tmp_item;
memset(&tmp_item,0,sizeof(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); skilldb_name2id = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, 0);
skill_readdb(); skill_readdb();
group_db = idb_alloc(DB_OPT_BASE); skillunit_group_db = idb_alloc(DB_OPT_BASE);
skillunit_db = idb_alloc(DB_OPT_BASE); skillunit_db = idb_alloc(DB_OPT_BASE);
skillusave_db = idb_alloc(DB_OPT_RELEASE_DATA); skillusave_db = idb_alloc(DB_OPT_RELEASE_DATA);
bowling_db = idb_alloc(DB_OPT_BASE); bowling_db = idb_alloc(DB_OPT_BASE);
@ -19982,7 +20107,7 @@ void do_init_skill (void){
void do_final_skill(void){ void do_final_skill(void){
skill_destroy_requirement(); skill_destroy_requirement();
db_destroy(skilldb_name2id); db_destroy(skilldb_name2id);
db_destroy(group_db); db_destroy(skillunit_group_db);
db_destroy(skillunit_db); db_destroy(skillunit_db);
db_destroy(skillusave_db); db_destroy(skillusave_db);
db_destroy(bowling_db); db_destroy(bowling_db);

View File

@ -211,35 +211,40 @@ struct skill_timerskill {
int flag; 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 { struct skill_unit_group {
int src_id; int src_id; /// Caster ID/RID, if player is account_id
int party_id; int party_id; /// Party ID
int guild_id; int guild_id; /// Guild ID
int bg_id; int bg_id; /// Battleground ID
int map; int map; /// Map
int target_flag; //Holds BCT_* flag for battle_check_target int target_flag; /// Holds BCT_* flag for battle_check_target
int bl_flag; //Holds BL_* flag for map_foreachin* functions int bl_flag; /// Holds BL_* flag for map_foreachin* functions
unsigned int tick; unsigned int tick; /// Tick when skill unit initialized
int limit,interval; int limit, /// Life time
uint16 skill_id,skill_lv; interval; /// Timer interval
int val1,val2,val3; uint16 skill_id, /// Skill ID
char *valstr; skill_lv; /// Skill level
int unit_id; int val1, val2, val3; /// Values
int group_id; char *valstr; /// String value, used for HT_TALKIEBOX & RG_GRAFFITI
int unit_count,alive_count; int unit_id; /// Unit ID (for client effect)
int item_id; //store item used. int group_id; /// Skill Group ID
struct skill_unit *unit; 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 { struct {
unsigned ammo_consume : 1; unsigned ammo_consume : 1; // Need to consume ammo
unsigned song_dance : 2; //0x1 Song/Dance, 0x2 Ensemble unsigned song_dance : 2; //0x1 Song/Dance, 0x2 Ensemble
unsigned guildaura : 1; unsigned guildaura : 1; // Guild Aura
} state; } state;
}; };
/// Skill unit
struct skill_unit { struct skill_unit {
struct block_list bl; struct block_list bl;
struct skill_unit_group *group; struct skill_unit_group *group; /// Skill group reference
int limit; int limit;
int val1, val2; int val1, val2;
short alive, range; short alive, range;
@ -358,7 +363,7 @@ int skill_get_itemqty( uint16 skill_id, int idx );
int skill_name2id(const char* name); 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_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_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); 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); 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); 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__) #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); 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); 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( struct block_list *bl, uint16 skill_id, uint16 skill_lv);
int skill_castfix_sc( struct block_list *bl, int time); 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); bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce);
// Abnormal status // 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(uint16 skill_id, struct map_session_data *sd);
bool skill_isNotOk_hom(uint16 skill_id, struct homun_data *hd); bool skill_isNotOk_hom(uint16 skill_id, struct homun_data *hd);
bool skill_isNotOk_mercenary(uint16 skill_id, struct mercenary_data *md); bool skill_isNotOk_mercenary(uint16 skill_id, struct mercenary_data *md);

View File

@ -1196,7 +1196,6 @@ void initChangeTables(void)
/* StatusChangeState (SCS_) NOCAST (skills) */ /* StatusChangeState (SCS_) NOCAST (skills) */
StatusChangeStateTable[SC_SILENCE] |= SCS_NOCAST; StatusChangeStateTable[SC_SILENCE] |= SCS_NOCAST;
StatusChangeStateTable[SC_STEELBODY] |= SCS_NOCAST; StatusChangeStateTable[SC_STEELBODY] |= SCS_NOCAST;
StatusChangeStateTable[SC_BASILICA] |= SCS_NOCAST;
StatusChangeStateTable[SC_BERSERK] |= SCS_NOCAST; StatusChangeStateTable[SC_BERSERK] |= SCS_NOCAST;
StatusChangeStateTable[SC__BLOODYLUST] |= SCS_NOCAST; StatusChangeStateTable[SC__BLOODYLUST] |= SCS_NOCAST;
StatusChangeStateTable[SC_DEATHBOUND] |= 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) 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); status = status_get_status_data(target);
if(!status || status == &dummy_status ) 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... ) { // Skills blocked through status changes...
if (!flag && ( // Blocked only from using the skill (stuff like autospell may still go through if (!flag && ( // Blocked only from using the skill (stuff like autospell may still go through
sc->cant.cast || 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_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_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)) || (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. if (sce->val3) { // Clear the group.
struct skill_unit_group* group = skill_id2group(sce->val3); struct skill_unit_group* group = skill_id2group(sce->val3);
sce->val3 = 0; sce->val3 = 0;
if (group)
skill_delunitgroup(group); skill_delunitgroup(group);
} }
break; break;
@ -10737,7 +10738,12 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
skill_clear_unitgroup(bl); skill_clear_unitgroup(bl);
break; break;
case SC_BASILICA: // Clear the skill area. [Skotlex] 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; break;
case SC_TRICKDEAD: case SC_TRICKDEAD:
if (vd) vd->dead_sit = 0; if (vd) vd->dead_sit = 0;