Преглед на файлове

Fixes to Devotion (see topic:153345)
- removed totally fake Devotion packet from Marionette Control code (see r3934)
- fixed one devoted chars array management code bug which caused chars to be included in the array multiple times, producing various problems (also see r3934)
- the link will now re-display when coming into view range
- the link will no longer break if the devotee walks away, but instead, if he receives damage while being out of range of Devotion

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@12171 54d463be-8e91-2dee-dedb-b68131a5f0ec

ultramage преди 17 години
родител
ревизия
2ef6778696
променени са 6 файла, в които са добавени 58 реда и са изтрити 65 реда
  1. 7 0
      Changelog-Trunk.txt
  2. 26 40
      src/map/clif.c
  3. 1 2
      src/map/clif.h
  4. 1 1
      src/map/map.h
  5. 15 9
      src/map/skill.c
  6. 8 13
      src/map/status.c

+ 7 - 0
Changelog-Trunk.txt

@@ -4,6 +4,13 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 2008/02/03
+	* Fixes to Devotion (see topic:153345) [ultramage]
+	- removed totally fake Devotion packet from Marionette Control code
+	- fixed one devoted chars array management code bug which caused chars
+	  to be included in the array multiple times, producing various problems
+	- the link will now re-display when coming into view range
+	- the link will no longer break if the devotee walks away, but instead,
+	  if he receives damage while being out of range of Devotion
 	* Added an iterator to map.h/c. [FlavioJS]
 	  Will be used instead of map_getallusers, which has problems with 
 	  dangling pointers (returned array isn't updated).

+ 26 - 40
src/map/clif.c

@@ -3384,7 +3384,9 @@ int clif_storageclose(struct map_session_data *sd)
  *------------------------------------------*/
 static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* dstsd)
 {
-	int len;
+	int gmlvl;
+	int i;
+
 	if(dstsd->chatID)
 	{
 		struct chat_data *cd;
@@ -3400,10 +3402,17 @@ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_d
 		clif_spiritball_single(sd->fd, dstsd);
 
 	if((sd->status.party_id && dstsd->status.party_id == sd->status.party_id) || //Party-mate, or hpdisp setting.
-		(battle_config.disp_hpmeter && (len = pc_isGM(sd)) >= battle_config.disp_hpmeter && len >= pc_isGM(dstsd))
+		(battle_config.disp_hpmeter && (gmlvl = pc_isGM(sd)) >= battle_config.disp_hpmeter && gmlvl >= pc_isGM(dstsd))
 		)
 		clif_hpmeter_single(sd->fd, dstsd->bl.id, dstsd->battle_status.hp, dstsd->battle_status.max_hp);
 
+	// display links to devoted chars for crusader
+	ARR_FIND( 0, 5, i, sd->devotion[i] == dstsd->bl.id );
+	if( i < 5 ) clif_devotion(sd, sd);
+	// display links to devoted chars for others
+	ARR_FIND( 0, 5, i, dstsd->devotion[i] > 0 );
+	if( i < 5 ) clif_devotion(dstsd, sd);
+
 	// pvp circle for duel [LuzZza]
 	//if(dstsd->duel_group)
 	//	clif_specialeffect(&dstsd->bl, 159, 4);
@@ -5283,7 +5292,7 @@ void clif_vendingreport(struct map_session_data* sd, int index, int amount)
 }
 
 /// Result of organizing a party.
-/// S 00FA <result>.B
+/// R 00FA <result>.B
 ///
 /// result=0 : opens party window and shows MsgStringTable[77]="party successfully organized"
 /// result=1 : MsgStringTable[78]="party name already exists"
@@ -5888,49 +5897,26 @@ int clif_autospell(struct map_session_data *sd,int skilllv)
 }
 
 /*==========================================
- * ディボーションの青い糸
+ * Devotion's visual effect
+ * S 01cf <devoter id>.L { <devotee id>.L }[5] <max distance>.W
  *------------------------------------------*/
