소스 검색

- Commiting a bunch of cleanups piled up from the past few weeks/months/years.
- Updated unitwarp so that an id of "0" causes the script's rid to be warped.
- Updated the Brasilis ontouchNPC warp command to use unitwarp instead.
- Signum Crucis's duration is now specified in the skill_cast_db file
- Updated @warp/@jump commands so that when an invalid tile is specified, a nearby cell is chosen (rather than using a map-wide random value)
- The if(req.weapon) code was broken, since req.weapon is never "0" for a skill. Updated the code so that the requirement of '99' (any weapon) is stored as 0, in order to make the checks effective.
- Cleaned up the code for script command warpparty
- Fixed the define itemdb_canrefine()
- Cleaned up some the status_damage() function
- Fixed map_random_dir(), which at times would pick cells that didn't preserve the required distance.
- Some aesthetic code cleanups.
- Fixed some possible crashes for skills where the code assumes the caster is a player.
- Fixed a bunch of idiotic code-snippets that should have embarrassed whoever was responsible for them.


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

Skotlex 13 년 전
부모
커밋
b7ad7aa055
14개의 변경된 파일116개의 추가작업 그리고 112개의 파일을 삭제
  1. 3 0
      Changelog-Trunk.txt
  2. 1 1
      db/skill_cast_db.txt
  3. 8 1
      doc/script_commands.txt
  4. 2 0
      npc/Changelog.txt
  5. 1 1
      npc/quests/quests_brasilis.txt
  6. 9 7
      src/map/atcommand.c
  7. 1 1
      src/map/itemdb.h
  8. 1 1
      src/map/map.c
  9. 1 1
      src/map/pc.c
  10. 0 1
      src/map/pc.h
  11. 31 23
      src/map/script.c
  12. 25 24
      src/map/skill.c
  13. 32 51
      src/map/status.c
  14. 1 0
      src/map/status.h

+ 3 - 0
Changelog-Trunk.txt

@@ -1,5 +1,8 @@
 Date	Added
 Date	Added
 
 
+2011/08/10
+	* Updated unitwarp so that an id of "0" causes the script's rid to be warped. This allows OnTouchNPC scripts to warp the monster. [Skotlex]
+	* Updated @warp/@jump commands so that when an invalid tile is specified, a nearby cell is chosen.
 2011/08/06
 2011/08/06
 	* Added missing fields to guild belong info packet 0x16c (ZC_UPDATE_GDID). [Ai4rei]
 	* Added missing fields to guild belong info packet 0x16c (ZC_UPDATE_GDID). [Ai4rei]
 2011/07/31
 2011/07/31

+ 1 - 1
db/skill_cast_db.txt

@@ -88,7 +88,7 @@
 //-- AL_HOLYWATER
 //-- AL_HOLYWATER
 31,1000,500,0,0,0
 31,1000,500,0,0,0
 //-- AL_CRUCIS
 //-- AL_CRUCIS
-32,500,2000,0,0,0
+32,500,2000,0,60000,0
 //-- AL ANGELUS
 //-- AL ANGELUS
 33,500,3500,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0
 33,500,3500,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0
 //-- AL_BLESSING
 //-- AL_BLESSING

+ 8 - 1
doc/script_commands.txt

@@ -181,6 +181,8 @@
 //=       Documented special map names recognized by 'warpguild'. [Ai4rei]
 //=       Documented special map names recognized by 'warpguild'. [Ai4rei]
 //= 3.45.20110709
 //= 3.45.20110709
 //=       Added 'getmercinfo' command. [Ai4rei]
 //=       Added 'getmercinfo' command. [Ai4rei]
+//= 3.46.20110810
+//=       Added information on OnTouchNPC and 'unitwarp' special case [Skotlex]
 //=========================================================
 //=========================================================
 
 
 This document is a reference manual for all the scripting commands and functions 
 This document is a reference manual for all the scripting commands and functions 
@@ -423,7 +425,8 @@ spanning triggerX cells in every direction across X and triggerY in every
 direction across Y. Walking into that area will trigger the NPC. If no 
 direction across Y. Walking into that area will trigger the NPC. If no 
 'OnTouch:' special label is present in the NPC code, the execution will start 
 'OnTouch:' special label is present in the NPC code, the execution will start 
 from the beginning of the script, otherwise, it will start from the 'OnTouch:' 
 from the beginning of the script, otherwise, it will start from the 'OnTouch:' 
-label.
+label. Monsters can also trigger the NPC, though the label 'OnTouchNPC:' is 
+used in this case.
 
 
 The code part is the script code that will execute whenever the NPC is 
 The code part is the script code that will execute whenever the NPC is 
 triggered. It may contain commands and function calls, descriptions of which 
 triggered. It may contain commands and function calls, descriptions of which 
@@ -5241,6 +5244,10 @@ Example(s):
 
 
 Okay, these commands should be fairly self explaining.
 Okay, these commands should be fairly self explaining.
 For the emotions, you can look in db/const.txt for prefixes with e_
 For the emotions, you can look in db/const.txt for prefixes with e_
