Sfoglia il codice sorgente

Updated recovery command with many more options - Suggestion tid:82374
-> Updated documentation on changes
Updated Overbrand to a closer official area behaviour - Fixes bugreport:7651
Follow up to r17320 - Fix incorrect condition check (lighta)
Fixed status effects not being removed correctly (lighta, Akinari) - Fixes bugreport:7634

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

akinari1087 12 anni fa
parent
commit
d21fa84734
8 ha cambiato i file con 245 aggiunte e 42 eliminazioni
  1. 1 1
      db/re/skill_db.txt
  2. 1 0
      db/re/skill_unit_db.txt
  3. 32 3
      doc/script_commands.txt
  4. 0 9
      src/map/mob.c
  5. 136 16
      src/map/script.c
  6. 57 13
      src/map/skill.c
  7. 1 0
      src/map/skill.h
  8. 17 0
      src/map/status.c

+ 1 - 1
db/re/skill_db.txt

@@ -889,7 +889,7 @@
 2314,1,6,1,-1,0,0,1,1,no,0,0,0,weapon,0,	LG_RAGEBURST,Rage Burst
 2315,0,6,4,0,0x2,3,3,1,yes,0,0,0,none,2,	LG_SHIELDSPELL,Shield Spell
 2316,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,	LG_EXEEDBREAK,Exceed Break
-2317,1,6,2,-1,0x2,5,5,1,yes,0,0,0,none,3:4:5:6:7,	LG_OVERBRAND,Over Brand //CHECK I know the splash is needed somehow for the strange AoE it gives.
+2317,0,6,2,-1,0x2,0,5,1,yes,0,0,0,none,3:4:5:6:7,	LG_OVERBRAND,Over Brand
 2318,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,	LG_PRESTIGE,Prestige
 2319,0,6,4,0,0x1,3,5,1,no,0,0,0,weapon,0,	LG_BANDING,Banding //CHECK Splash isnt needed right? Banding has its own UNIT ID.
 2320,0,6,4,-1,0x2,3,5,1,yes,0,0,0,weapon,0,	LG_MOONSLASHER,Moon Slasher

+ 1 - 0
db/re/skill_unit_db.txt

@@ -127,6 +127,7 @@
 2303,0xd0,    ,  3, 0,  -1,all,   0x2018	//SC_BLOODYLUST
 2304,0xd1,    ,  0, 2,  -1,enemy, 0x000	//SC_FEINTBOMB
 
+2317,0x86,    , -1, 0,	-1,enemy, 0x010	//LG_OVERBRAND
 2319,0xec,    ,  0, 3,5000,all,   0x000	//LG_BANDING
 
 2414,0xda,    ,  0, 0,1000,enemy, 0x008	//WM_REVERBERATION

+ 32 - 3
doc/script_commands.txt

@@ -3847,10 +3847,39 @@ you have maximum. Like 'heal', this will not call up any animations or effects.
 
 ---------------------------------------
 
-*recovery;
+*recovery <type>{,<id | mapname>,<revive_flag>{,<map>}};
 
