Sfoglia il codice sorgente

Adjusts Enchanting Shadow behavior (#7124)

* Fixes #7104.
* Implements Shadow Scar as a timer on units.
* Implements the official packet for Shadow Scar counter.
* Enchanting Shadow can now be triggered by skills as well as melee.
* Removes the hit count limit.
* Adjusts the damage rate of Shadow Wounds to increase by 3%.
* Adjusts the duration of Shadow Scar from 30 seconds to 15.
Thanks to @eppc0330 and @Lemongrass3110!
Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
Aleos 2 anni fa
parent
commit
4a43856271
9 ha cambiato i file con 107 aggiunte e 18 eliminazioni
  1. 1 1
      db/re/skill_db.yml
  2. 2 2
      src/map/battle.cpp
  3. 16 0
      src/map/clif.cpp
  4. 3 0
      src/map/clif.hpp
  5. 8 0
      src/map/packets.hpp
  6. 10 12
      src/map/skill.cpp
  7. 0 3
      src/map/status.cpp
  8. 62 0
      src/map/unit.cpp
  9. 5 0
      src/map/unit.hpp

+ 1 - 1
db/re/skill_db.yml

@@ -37451,7 +37451,7 @@ Body:
     CastCancel: true
     AfterCastActDelay: 500
     Duration1: 180000
-    Duration2: 30000
+    Duration2: 15000
     Cooldown: 150000
     FixedCastTime: 2000
     Requires:

+ 2 - 2
src/map/battle.cpp

@@ -1553,8 +1553,8 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 		}
 		if (sc->data[SC_HOLY_OIL] && (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
 			damage += damage * 50 / 100;// Need official adjustment. [Rytech]
-		if (sc->data[SC_SHADOW_SCAR])// Need official adjustment for this too.
-			damage += damage * (10 * sc->data[SC_SHADOW_SCAR]->val1) / 100;
+		if (sc->data[SC_SHADOW_SCAR]) // !TODO: Need official adjustment for this too.
+			damage += damage * (3 * sc->data[SC_SHADOW_SCAR]->val1) / 100;
 
 		// Damage reductions
 		// Assumptio increases DEF on RE mode, otherwise gives a reduction on the final damage. [Igniz]

+ 16 - 0
src/map/clif.cpp

@@ -1580,6 +1580,22 @@ static void clif_spiritcharm_single(int fd, struct map_session_data *sd)
 	WFIFOSET(fd, packet_len(0x08cf));
 }
 
+/*==========================================
+ * Enchanting Shadow / Shadow Scar Spirit
+ *------------------------------------------*/
+void clif_enchantingshadow_spirit(unit_data &ud) {
+#if PACKETVER_MAIN_NUM >= 20191120 || PACKETVER_RE_NUM >= 20191120 || PACKETVER_ZERO_NUM >= 20191127
+	PACKET_ZC_TARGET_SPIRITS p = {};
+
+	p.packetType = HEADER_ZC_TARGET_SPIRITS;
+	p.GID = ud.bl->id;
+	p.unknown_val = 0;
+	p.amount = static_cast<uint16>(ud.shadow_scar_timer.size());
+
+	clif_send(&p, sizeof(p), ud.bl, AREA);
+#endif
+}
+
 /*==========================================
  * Run when player changes map / refreshes
  * Tells its client to display all weather settings being used by this map

+ 3 - 0
src/map/clif.hpp

@@ -1214,4 +1214,7 @@ void clif_item_reform_open( struct map_session_data& sd, t_itemid item );
 // Item Enchant UI
 void clif_enchantwindow_open( struct map_session_data& sd, uint64 clientLuaIndex );
 
+// Enchanting Shadow / Shadow Scar Spirit
+void clif_enchantingshadow_spirit(unit_data &ud);
+
 #endif /* CLIF_HPP */

+ 8 - 0
src/map/packets.hpp

@@ -321,6 +321,13 @@ struct PACKET_CZ_CLOSE_UI_ENCHANT{
 	int16 packetType;
 } __attribute__((packed));
 
+struct PACKET_ZC_TARGET_SPIRITS {
+	int16 packetType;
+	uint32 GID;
+	uint32 unknown_val;
+	uint16 amount;
+} __attribute__((packed));
+
 // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
 #if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 )
 	#pragma pack( pop )
@@ -371,6 +378,7 @@ DEFINE_PACKET_HEADER(CZ_REQ_STYLE_CHANGE2, 0xafc)
 DEFINE_PACKET_HEADER(ZC_REMOVE_EFFECT, 0x0b0d)
 DEFINE_PACKET_HEADER(CZ_UNCONFIRMED_TSTATUS_UP, 0x0b24)
 DEFINE_PACKET_HEADER(CZ_GUILD_EMBLEM_CHANGE2, 0x0b46)
+DEFINE_PACKET_HEADER(ZC_TARGET_SPIRITS, 0xb68)
 DEFINE_PACKET_HEADER(ZC_UNCONFIRMED_SPIRITS3, 0xb73)
 DEFINE_PACKET_HEADER(CZ_UNCONFIRMED_RODEX_RETURN, 0xb98)
 DEFINE_PACKET_HEADER(ZC_SUMMON_HP_INIT, 0xb6b)

+ 10 - 12
src/map/skill.cpp

@@ -1303,6 +1303,16 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
 			}
 		}
 