+PS: unitwarp supports a <GID> of zero, which causes the executor of the script to be affected. This can be used with OnTouchNPC to warp monsters:
+
+OnTouchNPC:
+	unitwarp 0,"this",-1,-1;
 
 
 ---------------------------------------
 ---------------------------------------
 
 

+ 2 - 0
npc/Changelog.txt

@@ -1,5 +1,7 @@
 Date		Added
 Date		Added
 ======
 ======
+2011/08/10
+	* Updated the quests_brasilis ontouchNPC warp command to use unitwarp instead. [Skotlex]
 2011/08/09
 2011/08/09
 	* Rev. 14928 Implemented the rest of Brasilis, and updated existing Brasilis NPCs. [L0ne_W0lf]
 	* Rev. 14928 Implemented the rest of Brasilis, and updated existing Brasilis NPCs. [L0ne_W0lf]
 2011/07/16
 2011/07/16

+ 1 - 1
npc/quests/quests_brasilis.txt

@@ -2669,7 +2669,7 @@ bra_dun02,67,205,5	script	Recluse#bra	475,3,3,{
 	end;
 	end;
 
 
 OnTouchNPC:
 OnTouchNPC:
-	warp "bra_dun02",67,215;
+	unitwarp 0,"this",67,215;
 	end;
 	end;
 }
 }
 
 

+ 9 - 7
src/map/atcommand.c

