ソースを参照

Fixed Vanilmirth skills + NPC_SELFDESTRUCTION (#8650)

Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
Daegaladh 8 ヶ月 前
コミット
dc64916ec4
7 ファイル変更95 行追加87 行削除
  1. 7 18
      db/pre-re/skill_db.yml
  2. 7 19
      db/re/skill_db.yml
  3. 11 8
      src/map/clif.cpp
  4. 1 1
      src/map/clif_packetdb.hpp
  5. 7 0
      src/map/packets.hpp
  6. 58 39
      src/map/skill.cpp
  7. 4 2
      src/map/status.cpp

+ 7 - 18
db/pre-re/skill_db.yml

@@ -31026,19 +31026,7 @@ Body:
     MaxLevel: 5
     Type: Magic
     TargetType: Attack
-    Range: 15
-    Hit: Single
-    HitCount:
-      - Level: 1
-        Count: 1
-      - Level: 2
-        Count: 2
-      - Level: 3
-        Count: 3
-      - Level: 4
-        Count: 4
-      - Level: 5
-        Count: 5
+    Range: 9
     Requires:
       SpCost:
         - Level: 1
@@ -31055,10 +31043,10 @@ Body:
     Name: HVAN_CHAOTIC
     Description: Benediction of Chaos
     MaxLevel: 5
+    Type: Magic
     TargetType: Self
     DamageFlags:
       NoDamage: true
-    Hit: Single
     AfterCastWalkDelay: 1500
     Requires:
       SpCost: 40
@@ -31066,8 +31054,6 @@ Body:
     Name: HVAN_INSTRUCT
     Description: Instruct
     MaxLevel: 5
-    DamageFlags:
-      NoDamage: true
   - Id: 8016
     Name: HVAN_EXPLOSION
     Description: Bio Explosion
@@ -31079,10 +31065,13 @@ Body:
       IgnoreElement: true
       IgnoreFlee: true
       IgnoreDefCard: true
+    Flags:
+      TargetTrap: true
     Hit: Single
     HitCount: 1
-    Element: Weapon
-    SplashArea: 4
+    Element: Neutral
+    SplashArea: 5
+    Duration1: 1500
     Requires:
       SpCost: 1
   - Id: 8018

+ 7 - 19
db/re/skill_db.yml

@@ -43312,19 +43312,7 @@ Body:
     MaxLevel: 5
     Type: Magic
     TargetType: Attack
-    Range: 15
-    Hit: Single
-    HitCount:
-      - Level: 1
-        Count: 1
-      - Level: 2
-        Count: 2
-      - Level: 3
-        Count: 3
-      - Level: 4
-        Count: 4
-      - Level: 5
-        Count: 5
+    Range: 9
     Cooldown:
       - Level: 1
         Time: 2000
@@ -43352,10 +43340,10 @@ Body:
     Name: HVAN_CHAOTIC
     Description: Benediction of Chaos
     MaxLevel: 5
+    Type: Magic
     TargetType: Self
     DamageFlags:
       NoDamage: true
-    Hit: Single
     AfterCastWalkDelay: 1500
     Cooldown: 3000
     Requires:
@@ -43364,8 +43352,6 @@ Body:
     Name: HVAN_INSTRUCT
     Description: Instruct
     MaxLevel: 5
-    DamageFlags:
-      NoDamage: true
   - Id: 8016
     Name: HVAN_EXPLOSION
     Description: Bio Explosion
@@ -43377,11 +43363,13 @@ Body:
       IgnoreElement: true
       IgnoreFlee: true
       IgnoreDefCard: true
+    Flags:
+      TargetTrap: true
     Hit: Single
     HitCount: 1
-    Element: Weapon
-    SplashArea: 4
-    AfterCastActDelay: 5000
+    Element: Neutral
+    SplashArea: 5
+    Duration1: 1500
     CoolDown: 1000
     Requires:
       SpCost: 1

+ 11 - 8
src/map/clif.cpp

@@ -15460,24 +15460,28 @@ void clif_parse_HomMoveToMaster(int fd, map_session_data *sd){
 }
 
 
-/// Request to move homunculus/mercenary (CZ_REQUEST_MOVENPC).
-/// 0232 <id>.L <position data>.3B
+/// Request to move homunculus/mercenary.
+/// 0232 <id>.L <position data>.3B (CZ_REQUEST_MOVENPC)
 void clif_parse_HomMoveTo(int fd, map_session_data *sd){
-	struct s_packet_db* info = &packet_db[RFIFOW(fd,0)];
-	int id = RFIFOL(fd,info->pos[0]); // Mercenary or Homunculus
+#if PACKETVER >= 20050425
+	const PACKET_CZ_REQUEST_MOVENPC* p = reinterpret_cast<const PACKET_CZ_REQUEST_MOVENPC*>( RFIFOP( fd, 0 ) );
 	struct block_list *bl = nullptr;
 	short x, y;
 
-	RFIFOPOS(fd, info->pos[1], &x, &y, nullptr);
+	RBUFPOS( p->PosDir, 0, &x, &y, nullptr );
 
-	if( sd->md && sd->md->bl.id == id )
+	if( sd->md && sd->md->bl.id == p->GID )
 		bl = &sd->md->bl; // Moving Mercenary
-	else if( hom_is_active(sd->hd) && sd->hd->bl.id == id )
+	else if( hom_is_active(sd->hd) && sd->hd->bl.id == p->GID )
 		bl = &sd->hd->bl; // Moving Homunculus
 	else
 		return;
 
+	if (x < 0 || y < 0 || (x == bl->x && y == bl->y))
+		return;
+
 	unit_walktoxy(bl, x, y, 4);
+#endif
 }
 
 
@@ -15499,7 +15503,6 @@ void clif_parse_HomAttack(int fd,map_session_data *sd)
 		bl = &sd->md->bl;
 	else return;
 
-	unit_stop_attack(bl);
 	unit_attack(bl, target_id, action_type != 0);
 }
 

