浏览代码

Bug Fixes:
* Follow up 2d2991a, remove trailing spaces in inter_athena.conf
* Added `bound` field on `picklog` table (bugreport:9240) Thank @icxbb-xx (Napster)
* Fixed Randomize Spell infinite loop. Failure of skill improvise db reading. (bugreport:9288)
* Added **max_extended_aspd** for caping max ASPD for KO/Rebellion, default is 193. Pointed by @raynra & Ziu
* Mail attachment
* Added `bound` field on `mail` table, since group with PC_PERM_TRADE_BOUNDED can put bound item into attachment
* Fixed wrong data type causing wrong zeny amount (bugreport:9291)
* Fixed item color issue for bound item (bugreport:9238)
* Stackable item shouldn't be displayed as yellow color
* Equip doesn't shown as yellow after relog or item is moved
* Silence status immunity for Renewal (bugreport:9227)
* Bleeding (SC_BLEEDING): Vit -> Agi
* Silence (SC_SILENCE): Vit -> Int
* Sleep (SC_SLEEP): Int -> Agi
* Thank @Playtester, @Lilith-, partial merge of Hercules:6f26451
* Fixed status check when cast a skill to hidden target
* Stone Curse shouldn't be casted to hidden enemy when the caster has intravision (bugreport:9266)
* Added **INF3_HIT_HIDING** for skills that *maybe* have effect to/can hit the hidden target. Previously, every Earth Element skills *always* had it, doesn't matter ground skill or single-target skill
* **!TODO: Confirm other skills that have ability for this!**
* **!FIXME: For now, I rely as the previous check did, I put some Earth Element skills (and) with area/ground effect**
* Correcting Devotion behavior (Hercules:e7be725, 41f28c0)
* Failing to cast Devotion to the 6th player
* Only player who devotes other that 'shout' Auto Guard when it active also with the walk delay
* Status icon that inherited from devoter won't be displayed at devoted player
* Reflect Damage on devoted player won't reflect normal attack, only melee skill attack
* Added config **devotion_rdamage_skill_only** for backward compability, ignore the behavior above

**IMPORTANT**
* Please import sql-files/upgrades/upgrade_20140915_log.sql
* Please import sql-files/upgrades/upgrade_20140915.sql

Signed-off-by: Cydh Ramdh <house.bad@gmail.com>

Cydh Ramdh 10 年之前
父节点
当前提交
9b4d922ef4

+ 3 - 0
conf/battle/player.conf

@@ -69,6 +69,9 @@ max_aspd: 190
 // Same as max_aspd, but for 3rd classes. (Default 193, Highest allowed 199)
 max_third_aspd: 193
 
+// Max ASPD for extended class (Kagerou/Oboro and Rebellion). (Default 193, Highest allowed 199)
+max_extended_aspd: 193
+
 // Maximum walk speed rate (200 would be capped to twice the normal speed)
 max_walk_speed: 300
 

+ 4 - 0
conf/battle/skill.conf

@@ -187,6 +187,10 @@ devotion_level_difference: 10
 // the damage will be taken by the person who provides devotion instead the attacker.
 devotion_rdamage: 0
 
+// Officially, reflecting shield (SC_REFLECTDAMAGE) reflects physical damage by skill or normal attack.
+// But if the target is being devoted, it ONLY reflects the damage for melee skill. (Note 1)
+devotion_rdamage_skill_only: yes
+
 // If no than you can use the ensemble skills alone. (Note 1)
 player_skill_partner_check: yes
 

+ 3 - 3
conf/inter_athena.conf

@@ -14,9 +14,9 @@ party_share_level: 15
 
 // You can specify the codepage to use in your MySQL tables here.
 // (Note that this feature requires MySQL 4.1+)
-//default_codepage: 
+//default_codepage:
 
-// For IPs, ideally under linux, you want to use localhost instead of 127.0.0.1 
+// For IPs, ideally under linux, you want to use localhost instead of 127.0.0.1
 // Under windows, you want to use 127.0.0.1.  If you see a message like
 // "Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)"
 // and you have localhost, switch it to 127.0.0.1
@@ -37,7 +37,7 @@ login_case_sensitive: no
 ipban_db_ip: 127.0.0.1
 ipban_db_port: 3306
 ipban_db_id: ragnarok
-ipban_db_pw: ragnarok 
+ipban_db_pw: ragnarok
 ipban_db_db: ragnarok
 ipban_codepage:
 

+ 24 - 23
db/pre-re/skill_db.txt

@@ -47,22 +47,23 @@
 // 14 attack type (none, weapon, magic, misc)
 // 15 Blowcount (amount of tiles skill knockbacks)
 // 16 inf3 (skill information 3):
-//    0x0001- skill ignores land protector (e.g. arrow shower)
-//    0x0002- spell that doesn't end camouflage
-//    0x0004- usable skills while hiding
-//    0x0008- spell that can be use while in dancing state
-//    0x0010- spell that could hit emperium
-//    0x0020- spell blocked by statis
-//    0x0040- spell blocked by kagehumi
-//    0x0080- spell range affected by AC_VULTURE
-//    0x0100- spell range affected by GS_SNAKEEYE
-//    0x0200- spell range affected by NJ_SHADOWJUMP
-//    0x0400- spell range affected by WL_RADIUS
-//    0x0800- spell range affected by RA_RESEARCHTRAP
-//    0x1000- Spell that does not affect user that has NC_HOVERING active
-//    0x2000- spell that can be using while riding warg
-//    0x4000- spell that can't be used while in mado
-//    0x8000- spell that can be used to target while under Man Hole effect
+//    0x00001- skill ignores land protector (e.g. arrow shower)
+//    0x00002- spell that doesn't end camouflage
+//    0x00004- usable skills while hiding
+//    0x00008- spell that can be use while in dancing state
+//    0x00010- spell that could hit emperium
+//    0x00020- spell blocked by statis
+//    0x00040- spell blocked by kagehumi
+//    0x00080- spell range affected by AC_VULTURE
+//    0x00100- spell range affected by GS_SNAKEEYE
+//    0x00200- spell range affected by NJ_SHADOWJUMP
+//    0x00400- spell range affected by WL_RADIUS
+//    0x00800- spell range affected by RA_RESEARCHTRAP
+//    0x01000- Spell that does not affect user that has NC_HOVERING active
+//    0x02000- spell that can be using while riding warg
+//    0x04000- spell that can't be used while in mado
+//    0x08000- spell that can be used to target while under Man Hole effect
+//    0x10000- spell that having an affect to hiding target
 // 17 Name
 // 18 Description
 1,0,0,0,0,0,0,9,0,no,0,0,0,none,0,0x0,		NV_BASIC,Basic Skill
@@ -182,8 +183,8 @@
 88,0,6,4,1,0x2,2,10,1,yes,0,0x2000,0,magic,0,0x0,		WZ_FROSTNOVA,Frost Nova
 89,9,6,2,1,0,0,10,1,yes,0,0x2000,0,magic,2,0x20,		WZ_STORMGUST,Storm Gust
 90,9,8,1,2,0,0,5,1:2:3:4:5,yes,0,0x2000,0,magic,0,0x20,	WZ_EARTHSPIKE,Earth Spike
-91,9,8,2,2,0,0,5,1:2:3:4:5,yes,0,0x2000,0,magic,0,0x20,	WZ_HEAVENDRIVE,Heaven's Drive
-92,9,6,2,2,0x1,0,5,1,yes,0,0,3,magic,0,0x1020,		WZ_QUAGMIRE,Quagmire
+91,9,8,2,2,0,0,5,1:2:3:4:5,yes,0,0x2000,0,magic,0,0x10020,	WZ_HEAVENDRIVE,Heaven's Drive
+92,9,6,2,2,0x1,0,5,1,yes,0,0,3,magic,0,0x11020,		WZ_QUAGMIRE,Quagmire
 93,9,6,1,0,0x1,0,1,1,yes,0,0,0,magic,0,0x0,		WZ_ESTIMATION,Sense
 
 //****
@@ -291,7 +292,7 @@
 182,-9,6,1,-1,0,0,5,1,no,0,0x2,0,weapon,0,0x0,	NPC_SLEEPATTACK,Sleep attack
 183,-9,6,1,-3,0,0,10,1,no,0,0x2,0,weapon,0,0x0,	NPC_RANDOMATTACK,Random Attack
 184,-9,6,1,1,0,0,10,1,no,0,0x2,0,weapon,0,0x0,	NPC_WATERATTACK,Water Attribute Attack
-185,-9,6,1,2,0,0,10,1,no,0,0x2,0,weapon,0,0x0,	NPC_GROUNDATTACK,Earth Attribute Attack
+185,-9,6,1,2,0,0,10,1,no,0,0x2,0,weapon,0,0x10000,	NPC_GROUNDATTACK,Earth Attribute Attack
 186,-9,6,1,3,0,0,10,1,no,0,0x2,0,weapon,0,0x0,	NPC_FIREATTACK,Fire Attribute Attack
 187,-9,6,1,4,0,0,10,1,no,0,0x2,0,weapon,0,0x0,	NPC_WINDATTACK,Wind Attribute Attack
 188,-9,6,1,5,0,0,10,1,no,0,0x2,0,weapon,0,0x0,	NPC_POISONATTACK,Poison Attribute Attack
@@ -591,7 +592,7 @@
 // Professor
 402,9,6,1,0,0x1,0,5,1,no,0,0,0,none,0,0x0,		PF_MINDBREAKER,Mind Breaker
 403,0,0,4,0,0x1,0,1,1,yes,0,0,0,magic,0,0x0,		PF_MEMORIZE,Foresight
-404,9,6,2,2,0x1,0,5,1,yes,0,0x100,2,magic,0,0x20,	PF_FOGWALL,Blinding Mist
+404,9,6,2,2,0x1,0,5,1,yes,0,0x100,2,magic,0,0x10020,	PF_FOGWALL,Blinding Mist
 405,7,6,1,0,0x1,0,1,1,no,0,0,3,magic,0,0x20,		PF_SPIDERWEB,Fiber Lock
 
 //****
@@ -918,7 +919,7 @@
 2213,11,8,2,0,0x2,9,5,-20,yes,0,0,0,magic,2,0x400,	WL_COMET,Comet
 2214,11,6,1,0,0x2,3,5,1,yes,0,0,0,magic,0,0x400,		WL_CHAINLIGHTNING,Chain Lightning //CHECK Is the splash being used for the target search?
 2215,11,6,1,4,0,0,5,1,no,0,0,0,magic,0,0x0,		WL_CHAINLIGHTNING_ATK,Chain Lightning Attack
-2216,6,8,2,2,0,0,5,-6:-7:-8:-9:-10,yes,0,0,0,magic,0,0x20,	WL_EARTHSTRAIN,Earth Strain
+2216,6,8,2,2,0,0,5,-6:-7:-8:-9:-10,yes,0,0,0,magic,0,0x10020,	WL_EARTHSTRAIN,Earth Strain
 2217,11,6,1,0,0,0,5,1,yes,0,0,0,magic,0,0x400,	WL_TETRAVORTEX,Tetra Vortex
 2218,11,6,1,3,0,0,5,1,no,0,0,0,magic,0,0x0,		WL_TETRAVORTEX_FIRE,Tetra Vortex Fire
 2219,11,6,1,1,0,0,5,1,no,0,0,0,magic,0,0x0,		WL_TETRAVORTEX_WATER,Tetra Vortex Water
@@ -1081,7 +1082,7 @@
 2320,0,6,4,-1,0x2,3,5,1,yes,0,0,0,weapon,0,0x1000,	LG_MOONSLASHER,Moon Slasher
 2321,1,8,2,6,0x2,5,5,-7,yes,0,0,0,weapon,0,0x0,	LG_RAYOFGENESIS,Ray of Genesis
 2322,0,6,16,0,0x3,1,5,1,yes,0,0,0,none,0,0x0,	LG_PIETY,Piety
-2323,0,8,4,2,0x2,1:1:2:2:3,5,-5,yes,0,0,0,weapon,0,0x0,	LG_EARTHDRIVE,Earth Drive
+2323,0,8,4,2,0x2,1:1:2:2:3,5,-5,yes,0,0,0,weapon,0,0x10000,	LG_EARTHDRIVE,Earth Drive
 2324,3,8,1,-1,0,0,5,3,yes,0,0,0,weapon,0,0x0,	LG_HESPERUSLIT,Hesperus Lit
 2325,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0,	LG_INSPIRATION,Inspiration
 2519,1,6,1,-1,0x2,0,5,1,yes,0,0,0,weapon,3:4:5:6:7,0x0, LG_OVERBRAND_BRANDISH,Overbrand Brandish
@@ -1160,7 +1161,7 @@
 2443,0,6,4,3,0,0,5,1,yes,0,0,8:10:12:14:16,magic,0,0x1020,	SO_FIREWALK,Fire Walk //CHECK Video and data shows each cell only hits once.
 2444,0,6,4,4,0,0,5,1,yes,0,0,8:10:12:14:16,magic,0,0x1020,	SO_ELECTRICWALK,Electric Walk
 2445,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x20,		SO_SPELLFIST,Spell Fist
