- Implemented official Bowling Bash with all its special behaviors including the gutter line (bugreport:4209)

* As many servers probably want to remove the gutter line problem, it is configurable; just adjust the bowling_bash_area setting in skill.conf
- Sonic Blow now has a fixed range of 1, even for monsters; a monster can't use this skill if you tank it from farther away (bugreport:3453)

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@17295 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
playtester 2013-04-25 19:52:09 +00:00
parent b5769e1c67
commit a15cee063d
6 changed files with 83 additions and 26 deletions

View File

@ -280,3 +280,10 @@ dancing_weaponswitch_fix: yes
// 0: (official) Traps in GvG only make player stop moving after its walk path is complete, and it activates other traps on the way.
// 1: Traps in GvG make player stop moving right when stepping over it.
skill_trap_type: 0
// Area of Bowling Bash chain reaction
// 0: Use official gutter line system
// 1: Gutter line system without demi gutter bug
// 2-20: Area around caster (2 = 5x5, 3 = 7x7, 4 = 9x9, ..., 20 = 41x41)
// Note: If you knock the target out of the area it will only be hit once and won't do splash damage
bowling_bash_area: 0

View File

@ -179,7 +179,7 @@
133,0,0,0,0,0,0,5,0,no,0,0,0,weapon,0, AS_LEFT,Lefthand Mastery
134,0,0,0,0,0,0,10,0,no,0,0,0,weapon,0, AS_KATAR,Katar Mastery
135,0,6,4,0,0x1,0,10,1,no,0,0,0,weapon,0, AS_CLOAKING,Cloaking
136,-1,8,1,-1,0,0,10,8,no,0,0,0,weapon,0, AS_SONICBLOW,Sonic Blow
136,1,8,1,-1,0,0,10,8,no,0,0,0,weapon,0, AS_SONICBLOW,Sonic Blow
137,3:4:5:6:7,6,1,-1,0x2,1,5,1,no,0,0,0,weapon,0,AS_GRIMTOOTH,Grimtooth
138,1,6,16,5,0x1,0,10,1,no,0,0x400,0,weapon,0, AS_ENCHANTPOISON,Enchant Poison
139,0,6,4,0,0,0,10,1,no,0,0,0,weapon,0, AS_POISONREACT,Poison React

View File

@ -179,7 +179,7 @@
133,0,0,0,0,0,0,5,0,no,0,0,0,weapon,0, AS_LEFT,Lefthand Mastery
134,0,0,0,0,0,0,10,0,no,0,0,0,weapon,0, AS_KATAR,Katar Mastery
135,0,6,4,0,0x1,0,10,1,no,0,0,0,weapon,0, AS_CLOAKING,Cloaking
136,-1,8,1,-1,0,0,10,8,no,0,0,0,weapon,0, AS_SONICBLOW,Sonic Blow
136,1,8,1,-1,0,0,10,8,no,0,0,0,weapon,0, AS_SONICBLOW,Sonic Blow
137,3:4:5:6:7,6,1,-1,0x2,1,5,1,no,0,0,0,weapon,0,AS_GRIMTOOTH,Grimtooth
138,1,6,16,5,0x1,0,10,1,no,0,0x400,0,weapon,0, AS_ENCHANTPOISON,Enchant Poison
139,0,6,4,0,0,0,10,1,no,0,0,0,weapon,0, AS_POISONREACT,Poison React

View File