+		// Enchanting Shadow gives a chance to inflict Shadow Wounds to the enemy.
+		if (sc != nullptr) {
+			status_change_entry *sce = sc->data[SC_SHADOW_WEAPON];
+			unit_data *ud = unit_bl2ud(bl);
+
+			if (sce != nullptr && ud != nullptr && rnd_chance(sce->val1, 100)) {
+				unit_addshadowscar(*ud, skill_get_time2(SHC_ENCHANTING_SHADOW, sce->val1));
+			}
+		}
+
 		if( skill_id ) {
 			// Trigger status effects on skills
 			for (const auto &it : sd->addeff_onskill) {
@@ -1385,18 +1395,6 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
 					if((sce=sc->data[SC_EDP]))
 						sc_start4(src,bl,SC_DPOISON,sce->val2, sce->val1,src->id,0,0,
 							skill_get_time2(ASC_EDP,sce->val1));
-					// Enchanting Shadow gives a chance to inflict shadow wounds to the enemy.
-					if ((sce = sc->data[SC_SHADOW_WEAPON]) && rnd() % 100 < sce->val2) {
-						if (tsc && tsc->data[SC_SHADOW_SCAR]) {
-							uint16 count = 1 + tsc->data[SC_SHADOW_SCAR]->val1;
-
-							// Need official stack limit. [Rytech]
-							count = min(5, count);
-
-							sc_start(src, bl, SC_SHADOW_SCAR, 100, count, skill_get_time2(SHC_ENCHANTING_SHADOW, sce->val1));
-						} else
-							sc_start(src, bl, SC_SHADOW_SCAR, 100, 1, skill_get_time2(SHC_ENCHANTING_SHADOW, sce->val1));
-					}
 					if ((sce = sc->data[SC_LUXANIMA]) && rnd() % 100 < sce->val2)
 						skill_castend_nodamage_id(src, bl, RK_STORMBLAST, 1, tick, 0);
 				}

+ 0 - 3
src/map/status.cpp

@@ -12231,9 +12231,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_POTENT_VENOM:
 			val2 = 3 * val1;// Res Pierce Percentage
 			break;
-		case SC_SHADOW_WEAPON:
-			val2 = val1;// Success Chance of Shadow Scar
-			break;
 		case SC_A_MACHINE:
 			val4 = tick / 1000;
 			tick_time = 1000;

+ 62 - 0
src/map/unit.cpp

@@ -14,6 +14,7 @@
 #include "../common/showmsg.hpp"
 #include "../common/socket.hpp"
 #include "../common/timer.hpp"
+#include "../common/utils.hpp"
 
 #include "achievement.hpp"
 #include "battle.hpp"
@@ -37,6 +38,12 @@
 #include "storage.hpp"
 #include "trade.hpp"
 
+using namespace rathena;
+
+#ifndef MAX_SHADOW_SCAR 
+	#define MAX_SHADOW_SCAR 100 /// Max Shadow Scars
+#endif
+
 // Directions values
 // 1 0 7
 // 2 . 6
@@ -3626,6 +3633,60 @@ int unit_free(struct block_list *bl, clr_type clrtype)
 	return 0;
 }
 