@@ -416,7 +416,7 @@ ACMD_FUNC(mapmove)
 {
 {
 	char map_name[MAP_NAME_LENGTH_EXT];
 	char map_name[MAP_NAME_LENGTH_EXT];
 	unsigned short mapindex;
 	unsigned short mapindex;
-	int x = 0, y = 0;
+	short x = 0, y = 0;
 	int m = -1;
 	int m = -1;
 
 
 	nullpo_retr(-1, sd);
 	nullpo_retr(-1, sd);
@@ -424,8 +424,8 @@ ACMD_FUNC(mapmove)
 	memset(map_name, '\0', sizeof(map_name));
 	memset(map_name, '\0', sizeof(map_name));
 
 
 	if (!message || !*message ||
 	if (!message || !*message ||
-		(sscanf(message, "%15s %d %d", map_name, &x, &y) < 3 &&
-		 sscanf(message, "%15[^,],%d,%d", map_name, &x, &y) < 1)) {
+		(sscanf(message, "%15s %hd %hd", map_name, &x, &y) < 3 &&
+		 sscanf(message, "%15[^,],%hd,%hd", map_name, &x, &y) < 1)) {
 		 
 		 
 			clif_displaymessage(fd, "Please, enter a map (usage: @warp/@rura/@mapmove <mapname> <x> <y>).");
 			clif_displaymessage(fd, "Please, enter a map (usage: @warp/@rura/@mapmove <mapname> <x> <y>).");
 			return -1;
 			return -1;
@@ -443,7 +443,8 @@ ACMD_FUNC(mapmove)
 	if ((x || y) && map_getcell(m, x, y, CELL_CHKNOPASS))
 	if ((x || y) && map_getcell(m, x, y, CELL_CHKNOPASS))
   	{	//This is to prevent the pc_setpos call from printing an error.
   	{	//This is to prevent the pc_setpos call from printing an error.
 		clif_displaymessage(fd, msg_txt(2));
 		clif_displaymessage(fd, msg_txt(2));
-		x = y = 0; //Invalid cell, use random spot.
+		if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1))
+			x = y = 0; //Invalid cell, use random spot.
 	}
 	}
 	if (map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
 	if (map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
 		clif_displaymessage(fd, msg_txt(247));
 		clif_displaymessage(fd, msg_txt(247));
@@ -548,13 +549,13 @@ ACMD_FUNC(jumpto)
  *------------------------------------------*/
  *------------------------------------------*/
 ACMD_FUNC(jump)
 ACMD_FUNC(jump)
 {
 {
-	int x = 0, y = 0;
+	short x = 0, y = 0;
 
 
 	nullpo_retr(-1, sd);
 	nullpo_retr(-1, sd);
 
 
 	memset(atcmd_output, '\0', sizeof(atcmd_output));
 	memset(atcmd_output, '\0', sizeof(atcmd_output));
 
 
-	sscanf(message, "%d %d", &x, &y);
+	sscanf(message, "%hd %hd", &x, &y);
 
 
 	if (map[sd->bl.m].flag.noteleport && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
 	if (map[sd->bl.m].flag.noteleport && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
 		clif_displaymessage(fd, msg_txt(248));	// You are not authorized to warp from your current map.
 		clif_displaymessage(fd, msg_txt(248));	// You are not authorized to warp from your current map.
@@ -570,7 +571,8 @@ ACMD_FUNC(jump)
 	if ((x || y) && map_getcell(sd->bl.m, x, y, CELL_CHKNOPASS))
 	if ((x || y) && map_getcell(sd->bl.m, x, y, CELL_CHKNOPASS))
   	{	//This is to prevent the pc_setpos call from printing an error.
   	{	//This is to prevent the pc_setpos call from printing an error.
 		clif_displaymessage(fd, msg_txt(2));
 		clif_displaymessage(fd, msg_txt(2));
-		x = y = 0; //Invalid cell, use random spot.
+		if (!map_search_freecell(NULL, sd->bl.m, &x, &y, 10, 10, 1))
+			x = y = 0; //Invalid cell, use random spot.
 	}
 	}
 
 
 	pc_setpos(sd, sd->mapindex, x, y, CLR_TELEPORT);
 	pc_setpos(sd, sd->mapindex, x, y, CLR_TELEPORT);

+ 1 - 1
src/map/itemdb.h

@@ -114,7 +114,7 @@ int itemdb_searchrandomid(int flags);
 
 
 #define itemdb_value_buy(n) itemdb_search(n)->value_buy
 #define itemdb_value_buy(n) itemdb_search(n)->value_buy
 #define itemdb_value_sell(n) itemdb_search(n)->value_sell
 #define itemdb_value_sell(n) itemdb_search(n)->value_sell
-#define itemdb_canrefine(n) itemdb_search(n)->flag.no_refine
+#define itemdb_canrefine(n) (!itemdb_search(n)->flag.no_refine)
 //Item trade restrictions [Skotlex]
 //Item trade restrictions [Skotlex]
 int itemdb_isdropable_sub(struct item_data *, int, int);
 int itemdb_isdropable_sub(struct item_data *, int, int);
 int itemdb_cantrade_sub(struct item_data*, int, int);
 int itemdb_cantrade_sub(struct item_data*, int, int);

+ 1 - 1
src/map/map.c

@@ -2305,7 +2305,7 @@ int map_random_dir(struct block_list *bl, short *x, short *y)
 	if (dist < 1) dist =1;
 	if (dist < 1) dist =1;
 	
 	
 	do {
 	do {
-		j = rand()%8; //Pick a random direction
+		j = 1 + 2*(rand()%4); //Pick a random diagonal direction
 		segment = 1+(rand()%dist); //Pick a random interval from the whole vector in that direction
 		segment = 1+(rand()%dist); //Pick a random interval from the whole vector in that direction
 		xi = bl->x + segment*dirx[j];
 		xi = bl->x + segment*dirx[j];
 		segment = (short)sqrt((float)(dist2 - segment*segment)); //The complement of the previously picked segment
 		segment = (short)sqrt((float)(dist2 - segment*segment)); //The complement of the previously picked segment

+ 1 - 1
src/map/pc.c

@@ -7168,7 +7168,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos)
 	pos = pc_equippoint(sd,n); //With a few exceptions, item should go in all specified slots.
 	pos = pc_equippoint(sd,n); //With a few exceptions, item should go in all specified slots.
 
 
 	if(battle_config.battle_log)
 	if(battle_config.battle_log)
-		ShowInfo("equip %d(%d) %x:%x\n",sd->status.inventory[n].nameid,n,id->equip,req_pos);
+		ShowInfo("equip %d(%d) %x:%x\n",sd->status.inventory[n].nameid,n,id?id->equip:0,req_pos);
 	if(!pc_isequip(sd,n) || !(pos&req_pos) || sd->status.inventory[n].equip != 0 || sd->status.inventory[n].attribute==1 ) { // [Valaris]
 	if(!pc_isequip(sd,n) || !(pos&req_pos) || sd->status.inventory[n].equip != 0 || sd->status.inventory[n].attribute==1 ) { // [Valaris]
 		clif_equipitemack(sd,n,0,0);	// fail
 		clif_equipitemack(sd,n,0,0);	// fail
 		return 0;
 		return 0;

+ 0 - 1
src/map/pc.h

@@ -10,7 +10,6 @@
 #include "buyingstore.h"  // struct s_buyingstore
 #include "buyingstore.h"  // struct s_buyingstore
 #include "itemdb.h" // MAX_ITEMGROUP
 #include "itemdb.h" // MAX_ITEMGROUP
 #include "map.h" // RC_MAX
 #include "map.h" // RC_MAX
-#include "pc.h" // struct map_session_data
 #include "script.h" // struct script_reg, struct script_regstr
 #include "script.h" // struct script_reg, struct script_regstr
 #include "searchstore.h"  // struct s_search_store_info
 #include "searchstore.h"  // struct s_search_store_info
 #include "status.h" // OPTION_*, struct weapon_atk
 #include "status.h" // OPTION_*, struct weapon_atk

+ 31 - 23
src/map/script.c

@@ -4559,7 +4559,7 @@ BUILDIN_FUNC(warpparty)
 	struct party_data* p;
 	struct party_data* p;
 	int type;
 	int type;
 	int mapindex;
 	int mapindex;
-	int i, j;
+	int i;
 
 
 	const char* str = script_getstr(st,2);
 	const char* str = script_getstr(st,2);
 	int x = script_getnum(st,3);
 	int x = script_getnum(st,3);
@@ -4579,9 +4579,27 @@ BUILDIN_FUNC(warpparty)
 		 : ( strcmp(str,"Leader")==0 ) ? 3
 		 : ( strcmp(str,"Leader")==0 ) ? 3
 		 : 4;
 		 : 4;
 
 
-	if( type == 2 && ( sd = script_rid2sd(st) ) == NULL )
-	{// "SavePoint" uses save point of the currently attached player
-		return 0;
+	switch (type)
+	{
+	case 3:
+		for(i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++);
+		if (i == MAX_PARTY || !p->data[i].sd) //Leader not found / not online
+			return 0;
+		pl_sd = p->data[i].sd;
+		mapindex = pl_sd->mapindex;
+		x = pl_sd->bl.x;
+		y = pl_sd->bl.y;
+		break;
+	case 4:
+		mapindex = mapindex_name2id(str);
+		break;
+	case 2:
+		//"SavePoint" uses save point of the currently attached player
+		if (( sd = script_rid2sd(st) ) == NULL )
+			return 0;
+	default:
+		mapindex = 0;
+		break;
 	}
 	}
 
 
 	for (i = 0; i < MAX_PARTY; i++)
 	for (i = 0; i < MAX_PARTY; i++)
@@ -4610,25 +4628,9 @@ BUILDIN_FUNC(warpparty)
 				pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
 				pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
 		break;
 		break;
 		case 3: // Leader
 		case 3: // Leader
-			for(j = 0; j < MAX_PARTY && !p->party.member[j].leader; j++);
-			if (j == MAX_PARTY || !p->data[j].sd) //Leader not found / not online
-				return 0;
-			mapindex = p->data[j].sd->mapindex;
-			x = p->data[j].sd->bl.x;
-			y = p->data[j].sd->bl.y;
-			for (j = 0; j < MAX_PARTY; j++)
-			{
-				pl_sd = p->data[j].sd;
-				if (!pl_sd)
-					continue;
-				if(map[pl_sd->bl.m].flag.noreturn || map[pl_sd->bl.m].flag.nowarp)
-					continue;
-				pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
-			}
-		break;
 		case 4: // m,x,y
 		case 4: // m,x,y
 			if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp) 
 			if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp) 
-				pc_setpos(pl_sd,mapindex_name2id(str),x,y,CLR_TELEPORT);
+				pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
 		break;
 		break;
 		}
 		}
 	}
 	}
@@ -6574,6 +6576,9 @@ BUILDIN_FUNC(strnpcinfo)
 		case 3: // unique name
 		case 3: // unique name
 			name = aStrdup(nd->exname);
 			name = aStrdup(nd->exname);
 			break;
 			break;
+		case 4: // map name
+			name = aStrdup(map[nd->bl.m].name);
+			break;
 	}
 	}
 
 
 	if(name)
 	if(name)
@@ -13452,8 +13457,11 @@ BUILDIN_FUNC(unitwarp)
 	map = map_mapname2mapid(script_getstr(st, 3));
 	map = map_mapname2mapid(script_getstr(st, 3));
 	x = (short)script_getnum(st,4);
 	x = (short)script_getnum(st,4);
 	y = (short)script_getnum(st,5);
 	y = (short)script_getnum(st,5);
-
-	bl = map_id2bl(unit_id);
+	
+	if (!unit_id) //Warp the script's runner
+		bl = map_id2bl(st->rid);
+	else
+		bl = map_id2bl(unit_id);
 	if( map >= 0 && bl != NULL )
 	if( map >= 0 && bl != NULL )
 		script_pushint(st, unit_warp(bl,map,x,y,CLR_OUTSIGHT));
 		script_pushint(st, unit_warp(bl,map,x,y,CLR_OUTSIGHT));
 	else
 	else

+ 25 - 24
src/map/skill.c

@@ -268,8 +268,8 @@ int skill_get_range2 (struct block_list *bl, int id, int lv)
 int skill_calc_heal(struct block_list *src, struct block_list *target, int skill_id, int skill_lv, bool heal)
 int skill_calc_heal(struct block_list *src, struct block_list *target, int skill_id, int skill_lv, bool heal)
 {
 {
 	int skill, hp;
 	int skill, hp;
-	struct map_session_data *sd = map_id2sd(src->id);
-	struct map_session_data *tsd = map_id2sd(target->id);
+	struct map_session_data *sd = BL_CAST(BL_PC, src);
+	struct map_session_data *tsd = BL_CAST(BL_PC, target);
 	struct status_change* sc;
 	struct status_change* sc;
 
 
 	switch( skill_id )
 	switch( skill_id )
@@ -1008,8 +1008,9 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int
 
 
 			tbl = (sd->autospell[i].id < 0) ? src : bl;
 			tbl = (sd->autospell[i].id < 0) ? src : bl;
 
 
-			if( !battle_check_range(src, tbl, skill_get_range2(src, skill,skilllv) + (skill == RG_CLOSECONFINE?0:1)) && battle_config.autospell_check_range )
-				continue; // If autospell_check_range is yes, fail the autocast.
+			if( battle_config.autospell_check_range &&
+				!battle_check_range(src, tbl, skill_get_range2(src, skill,skilllv) + (skill == RG_CLOSECONFINE?0:1)) )
+				continue;
 
 
 			if (skill == AS_SONICBLOW)
 			if (skill == AS_SONICBLOW)
 				pc_stop_attack(sd); //Special case, Sonic Blow autospell should stop the player attacking.
 				pc_stop_attack(sd); //Special case, Sonic Blow autospell should stop the player attacking.
@@ -1113,7 +1114,8 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, int s
 			continue;
 			continue;
 		tbl = (sd->autospell3[i].id < 0) ? &sd->bl : bl;
 		tbl = (sd->autospell3[i].id < 0) ? &sd->bl : bl;
 
 
-		if( !battle_check_range(&sd->bl, tbl, skill_get_range2(&sd->bl, skill,skilllv) + (skill == RG_CLOSECONFINE?0:1)) && battle_config.autospell_check_range )
+		if( battle_config.autospell_check_range &&
+			!battle_check_range(&sd->bl, tbl, skill_get_range2(&sd->bl, skill,skilllv) + (skill == RG_CLOSECONFINE?0:1)) )
 			continue;
 			continue;
 
 
 		sd->state.autocast = 1;
 		sd->state.autocast = 1;
@@ -1640,13 +1642,10 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
 
 
 			//Spirit of Wizard blocks Kaite's reflection
 			//Spirit of Wizard blocks Kaite's reflection
 			if( type == 2 && sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_WIZARD )
 			if( type == 2 && sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_WIZARD )
-			{	//Consume one Fragment per hit of the casted skill. Val3 is the skill id and val4 is the ID of the damage src.
-				//This should account for ground spells (and single target spells will be completed on castend_id) [Skotlex]
-			  	type = pc_search_inventory (tsd, 7321);
-				if (type >= 0)
-					pc_delitem(tsd, type, 1, 0, 1);
-
+			{	//Consume one Fragment per hit of the casted skill? [Skotlex]
+			  	type = tsd?pc_search_inventory (tsd, 7321):0;
 				if (type >= 0) {
 				if (type >= 0) {
+					if ( tsd ) pc_delitem(tsd, type, 1, 0, 1);
 					dmg.damage = dmg.damage2 = 0;
 					dmg.damage = dmg.damage2 = 0;
 					dmg.dmg_lv = ATK_MISS;
 					dmg.dmg_lv = ATK_MISS;
 					sc->data[SC_SPIRIT]->val3 = skillid;
 					sc->data[SC_SPIRIT]->val3 = skillid;
@@ -3266,7 +3265,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 			break;
 			break;
 		{
 		{
 			int per = 0, sper = 0;
 			int per = 0, sper = 0;
-			if (status_get_sc(bl)->data[SC_HELLPOWER])
+			if (tsc && tsc->data[SC_HELLPOWER])
 				break;
 				break;
 
 
 			if (map[bl->m].flag.pvp && dstsd && dstsd->pvp_point < 0)
 			if (map[bl->m].flag.pvp && dstsd && dstsd->pvp_point < 0)
@@ -3310,7 +3309,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 
 
 	case AL_CRUCIS:
 	case AL_CRUCIS:
 		if (flag&1)
 		if (flag&1)
-			sc_start(bl,type, 23+skilllv*4 +status_get_lv(src) -status_get_lv(bl), skilllv,60000);
+			sc_start(bl,type, 23+skilllv*4 +status_get_lv(src) -status_get_lv(bl), skilllv,skill_get_time(skillid,skilllv));
 		else {
 		else {
 			map_foreachinrange(skill_area_sub, src, skill_get_splash(skillid, skilllv), BL_CHAR,
 			map_foreachinrange(skill_area_sub, src, skill_get_splash(skillid, skilllv), BL_CHAR,
 				src, skillid, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id);
 				src, skillid, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id);
@@ -3395,7 +3394,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 				break;
 				break;
 			heal = status_percent_heal(bl, 100, 0);
 			heal = status_percent_heal(bl, 100, 0);
 			clif_skill_nodamage(NULL, bl, AL_HEAL, heal, 1);
 			clif_skill_nodamage(NULL, bl, AL_HEAL, heal, 1);
-			if( skillid == NPC_ALLHEAL && dstmd )
+			if( dstmd )
 			{ // Reset Damage Logs
 			{ // Reset Damage Logs
 				memset(dstmd->dmglog, 0, sizeof(dstmd->dmglog));
 				memset(dstmd->dmglog, 0, sizeof(dstmd->dmglog));
 				dstmd->tdmg = 0;
 				dstmd->tdmg = 0;
@@ -3857,7 +3856,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 				mer->devotion_flag = 1; // Mercenary Devoting Owner
 				mer->devotion_flag = 1; // Mercenary Devoting Owner
 
 
 			clif_skill_nodamage(src, bl, skillid, skilllv,
 			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));
+				sc_start4(bl, type, 100, src->id, i, skill_get_range2(src,skillid,skilllv),0, skill_get_time2(skillid, skilllv)));
 			clif_devotion(src, NULL);
 			clif_devotion(src, NULL);
 		}
 		}
 		break;
 		break;
@@ -6194,7 +6193,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
 	case SA_VIOLENTGALE:
 	case SA_VIOLENTGALE:
 	{	//Does not consumes if the skill is already active. [Skotlex]
 	{	//Does not consumes if the skill is already active. [Skotlex]
 		struct skill_unit_group *sg;
 		struct skill_unit_group *sg;
-		if ((sg= skill_locate_element_field(&sd->bl)) != NULL && ( sg->skill_id == SA_VOLCANO || sg->skill_id == SA_DELUGE || sg->skill_id == SA_VIOLENTGALE ))
+		if ((sg= skill_locate_element_field(src)) != NULL && ( sg->skill_id == SA_VOLCANO || sg->skill_id == SA_DELUGE || sg->skill_id == SA_VIOLENTGALE ))
 		{
 		{
 			if (sg->limit - DIFF_TICK(gettick(), sg->tick) > 0)
 			if (sg->limit - DIFF_TICK(gettick(), sg->tick) > 0)
 			{
 			{
@@ -8200,7 +8199,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh
 	require = skill_get_requirement(sd,skill,lv);
 	require = skill_get_requirement(sd,skill,lv);
 
 
 	//Can only update state when weapon/arrow info is checked.
 	//Can only update state when weapon/arrow info is checked.
-	if (require.weapon) sd->state.arrow_atk = require.ammo?1:0;
+	sd->state.arrow_atk = require.ammo?1:0;
 
 
 	// perform skill-specific checks (and actions)
 	// perform skill-specific checks (and actions)
 	switch( skill )
 	switch( skill )
@@ -8834,9 +8833,11 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, short
 
 
 	req.weapon = skill_db[j].weapon;
 	req.weapon = skill_db[j].weapon;
 
 
-	req.ammo = skill_db[j].ammo;
 	req.ammo_qty = skill_db[j].ammo_qty[lv-1];
 	req.ammo_qty = skill_db[j].ammo_qty[lv-1];
-	if (req.weapon && !req.ammo && skill && skill_isammotype(sd, skill))
+	if (req.ammo_qty)
+		req.ammo = skill_db[j].ammo;
+
+	if (!req.ammo && skill && skill_isammotype(sd, skill))
 	{	//Assume this skill is using the weapon, therefore it requires arrows.
 	{	//Assume this skill is using the weapon, therefore it requires arrows.
 		req.ammo = 0xFFFFFFFF; //Enable use on all ammo types.
 		req.ammo = 0xFFFFFFFF; //Enable use on all ammo types.
 		req.ammo_qty = 1;
 		req.ammo_qty = 1;
@@ -11650,9 +11651,9 @@ static bool skill_parse_row_requiredb(char* split[], int columns, int current)
 	for( j = 0; j < 32; j++ )
 	for( j = 0; j < 32; j++ )
 	{
 	{
 		int l = atoi(p);
 		int l = atoi(p);
-		if( l == 99 ) // magic value?
+		if( l == 99 ) // Any weapon
 		{
 		{
-			skill_db[i].weapon = 0xffffffff;
+			skill_db[i].weapon = 0;
 			break;
 			break;
 		}
 		}
 		else
 		else
@@ -11668,12 +11669,12 @@ static bool skill_parse_row_requiredb(char* split[], int columns, int current)
 	for( j = 0; j < 32; j++ )
 	for( j = 0; j < 32; j++ )
 	{
 	{
 		int l = atoi(p);
 		int l = atoi(p);
-		if( l == 99 ) // magic value?
+		if( l == 99 ) // Any ammo type
 		{
 		{
-			skill_db[i].ammo = 0xffffffff;
+			skill_db[i].ammo = 0xFFFFFFFF;
 			break;
 			break;
 		}
 		}
-		else if( l ) // 0 not allowed?
+		else if( l ) // 0 stands for no requirement
 			skill_db[i].ammo |= 1<<l;
 			skill_db[i].ammo |= 1<<l;
 		p = strchr(p,':');
 		p = strchr(p,':');
 		if( !p )
 		if( !p )

+ 32 - 51
src/map/status.c

@@ -656,7 +656,7 @@ int status_charge(struct block_list* bl, int hp, int sp)
 //If flag&1, damage is passive and does not triggers cancelling status changes.
 //If flag&1, damage is passive and does not triggers cancelling status changes.
 //If flag&2, fail if target does not has enough to substract.
 //If flag&2, fail if target does not has enough to substract.
 //If flag&4, if killed, mob must not give exp/loot.
 //If flag&4, if killed, mob must not give exp/loot.
-//If flag&8, sp loss on dead target.
+//flag will be set to &8 when damaging sp of a dead character
 int status_damage(struct block_list *src,struct block_list *target,int hp, int sp, int walkdelay, int flag)
 int status_damage(struct block_list *src,struct block_list *target,int hp, int sp, int walkdelay, int flag)
 {
 {
 	struct status_data *status;
 	struct status_data *status;
@@ -666,18 +666,15 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
 		sp = 0; //Not a valid SP target.
 		sp = 0; //Not a valid SP target.
 
 
 	if (hp < 0) { //Assume absorbed damage.
 	if (hp < 0) { //Assume absorbed damage.
-		status_heal(target, cap_value(-hp, INT_MIN, INT_MAX), 0, 1);
+		status_heal(target, -hp, 0, 1);
 		hp = 0;
 		hp = 0;
 	}
 	}
 
 
 	if (sp < 0) {
 	if (sp < 0) {
-		status_heal(target, 0, cap_value(-sp, INT_MIN, INT_MAX), 1);
+		status_heal(target, 0, -sp, 1);
 		sp = 0;
 		sp = 0;
 	}
 	}
 
 
-	if (!hp && !sp)
-		return 0;
-
 	if (target->type == BL_SKILL)
 	if (target->type == BL_SKILL)
 		return skill_unit_ondamaged((struct skill_unit *)target, src, hp, gettick());
 		return skill_unit_ondamaged((struct skill_unit *)target, src, hp, gettick());
 
 
@@ -685,6 +682,19 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
 	if( status == &dummy_status )
 	if( status == &dummy_status )
 		return 0;
 		return 0;
 
 
+	if ((unsigned int)hp >= status->hp) {
+		if (flag&2) return 0;
+		hp = status->hp;
+	}
+
+	if ((unsigned int)sp > status->sp) {
+		if (flag&2) return 0;
+		sp = status->sp;
+	}
+
+	if (!hp && !sp)
+		return 0;
+
 	if( !status->hp )
 	if( !status->hp )
 		flag |= 8;
 		flag |= 8;
 
 
@@ -694,10 +704,10 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
 //		return 0; //Cannot damage a bl not on a map, except when "charging" hp/sp
 //		return 0; //Cannot damage a bl not on a map, except when "charging" hp/sp
 
 
 	sc = status_get_sc(target);
 	sc = status_get_sc(target);
-	if( battle_config.invincible_nodamage && src && sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] )
+	if( hp && battle_config.invincible_nodamage && src && sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] )
 		hp = 1;
 		hp = 1;
 
 
-	if( hp && !(flag&(1|8)) ) {
+	if( hp && !(flag&1) ) {
 		if( sc ) {
 		if( sc ) {
 			struct status_change_entry *sce;
 			struct status_change_entry *sce;
 			if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE)
 			if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE)
@@ -731,16 +741,6 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
 		unit_skillcastcancel(target, 2);
 		unit_skillcastcancel(target, 2);
 	}
 	}
 
 
-	if ((unsigned int)hp >= status->hp) {
-		if (flag&2) return 0;
-		hp = status->hp;
-	}
-
-	if ((unsigned int)sp > status->sp) {
-		if (flag&2) return 0;
-		sp = status->sp;
-	}
-
 	status->hp-= hp;
 	status->hp-= hp;
 	status->sp-= sp;
 	status->sp-= sp;
 
 
@@ -761,7 +761,7 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
 		case BL_MER: mercenary_damage((TBL_MER*)target,src,hp,sp); break;
 		case BL_MER: mercenary_damage((TBL_MER*)target,src,hp,sp); break;
 	}
 	}
 
 
-	if( status->hp || flag&8 )
+	if( status->hp || (flag&8) )
   	{	//Still lives or has been dead before this damage.
   	{	//Still lives or has been dead before this damage.
 		if (walkdelay)
 		if (walkdelay)
 			unit_set_walkdelay(target, gettick(), walkdelay, 0);
 			unit_set_walkdelay(target, gettick(), walkdelay, 0);
@@ -805,11 +805,11 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
 		}
 		}
 	}
 	}
    
    
-	if( !(flag&8) && sc && sc->data[SC_KAIZEL] )
+	if( sc && sc->data[SC_KAIZEL] )
 	{ //flag&8 = disable Kaizel
 	{ //flag&8 = disable Kaizel
 		int time = skill_get_time2(SL_KAIZEL,sc->data[SC_KAIZEL]->val1);
 		int time = skill_get_time2(SL_KAIZEL,sc->data[SC_KAIZEL]->val1);
 		//Look for Osiris Card's bonus effect on the character and revive 100% or revive normally
 		//Look for Osiris Card's bonus effect on the character and revive 100% or revive normally
-		if ( target->type == BL_PC && BL_CAST(BL_PC,target)->special_state.restart_full_recover == 1 )
+		if ( target->type == BL_PC && BL_CAST(BL_PC,target)->special_state.restart_full_recover )
 			status_revive(target, 100, 100);
 			status_revive(target, 100, 100);
 		else
 		else
 			status_revive(target, sc->data[SC_KAIZEL]->val2, 0);
 			status_revive(target, sc->data[SC_KAIZEL]->val2, 0);
@@ -869,7 +869,7 @@ int status_heal(struct block_list *bl,int hp,int sp, int flag)
 		sc = NULL;
 		sc = NULL;
 
 
 	if (hp < 0) {
 	if (hp < 0) {
-		status_damage(NULL, bl, cap_value(-hp, INT_MIN, INT_MAX), 0, 0, 1);
+		status_damage(NULL, bl, -hp, 0, 0, 1);
 		hp = 0;
 		hp = 0;
 	}
 	}
 
 
@@ -882,7 +882,7 @@ int status_heal(struct block_list *bl,int hp,int sp, int flag)
 	}
 	}
 
 
 	if(sp < 0) {
 	if(sp < 0) {
-		status_damage(NULL, bl, 0, cap_value(-sp, INT_MIN, INT_MAX), 0, 1);
+		status_damage(NULL, bl, 0, -sp, 0, 1);
 		sp = 0;
 		sp = 0;
 	}
 	}
 
 
@@ -1510,24 +1510,14 @@ int status_calc_mob_(struct mob_data* md, bool first)
 		gc=guild_mapname2gc(map[md->bl.m].name);
 		gc=guild_mapname2gc(map[md->bl.m].name);
 		if (!gc)
 		if (!gc)
 			ShowError("status_calc_mob: No castle set at map %s\n", map[md->bl.m].name);
 			ShowError("status_calc_mob: No castle set at map %s\n", map[md->bl.m].name);
-		else {
-			if(gc->castle_id > 23) {
-				if(md->class_ == MOBID_EMPERIUM) {
-					status->max_hp += 1000 * gc->defense;
-					status->max_sp += 200 * gc->defense;
-					status->hp = status->max_hp;
-					status->sp = status->max_sp;
-					status->def += (gc->defense+2)/3;
-					status->mdef += (gc->defense+2)/3;
-				}
-			}else{
-				status->max_hp += 1000 * gc->defense;
-				status->max_sp += 200 * gc->defense;
-				status->hp = status->max_hp;
-				status->sp = status->max_sp;
-				status->def += (gc->defense+2)/3;
-				status->mdef += (gc->defense+2)/3;
-			}
+		else
+		if(gc->castle_id < 24 || md->class_ == MOBID_EMPERIUM) {
+			status->max_hp += 1000 * gc->defense;
+			status->max_sp += 200 * gc->defense;
+			status->hp = status->max_hp;
+			status->sp = status->max_sp;
+			status->def += (gc->defense+2)/3;
+			status->mdef += (gc->defense+2)/3;
 		}
 		}
 		if(md->class_ != MOBID_EMPERIUM) {
 		if(md->class_ != MOBID_EMPERIUM) {
 			status->batk += status->batk * 10*md->guardian_data->guardup_lv/100;
 			status->batk += status->batk * 10*md->guardian_data->guardup_lv/100;
@@ -2693,7 +2683,7 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str
 	if (
 	if (
 		sc->data[SC_DANCING]
 		sc->data[SC_DANCING]
 		|| (
 		|| (
-			(((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK &&
+			(bl->type == BL_PC && ((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK &&
 			(sc->data[SC_EXTREMITYFIST] || (sc->data[SC_EXPLOSIONSPIRITS] && (!sc->data[SC_SPIRIT] || sc->data[SC_SPIRIT]->val2 != SL_MONK)))
 			(sc->data[SC_EXTREMITYFIST] || (sc->data[SC_EXPLOSIONSPIRITS] && (!sc->data[SC_SPIRIT] || sc->data[SC_SPIRIT]->val2 != SL_MONK)))
 			)
 			)
 		|| sc->data[SC_MAXIMIZEPOWER]
 		|| sc->data[SC_MAXIMIZEPOWER]
@@ -7250,15 +7240,6 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
 		}
 		}
 		break;
 		break;
 
 
-	case SC_DEVOTION:
-		//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;
-		
 	case SC_BERSERK:
 	case SC_BERSERK:
 		// 5% every 10 seconds [DracoRPG]
 		// 5% every 10 seconds [DracoRPG]
 		if( --( sce->val3 ) > 0 && status_charge(bl, sce->val2, 0) && status->hp > 100 )
 		if( --( sce->val3 ) > 0 && status_charge(bl, sce->val2, 0) && status->hp > 100 )

+ 1 - 0
src/map/status.h

@@ -8,6 +8,7 @@ struct block_list;
 struct mob_data;
 struct mob_data;
 struct pet_data;
 struct pet_data;
 struct homun_data;
 struct homun_data;
+struct mercenary_data;
 struct status_change;
 struct status_change;
 
 
 //Use this to refer the max refinery level [Skotlex]
 //Use this to refer the max refinery level [Skotlex]