+ 1 - 1
src/map/clif_packetdb.hpp

@@ -563,7 +563,7 @@
 // 2005-04-25aSakexe
 #if PACKETVER >= 20050425
 	parseable_packet(0x022d,5,clif_parse_HomMenu,2,4);
-	parseable_packet(0x0232,9,clif_parse_HomMoveTo,2,6);
+	parseable_packet( HEADER_CZ_REQUEST_MOVENPC, sizeof( PACKET_CZ_REQUEST_MOVENPC ), clif_parse_HomMoveTo, 0 );
 	parseable_packet(0x0233,11,clif_parse_HomAttack,2,6,10);
 	parseable_packet(0x0234,6,clif_parse_HomMoveToMaster,2);
 #endif

+ 7 - 0
src/map/packets.hpp

@@ -1362,6 +1362,13 @@ struct PACKET_ZC_NOTIFY_ACT{
 DEFINE_PACKET_HEADER(ZC_NOTIFY_ACT, 0x8a);
 #endif
 
+struct PACKET_CZ_REQUEST_MOVENPC{
+	int16 packetType;
+	uint32 GID;
+	uint8 PosDir[3];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_REQUEST_MOVENPC, 0x232);
+
 // 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 )

+ 58 - 39
src/map/skill.cpp

@@ -3812,12 +3812,12 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
 			dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, CR_HOLYCROSS, -1, DMG_SPLASH);
 			break;
 		//Skills that need be passed as a normal attack for the client to display correctly.
-		case HVAN_EXPLOSION:
 		case NPC_SELFDESTRUCTION:
 			if(src->type == BL_PC)
 				dmg.blewcount = 10;
 			dmg.amotion = 0; //Disable delay or attack will do no damage since source is dead by the time it takes effect. [Skotlex]
 			[[fallthrough]];