+static TIMER_FUNC(unit_shadowscar_timer) {
+	block_list *bl = map_id2bl(id);
+
+	if (bl == nullptr)
+		return 1;
+
+	unit_data *ud = unit_bl2ud(bl);
+
+	if (ud == nullptr)
+		return 1;
+
+	std::vector<int>::iterator it = ud->shadow_scar_timer.begin();
+
+	while (it != ud->shadow_scar_timer.end()) {
+		if (*it == tid) {
+			ud->shadow_scar_timer.erase(it);
+			break;
+		}
+
+		it++;
+	}
+
+	if (ud->shadow_scar_timer.empty())
+		status_change_end(bl, SC_SHADOW_SCAR, INVALID_TIMER);
+
+	return 0;
+}
+
+/**
+ * Adds a Shadow Scar to unit for 'interval' ms.
+ * @param ud: Unit data
+ * @param interval: Duration
+ */
+void unit_addshadowscar(unit_data &ud, int interval) {
+	if (ud.shadow_scar_timer.size() >= MAX_SHADOW_SCAR) {
+		ShowWarning("unit_addshadowscar: Unit %s (%d) has reached the maximum amount of Shadow Scars (%d).\n", status_get_name(ud.bl), ud.bl->id, MAX_SHADOW_SCAR);
+		return;
+	}
+
+	ud.shadow_scar_timer.push_back(add_timer(gettick() + interval, unit_shadowscar_timer, ud.bl->id, 0));
+
+	status_change *sc = status_get_sc(ud.bl);
+
+	if (sc != nullptr) {
+		if (sc->data[SC_SHADOW_SCAR] != nullptr) {
+			sc->data[SC_SHADOW_SCAR]->val1 = static_cast<int>(ud.shadow_scar_timer.size());
+		} else {
+			sc_start(ud.bl, ud.bl, SC_SHADOW_SCAR, 100, 1, INFINITE_TICK);
+		}
+
+		clif_enchantingshadow_spirit(ud);
+	}
+}
+
 /**
  * Initialization function for unit on map start
  * called in map::do_init
@@ -3638,6 +3699,7 @@ void do_init_unit(void){
 	add_timer_func_list(unit_delay_walktobl_timer,"unit_delay_walktobl_timer");
 	add_timer_func_list(unit_teleport_timer,"unit_teleport_timer");
 	add_timer_func_list(unit_step_timer,"unit_step_timer");
+	add_timer_func_list(unit_shadowscar_timer, "unit_shadowscar_timer");
 }
 
 /**

+ 5 - 0
src/map/unit.hpp

@@ -63,6 +63,8 @@ struct unit_data {
 	char walk_done_event[EVENT_NAME_LENGTH];
 	char title[NAME_LENGTH];
 	int32 group_id;
+
+	std::vector<int> shadow_scar_timer;
 };
 
 struct view_data {
@@ -172,6 +174,9 @@ int unit_free(struct block_list *bl, clr_type clrtype);
 int unit_changeviewsize(struct block_list *bl,short size);
 int unit_changetarget(struct block_list *bl,va_list ap);
 
+// Shadow Scar
+void unit_addshadowscar(unit_data &ud, int interval);
+
 void do_init_unit(void);
 void do_final_unit(void);