From ce090ce916e567444f223894d47ecd3a39dd77ef Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Wed, 1 Oct 2014 17:42:30 +0700 Subject: [PATCH] Skill Changes: * Wizard/Warlock Skill * Moved Sightrasher (WZ_SIGHTRASHER) requirement to check Sight (SC_SIGHT) is active or not to skill_check_condition_castend section. * Fixed Sightrasher (WZ_SIGHTRASHER) splash area to 3x3. (bugreport:9298) * Now Comet (WL_COMET) cannot hits Hiding target (The mistake is not at flag 0x10000 in skill_db.txt, the flash should be added by SD_ANIMATION). (bugreport:8909). * Now Reading Spell Book (WL_READING_SB) checking the number of available spell books in Spell Book DB first to prevent infinite loop. * Sage Skill * Now Abracadabra (SA_ABRACADABRA) checking the number of available skills in Abra DB first to prevent infinite loop. * Reduced MAX_SKILL_ABRA_DB from 350 to 160. * Shadow Chaser Skill * Fixed Chaos Panic (SC_CHAOSPANIC) effect. (bugreport:9321). * Genetic Skill * Now Wall of Thorn (GN_WALLOFTHORN) can be knocked back but not a whole skill group and durability (HP & max hit) for each skill unit. * Guillotine Cross Skill * Now Magic Mushroom (SC_MAGICMUSHROOM) effect checks the number of available skills in Magic Mushroom DB first to prevent infinite loop. * Changed 'RemoveFlag' in db/magicmushroom_db.txt value to 1 to remove skill by importing. (bugreport:9322). * Wanderer/Minstrel Skill * Now Randomize Spell (WM_RANDOMIZESPELL) checks the number of available skills in Improvise DB first to prevent infinite loop. * Reduced MAX_SKILL_IMPROVISE_DB from 50 to 30. * Rebellion Skill * Cleaned up, added, corrected some (missing) sequences & DB values. * Fixed Hammer of God (RL_HAMMER_OF_GOD) splash damage. * Fixed Shaterred Strom (RL_S_STORM) push back & force to sit effect (for player, or stun for monsters) (first implementation leftover). * Fixed Slug Shot (RL_SLUGSHOT) hitrate-distance penalty (first implementation leftover). * Fixed Howling Mine (RL_H_MINE) damage ratios (first implementation leftover). * Now Bind Trap (RL_B_TRAP) only can be placed 1 at same time. * Fixed Bind Trap (RL_B_TRAP) damage calculation by using Caster's DEX, Target's Current HP, & Skill Level. FIXME: Exact formula still unknown (refers to idAthena formula). * Now Dragon Tail (RL_D_TAIL) doesn't split damage among targets anymore. * Now Crimson Marker (RL_C_MARKER) will fails to cast if no slot available. * Implemented official packet `ZC_C_MARKERINFO` of Crimson Marker (RL_C_MARKER) mini-map marker (first implementation leftover). !TODO: Confirm the packet for older or newer clients (idAthena partial merge r1497) * References: http://forums.irowiki.org/showpost.php?p=1387992&postcount=968, follow up 507f047, dd67f9d Misc: * Fixed some skills that should work only in shoot range (map_foreachinshootange, by default), and added check for respecting *skill_wall_check* (map_foreachinrange). * Fixed item stackable check for `/item` command, follow up 9b4d922. * Fixed npc source file isn't removed properly by @unloadnpcfile. (bugreport:9311). * Added constantan for status_change_start() and sc_start() scripts as well * SCSTART_NONE = 0x0 * SCSTART_NOAVOID = 0x1 * SCSTART_NOTICKDEF = 0x2 * SCSTART_LOADED = 0x4 * SCSTART_NORATEDEF = 0x8 * SCSTART_NOICON = 0x10 * Moved and changed itemdb_unique_id() to pc_generate_unique_id(). * Seperated check for skill SC requirement to skill_check_condition_sc_required(). * Added skill unit flag `UF_KNOCKBACK_GROUP`, just an option to make skill unit can be knocked back a whole group. * Typos and other minor changes! Signed-off-by: Cydh Ramdh --- db/import-tmpl/magicmushroom_db.txt | 2 +- db/magicmushroom_db.txt | 2 +- db/packet_db.txt | 8 +- db/pre-re/skill_unit_db.txt | 37 +- db/re/skill_cast_db.txt | 18 +- db/re/skill_db.txt | 30 +- db/re/skill_require_db.txt | 2 +- db/re/skill_unit_db.txt | 39 +- src/config/const.h | 4 +- src/map/atcommand.c | 2 +- src/map/battle.c | 47 +- src/map/chrif.c | 2 +- src/map/clif.c | 100 +-- src/map/clif.h | 4 +- src/map/itemdb.c | 13 +- src/map/itemdb.h | 1 - src/map/map.c | 14 +- src/map/map.h | 4 +- src/map/mob.c | 8 +- src/map/npc.c | 2 + src/map/pc.c | 28 +- src/map/pc.h | 9 +- src/map/pet.c | 4 +- src/map/script.c | 55 +- src/map/skill.c | 940 +++++++++++++++++----------- src/map/skill.h | 52 +- src/map/status.c | 282 +++++---- src/map/status.h | 20 +- src/map/unit.c | 21 +- tools/check-doc.pl | 18 +- 30 files changed, 1041 insertions(+), 727 deletions(-) diff --git a/db/import-tmpl/magicmushroom_db.txt b/db/import-tmpl/magicmushroom_db.txt index 8f4d243957..a45939f81b 100644 --- a/db/import-tmpl/magicmushroom_db.txt +++ b/db/import-tmpl/magicmushroom_db.txt @@ -4,5 +4,5 @@ // Structure of Database: // SkillID{,RemoveFlag} // -// - To remove entry by importing, put any value on 'RemoveFlag' +// - To remove entry by importing, put 1 value on 'RemoveFlag' diff --git a/db/magicmushroom_db.txt b/db/magicmushroom_db.txt index c0016e9398..d5a5e5b193 100644 --- a/db/magicmushroom_db.txt +++ b/db/magicmushroom_db.txt @@ -4,7 +4,7 @@ // Structure of Database: // SkillID{,RemoveFlag} // -// - To remove entry by importing, put any value on 'RemoveFlag' +// - To remove entry by importing, put 1 value on 'RemoveFlag' 7 //SM_MAGNUM 8 //SM_ENDURE diff --git a/db/packet_db.txt b/db/packet_db.txt index da198a4cf5..9570e113b6 100644 --- a/db/packet_db.txt +++ b/db/packet_db.txt @@ -2244,6 +2244,7 @@ packet_ver: 45 0x023B,26,friendslistadd,2 0x0361,5,hommenu,2:4 0x0887,36,storagepassword,2:4:20 +0x09C1,10,ZC_C_MARKERINFO,2:6:8 //2013-12-23Ragexe packet_ver: 46 @@ -2277,13 +2278,14 @@ packet_ver: 46 0x0361,5,hommenu,2:4 0x08A4,36,storagepassword,2:4:20 //New Packets -0x09D4,2,dull,0 //npcshopclosed +//0x097E,12 //ZC_UPDATE_RANKING_POINT +0x09B4,6,dull,0 //Cash Shop - Special Tab 0x09CE,102,itemmonster,2 +0x09D4,2,dull,0 //npcshopclosed //NPC Market -0x09D8,2,dull,0 //npcmarketclosed 0x09D6,-1,dull,0 //npcmarketpurchase +0x09D8,2,dull,0 //npcmarketclosed 0x09DF,7 -0x09B4,6,dull,0 // Cash Shop - Special Tab //Add new packets here //packet_ver: 47 diff --git a/db/pre-re/skill_unit_db.txt b/db/pre-re/skill_unit_db.txt index 998cbb83f8..c4ff246376 100644 --- a/db/pre-re/skill_unit_db.txt +++ b/db/pre-re/skill_unit_db.txt @@ -6,22 +6,23 @@ // layout = -1:special, 0:1*1, 1:3*3, 2:5*5, up to 5:11*11 // target = friend (party +guildmates +neutral players) / party / guild // ally (party +guildmates) / all / sameguild (guild but no allies) / enemy -// flag 0x0001(UF_DEFNOTENEMY) If 'defunit_not_enemy' is set, the target is changed to 'friend' -// 0x0002(UF_NOREITERRATION) Spell cannot be stacked -// 0x0004(UF_NOFOOTSET) Spell cannot be cast near/on targets -// 0x0008(UF_NOOVERLAP) Spell effects do not overlap -// 0x0010(UF_PATHCHECK) Only cells with a shootable path will be placed -// 0x0020(UF_NOPC) Spell cannot affect players. -// 0x0040(UF_NOMOB) Spell cannot affect mobs. -// 0x0080(UF_SKILL) Spell CAN affect skills. -// 0x0100(UF_DANCE) Dance skill -// 0x0200(UF_ENSEMBLE) Ensemble skill -// 0x0400(UF_SONG) Song skill -// 0x0800(UF_DUALMODE) Spell has effects both at an interval and when you step in/out -// 0x1000(UF_NOKNOCKBACK) Cannot be knocked back (only unit that can be damaged) -// 0x2000(UF_RANGEDSINGLEUNIT) Layout hack, use layout range propriety but only display center. -// 0x4000(UF_REM_CRAZYWEED) Removed if be overlapped by GN_CRAZYWEED -// 0x8000(UF_REM_FIRERAIN) Removed if be overlapped by RL_FIRE_RAIN +// flag 0x00001(UF_DEFNOTENEMY) If 'defunit_not_enemy' is set, the target is changed to 'friend' +// 0x00002(UF_NOREITERRATION) Spell cannot be stacked +// 0x00004(UF_NOFOOTSET) Spell cannot be cast near/on targets +// 0x00008(UF_NOOVERLAP) Spell effects do not overlap +// 0x00010(UF_PATHCHECK) Only cells with a shootable path will be placed +// 0x00020(UF_NOPC) Spell cannot affect players. +// 0x00040(UF_NOMOB) Spell cannot affect mobs. +// 0x00080(UF_SKILL) Spell CAN affect skills. +// 0x00100(UF_DANCE) Dance skill +// 0x00200(UF_ENSEMBLE) Ensemble skill +// 0x00400(UF_SONG) Song skill +// 0x00800(UF_DUALMODE) Spell has effects both at an interval and when you step in/out +// 0x01000(UF_NOKNOCKBACK) Cannot be knocked back (only unit that can be damaged) +// 0x02000(UF_RANGEDSINGLEUNIT) Layout hack, use layout range propriety but only display center. +// 0x04000(UF_REM_CRAZYWEED) Removed if be overlapped by GN_CRAZYWEED +// 0x08000(UF_REM_FIRERAIN) Removed if be overlapped by RL_FIRE_RAIN +// 0x10000(UF_KNOCKBACK_GROUP) Knock back a whole skill group (by default, skill unit is knocked back each unit) // Example: 0x006 = 0x002+0x004 -> Cannot be stacked nor cast near targets // // Notes: @@ -126,7 +127,7 @@ 2299,0xcc, , 0, 1,1000,all, 0xC006 //SC_MANHOLE 2300,0xcd, , 0, 0,1000,all, 0xC006 //SC_DIMENSIONDOOR -2301,0xce, , 2, 0, -1,all, 0xE00E //SC_CHAOSPANIC +2301,0xce, , 2, 0,1000,all, 0xE00E //SC_CHAOSPANIC 2302,0xcf, , 2, 0, -1,all, 0xE002 //SC_MAELSTROM 2303,0xd0, , 3, 0, -1,all, 0xE058 //SC_BLOODYLUST 2304,0xd1, , 0, 2, 500,enemy, 0x018 //SC_FEINTBOMB @@ -151,7 +152,7 @@ 2468,0xf4, , 0, 1,1000,all, 0x010 //SO_EARTH_INSIGNIA 2479,0xe5, , 0, 1,1000,enemy, 0xC006 //GN_THORNS_TRAP -2482,0xe6,0x7f, -1, 1, 300,enemy, 0xD000 //GN_WALLOFTHORN +2482,0xe6,0x7f, -1, 1, 300,enemy, 0xC000 //GN_WALLOFTHORN 2484,0x86, , 0, 1, 100,enemy, 0x080 //GN_CRAZYWEED_ATK 2485,0xe7, , 0, 2,2000,enemy, 0x8098 //GN_DEMONIC_FIRE 2487,0xe8, , 2, 0, -1,enemy, 0x2000 //GN_FIRE_EXPANSION_SMOKE_POWDER diff --git a/db/re/skill_cast_db.txt b/db/re/skill_cast_db.txt index efb8d55eda..7162b4056f 100644 --- a/db/re/skill_cast_db.txt +++ b/db/re/skill_cast_db.txt @@ -1643,11 +1643,11 @@ //-- RL_RICHS_COIN 2552,0,1000,0,600000,0,0,-1 //-- RL_MASS_SPIRAL -2553,0,1000,0,0,30000,1000,-1 +2553,2000,1000,0,0,30000,1000,-1 //-- RL_BANISHING_BUSTER 2554,3000:2500:2000:1500:1000,1000,0,0,0,1500,-1 //-- RL_B_TRAP -2555,0,0,0,10000:11000:12000:13000:14000,0,2000,-1 +2555,0,0,0,4000,6000:7000:8000:9000:10000,2000,-1 //-- RL_FLICKER 2556,0,500,0,0,0,2000,-1 //-- RL_S_STORM @@ -1659,27 +1659,27 @@ //-- RL_C_MARKER 2560,0,0,0,30000,0,1000,-1 //-- RL_FIREDANCE -2561,0,1500,0,0,0,5000,-1 +2561,1600:1500:1400:1200:1000,1500,0,0,0,5000,-1 //-- RL_H_MINE -2562,0,1500,0,30000,15000,2000,-1 +2562,2000,1500,0,30000,15000,5000:4500:4000:3500:3000,-1 //-- RL_P_ALTER -2563,0,1000,0,60000,0,5000,-1 +2563,0,1000,0,30000:45000:60000:75000:90000,0,5000,-1 //-- RL_FALLEN_ANGEL 2564,0,1500,0,0,0,4500:4000:3500:2500:2000,-1 //-- RL_R_TRIP 2565,0,1500,0,0,0,3000,-1 //-- RL_D_TAIL -2566,0,1500,0,0,0,5000,-1 +2566,2000,1500,0,0,0,5000,-1 //-- RL_FIRE_RAIN 2567,0,1500,0,100,0,5000,-1 //-- RL_HEAT_BARREL 2568,0,1000,0,60000,10000,10000,-1 //-- RL_AM_BLAST -2569,2000,1500,0,0,6000:7000:8000:9000:10000,1000,-1 +2569,2000,1500,0,0,6000:7000:8000:9000:10000,1000,1000 //-- RL_SLUGSHOT -2570,5000:6000:7000:8000:9000,1000,0,0,10000,1500,1000 +2570,5000:6000:7000:8000:9000,1000,0,2000,0,1500,1000 //-- RL_HAMMER_OF_GOD -2571,0,1000,0,0,3000:3000:4000:4000:5000,3000,-1 +2571,3000,1000,0,0,3000:3000:4000:4000:5000,3000,-1 //-- RL_R_TRIP_PLUSATK //2572,0,0,0,0,0,0,-1 //-- RL_B_FLICKER_ATK diff --git a/db/re/skill_db.txt b/db/re/skill_db.txt index 72e77d2adf..b165b4d72e 100644 --- a/db/re/skill_db.txt +++ b/db/re/skill_db.txt @@ -864,7 +864,7 @@ 1003,0,0,0,0,0,0,1,0,no,0,0x1,0,weapon,0,0x0, AS_SONICACCEL,Sonic Acceleration 1004,9,8,1,0,0x8,0,1,1,no,0,0x1,0,weapon,0,0x0, AS_VENOMKNIFE,Throw Venom Knife 1005,1,6,1,0,0x1,0,1,1,no,0,0x1,0,weapon,0,0x0, RG_CLOSECONFINE,Close Confine -1006,0,6,4,3,0,2,1,1,yes,0,0x1,0,magic,3,0x20, WZ_SIGHTBLASTER,Sight Blaster +1006,0,6,4,3,0,1,1,1,yes,0,0x1,0,magic,3,0x20, WZ_SIGHTBLASTER,Sight Blaster 1007,0,6,4,0,0x1,0,1,0,no,0,0x1,0,none,0,0x0, SA_CREATECON,Create Elemental Converter 1008,9,6,1,1,0x1,0,1,1,yes,0,0x1,0,magic,0,0x0, SA_ELEMENTWATER,Elemental Change Water 1009,-9,6,1,0,0,0,1,1,no,0,0x1,0,weapon,3,0x0, HT_PHANTASMIC,Phantasmic Arrow @@ -1235,25 +1235,25 @@ // Rebellion //2551,0,0,0,0,0,0,10,0,no,0,0,0,none,0,0, RL_GLITTERING_GREED,Flip The Coin Greed 2552,0,6,4,0,0x1,0,1,1,no,0,0,0,none,0,0x0, RL_RICHS_COIN,Rich's Coin -2553,15,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0, RL_MASS_SPIRAL,Mass Spiral -2554,9,6,1,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0, RL_BANISHING_BUSTER,Banishing Buster -2555,3,6,2,0,0x1,1,5,1,no,0,0,3,misc,0,0x0, RL_B_TRAP,Bind Trap +2553,-9,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0, RL_MASS_SPIRAL,Mass Spiral +2554,-9,6,1,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0, RL_BANISHING_BUSTER,Banishing Buster +2555,3:4:4:5:5,6,2,0,0x1,1,5,1,no,0,0,1,misc,0,0x0, RL_B_TRAP,Bind Trap 2556,0,6,4,0,0x3,-1,1,1,no,0,0,0,none,0,0x0, RL_FLICKER,Flicker -2557,9,6,1,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0, RL_S_STORM,Shatter Storm +2557,-9,6,1,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0, RL_S_STORM,Shatter Storm 2558,0,6,4,0,0x1,0,10,1,no,0,0,0,none,0,0x0, RL_E_CHAIN,Eternal Chain -2559,-9,6,4,-1,0x3,21,1,1,no,0,0x0,0,weapon,0,0x0, RL_QD_SHOT,Quick Draw Shot -2560,11,6,1,0,0x1,0,1,1,no,0,0,3,none,0,0x0, RL_C_MARKER,Crimson Marker -2561,0,6,4,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0, RL_FIREDANCE,Fire Dance -2562,7:8:9:10:11,6,1,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0, RL_H_MINE,Howling Mine +2559,-9,6,4,-1,0x0,10,1,1,no,0,0x0,0,weapon,0,0x0, RL_QD_SHOT,Quick Draw Shot +2560,-9,6,1,0,0x1,0,1,1,no,0,0,3,none,0,0x0, RL_C_MARKER,Crimson Marker +2561,0,6,4,-1,0x2,3,5,1,no,0,0,0,weapon,0,0x0, RL_FIREDANCE,Fire Dance +2562,-9,6,1,-1,0x0,2,5,1,no,0,0,0,weapon,0,0x0, RL_H_MINE,Howling Mine 2563,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0, RL_P_ALTER,Platinum Alter -2564,9,6,2,0,0x1,0,5,1,no,0,0,0,none,0,0x0, RL_FALLEN_ANGEL,Fallen Angel +2564,-9,6,2,0,0x1,0,5,1,no,0,0,0,none,0,0x0, RL_FALLEN_ANGEL,Fallen Angel 2565,0,6,4,-1,0x2,3:3:4:5:6,5,1,no,0,0,0,weapon,3,0x0, RL_R_TRIP,Round Trip 2566,0,6,4,-1,0x3,-1,5,1,no,0,0,0,weapon,0,0x0, RL_D_TAIL,Dragon Tail -2567,9,6,2,-1,0x2,1,5,1,no,0,0,0,weapon,0,0, RL_FIRE_RAIN,Fire Rain +2567,-9,6,2,-1,0x2,1,5,1,no,0,0,0,weapon,0,0, RL_FIRE_RAIN,Fire Rain 2568,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0, RL_HEAT_BARREL,Heat Barrel -2569,9,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0, RL_AM_BLAST,Anti-Material Blast -2570,9,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0, RL_SLUGSHOT,Slug Shot -2571,7:8:9:10:11,6,2,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0, RL_HAMMER_OF_GOD,Hammer of God +2569,-9,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0, RL_AM_BLAST,Anti-Material Blast +2570,-9,6,1,-1,0,0,5,1,no,0,0,0,weapon,6,0x0, RL_SLUGSHOT,Slug Shot +2571,-9,6,2,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0, RL_HAMMER_OF_GOD,Hammer of God 2572,0,6,1,-1,0x40,0,5,1,no,0,0,0,weapon,0,0, RL_R_TRIP_PLUSATK,Round Trip Plus Attack //2573,0,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0, RL_B_FLICKER_ATK,Bind Flicker Attack //2574,0,6,1,-1,0,0,10,1,no,0,0,0,weapon,0,0, RL_GLITTERING_GREED_ATK,Flip The Coin Greed Attack @@ -1266,7 +1266,7 @@ 3004,3:4:5:6:7,8,1,-1,0,0,5,-2,no,0,0,0,weapon,0,0x0, KO_JYUMONJIKIRI,Cross Strike 3005,2,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0, KO_SETSUDAN,Soul Sever 3006,7:8:9:10:11,6,2,-1,0x42,2,5,1,no,0,0,0,weapon,0,0x0, KO_BAKURETSU,Bakuretsu Kunai -3007,5,6,4,-1,0x42,4:4:4:4:5,5,1,no,0,0,0,weapon,0,0x0, KO_HAPPOKUNAI,Happo Kunai +3007,0,6,4,-1,0x42,4:4:4:4:5,5,1,no,0,0,0,weapon,0,0x0, KO_HAPPOKUNAI,Happo Kunai 3008,11,8,2,0,0x56,1:1:1:1:1:1:1:1:1:2,10,-10,no,0,0,0,misc,0,0x0, KO_MUCHANAGE,Mucha Nage 3009,9:10:11:12:13,8,2,-1,0x2,3,5,2,no,0,0,0,weapon,0,0x0, KO_HUUMARANKA,Huuma Shuriken Ranka 3010,3,6,4,0,0x52,0,5,1,no,0,0x80,0,weapon,0,0x10, KO_MAKIBISHI,Makibishi diff --git a/db/re/skill_require_db.txt b/db/re/skill_require_db.txt index cf19810b7d..a7f1227001 100644 --- a/db/re/skill_require_db.txt +++ b/db/re/skill_require_db.txt @@ -896,7 +896,7 @@ 2554,0,0,55:60:65:70:75,0,0,0,20,3,1,none,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RL_BANISHING_BUSTER 2555,0,0,30:32:34:36:38,0,0,0,17:18:19:20:21,0,0,none,0,1,7940,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RL_B_TRAP 2556,0,0,2,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RL_FLICKER -2557,0,0,55:60:65:70:75,0,0,0,20,3,1,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RL_S_STORM +2557,0,0,55:60:65:70:75,0,0,0,20,3,1,none,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RL_S_STORM 2558,0,0,45,0,0,0,17:18:19:20:21,0,0,none,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RL_E_CHAIN 2559,0,0,5,0,0,0,17:18:19:20:21,3:4:5,1,none,SC_QD_SHOT_READY,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RL_QD_SHOT 2560,0,0,10,0,0,0,17:18:19:20:21,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RL_C_MARKER diff --git a/db/re/skill_unit_db.txt b/db/re/skill_unit_db.txt index 54c114bc23..cba445ac20 100644 --- a/db/re/skill_unit_db.txt +++ b/db/re/skill_unit_db.txt @@ -6,22 +6,23 @@ // layout = -1:special, 0:1*1, 1:3*3, 2:5*5, up to 5:11*11 // target = friend (party +guildmates +neutral players) / party / guild // ally (party +guildmates) / all / sameguild (guild but no allies) / enemy -// flag 0x0001(UF_DEFNOTENEMY) If 'defunit_not_enemy' is set, the target is changed to 'friend' -// 0x0002(UF_NOREITERRATION) Spell cannot be stacked -// 0x0004(UF_NOFOOTSET) Spell cannot be cast near/on targets -// 0x0008(UF_NOOVERLAP) Spell effects do not overlap -// 0x0010(UF_PATHCHECK) Only cells with a shootable path will be placed -// 0x0020(UF_NOPC) Spell cannot affect players. -// 0x0040(UF_NOMOB) Spell cannot affect mobs. -// 0x0080(UF_SKILL) Spell CAN affect skills. -// 0x0100(UF_DANCE) Dance skill -// 0x0200(UF_ENSEMBLE) Ensemble skill -// 0x0400(UF_SONG) Song skill -// 0x0800(UF_DUALMODE) Spell has effects both at an interval and when you step in/out -// 0x1000(UF_NOKNOCKBACK) Cannot be knocked back (only unit that can be damaged) -// 0x2000(UF_RANGEDSINGLEUNIT) Layout hack, use layout range propriety but only display center. -// 0x4000(UF_REM_CRAZYWEED) Removed if be overlapped by GN_CRAZYWEED -// 0x8000(UF_REM_FIRERAIN) Removed if be overlapped by RL_FIRE_RAIN +// flag 0x00001(UF_DEFNOTENEMY) If 'defunit_not_enemy' is set, the target is changed to 'friend' +// 0x00002(UF_NOREITERRATION) Spell cannot be stacked +// 0x00004(UF_NOFOOTSET) Spell cannot be cast near/on targets +// 0x00008(UF_NOOVERLAP) Spell effects do not overlap +// 0x00010(UF_PATHCHECK) Only cells with a shootable path will be placed +// 0x00020(UF_NOPC) Spell cannot affect players. +// 0x00040(UF_NOMOB) Spell cannot affect mobs. +// 0x00080(UF_SKILL) Spell CAN affect skills. +// 0x00100(UF_DANCE) Dance skill +// 0x00200(UF_ENSEMBLE) Ensemble skill +// 0x00400(UF_SONG) Song skill +// 0x00800(UF_DUALMODE) Spell has effects both at an interval and when you step in/out +// 0x01000(UF_NOKNOCKBACK) Cannot be knocked back (only unit that can be damaged) +// 0x02000(UF_RANGEDSINGLEUNIT) Layout hack, use layout range propriety but only display center. +// 0x04000(UF_REM_CRAZYWEED) Removed if be overlapped by GN_CRAZYWEED +// 0x08000(UF_REM_FIRERAIN) Removed if be overlapped by RL_FIRE_RAIN +// 0x10000(UF_KNOCKBACK_GROUP) Knock back a whole skill group (by default, skill unit is knocked back each unit) // Example: 0x006 = 0x002+0x004 -> Cannot be stacked nor cast near targets // // Notes: @@ -128,8 +129,8 @@ 2299,0xcc, , 0, 1,1000,all, 0xC006 //SC_MANHOLE 2300,0xcd, , 0, 0,1000,all, 0xC006 //SC_DIMENSIONDOOR -2301,0xce, , 2, 0, -1,all, 0xC00E //SC_CHAOSPANIC -2302,0xcf, , 2, 0, -1,all, 0xC002 //SC_MAELSTROM +2301,0xce, , 2, 0,1000,all, 0xE00E //SC_CHAOSPANIC +2302,0xcf, , 2, 0, -1,all, 0xE002 //SC_MAELSTROM 2303,0xd0, , 3, 0, -1,all, 0xE058 //SC_BLOODYLUST 2304,0xd1, , 0, 2, 500,enemy, 0x018 //SC_FEINTBOMB @@ -153,7 +154,7 @@ 2468,0xf4, , 0, 1,1000,all, 0x010 //SO_EARTH_INSIGNIA 2479,0xe5, , 0, 1,1000,enemy, 0xC006 //GN_THORNS_TRAP -2482,0xe6,0x7f, -1, 1, 300,enemy, 0xD000 //GN_WALLOFTHORN +2482,0xe6,0x7f, -1, 1, 300,enemy, 0xC000 //GN_WALLOFTHORN 2484,0x86, , 0, 1, 100,enemy, 0x080 //GN_CRAZYWEED_ATK 2485,0xe7, , 0, 2,2000,enemy, 0x8098 //GN_DEMONIC_FIRE 2487,0xe8, , 2, 0, -1,enemy, 0x2000 //GN_FIRE_EXPANSION_SMOKE_POWDER diff --git a/src/config/const.h b/src/config/const.h index 6fdaa56c70..be52bd7906 100644 --- a/src/config/const.h +++ b/src/config/const.h @@ -100,8 +100,8 @@ // Renewal variable cast time reduction #ifdef RENEWAL_CAST #define VARCAST_REDUCTION(val){ \ - if( (varcast_r += val) != 0 && varcast_r >= 0 ) \ - time = time * (1 - (float)min(val, 100) / 100); \ + if( (varcast_r += (val)) != 0 && varcast_r >= 0 ) \ + time = time * (1 - (float)min((val), 100) / 100); \ } #endif /** diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 217acb38b0..3c53d50aaa 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -5775,7 +5775,7 @@ ACMD_FUNC(autotrade) { if( battle_config.at_timeout ) { int timeout = atoi(message); - status_change_start(NULL,&sd->bl, SC_AUTOTRADE, 10000, 0, 0, 0, 0, ((timeout > 0) ? min(timeout,battle_config.at_timeout) : battle_config.at_timeout) * 60000, 0); + status_change_start(NULL,&sd->bl, SC_AUTOTRADE, 10000, 0, 0, 0, 0, ((timeout > 0) ? min(timeout,battle_config.at_timeout) : battle_config.at_timeout) * 60000, SCSTART_NONE); } channel_pcquit(sd,0xF); //leave all chan diff --git a/src/map/battle.c b/src/map/battle.c index dae4578e9c..578f62020e 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -347,16 +347,16 @@ int64 battle_attr_fix(struct block_list *src, struct block_list *target, int64 d if (sc && sc->count) { //increase dmg by src status switch(atk_elem){ case ELE_FIRE: - if(sc->data[SC_VOLCANO]) ratio += enchant_eff[sc->data[SC_VOLCANO]->val1-1]; + if (sc->data[SC_VOLCANO]) ratio += sc->data[SC_VOLCANO]->val3; break; case ELE_WIND: - if(sc->data[SC_VIOLENTGALE]) ratio += enchant_eff[sc->data[SC_VIOLENTGALE]->val1-1]; + if (sc->data[SC_VIOLENTGALE]) ratio += sc->data[SC_VIOLENTGALE]->val3; break; case ELE_WATER: - if(sc->data[SC_DELUGE]) ratio += enchant_eff[sc->data[SC_DELUGE]->val1-1]; + if (sc->data[SC_DELUGE]) ratio += sc->data[SC_DELUGE]->val3; break; case ELE_GHOST: - if(sc->data[SC_TELEKINESIS_INTENSE]) ratio += (sc->data[SC_TELEKINESIS_INTENSE]->val3); + if (sc->data[SC_TELEKINESIS_INTENSE]) ratio += (sc->data[SC_TELEKINESIS_INTENSE]->val3); break; } } @@ -886,7 +886,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam else sce->val3 = 1000; // Next shield } - status_change_start(src,bl,SC_STUN,10000,0,0,0,0,1000,2); + status_change_start(src,bl,SC_STUN,10000,0,0,0,0,1000,SCSTART_NOTICKDEF); } return 0; } @@ -2247,8 +2247,15 @@ static bool is_attack_hitting(struct Damage wd, struct block_list *src, struct b hitrate -= 35 - 5 * skill_lv; break; case RL_SLUGSHOT: - if (distance_bl(src,target) > 3) - hitrate -= (10 - (skill_lv - 1)); + { + int8 dist = distance_bl(src, target); + if (dist > 3) { + // Reduce n hitrate for each cell after initial 3 cells. Different each level + // -10:-9:-8:-7:-6 + dist -= 3; + hitrate -= ((11 - skill_lv) * dist); + } + } break; } } else if (sd && wd.type&DMG_MULTI_HIT && wd.div_ == 2) // +1 hit per level of Double Attack on a successful double attack (making sure other multi attack skills do not trigger this) [helvetica] @@ -2422,7 +2429,7 @@ static int battle_get_weapon_element(struct Damage wd, struct block_list *src, s element = ELE_HOLY; break; case RL_H_MINE: - if (sd && sd->skill_id_old == RL_FLICKER) //Force RL_H_MINE deals fire damage if activated by RL_FLICKER + if (sd && sd->flicker) //Force RL_H_MINE deals fire damage if activated by RL_FLICKER element = ELE_FIRE; break; } @@ -3034,9 +3041,10 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s skillratio += -100 + sc->data[SC_EXEEDBREAK]->val1; status_change_end(src,SC_EXEEDBREAK,INVALID_TIMER); } - if(sc->data[SC_HEAT_BARREL]) + //!TODO: Verify this placement & skills that affected by these effects [Cydh] + if (sc->data[SC_HEAT_BARREL]) skillratio += 200; - if(sc->data[SC_P_ALTER]) + if (sc->data[SC_P_ALTER]) skillratio += sc->data[SC_P_ALTER]->val2; } @@ -3858,9 +3866,11 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s * Rebellion **/ case RL_MASS_SPIRAL: + // 200%:400%:600%:800%:1000% skillratio += -100 + (200 * skill_lv); break; case RL_FIREDANCE: + // 100%:200%:300%:400%:500% (+Level ??) skillratio += -100 + (100 * skill_lv); skillratio += (skillratio * status_get_lv(src)) / 300; //(custom) break; @@ -3873,7 +3883,7 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s case RL_SLUGSHOT: { uint16 w = 50; - int16 idx = 0; + int16 idx = -1; if (sd && (idx = sd->equip_index[EQI_AMMO]) >= 0 && sd->inventory_data[idx]) w = sd->inventory_data[idx]->weight; w /= 10; @@ -3881,9 +3891,8 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s } break; case RL_D_TAIL: + // 3000%:3500%:4000%:4500%:5000% skillratio += -100 + (2500 + 500 * skill_lv ); - //if (sd && &sd->c_marker) - // skillratio /= max(sd->c_marker.count,1); break; case RL_R_TRIP: skillratio += -100 + (150 * skill_lv); //(custom) @@ -3892,10 +3901,11 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s skillratio += -100 + (50 * skill_lv); //(custom) break; case RL_H_MINE: - skillratio += 100 + (200 * skill_lv); - //If damaged by Flicker - if (sd && sd->skill_id_old == RL_FLICKER && tsc && tsc->data[SC_H_MINE] && tsc->data[SC_H_MINE]->val2 == src->id) - skillratio += 400 + (300 * skill_lv); + // 400%:600%:800%:1000%:1200% + skillratio += -100 + (200 + 200 * skill_lv); + //If damaged by Flicker, explosion damage (800%:1100%:1400%:1700%:2000%) + if (sd && sd->flicker) + skillratio += 300 + (100 * skill_lv); break; case RL_HAMMER_OF_GOD: //! TODO: Please check the right formula. [Cydh] @@ -6156,7 +6166,8 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * md.damage = ( skill_lv * status_get_lv(src) * 10 ) + ( status_get_int(src) * 7 / 2 ) * ( 18 + (sd?sd->status.job_level:0) / 4 ) * ( 5 / (10 - ((sd) ? pc_checkskill(sd,AM_CANNIBALIZE) : skill_get_max(AM_CANNIBALIZE))) ); break; case RL_B_TRAP: - md.damage = (200 + status_get_int(src) + status_get_dex(src)) * skill_lv * 10; //(custom) + // kRO 2014-02-12: Damage: Caster's DEX, Target's current HP, Skill Level + md.damage = ((200 + status_get_dex(src)) * skill_lv * 10) + sstatus->hp; // (custom) break; } diff --git a/src/map/chrif.c b/src/map/chrif.c index 7c7966f5b0..1049502ba6 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -1375,7 +1375,7 @@ int chrif_load_scdata(int fd) { for (i = 0; i < count; i++) { struct status_change_data *data = (struct status_change_data*)RFIFOP(fd,14 + i*sizeof(struct status_change_data)); - status_change_start(NULL,&sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, 1|2|4|8); + status_change_start(NULL,&sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_LOADED|SCSTART_NORATEDEF); } pc_scdata_received(sd); diff --git a/src/map/clif.c b/src/map/clif.c index 08ebb74b76..8313cdbd18 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -753,22 +753,22 @@ void clif_dropflooritem(struct flooritem_data* fitem) nullpo_retv(fitem); - if (fitem->item_data.nameid == 0) + if (fitem->item.nameid == 0) return; WBUFW(buf, offset+0) = header; WBUFL(buf, offset+2) = fitem->bl.id; - WBUFW(buf, offset+6) = ((view = itemdb_viewid(fitem->item_data.nameid)) > 0) ? view : fitem->item_data.nameid; + WBUFW(buf, offset+6) = ((view = itemdb_viewid(fitem->item.nameid)) > 0) ? view : fitem->item.nameid; #if PACKETVER >= 20130000 - WBUFW(buf, offset+8) = itemtype(fitem->item_data.nameid); + WBUFW(buf, offset+8) = itemtype(fitem->item.nameid); offset +=2; #endif - WBUFB(buf, offset+8) = fitem->item_data.identify; + WBUFB(buf, offset+8) = fitem->item.identify; WBUFW(buf, offset+9) = fitem->bl.x; WBUFW(buf, offset+11) = fitem->bl.y; WBUFB(buf, offset+13) = fitem->subx; WBUFB(buf, offset+14) = fitem->suby; - WBUFW(buf, offset+15) = fitem->item_data.amount; + WBUFW(buf, offset+15) = fitem->item.amount; clif_send(buf, packet_len(header), &fitem->bl, AREA); } @@ -4498,14 +4498,14 @@ void clif_getareachar_item(struct map_session_data* sd,struct flooritem_data* fi WFIFOHEAD(fd,packet_len(0x9d)); WFIFOW(fd,0)=0x9d; WFIFOL(fd,2)=fitem->bl.id; - if((view = itemdb_viewid(fitem->item_data.nameid)) > 0) + if((view = itemdb_viewid(fitem->item.nameid)) > 0) WFIFOW(fd,6)=view; else - WFIFOW(fd,6)=fitem->item_data.nameid; - WFIFOB(fd,8)=fitem->item_data.identify; + WFIFOW(fd,6)=fitem->item.nameid; + WFIFOB(fd,8)=fitem->item.identify; WFIFOW(fd,9)=fitem->bl.x; WFIFOW(fd,11)=fitem->bl.y; - WFIFOW(fd,13)=fitem->item_data.amount; + WFIFOW(fd,13)=fitem->item.amount; WFIFOB(fd,15)=fitem->subx; WFIFOB(fd,16)=fitem->suby; WFIFOSET(fd,packet_len(0x9d)); @@ -13173,7 +13173,7 @@ void clif_parse_GM_Item_Monster(int fd, struct map_session_data *sd) // Item if( (id = itemdb_searchname(str)) ) { StringBuf_Init(&command); - if( id->type == IT_WEAPON || id->type == IT_ARMOR ) //Nonstackable + if( !itemdb_isstackable2(id) ) //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); @@ -17340,21 +17340,36 @@ void clif_parse_GMFullStrip(int fd, struct map_session_data *sd) { /** * Marks Crimson Marker target on mini-map to the caster -* TODO: Please, check the proper packet for Crimson Marker [Cydh] +* 09C1 .L .W .W (ZC_C_MARKERINFO) * @param fd * @param bl Crimson Marker target -* @param remove True remove the marker from map, false therwise **/ -void clif_crimson_marker(int fd, struct block_list *bl, bool remove) { - WFIFOHEAD(fd,packet_len(0x107)); - WFIFOW(fd,0) = 0x107; - WFIFOL(fd,2) = bl->id; - WFIFOW(fd,6) = (remove) ? -1 : bl->x; - WFIFOW(fd,8) = (remove) ? -1 : bl->y; - WFIFOSET(fd,packet_len(0x107)); +void clif_crimson_marker(struct map_session_data *sd, struct block_list *bl, bool remove) { + struct s_packet_db* info; + int cmd = 0; + int16 len; + unsigned char buf[11]; + + nullpo_retv(sd); + + cmd = packet_db_ack[sd->packet_ver][ZC_C_MARKERINFO]; + if (!cmd) + cmd = 0x09C1; //default + info = &packet_db[sd->packet_ver][cmd]; + if (!(len = info->len)) + return; + + WBUFW(buf, 0) = cmd; + WBUFL(buf, info->pos[0]) = bl->id; + WBUFW(buf, info->pos[1]) = (remove ? -1 : bl->x); + WBUFW(buf, info->pos[2]) = (remove ? -1 : bl->y); + clif_send(buf, len, &sd->bl, SELF); } -///TODO: Special item that obtained, must be broadcasted by this packet +/** +* !TODO: Special item that obtained, must be broadcasted by this packet +* 07fd ?? (ZC_BROADCASTING_SPECIAL_ITEM_OBTAIN) +*/ //void clif_broadcast_obtain_special_item() {} #ifdef DUMP_UNKNOWN_PACKET @@ -17531,7 +17546,7 @@ void packetdb_readdb(void) int max_cmd=-1; bool skip_ver = false; int warned = 0; - char *str[64],*p,*str2[64],*p2,w1[256],w2[256]; + int packet_ver = MAX_PACKET_VER; // read into packet_db's version by default int packet_len_table[MAX_PACKET_DB] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -18012,6 +18027,7 @@ void packetdb_readdb(void) { "ZC_PERSONAL_INFOMATION", ZC_PERSONAL_INFOMATION}, { "ZC_PERSONAL_INFOMATION_CHN", ZC_PERSONAL_INFOMATION_CHN}, { "ZC_CLEAR_DIALOG", ZC_CLEAR_DIALOG}, + { "ZC_C_MARKERINFO", ZC_C_MARKERINFO}, }; const char *filename[] = { "packet_db.txt", DBIMPORT"/packet_db.txt"}; int f; @@ -18022,14 +18038,14 @@ void packetdb_readdb(void) packet_len(i) = packet_len_table[i]; clif_config.packet_db_ver = MAX_PACKET_VER; - for(f = 0; fstatus.char_id << 32) | sd->status.uniqueitem_counter++; -} - /** Check if the item is restricted by item_noequip.txt * @param id Item that will be checked * @param m Map ID @@ -1465,10 +1456,10 @@ bool itemdb_isNoEquip(struct item_data *id, uint16 m) { */ bool itemdb_is_spellbook2(unsigned short nameid) { unsigned char i; - if (!nameid || !itemdb_exists(nameid)) + if (!nameid || !itemdb_exists(nameid) || !skill_spellbook_count) return false; ARR_FIND(0, MAX_SKILL_SPELLBOOK_DB, i, skill_spellbook_db[i].nameid == nameid); - if (i >= MAX_SKILL_SPELLBOOK_DB) + if (i == MAX_SKILL_SPELLBOOK_DB) return false; return true; } diff --git a/src/map/itemdb.h b/src/map/itemdb.h index c9f97a0676..1b2de2ad12 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -480,7 +480,6 @@ bool itemdb_isequip2(struct item_data *id); char itemdb_isidentified(unsigned short nameid); bool itemdb_isstackable2(struct item_data *id); #define itemdb_isstackable(nameid) itemdb_isstackable2(itemdb_search(nameid)) -uint64 itemdb_unique_id(struct map_session_data *sd); // Unique Item ID bool itemdb_isNoEquip(struct item_data *id, uint16 m); struct item_combo *itemdb_combo_exists(unsigned short combo_id); diff --git a/src/map/map.c b/src/map/map.c index 94aba96f52..17a641f2a7 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1289,8 +1289,8 @@ int map_clearflooritem_timer(int tid, unsigned int tick, int id, intptr_t data) } - if (search_petDB_index(fitem->item_data.nameid, PET_EGG) >= 0) - intif_delete_petdata(MakeDWord(fitem->item_data.card[1], fitem->item_data.card[2])); + if (search_petDB_index(fitem->item.nameid, PET_EGG) >= 0) + intif_delete_petdata(MakeDWord(fitem->item.card[1], fitem->item.card[2])); clif_clearflooritem(fitem, 0); map_deliddb(&fitem->bl); @@ -1442,14 +1442,14 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1 * @param flag: &1 MVP item. &2 do stacking check. &4 bypass droppable check. * @return 0:failure, x:item_gid [MIN_FLOORITEM;MAX_FLOORITEM]==[2;START_ACCOUNT_NUM] *------------------------------------------*/ -int map_addflooritem(struct item *item_data,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags) +int map_addflooritem(struct item *item,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags) { int r; struct flooritem_data *fitem=NULL; - nullpo_ret(item_data); + nullpo_ret(item); - if(!(flags&4) && battle_config.item_onfloor && (itemdb_traderight(item_data->nameid)&1) ) + if(!(flags&4) && battle_config.item_onfloor && (itemdb_traderight(item->nameid)&1) ) return 0; //can't be dropped if(!map_searchrandfreecell(m,&x,&y,flags&2?1:0)) @@ -1475,8 +1475,8 @@ int map_addflooritem(struct item *item_data,int amount,int16 m,int16 x,int16 y,i fitem->third_get_charid = third_charid; fitem->third_get_tick = fitem->second_get_tick + (flags&1 ? battle_config.mvp_item_third_get_time : battle_config.item_third_get_time); - memcpy(&fitem->item_data,item_data,sizeof(*item_data)); - fitem->item_data.amount=amount; + memcpy(&fitem->item,item,sizeof(*item)); + fitem->item.amount=amount; fitem->subx=(r&3)*3+3; fitem->suby=((r>>2)&3)*3+3; fitem->cleartimer=add_timer(gettick()+battle_config.flooritem_lifetime,map_clearflooritem_timer,fitem->bl.id,0); diff --git a/src/map/map.h b/src/map/map.h index 3d9ba11b34..7d7a46b3f2 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -425,7 +425,7 @@ struct flooritem_data { int cleartimer; int first_get_charid,second_get_charid,third_get_charid; unsigned int first_get_tick,second_get_tick,third_get_tick; - struct item item_data; + struct item item; }; enum _sp { @@ -795,7 +795,7 @@ bool map_addnpc(int16 m,struct npc_data *); int map_clearflooritem_timer(int tid, unsigned int tick, int id, intptr_t data); int map_removemobs_timer(int tid, unsigned int tick, int id, intptr_t data); void map_clearflooritem(struct block_list* bl); -int map_addflooritem(struct item *item_data,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags); +int map_addflooritem(struct item *item,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags); // instances int map_addinstancemap(const char*,int); diff --git a/src/map/mob.c b/src/map/mob.c index 69292c2755..4e08a8d81c 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -417,7 +417,7 @@ bool mob_ksprotected (struct block_list *src, struct block_list *target) return true; } while(0); - status_change_start(src, target, SC_KSPROTECTED, 10000, sd->bl.id, sd->state.noks, sd->status.party_id, sd->status.guild_id, battle_config.ksprotection, 0); + status_change_start(src, target, SC_KSPROTECTED, 10000, sd->bl.id, sd->state.noks, sd->status.party_id, sd->status.guild_id, battle_config.ksprotection, SCSTART_NOAVOID); return false; } @@ -1603,15 +1603,15 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) fitem = (struct flooritem_data *)tbl; //Logs items, taken by (L)ooter Mobs [Lupus] - log_pick_mob(md, LOG_TYPE_LOOT, fitem->item_data.amount, &fitem->item_data); + log_pick_mob(md, LOG_TYPE_LOOT, fitem->item.amount, &fitem->item); if (md->lootitem_count < LOOTITEM_SIZE) { - memcpy (&md->lootitem[md->lootitem_count++], &fitem->item_data, sizeof(md->lootitem[0])); + memcpy (&md->lootitem[md->lootitem_count++], &fitem->item, sizeof(md->lootitem[0])); } else { //Destroy first looted item... if (md->lootitem[0].card[0] == CARD0_PET) intif_delete_petdata( MakeDWord(md->lootitem[0].card[1],md->lootitem[0].card[2]) ); memmove(&md->lootitem[0], &md->lootitem[1], (LOOTITEM_SIZE-1)*sizeof(md->lootitem[0])); - memcpy (&md->lootitem[LOOTITEM_SIZE-1], &fitem->item_data, sizeof(md->lootitem[0])); + memcpy (&md->lootitem[LOOTITEM_SIZE-1], &fitem->item, sizeof(md->lootitem[0])); } if (pcdb_checkid(md->vd->class_)) { //Give them walk act/delay to properly mimic players. [Skotlex] diff --git a/src/map/npc.c b/src/map/npc.c index 40b4037528..9bf6fd69fd 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -4175,6 +4175,8 @@ bool npc_unloadfile( const char* path ) { if( found ) /* refresh event cache */ npc_read_event_script(); + npc_delsrcfile(path); + return found; } diff --git a/src/map/pc.c b/src/map/pc.c index 0dc83da3c9..27d5794d03 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -4311,7 +4311,7 @@ char pc_additem(struct map_session_data *sd,struct item *item,int amount,e_log_p clif_additem(sd,i,amount,0); } if( !itemdb_isstackable2(id) && !item->unique_id ) - sd->status.inventory[i].unique_id = itemdb_unique_id(sd); + sd->status.inventory[i].unique_id = pc_generate_unique_id(sd); log_pick_pc(sd, log_type, amount, &sd->status.inventory[i]); sd->weight += w; @@ -4471,7 +4471,7 @@ bool pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem) } //This function takes care of giving the item to whoever should have it, considering party-share options. - if ((flag = party_share_loot(p,sd,&fitem->item_data, fitem->first_get_charid))) { + if ((flag = party_share_loot(p,sd,&fitem->item, fitem->first_get_charid))) { clif_additem(sd,0,0,flag); return true; } @@ -9546,7 +9546,7 @@ void pc_check_available_item(struct map_session_data *sd) { continue; } if (!sd->status.inventory[i].unique_id && !itemdb_isstackable(it)) - sd->status.inventory[i].unique_id = itemdb_unique_id(sd); + sd->status.inventory[i].unique_id = pc_generate_unique_id(sd); } } @@ -9564,7 +9564,7 @@ void pc_check_available_item(struct map_session_data *sd) { continue; } if (!sd->status.cart[i].unique_id && !itemdb_isstackable(it)) - sd->status.cart[i].unique_id = itemdb_unique_id(sd); + sd->status.cart[i].unique_id = pc_generate_unique_id(sd); } } @@ -9582,7 +9582,7 @@ void pc_check_available_item(struct map_session_data *sd) { continue; } if (!sd->status.storage.items[i].unique_id && !itemdb_isstackable(it)) - sd->status.storage.items[i].unique_id = itemdb_unique_id(sd); + sd->status.storage.items[i].unique_id = pc_generate_unique_id(sd); } } } @@ -10964,22 +10964,21 @@ enum e_BANKING_WITHDRAW_ACK pc_bank_withdraw(struct map_session_data *sd, int mo } /** -* Clear Cirmson Marker data from caster +* Clear Crimson Marker data from caster * @param sd: Player **/ void pc_crimson_marker_clear(struct map_session_data *sd) { uint8 i; - if (!sd || !(&sd->c_marker) || !sd->c_marker.target) + if (!sd) return; for (i = 0; i < MAX_SKILL_CRIMSON_MARKER; i++) { struct block_list *bl = NULL; - if (sd->c_marker.target[i] && (bl = map_id2bl(sd->c_marker.target[i]))) + if (sd->c_marker[i] && (bl = map_id2bl(sd->c_marker[i]))) status_change_end(bl,SC_C_MARKER,INVALID_TIMER); - sd->c_marker.target[i] = 0; + sd->c_marker[i] = 0; } - sd->c_marker.count = 0; } /** @@ -11233,6 +11232,15 @@ bool pc_is_same_equip_index(enum equip_index eqi, short *equip_index, short inde return false; } +/** + * Generate Unique item ID for player + * @param sd : Player + * @return A generated Unique item ID + */ +uint64 pc_generate_unique_id(struct map_session_data *sd) { + return ((uint64)sd->status.char_id << 32) | sd->status.uniqueitem_counter++; +} + /*========================================== * pc Init/Terminate *------------------------------------------*/ diff --git a/src/map/pc.h b/src/map/pc.h index c29f471fdb..86fd65fca6 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -591,11 +591,8 @@ struct map_session_data { uint16 dmglog[DAMAGELOG_SIZE_PC]; ///target ids - struct s_crimson_marker { ///Store target that marked by Crimson Marker [Cydh] - int target[MAX_SKILL_CRIMSON_MARKER]; //Target id storage - uint8 count; //Count of target for skill used (i.e. RL_D_TAIL). - } c_marker; - bool flicker; ///Is Flicker Skill skill as player's last action? [Cydh] + int c_marker[MAX_SKILL_CRIMSON_MARKER]; /// Store target that marked by Crimson Marker [Cydh] + bool flicker; /// Check RL_FLICKER usage status [Cydh] int storage_size; /// Holds player storage size (VIP system). #ifdef VIP_ENABLE @@ -879,6 +876,8 @@ char pc_additem(struct map_session_data *sd, struct item *item, int amount, e_lo char pc_getzeny(struct map_session_data *sd, int zeny, enum e_log_pick_type type, struct map_session_data *tsd); char pc_delitem(struct map_session_data *sd, int n, int amount, int type, short reason, e_log_pick_type log_type); +uint64 pc_generate_unique_id(struct map_session_data *sd); + //Bound items int pc_bound_chk(TBL_PC *sd,enum bound_type type,int *idxlist); diff --git a/src/map/pet.c b/src/map/pet.c index e57c57fe50..d27be6c9ca 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -946,8 +946,8 @@ static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, uns } else{ struct flooritem_data *fitem = (struct flooritem_data *)target; if(pd->loot->count < pd->loot->max){ - memcpy(&pd->loot->item[pd->loot->count++],&fitem->item_data,sizeof(pd->loot->item[0])); - pd->loot->weight += itemdb_weight(fitem->item_data.nameid)*fitem->item_data.amount; + memcpy(&pd->loot->item[pd->loot->count++],&fitem->item,sizeof(pd->loot->item[0])); + pd->loot->weight += itemdb_weight(fitem->item.nameid)*fitem->item.amount; map_clearflooritem(target); } //Target is unlocked regardless of whether it was picked or not. diff --git a/src/map/script.c b/src/map/script.c index 2932240966..e17ee7c3bb 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -2369,6 +2369,14 @@ void script_hardcoded_constants(void) { script_set_constant("BSF_REM_DEBUFF",BSF_REM_DEBUFF,false); script_set_constant("BSF_ALL",BSF_ALL,false); script_set_constant("BSF_CLEARALL",BSF_CLEARALL,false); + + /* sc_start flags */ + script_set_constant("SCSTART_NONE",SCSTART_NONE,false); + script_set_constant("SCSTART_NOAVOID",SCSTART_NOAVOID,false); + script_set_constant("SCSTART_NOTICKDEF",SCSTART_NOTICKDEF,false); + script_set_constant("SCSTART_LOADED",SCSTART_LOADED,false); + script_set_constant("SCSTART_NORATEDEF",SCSTART_NORATEDEF,false); + script_set_constant("SCSTART_NOICON",SCSTART_NOICON,false); } /*========================================== @@ -7753,8 +7761,31 @@ BUILDIN_FUNC(strnpcinfo) } -// aegis->athena slot position conversion table -static unsigned int equip[] = {EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_GARMENT,EQP_SHOES,EQP_ACC_L,EQP_ACC_R,EQP_HEAD_MID,EQP_HEAD_LOW,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_GARMENT,EQP_AMMO,EQP_SHADOW_ARMOR,EQP_SHADOW_WEAPON,EQP_SHADOW_SHIELD,EQP_SHADOW_SHOES,EQP_SHADOW_ACC_R,EQP_SHADOW_ACC_L}; +/// aegis->athena slot position conversion table +/// Index is used by EQI_ in db/const.txt +static unsigned int equip[] = { + EQP_HEAD_TOP, + EQP_ARMOR, + EQP_HAND_L, + EQP_HAND_R, + EQP_GARMENT, + EQP_SHOES, + EQP_ACC_L, + EQP_ACC_R, + EQP_HEAD_MID, + EQP_HEAD_LOW, + EQP_COSTUME_HEAD_LOW, + EQP_COSTUME_HEAD_MID, + EQP_COSTUME_HEAD_TOP, + EQP_COSTUME_GARMENT, + EQP_AMMO, + EQP_SHADOW_ARMOR, + EQP_SHADOW_WEAPON, + EQP_SHADOW_SHIELD, + EQP_SHADOW_SHOES, + EQP_SHADOW_ACC_R, + EQP_SHADOW_ACC_L +}; /*========================================== * GetEquipID(Pos); Pos: 1-14 @@ -10267,12 +10298,12 @@ BUILDIN_FUNC(getareausers) *------------------------------------------*/ static int buildin_getareadropitem_sub(struct block_list *bl,va_list ap) { - int item=va_arg(ap,int); + int nameid=va_arg(ap,int); int *amount=va_arg(ap,int *); struct flooritem_data *drop=(struct flooritem_data *)bl; - if(drop->item_data.nameid==item) - (*amount)+=drop->item_data.amount; + if(drop->item.nameid==nameid) + (*amount)+=drop->item.amount; return 0; } @@ -10280,7 +10311,7 @@ BUILDIN_FUNC(getareadropitem) { const char *str; int16 m,x0,y0,x1,y1; - int item,amount=0; + int nameid,amount=0; struct script_data *data; str=script_getstr(st,2); @@ -10294,18 +10325,18 @@ BUILDIN_FUNC(getareadropitem) if( data_isstring(data) ){ const char *name=conv_str(st,data); struct item_data *item_data = itemdb_searchname(name); - item=UNKNOWN_ITEM_ID; + nameid=UNKNOWN_ITEM_ID; if( item_data ) - item=item_data->nameid; + nameid=item_data->nameid; }else - item=conv_num(st,data); + nameid=conv_num(st,data); if( (m=map_mapname2mapid(str))< 0){ script_pushint(st,-1); return 0; } map_foreachinarea(buildin_getareadropitem_sub, - m,x0,y0,x1,y1,BL_ITEM,item,&amount); + m,x0,y0,x1,y1,BL_ITEM,nameid,&amount); script_pushint(st,amount); return SCRIPT_CMD_SUCCESS; } @@ -10492,7 +10523,7 @@ BUILDIN_FUNC(getscrate) bl = map_id2bl(st->rid); if (bl) - rate = status_get_sc_def(NULL,bl, (sc_type)type, 10000, 10000, 0); + rate = status_get_sc_def(NULL,bl, (sc_type)type, 10000, 10000, SCSTART_NONE); script_pushint(st,rate); return SCRIPT_CMD_SUCCESS; @@ -16674,7 +16705,7 @@ BUILDIN_FUNC(mercenary_sc_start) tick = script_getnum(st,3); val1 = script_getnum(st,4); - status_change_start(NULL, &sd->md->bl, type, 10000, val1, 0, 0, 0, tick, 2); + status_change_start(NULL, &sd->md->bl, type, 10000, val1, 0, 0, 0, tick, SCSTART_NOTICKDEF); return SCRIPT_CMD_SUCCESS; } diff --git a/src/map/skill.c b/src/map/skill.c index c553c85d49..594f35df07 100755 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -80,7 +80,7 @@ struct s_skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB]; static unsigned short skill_arrow_count; struct s_skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB]; -static unsigned short skill_abra_count; +unsigned short skill_abra_count; struct s_skill_improvise_db { uint16 skill_id; @@ -102,11 +102,11 @@ static unsigned short skill_changematerial_count; //Warlock struct s_skill_spellbook_db skill_spellbook_db[MAX_SKILL_SPELLBOOK_DB]; -static unsigned short skill_spellbook_count; +unsigned short skill_spellbook_count; //Guillotine Cross struct s_skill_magicmushroom_db skill_magicmushroom_db[MAX_SKILL_MAGICMUSHROOM_DB]; -static unsigned short skill_magicmushroom_count; +unsigned short skill_magicmushroom_count; struct s_skill_unit_layout skill_unit_layout[MAX_SKILL_UNIT_LAYOUT]; int firewall_unit_pos; @@ -127,6 +127,7 @@ static int skill_check_unit_range (struct block_list *bl, int x, int y, uint16 s static int skill_check_unit_range2 (struct block_list *bl, int x, int y, uint16 skill_id, uint16 skill_lv, bool isNearNPC); static int skill_destroy_trap( struct block_list *bl, va_list ap ); static int skill_check_condition_mob_master_sub (struct block_list *bl, va_list ap); +static bool skill_check_condition_sc_required(struct map_session_data *sd, unsigned short skill_id, struct skill_condition *require); //Since only mob-casted splash skills can hit ice-walls static inline int splash_target(struct block_list* bl) { #ifndef RENEWAL @@ -262,7 +263,6 @@ int skill_tree_get_max(uint16 skill_id, int b_class) return skill_get_max(skill_id); } int skill_frostjoke_scream(struct block_list *bl,va_list ap); -int skill_check_target_c_marker(struct block_list *bl,va_list ap); int skill_attack_area(struct block_list *bl,va_list ap); struct skill_unit_group *skill_locate_element_field(struct block_list *bl); // [Skotlex] int skill_graffitiremover(struct block_list *bl, va_list ap); // [Valaris] @@ -274,9 +274,7 @@ struct skill_unit_group_tickset *skill_unitgrouptickset_search(struct block_list static int skill_unit_onplace(struct skill_unit *src,struct block_list *bl,unsigned int tick); int skill_unit_onleft(uint16 skill_id, struct block_list *bl,unsigned int tick); static int skill_unit_effect(struct block_list *bl,va_list ap); - -int enchant_eff[5] = { 10, 14, 17, 19, 20 }; -int deluge_eff[5] = { 5, 9, 12, 14, 15 }; +static int skill_bind_trap(struct block_list *bl, va_list ap); int skill_get_casttype (uint16 skill_id) { int inf = skill_get_inf(skill_id); @@ -869,10 +867,10 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint skill = skill_get_time2(status_sc2skill(type),7); if (sd->addeff[i].flag&ATF_TARGET) - status_change_start(src,bl,type,rate,7,0,(type == SC_BURNING)?src->id:0,0,skill,0); + status_change_start(src,bl,type,rate,7,0,(type == SC_BURNING)?src->id:0,0,skill,SCSTART_NONE); if (sd->addeff[i].flag&ATF_SELF) - status_change_start(src,src,type,rate,7,0,(type == SC_BURNING)?src->id:0,0,skill,0); + status_change_start(src,src,type,rate,7,0,(type == SC_BURNING)?src->id:0,0,skill,SCSTART_NONE); } } @@ -887,9 +885,9 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint skill = skill_get_time2(status_sc2skill(type),7); if( sd->addeff3[i].target&ATF_TARGET ) - status_change_start(src,bl,type,sd->addeff3[i].rate,7,0,0,0,skill,0); + status_change_start(src,bl,type,sd->addeff3[i].rate,7,0,0,0,skill,SCSTART_NONE); if( sd->addeff3[i].target&ATF_SELF ) - status_change_start(src,src,type,sd->addeff3[i].rate,7,0,0,0,skill,0); + status_change_start(src,src,type,sd->addeff3[i].rate,7,0,0,0,skill,SCSTART_NONE); } //"While the damage can be blocked by Pneuma, the chance to break armor remains", irowiki. [Cydh] if (dmg_lv == ATK_BLOCK && skill_id == AM_ACIDTERROR) { @@ -957,7 +955,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint // Enchant Poison gives a chance to poison attacked enemies if((sce=sc->data[SC_ENCPOISON])) //Don't use sc_start since chance comes in 1/10000 rate. status_change_start(src,bl,SC_POISON,sce->val2, sce->val1,src->id,0,0, - skill_get_time2(AS_ENCHANTPOISON,sce->val1),0); + skill_get_time2(AS_ENCHANTPOISON,sce->val1),SCSTART_NONE); // Enchant Deadly Poison gives a chance to deadly poison attacked enemies if((sce=sc->data[SC_EDP])) sc_start4(src,bl,SC_DPOISON,sce->val2, sce->val1,src->id,0,0, @@ -970,7 +968,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint if( sd && skill_lv > 5 && pc_checkskill(sd,SM_FATALBLOW)>0 ){ //BaseChance gets multiplied with BaseLevel/50.0; 500/50 simplifies to 10 [Playtester] status_change_start(src,bl,SC_STUN,(skill_lv-5)*sd->status.base_level*10, - skill_lv,0,0,0,skill_get_time2(SM_FATALBLOW,skill_lv),0); + skill_lv,0,0,0,skill_get_time2(SM_FATALBLOW,skill_lv),SCSTART_NONE); } break; @@ -1257,7 +1255,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint break; case GS_BULLSEYE: //0.1% coma rate. if(tstatus->race == RC_BRUTE || tstatus->race == RC_DEMIHUMAN || tstatus->race == RC_PLAYER) - status_change_start(src,bl,SC_COMA,10,skill_lv,0,src->id,0,0,0); + status_change_start(src,bl,SC_COMA,10,skill_lv,0,src->id,0,0,SCSTART_NONE); break; case GS_PIERCINGSHOT: sc_start2(src,bl,SC_BLEEDING,(skill_lv*3),skill_lv,src->id,skill_get_time2(skill_id,skill_lv)); @@ -1400,7 +1398,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint break; case LG_HESPERUSLIT: if( sc && sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 3 ) - status_change_start(src,bl, SC_STUN, 10000, skill_lv, 0, 0, 0, rnd_value(4000, 8000), 2); + status_change_start(src,bl, SC_STUN, 10000, skill_lv, 0, 0, 0, rnd_value(4000, 8000), SCSTART_NOTICKDEF); if( pc_checkskill(sd,LG_PINPOINTATTACK) > 0 && sc && sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 5 ) skill_castend_damage_id(src,bl,LG_PINPOINTATTACK,rnd_value(1, pc_checkskill(sd,LG_PINPOINTATTACK)),tick,0); break; @@ -1563,9 +1561,6 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint case RL_SLUGSHOT: if (bl->type != BL_PC) sc_start(src,bl,SC_STUN,10 * skill_lv + rnd()%50,skill_lv,skill_get_time2(skill_id,skill_lv)); //(custom) - else if (dstsd) - //sit duration 2+skill_lv - status_change_start(src,bl,SC_SITDOWN_FORCE,10000,skill_lv,0,0,0,(2+skill_lv)*1000,1|2|8); break; case RL_BANISHING_BUSTER: { @@ -1676,17 +1671,9 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint case RL_AM_BLAST: sc_start(src,bl,SC_ANTI_M_BLAST,10 * skill_lv + rnd()%50,skill_lv,skill_get_time2(skill_id,skill_lv)); //(custom) break; - case RL_B_TRAP: - if (sd && sd->skill_id_old == RL_FLICKER && tsc && tsc->data[SC_B_TRAP]) - status_change_end(bl,SC_B_TRAP,INVALID_TIMER); - break; case RL_HAMMER_OF_GOD: sc_start(src,bl,SC_STUN,100,skill_lv,skill_get_time2(skill_id,skill_lv)); - case RL_D_TAIL: - case RL_QD_SHOT: - status_change_end(bl,SC_C_MARKER,INVALID_TIMER); - if (sc->data[SC_QD_SHOT_READY]) - status_change_end(bl,SC_QD_SHOT_READY,INVALID_TIMER); + status_change_end(bl, SC_C_MARKER, INVALID_TIMER); break; } //end switch skill_id @@ -1704,7 +1691,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint rate += sd->weapon_coma_race[tstatus->race] + sd->weapon_coma_race[RC_ALL]; rate += sd->weapon_coma_class[tstatus->class_] + sd->weapon_coma_class[CLASS_ALL]; if (rate) - status_change_start(src,bl, SC_COMA, rate, 0, 0, src->id, 0, 0, 0); + status_change_start(src,bl, SC_COMA, rate, 0, 0, src->id, 0, 0, SCSTART_NONE); } if( sd && battle_config.equip_self_break_rate ) { // Self weapon breaking @@ -1744,10 +1731,10 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint if (sd && !skill_id && bl->type == BL_PC) { // This effect does not work with skills. if (sd->def_set_race[tstatus->race].rate) status_change_start(src,bl, SC_DEFSET, sd->def_set_race[tstatus->race].rate, sd->def_set_race[tstatus->race].value, - 0, 0, 0, sd->def_set_race[tstatus->race].tick, 2); + 0, 0, 0, sd->def_set_race[tstatus->race].tick, SCSTART_NOTICKDEF); if (sd->def_set_race[tstatus->race].rate) status_change_start(src,bl, SC_MDEFSET, sd->mdef_set_race[tstatus->race].rate, sd->mdef_set_race[tstatus->race].value, - 0, 0, 0, sd->mdef_set_race[tstatus->race].tick, 2); + 0, 0, 0, sd->mdef_set_race[tstatus->race].tick, SCSTART_NOTICKDEF); } } @@ -2047,10 +2034,10 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * time = skill_get_time2(status_sc2skill(type),7); if (dstsd->addeff2[i].flag&ATF_TARGET) - status_change_start(src,src,type,rate,7,0,0,0,time,0); + status_change_start(src,src,type,rate,7,0,0,0,time,SCSTART_NONE); if (dstsd->addeff2[i].flag&ATF_SELF && !status_isdead(bl)) - status_change_start(src,bl,type,rate,7,0,0,0,time,0); + status_change_start(src,bl,type,rate,7,0,0,0,time,SCSTART_NONE); } } @@ -2088,7 +2075,7 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * if(sd && (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && map[sd->bl.m].flag.nosumstarmiracle == 0) //SG_MIRACLE [Komurka] - status_change_start(src,src,SC_MIRACLE,battle_config.sg_miracle_skill_ratio,1,0,0,0,battle_config.sg_miracle_skill_duration,0); + status_change_start(src,src,SC_MIRACLE,battle_config.sg_miracle_skill_ratio,1,0,0,0,battle_config.sg_miracle_skill_duration,SCSTART_NONE); if(sd && skill_id && attack_type&BF_MAGIC && status_isdead(bl) && !(skill_get_inf(skill_id)&(INF_GROUND_SKILL|INF_SELF_SKILL)) && @@ -2354,8 +2341,15 @@ int skill_strip_equip(struct block_list *src,struct block_list *bl, unsigned sho } return where?1:0; } -//Early declaration + +/* Stores temporary values. +* Common usages: +* [0] holds number of targets in area +* [1] holds the id of the original target +* [2] counts how many targets have already been processed +*/ static int skill_area_temp[8]; + /*========================================================================= Used to knock back players, monsters, traps, etc * @param src Object that give knock back @@ -2802,6 +2796,10 @@ void skill_attack_blow(struct block_list *src, struct block_list *dsrc, struct b if (skill_blown(dsrc,target,blewcount,dir,0) < blewcount) skill_addtimerskill(src, tick + status_get_amotion(src), target->id, 0, 0, RL_R_TRIP_PLUSATK, skill_lv, BF_WEAPON, flag|SD_ANIMATION); break; + case RL_SLUGSHOT: + skill_blown(dsrc,target,blewcount,dir, 0x0); + skill_addtimerskill(src, tick + status_get_amotion(src), target->id, 0, 0, skill_id, skill_lv, skill_get_type(skill_id), flag|SD_ANIMATION); + break; default: skill_blown(dsrc,target,blewcount,dir, 0x0 ); if (!blewcount && target->type == BL_SKILL && damage > 0) { @@ -2828,7 +2826,7 @@ void skill_attack_blow(struct block_list *src, struct block_list *dsrc, struct b * flag&0xFFF is passed to the underlying battle_calc_attack for processing * (usually holds number of targets, or just 1 for simple splash attacks) * - * Values from enum e_skill_display * + * Values from enum e_skill_display * Values from enum e_battle_check_target *-------------------------------------------------------------------------*/ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag) @@ -2843,7 +2841,8 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * bool shadow_flag = false; bool additional_effects = true; - if(skill_id > 0 && !skill_lv) return 0; + if(skill_id > 0 && !skill_lv) + return 0; nullpo_ret(src); //Source is the master behind the attack (player/mob/pet) nullpo_ret(dsrc); //dsrc is the actual originator of the damage, can be the same as src, or a skill casted by src. @@ -3137,6 +3136,9 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * dmg.dmotion = clif_skill_damage(src,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, flag&SD_LEVEL?-1:skill_lv, 5); break; case RL_R_TRIP_PLUSATK: + case RL_BANISHING_BUSTER: + case RL_S_STORM: + case RL_SLUGSHOT: dmg.dmotion = clif_skill_damage(dsrc,bl,tick,status_get_amotion(src),dmg.dmotion,damage,dmg.div_,skill_id,-1,5); break; case AB_DUPLELIGHT_MELEE: @@ -3287,8 +3289,8 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * } /*========================================== - * sub fonction for recursive skill call. - * Checking bl battle flag and display dammage + * Sub function for recursive skill call. + * Checking bl battle flag and display damage * then call func with source,target,skill_id,skill_lv,tick,flag *------------------------------------------*/ typedef int (*SkillFunc)(struct block_list *, struct block_list *, int, int, unsigned int, int); @@ -3611,6 +3613,27 @@ static int skill_check_condition_mercenary(struct block_list *bl, int skill, int *------------------------------------------*/ int skill_area_sub_count (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag) { + switch (skill_id) { + case RL_QD_SHOT: + { + if (src->type == BL_PC && BL_CAST(BL_PC,src)) { + struct unit_data *ud = unit_bl2ud(src); + if (ud && ud->target == target->id) + return 1; + } + } + case RL_D_TAIL: + case RL_HAMMER_OF_GOD: + if (src->type != BL_PC) + return 0; + { + struct status_change *tsc = status_get_sc(target); + // Only counts marked target with SC_C_MARKER by caster + if (!tsc || !tsc->data[SC_C_MARKER] || tsc->data[SC_C_MARKER]->val2 != src->id) + return 0; + } + break; + } return 1; } @@ -3753,7 +3776,7 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) status_change_start(src,target, i, 10000, skl->skill_lv, (i == SC_BURNING ? 1000 : (i == SC_BLEEDING ? src->id : 0)), (i == SC_BURNING ? src->id : 0), - 0, skill_get_time(WL_TETRAVORTEX,skl->skill_lv)+1, 0); + 0, skill_get_time(WL_TETRAVORTEX,skl->skill_lv)+1, SCSTART_NONE); } } } @@ -3821,6 +3844,10 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) skill_addtimerskill(src, tick + 80, src->id, 0, 0, skl->skill_id, skl->skill_lv, skl->type + 1, 0); } break; + case RL_SLUGSHOT: + if (target->type == BL_PC) + sc_start(src, target, SC_SITDOWN_FORCE, 100, skl->skill_lv, skill_get_time(skl->skill_id, skl->skill_lv)); + break; default: skill_attack(skl->type,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag); break; @@ -4006,31 +4033,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint tstatus = status_get_status_data(bl); - //Hits the target if marked with SC_C_MARKER only - switch (skill_id) { - case RL_QD_SHOT: - if (sd && bl->id == sd->ud.target) - return 1; - case RL_D_TAIL: - case RL_HAMMER_OF_GOD: - { - tsc = status_get_sc(bl); - if (!tsc || !tsc->data[SC_C_MARKER] || tsc->data[SC_C_MARKER]->val2 != src->id) - return 1; - } - break; - case RL_FLICKER: - { - tsc = status_get_sc(bl); - if (!tsc) - return 1; - if ((!tsc->data[SC_H_MINE] || tsc->data[SC_H_MINE]->val2 != src->id) && - (!tsc->data[SC_B_TRAP] || tsc->data[SC_B_TRAP]->val2 != src->id)) - return 1; - } - break; - } - map_freeblock_lock(); switch(skill_id) @@ -4388,41 +4390,20 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case RL_FIREDANCE: case RL_BANISHING_BUSTER: case RL_S_STORM: - case RL_D_TAIL: case RL_R_TRIP: - case RL_FLICKER: - case RL_HAMMER_OF_GOD: - case RL_QD_SHOT: case MH_XENO_SLASHER: if( flag&1 ) {//Recursive invocation - // skill_area_temp[0] holds number of targets in area - // skill_area_temp[1] holds the id of the original target - // skill_area_temp[2] counts how many targets have already been processed int sflag = skill_area_temp[0] & 0xFFF; + int heal = 0; if( flag&SD_LEVEL ) sflag |= SD_LEVEL; // -1 will be used in packets instead of the skill level if( skill_area_temp[1] != bl->id && !(skill_get_inf2(skill_id)&INF2_NPC_SKILL) ) sflag |= SD_ANIMATION; // original target gets no animation (as well as all NPC skills) - if (skill_id == RL_FLICKER) { //Skills that triggered by RL_FLICKER - tsc = status_get_sc(bl); - if (sd) - sd->flicker = true; - if (!tsc) - break; - if (tsc->data[SC_B_TRAP]) - skill_attack(skill_get_type(RL_B_TRAP), src, src, bl, RL_B_TRAP, pc_checkskill(sd,RL_B_TRAP), tick, sflag); - if (tsc->data[SC_H_MINE]) - skill_castend_damage_id(src,bl,RL_H_MINE,pc_checkskill(sd,RL_H_MINE),tick,sflag); - if (sd) - sd->flicker = false; - } - else { - int heal = (int)skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, sflag); - if( skill_id == NPC_VAMPIRE_GIFT && heal > 0 ) { - clif_skill_nodamage(NULL, src, AL_HEAL, heal, 1); - status_heal(src,heal,0,0); - } + heal = (int)skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, sflag); + if( skill_id == NPC_VAMPIRE_GIFT && heal > 0 ) { + clif_skill_nodamage(NULL, src, AL_HEAL, heal, 1); + status_heal(src,heal,0,0); } } else { switch ( skill_id ) { @@ -4629,6 +4610,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case WM_METALICSOUND: case KO_KAIHOU: case MH_ERASER_CUTTER: + case RL_B_TRAP: skill_attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag); break; @@ -4699,7 +4681,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case SL_STIN: case SL_STUN: if (sd && !battle_config.allow_es_magic_pc && bl->type != BL_MOB) { - status_change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,10); + status_change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,SCSTART_NOTICKDEF|SCSTART_NORATEDEF); clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } @@ -5066,7 +5048,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint // Causes Freezing status through walls. sc_start(src,bl,status_skill2sc(skill_id),20+12*skill_lv+(sd ? sd->status.job_level : 50)/5,skill_lv,skill_get_time(skill_id,skill_lv)); // Doesn't deal damage through non-shootable walls. - if( path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKWALL) ) + if( !battle_config.skill_wall_check || (battle_config.skill_wall_check && path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKWALL)) ) skill_attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag|SD_ANIMATION); break; case WL_HELLINFERNO: @@ -5366,12 +5348,13 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint //recursive homon skill case MH_MAGMA_FLOW: case MH_HEILIGE_STANGE: - if(flag & 1){ - if((skill_id == MH_MAGMA_FLOW) && ((rnd()%100)>(3*skill_lv)) ) break;//chance to not trigger atk for magma - skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); + if(flag&1){ + if((skill_id == MH_MAGMA_FLOW) && ((rnd()%100)>(3*skill_lv)) ) + break;//chance to not trigger atk for magma + skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); } else - map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id); + map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id); break; case MH_STAHL_HORN: @@ -5408,26 +5391,64 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint break; case RL_H_MINE: - if (sd) { - //Splash damage around the main target(s) - if (!(flag&1) && sd->flicker && tsc && tsc->data[SC_H_MINE] && tsc->data[SC_H_MINE]->val2 == src->id) { - map_foreachinrange(skill_area_sub,bl,skill_get_splash(skill_id,skill_lv),splash_target(src), - src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); + if (!(flag&1)) { + // Direct attack + if (!sd || !sd->flicker) { + if (skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag)) + status_change_start(src, bl, SC_H_MINE, 10000, skill_id, 0, 0, 0, skill_get_time(skill_id,skill_lv), SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_NORATEDEF); + break; } - else { - if (sd && sd->flicker && tsc && tsc->data[SC_H_MINE] && tsc->data[SC_H_MINE]->val2 == src->id) - { - skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); - tsc->data[SC_H_MINE]->val3 = 1; //Mark the SC end because not expired - status_change_end(bl,SC_H_MINE,INVALID_TIMER); - sc_start4(src,bl,SC_BURNING,10 * skill_lv + rnd()%50,skill_lv,1000,src->id,0,skill_get_time2(skill_id,skill_lv)); - } - else if (skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag) && !sd->flicker && !status_isdead(bl)) - sc_start(src,bl,SC_H_MINE,100,skill_id,skill_get_time(skill_id,skill_lv)); + // Triggered by RL_FLICKER + if (sd && sd->flicker && tsc && tsc->data[SC_H_MINE] && tsc->data[SC_H_MINE]->val2 == src->id) { + // Splash damage around it! + map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill_castend_damage_id); + flag |= 1; // Don't consume requirement + tsc->data[SC_H_MINE]->val3 = 1; // Mark the SC end because not expired + status_change_end(bl, SC_H_MINE, INVALID_TIMER); + sc_start4(src, bl, SC_BURNING, 10 * skill_lv, skill_lv, 1000, src->id, 0, skill_get_time2(skill_id,skill_lv)); + } + } + else + skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); + if (sd && sd->flicker) + flag |= 1; // Don't consume requirement + break; + + case RL_HAMMER_OF_GOD: + if (!(flag&1)) { + if (!sd) { + skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); + break; + } + + // First attack. If target is marked by SC_C_MARKER, do another splash damage! + if (tsc && tsc->data[SC_C_MARKER] && tsc->data[SC_C_MARKER]->val2 == src->id) { + map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill_castend_damage_id); + status_change_end(bl, SC_C_MARKER, INVALID_TIMER); + } + } + else + skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); + if ((flag&8)) + flag |= 1; + break; + + case RL_QD_SHOT: + case RL_D_TAIL: + if (!sd || (sd && tsc && tsc->data[SC_C_MARKER] && tsc->data[SC_C_MARKER]->val2 == src->id)) { + int sflag = flag; + if (skill_id == RL_QD_SHOT && skill_area_temp[1] == bl->id ) + break; + if (flag&1) + sflag = (skill_area_temp[0]&0xFFF)|(flag&SD_LEVEL ? SD_LEVEL : 0)|(flag&SD_ANIMATION ? SD_ANIMATION : 0); + skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, sflag); + if (sd) { + if (skill_id != RL_D_TAIL) + status_change_end(bl, SC_C_MARKER, INVALID_TIMER); } } - else if (!sd && skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag)) - sc_start4(src,bl,SC_BURNING,10 * skill_lv + rnd()%50,skill_lv,1000,src->id,0,skill_get_time2(skill_id,skill_lv)); break; case 0:/* no skill - basic/normal attack */ @@ -5778,19 +5799,22 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; 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; - } + if (!skill_abra_count) { + clif_skill_nodamage (src, bl, skill_id, skill_lv, 1); + break; + } + else { + int abra_skill_id = 0, abra_skill_lv, checked = 0, checked_max = MAX_SKILL_ABRA_DB * 3; do { i = rnd() % MAX_SKILL_ABRA_DB; abra_skill_id = skill_abra_db[i].skill_id; abra_skill_lv = min(skill_lv, skill_get_max(abra_skill_id)); - } while (abra_skill_id == 0 || - rnd()%10000 >= skill_abra_db[i].per[max(skill_lv-1,0)] - ); + } while ( checked++ < checked_max && + (abra_skill_id == 0 || + rnd()%10000 >= skill_abra_db[i].per[max(skill_lv-1,0)]) ); + + if (!skill_get_index(abra_skill_id)) + break; clif_skill_nodamage (src, bl, skill_id, skill_lv, 1); @@ -6460,11 +6484,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; //List of self skills that give damage around caster - case RL_FLICKER: - if (sd) { - sd->skill_id_old = RL_FLICKER; - sd->flicker = true; - } case ASC_METEORASSAULT: case GS_SPREADATTACK: case RK_STORMBLAST: @@ -6478,12 +6497,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case RL_R_TRIP: skill_area_temp[1] = 0; clif_skill_nodamage(src,bl,skill_id,skill_lv,1); - i = map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), - src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); + if (battle_config.skill_wall_check) + i = map_foreachinshootrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); + else + i = map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); if( !i && ( skill_id == NC_AXETORNADO || skill_id == SR_SKYNETBLOW || skill_id == KO_HAPPOKUNAI ) ) clif_skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - if (sd && skill_id == RL_FLICKER) - sd->flicker = false; break; case NC_EMERGENCYCOOL: @@ -6619,7 +6640,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui dstsd->status.char_id == sd->status.partner_id || dstsd->status.char_id == sd->status.child )) { - status_change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,8); + status_change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,SCSTART_NORATEDEF); clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } @@ -6662,6 +6683,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if (sd) // If the client receives a skill-use packet inmediately before a walkok packet, it will discard the walk packet! [Skotlex] clif_walkok(sd); // So aegis has to resend the walk ok. break; + case AS_CLOAKING: case GC_CLOAKINGEXCEED: case LG_FORCEOFVANGUARD: @@ -6825,7 +6847,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui status_change_start(src,bl, SC_BLIND, 100*(100-(tstatus->int_/2+tstatus->vit/3+tstatus->luk/10)), 1,0,0,0, - skill_get_time2(skill_id, skill_lv) * (100-(tstatus->int_+tstatus->vit)/2)/100,0); + skill_get_time2(skill_id, skill_lv) * (100-(tstatus->int_+tstatus->vit)/2)/100,SCSTART_NONE); } clif_skill_nodamage(src,bl,skill_id,skill_lv,1); if(dstmd) @@ -7700,7 +7722,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui map_freeblock_unlock(); return 0; } - status_change_start(src,bl,SC_STUN,10000,skill_lv,0,0,0,skill_get_time2(skill_id,skill_lv),8); + status_change_start(src,bl,SC_STUN,10000,skill_lv,0,0,0,skill_get_time2(skill_id,skill_lv),SCSTART_NORATEDEF); if (f_sd) sc_start(src,&f_sd->bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv)); if (m_sd) sc_start(src,&m_sd->bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv)); } @@ -8111,7 +8133,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SL_SKE: if (sd && !battle_config.allow_es_magic_pc && bl->type != BL_MOB) { clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - status_change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,10); + status_change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,SCSTART_NOTICKDEF|SCSTART_NORATEDEF); break; } clif_skill_nodamage(src,bl,skill_id,skill_lv,sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv))); @@ -8834,7 +8856,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv)); else { - map_foreachinrange(skill_area_sub,src,skill_get_splash(skill_id, skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,(map_flag_vs(src->m)?BCT_ALL:BCT_ENEMY|BCT_SELF)|flag|1,skill_castend_nodamage_id); + if (battle_config.skill_wall_check) + map_foreachinshootrange(skill_area_sub,src,skill_get_splash(skill_id, skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,(map_flag_vs(src->m)?BCT_ALL:BCT_ENEMY|BCT_SELF)|flag|1,skill_castend_nodamage_id); + else + map_foreachinrange(skill_area_sub,src,skill_get_splash(skill_id, skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,(map_flag_vs(src->m)?BCT_ALL:BCT_ENEMY|BCT_SELF)|flag|1,skill_castend_nodamage_id); clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); } break; @@ -8899,7 +8924,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case WL_JACKFROST: clif_skill_nodamage(src,bl,skill_id,skill_lv,1); - map_foreachinshootrange(skill_area_sub,bl,skill_get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); + if (battle_config.skill_wall_check) + map_foreachinshootrange(skill_area_sub,bl,skill_get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); + else + map_foreachinrange(skill_area_sub,bl,skill_get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); break; case WL_MARSHOFABYSS: @@ -8919,13 +8947,13 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( tsc && tsc->data[SC_STONE] ) status_change_end(bl,SC_STONE,INVALID_TIMER); else - status_change_start(src,bl,SC_STONE,10000,skill_lv,0,0,1000,skill_get_time(skill_id, skill_lv),2); + status_change_start(src,bl,SC_STONE,10000,skill_lv,0,0,1000,skill_get_time(skill_id, skill_lv),SCSTART_NOTICKDEF); } else { int rate = 45 + 5 * skill_lv + ( sd? sd->status.job_level : 50 ) / 4; // IroWiki says Rate should be reduced by target stats, but currently unknown if( rnd()%100 < rate ) { // Success on First Target if( !tsc->data[SC_STONE] ) - rate = status_change_start(src,bl,SC_STONE,10000,skill_lv,0,0,1000,skill_get_time(skill_id, skill_lv),2); + rate = status_change_start(src,bl,SC_STONE,10000,skill_lv,0,0,1000,skill_get_time(skill_id, skill_lv),SCSTART_NOTICKDEF); else { rate = 1; status_change_end(bl,SC_STONE,INVALID_TIMER); @@ -9561,16 +9589,24 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } break; - 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; - } + case WM_RANDOMIZESPELL: + if (!skill_improvise_count) { + clif_skill_nodamage (src, bl, skill_id, skill_lv, 1); + break; + } + else { + int improv_skill_id = 0, improv_skill_lv, checked = 0, checked_max = MAX_SKILL_IMPROVISE_DB*3; do { i = rnd() % MAX_SKILL_IMPROVISE_DB; improv_skill_id = skill_improvise_db[i].skill_id; - } while( improv_skill_id == 0 || rnd()%10000 >= skill_improvise_db[i].per ); + } while( checked++ < checked_max && (improv_skill_id == 0 || rnd()%10000 >= skill_improvise_db[i].per) ); + + if (!skill_get_index(improv_skill_id)) { + if (sd) + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + break; + } + improv_skill_lv = 4 + skill_lv; clif_skill_nodamage (src, bl, skill_id, skill_lv, 1); @@ -9991,10 +10027,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( dstsd && tsc && !tsc->data[type] && rand()%100 < ((45+5*skill_lv) + skill_lv*5 - status_get_int(bl)/2) ){//[(Base chance of success) + (Skill Level x 5) - (int / 2)]%. clif_skill_nodamage(src,bl,skill_id,skill_lv, - status_change_start(src,bl,type,10000,skill_lv,0,0,0,skill_get_time(skill_id,skill_lv),1)); + status_change_start(src,bl,type,10000,skill_lv,0,0,0,skill_get_time(skill_id,skill_lv),SCSTART_NOAVOID)); status_zap(bl, tstatus->max_hp*skill_lv*5/100 , 0); if( status_get_lv(bl) <= status_get_lv(src) ) - status_change_start(src,bl,SC_COMA,10,skill_lv,0,src->id,0,0,0); + status_change_start(src,bl,SC_COMA,10,skill_lv,0,src->id,0,0,SCSTART_NONE); }else if( sd ) clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; @@ -10059,7 +10095,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } }else{ skill_area_temp[2] = 0; - map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_nodamage_id); + if (battle_config.skill_wall_check) + map_foreachinshootrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_nodamage_id); + else + map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_nodamage_id); } break; @@ -10072,8 +10111,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui status_base_matk_min(&hd->battle_status); #endif //Silences the homunculus and target - status_change_start(src,src,SC_SILENCE,10000,skill_lv,0,0,0,skill_get_time(skill_id,skill_lv),0); - status_change_start(src,bl,SC_SILENCE,10000,skill_lv,0,0,0,skill_get_time(skill_id,skill_lv),0); + status_change_start(src,src,SC_SILENCE,10000,skill_lv,0,0,0,skill_get_time(skill_id,skill_lv),SCSTART_NONE); + status_change_start(src,bl,SC_SILENCE,10000,skill_lv,0,0,0,skill_get_time(skill_id,skill_lv),SCSTART_NONE); //Recover the target's HP status_heal(bl,heal,0,3); @@ -10181,52 +10220,93 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } break; case RL_C_MARKER: - if (sd && (dstsd || (bl->type == BL_MOB && dstmd))) { - uint8 i_scm; - sd->c_marker.count = 0; - //Find empty slot. If already exist, renew it! - ARR_FIND(0,MAX_SKILL_CRIMSON_MARKER,i_scm,sd->c_marker.target[i_scm] == bl->id || !sd->c_marker.target[i_scm]); - if (i_scm >= MAX_SKILL_CRIMSON_MARKER) { //No slot + if (sd) { + // If marked by someone else, failed + if (tsc->data[SC_C_MARKER] && tsc->data[SC_C_MARKER]->val2 != src->id) { clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - //Attempt to run SC to the target - if (!sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv))) { - clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; + + // Check if marked before + ARR_FIND(0, MAX_SKILL_CRIMSON_MARKER, i, sd->c_marker[i] == bl->id); + if (i == MAX_SKILL_CRIMSON_MARKER) { + // Find empty slot + ARR_FIND(0, MAX_SKILL_CRIMSON_MARKER, i, !sd->c_marker[i]); + if (i == MAX_SKILL_CRIMSON_MARKER) { + clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } } - sd->c_marker.target[i_scm] = bl->id; - clif_skill_nodamage(src,bl,skill_id,skill_lv,1); + + sd->c_marker[i] = bl->id; + status_change_start(src, bl, type, 10000, skill_lv, src->id, 0, 0, skill_get_time(skill_id,skill_lv), SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_NORATEDEF); + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + } + // If mob casts this, at least SC_C_MARKER as debuff + else { + status_change_start(src, bl, type, 10000, skill_lv, src->id, 0, 0, skill_get_time(skill_id,skill_lv), SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_NORATEDEF); + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); } break; case RL_D_TAIL: - if (sd && &sd->c_marker) { - sd->c_marker.count = min(map_foreachinrange(skill_check_target_c_marker,bl,skill_get_splash(skill_id,skill_lv),splash_target(src),src,skill_id),MAX_SKILL_CRIMSON_MARKER); - if (!sd->c_marker.count) { - clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + if (sd) { + if (battle_config.skill_wall_check) + skill_area_temp[0] = map_foreachinshootrange(skill_area_sub, src, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill_area_sub_count); + else + skill_area_temp[0] = map_foreachinrange(skill_area_sub, src, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill_area_sub_count); + if (!skill_area_temp[0]) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); break; } - status_zap(src,0,skill_get_sp(skill_id,skill_lv)); - skill_area_temp[1] = 0; - clif_skill_nodamage(src,bl,skill_id,skill_lv,1); - if (sd->c_marker.count) - map_foreachinrange(skill_area_sub,bl,skill_get_splash(skill_id,skill_lv),splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_SPLASH|1,skill_castend_damage_id); - sd->c_marker.count = 0; } + if (battle_config.skill_wall_check) + map_foreachinshootrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|SD_ANIMATION|1, skill_castend_damage_id); + else + map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|SD_ANIMATION|1, skill_castend_damage_id); + skill_area_temp[0] = 0; break; case RL_QD_SHOT: - if (!sd) - break; - if (&sd->c_marker && sd->c_marker.target) { - i = min(map_foreachinrange(skill_check_target_c_marker,bl,skill_get_splash(skill_id,skill_lv),splash_target(src),src,skill_id),MAX_SKILL_CRIMSON_MARKER); + if (sd) { + skill_area_temp[1] = bl->id; + // Check surrounding + if (battle_config.skill_wall_check) + skill_area_temp[0] = map_foreachinshootrange(skill_area_sub, src, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill_area_sub_count); + else + skill_area_temp[0] = map_foreachinrange(skill_area_sub, src, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill_area_sub_count); + if (skill_area_temp[0]) + map_foreachinrange(skill_area_sub, src, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); - skill_area_temp[1] = 0; - clif_skill_nodamage(src,bl,skill_id,skill_lv,1); - if (i) - map_foreachinrange(skill_area_sub,bl,skill_get_splash(skill_id,skill_lv),splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_SPLASH|1,skill_castend_damage_id); + // Main target always receives damage + clif_skill_nodamage(src, src, skill_id, skill_lv, 1); + skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_LEVEL); + if (tsc && tsc->data[SC_C_MARKER]) + status_change_end(bl, SC_C_MARKER, INVALID_TIMER); + } + else { + clif_skill_nodamage(src, src, skill_id, skill_lv, 1); + if (battle_config.skill_wall_check) + map_foreachinshootrange(skill_area_sub, src, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); + else + map_foreachinrange(skill_area_sub, src, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); + } + skill_area_temp[0] = 0; + skill_area_temp[1] = 0; + break; + case RL_FLICKER: + if (sd) { + int16 splash = skill_get_splash(skill_id, skill_lv); + sd->flicker = true; + skill_area_temp[1] = 0; + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + // Detonate RL_B_TRAP + if ((i = pc_checkskill(sd, RL_B_TRAP))) { + map_foreachinrange(skill_bind_trap, src, AREA_SIZE, BL_SKILL, src); + } + // Detonate RL_H_MINE + if ((i = pc_checkskill(sd, RL_H_MINE))) + map_foreachinrange(skill_area_sub, src, splash, BL_CHAR, src, RL_H_MINE, i, tick, flag|BCT_ENEMY|SD_SPLASH, skill_castend_damage_id); + sd->flicker = false; } - //Doesn't matter if the main target has SC_C_MARKER or not - skill_attack(skill_get_type(RL_QD_SHOT),src,src,bl,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_LEVEL|SD_ANIMATION); break; case SO_ELEMENTAL_SHIELD: @@ -10995,8 +11075,6 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case NC_MAGMA_ERUPTION: case SO_ELEMENTAL_SHIELD: case RL_B_TRAP: - if (skill_id == RL_B_TRAP && sd) - sd->skill_id_old = skill_id; flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete). case GS_GROUNDDRIFT: //Ammo should be deleted right away. case GN_WALLOFTHORN: @@ -11302,7 +11380,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui sc->comet_y = y; } i = skill_get_splash(skill_id,skill_lv); - map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); + map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_ANIMATION|1,skill_castend_damage_id); break; case WL_EARTHSTRAIN: @@ -11519,27 +11597,33 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui uint8 skill_use_lv = pc_checkskill(sd,skill_use); clif_slide(src, x, y); clif_fixpos(src); - if (skill_check_condition_castend(sd,skill_use,skill_use_lv)) { + if (skill_use_lv && skill_check_condition_castend(sd,skill_use,skill_use_lv)) { sd->skill_id_old = RL_FALLEN_ANGEL; skill_castend_pos2(src,src->x,src->y,skill_use,skill_use_lv,tick,SD_LEVEL|SD_ANIMATION|SD_SPLASH); battle_consume_ammo(sd,skill_use,skill_use_lv); } sd->skill_id_old = 0; } - else if (sd) - clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + else { + if (sd) + clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + } break; case RL_HAMMER_OF_GOD: - if (sd && &sd->c_marker) { + { i = skill_get_splash(skill_id, skill_lv); - //Get how many target around the clicked area - if (map_foreachinarea(skill_check_target_c_marker, src->m, x-i, y-i, x+i, y+i, BL_CHAR, src)) { - skill_area_temp[1] = 0; - map_foreachinarea(skill_area_sub, src->m, x-i, y-i, x+i, y+i, BL_CHAR, - src, skill_id, skill_lv, tick, flag|BCT_ENEMY|2, skill_castend_damage_id); + if (sd) { + skill_area_temp[0] = map_foreachinarea(skill_area_sub, src->m, x-i, y-i, x+i, y+i, BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill_area_sub_count); + if (!skill_area_temp[0]) { + // This skill doesn't have area effect, apply self? :P + //clif_skill_poseffect(src, skill_id, skill_lv, x, y, tick+500); + clif_skill_nodamage(src, src, skill_id, 0, 1); + break; + } } - else - clif_skill_poseffect(src,skill_id,skill_lv,x,y,tick+500); + map_foreachinarea(skill_area_sub, src->m, x-i, y-i, x+i, y+i, BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|SD_ANIMATION|8, skill_castend_damage_id); + skill_area_temp[0] = 0; + break; } break; case RL_FIRE_RAIN: { @@ -12180,6 +12264,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill group->state.song_dance = (unit_flag&(UF_DANCE|UF_SONG)?1:0)|(unit_flag&UF_ENSEMBLE?2:0); //Signals if this is a song/dance/duet group->state.guildaura = ( skill_id >= GD_LEADERSHIP && skill_id <= GD_HAWKEYES )?1:0; group->item_id = req_item; + // If tick is greater than current, do not invoke onplace function just yet. [Skotlex] if (DIFF_TICK(group->tick, gettick()) > SKILLUNITTIMER_INTERVAL) active_flag = 0; @@ -12227,14 +12312,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill continue; // no path between cell and center of casting. switch( skill_id ) { - case MG_FIREWALL: - case NJ_KAENSIN: - unit_val2 = group->val2; - break; - case WZ_ICEWALL: - unit_val1 = (skill_lv <= 1) ? 500 : 200 + 200*skill_lv; - unit_val2 = map_getcell(src->m, ux, uy, CELL_GETTYPE); - break; + // HP for Skill unit that can be damaged, see also skill_unit_ondamaged case HT_LANDMINE: case MA_LANDMINE: case HT_ANKLESNARE: @@ -12257,9 +12335,17 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill case RA_VERDURETRAP: case RA_FIRINGTRAP: case RA_ICEBOUNDTRAP: - case RL_B_TRAP: unit_val1 = 3500; break; + + case MG_FIREWALL: + case NJ_KAENSIN: + unit_val2 = group->val2; + break; + case WZ_ICEWALL: + unit_val1 = (skill_lv <= 1) ? 500 : 200 + 200*skill_lv; + unit_val2 = map_getcell(src->m, ux, uy, CELL_GETTYPE); + break; case GS_DESPERADO: unit_val1 = abs(layout->dx[i]); unit_val2 = abs(layout->dy[i]); @@ -12282,11 +12368,16 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill unit_val1 = 2000 + 2000 * skill_lv; // HP unit_val2 = 20; // Max hits break; + case RL_B_TRAP: + unit_val1 = 3500; + unit_val2 = 0; + break; default: if (group->state.song_dance&0x1) unit_val2 = unit_flag&(UF_DANCE|UF_SONG); //Store whether this is a song/dance break; } + if (unit_flag&UF_RANGEDSINGLEUNIT && i == (layout->count / 2)) unit_val2 |= UF_RANGEDSINGLEUNIT; // center. @@ -12338,7 +12429,8 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill *------------------------------------------*/ void ext_skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, unsigned int tick){skill_unit_onplace(unit, bl, tick);} /** -* Triggeres when 'target' (based on skill unit target) is step in unit area. +* Triggeres when 'target' (based on skill unit target) is stand at unit area +* while skill unit initialized or moved (such by knock back). * As a follow of skill_unit_effect flag &1 * @param unit * @param bl Target @@ -12381,7 +12473,7 @@ static int skill_unit_onplace (struct skill_unit *unit, struct block_list *bl, u return 0; // Under Hovering characters are immune to trap and ground target skills. type = status_skill2sc(sg->skill_id); - sce = (sc && type != -1)?sc->data[type]:NULL; + sce = (sc && type != SC_NONE) ? sc->data[type] : NULL; skill_id = sg->skill_id; //In case the group is deleted, we need to return the correct skill id, still. switch (sg->unit_id) { case UNT_SPIDERWEB: @@ -12391,7 +12483,7 @@ static int skill_unit_onplace (struct skill_unit *unit, struct block_list *bl, u break; } else if( sc && battle_check_target(&sg->unit->bl,bl,sg->target_flag) > 0 ) { int sec = skill_get_time2(sg->skill_id,sg->skill_lv); - if( status_change_start(ss, bl,type,10000,sg->skill_lv,1,sg->group_id,0,sec,8) ) { + if( status_change_start(ss, bl,type,10000,sg->skill_lv,1,sg->group_id,0,sec,SCSTART_NORATEDEF) ) { const struct TimerData* td = sc->data[type]?get_timer(sc->data[type]->timer):NULL; if( td ) sec = DIFF_TICK(td->tick, tick); @@ -12419,11 +12511,14 @@ static int skill_unit_onplace (struct skill_unit *unit, struct block_list *bl, u break; case UNT_PNEUMA: - case UNT_CHAOSPANIC: if (!sce) sc_start4(ss, bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit); break; + case UNT_CHAOSPANIC: + status_change_start(ss, bl, type, 3500 + (sg->skill_lv * 1500), sg->skill_lv, 0, 0, 1, sg->skill_lv * 4000, SCSTART_NOAVOID|SCSTART_NORATEDEF|SCSTART_NOTICKDEF); + break; + case UNT_WARP_WAITING: { int working = sg->val1&0xffff; @@ -12655,6 +12750,73 @@ int skill_unit_onplace_timer (struct skill_unit *unit, struct block_list *bl, un } switch (sg->unit_id) { + // Units that deals simple attack + case UNT_GRAVITATION: + case UNT_EARTHSTRAIN: + case UNT_FIREWALK: + case UNT_ELECTRICWALK: + case UNT_PSYCHIC_WAVE: + case UNT_MAGMA_ERUPTION: + case UNT_MAKIBISHI: + skill_attack(skill_get_type(sg->skill_id),ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,0); + break; + + case UNT_DUMMYSKILL: + switch (sg->skill_id) + { + case SG_SUN_WARM: //SG skills [Komurka] + case SG_MOON_WARM: + case SG_STAR_WARM: + { + int count = 0; + const int x = bl->x, y = bl->y; + + //If target isn't knocked back it should hit every "interval" ms [Playtester] + do + { + if( bl->type == BL_PC ) + status_zap(bl, 0, 15); // sp damage to players + else // mobs + if( status_charge(ss, 0, 2) ) // costs 2 SP per hit + { + if( !skill_attack(BF_WEAPON,ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick+count*sg->interval,0) ) + status_charge(ss, 0, 8); //costs additional 8 SP if miss + } + else + { //should end when out of sp. + sg->limit = DIFF_TICK(tick,sg->tick); + break; + } + } while( x == bl->x && y == bl->y && + ++count < SKILLUNITTIMER_INTERVAL/sg->interval && !status_isdead(bl) ); + } + break; + /** + * The storm gust counter was dropped in renewal + **/ +#ifndef RENEWAL + case WZ_STORMGUST: //SG counter does not reset per stormgust. IE: One hit from a SG and two hits from another will freeze you. + if (tsc) + tsc->sg_counter++; //SG hit counter. + if (skill_attack(skill_get_type(sg->skill_id),ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,0) <= 0 && tsc) + tsc->sg_counter=0; //Attack absorbed. + break; +#endif + case GS_DESPERADO: + if (rnd()%100 < unit->val1) + skill_attack(BF_WEAPON,ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,0); + break; + case GN_CRAZYWEED_ATK: + if( bl->type == BL_SKILL ){ + struct skill_unit *su = (struct skill_unit *)bl; + if( su && !(skill_get_inf2(su->group->skill_id)&INF2_TRAP) ) + break; + } + default: + skill_attack(skill_get_type(sg->skill_id),ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,0); + } + break; + case UNT_FIREWALL: case UNT_KAEN: { int count = 0; @@ -12727,62 +12889,6 @@ int skill_unit_onplace_timer (struct skill_unit *unit, struct block_list *bl, un skill_attack(BF_MAGIC,ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,0); break; - case UNT_DUMMYSKILL: - switch (sg->skill_id) - { - case SG_SUN_WARM: //SG skills [Komurka] - case SG_MOON_WARM: - case SG_STAR_WARM: - { - int count = 0; - const int x = bl->x, y = bl->y; - - //If target isn't knocked back it should hit every "interval" ms [Playtester] - do - { - if( bl->type == BL_PC ) - status_zap(bl, 0, 15); // sp damage to players - else // mobs - if( status_charge(ss, 0, 2) ) // costs 2 SP per hit - { - if( !skill_attack(BF_WEAPON,ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick+count*sg->interval,0) ) - status_charge(ss, 0, 8); //costs additional 8 SP if miss - } - else - { //should end when out of sp. - sg->limit = DIFF_TICK(tick,sg->tick); - break; - } - } while( x == bl->x && y == bl->y && - ++count < SKILLUNITTIMER_INTERVAL/sg->interval && !status_isdead(bl) ); - } - break; - /** - * The storm gust counter was dropped in renewal - **/ -#ifndef RENEWAL - case WZ_STORMGUST: //SG counter does not reset per stormgust. IE: One hit from a SG and two hits from another will freeze you. - if (tsc) - tsc->sg_counter++; //SG hit counter. - if (skill_attack(skill_get_type(sg->skill_id),ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,0) <= 0 && tsc) - tsc->sg_counter=0; //Attack absorbed. - break; -#endif - case GS_DESPERADO: - if (rnd()%100 < unit->val1) - skill_attack(BF_WEAPON,ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,0); - break; - case GN_CRAZYWEED_ATK: - if( bl->type == BL_SKILL ){ - struct skill_unit *su = (struct skill_unit *)bl; - if( su && !(skill_get_inf2(su->group->skill_id)&INF2_TRAP) ) - break; - } - default: - skill_attack(skill_get_type(sg->skill_id),ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,0); - } - break; - case UNT_FIREPILLAR_WAITING: skill_unitsetting(ss,sg->skill_id,sg->skill_lv,unit->bl.x,unit->bl.y,1); skill_delunit(unit); @@ -12801,7 +12907,7 @@ int skill_unit_onplace_timer (struct skill_unit *unit, struct block_list *bl, un if( sg->val2 == 0 && tsc && (sg->unit_id == UNT_ANKLESNARE || bl->id != sg->src_id) ) { int sec = skill_get_time2(sg->skill_id,sg->skill_lv); - if( status_change_start(ss, bl,type,10000,sg->skill_lv,sg->group_id,0,0,sec, 8) ) { + if( status_change_start(ss, bl,type,10000,sg->skill_lv,sg->group_id,0,0,sec, SCSTART_NORATEDEF) ) { const struct TimerData* td = tsc->data[type]?get_timer(tsc->data[type]->timer):NULL; if( td ) @@ -12832,7 +12938,7 @@ int skill_unit_onplace_timer (struct skill_unit *unit, struct block_list *bl, un if( bl->id != ss->id ) { if( status_get_mode(bl)&MD_BOSS ) break; - if( status_change_start(ss, bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill_get_time2(sg->skill_id, sg->skill_lv), 8) ) { + if( status_change_start(ss, bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill_get_time2(sg->skill_id, sg->skill_lv), SCSTART_NORATEDEF) ) { map_moveblock(bl, unit->bl.x, unit->bl.y, tick); clif_fixpos(bl); } @@ -12843,7 +12949,7 @@ int skill_unit_onplace_timer (struct skill_unit *unit, struct block_list *bl, un case UNT_VENOMDUST: if(tsc && !tsc->data[type]) - status_change_start(ss, bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),0); + status_change_start(ss, bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),SCSTART_NONE); break; case UNT_MAGENTATRAP: @@ -13044,16 +13150,6 @@ int skill_unit_onplace_timer (struct skill_unit *unit, struct block_list *bl, un } break; - case UNT_GRAVITATION: - case UNT_EARTHSTRAIN: - case UNT_FIREWALK: - case UNT_ELECTRICWALK: - case UNT_PSYCHIC_WAVE: - case UNT_MAGMA_ERUPTION: - case UNT_MAKIBISHI: - skill_attack(skill_get_type(sg->skill_id),ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,0); - break; - case UNT_GROUNDDRIFT_WIND: case UNT_GROUNDDRIFT_DARK: case UNT_GROUNDDRIFT_POISON: @@ -13182,14 +13278,14 @@ int skill_unit_onplace_timer (struct skill_unit *unit, struct block_list *bl, un case UNT_HELLS_PLANT: if( battle_check_target(&unit->bl,bl,BCT_ENEMY) > 0 ) - skill_attack(skill_get_type(GN_HELLS_PLANT_ATK), ss, &unit->bl, bl, GN_HELLS_PLANT_ATK, sg->skill_lv, tick, 0); + skill_attack(skill_get_type(GN_HELLS_PLANT_ATK), ss, &unit->bl, bl, GN_HELLS_PLANT_ATK, sg->skill_lv, tick, SCSTART_NONE); if( ss != bl) // The caster is the only one who can step on the Plants without destroying them sg->limit = DIFF_TICK(tick, sg->tick) + 100; break; case UNT_CLOUD_KILL: if(tsc && !tsc->data[type]) - status_change_start(ss, bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),8); + status_change_start(ss, bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),SCSTART_NORATEDEF); skill_attack(skill_get_type(sg->skill_id),ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,0); break; @@ -13313,15 +13409,22 @@ int skill_unit_onplace_timer (struct skill_unit *unit, struct block_list *bl, un break; case UNT_POISON_MIST: skill_attack(BF_MAGIC, ss, &unit->bl, bl, sg->skill_id, sg->skill_lv, tick, 0); - status_change_start(ss, bl, SC_BLIND, (10 + 10 * sg->skill_lv)*100, sg->skill_lv, sg->skill_id, 0, 0, skill_get_time2(sg->skill_id, sg->skill_lv), 2|8); + status_change_start(ss, bl, SC_BLIND, (10 + 10 * sg->skill_lv)*100, sg->skill_lv, sg->skill_id, 0, 0, skill_get_time2(sg->skill_id, sg->skill_lv), SCSTART_NOTICKDEF|SCSTART_NORATEDEF); + break; + + case UNT_CHAOSPANIC: + if (tsc && tsc->data[type]) + break; + status_change_start(ss, bl, type, 3500 + (sg->skill_lv * 1500), sg->skill_lv, 0, 0, 1, sg->skill_lv * 4000, SCSTART_NOAVOID|SCSTART_NORATEDEF|SCSTART_NOTICKDEF); break; case UNT_B_TRAP: - sc_start(ss,bl,SC_B_TRAP,100,sg->skill_lv,max(status_get_str(bl) * 150,5000)); //(custom) - sg->unit_id = UNT_USED_TRAPS; - clif_changetraplook(&unit->bl, UNT_USED_TRAPS); - sg->limit = DIFF_TICK(tick,sg->tick)+1500; + if (tsc && tsc->data[type]) + break; + sc_start(ss, bl, type, 100, sg->skill_lv, skill_get_time2(sg->skill_id,sg->skill_lv)); + unit->val2++; // Mark as ever been used break; + case UNT_FIRE_RAIN: clif_skill_damage(ss,bl,tick,status_get_amotion(ss),0, skill_attack(skill_get_type(sg->skill_id),ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,SD_ANIMATION|SD_SPLASH), @@ -13843,6 +13946,61 @@ int skill_isammotype (struct map_session_data *sd, unsigned short skill_id) ); } +/** +* Check SC required to cast a skill +* @param sc +* @param skill_id +* @return True if condition is met, False otherwise +**/ +static bool skill_check_condition_sc_required(struct map_session_data *sd, unsigned short skill_id, struct skill_condition *require) { + uint8 c = 0; + struct status_change *sc = NULL; + + if (!require->status_count) + return true; + + nullpo_ret(sd); + + if (!require || !skill_get_index(skill_id)) + return false; + + if (!(sc = &sd->sc)) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + return false; + } + + /* May has multiple requirements */ + for (c = 0; c < require->status_count; c++) { + enum sc_type req_sc = require->status[c]; + if (req_sc == SC_NONE) + continue; + + switch (req_sc) { + /* Official fail msg */ + case SC_PUSH_CART: + if (!sc->data[SC_PUSH_CART]) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_CART, 0); + return false; + } + break; + case SC_POISONINGWEAPON: + if (!sc->data[SC_POISONINGWEAPON]) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_GC_POISONINGWEAPON, 0); + return false; + } + break; + + default: + if (!sc->data[req_sc]) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + return false; + } + break; + } + } + return true; +} + /** Check skill condition when cast begin * NOTE: For ammo, only check if the skill need ammo, for checking ammo requirement (type and amount) will be skill_check_condition_castend * @param sd Player who uses skill @@ -14650,35 +14808,14 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i /* check the status required */ if (require.status_count) { - uint8 c; - /* May has multiple requirements */ - for (c = 0; c < require.status_count; c++) { - enum sc_type req_sc = require.status[c]; - if (req_sc == SC_NONE) - continue; - - switch (req_sc) { - /* Official fail msg */ - case SC_PUSH_CART: - if (!sc || !sc->data[SC_PUSH_CART]) { - clif_skill_fail(sd,skill_id,USESKILL_FAIL_CART,0); - return false; - } - break; - case SC_POISONINGWEAPON: - if (!sc || !sc->data[SC_POISONINGWEAPON]) { - clif_skill_fail(sd,skill_id,USESKILL_FAIL_GC_POISONINGWEAPON,0); - return false; - } - break; - - default: - if (!sc || !sc->data[req_sc]) { - clif_skill_fail(sd, skill_id, USESKILL_FAIL_CONDITION, 0); - return false; - } - break; - } + switch (skill_id) { + // Being checked later in skill_check_condition_castend() + case WZ_SIGHTRASHER: + break; + default: + if (!skill_check_condition_sc_required(sd, skill_id, &require)) + return false; + break; } } @@ -14908,6 +15045,18 @@ bool skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, } } + /* check the status required */ + if (require.status_count) { + switch (skill_id) { + case WZ_SIGHTRASHER: + if (!skill_check_condition_sc_required(sd, skill_id, &require)) + return false; + break; + default: + break; + } + } + return true; } @@ -14931,7 +15080,6 @@ void skill_consume_requirement( struct map_session_data *sd, uint16 skill_id, ui switch( skill_id ) { case CG_TAROTCARD: // TarotCard will consume sp in skill_cast_nodamage_id [Inkfish] case MC_IDENTIFY: - case RL_D_TAIL: require.sp = 0; break; case GS_DESPERADO: @@ -14998,10 +15146,6 @@ void skill_consume_requirement( struct map_session_data *sd, uint16 skill_id, ui if( sc && sc->data[SC_WILD_STORM_OPTION] && rnd()%100 < 50 ) continue; break; - case RL_H_MINE: - if (sd->flicker) - continue; - break; } if( (n = pc_search_inventory(sd,require.itemid[i])) >= 0 ) @@ -16106,27 +16250,6 @@ int skill_frostjoke_scream (struct block_list *bl, va_list ap) return 0; } -int skill_check_target_c_marker(struct block_list *bl, va_list ap) { - struct block_list *src; - struct status_change *tsc; - struct map_session_data *sd; - - nullpo_ret(bl); - nullpo_ret(src = va_arg(ap,struct block_list*)); - - if (src == bl || status_isdead(bl) || src->type != BL_PC) - return 0; - if (!(sd = (struct map_session_data *)src) || !(&sd->c_marker) || !sd->c_marker.target) - return 0; - - //Skip target with no Crimson Marker - tsc = status_get_sc(bl); - if (!tsc || !tsc->data[SC_C_MARKER] || tsc->data[SC_C_MARKER]->val2 != src->id) - return 0; - - return 1; -} - /*========================================== * Set map cell flag as skill unit effect * @param src Skill unit @@ -16147,8 +16270,11 @@ static void skill_unitsetmapcell (struct skill_unit *src, uint16 skill_id, uint1 /*========================================== * Do skill attack area (such splash effect) around the 'first' target. - * First target will skill skill condition, always receive damage. But, - * around it, still need target/condition validation + * First target will skip skill condition, always receive damage. But, + * around it, still need target/condition validation by + * battle_check_target and status_check_skilluse + * @param bl + * @param ap { atk_type, src, dsrc, skill_id, skill_lv, tick, flag, type } *------------------------------------------*/ int skill_attack_area (struct block_list *bl, va_list ap) { @@ -16345,6 +16471,31 @@ int skill_detonator(struct block_list *bl, va_list ap) return 0; } +/** +* Rebellion's Bind Trap explosion +* @author [Cydh] +**/ +static int skill_bind_trap(struct block_list *bl, va_list ap) { + struct skill_unit *su = NULL; + struct block_list *src = NULL; + + nullpo_ret(bl); + nullpo_ret(ap); + + src = va_arg(ap,struct block_list *); + + if (bl->type != BL_SKILL || !(su = (struct skill_unit *)bl) || !(su->group)) + return 0; + if (su->group->unit_id != UNT_B_TRAP || su->group->src_id != src->id ) + return 0; + + map_foreachinrange(skill_trap_splash, bl, su->range, BL_CHAR, bl,su->group->tick); + clif_changetraplook(bl, UNT_USED_TRAPS); + su->group->unit_id = UNT_USED_TRAPS; + su->group->limit = DIFF_TICK(gettick(), su->group->tick) + 500; + return 1; +} + /*========================================== * Check new skill unit cell when overlapping in other skill unit cell. * Catched skill in cell value pushed to *unit pointer. @@ -16483,16 +16634,20 @@ static int skill_trap_splash (struct block_list *bl, va_list ap) unit = (struct skill_unit *)src; tick = va_arg(ap,int); - if( !unit->alive || bl->prev == NULL ) + if (!unit->alive || bl->prev == NULL) return 0; nullpo_ret(sg = unit->group); nullpo_ret(ss = map_id2bl(sg->src_id)); - if(battle_check_target(src,bl,sg->target_flag) <= 0) + if (battle_check_target(src,bl,sg->target_flag) <= 0) return 0; - switch(sg->unit_id){ + switch (sg->unit_id) { + case UNT_B_TRAP: + if (battle_check_target(ss, bl, sg->target_flag&~BCT_SELF) > 0) + skill_castend_damage_id(ss, bl, sg->skill_id, sg->skill_lv, tick, SD_ANIMATION|SD_LEVEL|SD_SPLASH|1); + break; case UNT_SHOCKWAVE: case UNT_SANDMAN: case UNT_FLASHER: @@ -16522,7 +16677,7 @@ static int skill_trap_splash (struct block_list *bl, va_list ap) if (bl->id != ss->id) { if (status_get_mode(bl)&MD_BOSS) break; - if (status_change_start(ss, bl, SC_ELECTRICSHOCKER, 10000, sg->skill_lv, sg->group_id, 0, 0, skill_get_time2(sg->skill_id, sg->skill_lv), 8)) { + if (status_change_start(ss, bl, SC_ELECTRICSHOCKER, 10000, sg->skill_lv, sg->group_id, 0, 0, skill_get_time2(sg->skill_id, sg->skill_lv), SCSTART_NORATEDEF)) { map_moveblock(bl, unit->bl.x, unit->bl.y, tick); clif_fixpos(bl); clif_skill_damage(src, bl, tick, 0, 0, -30000, 1, sg->skill_id, sg->skill_lv, 5); @@ -17269,7 +17424,6 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) case UNT_VERDURETRAP: case UNT_FIRINGTRAP: case UNT_ICEBOUNDTRAP: - case UNT_B_TRAP: { struct block_list* src; if( unit->val1 > 0 && (src = map_id2bl(group->src_id)) != NULL && src->type == BL_PC ) @@ -17353,6 +17507,20 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) } break; + case UNT_B_TRAP: + { + struct block_list* src; + if (group->item_id && unit->val2 <= 0 && (src = map_id2bl(group->src_id)) && src->type == BL_PC) { + struct item item_tmp; + memset(&item_tmp, 0, sizeof(item_tmp)); + item_tmp.nameid = group->item_id; + item_tmp.identify = 1; + map_addflooritem(&item_tmp, 1, bl->m, bl->x, bl->y, 0, 0, 0, 4); + } + skill_delunit(unit); + } + break; + default: skill_delunit(unit); } @@ -17397,16 +17565,12 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) } break; case UNT_WALLOFTHORN: - if (unit->val1 <= 0 || unit->val2 <= 0 || group->val3 < 0) { - group->unit_id = UNT_USED_TRAPS; - group->limit = DIFF_TICK(tick, group->tick); - } - /*if (group->val3 < 0) { // Remove if attacked by fire element, turned to Fire Wall + if (group->val3 < 0) { // Remove if attacked by fire element, turned to Fire Wall skill_delunitgroup(group); break; } - if (unit->val1 <= 0 || unit->val2 <= 0) // Remove unit only if no HP or hit limit reached - skill_delunit(unit);*/ + if (unit->val1 <= 0 || unit->val2 <= 0) // Remove the unit only if no HP or hit limit is reached + skill_delunit(unit); break; } } @@ -17581,6 +17745,39 @@ int skill_unit_move (struct block_list *bl, unsigned int tick, int flag) { return 0; } +/*========================================== + * Moves skill unit to map m with coordinates x & y (example when knocked back) + * @param bl Skill unit + * @param m Map + * @param dx + * @param dy + *------------------------------------------*/ +void skill_unit_move_unit(struct block_list *bl, int dx, int dy) { + unsigned int tick = gettick(); + struct skill_unit *su; + + if (bl->type != BL_SKILL) + return; + if (!(su = (struct skill_unit *)bl)) + return; + if (!su->alive) + return; + + if (su->group && skill_get_unit_flag(su->group->skill_id)&UF_ENSEMBLE) + return; //Ensembles may not be moved around. + + if (!bl->prev) { + bl->x = dx; + bl->y = dy; + return; + } + + map_moveblock(bl, dx, dy, tick); + map_foreachincell(skill_unit_effect,bl->m,bl->x,bl->y,su->group->bl_flag,bl,tick,1); + clif_getareachar_skillunit(bl, su, AREA); + return; +} + /*========================================== * Moves skill unit group to map m with coordinates x & y (example when knocked back) * @param group Skill Group @@ -18358,7 +18555,7 @@ bool skill_arrow_create(struct map_session_data *sd, unsigned short nameid) { nullpo_ret(sd); - if (nameid == 0 || !itemdb_exists(nameid)) + if (nameid == 0 || !itemdb_exists(nameid) || !skill_arrow_count) return false; for (i = 0; i < MAX_SKILL_ARROW_DB;i++) { @@ -18513,28 +18710,36 @@ int skill_magicdecoy(struct map_session_data *sd, unsigned short nameid) { } // Warlock Spellbooks. [LimitLine/3CeAM] -int skill_spellbook (struct map_session_data *sd, unsigned short nameid) { +void skill_spellbook (struct map_session_data *sd, unsigned short nameid) { int i, max_preserve, skill_id, point; struct status_change *sc; - nullpo_ret(sd); + nullpo_retv(sd); sc = status_get_sc(&sd->bl); status_change_end(&sd->bl, SC_STOP, INVALID_TIMER); - for(i=SC_SPELLBOOK1; i <= SC_MAXSPELLBOOK; i++) if( sc && !sc->data[i] ) break; - if( i > SC_MAXSPELLBOOK ) { - clif_skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_READING, 0); - return 0; + for (i = SC_SPELLBOOK1; i <= SC_MAXSPELLBOOK; i++) { + if( sc && !sc->data[i] ) + break; } + if( i > SC_MAXSPELLBOOK ) { + clif_skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_READING, 0); + return; + } + + if (!skill_spellbook_count) + return; + ARR_FIND(0,MAX_SKILL_SPELLBOOK_DB,i,skill_spellbook_db[i].nameid == nameid); // Search for information of this item - if( i == MAX_SKILL_SPELLBOOK_DB ) return 0; + if( i == MAX_SKILL_SPELLBOOK_DB ) + return; if( !pc_checkskill(sd, (skill_id = skill_spellbook_db[i].skill_id)) ) { // User don't know the skill sc_start(&sd->bl,&sd->bl, SC_SLEEP, 100, 1, skill_get_time(WL_READING_SB, pc_checkskill(sd,WL_READING_SB))); clif_skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_DIFFICULT_SLEEP, 0); - return 0; + return; } max_preserve = 4 * pc_checkskill(sd, WL_FREEZE_SP) + status_get_int(&sd->bl) / 10 + sd->status.base_level / 10; @@ -18543,7 +18748,7 @@ int skill_spellbook (struct map_session_data *sd, unsigned short nameid) { if( sc && sc->data[SC_READING_SB] ) { if( (sc->data[SC_READING_SB]->val2 + point) > max_preserve ) { clif_skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_PRESERVATION_POINT, 0); - return 0; + return; } for(i = SC_MAXSPELLBOOK; i >= SC_SPELLBOOK1; i--){ // This is how official saves spellbook. [malufett] if( !sc->data[i] ){ @@ -18559,8 +18764,6 @@ int skill_spellbook (struct map_session_data *sd, unsigned short nameid) { // Reading Spell Book SP cost same as the sealed spell. status_zap(&sd->bl, 0, skill_get_sp(skill_id, pc_checkskill(sd, skill_id))); - - return 1; } int skill_select_menu(struct map_session_data *sd,uint16 skill_id) { @@ -19975,6 +20178,7 @@ static bool skill_parse_row_improvisedb(char* split[], int columns, int current) */ static bool skill_parse_row_magicmushroomdb(char* split[], int column, int current) { unsigned short i, skill_id = atoi(split[0]); + bool rem = (atoi(split[1]) == 1 ? true : false); if (!skill_get_index(skill_id) || !skill_get_max(skill_id)) { ShowError("skill_parse_row_magicmushroomdb: Invalid skill ID %d\n", skill_id); @@ -19990,7 +20194,7 @@ static bool skill_parse_row_magicmushroomdb(char* split[], int column, int curre return false; } // Import just for clearing/disabling from original data - if (split[1] != NULL) { + if (rem) { 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; diff --git a/src/map/skill.h b/src/map/skill.h index c2c0a285b8..18d6220346 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -18,10 +18,10 @@ struct status_change_entry; #define MAX_PRODUCE_RESOURCE 12 /// Max Produce requirements #define MAX_SKILL_ARROW_DB 150 /// Max Arrow Creation DB #define MAX_ARROW_RESULT 5 /// Max Arrow results/created -#define MAX_SKILL_ABRA_DB 350 /// Max Skill list of Abracadabra DB -#define MAX_SKILL_IMPROVISE_DB 50 /// Max Skill for Improvise +#define MAX_SKILL_ABRA_DB 160 /// Max Skill list of Abracadabra DB +#define MAX_SKILL_IMPROVISE_DB 30 /// Max Skill for Improvise #define MAX_SKILL_LEVEL 100 /// Max Skill Level -#define MAX_SKILL_CRIMSON_MARKER 3 /// Max Crimson Marker targets +#define MAX_SKILL_CRIMSON_MARKER 3 /// Max Crimson Marker targets (RL_C_MARKER) #define SKILL_NAME_LENGTH 31 /// Max Skill Name length #define SKILL_DESC_LENGTH 31 /// Max Skill Desc length @@ -101,7 +101,7 @@ enum e_skill_inf3 { /// Flags passed to skill_attack/skill_area_sub enum e_skill_display { SD_LEVEL = 0x1000, // skill_attack will send -1 instead of skill level (affects display of some skills) - SD_ANIMATION = 0x2000, // skill_attack will use '5' instead of the skill's 'type' (this makes skills show an animation) + SD_ANIMATION = 0x2000, // skill_attack will use '5' instead of the skill's 'type' (this makes skills show an animation). Also being used in skill_attack for splash skill (NK_SPLASH) to check status_check_skilluse SD_SPLASH = 0x4000, // skill_area_sub will count targets in skill_area_temp[2] SD_PREAMBLE = 0x8000, // skill_area_sub will transmit a 'magic' damage packet (-30000 dmg) for the first target selected }; @@ -259,22 +259,23 @@ struct skill_unit_group_tickset { enum { - UF_DEFNOTENEMY = 0x0001, // If 'defunit_not_enemy' is set, the target is changed to 'friend' - UF_NOREITERATION = 0x0002, // Spell cannot be stacked - UF_NOFOOTSET = 0x0004, // Spell cannot be cast near/on targets - UF_NOOVERLAP = 0x0008, // Spell effects do not overlap - UF_PATHCHECK = 0x0010, // Only cells with a shootable path will be placed - UF_NOPC = 0x0020, // May not target players - UF_NOMOB = 0x0040, // May not target mobs - UF_SKILL = 0x0080, // May target skills - UF_DANCE = 0x0100, // Dance - UF_ENSEMBLE = 0x0200, // Duet - UF_SONG = 0x0400, // Song - UF_DUALMODE = 0x0800, // Spells should trigger both ontimer and onplace/onout/onleft effects. - UF_NOKNOCKBACK = 0x1000, // Skill unit cannot be knocked back - UF_RANGEDSINGLEUNIT = 0x2000, // hack for ranged layout, only display center - UF_REM_CRAZYWEED = 0x4000, // removed by Crazyweed - UF_REM_FIRERAIN = 0x8000, // removed by Fire Rain + UF_DEFNOTENEMY = 0x00001, // If 'defunit_not_enemy' is set, the target is changed to 'friend' + UF_NOREITERATION = 0x00002, // Spell cannot be stacked + UF_NOFOOTSET = 0x00004, // Spell cannot be cast near/on targets + UF_NOOVERLAP = 0x00008, // Spell effects do not overlap + UF_PATHCHECK = 0x00010, // Only cells with a shootable path will be placed + UF_NOPC = 0x00020, // May not target players + UF_NOMOB = 0x00040, // May not target mobs + UF_SKILL = 0x00080, // May target skills + UF_DANCE = 0x00100, // Dance + UF_ENSEMBLE = 0x00200, // Duet + UF_SONG = 0x00400, // Song + UF_DUALMODE = 0x00800, // Spells should trigger both ontimer and onplace/onout/onleft effects. + UF_NOKNOCKBACK = 0x01000, // Skill unit cannot be knocked back + UF_RANGEDSINGLEUNIT = 0x02000, // hack for ranged layout, only display center + UF_REM_CRAZYWEED = 0x04000, // removed by Crazyweed + UF_REM_FIRERAIN = 0x08000, // removed by Fire Rain + UF_KNOCKBACK_GROUP = 0x10000, // knockback skill unit with its group instead of single unit }; /// Create Database item @@ -303,9 +304,7 @@ struct s_skill_abra_db { int per[MAX_SKILL_LEVEL]; /// Probability summoned }; extern struct s_skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB]; - -extern int enchant_eff[5]; -extern int deluge_eff[5]; +extern unsigned short skill_abra_count; void do_init_skill(void); void do_final_skill(void); @@ -414,6 +413,7 @@ int skill_check_unit_cell(uint16 skill_id,int16 m,int16 x,int16 y,int unit_id); int skill_unit_out_all( struct block_list *bl,unsigned int tick,int range); int skill_unit_move(struct block_list *bl,unsigned int tick,int flag); void skill_unit_move_unit_group( struct skill_unit_group *group, int16 m,int16 dx,int16 dy); +void skill_unit_move_unit(struct block_list *bl, int dx, int dy); struct skill_unit_group *skill_check_dancing( struct block_list *src ); @@ -1984,17 +1984,19 @@ struct s_skill_spellbook_db { unsigned short point; }; extern struct s_skill_spellbook_db skill_spellbook_db[MAX_SKILL_SPELLBOOK_DB]; -int skill_spellbook (struct map_session_data *sd, unsigned short nameid); +extern unsigned short skill_spellbook_count; +void skill_spellbook (struct map_session_data *sd, unsigned short nameid); int skill_block_check(struct block_list *bl, enum sc_type type, uint16 skill_id); /** * Guilottine Cross **/ -#define MAX_SKILL_MAGICMUSHROOM_DB 23 +#define MAX_SKILL_MAGICMUSHROOM_DB 25 struct s_skill_magicmushroom_db { uint16 skill_id; }; extern struct s_skill_magicmushroom_db skill_magicmushroom_db[MAX_SKILL_MAGICMUSHROOM_DB]; +extern unsigned short skill_magicmushroom_count; int skill_maelstrom_suction(struct block_list *bl, va_list ap); bool skill_check_shadowform(struct block_list *bl, int64 damage, int hit); diff --git a/src/map/status.c b/src/map/status.c index 057680e4b4..239d4f50db 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -689,7 +689,7 @@ void initChangeTables(void) set_sc( SC_WEAKNESS , SC__WEAKNESS , SI_WEAKNESS , SCB_MAXHP ); set_sc( SC_STRIPACCESSARY , SC__STRIPACCESSORY , SI_STRIPACCESSARY , SCB_DEX|SCB_INT|SCB_LUK ); set_sc_with_vfx( SC_MANHOLE , SC__MANHOLE , SI_MANHOLE , SCB_NONE ); - add_sc( SC_CHAOSPANIC , SC__CHAOS ); + add_sc( SC_CHAOSPANIC , SC_CONFUSION ); add_sc( SC_BLOODYLUST , SC_BERSERK ); add_sc( SC_FEINTBOMB , SC__FEINTBOMB ); @@ -801,6 +801,7 @@ void initChangeTables(void) /* Rebellion */ add_sc( RL_MASS_SPIRAL , SC_BLEEDING ); add_sc( RL_HAMMER_OF_GOD , SC_STUN ); + set_sc( RL_H_MINE , SC_H_MINE , SI_H_MINE , SCB_NONE); set_sc( RL_B_TRAP , SC_B_TRAP , SI_B_TRAP , SCB_SPEED ); set_sc( RL_E_CHAIN , SC_E_CHAIN , SI_E_CHAIN , SCB_NONE ); set_sc( RL_P_ALTER , SC_P_ALTER , SI_P_ALTER , SCB_NONE ); @@ -981,7 +982,6 @@ void initChangeTables(void) StatusIconChangeTable[SC_MTF_CRIDAMAGE] = SI_MTF_CRIDAMAGE; StatusIconChangeTable[SC_MOONSTAR] = SI_MOONSTAR; StatusIconChangeTable[SC_SUPER_STAR] = SI_SUPER_STAR; - StatusIconChangeTable[SC_H_MINE] = SI_H_MINE; StatusIconChangeTable[SC_QD_SHOT_READY] = SI_E_QD_SHOT_READY; StatusIconChangeTable[SC_HEAT_BARREL_AFTER] = SI_HEAT_BARREL_AFTER; StatusIconChangeTable[SC_STRANGELIGHTS] = SI_STRANGELIGHTS; @@ -1918,9 +1918,8 @@ bool status_check_skilluse(struct block_list *src, struct block_list *target, ui return false; if(skill_id == PR_LEXAETERNA && (tsc->data[SC_FREEZE] || (tsc->data[SC_STONE] && tsc->opt1 == OPT1_STONE))) return false; - if (tsc->data[SC__MANHOLE]) - if (!(skill_get_inf3(skill_id)&INF3_USABLE_MANHOLE)) - return false; + if (tsc->data[SC__MANHOLE] && !(skill_get_inf3(skill_id)&INF3_USABLE_MANHOLE)) + return false; } // If targetting, cloak+hide protect you, otherwise only hiding does. @@ -5491,6 +5490,7 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change if(sc->data[SC_TINDER_BREAKER] || sc->data[SC_TINDER_BREAKER2]) return 1; // 1 = min flee + // Fixed value if(sc->data[SC_INCFLEE]) flee += sc->data[SC_INCFLEE]->val1; if(sc->data[SC_FLEEFOOD]) @@ -5521,11 +5521,14 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change flee += sc->data[SC_HALLUCINATIONWALK]->val2; if( sc->data[SC_WATER_BARRIER] ) flee -= sc->data[SC_WATER_BARRIER]->val3; + if( sc->data[SC_C_MARKER] ) + flee -= sc->data[SC_C_MARKER]->val3; #ifdef RENEWAL if( sc->data[SC_SPEARQUICKEN] ) flee += 2 * sc->data[SC_SPEARQUICKEN]->val1; #endif + // Rate value if(sc->data[SC_INCFLEERATE]) flee += flee * sc->data[SC_INCFLEERATE]->val1/100; if(sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1) @@ -5558,8 +5561,8 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change flee += flee * 20 / 100; if (sc->data[SC_TEARGAS]) flee -= flee * 50 / 100; - if( sc->data[SC_C_MARKER] ) - flee -= (flee * sc->data[SC_C_MARKER]->val3) / 100; + //if( sc->data[SC_C_MARKER] ) + // flee -= (flee * sc->data[SC_C_MARKER]->val3) / 100; if(sc->data[SC_HEAT_BARREL]) flee -= sc->data[SC_HEAT_BARREL]->val4; @@ -7043,14 +7046,10 @@ void status_change_init(struct block_list *bl) * @param type: Status change (SC_*) * @param rate: Initial percentage rate of affecting bl * @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 +* @param flag: Value which determines what parts to calculate. See e_status_change_start_flags * @return adjusted duration based on flag values **/ -int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int tick, int flag) +int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int tick, unsigned char flag) { /// Resistance rate: 10000 = 100% /// Example: 50% (5000) -> sc_def = 5000 -> 25%; @@ -7269,6 +7268,9 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ case SC_VOICEOFSIREN: tick_def2 = (status_get_lv(bl) * 100) + ((bl->type == BL_PC)?((TBL_PC*)bl)->status.job_level * 200 : 0); break; + case SC_B_TRAP: + tick_def = b_status->str * 50; // (custom) + break; default: // Effect that cannot be reduced? Likely a buff. if (!(rnd()%10000 < rate)) @@ -7320,7 +7322,7 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ tick_def = sc_def; // Natural resistance - if (!(flag&8)) { + if (!(flag&SCSTART_NORATEDEF)) { rate -= rate*sc_def/10000; rate -= sc_def2; @@ -7347,10 +7349,11 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ return 0; // Even if a status change doesn't have a duration, it should still trigger - if (tick < 1) return 1; + if (tick < 1) + return 1; - // Rate reduction - if (flag&2) + // Duration cannot be reduced + if (flag&SCSTART_NOTICKDEF) return tick; tick -= tick*tick_def/10000; @@ -7458,16 +7461,10 @@ void status_display_remove(struct map_session_data *sd, enum sc_type type) { * @param rate: Initial percentage rate of affecting bl (0~10000) * @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 -* &16: don't send SI +* @param flag: Value which determines what parts to calculate. See e_status_change_start_flags * @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) -{ +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,unsigned char flag) { struct map_session_data *sd = NULL; struct status_change* sc; struct status_change_entry* sce; @@ -7565,11 +7562,14 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty sd = BL_CAST(BL_PC, bl); // Adjust tick according to status resistances - if( !(flag&(1|4)) ) { + if( !(flag&(SCSTART_NOAVOID|SCSTART_LOADED)) ) { tick = status_get_sc_def(src, bl, type, rate, tick, flag); - if( !tick ) return 0; + if( !tick ) + return 0; } + vd = status_get_viewdata(bl); + undead_flag = battle_check_undead(status->race,status->def_ele); // Check for immunities / sc fails switch (type) { @@ -7595,7 +7595,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty return 0; case SC_FREEZE: // Undead are immune to Freeze/Stone - if (undead_flag && !(flag&1)) + if (undead_flag && !(flag&SCSTART_NOAVOID)) return 0; case SC_DEEPSLEEP: case SC_SLEEP: @@ -7724,7 +7724,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty break; // Strip skills, need to divest something or it fails. case SC_STRIPWEAPON: - if (sd && !(flag&4)) { // Apply sc anyway if loading saved sc_data + if (sd && !(flag&SCSTART_LOADED)) { // Apply sc anyway if loading saved sc_data short i; opt_flag = 0; // Reuse to check success condition. if(sd->bonus.unstripable_equip&EQP_WEAPON) @@ -7747,7 +7747,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_STRIPSHIELD: if( val2 == 1 ) val2 = 0; // GX effect. Do not take shield off.. else - if (sd && !(flag&4)) { + if (sd && !(flag&SCSTART_LOADED)) { short i; if(sd->bonus.unstripable_equip&EQP_SHIELD) return 0; @@ -7759,7 +7759,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC break; case SC_STRIPARMOR: - if (sd && !(flag&4)) { + if (sd && !(flag&SCSTART_LOADED)) { short i; if(sd->bonus.unstripable_equip&EQP_ARMOR) return 0; @@ -7771,7 +7771,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC break; case SC_STRIPHELM: - if (sd && !(flag&4)) { + if (sd && !(flag&SCSTART_LOADED)) { short i; if(sd->bonus.unstripable_equip&EQP_HELM) return 0; @@ -7896,20 +7896,19 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty if (sc->data[SC_P_ALTER] || sc->data[SC_HEAT_BARREL]) return 0; break; - case SC_C_MARKER: - if (src == bl) + + case SC_WEDDING: + case SC_XMAS: + case SC_SUMMER: + case SC_HANBOK: + case SC_OKTOBERFEST: + if (!vd) return 0; - else { - struct status_change *tsc = status_get_sc(bl); - // Failed if the target is already marked and the new marker that isn't same marker - if (tsc && tsc->data[type] && tsc->data[type]->val2 != src->id) - return 0; - } break; } // Check for BOSS resistances - if(status->mode&MD_BOSS && !(flag&1)) { + if(status->mode&MD_BOSS && !(flag&SCSTART_NOAVOID)) { if (type>=SC_COMMON_MIN && type <= SC_COMMON_MAX) return 0; switch (type) { @@ -7953,7 +7952,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty } } // Check for mvp resistance // atm only those who OS - if(status->mode&MD_MVP && !(flag&1)) { + if(status->mode&MD_MVP && !(flag&SCSTART_NOAVOID)) { switch (type) { case SC_COMA: // continue list... @@ -8274,7 +8273,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC__LAZINESS: case SC__WEAKNESS: case SC__UNLUCKY: - case SC__CHAOS: + //case SC__CHAOS: return 0; case SC_COMBO: case SC_DANCING: @@ -8337,11 +8336,26 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty } } - vd = status_get_viewdata(bl); calc_flag = StatusChangeFlagTable[type]; - if(!(flag&4)) // &4 - Do not parse val settings when loading SCs + if(!(flag&SCSTART_LOADED)) // &4 - Do not parse val settings when loading SCs switch(type) { + /* Permanent effects */ + case SC_AETERNA: + case SC_MODECHANGE: + case SC_WEIGHT50: + case SC_WEIGHT90: + case SC_BROKENWEAPON: + case SC_BROKENARMOR: + case SC_READYSTORM: + case SC_READYDOWN: + case SC_READYCOUNTER: + case SC_READYTURN: + case SC_DODGE: + case SC_PUSH_CART: + tick = -1; + break; + case SC_DECREASEAGI: case SC_INCREASEAGI: case SC_ADORAMUS: @@ -8351,17 +8365,17 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty break; case SC_ENDURE: val2 = 7; // Hit-count [Celest] - if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg(bl->m) && !map[bl->m].flag.battleground && !val4 ) { + if( !(flag&SCSTART_NOAVOID) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg(bl->m) && !map[bl->m].flag.battleground && !val4 ) { struct map_session_data *tsd; if( sd ) { int 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|16); + status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, SCSTART_NOAVOID|SCSTART_NOICON); } } 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, val3, val4, tick, 1); + status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, SCSTART_NOAVOID|SCSTART_NOICON); } // val4 signals infinite endure (if val4 == 2 it is infinite endure from Berserk) if( val4 ) @@ -8445,17 +8459,17 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_REFLECTSHIELD: 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)) ) { + if( !(flag&SCSTART_NOAVOID) && (bl->type&(BL_PC|BL_MER)) ) { struct map_session_data *tsd; if( sd ) { int 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, 1, tick, 1|16); + status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, SCSTART_NOAVOID|SCSTART_NOICON); } } 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, 1, tick, 1); + status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, SCSTART_NOAVOID|SCSTART_NOICON); } break; case SC_STRIPWEAPON: @@ -8481,25 +8495,44 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty val4 = 5 + val1*2; // Chance of casting break; case SC_VOLCANO: - val2 = val1*10; // Watk increase + { + int8 enchant_eff[] = { 10, 14, 17, 19, 20 }; // Enchant addition + uint8 i = max((val1-1)%5, 0); + + val2 = val1*10; // Watk increase #ifndef RENEWAL - if (status->def_ele != ELE_FIRE) - val2 = 0; + if (status->def_ele != ELE_FIRE) + val2 = 0; #endif + val3 = enchant_eff[i]; + } break; case SC_VIOLENTGALE: - val2 = val1*3; // Flee increase + { + int8 enchant_eff[] = { 10, 14, 17, 19, 20 }; // Enchant addition + uint8 i = max((val1-1)%5, 0); + + val2 = val1*3; // Flee increase #ifndef RENEWAL - if (status->def_ele != ELE_WIND) - val2 = 0; + if (status->def_ele != ELE_WIND) + val2 = 0; #endif + val3 = enchant_eff[i]; + } break; case SC_DELUGE: - val2 = deluge_eff[val1-1]; // HP increase + { + int8 deluge_eff[] = { 5, 9, 12, 14, 15 }; // HP addition rate n/100 + int8 enchant_eff[] = { 10, 14, 17, 19, 20 }; // Enchant addition + uint8 i = max((val1-1)%5, 0); + + val2 = deluge_eff[i]; // HP increase #ifndef RENEWAL - if(status->def_ele != ELE_WATER) - val2 = 0; + if (status->def_ele != ELE_WATER) + val2 = 0; #endif + val3 = enchant_eff[i]; + } break; case SC_SUITON: if (!val2 || (sd && (sd->class_&MAPID_BASEMASK) == MAPID_NINJA)) { @@ -8551,15 +8584,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty val2 = 50*(2+type-SC_ASPDPOTION0); break; - case SC_WEDDING: - case SC_XMAS: - case SC_SUMMER: - case SC_HANBOK: - case SC_OKTOBERFEST: - if (!vd) return 0; - // Store previous values as they could be removed. - unit_stop_attack(bl); - break; case SC_NOCHAT: // A hardcoded interval of 60 seconds is expected, as the time that SC_NOCHAT uses is defined by // mmocharstatus.manner, each negative point results in 1 minute with this status activated. @@ -8607,7 +8631,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty break; case SC_CONFUSION: - clif_emotion(bl,E_WHAT); + if (!val4) + clif_emotion(bl,E_WHAT); break; case SC_BLEEDING: val4 = tick/10000; @@ -8674,24 +8699,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty tick_time = 10; // [GodLesZ] tick time break; - /* Permanent effects */ - case SC_AETERNA: - case SC_MODECHANGE: - case SC_WEIGHT50: - case SC_WEIGHT90: - case SC_BROKENWEAPON: - case SC_BROKENARMOR: - case SC_READYSTORM: - case SC_READYDOWN: - case SC_READYCOUNTER: - case SC_READYTURN: - case SC_DODGE: - case SC_PUSH_CART: - tick = -1; - break; - case SC_AUTOGUARD: - if( !(flag&1) ) { + if( !(flag&SCSTART_NOAVOID) ) { struct map_session_data *tsd; int i; for( i = val2 = 0; i < val1; i++) { @@ -8703,17 +8712,17 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty if( sd ) { 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|16); + status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, SCSTART_NOAVOID|SCSTART_NOICON); } } 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, 0, tick, SCSTART_NOAVOID|SCSTART_NOICON); } } break; case SC_DEFENDER: - if (!(flag&1)) { + if (!(flag&SCSTART_NOAVOID)) { val2 = 5 + 15*val1; // Damage reduction val3 = 0; // Unused, previously speed adjustment val4 = 250 - 50*val1; // Aspd adjustment @@ -8723,7 +8732,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty int i; 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); + status_change_start(src,&tsd->bl,type,10000,val1,5+val1*5,val3,val4,tick,SCSTART_NOAVOID); } } } @@ -8848,7 +8857,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] ) - 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); + 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 : SCSTART_NOAVOID|SCSTART_NOICON); i--; } } @@ -9239,7 +9248,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty tick_time = 4000; // [GodLesZ] tick time break; case SC_PYREXIA: - status_change_start(src,bl,SC_BLIND,10000,val1,0,0,0,30000,11); // Blind status that last for 30 seconds + status_change_start(src,bl,SC_BLIND,10000,val1,0,0,0,30000,SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_NORATEDEF); // Blind status that last for 30 seconds val4 = tick / 3000; tick_time = 3000; // [GodLesZ] tick time break; @@ -9355,14 +9364,14 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty break; case SC__UNLUCKY: { - short rand_eff; + sc_type rand_eff; switch(rand() % 3) { case 1: rand_eff = SC_BLIND; break; case 2: rand_eff = SC_SILENCE; break; default: rand_eff = SC_POISON; break; } val2 = 10 * val1; // Crit and Flee2 Reduction - status_change_start(src,bl,rand_eff,10000,val1,0,0,0,tick,10); + status_change_start(src,bl,rand_eff,10000,val1,0,0,0,tick,SCSTART_NOTICKDEF|SCSTART_NORATEDEF); break; } case SC__WEAKNESS: @@ -9842,11 +9851,12 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty val3 = val1 * 25; // -movespeed (custom) break; case SC_C_MARKER: - val2 = src->id; - val3 = 10; //-10% flee + // val1 = skill_lv + // val2 = src_id + val3 = 10; // -10 flee //Start timer to send mark on mini map val4 = tick/1000; - tick_time = 1000; + tick_time = 1000; // Sends every 1 seconds break; case SC_H_MINE: val2 = src->id; @@ -9854,8 +9864,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_HEAT_BARREL: //kRO Update 2014-02-26 { - short n = 10; - if (sd) n = sd->spiritball_old; + uint8 n = 10; + if (sd) + n = (uint8)sd->spiritball_old; val2 = val1 * 5; // -fixed casttime (custom) val3 = val1 * n / 5; // +aspd (custom) val4 = 75 - val1 * 5; // -flee @@ -9863,8 +9874,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty break; case SC_P_ALTER: { - short n = 10; - if (sd) n = sd->spiritball_old; + uint8 n = 10; + if (sd) + n = (uint8)sd->spiritball_old; val2 = val1 * n * 2; // +atk (custom) val3 = val1 * 15; // +def (custom) } @@ -9872,7 +9884,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_E_CHAIN: val2 = 10; if (sd) - val2 = (uint8)sd->spiritball_old; + val2 = sd->spiritball_old; break; case SC_ANTI_M_BLAST: val2 = val1 * 10; @@ -10007,7 +10019,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_BITE: case SC_THORNSTRAP: case SC__MANHOLE: - case SC__CHAOS: + //case SC__CHAOS: case SC_CRYSTALIZE: case SC_CURSEDCIRCLE_ATKER: case SC_FEAR: @@ -10017,11 +10029,11 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_PARALYSIS: case SC_MAGNETICFIELD: unit_stop_walking(bl,1); - break; + break; case SC_ANKLE: if( battle_config.skill_trap_type || !map_flag_gvg(bl->m) ) unit_stop_walking(bl,1); - break; + break; case SC_HIDING: case SC_CLOAKING: case SC_CLOAKINGEXCEED: @@ -10031,16 +10043,21 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_CAMOUFLAGE: case SC_VOICEOFSIREN: case SC_HEAT_BARREL_AFTER: + case SC_WEDDING: + case SC_XMAS: + case SC_SUMMER: + case SC_HANBOK: + case SC_OKTOBERFEST: unit_stop_attack(bl); - break; + break; case SC_SILENCE: if (battle_config.sc_castcancel&bl->type) unit_skillcastcancel(bl, 0); - break; + break; case SC_VACUUM_EXTREME: if (!map_flag_gvg(bl->m)) unit_stop_walking(bl, 1); - break; + break; case SC_ITEMSCRIPT: // Shows Buff Icons if (sd && val2 != SI_BLANK) clif_status_change(bl, (enum si_type)val2, 1, tick, 0, 0, 0); @@ -10231,7 +10248,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty calc_flag&=~SCB_DYE; } - if(!(flag&16) && !(flag&4 && StatusDisplayType[type])) + if(!(flag&SCSTART_NOICON) && !(flag&SCSTART_LOADED && 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. @@ -10333,7 +10350,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_C_MARKER: //Send mini-map, don't wait for first timer triggered if (src->type == BL_PC && (sd = map_id2sd(src->id))) - clif_crimson_marker(sd->fd,bl,false); + clif_crimson_marker(sd, bl, false); break; } @@ -10495,7 +10512,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const struct status_change_entry *sce; struct status_data *status; struct view_data *vd; - int opt_flag=0, calc_flag,temp_n = 0; + int opt_flag = 0, calc_flag; nullpo_ret(bl); @@ -10542,11 +10559,6 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const if ( StatusChangeStateTable[type] ) status_calc_state(bl,sc,( enum scs_flag ) StatusChangeStateTable[type],false); - switch (type) { - case SC_H_MINE: temp_n = sc->data[type]->val3; break; // If ended by RL_FLICKER, don't drop the trap - case SC_C_MARKER: temp_n = sc->data[type]->val2; break; // Player who gave mark - } - sc->data[type] = NULL; if (sd && StatusDisplayType[type]) @@ -10984,15 +10996,15 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC_C_MARKER: { // Remove mark data from caster - struct map_session_data *caster = map_id2sd(temp_n); + struct map_session_data *caster = map_id2sd(sce->val2); uint8 i = 0; - if (!caster || !&caster->c_marker || !caster->c_marker.target) + if (!caster) break; - ARR_FIND(0,MAX_SKILL_CRIMSON_MARKER,i,caster->c_marker.target[i] == bl->id); + ARR_FIND(0,MAX_SKILL_CRIMSON_MARKER,i,caster->c_marker[i] == bl->id); if (i < MAX_SKILL_CRIMSON_MARKER) { - caster->c_marker.target[i] = 0; - clif_crimson_marker(caster->fd,bl,true); + caster->c_marker[i] = 0; + clif_crimson_marker(caster, bl, true); } } break; @@ -11000,15 +11012,17 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const { // Drop the material from target if expired struct item it; - if (temp_n) + struct map_session_data *caster = NULL; + + if (sce->val3 || status_isdead(bl) || !(caster = map_id2sd(sce->val2))) break; if (!itemdb_exists(skill_get_itemid(RL_H_MINE,0))) break; - memset(&it,0,sizeof(it)); + memset(&it, 0, sizeof(it)); it.nameid = skill_get_itemid(RL_H_MINE,0); it.amount = max(skill_get_itemqty(RL_H_MINE,0),1); it.identify = 1; - map_addflooritem(&it,it.amount,bl->m,bl->x,bl->y,0,0,0,4); + map_addflooritem(&it, it.amount, bl->m,bl->x, bl->y, caster->status.char_id, 0, 0, 4); } break; } @@ -11646,15 +11660,18 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) } if( !flag ) { // Random Skill Cast - if (sd && !pc_issit(sd)) { // Can't cast if sit - int mushroom_skill_id = 0; + if (skill_magicmushroom_count && sd && !pc_issit(sd)) { // Can't cast if sit + int mushroom_skill_id = 0, checked = 0, checked_max = MAX_SKILL_MAGICMUSHROOM_DB * 3; unit_stop_attack(bl); unit_skillcastcancel(bl,1); do { int i = rnd() % MAX_SKILL_MAGICMUSHROOM_DB; mushroom_skill_id = skill_magicmushroom_db[i].skill_id; } - while( mushroom_skill_id == 0 ); + while( checked++ < checked_max && mushroom_skill_id == 0 ); + + if (!skill_get_index(mushroom_skill_id)) + break; switch( skill_get_casttype(mushroom_skill_id) ) { // Magic Mushroom skills are buffs or area damage case CAST_GROUND: @@ -12114,17 +12131,18 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_C_MARKER: if( --(sce->val4) >= 0 ) { - TBL_PC *tsd = map_id2sd(sce->val2); - if (!tsd || tsd->bl.m != bl->m) //End the SC if caster isn't in same map + TBL_PC *caster = map_id2sd(sce->val2); + if (!caster || caster->bl.m != bl->m) //End the SC if caster isn't in same map break; sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - clif_crimson_marker(tsd->fd,bl,false); + clif_crimson_marker(caster, bl, false); return 0; } break; } // Default for all non-handled control paths is to end the status + return status_change_end( bl,type,tid ); #undef sc_timer_next } @@ -12474,7 +12492,7 @@ int status_change_spread( struct block_list *src, struct block_list *bl ) data.val2 = sc->data[i]->val2; data.val3 = sc->data[i]->val3; data.val4 = sc->data[i]->val4; - status_change_start(src,bl,(sc_type)i,10000,data.val1,data.val2,data.val3,data.val4,data.tick,1|2|8); + status_change_start(src,bl,(sc_type)i,10000,data.val1,data.val2,data.val3,data.val4,data.tick,SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_NORATEDEF); flag = 1; } } diff --git a/src/map/status.h b/src/map/status.h index eb3a3e2b27..251e5ad496 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -1732,6 +1732,16 @@ enum e_status_calc_opt { SCO_FORCE = 0x2, /* Only relevant to BL_PC types, ensures call bypasses the queue caused by delayed damage */ }; +/// Flags for status_change_start and status_get_sc_def +enum e_status_change_start_flags { + SCSTART_NONE = 0x00, + SCSTART_NOAVOID = 0x01, /// Cannot be avoided (it has to start) + SCSTART_NOTICKDEF = 0x02, /// Tick should not be reduced (by statuses or bonuses) + SCSTART_LOADED = 0x04, /// When sc_data loaded (fetched from table), no values (val1 ~ val4) have to be altered/recalculate + SCSTART_NORATEDEF = 0x08, /// Rate should not be reduced (by statuses or bonuses) + SCSTART_NOICON = 0x10, /// Status icon won't be sent to client +}; + ///Enum for bonus_script's flag [Cydh] enum e_bonus_script_flags { BSF_REM_ON_DEAD = 0x001, ///Removed when dead @@ -1995,13 +2005,13 @@ struct status_change *status_get_sc(struct block_list *bl); int status_isdead(struct block_list *bl); int status_isimmune(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); +int status_get_sc_def(struct block_list *src,struct block_list *bl, enum sc_type type, int rate, int tick, unsigned char flag); //Short version, receives rate in 1->100 range, and does not uses a flag setting. -#define sc_start(src, bl, type, rate, val1, tick) status_change_start(src,bl,type,100*(rate),val1,0,0,0,tick,0) -#define sc_start2(src, bl, type, rate, val1, val2, tick) status_change_start(src,bl,type,100*(rate),val1,val2,0,0,tick,0) -#define sc_start4(src, bl, type, rate, val1, val2, val3, val4, tick) status_change_start(src,bl,type,100*(rate),val1,val2,val3,val4,tick,0) +#define sc_start(src, bl, type, rate, val1, tick) status_change_start(src,bl,type,100*(rate),val1,0,0,0,tick,SCSTART_NONE) +#define sc_start2(src, bl, type, rate, val1, val2, tick) status_change_start(src,bl,type,100*(rate),val1,val2,0,0,tick,SCSTART_NONE) +#define sc_start4(src, bl, type, rate, val1, val2, val3, val4, tick) status_change_start(src,bl,type,100*(rate),val1,val2,val3,val4,tick,SCSTART_NONE) -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); +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,unsigned char flag); int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const char* file, int line); #define status_change_end(bl,type,tid) status_change_end_(bl,type,tid,__FILE__,__LINE__) int kaahi_heal_timer(int tid, unsigned int tick, int id, intptr_t data); diff --git a/src/map/unit.c b/src/map/unit.c index 4445ac923a..fef01374e7 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -934,8 +934,12 @@ int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag) if(dx || dy) { map_foreachinmovearea(clif_outsight, bl, AREA_SIZE, dx, dy, bl->type == BL_PC ? BL_ALL : BL_PC, bl); - if(su) - skill_unit_move_unit_group(su->group, bl->m, dx, dy); + if(su) { + if (su->group && skill_get_unit_flag(su->group->skill_id)&UF_KNOCKBACK_GROUP) + skill_unit_move_unit_group(su->group, bl->m, dx, dy); + else + skill_unit_move_unit(bl, nx, ny); + } else map_moveblock(bl, nx, ny, gettick()); @@ -1424,6 +1428,19 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui } } break; + case RL_C_MARKER: + { + uint8 i = 0; + ARR_FIND(0, MAX_SKILL_CRIMSON_MARKER, i, sd->c_marker[i] == target_id); + if (i == MAX_SKILL_CRIMSON_MARKER) { + ARR_FIND(0, MAX_SKILL_CRIMSON_MARKER, i, sd->c_marker[i] == 0); + if (i == MAX_SKILL_CRIMSON_MARKER) { // 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; diff --git a/tools/check-doc.pl b/tools/check-doc.pl index 8599cabfda..28ade163f5 100755 --- a/tools/check-doc.pl +++ b/tools/check-doc.pl @@ -24,8 +24,8 @@ Main($sCmd,$sTarget); sub GetArgs { GetOptions( - 'cmd=s' => \$sCmd, # wich command to run - 'atcf=s' => \$sAtcf, #atc doc file + 'cmd=s' => \$sCmd, # which command to run + 'atcf=s' => \$sAtcf, #atcommand doc file 'scriptf=s' => \$sSctf, #script doc file 'inc_atcf=s' => \$sInc_atcf, #include script doc file (for customs doc) 'inc_scrtf=s' => \$sInc_scrtf, #include script doc file (for customs doc) @@ -35,7 +35,7 @@ sub GetArgs { ) or $sHelp=1; #display help if invalid option if( $sHelp ) { - print "Incorect option specified, available option are:\n" + print "Incorrect option specified, available options are:\n" ."\t --atcf filename => file (specify atcommand doc to use)\n" ."\t --inc_atcf filename => include file (specify atcommand doc to use)\n" ."\t --scriptf filename => file (specify script doc to use)\n" @@ -46,12 +46,12 @@ sub GetArgs { exit; } unless($sTarget =~ /$sValidTarget/i){ - print "Incorect target specified, available target are:\n" + print "Incorrect target specified, available target is:\n" ."\t --target => target (specify wich check to run [(default)$sValidTarget])\n"; exit; } unless($sCmd =~ /$sValidCmd/i){ - print "Incorect command specified, available command are:\n" + print "Incorrect command specified, available command is:\n" ."\t --cmd => cmd (specify wich command to run [(default)$sValidCmd])\n"; exit; } @@ -65,14 +65,14 @@ sub Main { my ($sCmd,$sTarget) = @_; if($sTarget=~/script/i){ #find which script commands are missing from doc/script_commands.txt my $raSct_cmd = Script_GetCmd(); if($sCmd =~ /ls/i) { - print "The list of script-command found are = \n[ @$raSct_cmd ] \n\n"; + print "The list of script-commands found are = \n[ @$raSct_cmd ] \n\n"; } if($sCmd =~ /chk/i) { Script_Chk($raSct_cmd); } } if($sTarget=~/atc/i){ #find which atcommands are missing from doc/atcommands.txt my $raAct_cmd = Atc_GetCmd(); if($sCmd =~ /ls/i) { - print "The list of atcommand found are = \n[ @$raAct_cmd ] \n\n"; + print "The list of atcommands found are = \n[ @$raAct_cmd ] \n\n"; } if($sCmd =~ /chk/i) { Atc_Chk($raAct_cmd); } } @@ -240,12 +240,12 @@ sub Atc_Chk { my ($raDef_act) = @_; if($sLeftOverChk){ my $raLeftover_sct = Chk(\@aDoc_act,$raDef_act); #we just inverse the chk for leftover if(scalar(@$raLeftover_sct)){ - print "Those atcommand command was found in doc but no source associated, leftover ? : {\n"; + print "Those atcommands were found in doc but no source associated, leftover ? : {\n"; foreach(@$raLeftover_sct){ print "\t$_ \n"; } print "}\n\n"; } - else { print "All atcommand in documentation match a source ATCMD, no leftover found\n"; } + else { print "All atcommands in documentation match a source ATCMD, no leftover found\n"; } } }