-2446,9,6,2,2,0,0,5,-3,yes,0,0,0,magic,0,0x20,	SO_EARTHGRAVE,Earth Grave
+2446,9,6,2,2,0,0,5,-3,yes,0,0,0,magic,0,0x10020,	SO_EARTHGRAVE,Earth Grave
 2447,9,6,2,1,0,0,5,-5,yes,0,0,0,magic,0,0x20,	SO_DIAMONDDUST,Diamond Dust
 2448,9,6,1,5,0x2,1:1:1:1:2,5,1,yes,0,0,0,magic,0,0x20,	SO_POISON_BUSTER,Poison Buster
 2449,9,6,2,0,0,0,5,1,yes,0,0,0,magic,0,0x20,		SO_PSYCHIC_WAVE,Psychic Wave

+ 24 - 23
db/re/skill_db.txt

@@ -47,22 +47,23 @@
 // 14 attack type (none, weapon, magic, misc)
 // 15 Blowcount (amount of tiles skill knockbacks)
 // 16 inf3 (skill information 3):
-//    0x0001- skill ignores land protector (e.g. arrow shower)
-//    0x0002- spell that doesn't end camouflage
-//    0x0004- usable skills while hiding
-//    0x0008- spell that can be use while in dancing state
-//    0x0010- spell that could hit emperium
-//    0x0020- spell blocked by statis
-//    0x0040- spell blocked by kagehumi
-//    0x0080- spell range affected by AC_VULTURE
-//    0x0100- spell range affected by GS_SNAKEEYE
-//    0x0200- spell range affected by NJ_SHADOWJUMP
-//    0x0400- spell range affected by WL_RADIUS
-//    0x0800- spell range affected by RA_RESEARCHTRAP
-//    0x1000- Spell that does not affect user that has NC_HOVERING active
-//    0x2000- spell that can be using while riding warg
-//    0x4000- spell that can't be used while in mado
-//    0x8000- spell that can be used to target while under Man Hole effect
+//    0x00001- skill ignores land protector (e.g. arrow shower)
+//    0x00002- spell that doesn't end camouflage
+//    0x00004- usable skills while hiding
+//    0x00008- spell that can be use while in dancing state
+//    0x00010- spell that could hit emperium
+//    0x00020- spell blocked by statis
+//    0x00040- spell blocked by kagehumi
+//    0x00080- spell range affected by AC_VULTURE
+//    0x00100- spell range affected by GS_SNAKEEYE
+//    0x00200- spell range affected by NJ_SHADOWJUMP
+//    0x00400- spell range affected by WL_RADIUS
+//    0x00800- spell range affected by RA_RESEARCHTRAP
+//    0x01000- Spell that does not affect user that has NC_HOVERING active
+//    0x02000- spell that can be using while riding warg
+//    0x04000- spell that can't be used while in mado
+//    0x08000- spell that can be used to target while under Man Hole effect
+//    0x10000- spell that having an affect to hiding target
 // 17 Name
 // 18 Description
 1,0,0,0,0,0,0,9,0,no,0,0,0,none,0,0x0,		NV_BASIC,Basic Skill
@@ -182,8 +183,8 @@
 88,0,6,4,1,0x2,2,10,1,yes,0,0x2000,0,magic,0,0x0,	WZ_FROSTNOVA,Frost Nova
 89,9,6,2,1,0,0,10,1,yes,0,0x2000,0,magic,2,0x20,		WZ_STORMGUST,Storm Gust
 90,9,8,1,2,0,0,5,1:2:3:4:5,yes,0,0x2000,0,magic,0,0x20,	WZ_EARTHSPIKE,Earth Spike
-91,9,8,2,2,0,0,5,1:2:3:4:5,yes,0,0x2000,0,magic,0,0x20,	WZ_HEAVENDRIVE,Heaven's Drive
-92,9,6,2,2,0x1,0,5,1,yes,0,0,3,magic,0,0x1020,		WZ_QUAGMIRE,Quagmire
+91,9,8,2,2,0,0,5,1:2:3:4:5,yes,0,0x2000,0,magic,0,0x10020,	WZ_HEAVENDRIVE,Heaven's Drive
+92,9,6,2,2,0x1,0,5,1,yes,0,0,3,magic,0,0x11020,		WZ_QUAGMIRE,Quagmire
 93,9,6,1,0,0x1,0,1,1,yes,0,0,0,magic,0,0x0,		WZ_ESTIMATION,Sense
 
 //****
@@ -291,7 +292,7 @@
 182,-9,6,1,-1,0,0,5,1,no,0,0x2,0,weapon,0,0x0,	NPC_SLEEPATTACK,Sleep attack
 183,-9,6,1,-3,0,0,10,1,no,0,0x2,0,weapon,0,0x0,	NPC_RANDOMATTACK,Random Attack
 184,-9,6,1,1,0,0,10,1,no,0,0x2,0,weapon,0,0x0,	NPC_WATERATTACK,Water Attribute Attack
-185,-9,6,1,2,0,0,10,1,no,0,0x2,0,weapon,0,0x0,	NPC_GROUNDATTACK,Earth Attribute Attack
+185,-9,6,1,2,0,0,10,1,no,0,0x2,0,weapon,0,0x10000,	NPC_GROUNDATTACK,Earth Attribute Attack
 186,-9,6,1,3,0,0,10,1,no,0,0x2,0,weapon,0,0x0,	NPC_FIREATTACK,Fire Attribute Attack
 187,-9,6,1,4,0,0,10,1,no,0,0x2,0,weapon,0,0x0,	NPC_WINDATTACK,Wind Attribute Attack
 188,-9,6,1,5,0,0,10,1,no,0,0x2,0,weapon,0,0x0,	NPC_POISONATTACK,Poison Attribute Attack
@@ -591,7 +592,7 @@
 // Professor
 402,9,6,1,0,0x1,0,5,1,no,0,0,0,none,0,0x0,		PF_MINDBREAKER,Mind Breaker
 403,0,0,4,0,0x1,0,1,1,yes,0,0,0,magic,0,0x0,		PF_MEMORIZE,Foresight
-404,9,6,2,2,0x1,0,5,1,yes,0,0x100,2,magic,0,0x20,	PF_FOGWALL,Blinding Mist
+404,9,6,2,2,0x1,0,5,1,yes,0,0x100,2,magic,0,0x10020,	PF_FOGWALL,Blinding Mist
 405,7,6,1,0,0x1,0,1,1,no,0,0,3,magic,0,0x20,		PF_SPIDERWEB,Fiber Lock
 
 //****
@@ -918,7 +919,7 @@
 2213,11,8,2,0,0x2,9,5,-20,yes,0,0,0,magic,2,0x400,	WL_COMET,Comet
 2214,11,6,1,0,0x2,3,5,1,yes,0,0,0,magic,0,0x400,		WL_CHAINLIGHTNING,Chain Lightning //CHECK Is the splash being used for the target search?
 2215,11,6,1,4,0,0,5,1,no,0,0,0,magic,0,0x0,		WL_CHAINLIGHTNING_ATK,Chain Lightning Attack
-2216,6,8,2,2,0,0,5,-6:-7:-8:-9:-10,yes,0,0,0,magic,0,0x20,	WL_EARTHSTRAIN,Earth Strain
+2216,6,8,2,2,0,0,5,-6:-7:-8:-9:-10,yes,0,0,0,magic,0,0x10020,	WL_EARTHSTRAIN,Earth Strain
 2217,11,6,1,0,0,0,5,1,yes,0,0,0,magic,0,0x400,	WL_TETRAVORTEX,Tetra Vortex
 2218,11,6,1,3,0,0,5,1,no,0,0,0,magic,0,0x0,		WL_TETRAVORTEX_FIRE,Tetra Vortex Fire
 2219,11,6,1,1,0,0,5,1,no,0,0,0,magic,0,0x0,		WL_TETRAVORTEX_WATER,Tetra Vortex Water
@@ -1081,7 +1082,7 @@
 2320,0,6,4,-1,0x2,3,5,1,yes,0,0,0,weapon,0,0x1000,	LG_MOONSLASHER,Moon Slasher
 2321,1,8,2,6,0x2,5,5,-7,yes,0,0,0,weapon,0,0x0,	LG_RAYOFGENESIS,Ray of Genesis
 2322,0,6,16,0,0x3,1,5,1,yes,0,0,0,none,0,0x0,	LG_PIETY,Piety
-2323,0,8,4,2,0x2,1:1:2:2:3,5,-5,yes,0,0,0,weapon,0,0x0,	LG_EARTHDRIVE,Earth Drive
+2323,0,8,4,2,0x2,1:1:2:2:3,5,-5,yes,0,0,0,weapon,0,0x10000,	LG_EARTHDRIVE,Earth Drive
 2324,3,8,1,-1,0,0,5,3,yes,0,0,0,weapon,0,0x0,	LG_HESPERUSLIT,Hesperus Lit
 2325,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0,	LG_INSPIRATION,Inspiration
 2519,1,6,1,-1,0x2,0,5,1,yes,0,0,0,weapon,3:4:5:6:7,0x0, LG_OVERBRAND_BRANDISH,Overbrand Brandish
@@ -1160,7 +1161,7 @@
 2443,0,6,4,3,0,0,5,1,yes,0,0,8:10:12:14:16,magic,0,0x1020,	SO_FIREWALK,Fire Walk //CHECK Video and data shows each cell only hits once.
 2444,0,6,4,4,0,0,5,1,yes,0,0,8:10:12:14:16,magic,0,0x1020,	SO_ELECTRICWALK,Electric Walk
 2445,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x20,		SO_SPELLFIST,Spell Fist
-2446,9,6,2,2,0,0,5,-3,yes,0,0,0,magic,0,0x20,	SO_EARTHGRAVE,Earth Grave
+2446,9,6,2,2,0,0,5,-3,yes,0,0,0,magic,0,0x10020,	SO_EARTHGRAVE,Earth Grave
 2447,9,6,2,1,0,0,5,-5,yes,0,0,0,magic,0,0x20,	SO_DIAMONDDUST,Diamond Dust
 2448,9,6,1,5,0x2,1:1:1:1:2,5,1,yes,0,0,0,magic,0,0x20,	SO_POISON_BUSTER,Poison Buster
 2449,9,6,2,0,0,0,5,1,yes,0,0,0,magic,0,0x20,		SO_PSYCHIC_WAVE,Psychic Wave

+ 1 - 0
sql-files/logs.sql

@@ -20,6 +20,7 @@ CREATE TABLE IF NOT EXISTS `picklog` (
   `card3` smallint(5) unsigned NOT NULL default '0',
   `unique_id` bigint(20) unsigned NOT NULL default '0',
   `map` varchar(11) NOT NULL default '',
+  `bound` tinyint(1) unsigned NOT NULL default '0',
   PRIMARY KEY  (`id`),
   INDEX (`type`)
 ) ENGINE=MyISAM AUTO_INCREMENT=1 ;

+ 1 - 0
sql-files/main.sql

@@ -528,6 +528,7 @@ CREATE TABLE IF NOT EXISTS `mail` (
   `card2` smallint(5) unsigned NOT NULL default '0',
   `card3` smallint(5) unsigned NOT NULL default '0',
   `unique_id` bigint(20) unsigned NOT NULL default '0',
+  `bound` tinyint(1) unsigned NOT NULL default '0',
   PRIMARY KEY  (`id`)
 ) ENGINE=MyISAM;
 

+ 1 - 0
sql-files/upgrades/upgrade_20140915.sql

@@ -0,0 +1 @@
+ALTER TABLE `mail` ADD `bound` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0';

+ 1 - 0
sql-files/upgrades/upgrade_20140915_log.sql

@@ -0,0 +1 @@
+ALTER TABLE `picklog` ADD `bound` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0';

+ 2 - 3
src/char/char.c

@@ -2245,7 +2245,7 @@ bool char_checkdb(void){
 	//checking mail_db
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT  `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,"
 			"`title`,`message`,`time`,`status`,`zeny`,`nameid`,`amount`,`refine`,`attribute`,`identify`,"
-			"`card0`,`card1`,`card2`,`card3`,`unique_id`"
+			"`card0`,`card1`,`card2`,`card3`,`unique_id`, `bound`"
 			" from `%s`;", schema_config.mail_db) ){
 		Sql_ShowDebug(sql_handle);
 		return false;
@@ -2276,8 +2276,7 @@ bool char_checkdb(void){
 		return false;
 	}
 	//checking mercenary_db
-	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT  `mer_id`,`char_id`,`class`,`hp`,`sp`,`kill_counter`,`life_time` "
-                                                " from `%s`;", schema_config.mercenary_db) ){
+	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT  `mer_id`,`char_id`,`class`,`hp`,`sp`,`kill_counter`,`life_time` from `%s`;", schema_config.mercenary_db) ){
 		Sql_ShowDebug(sql_handle);
 		return false;
 	}

+ 9 - 9
src/char/int_mail.c

@@ -29,7 +29,7 @@ static int mail_fromsql(int char_id, struct mail_data* md)
 
 	StringBuf_Init(&buf);
 	StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`,"
-		"`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`,`unique_id`");
+		"`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`,`unique_id`,`bound`");
 	for (i = 0; i < MAX_SLOTS; i++)
 		StringBuf_Printf(&buf, ",`card%d`", i);
 
