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>
This commit is contained in:
Cydh Ramdh 2014-09-15 18:02:49 +07:00
parent 20ff69e5ce
commit 9b4d922ef4
25 changed files with 479 additions and 359 deletions

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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 ;

View File

@ -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;

View File

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

View File

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

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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...

View File

@ -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;

View File

@ -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);

View File

@ -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);
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)= 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;
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
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
item_monster_name = str;
item_monster_name[(sizeof(str) - 2) - 1] = '\0';
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);
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);
// 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;
}
if( (count = mobdb_searchname_array(mob_array, 10, item_monster_name)) > 0 ) {
for( i = 0; i < count; i++ )
if( !mob_array[i] )
continue;
// 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( i < count ) {
safesnprintf(command, sizeof(command) - 1, "%cmonster %s", atcommand_symbol, mob_array[i]->sprite);
is_atcommand(fd, sd, command, 1);
}
// Monster
if ((mob_id = mobdb_searchname(str)) == 0)
mob_id = mobdb_checkid(atoi(str));
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;
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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
};

View File

@ -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:
case SC_SILENCE:
case SC_BLEEDING:
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.
}
}

View File

@ -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 );

View File

@ -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;