Browse Source

Cleaned up Joint Beat behavior (#4123)

* Fixes #4122.
* Added missing rate and duration reduction based on the targets stats.
* Confirmed that double damage only applies to BREAK_NECK.
* Cleaned up skill to remove jb_flag from status_change struct.
Thanks to @mrjnumber1!
Aleos 5 năm trước cách đây
mục cha
commit
cb2c553f34
4 tập tin đã thay đổi với 23 bổ sung35 xóa
  1. 3 5
      src/map/battle.cpp
  2. 6 20
      src/map/skill.cpp
  3. 6 0
      src/map/status.cpp
  4. 8 10
      src/map/status.hpp

+ 3 - 5
src/map/battle.cpp

@@ -3634,11 +3634,9 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			skillratio += 40 * skill_lv;
 			break;
 		case LK_JOINTBEAT:
-			i = 10 * skill_lv - 50;
-			// Although not clear, it's being assumed that the 2x damage is only for the break neck ailment.
-			if (wd->miscflag&BREAK_NECK)
-				i *= 2;
-			skillratio += i;
+			skillratio += -100 + 10 * skill_lv - 50;
+			if (wd->miscflag & BREAK_NECK || (tsc && tsc->data[status_skill2sc(skill_id)]->val2 & BREAK_NECK)) // The 2x damage is only for the BREAK_NECK ailment.
+				skillratio <<= 1;
 			break;
 #ifdef RENEWAL
 		// Renewal: skill ratio applies to entire damage [helvetica]

+ 6 - 20
src/map/skill.cpp

@@ -1511,13 +1511,6 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
 			sc_start2(src,bl, SC_BLEEDING,50, skill_lv, src->id, skill_get_time2(skill_id,skill_lv));
 		break;
 
-	case LK_JOINTBEAT:
-		status = status_skill2sc(skill_id);
-		if (tsc->jb_flag) {
-			sc_start4(src,bl,status,(5*skill_lv+5),skill_lv,tsc->jb_flag&BREAK_FLAGS,src->id,0,skill_get_time2(skill_id,skill_lv));
-			tsc->jb_flag = 0;
-		}
-		break;
 	case ASC_METEORASSAULT:
 		//Any enemies hit by this skill will receive Stun, Darkness, or external bleeding status ailment with a 5%+5*skill_lv% chance.
 		switch(rnd()%3) {
@@ -4778,19 +4771,12 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 		skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag|SD_ANIMATION);
 		break;
 
-	case LK_JOINTBEAT: // decide the ailment first (affects attack damage and effect)
-		switch( rnd()%6 ){
-		case 0: flag |= BREAK_ANKLE; break;
-		case 1: flag |= BREAK_WRIST; break;
-		case 2: flag |= BREAK_KNEE; break;
-		case 3: flag |= BREAK_SHOULDER; break;
-		case 4: flag |= BREAK_WAIST; break;
-		case 5: flag |= BREAK_NECK; break;
-		}
-		//TODO: is there really no cleaner way to do this?
-		sc = status_get_sc(bl);
-		if (sc) sc->jb_flag = flag;
-		skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag);
+	case LK_JOINTBEAT:
+		flag = 1 << rnd() % 6;
+		if (flag != BREAK_NECK && tsc && tsc->data[status_skill2sc(skill_id)]->val2 & BREAK_NECK)
+			flag = BREAK_NECK; // Target should always receive double damage if neck is already broken
+		if (skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag))
+			sc_start4(src, bl, status_skill2sc(skill_id), 50 + (skill_lv + 1), skill_lv, flag&BREAK_FLAGS, src->id, 0, skill_get_time2(skill_id, skill_lv));
 		break;
 
 	case MO_COMBOFINISH:

+ 6 - 0
src/map/status.cpp

@@ -8191,6 +8191,10 @@ t_tick status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_
 				tick /= 5;
 			sc_def = status->agi*50;
 			break;
+		case SC_JOINTBEAT:
+			sc_def2 = 270 * status->str / 100; // 270 * STR / 100
+			tick_def2 = (status->luk * 50 + status->agi * 200) / 2; // (50 * LUK / 100 + 20 * AGI / 100) / 2
+			break;
 		case SC_DEEPSLEEP:
 			tick_def2 = status_get_base_status(bl)->int_ * 25 + status_get_lv(bl) * 50;
 			break;
@@ -9527,6 +9531,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 					return 0;
 				break;
 			case SC_JOINTBEAT:
+				if (sc && sc->data[type]->val2 & BREAK_NECK)
+					return 0; // BREAK_NECK cannot be stacked with new breaks until the status is over.
 				val2 |= sce->val2; // Stackable ailments
 			default:
 				if(sce->val1 > val1)

+ 8 - 10
src/map/status.hpp

@@ -1956,15 +1956,14 @@ enum efst_types : short{
 };
 
 /// JOINTBEAT stackable ailments
-enum e_joint_break
-{
-	BREAK_ANKLE	= 0x01, ///< MoveSpeed reduced by 50%
-	BREAK_WRIST	= 0x02, ///< ASPD reduced by 25%
-	BREAK_KNEE	= 0x04, ///< MoveSpeed reduced by 30%, ASPD reduced by 10%
-	BREAK_SHOULDER	= 0x08, ///< DEF reduced by 50%
-	BREAK_WAIST	= 0x10, ///< DEF reduced by 25%, ATK reduced by 25%
-	BREAK_NECK	= 0x20, ///< current attack does 2x damage, inflicts 'bleeding' for 30 seconds
-	BREAK_FLAGS	= BREAK_ANKLE | BREAK_WRIST | BREAK_KNEE | BREAK_SHOULDER | BREAK_WAIST | BREAK_NECK,
+enum e_joint_break : uint8 {
+	BREAK_ANKLE = 0x01,		///< MoveSpeed reduced by 50%
+	BREAK_WRIST = 0x02,		///< ASPD reduced by 25%
+	BREAK_KNEE = 0x04,		///< MoveSpeed reduced by 30%, ASPD reduced by 10%
+	BREAK_SHOULDER = 0x08,	///< DEF reduced by 50%
+	BREAK_WAIST = 0x10,		///< DEF reduced by 25%, ATK reduced by 25%
+	BREAK_NECK = 0x20,		///< Current attack does 2x damage, inflicts 'bleeding' for 30 seconds
+	BREAK_FLAGS = BREAK_ANKLE | BREAK_WRIST | BREAK_KNEE | BREAK_SHOULDER | BREAK_WAIST | BREAK_NECK,
 };
 
 extern short current_equip_item_index;
@@ -2330,7 +2329,6 @@ struct status_change {
 	unsigned short opt2;// health state (bitfield)
 	unsigned char count;
 	//! TODO: See if it is possible to implement the following SC's without requiring extra parameters while the SC is inactive.
-	unsigned char jb_flag; //Joint Beat type flag
 	struct {
 		unsigned char move;
 		unsigned char pickup;