@@ -64,12 +64,12 @@ static int mail_fromsql(int char_id, struct mail_data* md)
 		Sql_GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data);
 		Sql_GetData(sql_handle,14, &data, NULL); item->identify = atoi(data);
 		Sql_GetData(sql_handle,15, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
+		Sql_GetData(sql_handle,16, &data, NULL); item->bound = atoi(data);
 		item->expire_time = 0;
-		item->bound = 0;
 
 		for (j = 0; j < MAX_SLOTS; j++)
 		{
-			Sql_GetData(sql_handle, 16 + j, &data, NULL);
+			Sql_GetData(sql_handle, 17 + j, &data, NULL);
 			item->card[j] = atoi(data);
 		}
 	}
@@ -110,11 +110,11 @@ int mail_savemessage(struct mail_message* msg)
 
 	// build message save query
 	StringBuf_Init(&buf);
-	StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`, `unique_id`", schema_config.mail_db);
+	StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`, `unique_id`, `bound`", schema_config.mail_db);
 	for (j = 0; j < MAX_SLOTS; j++)
 		StringBuf_Printf(&buf, ", `card%d`", j);
-	StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%d', '%d', '%d', '%hu', '%d', '%d', '%d', '%"PRIu64"'",
-		msg->send_id, msg->dest_id, (unsigned long)msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify, msg->item.unique_id);
+	StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%d', '%d', '%d', '%hu', '%d', '%d', '%d', '%"PRIu64"', '%d'",
+		msg->send_id, msg->dest_id, (unsigned long)msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify, msg->item.unique_id, msg->item.bound);
 	for (j = 0; j < MAX_SLOTS; j++)
 		StringBuf_Printf(&buf, ", '%hu'", msg->item.card[j]);
 	StringBuf_AppendStr(&buf, ")");
