From 9b4d922ef4ab11c76ce9e73dd18ac2c4aed9cb79 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Mon, 15 Sep 2014 18:02:49 +0700 Subject: [PATCH] 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 --- conf/battle/player.conf | 3 + conf/battle/skill.conf | 4 + conf/inter_athena.conf | 6 +- db/pre-re/skill_db.txt | 47 ++--- db/re/skill_db.txt | 47 ++--- sql-files/logs.sql | 1 + sql-files/main.sql | 1 + sql-files/upgrades/upgrade_20140915.sql | 1 + sql-files/upgrades/upgrade_20140915_log.sql | 1 + src/char/char.c | 5 +- src/char/int_mail.c | 18 +- src/common/mmo.h | 5 +- src/map/battle.c | 112 +++++++---- src/map/battle.h | 2 + src/map/clif.c | 179 +++++++++-------- src/map/log.c | 10 +- src/map/mail.c | 2 +- src/map/mail.h | 2 +- src/map/pc.c | 15 +- src/map/pc.h | 14 +- src/map/skill.c | 102 +++++----- src/map/skill.h | 33 +-- src/map/status.c | 211 +++++++++++--------- src/map/status.h | 4 +- src/map/unit.c | 13 ++ 25 files changed, 479 insertions(+), 359 deletions(-) create mode 100644 sql-files/upgrades/upgrade_20140915.sql create mode 100644 sql-files/upgrades/upgrade_20140915_log.sql diff --git a/conf/battle/player.conf b/conf/battle/player.conf index 5c8c4cd19c..609bacaf74 100644 --- a/conf/battle/player.conf +++ b/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 diff --git a/conf/battle/skill.conf b/conf/battle/skill.conf index 297c47acf9..827305cd6c 100644 --- a/conf/battle/skill.conf +++ b/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 diff --git a/conf/inter_athena.conf b/conf/inter_athena.conf index 14171e8568..7251264f00 100644 --- a/conf/inter_athena.conf +++ b/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: diff --git a/db/pre-re/skill_db.txt b/db/pre-re/skill_db.txt index ed45fff34c..472ab58bb2 100644 --- a/db/pre-re/skill_db.txt +++ b/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 diff --git a/db/re/skill_db.txt b/db/re/skill_db.txt index 92bbe51eb1..1f655d62ae 100644 --- a/db/re/skill_db.txt +++ b/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 diff --git a/sql-files/logs.sql b/sql-files/logs.sql index 0bb8d43c7b..01869aa0ac 100644 --- a/sql-files/logs.sql +++ b/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 ; diff --git a/sql-files/main.sql b/sql-files/main.sql index 0f32ea5684..a3ced98d13 100644 --- a/sql-files/main.sql +++ b/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; diff --git a/sql-files/upgrades/upgrade_20140915.sql b/sql-files/upgrades/upgrade_20140915.sql new file mode 100644 index 0000000000..136c9b245d --- /dev/null +++ b/sql-files/upgrades/upgrade_20140915.sql @@ -0,0 +1 @@ +ALTER TABLE `mail` ADD `bound` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0'; diff --git a/sql-files/upgrades/upgrade_20140915_log.sql b/sql-files/upgrades/upgrade_20140915_log.sql new file mode 100644 index 0000000000..222e406d80 --- /dev/null +++ b/sql-files/upgrades/upgrade_20140915_log.sql @@ -0,0 +1 @@ +ALTER TABLE `picklog` ADD `bound` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0'; diff --git a/src/char/char.c b/src/char/char.c index c57bfb91c8..db91d5cd02 100644 --- a/src/char/char.c +++ b/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; } diff --git a/src/char/int_mail.c b/src/char/int_mail.c index c99d647cbd..4375cdda58 100644 --- a/src/char/int_mail.c +++ b/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); } } diff --git a/src/common/mmo.h b/src/common/mmo.h index f45495e44a..e21b569a04 100644 --- a/src/common/mmo.h +++ b/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... diff --git a/src/map/battle.c b/src/map/battle.c index 7859f9530d..58449aeb0f 100644 --- a/src/map/battle.c +++ b/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; diff --git a/src/map/battle.h b/src/map/battle.h index 5cdaebb376..c792c91348 100644 --- a/src/map/battle.h +++ b/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); diff --git a/src/map/clif.c b/src/map/clif.c index 58904a169d..81a0b66205 100644 --- a/src/map/clif.c +++ b/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); + 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 .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; } diff --git a/src/map/log.c b/src/map/log.c index 00987a8093..3a55efa869 100644 --- a/src/map/log.c +++ b/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); } } diff --git a/src/map/mail.c b/src/map/mail.c index 7826fbda02..19819b7644 100644 --- a/src/map/mail.c +++ b/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; diff --git a/src/map/mail.h b/src/map/mail.h index cd7b79c6da..d0c8e5396a 100644 --- a/src/map/mail.h +++ b/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); diff --git a/src/map/pc.c b/src/map/pc.c index 3611609b46..7d7ba79675 100755 --- a/src/map/pc.c +++ b/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 diff --git a/src/map/pc.h b/src/map/pc.h index e294c1cb8e..f9d466ea77 100644 --- a/src/map/pc.h +++ b/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 diff --git a/src/map/skill.c b/src/map/skill.c index 2881f5f3dc..c5289b98b3 100755 --- a/src/map/skill.c +++ b/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{,} */ 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; diff --git a/src/map/skill.h b/src/map/skill.h index 4b5adda844..8f82f5f6ae 100644 --- a/src/map/skill.h +++ b/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 }; diff --git a/src/map/status.c b/src/map/status.c index 03881f3ee8..769790c14c 100644 --- a/src/map/status.c +++ b/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: - 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. } } diff --git a/src/map/status.h b/src/map/status.h index 440a31e1b5..eb3a3e2b27 100644 --- a/src/map/status.h +++ b/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 ); diff --git a/src/map/unit.c b/src/map/unit.c index a7e7d3ca1b..b61bdbbd32 100644 --- a/src/map/unit.c +++ b/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;