-This command will revive and restore full HP and SP to all characters currently 
-connected to the server.
+Recovery can be used to recover all HP/SP to specific characters as well as revive.
+Party and Guild type use party and guild name.  This command will return 1 on
+successful use.
+
+<type> is who you are targeting.  Valid types are:
+	- 0: Specific Character (<charid> or target is invoker)
+	- 1: Party (<partyid> or target party is invoker's)
+	- 2: Guild (<guildid> or target guild is invoker's)
+	- 3: Map (<string> or invoker map)
+	- 4: All
+
+<revive_flag> is used to determine what actions to take.
+	- 1: Revive and Recover (Default)
+	- 2: Only Full Heal
+	- 4: Only Revive
+
+<map> is used only when <type> is 1-2 (Party/Guild) to define a single map where
+the party or guild gets the recovery.
+
+Examples:
+	//Only revive characters in invoking party on map morocc
+	recovery 1,getcharid(1),4,"morocc";
+
+	//Fully heal (don't revive) all members of invoking character's guild
+	recovery 2,getcharid(2),2;
+
+	//Revive and fully heal everyone in map prontera
+	recovery 3,"prontera";
+
+	//Only revive all dead characters on server
+	recovery 4,4;
 
 ---------------------------------------
 

+ 0 - 9
src/map/mob.c

@@ -2629,15 +2629,6 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 	if (battle_config.mvp_tomb_enabled && md->spawn->state.boss)
 		mvptomb_create(md, mvp_sd ? mvp_sd->status.name : NULL, time(NULL));
 
-	// Remove all status changes before creating a respawn
-	if( sc ) {
-		for(i=0; i<SC_MAX; i++){
-			if(sc->data[i] && (sc->data[i]->timer != INVALID_TIMER))
-				delete_timer(sc->data[i]->timer, status_change_timer);
-		}
-		memset( sc, 0, sizeof( struct status_change ) );
-	}
-
 	if( !rebirth )
 		mob_setdelayspawn(md); //Set respawning.
 	return 3; //Remove from map.

+ 136 - 16
src/map/script.c

@@ -12803,25 +12803,145 @@ BUILDIN_FUNC(dispbottom)
 	return 0;
 }
 
-/*==========================================
- * All The Players Full Recovery
- * (HP/SP full restore and resurrect if need)
- *------------------------------------------*/
+/*===================================
+ * Heal portion of recovery command
+ *-----------------------------------*/
+int recovery_sub(struct map_session_data* sd, int revive)
+{
+	if(revive&(1|4) && pc_isdead(sd)) {
+		status_revive(&sd->bl, 100, 100);
+		clif_displaymessage(sd->fd,msg_txt(sd,16));
+		clif_specialeffect(&sd->bl, 77, AREA);
+	} else if(revive&(1|2) && !pc_isdead(sd)) {
+		status_percent_heal(&sd->bl, 100, 100);
+		clif_displaymessage(sd->fd,msg_txt(sd,680));
+	}
+	return 0;
+}
+
+/*=========================================================================
+ * Fully Recover a Character's HP/SP - [Capuche] & [Akinari] 
+ * recovery <target>,{<id | map>,<revive_flag>,{<map>}};
+ * <target> :
+ *	0 - Character
+ *	1 - Character Party
+ *	2 - Character Guild
+ *	3 - Map (Character on map)
+ *	4 - All Characters
+ * <id | map> :
+ *	<target> : 0   => Character's Account ID
+ *	<target> : 1-2 => Character's Party/Guild ID
+ *	<target> : 3   => Map Name (player attached map's name by default)
+ * <revive_flag> : 
+ *		 : 1 => Revive and Recover (Default)
+ *		 : 2 => Only Full Heal
+ *		 : 4 => Only Revive
+ * <map> :
+ *	<target> : 1-2 => Map name (Null = All)
+ *-------------------------------------------------------------------------*/
 BUILDIN_FUNC(recovery)
 {
-	TBL_PC* sd;
-	struct s_mapiterator* iter;
+	TBL_PC *sd = script_rid2sd(st);
 
-	iter = mapit_getallusers();
-	for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
-	{
-		if(pc_isdead(sd))
-			status_revive(&sd->bl, 100, 100);
-		else
-			status_percent_heal(&sd->bl, 100, 100);
-		clif_displaymessage(sd->fd,msg_txt(sd,680));
+	int map = 0, type = 0, revive = 1;
+	const char *mapname;
+
+	type = script_getnum(st,2);
+
+	if(script_hasdata(st,4))
+		revive = script_getnum(st,4);
+
+	switch(type) {
+		case 0:
+			if(script_hasdata(st,3))
+				sd=map_id2sd(script_getnum(st,3));
+			if(sd == NULL) //If we don't have sd by now, bail out
+				return 0;
+			recovery_sub(sd, revive);
+			break;
+		case 1:
+		{
+			if(script_hasdata(st,5)) {//Bad maps shouldn't cause issues
+				map = map_mapname2mapid(script_getstr(st,5));
+				if(map < 1) { //But we'll check anyways
+					ShowDebug("recovery: bad map name given (%s)\n", script_getstr(st,5));
+					return 1;
+				}
+			}
+			struct party_data* p;
+			struct map_session_data* pl_sd;
+			//When no party given, we use invoker party
+			int p_id, i;
+			if(script_hasdata(st,3))
+				p_id = script_getnum(st,3);
+			else
+				p_id = (sd)?sd->status.party_id:0;
+			p = party_search(p_id);
+			if(p == NULL)
+				return 0;
+			for (i = 0; i < MAX_PARTY; i++) {
+				if((!(pl_sd = p->data[i].sd) || pl_sd->status.party_id != p_id)
+					|| (map && pl_sd->bl.m != map))
+					continue;
+				recovery_sub(pl_sd, revive);
+			}
+			break;
+		}
+		case 2:
+		{
+			if(script_hasdata(st,5)) {//Bad maps shouldn't cause issues
+				map = map_mapname2mapid(script_getstr(st,5));
+				if(map < 1) { //But we'll check anyways
+					ShowDebug("recovery: bad map name given (%s)\n", script_getstr(st,5));
+					return 1;
+				}
+			}
+			struct guild* g;
+			struct map_session_data* pl_sd;
+			//When no guild given, we use invoker guild
+			int g_id, i;
+			if(script_hasdata(st,3))
+				g_id = script_getnum(st,3);
+			else
+				g_id = (sd)?sd->status.guild_id:0;
+			g = guild_search(g_id);
+			if(g == NULL)
+				return 0;
+			for (i = 0; i < MAX_GUILD; i++) {
+				if((!(pl_sd = g->member[i].sd) || pl_sd->status.guild_id != g_id)
+					|| (map && pl_sd->bl.m != map))
+					continue;
+				recovery_sub(pl_sd, revive);
+			}
+			break;
+		}
+		case 3:
+			if(script_hasdata(st,3))
+				map = map_mapname2mapid(script_getstr(st,3));
+			else
+				map = (sd)?sd->bl.m:0; //No sd and no map given - return
+			if(map < 1)
+				return 1;
+		case 4:
+		{
+			struct s_mapiterator *iter;
+			if(script_hasdata(st,3) && !script_isstring(st,3))
+				revive = script_getnum(st,3);
+			iter = mapit_getallusers();
+			for (sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) {
+				if(type == 3 && sd->bl.m != map)
+					continue;
+				recovery_sub(sd, revive);
+			}
+			mapit_free(iter);
+			break;
+		}
+		default:
+			ShowWarning("script: buildin_recovery: Invalid type %d\n", type);
+			script_pushint(st,-1);
+			return 1;
 	}
-	mapit_free(iter);
+	script_pushint(st,1); //Successfully executed without errors
 	return 0;
 }
 /*==========================================
@@ -17876,7 +17996,7 @@ struct script_function buildin_func[] = {
 #endif
 	BUILDIN_DEF(dispbottom,"s"), //added from jA [Lupus]
 	BUILDIN_DEF(getusersname,""),
-	BUILDIN_DEF(recovery,""),
+	BUILDIN_DEF(recovery,"i???"),
 	BUILDIN_DEF(getpetinfo,"i"),
 	BUILDIN_DEF(gethominfo,"i"),
 	BUILDIN_DEF(getmercinfo,"i?"),

+ 57 - 13
src/map/skill.c

@@ -10392,15 +10392,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
 		break;
 
 	case LG_OVERBRAND:
-		{
-			int width;//according to data from irowiki it actually is a square
-			for( width = 0; width < 7; width++ )
-				for( i = 0; i < 7; i++ )
-					map_foreachincell(skill_area_sub, src->m, x-2+i, y-2+width, splash_target(src), src, LG_OVERBRAND_BRANDISH, skill_lv, tick, flag|BCT_ENEMY,skill_castend_damage_id);
-			for( width = 0; width < 7; width++ )
-				for( i = 0; i < 7; i++ )
-					map_foreachincell(skill_area_sub, src->m, x-2+i, y-2+width, splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY,skill_castend_damage_id);
-		}
+		skill_overbrand(src, skill_id, skill_lv, x, y, tick, flag);
 		break;
 
 	case LG_BANDING:
@@ -13138,14 +13130,15 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id
 		//	}
 		//	break;
 
-		
+
 		case AB_ADORAMUS: // bugreport:7647 mistress card DOES remove requirements for gemstones from Adoramus and Comet -helvetica
 		/**
 		 * Warlock
 		 **/
 		case WL_COMET:
 			if( skill_check_pc_partner(sd,skill_id,&skill_lv,1,0) <= 0
-				&& ((i = pc_search_inventory(sd,require.itemid[0])) < 0 || sd->status.inventory[i].amount < require.amount[0] || !sd->special_state.no_gemstone) ) {
+				&& sd->special_state.no_gemstone == 0
+				&& ((i = pc_search_inventory(sd,require.itemid[0])) < 0 || sd->status.inventory[i].amount < require.amount[0]) ) {
 				//clif_skill_fail(sd,skill_id,USESKILL_FAIL_NEED_ITEM,require.amount[0],require.itemid[0]);
 				clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
 				return 0;
@@ -13164,14 +13157,14 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id
 			}
 			break;
 		case WL_TETRAVORTEX: // bugreport:7598 moved sphere check to precast to avoid triggering cooldown per official behavior -helvetica
-			if( sc ) {	
+			if( sc ) {
 				int j = 0;
 
 				for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ )
 					if( sc->data[i] ) {
 						j++;
 					}
-			
+
 				if( j < 4 ) { // Need 4 spheres minimum
 					clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
 					return 0;
@@ -14300,6 +14293,45 @@ int skill_delayfix (struct block_list *bl, uint16 skill_id, uint16 skill_lv)
 /*=========================================
  *
  *-----------------------------------------*/
+void skill_overbrand(struct block_list* src, uint16 skill_id, uint16 skill_lv, uint16 x, uint16 y, unsigned int tick, int flag)
+{
+	struct s_skill_unit_layout *layout;
+	layout = skill_get_unit_layout(skill_id,skill_lv,src,x,y);
+	int i, ux[53], uy[53]; //Number of cells we are attacking
+	short dir = map_calc_dir(src,x,y);
+	if(dir > 0 && dir < 4) { //Need to invert the cell locations for directions
+		for(i = 0; i < 53; i++) {
+			ux[i] = layout->dy[i];
+			uy[i] = layout->dx[i] * -1;
+		}
+	} else if(dir == 4) {
+		for(i = 0; i < 53; i++) {
+			ux[i] = layout->dx[i];
+			uy[i] = layout->dy[i];
+		}
+	} else if(dir > 4) {
+		for(i = 0; i < 53; i++) {
+			ux[i] = layout->dy[i] * -1;
+			uy[i] = layout->dx[i];
+		}
+	} else {
+		for(i = 0; i < 53; i++) {
+			ux[i] = layout->dx[i];
+			uy[i] = layout->dy[i] * -1;
+		}
+	}
+	for( i = 0; i < 53; i++ ) {
+		if(i < 12) { //Close range hits twice
+			map_foreachincell(skill_area_sub, src->m, x+ux[i], y+uy[i], splash_target(src), src, LG_OVERBRAND_BRANDISH, skill_lv, tick, flag|BCT_ENEMY,skill_castend_damage_id);
+			map_foreachincell(skill_area_sub, src->m, x+ux[i], y+uy[i], splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY,skill_castend_damage_id);
+		} else if(i > 11 && i < 45) //Far sides do knockback damage
+			map_foreachincell(skill_area_sub, src->m, x+ux[i], y+uy[i], splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY,skill_castend_damage_id);
+		else //Far middle does piercing damage
+			map_foreachincell(skill_area_sub, src->m, x+ux[i], y+uy[i], splash_target(src), src, LG_OVERBRAND_BRANDISH, skill_lv, tick, flag|BCT_ENEMY,skill_castend_damage_id);
+	}
+
+}
+
 struct square {
 	int val1[5];
 	int val2[5];
@@ -17546,6 +17578,18 @@ void skill_init_unit_layout (void) {
 						memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
 					}
 					break;
+				case LG_OVERBRAND: {
+						static const int dx[] = {-1,-1,-1,-1, 0, 0, 0, 0, 1, 1, 1, 1,
+									 -5,-5,-5,-5,-4,-4,-4,-4,-3,-3,-3,-3,-2,-2,-2,-2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5,
+									 -1,-1,-1, 0, 0, 0, 1, 1, 1};
+						static const int dy[] = { 0,-1,-2,-3, 0,-1,-2,-3, 0,-1,-2,-3, 
+									  0,-1,-2,-3, 0,-1,-2,-3, 0,-1,-2,-3, 0,-1,-2,-3, 0,-1,-2,-3, 0,-1,-2,-3, 0,-1,-2,-3, 0,-1,-2,-3,
+									 -4,-5,-6,-4,-5,-6,-4,-5,-6};
+						skill_unit_layout[pos].count = 53;
+						memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
+						memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
+					}
+					break;
 				default:
 					ShowError("unknown unit layout at skill %d\n",i);
 					break;

+ 1 - 0
src/map/skill.h

@@ -333,6 +333,7 @@ int skill_castcancel(struct block_list *bl,int type);
 
 int skill_sit (struct map_session_data *sd, int type);
 void skill_brandishspear(struct block_list* src, struct block_list* bl, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag);
+void skill_overbrand(struct block_list* src, uint16 skill_id, uint16 skill_lv, uint16 x, uint16 y, unsigned int tick, int flag);
 void skill_repairweapon(struct map_session_data *sd, int idx);
 void skill_identify(struct map_session_data *sd,int idx);
 void skill_weaponrefine(struct map_session_data *sd,int idx); // [Celest]

+ 17 - 0
src/map/status.c

@@ -9250,6 +9250,14 @@ int status_change_clear(struct block_list* bl, int type) {
 	sc->opt2 = 0;
 	sc->opt3 = 0;
 
+	//cleaning all extras vars
+	sc->comet_x = 0;
+	sc->comet_y = 0;
+#ifndef RENEWAL
+	sc->sg_counter = 0;
+#endif
+	sc->bs_counter = 0;
+
 	if( type == 0 || type == 2 )
 		clif_changeoption(bl);
 
@@ -11000,6 +11008,15 @@ int status_change_clear_buffs (struct block_list* bl, int type)
 		}
 		status_change_end(bl, (sc_type)i, INVALID_TIMER);
 	}
+
+	//cleaning all extras vars
+	sc->comet_x = 0;
+	sc->comet_y = 0;
+#ifndef RENEWAL
+	sc->sg_counter = 0;
+#endif
+	sc->bs_counter = 0;
+
 	return 0;
 }