@@ -148,7 +148,7 @@ static bool mail_loadmessage(int mail_id, struct mail_message* msg)
 
 	StringBuf_Init(&buf);
 	StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`,"
-		"`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`,`unique_id`");
+		"`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`,`unique_id`,`bound`");
 	for( j = 0; j < MAX_SLOTS; j++ )
 		StringBuf_Printf(&buf, ",`card%d`", j);
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `id` = '%d'", schema_config.mail_db, mail_id);
@@ -181,12 +181,12 @@ static bool mail_loadmessage(int mail_id, struct mail_message* msg)
 		Sql_GetData(sql_handle,13, &data, NULL); msg->item.attribute = atoi(data);
 		Sql_GetData(sql_handle,14, &data, NULL); msg->item.identify = atoi(data);
 		Sql_GetData(sql_handle,15, &data, NULL); msg->item.unique_id = strtoull(data, NULL, 10);
+		Sql_GetData(sql_handle,16, &data, NULL); msg->item.bound = atoi(data);
 		msg->item.expire_time = 0;
-		msg->item.bound = BOUND_NONE;
 
 		for( j = 0; j < MAX_SLOTS; j++ )
 		{
-			Sql_GetData(sql_handle,16 + j, &data, NULL);
+			Sql_GetData(sql_handle,17 + j, &data, NULL);
 			msg->item.card[j] = atoi(data);
 		}
 	}

+ 4 - 1
src/common/mmo.h

@@ -796,7 +796,10 @@ enum bound_type {
 	BOUND_GUILD, /// 2 - Guild Bound
 	BOUND_PARTY, /// 3 - Party Bound
 	BOUND_CHAR, /// 4 - Character Bound
-	BOUND_MAX
+	BOUND_MAX,
+
+	//BOUND_ONEQUIP = 1, //! TODO
+	BOUND_DISPYELLOW = 2, /// Shows the item name in yellow color
 };
 
 // sanity checks...

+ 69 - 43
src/map/battle.c

@@ -845,9 +845,21 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 			sc_start2(src,bl,SC_COMBO,100,GC_WEAPONBLOCKING,src->id,2000);
 			return 0;
 		}
-		if( (sce=sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON && !(skill_get_nk(skill_id)&NK_NO_CARDFIX_ATK) && rnd()%100 < sce->val2 ) {
+		if( (sce = sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON && !(skill_get_nk(skill_id)&NK_NO_CARDFIX_ATK) && rnd()%100 < sce->val2 ) {
 			int delay;
-			clif_skill_nodamage(bl,bl,CR_AUTOGUARD,sce->val1,1);
+			struct block_list *d_bl = NULL;
+			struct status_change_entry *sce_d = NULL;
+			bool devoted = false;
+
+			if ((sce_d = sc->data[SC_DEVOTION]) && (d_bl = map_id2bl(sce_d->val1)) &&
+				((d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == bl->id) ||
+				(d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce_d->val2] == bl->id)))
+			{ // if player is target of devotion, show guard effect on the devotion caster rather than the target
+				devoted = true;
+				clif_skill_nodamage(d_bl, d_bl, CR_AUTOGUARD, sce->val1, 1);
+			} else
+				clif_skill_nodamage(bl, bl, CR_AUTOGUARD,sce->val1, 1);
+
 			// different delay depending on skill level [celest]
 			if (sce->val1 <= 5)
 				delay = 300;
@@ -855,7 +867,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 				delay = 200;
 			else
 				delay = 100;
-			unit_set_walkdelay(bl, gettick(), delay, 1);
+			unit_set_walkdelay((devoted ? d_bl : bl), gettick(), delay, 1);
 
 			if(sc->data[SC_SHRINK] && rnd()%100<5*sce->val1)
 				skill_blown(bl,src,skill_get_blewcount(CR_SHRINK,1),-1,0);
@@ -4705,6 +4717,22 @@ static struct Damage initialize_weapon_data(struct block_list *src, struct block
 	return wd;
 }
 
+/**
+* Check if bl is devoted by someone
+* @param bl
+* @return 'd_bl' if devoted or NULL if not devoted
+*/
+struct block_list *battle_check_devotion(struct block_list *bl) {
+	struct block_list *d_bl = NULL;
+
+	if (battle_config.devotion_rdamage && battle_config.devotion_rdamage > rand()%100) {
+		struct status_change *sc = status_get_sc(bl);
+		if (sc && sc->data[SC_DEVOTION])
+			d_bl = map_id2bl(sc->data[SC_DEVOTION]->val1);
+	}
+	return d_bl;
+}
+
 /*
  * Check if we should reflect the damage and calculate it if so
  * @param attack_type : BL_WEAPON,BL_MAGIC or BL_MISC
@@ -4727,47 +4755,35 @@ void battle_do_reflect(int attack_type, struct Damage *wd, struct block_list* sr
 		int tick = gettick(), rdelay = 0;
 
 		// Item reflect gets calculated first
-		rdamage = battle_calc_return_damage(target, src, &damage, wd->flag, skill_id, 0);
+		rdamage = battle_calc_return_damage(target, src, &damage, wd->flag, skill_id, false);
 		if( rdamage > 0 ) {
-			bool isDevotRdamage = false;
-			//Get info if the attacker has Devotion from other player
-			struct block_list *d_bl = NULL;
-			if (battle_config.devotion_rdamage && battle_config.devotion_rdamage > rand()%100) {
-				struct status_change *ssc = status_get_sc(src);
-				if (ssc && ssc->data[SC_DEVOTION] && (d_bl = map_id2bl(ssc->data[SC_DEVOTION]->val1)))
-					isDevotRdamage = true;
-			}
-			rdelay = clif_damage(src, (!isDevotRdamage) ? src : d_bl, tick, wd->amotion, sstatus->dmotion, rdamage, 1, DMG_ENDURE, 0);
+			struct block_list *d_bl = battle_check_devotion(src);
+
+			rdelay = clif_damage(src, (!d_bl) ? src : d_bl, tick, wd->amotion, sstatus->dmotion, rdamage, 1, DMG_ENDURE, 0);
 			if( tsd )
 				battle_drain(tsd, src, rdamage, rdamage, sstatus->race, sstatus->class_);
 			//Use Reflect Shield to signal this kind of skill trigger. [Skotlex]
-			battle_delay_damage(tick, wd->amotion,target,(!isDevotRdamage) ? src : d_bl,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true);
-			skill_additional_effect(target, (!isDevotRdamage) ? src : d_bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick);
+			battle_delay_damage(tick, wd->amotion,target,(!d_bl) ? src : d_bl, 0, CR_REFLECTSHIELD, 0, rdamage, ATK_DEF, rdelay, true);
+			skill_additional_effect(target, (!d_bl) ? src : d_bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL, ATK_DEF, tick);
 		}
 
+		if (!tsc)
+			return;
+
 		// Calculate skill reflect damage separately
-		if( tsc ) {
-			struct status_data *tstatus = status_get_status_data(target);
-			rdamage = battle_calc_return_damage(target, src, &damage, wd->flag, skill_id, 1);
-			if( rdamage > 0 ) {
-				bool isDevotRdamage = false;
-				//Get info if the attacker has Devotion from other player			
-				struct block_list *d_bl = NULL;
-				if (battle_config.devotion_rdamage && battle_config.devotion_rdamage > rand()%100) {
-					struct status_change *ssc = status_get_sc(src);;
-					if (ssc && ssc->data[SC_DEVOTION] && (d_bl = map_id2bl(ssc->data[SC_DEVOTION]->val1)))
-						isDevotRdamage = true;
-				}
-				if( attack_type == BF_WEAPON && tsc->data[SC_REFLECTDAMAGE] ) // Don't reflect your own damage (Grand Cross)
-					map_foreachinshootrange(battle_damage_area,target,skill_get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,target,wd->amotion,sstatus->dmotion,rdamage,tstatus->race);
-				else if( attack_type == BF_WEAPON || attack_type == BF_MISC) {
-					rdelay = clif_damage(src, (!isDevotRdamage) ? src : d_bl, tick, wd->amotion, sstatus->dmotion, rdamage, 1, DMG_ENDURE, 0);
-					if( tsd )
-						battle_drain(tsd, src, rdamage, rdamage, sstatus->race, sstatus->class_);
-					// It appears that official servers give skill reflect damage a longer delay
-					battle_delay_damage(tick, wd->amotion,target,(!isDevotRdamage) ? src : d_bl,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true);
-					skill_additional_effect(target, (!isDevotRdamage) ? src : d_bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick);
-				}
+		rdamage = battle_calc_return_damage(target, src, &damage, wd->flag, skill_id,true);
+		if( rdamage > 0 ) {
+			struct block_list *d_bl = battle_check_devotion(src);
+			
+			if( attack_type == BF_WEAPON && tsc->data[SC_REFLECTDAMAGE] ) // Don't reflect your own damage (Grand Cross)
+				map_foreachinshootrange(battle_damage_area,target,skill_get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,target,wd->amotion,sstatus->dmotion,rdamage,status_get_race(target));
+			else if( attack_type == BF_WEAPON || attack_type == BF_MISC) {
+				rdelay = clif_damage(src, (!d_bl) ? src : d_bl, tick, wd->amotion, sstatus->dmotion, rdamage, 1, DMG_ENDURE, 0);
+				if( tsd )
+					battle_drain(tsd, src, rdamage, rdamage, sstatus->race, sstatus->class_);
+				// It appears that official servers give skill reflect damage a longer delay
+				battle_delay_damage(tick, wd->amotion, target, (!d_bl) ? src : d_bl, 0, CR_REFLECTSHIELD, 0, rdamage, ATK_DEF, rdelay ,true);
+				skill_additional_effect(target, (!d_bl) ? src : d_bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL, ATK_DEF, tick);
 			}
 		}
 	}
@@ -6323,7 +6339,8 @@ int64 battle_calc_return_damage(struct block_list* bl, struct block_list *src, i
 	if (flag & BF_SHORT) {//Bounces back part of the damage.
 		if ( !status_reflect && sd && sd->bonus.short_weapon_damage_return ) {
 			rdamage += damage * sd->bonus.short_weapon_damage_return / 100;
-			if(rdamage < 1) rdamage = 1;
+			if(rdamage < 1)
+				rdamage = 1;
 		} else if( status_reflect && sc && sc->count ) {
 			if( sc->data[SC_REFLECTDAMAGE] && !(skill_get_inf2(skill_id)&INF2_TRAP)) {
 				if( rnd()%100 <= sc->data[SC_REFLECTDAMAGE]->val1*10 + 30 ){
@@ -6334,8 +6351,14 @@ int64 battle_calc_return_damage(struct block_list* bl, struct block_list *src, i
 				}
 			} else {
 				if ( sc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION ) {
-					rdamage += damage * sc->data[SC_REFLECTSHIELD]->val2 / 100;
-					if (rdamage < 1) rdamage = 1;
+					// Don't reflect non-skill attack if has SC_REFLECTSHIELD from Devotion bonus inheritance
+					if (!skill_id && battle_config.devotion_rdamage_skill_only && sc->data[SC_REFLECTSHIELD]->val4)
+						rdamage = 0;
+					else {
+						rdamage += damage * sc->data[SC_REFLECTSHIELD]->val2 / 100;
+						if (rdamage < 1)
+							rdamage = 1;
+					}
 				}
 
 				if(sc->data[SC_DEATHBOUND] && skill_id != WS_CARTTERMINATION && !(src->type == BL_MOB && is_boss(src)) ) {
@@ -6846,9 +6869,9 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
 					}
 
 					if( type != CAST_GROUND ){
-							clif_skill_fail(sd,r_skill,USESKILL_FAIL_LEVEL,0);
-							map_freeblock_unlock();
-							return wd.dmg_lv;
+						clif_skill_fail(sd,r_skill,USESKILL_FAIL_LEVEL,0);
+						map_freeblock_unlock();
+						return wd.dmg_lv;
 					}
 				}
 
@@ -7799,6 +7822,8 @@ static const struct _battle_data {
 	{ "idletime_option",                    &battle_config.idletime_option,                 0x25,   1,      INT_MAX,        },
 	{ "spawn_direction",                    &battle_config.spawn_direction,                 0,      0,      1,              },
 	{ "arrow_shower_knockback",             &battle_config.arrow_shower_knockback,          1,      0,      1,              },
+	{ "devotion_rdamage_skill_only",        &battle_config.devotion_rdamage_skill_only,     1,      0,      1,              },
+	{ "max_extended_aspd",                  &battle_config.max_extended_aspd,               193,    100,    199,            },
 };
 #ifndef STATS_OPT_OUT
 /**
@@ -7982,6 +8007,7 @@ void battle_adjust_conf()
 	battle_config.monster_max_aspd = 2000 - battle_config.monster_max_aspd * 10;
 	battle_config.max_aspd = 2000 - battle_config.max_aspd * 10;
 	battle_config.max_third_aspd = 2000 - battle_config.max_third_aspd * 10;
+	battle_config.max_extended_aspd = 2000 - battle_config.max_extended_aspd * 10;
 	battle_config.max_walk_speed = 100 * DEFAULT_WALK_SPEED / battle_config.max_walk_speed;
 	battle_config.max_cart_weight *= 10;
 

+ 2 - 0
src/map/battle.h

@@ -568,6 +568,8 @@ extern struct Battle_Config
 	int idletime_option;
 	int spawn_direction;
 	int arrow_shower_knockback;
+	int devotion_rdamage_skill_only;
+	int max_extended_aspd;
 } battle_config;
 
 void do_init_battle(void);

+ 98 - 87
src/map/clif.c

@@ -2250,7 +2250,8 @@ void clif_additem(struct map_session_data *sd, int n, int amount, unsigned char
 		WFIFOL(fd,offs+23)=sd->status.inventory[n].expire_time;
 #endif
 #if PACKETVER >= 20071002
-		WFIFOW(fd,offs+27)=sd->status.inventory[n].bound ? BOUND_GUILD : 0;
+		/* Yellow color only for non-stackable item */
+		WFIFOW(fd,offs+27)=sd->status.inventory[n].bound && !itemdb_isstackable(sd->status.inventory[n].nameid) ? BOUND_DISPYELLOW : 0;
 #endif
 	}
 
@@ -2306,67 +2307,67 @@ void clif_delitem(struct map_session_data *sd,int n,int amount, short reason)
 #endif
 }
 
-void clif_item_sub_v5(unsigned char *buf, int n, int idx, struct item *i, struct item_data *id, int equip) {
+void clif_item_sub_v5(unsigned char *buf, int n, int idx, struct item *it, struct item_data *id, int equip) {
 	char normal = (equip < 0);
 
-	WBUFW(buf,n)=idx; //index
-	WBUFW(buf,n+2)= (id->view_id > 0)?id->view_id:i->nameid;
-	WBUFB(buf,n+4)=itemtype(id->nameid);
-
-	if(!normal){ //equip 31B
-		WBUFL(buf,n+5)= equip; //location
-		WBUFL(buf,n+9)= i->equip; //wear state
-		WBUFB(buf,n+13)= i->refine; //refine lvl
-		clif_addcards(WBUFP(buf, n+14), i); //EQUIPSLOTINFO 8B
-		WBUFL(buf,n+22) = i->expire_time;
-		WBUFW(buf,n+26)= 0; //bindOnEquipType
-		WBUFW(buf,n+28)= (id->equip&EQP_VISIBLE)?id->look:0;
+	WBUFW(buf,n) = idx; //index
+	WBUFW(buf,n+2) = (id->view_id > 0) ? id->view_id : it->nameid;
+	WBUFB(buf,n+4) = itemtype(id->nameid);
+
+	if (!normal){ //equip 31B
+		WBUFL(buf,n+5) = equip; //location
+		WBUFL(buf,n+9) = it->equip; //wear state
+		WBUFB(buf,n+13) = it->refine; //refine lvl
+		clif_addcards(WBUFP(buf, n+14), it); //EQUIPSLOTINFO 8B
+		WBUFL(buf,n+22) = it->expire_time;
+		WBUFW(buf,n+26) = it->bound ? BOUND_DISPYELLOW : 0; //bindOnEquipType
+		WBUFW(buf,n+28) = (id->equip&EQP_VISIBLE) ? id->look : 0;
 		//V5_ITEM_flag
-		WBUFB(buf,n+30)=i->identify; //0x1 IsIdentified
-		WBUFB(buf,n+30)|=(i->attribute)?0x2:0; //0x2 IsDamaged
-		WBUFB(buf,n+30)|= (i->favorite)?0x4:0; //0x4 PlaceETCTab
+		WBUFB(buf,n+30) = it->identify; //0x1 IsIdentified
+		WBUFB(buf,n+30) |= (it->attribute) ? 0x2 : 0; //0x2 IsDamaged
+		WBUFB(buf,n+30) |= (it->favorite) ? 0x4 : 0; //0x4 PlaceETCTab
 	}
 	else { //normal 24B
-		WBUFW(buf,n+5)=i->amount;
-		WBUFL(buf,n+7)=(equip == -2 && id->equip == EQP_AMMO)?id->equip:0; //wear state
-		clif_addcards(WBUFP(buf, n+11), i); //EQUIPSLOTINFO 8B
-		WBUFL(buf,n+19) = i->expire_time;
+		WBUFW(buf,n+5) = it->amount;
+		WBUFL(buf,n+7) = (equip == -2 && id->equip == EQP_AMMO)?id->equip:0; //wear state
+		clif_addcards(WBUFP(buf, n+11), it); //EQUIPSLOTINFO 8B
+		WBUFL(buf,n+19) = it->expire_time;
 		//V5_ITEM_flag
-		WBUFB(buf,n+23)=i->identify; //0x1 IsIdentified
-		WBUFB(buf,n+23)|= (i->favorite)?0x2:0; //0x4,0x2 PlaceETCTab
+		WBUFB(buf,n+23) = it->identify; //0x1 IsIdentified
+		WBUFB(buf,n+23) |= (it->favorite) ? 0x2 : 0; //0x4,0x2 PlaceETCTab
 	}
 }
 
 // Simplifies inventory/cart/storage packets by handling the packet section relevant to items. [Skotlex]
 // Equip is >= 0 for equippable items (holds the equip-point, is 0 for pet
 // armor/egg) -1 for stackable items, -2 for stackable items where arrows must send in the equip-point.
-void clif_item_sub(unsigned char *buf, int n, int idx, struct item *i, struct item_data *id, int equip) {
+void clif_item_sub(unsigned char *buf, int n, int idx, struct item *it, struct item_data *id, int equip) {
 #if PACKETVER >= 20120925
-	clif_item_sub_v5(buf, n, idx, i, id, equip);
+	clif_item_sub_v5(buf, n, idx, it, id, equip);
 #else
-	WBUFW(buf,n)=idx; //index
-	WBUFW(buf,n+2)=(id->view_id > 0)?id->view_id:i->nameid; //itid
-	WBUFB(buf,n+4)=itemtype(id->nameid);
-	WBUFB(buf,n+5)=i->identify;
+	WBUFW(buf,n) = idx; //index
+	WBUFW(buf,n+2) = (id->view_id > 0) ? id->view_id : it->nameid; //itid
+	WBUFB(buf,n+4) = itemtype(id->nameid);
+	WBUFB(buf,n+5) = it->identify;
 	if (equip >= 0) { //Equippable item 28.B
-		WBUFW(buf,n+6)=equip;
-		WBUFW(buf,n+8)=i->equip;
-		WBUFB(buf,n+10)=i->attribute;
-		WBUFB(buf,n+11)=i->refine;
-		clif_addcards(WBUFP(buf, n+12), i); //8B
+		WBUFW(buf,n+6) = equip;
+		WBUFW(buf,n+8) = it->equip;
+		WBUFB(buf,n+10) = it->attribute;
+		WBUFB(buf,n+11) = it->refine;
+		clif_addcards(WBUFP(buf, n+12), it); //8B
 #if PACKETVER >= 20071002
-		WBUFL(buf,n+20)=i->expire_time;
-		WBUFW(buf,n+24)=i->bound ? BOUND_GUILD : 0;
+		WBUFL(buf,n+20) = it->expire_time;
+		WBUFW(buf,n+24) = it->bound ? BOUND_DISPYELLOW : 0;
 #endif
 #if PACKETVER >= 20100629
-		WBUFW(buf,n+26)= (id->equip&EQP_VISIBLE)?id->look:0;
+		WBUFW(buf,n+26) = (id->equip&EQP_VISIBLE) ? id->look : 0;
 #endif
 	} else { //Stackable item. 22.B
-		WBUFW(buf,n+6)=i->amount;
-		WBUFW(buf,n+8)=(equip == -2 && id->equip == EQP_AMMO)?id->equip:0;
-		clif_addcards(WBUFP(buf, n+10), i); //8B
+		WBUFW(buf,n+6) = it->amount;
+		WBUFW(buf,n+8) = (equip == -2 && id->equip == EQP_AMMO) ? id->equip : 0;
+		clif_addcards(WBUFP(buf, n+10), it); //8B
 #if PACKETVER >= 20071002
-		WBUFL(buf,n+18)=i->expire_time;
+		WBUFL(buf,n+18) = it->expire_time;
 #endif
 	}
 #endif
@@ -4171,11 +4172,13 @@ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_d
 		clif_hpmeter_single(sd->fd, dstsd->bl.id, dstsd->battle_status.hp, dstsd->battle_status.max_hp);
 
 	// display link (sd - dstsd) to sd
-	ARR_FIND( 0, 5, i, sd->devotion[i] == dstsd->bl.id );
-	if( i < 5 ) clif_devotion(&sd->bl, sd);
+	ARR_FIND( 0, MAX_DEVOTION, i, sd->devotion[i] == dstsd->bl.id );
+	if( i < MAX_DEVOTION )
+		clif_devotion(&sd->bl, sd);
 	// display links (dstsd - devotees) to sd
-	ARR_FIND( 0, 5, i, dstsd->devotion[i] > 0 );
-	if( i < 5 ) clif_devotion(&dstsd->bl, sd);
+	ARR_FIND( 0, MAX_DEVOTION, i, dstsd->devotion[i] > 0 );
+	if( i < MAX_DEVOTION )
+		clif_devotion(&dstsd->bl, sd);
 	// display link (dstsd - crusader) to sd
 	if( dstsd->sc.data[SC_DEVOTION] && (d_bl = map_id2bl(dstsd->sc.data[SC_DEVOTION]->val1)) != NULL )
 		clif_devotion(d_bl, sd);
@@ -7331,7 +7334,7 @@ void clif_devotion(struct block_list *src, struct map_session_data *tsd)
 		if( sd == NULL )
 			return;
 
-		for( i = 0; i < 5; i++ )
+		for( i = 0; i < 5 /*MAX_DEVOTION*/; i++ ) // Client only able show to 5 links
 			WBUFL(buf,6+4*i) = sd->devotion[i];
 		WBUFW(buf,26) = skill_get_range2(src, CR_DEVOTION, pc_checkskill(sd, CR_DEVOTION));
 	}
@@ -13140,50 +13143,56 @@ void clif_parse_GMRecall2(int fd, struct map_session_data* sd)
 /// 09ce <item/mob name>.100B [Ind/Yommy]
 void clif_parse_GM_Item_Monster(int fd, struct map_session_data *sd)
 {
-	int i, count;
-	char *item_monster_name;
-	struct item_data *item_array[10];
-	struct mob_db *mob_array[10];
-	char command[256];
-#if PACKETVER >= 20131218
-	char str[100];
-#else
-	char str[24];
-#endif
-
-	item_monster_name = str;
-	item_monster_name[(sizeof(str) - 2) - 1] = '\0';
-
-	if( (count = itemdb_searchname_array(item_array, 10, item_monster_name)) > 0 ) {
-		for( i = 0; i < count; i++ )
-			if( !item_array[i] )
-				continue;
-
-		if( i < count ) {
-			if( item_array[i]->type == IT_WEAPON || item_array[i]->type == IT_ARMOR ) //Nonstackable
-				safesnprintf(command, sizeof(command) - 1, "%citem2 %d 1 0 0 0 0 0 0 0", atcommand_symbol, item_array[i]->nameid);
-			else
-				safesnprintf(command, sizeof(command) - 1, "%citem %d 20", atcommand_symbol, item_array[i]->nameid);
-			is_atcommand(fd, sd, command, 1);
-			return;
-		}
-	}
-
-	if( strcmp(item_monster_name, "money") == 0 ) {
-		safesnprintf(command, sizeof(command) - 1, "%czeny %d", atcommand_symbol, INT_MAX);
-		is_atcommand(fd, sd, command, 1);
+	struct s_packet_db* info = &packet_db[sd->packet_ver][RFIFOW(fd,0)];
+	int mob_id = 0;
+	struct item_data *id = NULL;
+	struct mob_db *mob = NULL;
+	StringBuf command;
+	char *str;
+//#if PACKETVER >= 20131218
+//	char str[100];
+//#else
+//	char str[24];
+//#endif
+
+	str = (char*)RFIFOP(fd,info->pos[0]);
+	if (!str || str[0] == '\0')
+		return;
+	if (strcmpi(str,"SPPOINT") == 0 || strcmpi(str,"JOBLEVEL") == 0) //! TODO /sp sends these values
+		return;
+	trim(str);
+
+	// Zeny
+	if( strcmpi(str, "money") == 0 ) {
+		StringBuf_Init(&command);
+		StringBuf_Printf(&command, "%czeny %d", atcommand_symbol, INT_MAX);
+		is_atcommand(fd, sd, StringBuf_Value(&command), 1);
+		StringBuf_Destroy(&command);
+		return;
+	}
+
+	// Item
+	if( (id = itemdb_searchname(str)) ) {
+		StringBuf_Init(&command);
+		if( id->type == IT_WEAPON || id->type == IT_ARMOR ) //Nonstackable
+			StringBuf_Printf(&command, "%citem2 %d 1 0 0 0 0 0 0 0", atcommand_symbol, id->nameid);
+		else
+			StringBuf_Printf(&command, "%citem %d 20", atcommand_symbol, id->nameid);
+		is_atcommand(fd, sd, StringBuf_Value(&command), 1);
+		StringBuf_Destroy(&command);
 		return;
 	}
 
-	if( (count = mobdb_searchname_array(mob_array, 10, item_monster_name)) > 0 ) {
-		for( i = 0; i < count; i++ )
-			if( !mob_array[i] )
-				continue;
+	// Monster
+	if ((mob_id = mobdb_searchname(str)) == 0)
+		mob_id = mobdb_checkid(atoi(str));
 
-		if( i < count ) {
-			safesnprintf(command, sizeof(command) - 1, "%cmonster %s", atcommand_symbol, mob_array[i]->sprite);
-			is_atcommand(fd, sd, command, 1);
-		}
+	if( (mob = mob_db(mob_id)) ) {
+		StringBuf_Init(&command);
+		StringBuf_Printf(&command, "%cmonster %s", atcommand_symbol, mob->sprite);
+		is_atcommand(fd, sd, StringBuf_Value(&command), 1);
+		StringBuf_Destroy(&command);
+		return;
 	}
 }
 
@@ -14722,8 +14731,10 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd){
 
 	if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time ||
 			!sd->status.inventory[idx].identify ||
+			(sd->status.inventory[idx].bound && !pc_can_give_bounded_items(sd)) ||
 			!itemdb_available(sd->status.inventory[idx].nameid) ||
-			!itemdb_canauction(&sd->status.inventory[idx],pc_get_group_level(sd)) ) { // Quest Item or something else
+			!itemdb_canauction(&sd->status.inventory[idx],pc_get_group_level(sd)) // Quest Item or something else
+			) {
 		clif_Auction_setitem(sd->fd, idx, true);
 		return;
 	}

+ 5 - 5
src/map/log.c

@@ -201,12 +201,12 @@ void log_pick(int id, int16 m, e_log_pick_type type, int amount, struct item* it
 #ifdef BETA_THREAD_TEST
 		char entry[512];
 		int e_length = 0;
-		e_length = sprintf(entry, LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`, `unique_id`) VALUES (NOW(), '%d', '%c', '%hu', '%d', '%d', '%hu', '%hu', '%hu', '%hu', '%s', '%"PRIu64"')",
-				log_config.log_pick, id, log_picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], map[m].name?map[m].name:"", itm->unique_id);
+		e_length = sprintf(entry, LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`, `unique_id`, `bound`) VALUES (NOW(), '%d', '%c', '%hu', '%d', '%d', '%hu', '%hu', '%hu', '%hu', '%s', '%"PRIu64"', '%d')",
+				log_config.log_pick, id, log_picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], map[m].name?map[m].name:"", itm->unique_id, itm->bound);
 		queryThread_log(entry,e_length);
 #else
-		if( SQL_ERROR == Sql_Query(logmysql_handle, LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`, `unique_id`) VALUES (NOW(), '%d', '%c', '%hu', '%d', '%d', '%hu', '%hu', '%hu', '%hu', '%s', '%"PRIu64"')",
-			log_config.log_pick, id, log_picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], map[m].name?map[m].name:"", itm->unique_id) )
+		if( SQL_ERROR == Sql_Query(logmysql_handle, LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`, `unique_id`, `bound`) VALUES (NOW(), '%d', '%c', '%hu', '%d', '%d', '%hu', '%hu', '%hu', '%hu', '%s', '%"PRIu64"', '%d')",
+			log_config.log_pick, id, log_picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], map[m].name?map[m].name:"", itm->unique_id, itm->bound) )
 		{
 			Sql_ShowDebug(logmysql_handle);
 			return;
@@ -223,7 +223,7 @@ void log_pick(int id, int16 m, e_log_pick_type type, int amount, struct item* it
 			return;
 		time(&curtime);
 		strftime(timestring, sizeof(timestring), "%m/%d/%Y %H:%M:%S", localtime(&curtime));
-		fprintf(logfp,"%s - %d\t%c\t%hu,%d,%d,%hu,%hu,%hu,%hu,%s,'%"PRIu64"'\n", timestring, id, log_picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], map[m].name?map[m].name:"", itm->unique_id);
+		fprintf(logfp,"%s - %d\t%c\t%hu,%d,%d,%hu,%hu,%hu,%hu,%s,'%"PRIu64"',%d\n", timestring, id, log_picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], map[m].name?map[m].name:"", itm->unique_id, itm->bound);
 		fclose(logfp);
 	}
 }

+ 1 - 1
src/map/mail.c

@@ -64,7 +64,7 @@ int mail_removezeny(struct map_session_data *sd, short flag)
 * @param amount
 * @return True if item/zeny can be set, False if failed
 */
-bool mail_setitem(struct map_session_data *sd, short idx, unsigned short amount) {
+bool mail_setitem(struct map_session_data *sd, short idx, int amount) {
 
 	if( pc_istrading(sd) )
 		return false;

+ 1 - 1
src/map/mail.h

@@ -9,7 +9,7 @@
 void mail_clear(struct map_session_data *sd);
 int mail_removeitem(struct map_session_data *sd, short flag);
 int mail_removezeny(struct map_session_data *sd, short flag);
-bool mail_setitem(struct map_session_data *sd, short idx, unsigned short amount);
+bool mail_setitem(struct map_session_data *sd, short idx, int amount);
 bool mail_setattachment(struct map_session_data *sd, struct mail_message *msg);
 void mail_getattachment(struct map_session_data* sd, int zeny, struct item* item);
 int mail_openmail(struct map_session_data *sd);

+ 14 - 1
src/map/pc.c

@@ -7197,13 +7197,14 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 		}
 	}
 
-	for(k = 0; k < 5; k++)
+	for(k = 0; k < MAX_DEVOTION; k++) {
 		if (sd->devotion[k]){
 			struct map_session_data *devsd = map_id2sd(sd->devotion[k]);
 			if (devsd)
 				status_change_end(&devsd->bl, SC_DEVOTION, INVALID_TIMER);
 			sd->devotion[k] = 0;
 		}
+	}
 	if(sd->shadowform_id) { //if we were target of shadowform
 		status_change_end(map_id2bl(sd->shadowform_id), SC__SHADOWFORM, INVALID_TIMER);
 		sd->shadowform_id = 0; //should be remove on status end anyway
@@ -11142,6 +11143,18 @@ short pc_maxparameter(struct map_session_data *sd, enum e_params param) {
 		((class_&JOBL_UPPER) ? battle_config.max_trans_parameter : battle_config.max_parameter)));
 }
 
+/**
+* Get max ASPD for player based on Class
+* @param sd Player
+* @return ASPD
+*/
+short pc_maxaspd(struct map_session_data *sd) {
+	nullpo_ret(sd);
+
+	return (( sd->class_&JOBL_THIRD) ? battle_config.max_third_aspd : (
+			((sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO || (sd->class_&MAPID_UPPERMASK) == MAPID_REBELLION) ? battle_config.max_extended_aspd :
+			battle_config.max_aspd ));
+}
 
 /**
 * Calculates total item-group related bonuses for the given item

+ 8 - 6
src/map/pc.h

@@ -21,11 +21,12 @@
 #include "log.h"
 #include "pc_groups.h"
 
-#define MAX_PC_BONUS 10
-#define MAX_PC_SKILL_REQUIRE 5
-#define MAX_PC_FEELHATE 3
-#define DAMAGELOG_SIZE_PC 100	// Any idea for this value?
-#define MAX_SPIRITBALL 15
+#define MAX_PC_BONUS 10 /// Max bonus, usually used by item bonus
+#define MAX_PC_SKILL_REQUIRE 5 /// Max skill tree requirement
+#define MAX_PC_FEELHATE 3 /// Max feel hate info
+#define DAMAGELOG_SIZE_PC 100	/// Damage log
+#define MAX_SPIRITBALL 15 /// Max spirit balls
+#define MAX_DEVOTION 5 /// Max Devotion slots
 
 //Update this max as necessary. 55 is the value needed for Super Baby currently
 //Raised to 84 since Expanded Super Novice needs it.
@@ -442,7 +443,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 account IDs of chars devoted to.
+	int devotion[MAX_DEVOTION]; //Stores the account IDs of chars devoted to.
 	int reg_num; //Number of registries (type numeric)
 	int regstr_num; //Number of registries (type string)
 
@@ -759,6 +760,7 @@ enum e_params {
 	PARAM_MAX
 };
 short pc_maxparameter(struct map_session_data *sd, enum e_params param);
+short pc_maxaspd(struct map_session_data *sd);
 
 /**
  * Ranger

+ 53 - 49
src/map/skill.c

@@ -5781,6 +5781,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 	case SA_ABRACADABRA:
 		{
 			int abra_skill_id = 0, abra_skill_lv;
+			if (!skill_abra_count) {
+				clif_skill_nodamage (src, bl, skill_id, skill_lv, 1);
+				break;
+			}
 			do {
 				i = rnd() % MAX_SKILL_ABRA_DB;
 				abra_skill_id = skill_abra_db[i].skill_id;
@@ -6345,7 +6349,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			}
 
 			i = 0;
-			count = (sd)? min(skill_lv,5) : 1; // Mercenary only can Devote owner
+			count = (sd)? min(skill_lv,MAX_DEVOTION) : 1; // Mercenary only can Devote owner
 			if( sd )
 			{ // Player Devoting Player
 				ARR_FIND(0, count, i, sd->devotion[i] == bl->id );
@@ -6366,7 +6370,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 				mer->devotion_flag = 1; // Mercenary Devoting Owner
 
 			clif_skill_nodamage(src, bl, skill_id, skill_lv,
-				sc_start4(src, bl, type, 100, src->id, i, skill_get_range2(src,skill_id,skill_lv),0, skill_get_time2(skill_id, skill_lv)));
+				sc_start4(src, bl, type, 10000, src->id, i, skill_get_range2(src,skill_id,skill_lv), 0, skill_get_time2(skill_id, skill_lv)));
 			clif_devotion(src, NULL);
 		}
 		break;
@@ -9562,6 +9566,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 
 	case WM_RANDOMIZESPELL: {
 			int improv_skill_id = 0, improv_skill_lv;
+			if (!skill_improvise_count) {
+				clif_skill_nodamage (src, bl, skill_id, skill_lv, 1);
+				break;
+			}
 			do {
 				i = rnd() % MAX_SKILL_IMPROVISE_DB;
 				improv_skill_id = skill_improvise_db[i].skill_id;
@@ -12366,7 +12374,7 @@ static int skill_unit_onplace (struct skill_unit *unit, struct block_list *bl, u
 
 	sc = status_get_sc(bl);
 
-	if (sc && sc->option&OPTION_HIDE && sg->skill_id != WZ_HEAVENDRIVE && sg->skill_id != WL_EARTHSTRAIN)
+	if (sc && sc->option&OPTION_HIDE && !(skill_get_inf3(sg->skill_id)&INF3_HIT_HIDING))
 		return 0; //Hidden characters are immune to AoE skills except to these. [Skotlex]
 
 	if (sc && sc->data[SC_VACUUM_EXTREME] && map_getcell(bl->m, bl->x, bl->y, CELL_CHKLANDPROTECTOR))
@@ -19861,34 +19869,33 @@ static bool skill_parse_row_producedb(char* split[], int columns, int current) {
 * SourceID,MakeID1,MakeAmount1,...,MakeID5,MakeAmount5
 */
 static bool skill_parse_row_createarrowdb(char* split[], int columns, int current) {
-	unsigned short x, y, j;
-	unsigned short material_id = atoi(split[0]);
+	unsigned short x, y, i, material_id = atoi(split[0]);
 
 	if (!(itemdb_exists(material_id))) {
 		ShowError("skill_parse_row_createarrowdb: Invalid item %d.\n", material_id);
 		return false;
 	}
 
-	//search if we override something, (if not j=last idx)
-	ARR_FIND(0, skill_arrow_count, j, skill_arrow_db[j].nameid == material_id);
-	if (j >= ARRAYLENGTH(skill_arrow_db)) {
+	//search if we override something, (if not i=last idx)
+	ARR_FIND(0, skill_arrow_count, i, skill_arrow_db[i].nameid == material_id);
+	if (i >= ARRAYLENGTH(skill_arrow_db)) {
 		ShowError("skill_parse_row_createarrowdb: Maximum db entries reached.\n");
 		return false;
 	}
 
 	// Import just for clearing/disabling from original data
 	if (atoi(split[1]) == 0) {
-		memset(&skill_arrow_db[j], 0, sizeof(skill_arrow_db[j]));
+		memset(&skill_arrow_db[i], 0, sizeof(skill_arrow_db[i]));
 		//ShowInfo("skill_parse_row_createarrowdb: Arrow creation with Material ID %d removed from list.\n", material_id);
 		return true;
 	}
 
-	skill_arrow_db[j].nameid = material_id;
+	skill_arrow_db[i].nameid = material_id;
 	for (x = 1, y = 0; x+1 < columns && split[x] && split[x+1] && y < MAX_ARROW_RESULT; x += 2, y++) {
-		skill_arrow_db[j].cre_id[y] = atoi(split[x]);
-		skill_arrow_db[j].cre_amount[y] = atoi(split[x+1]);
+		skill_arrow_db[i].cre_id[y] = atoi(split[x]);
+		skill_arrow_db[i].cre_amount[y] = atoi(split[x+1]);
 	}
-	if (j == skill_arrow_count)
+	if (i == skill_arrow_count)
 		skill_arrow_count++;
 
 	return true;
@@ -19898,33 +19905,33 @@ static bool skill_parse_row_createarrowdb(char* split[], int columns, int curren
 * SkillID,PreservePoints,RequiredBook
 */
 static bool skill_parse_row_spellbookdb(char* split[], int columns, int current) {
-	unsigned short j;
-	unsigned short skill_id = atoi(split[0]);
-	unsigned short points = atoi(split[1]);
-	unsigned short nameid = atoi(split[2]);
+	unsigned short i,
+		skill_id = atoi(split[0]),
+		points = atoi(split[1]),
+		nameid = atoi(split[2]);
 
 	if (!skill_get_index(skill_id) || !skill_get_max(skill_id))
 		ShowError("skill_parse_row_spellbookdb: Invalid skill ID %d\n", skill_id);
 	if (!skill_get_inf(skill_id))
 		ShowError("skill_parse_row_spellbookdb: Passive skills cannot be memorized (%d/%s)\n", skill_id, skill_get_name(skill_id));
 	else {
-		ARR_FIND(0, skill_spellbook_count, j, skill_spellbook_db[j].skill_id == skill_id);
-		if (j >= ARRAYLENGTH(skill_spellbook_db)) {
+		ARR_FIND(0, skill_spellbook_count, i, skill_spellbook_db[i].skill_id == skill_id);
+		if (i >= ARRAYLENGTH(skill_spellbook_db)) {
 			ShowError("skill_parse_row_spellbookdb: Maximum db entries reached.\n");
 			return false;
 		}
 		// Import just for clearing/disabling from original data
 		if (points == 0) {
-			memset(&skill_spellbook_db[j], 0, sizeof(skill_spellbook_db[j]));
+			memset(&skill_spellbook_db[i], 0, sizeof(skill_spellbook_db[i]));
 			//ShowInfo("skill_parse_row_spellbookdb: Skill %d removed from list.\n", skill_id);
 			return true;
 		}
 
-		skill_spellbook_db[j].skill_id = skill_id;
-		skill_spellbook_db[j].point = points;
-		skill_spellbook_db[j].nameid = nameid;
+		skill_spellbook_db[i].skill_id = skill_id;
+		skill_spellbook_db[i].point = points;
+		skill_spellbook_db[i].nameid = nameid;
 
-		if (j == skill_spellbook_count)
+		if (i == skill_spellbook_count)
 			skill_spellbook_count++;
 		return true;
 	}
@@ -19937,8 +19944,7 @@ static bool skill_parse_row_spellbookdb(char* split[], int columns, int current)
 * SkillID,Rate
 */
 static bool skill_parse_row_improvisedb(char* split[], int columns, int current) {
-	uint16 skill_id = atoi(split[0]);
-	unsigned short j = atoi(split[1]);
+	unsigned short skill_id = atoi(split[0]), per = atoi(split[1]), i;
 
 	if( !skill_get_index(skill_id) || !skill_get_max(skill_id) ) {
 		ShowError("skill_parse_row_improvisedb: Invalid skill ID %d\n", skill_id);
@@ -19948,22 +19954,22 @@ static bool skill_parse_row_improvisedb(char* split[], int columns, int current)
 		ShowError("skill_parse_row_improvisedb: Passive skills cannot be casted (%d/%s)\n", skill_id, skill_get_name(skill_id));
 		return false;
 	}
-	ARR_FIND(0, skill_improvise_count, j, skill_improvise_db[j].skill_id == skill_id);
-	if (j >= ARRAYLENGTH(skill_improvise_db)) {
+	ARR_FIND(0, skill_improvise_count, i, skill_improvise_db[i].skill_id == skill_id);
+	if (i >= ARRAYLENGTH(skill_improvise_db)) {
 		ShowError("skill_parse_row_improvisedb: Maximum amount of entries reached (%d), increase MAX_SKILL_IMPROVISE_DB\n",MAX_SKILL_IMPROVISE_DB);
 		return false;
 	}
 	// Import just for clearing/disabling from original data
-	if (j == 0) {
-		memset(&skill_improvise_db[j], 0, sizeof(skill_improvise_db[j]));
+	if (per == 0) {
+		memset(&skill_improvise_db[i], 0, sizeof(skill_improvise_db[i]));
 		//ShowInfo("skill_parse_row_improvisedb: Skill %d removed from list.\n", skill_id);
 		return true;
 	}
 
-	skill_improvise_db[j].skill_id = skill_id;
-	skill_improvise_db[j].per = j; // Still need confirm it.
+	skill_improvise_db[i].skill_id = skill_id;
+	skill_improvise_db[i].per = per; // Still need confirm it.
 	
-	if (j == skill_improvise_count)
+	if (i == skill_improvise_count)
 		skill_improvise_count++;
 	
 	return true;
@@ -19973,8 +19979,7 @@ static bool skill_parse_row_improvisedb(char* split[], int columns, int current)
 * SkillID{,<RemoveFlag>}
 */
 static bool skill_parse_row_magicmushroomdb(char* split[], int column, int current) {
-	int j;
-	uint16 skill_id = atoi(split[0]);
+	unsigned short i, skill_id = atoi(split[0]);
 
 	if (!skill_get_index(skill_id) || !skill_get_max(skill_id)) {
 		ShowError("skill_parse_row_magicmushroomdb: Invalid skill ID %d\n", skill_id);
@@ -19984,20 +19989,20 @@ static bool skill_parse_row_magicmushroomdb(char* split[], int column, int curre
 		ShowError("skill_parse_row_magicmushroomdb: Passive skills cannot be casted (%d/%s)\n", skill_id, skill_get_name(skill_id));
 		return false;
 	}
-	ARR_FIND(0, skill_magicmushroom_count, j, skill_magicmushroom_db[j].skill_id==skill_id);
-	if (j >= ARRAYLENGTH(skill_magicmushroom_db)) {
+	ARR_FIND(0, skill_magicmushroom_count, i, skill_magicmushroom_db[i].skill_id==skill_id);
+	if (i >= ARRAYLENGTH(skill_magicmushroom_db)) {
 		ShowError("skill_parse_row_magicmushroomdb: Maximum db entries reached.\n");
 		return false;
 	}
 	// Import just for clearing/disabling from original data
 	if (split[1] != NULL) {
-		memset(&skill_magicmushroom_db[j], 0, sizeof(skill_magicmushroom_db[j]));
+		memset(&skill_magicmushroom_db[i], 0, sizeof(skill_magicmushroom_db[i]));
 		//ShowInfo("skill_parse_row_magicmushroomdb: Skill %d removed from list.\n", skill_id);
 		return true;
 	}
 
-	skill_magicmushroom_db[j].skill_id = skill_id;	
-	if (j == skill_magicmushroom_count)
+	skill_magicmushroom_db[i].skill_id = skill_id;	
+	if (i == skill_magicmushroom_count)
 		skill_magicmushroom_count++;
 
 	return true;
@@ -20067,8 +20072,7 @@ static bool skill_parse_row_nonearnpcrangedb(char* split[], int column, int curr
 * SkillID,DummyName,RatePerLvl
 */
 static bool skill_parse_row_abradb(char* split[], int columns, int current) {
-	int j;
-	uint16 skill_id = atoi(split[0]);
+	unsigned short i, skill_id = atoi(split[0]);
 	if (!skill_get_index(skill_id) || !skill_get_max(skill_id)) {
 		ShowError("skill_parse_row_abradb: Invalid skill ID %d\n", skill_id);
 		return false;
@@ -20078,22 +20082,22 @@ static bool skill_parse_row_abradb(char* split[], int columns, int current) {
 		return false;
 	}
 
-	ARR_FIND(0, skill_abra_count, j, skill_abra_db[j].skill_id==skill_id);
-	if (j >= ARRAYLENGTH(skill_abra_db)) {
+	ARR_FIND(0, skill_abra_count, i, skill_abra_db[i].skill_id==skill_id);
+	if (i >= ARRAYLENGTH(skill_abra_db)) {
 		ShowError("skill_parse_row_abradb: Maximum db entries reached.\n");
 		return false;
 	}
 	// Import just for clearing/disabling from original data
 	if (strcmp(split[1],"clear") == 0) {
-		memset(&skill_abra_db[j], 0, sizeof(skill_abra_db[j]));
+		memset(&skill_abra_db[i], 0, sizeof(skill_abra_db[i]));
 		//ShowInfo("skill_parse_row_abradb: Skill %d removed from list.\n", skill_id);
 		return true;
 	}
 
-	skill_abra_db[j].skill_id = skill_id;
-	safestrncpy(skill_abra_db[j].name, trim(split[1]), sizeof(skill_abra_db[j].name)); //store dummyname
-	skill_split_atoi(split[2],skill_abra_db[j].per);
-	if (j == skill_abra_count)
+	skill_abra_db[i].skill_id = skill_id;
+	safestrncpy(skill_abra_db[i].name, trim(split[1]), sizeof(skill_abra_db[i].name)); //store dummyname
+	skill_split_atoi(split[2],skill_abra_db[i].per);
+	if (i == skill_abra_count)
 		skill_abra_count++;
 
 	return true;

+ 17 - 16
src/map/skill.h

@@ -76,22 +76,23 @@ enum e_skill_inf2 {
 
 /// Skill info type 3
 enum e_skill_inf3 {
-	INF3_NOLP				= 0x0001,	// Spells that can ignore Land Protector
-	INF3_NOENDCAMOUFLAGE	= 0x0002,	// spell that doesn't end camouflage
-	INF3_USABLE_HIDING		= 0x0004,	// spell that can be use in hiding
-	INF3_USABLE_DANCE		= 0x0008,	// spell that can be use while in dancing state
-	INF3_HIT_EMP			= 0x0010,	// spell that could hit emperium
-	INF3_STATIS_BL			= 0x0020,	// spell blocked by statis
-	INF3_KAGEHUMI_BL		= 0x0040,	// spell blocked by kagehumi
-	INF3_EFF_VULTURE		= 0x0080,	// spell range affected by AC_VULTURE
-	INF3_EFF_SNAKEEYE		= 0x0100,	// spell range affected by GS_SNAKEEYE
-	INF3_EFF_SHADOWJUMP		= 0x0200,	// spell range affected by NJ_SHADOWJUMP
-	INF3_EFF_RADIUS			= 0x0400,	// spell range affected by WL_RADIUS
-	INF3_EFF_RESEARCHTRAP	= 0x0800,	// spell range affected by RA_RESEARCHTRAP
-	INF3_NO_EFF_HOVERING	= 0x1000,	// Spell that does not affect user that has SC_HOVERING active
-	INF3_USABLE_WARG		= 0x2000,	// spell that can be use while riding warg
-	INF3_DIS_MADO			= 0x4000,	// spell that can't be used while in mado
-	INF3_USABLE_MANHOLE		= 0x8000,	// spell that can be used to target while under Man Hole effect
+	INF3_NOLP				= 0x00001,	// Spells that can ignore Land Protector
+	INF3_NOENDCAMOUFLAGE	= 0x00002,	// spell that doesn't end camouflage
+	INF3_USABLE_HIDING		= 0x00004,	// spell that can be use in hiding
+	INF3_USABLE_DANCE		= 0x00008,	// spell that can be use while in dancing state
+	INF3_HIT_EMP			= 0x00010,	// spell that could hit emperium
+	INF3_STATIS_BL			= 0x00020,	// spell blocked by statis
+	INF3_KAGEHUMI_BL		= 0x00040,	// spell blocked by kagehumi
+	INF3_EFF_VULTURE		= 0x00080,	// spell range affected by AC_VULTURE
+	INF3_EFF_SNAKEEYE		= 0x00100,	// spell range affected by GS_SNAKEEYE
+	INF3_EFF_SHADOWJUMP		= 0x00200,	// spell range affected by NJ_SHADOWJUMP
+	INF3_EFF_RADIUS			= 0x00400,	// spell range affected by WL_RADIUS
+	INF3_EFF_RESEARCHTRAP	= 0x00800,	// spell range affected by RA_RESEARCHTRAP
+	INF3_NO_EFF_HOVERING	= 0x01000,	// Spell that does not affect user that has SC_HOVERING active
+	INF3_USABLE_WARG		= 0x02000,	// spell that can be use while riding warg
+	INF3_DIS_MADO			= 0x04000,	// spell that can't be used while in mado
+	INF3_USABLE_MANHOLE		= 0x08000,	// spell that can be used to target while under Man Hole effect
+	INF3_HIT_HIDING			= 0x10000,	// spell that having an affect to hiding target
 	//... add other spell list option here
 };
 

+ 120 - 87
src/map/status.c

@@ -1755,28 +1755,28 @@ int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per
 *		1 - Cast bar is done
 *		2 - Skill already pulled off, check is due to ground-based skills or splash-damage ones
 * @return src can use skill (1) or cannot use skill (0)
+* @author [Skotlex]
 **/
-int status_check_skilluse(struct block_list *src, struct block_list *target, uint16 skill_id, int flag)
-{
+bool status_check_skilluse(struct block_list *src, struct block_list *target, uint16 skill_id, int flag) {
 	struct status_data *status;
-	struct status_change *sc=NULL, *tsc;
+	struct status_change *sc = NULL, *tsc;
 	int hide_flag;
 
-	status = src?status_get_status_data(src):&dummy_status;
+	status = src ? status_get_status_data(src) : &dummy_status;
 
 	if (src && src->type != BL_PC && status_isdead(src))
-		return 0;
+		return false;
 
 	if (!skill_id) { // Normal attack checks.
 		// This mode is only needed for melee attacking.
 		if (!(status->mode&MD_CANATTACK))
-			return 0;
+			return false;
 		// Dead state is not checked for skills as some skills can be used
 		// on dead characters, said checks are left to skill.c [Skotlex]
 		if (target && status_isdead(target))
-			return 0;
+			return false;
 		if( src && (sc = status_get_sc(src)) && sc->data[SC_CRYSTALIZE] && src->type != BL_MOB)
-			return 0;
+			return false;
 	}
 
 	switch( skill_id ) {
@@ -1785,12 +1785,12 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin
 				// Gloria Avoids pretty much everything....
 				tsc = status_get_sc(target);
 				if(tsc && tsc->option&OPTION_HIDE)
-					return 0;
+					return false;
 			}
 			break;
 		case GN_WALLOFTHORN:
 			if( target && status_isdead(target) )
-				return 0;
+				return false;
 			break;
 		case AL_TELEPORT:
 		case ALL_ODINS_POWER:
@@ -1798,25 +1798,30 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin
 			if (src && map_getcell(src->m, src->x, src->y, CELL_CHKLANDPROTECTOR)
 				&& !(status->mode&MD_BOSS)
 				&& (src->type != BL_PC || ((TBL_PC*)src)->skillitem != skill_id))
-				return 0;
+				return false;
 			break;
 		default:
 			break;
 	}
 
-	if ( src ) sc = status_get_sc(src);
+	if ( src )
+		sc = status_get_sc(src);
 
 	if( sc && sc->count ) {
-		if((sc->data[SC_ASH] && rnd()%2)) {
-			if(src->type==BL_PC) clif_skill_fail((TBL_PC*)src,skill_id,0,0);
-			return 0;
+		if (sc->data[SC_ALL_RIDING])
+			return false; //You can't use skills while in the new mounts (The client doesn't let you, this is to make cheat-safe)
+
+		if ((sc->data[SC_ASH] && rnd()%2)) {
+			if (src->type == BL_PC)
+				clif_skill_fail((TBL_PC*)src,skill_id,USESKILL_FAIL_LEVEL,0);
+			return false;
 		}
 
-		if (skill_id != RK_REFRESH && sc->opt1 >0 && !(sc->opt1 == OPT1_CRYSTALIZE && src->type == BL_MOB) && sc->opt1 != OPT1_BURNING && skill_id != SR_GENTLETOUCH_CURE) { // Stuned/Frozen/etc
+		if (skill_id != RK_REFRESH && sc->opt1 && !(sc->opt1 == OPT1_CRYSTALIZE && src->type == BL_MOB) && sc->opt1 != OPT1_BURNING && skill_id != SR_GENTLETOUCH_CURE) { // Stuned/Frozen/etc
 			if (flag != 1) // Can't cast, casted stuff can't damage.
-				return 0;
+				return false;
 			if (!(skill_get_inf(skill_id)&INF_GROUND_SKILL)) 
-				return 0; // Targetted spells can't come off.
+				return false; // Targetted spells can't come off.
 		}
 
 		if (
@@ -1825,13 +1830,13 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin
 			|| (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF && skill_id != PA_GOSPEL)
 			|| (sc->data[SC_GRAVITATION] && sc->data[SC_GRAVITATION]->val3 == BCT_SELF && flag != 2)
 		)
-			return 0;
+			return false;
 
 		if (sc->data[SC_WINKCHARM] && target && !flag) { // Prevents skill usage
-			if( unit_bl2ud(src) && (unit_bl2ud(src))->walktimer == INVALID_TIMER )
+			if (unit_bl2ud(src) && (unit_bl2ud(src))->walktimer == INVALID_TIMER)
 				unit_walktobl(src, map_id2bl(sc->data[SC_WINKCHARM]->val2), 3, 1);
 			clif_emotion(src, E_LV);
-			return 0;
+			return false;
 		}
 
 		if (sc->data[SC_BLADESTOP]) {
@@ -1840,24 +1845,25 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin
 				case 4: if (skill_id == MO_CHAINCOMBO) break;
 				case 3: if (skill_id == MO_INVESTIGATE) break;
 				case 2: if (skill_id == MO_FINGEROFFENSIVE) break;
-				default: return 0;
+				default: return false;
 			}
 		}
 
 		if (sc->data[SC_DANCING] && flag!=2) {
-			if( src->type == BL_PC && ((skill_id >= WA_SWING_DANCE && skill_id <= WM_UNLIMITED_HUMMING_VOICE ) ||
-				skill_id == WM_FRIGG_SONG)) { // Lvl 5 Lesson or higher allow you use 3rd job skills while dancing.
+			if (src->type == BL_PC && ((skill_id >= WA_SWING_DANCE && skill_id <= WM_UNLIMITED_HUMMING_VOICE ) ||
+				skill_id == WM_FRIGG_SONG))
+			{ // Lvl 5 Lesson or higher allow you use 3rd job skills while dancing.
 				if( pc_checkskill((TBL_PC*)src,WM_LESSON) < 5 )
-					return 0;
+					return false;
 			} else if(sc->data[SC_LONGING]) { // Allow everything except dancing/re-dancing. [Skotlex]
 				if (skill_id == BD_ENCORE ||
 					skill_get_inf2(skill_id)&(INF2_SONG_DANCE|INF2_ENSEMBLE_SKILL)
 					)
-					return 0;
+					return false;
 			} else if(!(skill_get_inf3(skill_id)&INF3_USABLE_DANCE)) // Skills that can be used in dancing state
-				return 0;
+				return false;
 			if ((sc->data[SC_DANCING]->val1&0xFFFF) == CG_HERMODE && skill_id == BD_ADAPTATION)
-				return 0; // Can't amp out of Wand of Hermode :/ [Skotlex]
+				return false; // Can't amp out of Wand of Hermode :/ [Skotlex]
 		}
 
 		if (skill_id && // Do not block item-casted skills.
@@ -1871,7 +1877,7 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin
 				(sc->data[SC_STASIS] && skill_block_check(src, SC_STASIS, skill_id)) ||
 				(sc->data[SC_KAGEHUMI] && skill_block_check(src, SC_KAGEHUMI, skill_id))
 			))
-				return 0;
+				return false;
 
 			// Skill blocking.
 			if (
@@ -1880,52 +1886,48 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin
 				(sc->data[SC_HERMODE] && skill_get_inf(skill_id) & INF_SUPPORT_SKILL) ||
 				(sc->data[SC_NOCHAT] && sc->data[SC_NOCHAT]->val1&MANNER_NOSKILL)
 			)
-				return 0;
+				return false;
 		}
-		if (sc->data[SC_ALL_RIDING])
-			return 0; //You can't use skills while in the new mounts (The client doesn't let you, this is to make cheat-safe)
-	}
 
-	if (sc) {
 		if (sc->option) {
-			if ((sc->option&OPTION_HIDE) && src->type == BL_PC &&( !skill_id || !(skill_get_inf3(skill_id)&INF3_USABLE_HIDING))) {
+			if ((sc->option&OPTION_HIDE) && src->type == BL_PC && (!skill_id || !(skill_get_inf3(skill_id)&INF3_USABLE_HIDING))) {
 				// Non players can use all skills while hidden.
-				return 0;
+				return false;
 			}
 			if (sc->option&OPTION_CHASEWALK && skill_id != ST_CHASEWALK)
-				return 0;
+				return false;
 		}
 	}
 
 	if (target == NULL || target == src) // No further checking needed.
-		return 1;
+		return true;
 
 	tsc = status_get_sc(target);
 
-	if(tsc && tsc->count) {
+	if (tsc && tsc->count) {
 		/**
 		* Attacks in invincible are capped to 1 damage and handled in batte.c.
 		* Allow spell break and eske for sealed shrine GDB when in INVINCIBLE state.
 		**/
 		if( tsc->data[SC_INVINCIBLE] && !tsc->data[SC_INVINCIBLEOFF] && skill_id && !(skill_id&(SA_SPELLBREAKER|SL_SKE)) )
-			return 0;
+			return false;
 		if(!skill_id && tsc->data[SC_TRICKDEAD])
-			return 0;
+			return false;
 		if((skill_id == WZ_STORMGUST || skill_id == WZ_FROSTNOVA || skill_id == NJ_HYOUSYOURAKU)
 			&& tsc->data[SC_FREEZE])
-			return 0;
+			return false;
 		if(skill_id == PR_LEXAETERNA && (tsc->data[SC_FREEZE] || (tsc->data[SC_STONE] && tsc->opt1 == OPT1_STONE)))
-			return 0;
+			return false;
 		if (tsc->data[SC__MANHOLE])
 			if (!(skill_get_inf3(skill_id)&INF3_USABLE_MANHOLE))
-				return 0;
+				return false;
 	}
 
 	// If targetting, cloak+hide protect you, otherwise only hiding does.
 	hide_flag = flag?OPTION_HIDE:(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK);
 
- 	// You cannot hide from ground skills.
-	if( skill_get_ele(skill_id,1) == ELE_EARTH ) // !TODO: Need Skill Lv here :/
+ 	// Skill that can hit hidden target
+	if( skill_get_inf3(skill_id)&INF3_HIT_HIDING )
 		hide_flag &= ~OPTION_HIDE;
 
 	switch( target->type ) {
@@ -1935,43 +1937,43 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin
 				bool is_detect = ((status->mode&MD_DETECTOR)?true:false);// god-knows-why gcc doesn't shut up until this happens
 
 				if (pc_isinvisible(tsd))
-					return 0;
+					return false;
 				if (tsc) {
 					if ((tsc->option&hide_flag) && !(status->mode&MD_BOSS) && (tsd->special_state.perfect_hiding || !is_detect))
-						return 0;
+						return false;
 					if (tsc->data[SC_CLOAKINGEXCEED] && !(status->mode&MD_BOSS) && (tsd->special_state.perfect_hiding || is_detect))
-						return 0;
+						return false;
 					if (tsc->data[SC__FEINTBOMB] && (is_boss || is_detect))
-						return 0;
+						return false;
 					if (tsc->data[SC_CAMOUFLAGE] && !(is_boss || is_detect) && !skill_id)
-						return 0;
+						return false;
 					if (tsc->data[SC_STEALTHFIELD] && !(is_boss || is_detect))
-						return 0;
+						return false;
 				}
 			}
 			break;
 		case BL_ITEM: // Allow targetting of items to pick'em up (or in the case of mobs, to loot them).
 			// !TODO: Would be nice if this could be used to judge whether the player can or not pick up the item it targets. [Skotlex]
 			if (status->mode&MD_LOOTER)
-				return 1;
-			return 0;
+				return true;
+			return false;
 		case BL_HOM:
 		case BL_MER:
 		case BL_ELEM:
 			if( target->type == BL_HOM && skill_id && battle_config.hom_setting&HOMSET_NO_SUPPORT_SKILL && skill_get_inf(skill_id)&INF_SUPPORT_SKILL && battle_get_master(target) != src )
-				return 0; // Can't use support skills on Homunculus (only Master/Self)
+				return false; // Can't use support skills on Homunculus (only Master/Self)
 			if( target->type == BL_MER && (skill_id == PR_ASPERSIO || (skill_id >= SA_FLAMELAUNCHER && skill_id <= SA_SEISMICWEAPON)) && battle_get_master(target) != src )
-				return 0; // Can't use Weapon endow skills on Mercenary (only Master)
+				return false; // Can't use Weapon endow skills on Mercenary (only Master)
 			if( skill_id == AM_POTIONPITCHER && ( target->type == BL_MER || target->type == BL_ELEM) )
-				return 0; // Can't use Potion Pitcher on Mercenaries
+				return false; // Can't use Potion Pitcher on Mercenaries
 		default:
 			// Check for chase-walk/hiding/cloaking opponents.
 			if( tsc ) {
 				if( tsc->option&hide_flag && !(status->mode&(MD_BOSS|MD_DETECTOR)))
-					return 0;
+					return false;
 			}
 	}
-	return 1;
+	return true;
 }
 
 /**
@@ -1979,6 +1981,7 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin
 * @param src:	Object using skill on target [PC|MOB|PET|HOM|MER|ELEM]
 * @param target: Object being targeted by src [PC|MOB|HOM|MER|ELEM]
 * @return src can see (1) or target is invisible (0)
+* @author [Skotlex]
 **/
 int status_check_visibility(struct block_list *src, struct block_list *target)
 {
@@ -3401,7 +3404,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 
 	// Basic ASPD value
 	i = status_base_amotion_pc(sd,status);
-	status->amotion = cap_value(i,((sd->class_&JOBL_THIRD) ? battle_config.max_third_aspd : battle_config.max_aspd),2000);
+	status->amotion = cap_value(i,pc_maxaspd(sd),2000);
 
 	// Relative modifiers from passive skills
 #ifndef RENEWAL_ASPD
@@ -4469,14 +4472,14 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag)
 			amotion -= (int)(sqrt( (pow(status->agi, 2) / 2) + (pow(status->dex, 2) / 5) ) / 4 + (status_calc_aspd(bl, sc, 1) * status->agi / 200)) * 10;
 
 			if( (status_calc_aspd(bl, sc, 2) + status->aspd_rate2) != 0 ) // RE ASPD percertage modifier
-				amotion -= ( amotion - ((sd->class_&JOBL_THIRD) ? battle_config.max_third_aspd : battle_config.max_aspd) )
+				amotion -= ( amotion - pc_maxaspd(sd) )
 							* (status_calc_aspd(bl, sc, 2) + status->aspd_rate2) / 100;
 
 			if(status->aspd_rate != 1000) // Absolute percentage modifier
 				amotion = ( 200 - (200-amotion/10) * status->aspd_rate / 1000 ) * 10;
 #endif
 			amotion = status_calc_fix_aspd(bl, sc, amotion);
-			status->amotion = cap_value(amotion,((sd->class_&JOBL_THIRD) ? battle_config.max_third_aspd : battle_config.max_aspd),2000);
+			status->amotion = cap_value(amotion,pc_maxaspd(sd),2000);
 
 			status->adelay = 2*status->amotion;
 		} else if( bl->type&BL_HOM ) {
@@ -7049,11 +7052,13 @@ void status_change_init(struct block_list *bl)
 **/
 int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int tick, int flag)
 {
-	/// Percentual resistance: 10000 = 100% Resist
-	/// Example: 50% -> sc_def=5000 -> 25%; 5000ms -> tick_def=5000 -> 2500ms
+	/// Resistance rate: 10000 = 100%
+	/// Example:	50% (5000) -> sc_def = 5000 -> 25%;
+	///				5000ms -> tick_def = 5000 -> 2500ms
 	int sc_def = 0, tick_def = -1; // -1 = use sc_def
-	/// Linear resistance substracted from rate and tick after percentual resistance was applied
-	/// Example: 25% -> sc_def2=2000 -> 5%; 2500ms -> tick_def2=2000 -> 500ms
+	/// Fixed resistance value (after rate calculation)
+	/// Example:	25% (2500) -> sc_def2 = 2000 -> 5%;
+	///				2500ms -> tick_def2=2000 -> 500ms
 	int sc_def2 = 0, tick_def2 = 0;
 
 	struct status_data *status, *status_src, *b_status;
@@ -7061,10 +7066,11 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ
 	struct map_session_data *sd;
 
 	nullpo_ret(bl);
-	if(src==NULL) return tick?tick:1; // This should not happen in current implementation, but leave it anyway
+	if (src == NULL)
+		return tick?tick:1; // This should not happen in current implementation, but leave it anyway
 
 	// Status that are blocked by Golden Thief Bug card or Wand of Hermod
-	if (status_isimmune(bl))
+	if (status_isimmune(bl)) {
 		switch (type) {
 			case SC_DECREASEAGI:
 			case SC_SILENCE:
@@ -7097,6 +7103,7 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ
 			case SC__WEAKNESS:
 				return 0;
 		}
+	}
 
 	sd = BL_CAST(BL_PC,bl);
 	status = status_get_status_data(bl);
@@ -7122,15 +7129,38 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ
 			}
 			break;
 		case SC_STUN:
+			sc_def = status->vit*100;
+			sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
+			tick_def2 = status->luk*10;
+			break;
 		case SC_SILENCE:
+#ifndef RENEWAL
+			sc_def = status->vit*100;
+			sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
+#else
+			sc_def = status->int_*100;
+			sc_def2 = (status->vit + status->luk) * 5 + status_get_lv(bl)*10 - status_get_lv(src)*10;
+#endif
+			tick_def2 = status->luk*10;
+			break;
 		case SC_BLEEDING:
+#ifndef RENEWAL
 			sc_def = status->vit*100;
 			sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
+#else
+			sc_def = status->agi*100;
+			sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
+#endif
 			tick_def2 = status->luk*10;
 			break;
 		case SC_SLEEP:
+#ifndef RENEWAL
 			sc_def = status->int_*100;
 			sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
+#else
+			sc_def = status->agi*100;
+			sc_def2 = (status->int_ + status->luk) * 5 + status_get_lv(bl)*10 - status_get_lv(src)*10;
+#endif
 			tick_def2 = status->luk*10;
 			break;
 		case SC_STONE:
@@ -7164,7 +7194,8 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ
 			break;
 		case SC_DECREASEAGI:
 		case SC_ADORAMUS: // Arch Bishop
-			if (sd) tick>>=1; // Half duration for players.
+			if (sd)
+				tick >>= 1; // Half duration for players.
 			sc_def = status->mdef*100;
 			tick_def = 0; // No duration reduction
 			break;
@@ -7428,10 +7459,11 @@ void status_display_remove(struct map_session_data *sd, enum sc_type type) {
 * @param val1~4: Depends on type of status change
 * @param tick: Initial duration that the status change affects bl
 * @param flag: Value which determines what parts to calculate
-*	&1: Cannot be avoided (it has to start)
-*	&2: Tick should not be reduced (by vit, luk, lv, etc)
-*	&4: sc_data loaded, no value has to be altered.
-*	&8: rate should not be reduced
+*	&1 : Cannot be avoided (it has to start)
+*	&2 : Tick should not be reduced (by vit, luk, lv, etc)
+*	&4 : sc_data loaded, no value has to be altered.
+*	&8 : rate should not be reduced
+*	&16: don't send SI
 * @return adjusted duration based on flag values
 **/
 int status_change_start(struct block_list* src, struct block_list* bl,enum sc_type type,int rate,int val1,int val2,int val3,int val4,int tick,int flag)
@@ -8323,9 +8355,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 				struct map_session_data *tsd;
 				if( sd ) {
 					int i;
-					for( i = 0; i < 5; i++ ) {
+					for( i = 0; i < MAX_DEVOTION; i++ ) {
 						if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
-							status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1);
+							status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1|16);
 					}
 				}
 				else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
@@ -8408,21 +8440,22 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			val3 = 0; // Not need to keep this info.
 			break;
 		case SC_PROVIDENCE:
-			val2=val1*5; // Race/Ele resist
+			val2 = val1*5; // Race/Ele resist
 			break;
 		case SC_REFLECTSHIELD:
-			val2=10+val1*3; // %Dmg reflected
+			val2 = 10+val1*3; // %Dmg reflected
+			// val4 used to mark if reflect shield is an inheritance bonus from Devotion
 			if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) ) {
 				struct map_session_data *tsd;
 				if( sd ) {
 					int i;
-					for( i = 0; i < 5; i++ ) {
+					for( i = 0; i < MAX_DEVOTION; i++ ) {
 						if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
-							status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1);
+							status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, 1|16);
 					}
 				}
 				else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
-					status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1);
+					status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, 1);
 			}
 			break;
 		case SC_STRIPWEAPON:
@@ -8668,9 +8701,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 
 				if( bl->type&(BL_PC|BL_MER) ) {
 					if( sd ) {
-						for( i = 0; i < 5; i++ ) {
+						for( i = 0; i < MAX_DEVOTION; i++ ) {
 							if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
-								status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1);
+								status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1|16);
 						}
 					}
 					else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
@@ -8688,7 +8721,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 				if (sd) {
 					struct map_session_data *tsd;
 					int i;
-					for (i = 0; i < 5; i++) { // See if there are devoted characters, and pass the status to them. [Skotlex]
+					for (i = 0; i < MAX_DEVOTION; i++) { // See if there are devoted characters, and pass the status to them. [Skotlex]
 						if (sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])))
 							status_change_start(src,&tsd->bl,type,10000,val1,5+val1*5,val3,val4,tick,1);
 					}
@@ -8815,7 +8848,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 				while( i >= 0 ) {
 					enum sc_type type2 = types[i];
 					if( d_sc->data[type2] )
-						sc_start(d_bl,bl, type2, 100, d_sc->data[type2]->val1, skill_get_time(status_sc2skill(type2),d_sc->data[type2]->val1));
+						status_change_start(d_bl, bl, type2, 10000, d_sc->data[type2]->val1, 0, 0, (type2 == SC_REFLECTSHIELD ? 1 : 0), skill_get_time(status_sc2skill(type2),d_sc->data[type2]->val1), (type2 == SC_DEFENDER) ? 1 : 1|16);
 					i--;
 				}
 			}
@@ -10198,7 +10231,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		calc_flag&=~SCB_DYE;
 	}
 
-	if(!(flag&4 && StatusDisplayType[type]))
+	if(!(flag&16) && !(flag&4 && StatusDisplayType[type]))
 		clif_status_change(bl,StatusIconChangeTable[type],1,tick,(val_flag&1)?val1:1,(val_flag&2)?val2:0,(val_flag&4)?val3:0);
 
 	// Used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first.
@@ -10565,7 +10598,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
 				struct map_session_data *tsd;
 				if( bl->type == BL_PC ) { // Clear Status from others
 					int i;
-					for( i = 0; i < 5; i++ ) {
+					for( i = 0; i < MAX_DEVOTION; i++ ) {
 						if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) && tsd->sc.data[type] )
 							status_change_end(&tsd->bl, type, INVALID_TIMER);
 					}
@@ -12145,7 +12178,7 @@ int status_change_timer_sub(struct block_list* bl, va_list ap)
 			status_check_skilluse(src, bl, WZ_SIGHTBLASTER, 2))
 		{
 			if (sce && !(bl->type&BL_SKILL) // The hit is not counted if it's against a trap
-				&& skill_attack(BF_MAGIC,src,src,bl,WZ_SIGHTBLASTER,1,tick,0)) {
+				&& skill_attack(BF_MAGIC,src,src,bl,WZ_SIGHTBLASTER,sce->val1,tick,0)) {
 				sce->val2 = 0; // This signals it to end.
 			}
 		}

+ 2 - 2
src/map/status.h

@@ -2032,8 +2032,8 @@ void status_calc_misc(struct block_list *bl, struct status_data *status, int lev
 void status_calc_regen(struct block_list *bl, struct status_data *status, struct regen_data *regen);
 void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, struct status_change *sc);
 
-int status_check_skilluse(struct block_list *src, struct block_list *target, uint16 skill_id, int flag); // [Skotlex]
-int status_check_visibility(struct block_list *src, struct block_list *target); //[Skotlex]
+bool status_check_skilluse(struct block_list *src, struct block_list *target, uint16 skill_id, int flag);
+int status_check_visibility(struct block_list *src, struct block_list *target);
 
 int status_change_spread( struct block_list *src, struct block_list *bl );
 

+ 13 - 0
src/map/unit.c

@@ -1408,6 +1408,19 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
 				sd->skill_id_old = skill_id;
 				sd->skill_lv_old = skill_lv;
 				break;
+			case CR_DEVOTION:
+				if (target->type == BL_PC) {
+					uint8 i = 0, count = min(skill_lv, MAX_DEVOTION);
+					ARR_FIND(0, count, i, sd->devotion[i] == target_id);
+					if (i == count) {
+						ARR_FIND(0, count, i, sd->devotion[i] == 0);
+						if (i == count) { // No free slots, skill Fail
+							clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0);
+							return 0;
+						}
+					}
+				}
+				break;
 		}
 		if (!skill_check_condition_castbegin(sd, skill_id, skill_lv))
 			return 0;