+		case HVAN_EXPLOSION:
 		case KN_AUTOCOUNTER:
 		case NPC_CRITICALSLASH:
 		case TF_DOUBLE:
@@ -4762,6 +4762,9 @@ static TIMER_FUNC(skill_timerskill){
 				case ABC_FRENZY_SHOT:
 					skill_castend_damage_id(src, target, skl->skill_id, skl->skill_lv, tick, skl->flag);
 					break;
+				case HVAN_EXPLOSION:
+					status_kill(src);
+					break;
 				default:
 					skill_attack(skl->type,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag);
 					break;
@@ -6193,18 +6196,11 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 		sc_start(src,src,SC_MAGICALATTACK,100,skill_lv,skill_get_time(skill_id,skill_lv));
 		break;
 
-	case HVAN_CAPRICE: //[blackhole89]
+	case HVAN_CAPRICE:
 		{
-			int ran=rnd()%4;
-			int sid = 0;
-			switch(ran)
-			{
-			case 0: sid=MG_COLDBOLT; break;
-			case 1: sid=MG_FIREBOLT; break;
-			case 2: sid=MG_LIGHTNINGBOLT; break;
-			case 3: sid=WZ_EARTHSPIKE; break;
-			}
-			skill_attack(BF_MAGIC,src,src,bl,sid,skill_lv,tick,flag|SD_LEVEL);
+			static const std::array<e_skill, 4> subskills = { MG_COLDBOLT, MG_FIREBOLT, MG_LIGHTNINGBOLT, WZ_EARTHSPIKE };
+			e_skill subskill_id = subskills.at(rnd() % subskills.size());
+			skill_attack(skill_get_type(subskill_id), src, src, bl, subskill_id, skill_lv, tick, flag);
 		}
 		break;
 
@@ -6324,7 +6320,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 		[[fallthrough]];
 	case HVAN_EXPLOSION:
 		if (src != bl)
-			skill_attack(BF_MISC,src,src,bl,skill_id,skill_lv,tick,flag);
+			skill_attack(skill_get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag);
 		break;
 
 	// Celest
@@ -8817,13 +8813,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			BF_MAGIC, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY);
 		break;
 
-	case HVAN_EXPLOSION:	//[orn]
 	case NPC_SELFDESTRUCTION:
 		//Self Destruction hits everyone in range (allies+enemies)
 		//Except for Summoned Marine spheres on non-versus maps, where it's just enemy.
 		i = ((!md || md->special_state.ai == AI_SPHERE) && !map_flag_vs(src->m))?
 			BCT_ENEMY:BCT_ALL;
-		clif_skill_nodamage(src, *src, skill_id, -1);
 		map_delblock(src); //Required to prevent chain-self-destructions hitting back.
 		map_foreachinshootrange(skill_area_sub, bl,
 			skill_get_splash(skill_id, skill_lv), BL_CHAR|BL_SKILL,
@@ -8833,14 +8827,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			map_freeblock_unlock();
 			return 1;
 		}
-		status_damage(src, src, sstatus->max_hp,0,0,1, skill_id);
-		if(skill_id == HVAN_EXPLOSION && src->type == BL_HOM) {
-			homun_data& hd = reinterpret_cast<homun_data&>( *src );
-
-			hd.homunculus.intimacy = hom_intimacy_grade2intimacy(HOMGRADE_HATE_WITH_PASSION);
-
-			clif_send_homdata( hd, SP_INTIMATE );
-		}
+		status_kill(src);
 		break;
 	case AL_ANGELUS:
 #ifdef RENEWAL
@@ -10703,26 +10690,58 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 		else if (sd != nullptr)
 			clif_skill_fail( *sd, skill_id );
 		break;
