瀏覽代碼

- 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

playtester 12 年之前
父節點
當前提交
a15cee063d
共有 6 個文件被更改,包括 84 次插入27 次删除
  1. 7 0
      conf/battle/skill.conf
  2. 1 1
      db/pre-re/skill_db.txt
  3. 1 1
      db/re/skill_db.txt
  4. 1 0
      src/map/battle.c
  5. 1 0
      src/map/battle.h
  6. 73 25
      src/map/skill.c

+ 7 - 0
conf/battle/skill.conf

@@ -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

+ 1 - 1
db/pre-re/skill_db.txt

@@ -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

+ 1 - 1
db/re/skill_db.txt

@@ -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

+ 1 - 0
src/map/battle.c

@@ -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
 /**

+ 1 - 0
src/map/battle.h

@@ -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);

+ 73 - 25
src/map/skill.c

@@ -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
-			}
-			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);
+		{
+			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;
+			}
+			// 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;
+			}
+			// 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;
+				}
 			}
-			//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);
+			// 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;