@ -5943,6 +5943,7 @@ static const struct _battle_data {
{ "max_walk_path", &battle_config.max_walk_path, 17, 1, MAX_WALKPATH, },
{ "item_enabled_npc", &battle_config.item_enabled_npc, 1, 0, 1, },
{ "item_flooritem_check", &battle_config.item_onfloor, 1, 0, 1, },
{ "bowling_bash_area", &battle_config.bowling_bash_area, 0, 0, 20, },
};
#ifndef STATS_OPT_OUT
/**

View File

@ -487,6 +487,7 @@ extern struct Battle_Config
int max_walk_path;
int item_enabled_npc;
int item_onfloor; // Whether to drop an undroppable item on the map or destroy it if inventory is full.
int bowling_bash_area;
} battle_config;
void do_init_battle(void);

View File

@ -59,6 +59,7 @@
#endif
static struct eri *skill_unit_ers = NULL; //For handling skill_unit's [Skotlex]
static struct eri *skill_timer_ers = NULL; //For handling skill_timerskills [Skotlex]
static DBMap* bowling_db = NULL; // int mob_id -> struct mob_data*
DBMap* skillunit_db = NULL; // int id -> struct skill_unit*
@ -1074,7 +1075,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint
break;
case NPC_MENTALBREAKER:
{ //Based on observations by Tharis, Mental Breaker should do SP damage
//equal to Matk*skLevel.
//equal to Matk*skLevel.
rate = sstatus->matk_min;
if (rate < sstatus->matk_max)
rate += rnd()%(sstatus->matk_max - sstatus->matk_min);
@ -1138,7 +1139,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint
break;
default:
sc_start2(src,bl,SC_BLEEDING,(5+skill_lv*5),skill_lv,src->id,skill_get_time2(skill_id,3));
}
}
break;
case HW_NAPALMVULCAN:
@ -3968,30 +3969,75 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
case KN_BOWLINGBASH:
case MS_BOWLINGBASH:
if(flag&1){
if(bl->id==skill_area_temp[1])
break;
//two hits for 500%
skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,SD_ANIMATION);
skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,SD_ANIMATION);
} else {
int i,c;
c = skill_get_blewcount(skill_id,skill_lv);
// keep moving target in the direction that src is looking, square by square
for(i=0;i<c;i++){
if (!skill_blown(src,bl,1,(unit_getdir(src)+4)%8,0x1))
break; //Can't knockback
skill_area_temp[0] = map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY, skill_area_sub_count);
if( skill_area_temp[0] > 1 ) break; // collision
{
int min_x,max_x,min_y,max_y,i,c,dir,tx,ty;
// Chain effect and check range gets reduction by recursive depth, as this can reach 0, we don't use blowcount
c = (skill_lv-(flag&0xFFF)+1)/2;
// Determine the Bowling Bash area depending on configuration
if (battle_config.bowling_bash_area == 0) {
// Gutter line system
min_x = ((src->x)-c) - ((src->x)-c)%40;
if(min_x < 0) min_x = 0;
max_x = min_x + 39;
min_y = ((src->y)-c) - ((src->y)-c)%40;
if(min_y < 0) min_y = 0;
max_y = min_y + 39;
} else if (battle_config.bowling_bash_area == 1) {
// Gutter line system without demi gutter bug
min_x = src->x - (src->x)%40;
max_x = min_x + 39;
min_y = src->y - (src->y)%40;
max_y = min_y + 39;
} else {
// Area around caster
min_x = src->x - battle_config.bowling_bash_area;
max_x = src->x + battle_config.bowling_bash_area;
min_y = src->y - battle_config.bowling_bash_area;
max_y = src->y + battle_config.bowling_bash_area;
}
clif_blown(bl); //Update target pos.
if (i!=c) { //Splash
skill_area_temp[1] = bl->id;
map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill_castend_damage_id);
// Initialization, break checks, direction
if((flag&0xFFF) > 0) {
// Ignore monsters outside area
if(bl->x < min_x || bl->x > max_x || bl->y < min_y || bl->y > max_y)
break;
// Ignore monsters already in list
if(idb_exists(bowling_db, bl->id))
break;
// Random direction
dir = rand()%8;
} else {
// Create an empty list of already hit targets
db_clear(bowling_db);
// Direction is walkpath
dir = (unit_getdir(src)+4)%8;
}
//Weirdo dual-hit property, two attacks for 500%
skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,0);
skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,0);
// Add current target to the list of already hit targets
idb_put(bowling_db, bl->id, bl);
// Keep moving target in direction square by square
tx = bl->x;
ty = bl->y;
for(i=0;i<c;i++) {
// Target coordinates (get changed even if knockback fails)
tx -= dirx[dir];
ty -= diry[dir];
// If target cell is a wall then break
if(map_getcell(bl->m,tx,ty,CELL_CHKWALL))
break;
skill_blown(src,bl,1,dir,0);
// Splash around target cell, but only cells inside area; we first have to check the area is not negative
if((max(min_x,tx-1) <= min(max_x,tx+1)) &&
(max(min_y,ty-1) <= min(max_y,ty+1)) &&
(map_foreachinarea(skill_area_sub, bl->m, max(min_x,tx-1), max(min_y,ty-1), min(max_x,tx+1), min(max_y,ty+1), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY, skill_area_sub_count))) {
// Recursive call
map_foreachinarea(skill_area_sub, bl->m, max(min_x,tx-1), max(min_y,ty-1), min(max_x,tx+1), min(max_y,ty+1), splash_target(src), src, skill_id, skill_lv, tick, (flag|BCT_ENEMY)+1, skill_castend_damage_id);
// Self-collision
if(bl->x >= min_x && bl->x <= max_x && bl->y >= min_y && bl->y <= max_y)
skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,(flag&0xFFF)>0?SD_ANIMATION:0);
break;
}
}
// Original hit or chain hit depending on flag
skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,(flag&0xFFF)>0?SD_ANIMATION:0);
}
break;
@ -18191,6 +18237,7 @@ int do_init_skill (void)
skillunit_db = idb_alloc(DB_OPT_BASE);
skillcd_db = idb_alloc(DB_OPT_RELEASE_DATA);
skillusave_db = idb_alloc(DB_OPT_RELEASE_DATA);
bowling_db = idb_alloc(DB_OPT_BASE);
skill_unit_ers = ers_new(sizeof(struct skill_unit_group),"skill.c::skill_unit_ers",ERS_OPT_NONE);
skill_timer_ers = ers_new(sizeof(struct skill_timerskill),"skill.c::skill_timer_ers",ERS_OPT_NONE);
@ -18212,6 +18259,7 @@ int do_final_skill(void)
db_destroy(skillunit_db);
db_destroy(skillcd_db);
db_destroy(skillusave_db);
db_destroy(bowling_db);
ers_destroy(skill_unit_ers);
ers_destroy(skill_timer_ers);
return 0;