-	case HVAN_CHAOTIC:	//[orn]
+	case HVAN_CHAOTIC:
 		{
-			static const int per[5][2]={{20,50},{50,60},{25,75},{60,64},{34,67}};
-			int r = rnd()%100;
-			i = (skill_lv-1)%5;
-			if(r<per[i][0]) //Self
+			// Chance per skill level
+			static const std::array<uint8, 5> chance_homunculus = {
+				20,
+				50,
+				25,
+				50,
+				34
+			};
+			static const std::array<uint8, 5> chance_master = {
+				static_cast<uint8>(chance_homunculus[0] + 30),
+				static_cast<uint8>(chance_homunculus[1] + 10),
+				static_cast<uint8>(chance_homunculus[2] + 50),
+				static_cast<uint8>(chance_homunculus[3] + 4),
+				static_cast<uint8>(chance_homunculus[4] + 33)
+			};
+
+			uint8 chance = rnd_value(1, 100);
+
+			// Homunculus
+			if (chance <= chance_homunculus[skill_lv - 1])
 				bl = src;
-			else if(r<per[i][1]) //Master
+			// Master
+			else if (chance <= chance_master[skill_lv - 1])
 				bl = battle_get_master(src);
-			else //Enemy
-				bl = map_id2bl(battle_gettarget(src));
+			// Enemy (A random enemy targeting the master)
+			else
+				bl = battle_gettargeted(battle_get_master(src));
 
-			if (!bl) bl = src;
-			i = skill_calc_heal(src, bl, skill_id, 1+rnd()%skill_lv, true);
-			//Eh? why double skill packet?
-			clif_skill_nodamage(src,*bl,AL_HEAL,i);
-			clif_skill_nodamage(src,*bl,skill_id,i);
-			status_heal(bl, i, 0, 0);
-		}
-		break;
+			// If there's no enemy the chance reverts to the homunculus
+			if (bl == nullptr)
+				bl = src;
+
+			int32 heal = skill_calc_heal(src, bl, skill_id, rnd_value<uint16>(1, skill_lv), true);
+
+			// Official servers send the Heal skill packet with the healed amount, and then the skill packet with 1 as healed amount
+			clif_skill_nodamage(src, *bl, AL_HEAL, heal);
+			clif_skill_nodamage(src, *bl, skill_id, 1);
+			status_heal(bl, heal, 0, 0);
+		} break;
+	case HVAN_EXPLOSION:
+		if( hd != nullptr ){
+			clif_skill_nodamage(src, *src, skill_id, skill_lv, 1);
+			map_foreachinshootrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR | BL_SKILL, src, skill_id, skill_lv, tick, flag | BCT_ENEMY, skill_castend_damage_id);
+
+			hd->homunculus.intimacy = hom_intimacy_grade2intimacy(HOMGRADE_HATE_WITH_PASSION);
+			clif_send_homdata(*hd, SP_INTIMATE);
+
+			// There's a delay between the explosion and the homunculus death
+			skill_addtimerskill(src, tick + skill_get_time(skill_id, skill_lv), src->id, 0, 0, skill_id, skill_lv, 0, flag);
+		} break;
 	// Homun single-target support skills [orn]
 	case HLIF_CHANGE:
 #ifndef RENEWAL

+ 4 - 2
src/map/status.cpp

@@ -5067,8 +5067,10 @@ int status_calc_homunculus_(struct homun_data *hd, uint8 opt)
 		status->def += skill_lv * 4;
 
 	if((skill_lv = hom_checkskill(hd, HVAN_INSTRUCT)) > 0) {
-		status->int_ += 1 + skill_lv / 2 + skill_lv / 4 + skill_lv / 5;
-		status->str += 1 + skill_lv / 3 + skill_lv / 3 + skill_lv / 4;
+		static const uint8 bonus_int[] = { 1, 2, 2, 4, 5 };
+		static const uint8 bonus_str[] = { 1, 1, 3, 4, 4 };
+		status->int_ += bonus_int[skill_lv - 1];
+		status->str += bonus_str[skill_lv - 1];
 	}
 
 	if((skill_lv = hom_checkskill(hd, HAMI_SKIN)) > 0)