-int clif_devotion(struct map_session_data *sd)
+void clif_devotion(struct map_session_data *sd, struct map_session_data *tsd)
 {
 	unsigned char buf[56];
-	int i,n;
-
-	nullpo_retr(0, sd);
-
-	WBUFW(buf,0)=0x1cf;
-	WBUFL(buf,2)=sd->bl.id;
-	for(i=0,n=0;i<5;i++) {
-		if (!sd->devotion[i])
-			continue;
-		WBUFL(buf,6+4*n)=sd->devotion[i];
-		n++;
-	}
-	for(;n<5;n++)
-		WBUFL(buf,6+4*n)=0;
-		
-	WBUFB(buf,26)=8;
-	WBUFB(buf,27)=0;
-
-	clif_send(buf,packet_len(0x1cf),&sd->bl,AREA);
-	return 0;
-}
+	int i;
 
-int clif_marionette(struct block_list *src, struct block_list *target)
-{
-	unsigned char buf[56];
-	int n;
+	nullpo_retv(sd);
 
-	WBUFW(buf,0)=0x1cf;
-	WBUFL(buf,2)=src->id;
-	for(n=0;n<5;n++)
-		WBUFL(buf,6+4*n)=0;
-	if (target) //The target goes on the second slot.
-		WBUFL(buf,6+4) = target->id;
-	WBUFB(buf,26)=8;
-	WBUFB(buf,27)=0;
+	WBUFW(buf,0) = 0x1cf;
+	WBUFL(buf,2) = sd->bl.id;
+	for( i = 0; i < 5; i++ )
+		WBUFL(buf,6+4*i) = sd->devotion[i];
+	WBUFW(buf,26) = skill_get_range2(&sd->bl,CR_DEVOTION,pc_checkskill(sd,CR_DEVOTION)); // ignored
 
-	clif_send(buf,packet_len(0x1cf),src,AREA);
-	return 0;
+	if( tsd )
+		clif_send(buf,packet_len(0x1cf),&tsd->bl,SELF);
+	else
+		clif_send(buf,packet_len(0x1cf),&sd->bl,AREA);
 }
 
 /*==========================================

+ 1 - 2
src/map/clif.h

@@ -225,8 +225,7 @@ void clif_skill_delunit(struct skill_unit *unit);
 void clif_01ac(struct block_list* bl);
 
 int clif_autospell(struct map_session_data *sd,int skilllv);
-int clif_devotion(struct map_session_data *sd);
-int clif_marionette(struct block_list *src, struct block_list *target);
+void clif_devotion(struct map_session_data *sd, struct map_session_data *tsd);
 int clif_spiritball(struct map_session_data *sd);
 int clif_combo_delay(struct block_list *src,int wait);
 int clif_bladestop(struct block_list *src,struct block_list *dst,int bool_);

+ 1 - 1
src/map/map.h

@@ -728,7 +728,7 @@ struct map_session_data {
 	unsigned char mission_count; //Stores the bounty kill count for TK_MISSION
 	short mission_mobid; //Stores the target mob_id for TK_MISSION
 	int die_counter; //Total number of times you've died
-	int devotion[5]; //Stores the char IDs of chars devoted to.
+	int devotion[5]; //Stores the account IDs of chars devoted to.
 	int reg_num; //Number of registries (type numeric)
 	int regstr_num; //Number of registries (type string)
 

+ 15 - 9
src/map/skill.c

@@ -3152,7 +3152,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 				if (!sc->data[type] && !tsc->data[type2]) {
 					sc_start(src,type,100,bl->id,skill_get_time(skillid,skilllv));
 					sc_start(bl,type2,100,src->id,skill_get_time(skillid,skilllv));
-					clif_marionette(src, bl);
 					clif_skill_nodamage(src,bl,skillid,skilllv,1);
 				}
 				else if (sc->data[type] && tsc->data[type2] &&
@@ -3444,6 +3443,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 	case CR_DEVOTION:
 		if(sd && dstsd)
 		{
+			int count = min(skilllv, 5);
 			int lv = sd->status.base_level - dstsd->status.base_level;
 			if (lv < 0) lv = -lv;
 			if (lv > battle_config.devotion_level_difference ||
@@ -3453,18 +3453,24 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 				map_freeblock_unlock();
 				return 1;
 			}
-			//Look for an empty slot (or reuse in case you cast it twice in the same char. [Skotlex]
-			for (i = 0; i < skilllv && i < 5 && sd->devotion[i]!=bl->id && sd->devotion[i]; i++);
-			if (i == skilllv)
-			{
-				clif_skill_fail(sd,skillid,0,0);
-				map_freeblock_unlock();
-				return 1;
+
+			// check if the char isn't devoted already
+			ARR_FIND( 0, count, i, sd->devotion[i] == bl->id );
+			if( i == count )
+			{// not there, find first empty slot
+				ARR_FIND( 0, count, i, sd->devotion[i] == 0 );
+				if( i == count )
+				{// all slots full, fail
+					clif_skill_fail(sd,skillid,0,0);
+					map_freeblock_unlock();
+					return 1;
+				}
 			}
+
 			sd->devotion[i] = bl->id;
 			clif_skill_nodamage(src,bl,skillid,skilllv,
 				sc_start4(bl,type,100,src->id,i,skill_get_range2(src,skillid,skilllv),skill_get_time2(skillid, skilllv),1000));
-			clif_devotion(sd);
+			clif_devotion(sd,NULL);
 		}
 		else
 			if (sd)

+ 8 - 13
src/map/status.c

@@ -647,7 +647,7 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
 			if ((sce=sc->data[SC_DEVOTION]) && src && battle_getcurrentskill(src) != PA_PRESSURE)
 			{	//Devotion prevents any of the other ailments from ending.
 				struct map_session_data *sd2 = map_id2sd(sce->val1);
-				if (sd2 && sd2->devotion[sce->val2] == target->id)
+				if (sd2 && sd2->devotion[sce->val2] == target->id && check_distance_bl(target, &sd2->bl, sce->val3))
 				{
 					clif_damage(&sd2->bl, &sd2->bl, gettick(), 0, 0, hp, 0, 0, 0);
 					status_fix_damage(NULL, &sd2->bl, hp, 0);
@@ -6322,7 +6322,7 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 			if (md)
 			{
 				md->devotion[sce->val2] = 0;
-				clif_devotion(md);
+				clif_devotion(md,NULL);
 			}
 			//Remove inherited status [Skotlex]
 			if (sc->data[SC_AUTOGUARD])
@@ -6333,8 +6333,8 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 				status_change_end(bl,SC_REFLECTSHIELD,-1);
 			if (sc->data[SC_ENDURE])
 				status_change_end(bl,SC_ENDURE,-1);
-			break;
 		}
+		break;
 		case SC_BLADESTOP:
 			if(sce->val4)
 			{
@@ -6431,8 +6431,6 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 					status_change_end(pbl, type2, -1);
 				}
 			}
-			if (type == SC_MARIONETTE)
-				clif_marionette(bl, 0); //Clear effect.
 			break;
 
 		case SC_BERSERK:
@@ -6906,14 +6904,11 @@ int status_change_timer(int tid, unsigned int tick, int id, int data)
 		break;
 
 	case SC_DEVOTION:
-		{	//Check range and timeleft to preserve status [Skotlex]
-			//This implementation won't work for mobs because of map_id2sd, but it's a small cost in exchange of the speed of map_id2sd over map_id2bl
-			struct map_session_data *md = map_id2sd(sce->val1);
-			if (md && check_distance_bl(bl, &md->bl, sce->val3) && (sce->val4-=1000)>0)
-			{
-				sc_timer_next(1000+tick, status_change_timer, bl->id, data);
-				return 0;
-			}
+		//FIXME: use normal status duration instead of a looping timer
+		if( (sce->val4 -= 1000) > 0 )
+		{
+			sc_timer_next(1000+tick, status_change_timer, bl->id, data);
+			return 0;
 		}
 		break;