From 7556453dfcd21180566ab56a891f628caa75e3db Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Thu, 30 Dec 2021 20:25:19 +0100 Subject: [PATCH] Merge of Rytech's 4CrAM (#6414) Merged Rytech2/4CrAM-Open@978d4fc40697faed61a68598657320bd88281a1d Original author is @Rytech2 and all credits belong to him. Cleanups by @Lemongrass3110, @aleos89 and @Atemo. Co-authored-by: Rytech2 Co-authored-by: aleos Co-authored-by: Atemo --- conf/atcommands.yml | 7 + conf/battle/exp.conf | 5 + conf/battle/player.conf | 47 +- conf/battle/skill.conf | 9 +- conf/msg_conf/char_msg.conf | 14 +- conf/msg_conf/map_msg.conf | 24 +- db/import-tmpl/mob_db.yml | 4 +- db/import-tmpl/skill_db.yml | 11 +- db/import-tmpl/statpoint.yml | 3 +- db/mob_db.yml | 4 +- db/pre-re/mob_db.yml | 4 +- db/pre-re/skill_db.yml | 11 +- db/pre-re/statpoint.yml | 3 +- db/re/elemental_db.yml | 70 + db/re/item_db_equip.yml | 3 + db/re/item_db_etc.yml | 45 +- db/re/item_db_usable.yml | 108 +- db/re/job_basepoints.yml | 4224 ++++++++++++++- db/re/job_noenter_map.txt | 31 +- db/re/mob_db.yml | 220 +- db/re/mob_skill_db.txt | 14 + db/re/produce_db.txt | 38 + db/re/skill_db.yml | 6457 ++++++++++++++++++++++- db/re/skill_nocast_db.txt | 3 + db/re/skill_tree.yml | 1187 +++++ db/re/statpoint.yml | 203 +- db/skill_db.yml | 11 +- db/statpoint.yml | 3 +- db/status_disabled.txt | 140 + doc/item_bonus.txt | 29 +- doc/item_db.txt | 2 +- doc/mob_db.txt | 8 + doc/script_commands.txt | 28 + doc/skill_db.txt | 63 + doc/yaml/db/mob_db.yml | 2 + doc/yaml/db/skill_db.yml | 9 + doc/yaml/db/statpoint.yml | 1 + doc/yaml/sql/mob_db2_re.sql | 2 + doc/yaml/sql/mob_db_re.sql | 2 + npc/custom/jobmaster.txt | 54 +- npc/other/CashShop_Functions.txt | 25 + sql-files/main.sql | 9 + sql-files/mob_db2_re.sql | 2 + sql-files/mob_db_re.sql | 2 + sql-files/upgrades/upgrade_20211230.sql | 11 + src/char/char.cpp | 42 +- src/char/char_logif.cpp | 4 + src/char/inter.cpp | 5 +- src/common/mmo.hpp | 14 +- src/config/packets.hpp | 4 +- src/map/atcommand.cpp | 231 +- src/map/battle.cpp | 943 +++- src/map/battle.hpp | 14 +- src/map/chrif.cpp | 57 +- src/map/clif.cpp | 250 +- src/map/clif.hpp | 7 +- src/map/clif_packetdb.hpp | 4 + src/map/elemental.cpp | 70 +- src/map/elemental.hpp | 8 + src/map/itemdb.hpp | 2 +- src/map/map.cpp | 3 + src/map/map.hpp | 5 + src/map/mob.cpp | 40 +- src/map/mob.hpp | 10 +- src/map/packets.hpp | 7 + src/map/party.cpp | 3 + src/map/pc.cpp | 776 ++- src/map/pc.hpp | 49 +- src/map/script.cpp | 75 + src/map/script.hpp | 4 + src/map/script_constants.hpp | 161 +- src/map/skill.cpp | 1589 +++++- src/map/skill.hpp | 273 +- src/map/status.cpp | 1636 +++++- src/map/status.hpp | 254 +- src/map/unit.cpp | 43 +- src/tool/csv2yaml.cpp | 8 +- src/tool/yaml2sql.cpp | 6 + 78 files changed, 19190 insertions(+), 559 deletions(-) create mode 100644 sql-files/upgrades/upgrade_20211230.sql diff --git a/conf/atcommands.yml b/conf/atcommands.yml index 7e2e918de2..232b28fb8b 100644 --- a/conf/atcommands.yml +++ b/conf/atcommands.yml @@ -335,6 +335,10 @@ Body: Help: | Params: [ ] Heals the desired amount of HP and SP. No value specified will do a full heal. + - Command: healap + Help: | + Params: [] + Heals the desired amount of AP. No value specified will do a full AP heal. - Command: dye Aliases: - ccolor @@ -480,6 +484,9 @@ Body: - Command: stpoint Help: | Params: - Gives you the desired number of stat points. + - Command: trpoint + Help: | + Params: - Gives you the desired number of trait stat points. - Command: skpoint Help: | Params: - Gives you the desired number of skill points. diff --git a/conf/battle/exp.conf b/conf/battle/exp.conf index 352c189702..692d61d2c5 100644 --- a/conf/battle/exp.conf +++ b/conf/battle/exp.conf @@ -102,6 +102,11 @@ disp_zeny: no // through external means (ie: stat point buyers/sellers) use_statpoint_table: yes +// Use the contents of db/statpoint.yml when doing a stats reset and leveling up? (Note 1) +// If no, an equation will be used which preserves trait points earned/lost +// through external means (ie: trait point buyers/sellers) +use_traitpoint_table: yes + // EXP cost for cast PR_REDEMPTIO (Note 2) exp_cost_redemptio: 1 diff --git a/conf/battle/player.conf b/conf/battle/player.conf index b6affc445c..ef56ec4742 100644 --- a/conf/battle/player.conf +++ b/conf/battle/player.conf @@ -108,14 +108,11 @@ max_baby_parameter: 80 max_baby_third_parameter: 117 max_extended_parameter: 125 max_summoner_parameter: 120 -max_fourth_parameter: 135 +max_fourth_parameter: 130 // Status points bonus for transcendent class transcendent_status_points: 52 -// Maximum traits for fourth class. (pow, sta, wis, spl, con, and crt) -max_fourth_trait: 100 - // Max armor def/mdef // NOTE: This setting have no effect if server is run on Renewal Mode (RENEWAL) // NOTE: does not affects skills and status effects like Mental Strength @@ -288,3 +285,45 @@ idletime_option: 0x7C1F // - Summoners are small size (0) instead of medium (1) summoner_race: 11 summoner_size: 0 + +//================================ +// 4th Job Systems +//================================ +// How many trait points do players get when changing to a 4th job? +// Default: 7 +trait_points_job_change: 7 + +// Max trait stats cap. +// Trait Stats: POW, STA, WIS, SPL, CON, CRT +// Official is 100. +max_trait_parameter: 100 + +// Max amount of RES/MRES to take into the resistance damage reduction formula. +// A setting of 625 means the max reduction of damage allowed is 50.0%. +// Formula is 100 - 100 * (5000 + RES) / (5000 + 10 * RES) +// Note: Best to leave this setting alone unless you know what your doing. +// Default: 625 +max_res_mres_reduction: 625 + +// Maximum AP +// Default: 1000 +max_ap: 1000 + +// Players' maximum AP rate? (Default is 100) +ap_rate: 100 + +// The amount of AP a player will respawn with, 0 is default. +// (Unit is in percentage of total AP, 100 is full heal of AP, 0 is respawn with 0 AP total.) +restart_ap_rate: 0 + +// Is AP lost when the player dies? +// Default: yes +loose_ap_on_death: yes + +// Is AP lost when the player enters a PVP/GVG/WoE/Battleground maps? +// Default: yes +loose_ap_on_map: yes + +// Do player's keep their AP when logging out? +// Default: yes +keep_ap_on_logout: yes diff --git a/conf/battle/skill.conf b/conf/battle/skill.conf index 56ac8eb9d4..1cdffedd9e 100644 --- a/conf/battle/skill.conf +++ b/conf/battle/skill.conf @@ -274,8 +274,9 @@ sg_miracle_skill_duration: 3600000 sg_angel_skill_ratio: 10 // Skills that bHealPower has effect on -// 1: Heal, 2: Sanctuary, 4: Potion Pitcher, 8: Slim Pitcher, 16: Apple of Idun -skill_add_heal_rate: 7 +// 1: Heal, 2: Sanctuary, 4: Potion Pitcher, 8: Slim Pitcher, 16: Apple of Idun, +// 32: Coluceo Heal, 64: Highness Heal, 128: Mediale Votum, 256: Dilectio Heal +skill_add_heal_rate: 487 // Whether the damage of EarthQuake with a single target on screen is able to be reflected. // Note: On official servers, EQ is reflectable when there is only one target on the screen, @@ -410,3 +411,7 @@ skill_drop_items_full: no // 2: Enabled on renewal. // 3: 1+2 switch_remove_edp: 2 + +// Max Level Difference when casting Meister's Attack Machine on other party members. +// Default: 15 +attack_machine_level_difference: 15 diff --git a/conf/msg_conf/char_msg.conf b/conf/msg_conf/char_msg.conf index 706e1be07e..dd9504bb2c 100644 --- a/conf/msg_conf/char_msg.conf +++ b/conf/msg_conf/char_msg.conf @@ -142,13 +142,13 @@ 132: Inquisitor 133: Troubadour 134: Trouvere -144: Sky Emperor -145: Soul Ascetic -146: Shinkiro -147: Shiranui -148: Night Watch -149: Hyper Novice -150: Spirit Handler +135: Sky Emperor +136: Soul Ascetic +137: Shinkiro +138: Shiranui +139: Night Watch +140: Hyper Novice +141: Spirit Handler 199: Unknown Job diff --git a/conf/msg_conf/map_msg.conf b/conf/msg_conf/map_msg.conf index 7348622fad..b5ce3a6d3e 100644 --- a/conf/msg_conf/map_msg.conf +++ b/conf/msg_conf/map_msg.conf @@ -899,7 +899,27 @@ 818: Hyper Novice 819: Spirit Handler -//820-899 free +// @trpoint +820: Please enter a number (usage: @trpoint ). + +// @chargeap +821: AP recovered. +822: AP modified. +823: AP have already been recovered. + +// @displayskillcast +824: Usage: @displayskillcast { } + +// @displayskill (2nd Message Line) +825: Effect Types: 0: All, 1: Damage, 2: Splash Dmg, 3: No Damage, 4: Ground + +// @displayskillunit +826: Usage: @displayskillunit { } + +// @mobinfo RES/MRES +827: RES:%d MRES:%d + +//828-899 free //------------------------------------ // More atcommands message @@ -1220,7 +1240,7 @@ 1165: Usage: @useskill // @displayskill -1166: Usage: @displayskill {} +1166: Usage: @displayskill { } // @skilltree 1167: Usage: @skilltree diff --git a/db/import-tmpl/mob_db.yml b/db/import-tmpl/mob_db.yml index c691773f56..dd7bd94d6a 100644 --- a/db/import-tmpl/mob_db.yml +++ b/db/import-tmpl/mob_db.yml @@ -36,6 +36,8 @@ # Attack2 Maximum attack in pre-renewal and base magic attack in renewal. (Default: 0) # Defense Physical defense of the monster, reduces melee and ranged physical attack/skill damage. (Default: 0) # MagicDefense Magic defense of the monster, reduces magical skill damage. (Default: 0) +# Resistance Physical resistance of the monster, reduces melee and ranged physical attack/skill damage. (Default: 0) +# MagicResistance Magic resistance of the monster, reduces magical skill damage. (Default: 0) # Str Strength which affects attack. (Default: 1) # Agi Agility which affects flee. (Default: 1) # Vit Vitality which affects defense. (Default: 1) @@ -75,7 +77,7 @@ Header: Type: MOB_DB - Version: 2 + Version: 3 #Body: # eAthena Dev Team diff --git a/db/import-tmpl/skill_db.yml b/db/import-tmpl/skill_db.yml index c748487805..3b59e2bfbc 100644 --- a/db/import-tmpl/skill_db.yml +++ b/db/import-tmpl/skill_db.yml @@ -49,6 +49,9 @@ # Knockback: Amount of tiles the skill knockbacks. (Default: 0) # - Level Skill level. # Amount Knockback count at specific skill level. +# GiveAp: Gives AP on successful skill cast. (Default: 0) +# - Level Skill level. +# Amount AP gained at specific skill level. # CopyFlags: Determines if the skill is copyable. (Optional) # Skill: Type of skill that can copy. # RemoveRequirement: Remove a requirement type. (Optional) @@ -87,12 +90,18 @@ # SpCost: SP required to cast. (Default: 0) # - Level Skill level. # Amount SP required at specific skill level. +# ApCost: AP required to cast. (Default: 0) +# - Level Skill level. +# Amount AP required at specific skill level. # HpRateCost: HP rate required to cast. If positive, uses current HP, else uses Max HP. (Default: 0) # - Level Skill level. # Amount HP rate required at specific skill level. # SpRateCost: SP rate required to cast. If positive, uses current SP, else uses Max SP. (Default: 0) # - Level Skill level. # Amount SP rate required at specific skill level. +# ApRateCost: AP rate required to cast. If positive, uses current AP, else uses Max AP. (Default: 0) +# - Level Skill level. +# Amount AP rate required at specific skill level. # MaxHpTrigger: Maximum amount of HP to cast the skill. (Default: 0) # - Level Skill level. # Amount Maximum HP trigger required at specific skill level. @@ -130,4 +139,4 @@ Header: Type: SKILL_DB - Version: 2 + Version: 3 diff --git a/db/import-tmpl/statpoint.yml b/db/import-tmpl/statpoint.yml index 04710362e8..be7acb524c 100644 --- a/db/import-tmpl/statpoint.yml +++ b/db/import-tmpl/statpoint.yml @@ -24,8 +24,9 @@ ########################################################################### # - Level BaseLevel required. # Points Total status points given from BaseLevel 1 to 'Level'. +# TraitPoints Total trait points given from BaseLevel 1 to 'Level'. ########################################################################### Header: Type: STATPOINT_DB - Version: 1 + Version: 2 diff --git a/db/mob_db.yml b/db/mob_db.yml index 51649b07d2..48e29e9c67 100644 --- a/db/mob_db.yml +++ b/db/mob_db.yml @@ -36,6 +36,8 @@ # Attack2 Maximum attack in pre-renewal and base magic attack in renewal. (Default: 0) # Defense Physical defense of the monster, reduces melee and ranged physical attack/skill damage. (Default: 0) # MagicDefense Magic defense of the monster, reduces magical skill damage. (Default: 0) +# Resistance Physical resistance of the monster, reduces melee and ranged physical attack/skill damage. (Default: 0) +# MagicResistance Magic resistance of the monster, reduces magical skill damage. (Default: 0) # Str Strength which affects attack. (Default: 1) # Agi Agility which affects flee. (Default: 1) # Vit Vitality which affects defense. (Default: 1) @@ -75,7 +77,7 @@ Header: Type: MOB_DB - Version: 2 + Version: 3 Footer: Imports: diff --git a/db/pre-re/mob_db.yml b/db/pre-re/mob_db.yml index 7b01f0eab0..2190f2b27b 100644 --- a/db/pre-re/mob_db.yml +++ b/db/pre-re/mob_db.yml @@ -36,6 +36,8 @@ # Attack2 Maximum attack in pre-renewal and base magic attack in renewal. (Default: 0) # Defense Physical defense of the monster, reduces melee and ranged physical attack/skill damage. (Default: 0) # MagicDefense Magic defense of the monster, reduces magical skill damage. (Default: 0) +# Resistance Physical resistance of the monster, reduces melee and ranged physical attack/skill damage. (Default: 0) +# MagicResistance Magic resistance of the monster, reduces magical skill damage. (Default: 0) # Str Strength which affects attack. (Default: 1) # Agi Agility which affects flee. (Default: 1) # Vit Vitality which affects defense. (Default: 1) @@ -75,7 +77,7 @@ Header: Type: MOB_DB - Version: 2 + Version: 3 Body: - Id: 1001 diff --git a/db/pre-re/skill_db.yml b/db/pre-re/skill_db.yml index 45e05f79f1..109138c741 100644 --- a/db/pre-re/skill_db.yml +++ b/db/pre-re/skill_db.yml @@ -49,6 +49,9 @@ # Knockback: Amount of tiles the skill knockbacks. (Default: 0) # - Level Skill level. # Amount Knockback count at specific skill level. +# GiveAp: Gives AP on successful skill cast. (Default: 0) +# - Level Skill level. +# Amount AP gained at specific skill level. # CopyFlags: Determines if the skill is copyable. (Optional) # Skill: Type of skill that can copy. # RemoveRequirement: Remove a requirement type. (Optional) @@ -87,12 +90,18 @@ # SpCost: SP required to cast. (Default: 0) # - Level Skill level. # Amount SP required at specific skill level. +# ApCost: AP required to cast. (Default: 0) +# - Level Skill level. +# Amount AP required at specific skill level. # HpRateCost: HP rate required to cast. If positive, uses current HP, else uses Max HP. (Default: 0) # - Level Skill level. # Amount HP rate required at specific skill level. # SpRateCost: SP rate required to cast. If positive, uses current SP, else uses Max SP. (Default: 0) # - Level Skill level. # Amount SP rate required at specific skill level. +# ApRateCost: AP rate required to cast. If positive, uses current AP, else uses Max AP. (Default: 0) +# - Level Skill level. +# Amount AP rate required at specific skill level. # MaxHpTrigger: Maximum amount of HP to cast the skill. (Default: 0) # - Level Skill level. # Amount Maximum HP trigger required at specific skill level. @@ -130,7 +139,7 @@ Header: Type: SKILL_DB - Version: 2 + Version: 3 Body: - Id: 1 diff --git a/db/pre-re/statpoint.yml b/db/pre-re/statpoint.yml index dd5c180f2b..9b2710fda4 100644 --- a/db/pre-re/statpoint.yml +++ b/db/pre-re/statpoint.yml @@ -24,11 +24,12 @@ ########################################################################### # - Level BaseLevel required. # Points Total status points given from BaseLevel 1 to 'Level'. +# TraitPoints Total trait points given from BaseLevel 1 to 'Level'. ########################################################################### Header: Type: STATPOINT_DB - Version: 1 + Version: 2 Body: - Level: 1 diff --git a/db/re/elemental_db.yml b/db/re/elemental_db.yml index 64fbe2474e..f072c4d190 100644 --- a/db/re/elemental_db.yml +++ b/db/re/elemental_db.yml @@ -234,3 +234,73 @@ Body: Skill: EL_POWER_OF_GAIA Aggressive: Skill: EL_STONE_RAIN + - Id: 20816 + AegisName: EM_DILUVIO + Name: Diluvio + Level: 200 + Size: Large + Element: Water + ElementLevel: 4 + Mode: + Passive: + Skill: EM_EL_COLD_FORCE + Assist: + Skill: EM_EL_CRYSTAL_ARMOR + Aggressive: + Skill: EM_EL_AGE_OF_ICE + - Id: 20817 + AegisName: EM_ARDOR + Name: Ardor + Level: 200 + Size: Large + Element: Fire + ElementLevel: 4 + Mode: + Passive: + Skill: EM_EL_FLAMETECHNIC + Assist: + Skill: EM_EL_FLAMEARMOR + Aggressive: + Skill: EM_EL_FLAMEROCK + - Id: 20818 + AegisName: EM_PROCELLA + Name: Procella + Level: 200 + Size: Large + Element: Wind + ElementLevel: 4 + Mode: + Passive: + Skill: EM_EL_GRACE_BREEZE + Assist: + Skill: EM_EL_EYES_OF_STORM + Aggressive: + Skill: EM_EL_STORM_WIND + - Id: 20819 + AegisName: EM_TERREMOTUS + Name: Terremotus + Level: 200 + Size: Large + Element: Earth + ElementLevel: 4 + Mode: + Passive: + Skill: EM_EL_EARTH_CARE + Assist: + Skill: EM_EL_STRONG_PROTECTION + Aggressive: + Skill: EM_EL_AVALANCHE + - Id: 20820 + AegisName: EM_SERPENS + Name: Serpens + Level: 200 + Size: Large + Element: Poison + ElementLevel: 4 + Mode: + Passive: + Skill: EM_EL_DEEP_POISONING + Assist: + Skill: EM_EL_POISON_SHIELD + Aggressive: + Skill: EM_EL_DEADLY_POISON diff --git a/db/re/item_db_equip.yml b/db/re/item_db_equip.yml index 7616b64542..1ff7f1b037 100644 --- a/db/re/item_db_equip.yml +++ b/db/re/item_db_equip.yml @@ -144377,6 +144377,7 @@ Body: AegisName: 4th_Q_Necklace Name: Hourglass Necklace Type: Armor + Buy: 20 Locations: Both_Accessory: true ArmorLevel: 1 @@ -144390,6 +144391,8 @@ Body: NoGuildStorage: true NoMail: true NoAuction: true + Script: | + bonus bAllTraits,6-(JobLevel/5); - Id: 490090 AegisName: aegis_490090 Name: Aegir Ring diff --git a/db/re/item_db_etc.yml b/db/re/item_db_etc.yml index 6fe155d576..dbe5c14bf2 100644 --- a/db/re/item_db_etc.yml +++ b/db/re/item_db_etc.yml @@ -31918,7 +31918,7 @@ Body: Name: Special Alloy Trap Type: Etc Buy: 300 - Weight: 1 + Weight: 2 Flags: BuyingStore: true - Id: 7941 @@ -56651,36 +56651,43 @@ Body: AegisName: Beaker Name: Beaker Type: Etc + Buy: 1000 Weight: 1 - Id: 1000276 AegisName: Flame_Acid_Bottle Name: Flame Acid Bottle Type: Etc + Buy: 20 Weight: 1 - Id: 1000277 AegisName: Earth_Acid_Bottle Name: Earth Acid Bottle Type: Etc + Buy: 20 Weight: 1 - Id: 1000278 AegisName: Gale_Acid_Bottle Name: Gale Acid Bottle Type: Etc + Buy: 20 Weight: 1 - Id: 1000279 AegisName: Icicle_Acid_Bottle Name: Icicle Acid Bottle Type: Etc + Buy: 20 Weight: 1 - Id: 1000280 AegisName: High_Coating_Bottle - Name: Advanced Coating Potion + Name: High Coating Bottle Type: Etc + Buy: 20 Weight: 1 - Id: 1000281 AegisName: High_Plant_Bottle - Name: Greater Plant Bottle + Name: High Plant Bottle Type: Etc + Buy: 20 Weight: 1 - Id: 1000282 AegisName: EpisodClear16 @@ -56724,38 +56731,45 @@ Body: NoAuction: true - Id: 1000289 AegisName: Device_Capsule - Name: Machine Capsule + Name: Device Capsule Type: Etc + Buy: 20 Weight: 5 - Id: 1000290 AegisName: Auto_Battle_Capsule - Name: ABR Capsule + Name: Auto Battle Capsule Type: Etc + Buy: 20 Weight: 10 - Id: 1000291 AegisName: Wind_Stone_4th - Name: Lightning Stone + Name: Wind Stone 4th Type: Etc + Buy: 1000 Weight: 1 - Id: 1000292 AegisName: Earth_Stone_4th - Name: Earth Stone + Name: Earth Stone 4th Type: Etc + Buy: 1000 Weight: 1 - Id: 1000293 AegisName: Flame_Stone_4th - Name: Fire Stone + Name: Flame Stone 4th Type: Etc + Buy: 1000 Weight: 1 - Id: 1000294 AegisName: Poison_Stone_4th - Name: Poison Stone + Name: Poison Stone 4th Type: Etc + Buy: 1000 Weight: 1 - Id: 1000295 AegisName: Ice_Stone_4th - Name: Ice Stone + Name: Ice Stone 4th Type: Etc + Buy: 1000 Weight: 1 - Id: 1000296 AegisName: RuneknightStone_Robe2 @@ -56821,6 +56835,7 @@ Body: AegisName: Hawk_Flute Name: Hawk Flute Type: Etc + Buy: 20 Trade: Override: 100 NoDrop: true @@ -56952,13 +56967,15 @@ Body: Flags: BuyingStore: true - Id: 1000346 - AegisName: aegis_1000346 - Name: Guide for 4th Job Change + AegisName: 4th_Job_Guide + Name: 4th Job Guide Type: Etc + Buy: 20 - Id: 1000352 - AegisName: aegis_1000352 - Name: Machine Creation Guide + AegisName: Device_Creation_Guide + Name: Device Creation Guide Type: Etc + Buy: 20 Weight: 10 - Id: 1000363 AegisName: MD_Airboat_Tokken diff --git a/db/re/item_db_usable.yml b/db/re/item_db_usable.yml index f7f9d9b0d0..decd402ffb 100644 --- a/db/re/item_db_usable.yml +++ b/db/re/item_db_usable.yml @@ -1857,7 +1857,7 @@ Body: Flags: BuyingStore: true Script: | - if (Class == Job_Assassin_Cross || Class == Job_Guillotine_Cross || Class == Job_Guillotine_Cross_T) { + if (Class == Job_Assassin_Cross || Class == Job_Guillotine_Cross || Class == Job_Guillotine_Cross_T || Class == Job_Shadow_Cross) { sc_start SC_DPOISON,60000,0; sc_start SC_ASPDPOTION3,60000,9; } @@ -50841,6 +50841,48 @@ Body: BuyingStore: true Script: | /* upgradeui 100436; */ + - Id: 100452 + AegisName: Minus_POW + Name: POW Reduction Potion + Type: Delayconsume + Buy: 10 + Script: | + callfunc "F_CashReduceTraitStat",bPow,-1,100452; + - Id: 100453 + AegisName: Minus_SPL + Name: SPL Reduction Potion + Type: Delayconsume + Buy: 10 + Script: | + callfunc "F_CashReduceTraitStat",bSpl,-1,100453; + - Id: 100454 + AegisName: Minus_STA + Name: STA Reduction Potion + Type: Delayconsume + Buy: 10 + Script: | + callfunc "F_CashReduceTraitStat",bSta,-1,100454; + - Id: 100455 + AegisName: Minus_WIS + Name: WIS Reduction Potion + Type: Delayconsume + Buy: 10 + Script: | + callfunc "F_CashReduceTraitStat",bWis,-1,100455; + - Id: 100456 + AegisName: Minus_CON + Name: CON Reduction Potion + Type: Delayconsume + Buy: 10 + Script: | + callfunc "F_CashReduceTraitStat",bCon,-1,100456; + - Id: 100457 + AegisName: Minus_CRT + Name: CRT Reduction Potion + Type: Delayconsume + Buy: 10 + Script: | + callfunc "F_CashReduceTraitStat",bCrt,-1,100457; - Id: 100466 AegisName: Egir_Power_Box Name: Aegir's Power Box @@ -50921,6 +50963,70 @@ Body: Container: true Script: | /* getgroupitem(IG_Enchant_Stone_Box22); */ + - Id: 100516 + AegisName: Eye_Cleaner + Name: Eye Cleaner + Type: Healing + Buy: 20 + Weight: 50 + Script: | + sc_end SC_HANDICAPSTATE_DEEPBLIND; + - Id: 100517 + AegisName: Ear_Cleaner + Name: Ear Cleaner + Type: Healing + Buy: 20 + Weight: 50 + Script: | + sc_end SC_HANDICAPSTATE_DEEPSILENCE; + - Id: 100518 + AegisName: Tonics + Name: Tonics + Type: Healing + Buy: 20 + Weight: 50 + Script: | + sc_end SC_HANDICAPSTATE_LASSITUDE; + - Id: 100519 + AegisName: Mini_Extinguisher + Name: Mini Extinguisher + Type: Healing + Buy: 20 + Weight: 50 + Script: | + sc_end SC_HANDICAPSTATE_CONFLAGRATION; + - Id: 100520 + AegisName: Water_Of_Lucky + Name: Water Of Lucky + Type: Healing + Buy: 20 + Weight: 50 + Script: | + sc_end SC_HANDICAPSTATE_MISFORTUNE; + - Id: 100521 + AegisName: Strong_Antidote + Name: Strong Antidote + Type: Healing + Buy: 20 + Weight: 50 + Script: | + sc_end SC_HANDICAPSTATE_DEADLYPOISON; + - Id: 100522 + AegisName: High_Energy_Chocolate + Name: High Energy Chocolate + Type: Healing + Buy: 20 + Weight: 50 + Script: | + sc_end SC_HANDICAPSTATE_DEPRESSION; + - Id: 100523 + AegisName: Refined_Holy_Water + Name: Refined Holy Water + Type: Healing + Buy: 20 + Weight: 50 + Script: | + sc_end SC_HANDICAPSTATE_HOLYFLAME; - Id: 100572 AegisName: FullPeneShadow_Mix Name: Full Penetration Shadow Thump Box diff --git a/db/re/job_basepoints.yml b/db/re/job_basepoints.yml index 13abb8090a..0c54926b83 100644 --- a/db/re/job_basepoints.yml +++ b/db/re/job_basepoints.yml @@ -289,7 +289,6 @@ Body: Super_Baby: true Super_Novice_E: true Super_Baby_E: true - Hyper_Novice: true BaseHp: - Level: 1 Hp: 40 @@ -7505,7 +7504,6 @@ Body: - Jobs: Rebellion: true Baby_Rebellion: true - Night_Watch: true BaseHp: - Level: 99 Hp: 4938 @@ -7916,7 +7914,6 @@ Body: - Jobs: Kagerou: true Baby_Kagerou: true - Shinkiro: true BaseHp: - Level: 99 Hp: 4250 @@ -8125,7 +8122,6 @@ Body: - Jobs: Oboro: true Baby_Oboro: true - Shiranui: true BaseHp: - Level: 99 Hp: 4250 @@ -9545,7 +9541,6 @@ Body: - Jobs: Summoner: true Baby_Summoner: true - Spirit_Handler: true BaseHp: - Level: 1 Hp: 40 @@ -9906,7 +9901,6 @@ Body: Super_Baby: true Super_Novice_E: true Super_Baby_E: true - Hyper_Novice: true BaseSp: - Level: 1 Sp: 11 @@ -16922,7 +16916,6 @@ Body: Rebellion: true Baby_Gunslinger: true Baby_Rebellion: true - Night_Watch: true BaseSp: - Level: 1 Sp: 12 @@ -17529,7 +17522,6 @@ Body: - Jobs: Kagerou: true Baby_Kagerou: true - Shinkiro: true BaseSp: - Level: 99 Sp: 522 @@ -17738,7 +17730,6 @@ Body: - Jobs: Oboro: true Baby_Oboro: true - Shiranui: true BaseSp: - Level: 99 Sp: 522 @@ -19158,7 +19149,6 @@ Body: - Jobs: Summoner: true Baby_Summoner: true - Spirit_Handler: true BaseSp: - Level: 1 Sp: 8 @@ -19516,7 +19506,6 @@ Body: Baby_Star_Emperor: true Star_Emperor2: true Baby_Star_Emperor2: true - Sky_Emperor: true BaseHp: - Level: 99 Hp: 4300 @@ -19676,7 +19665,6 @@ Body: - Jobs: Soul_Reaper: true Baby_Soul_Reaper: true - Soul_Ascetic: true BaseHp: - Level: 99 Hp: 4300 @@ -19838,7 +19826,6 @@ Body: Baby_Star_Emperor: true Star_Emperor2: true Baby_Star_Emperor2: true - Sky_Emperor: true BaseSp: - Level: 99 Sp: 522 @@ -19998,7 +19985,6 @@ Body: - Jobs: Soul_Reaper: true Baby_Soul_Reaper: true - Soul_Ascetic: true BaseSp: - Level: 99 Sp: 900 @@ -20155,3 +20141,4213 @@ Body: - Level: 175 Sp: 1615 # Levels 176-200 are unknown + - Jobs: + Dragon_Knight: true + Dragon_Knight2: true + BaseHp: + - Level: 200 + Hp: 22875 + - Level: 201 + Hp: 23050 + - Level: 202 + Hp: 23225 + - Level: 203 + Hp: 23400 + - Level: 204 + Hp: 23575 + - Level: 205 + Hp: 23750 + - Level: 206 + Hp: 23925 + - Level: 207 + Hp: 24100 + - Level: 208 + Hp: 24275 + - Level: 209 + Hp: 24450 + - Level: 210 + Hp: 24625 + - Level: 211 + Hp: 24800 + - Level: 212 + Hp: 24975 + - Level: 213 + Hp: 25150 + - Level: 214 + Hp: 25325 + - Level: 215 + Hp: 25500 + - Level: 216 + Hp: 25675 + - Level: 217 + Hp: 25850 + - Level: 218 + Hp: 26025 + - Level: 219 + Hp: 26200 + - Level: 220 + Hp: 26375 + - Level: 221 + Hp: 26550 + - Level: 222 + Hp: 26725 + - Level: 223 + Hp: 26900 + - Level: 224 + Hp: 27075 + - Level: 225 + Hp: 27250 + - Level: 226 + Hp: 27425 + - Level: 227 + Hp: 27600 + - Level: 228 + Hp: 27775 + - Level: 229 + Hp: 27950 + - Level: 230 + Hp: 28125 + - Level: 231 + Hp: 28300 + - Level: 232 + Hp: 28475 + - Level: 233 + Hp: 28650 + - Level: 234 + Hp: 28825 + - Level: 235 + Hp: 29000 + - Level: 236 + Hp: 29175 + - Level: 237 + Hp: 29350 + - Level: 238 + Hp: 29525 + - Level: 239 + Hp: 29700 + - Level: 240 + Hp: 29875 + - Level: 241 + Hp: 30050 + - Level: 242 + Hp: 30225 + - Level: 243 + Hp: 30400 + - Level: 244 + Hp: 30575 + - Level: 245 + Hp: 30750 + - Level: 246 + Hp: 30925 + - Level: 247 + Hp: 31100 + - Level: 248 + Hp: 31275 + - Level: 249 + Hp: 31450 + - Level: 250 + Hp: 31625 + - Jobs: + Meister: true + Meister2: true + BaseHp: + - Level: 200 + Hp: 21000 + - Level: 201 + Hp: 21175 + - Level: 202 + Hp: 21350 + - Level: 203 + Hp: 21525 + - Level: 204 + Hp: 21700 + - Level: 205 + Hp: 21875 + - Level: 206 + Hp: 22050 + - Level: 207 + Hp: 22225 + - Level: 208 + Hp: 22400 + - Level: 209 + Hp: 22575 + - Level: 210 + Hp: 22750 + - Level: 211 + Hp: 22925 + - Level: 212 + Hp: 23100 + - Level: 213 + Hp: 23275 + - Level: 214 + Hp: 23450 + - Level: 215 + Hp: 23625 + - Level: 216 + Hp: 23800 + - Level: 217 + Hp: 23975 + - Level: 218 + Hp: 24150 + - Level: 219 + Hp: 24325 + - Level: 220 + Hp: 24500 + - Level: 221 + Hp: 24675 + - Level: 222 + Hp: 24850 + - Level: 223 + Hp: 25025 + - Level: 224 + Hp: 25200 + - Level: 225 + Hp: 25375 + - Level: 226 + Hp: 25550 + - Level: 227 + Hp: 25725 + - Level: 228 + Hp: 25900 + - Level: 229 + Hp: 26075 + - Level: 230 + Hp: 26250 + - Level: 231 + Hp: 26425 + - Level: 232 + Hp: 26600 + - Level: 233 + Hp: 26775 + - Level: 234 + Hp: 26950 + - Level: 235 + Hp: 27125 + - Level: 236 + Hp: 27300 + - Level: 237 + Hp: 27475 + - Level: 238 + Hp: 27650 + - Level: 239 + Hp: 27825 + - Level: 240 + Hp: 28000 + - Level: 241 + Hp: 28175 + - Level: 242 + Hp: 28350 + - Level: 243 + Hp: 28525 + - Level: 244 + Hp: 28700 + - Level: 245 + Hp: 28875 + - Level: 246 + Hp: 29050 + - Level: 247 + Hp: 29225 + - Level: 248 + Hp: 29400 + - Level: 249 + Hp: 29575 + - Level: 250 + Hp: 29750 + - Jobs: + Shadow_Cross: true + BaseHp: + - Level: 200 + Hp: 20725 + - Level: 201 + Hp: 20875 + - Level: 202 + Hp: 21025 + - Level: 203 + Hp: 21175 + - Level: 204 + Hp: 21325 + - Level: 205 + Hp: 21475 + - Level: 206 + Hp: 21625 + - Level: 207 + Hp: 21775 + - Level: 208 + Hp: 21925 + - Level: 209 + Hp: 22075 + - Level: 210 + Hp: 22225 + - Level: 211 + Hp: 22375 + - Level: 212 + Hp: 22525 + - Level: 213 + Hp: 22675 + - Level: 214 + Hp: 22825 + - Level: 215 + Hp: 22975 + - Level: 216 + Hp: 23125 + - Level: 217 + Hp: 23275 + - Level: 218 + Hp: 23425 + - Level: 219 + Hp: 23575 + - Level: 220 + Hp: 23725 + - Level: 221 + Hp: 23875 + - Level: 222 + Hp: 24025 + - Level: 223 + Hp: 24175 + - Level: 224 + Hp: 24325 + - Level: 225 + Hp: 24475 + - Level: 226 + Hp: 24625 + - Level: 227 + Hp: 24775 + - Level: 228 + Hp: 24925 + - Level: 229 + Hp: 25075 + - Level: 230 + Hp: 25225 + - Level: 231 + Hp: 25375 + - Level: 232 + Hp: 25525 + - Level: 233 + Hp: 25675 + - Level: 234 + Hp: 25825 + - Level: 235 + Hp: 25975 + - Level: 236 + Hp: 26125 + - Level: 237 + Hp: 26275 + - Level: 238 + Hp: 26425 + - Level: 239 + Hp: 26575 + - Level: 240 + Hp: 26725 + - Level: 241 + Hp: 26875 + - Level: 242 + Hp: 27025 + - Level: 243 + Hp: 27175 + - Level: 244 + Hp: 27325 + - Level: 245 + Hp: 27475 + - Level: 246 + Hp: 27625 + - Level: 247 + Hp: 27775 + - Level: 248 + Hp: 27925 + - Level: 249 + Hp: 28075 + - Level: 250 + Hp: 28225 + - Jobs: + Arch_Mage: true + BaseHp: + - Level: 200 + Hp: 15625 + - Level: 201 + Hp: 15800 + - Level: 202 + Hp: 15975 + - Level: 203 + Hp: 16150 + - Level: 204 + Hp: 16325 + - Level: 205 + Hp: 16500 + - Level: 206 + Hp: 16675 + - Level: 207 + Hp: 16850 + - Level: 208 + Hp: 17025 + - Level: 209 + Hp: 17200 + - Level: 210 + Hp: 17375 + - Level: 211 + Hp: 17550 + - Level: 212 + Hp: 17725 + - Level: 213 + Hp: 17900 + - Level: 214 + Hp: 18075 + - Level: 215 + Hp: 18250 + - Level: 216 + Hp: 18425 + - Level: 217 + Hp: 18600 + - Level: 218 + Hp: 18775 + - Level: 219 + Hp: 18950 + - Level: 220 + Hp: 19125 + - Level: 221 + Hp: 19300 + - Level: 222 + Hp: 19475 + - Level: 223 + Hp: 19650 + - Level: 224 + Hp: 19825 + - Level: 225 + Hp: 20000 + - Level: 226 + Hp: 20175 + - Level: 227 + Hp: 20350 + - Level: 228 + Hp: 20525 + - Level: 229 + Hp: 20700 + - Level: 230 + Hp: 20875 + - Level: 231 + Hp: 21050 + - Level: 232 + Hp: 21225 + - Level: 233 + Hp: 21400 + - Level: 234 + Hp: 21575 + - Level: 235 + Hp: 21750 + - Level: 236 + Hp: 21925 + - Level: 237 + Hp: 22100 + - Level: 238 + Hp: 22275 + - Level: 239 + Hp: 22450 + - Level: 240 + Hp: 22625 + - Level: 241 + Hp: 22800 + - Level: 242 + Hp: 22975 + - Level: 243 + Hp: 23150 + - Level: 244 + Hp: 23325 + - Level: 245 + Hp: 23500 + - Level: 246 + Hp: 23675 + - Level: 247 + Hp: 23850 + - Level: 248 + Hp: 24025 + - Level: 249 + Hp: 24200 + - Level: 250 + Hp: 24375 + - Jobs: + Cardinal: true + BaseHp: + - Level: 200 + Hp: 16010 + - Level: 201 + Hp: 16185 + - Level: 202 + Hp: 16360 + - Level: 203 + Hp: 16535 + - Level: 204 + Hp: 16710 + - Level: 205 + Hp: 16885 + - Level: 206 + Hp: 17060 + - Level: 207 + Hp: 17235 + - Level: 208 + Hp: 17410 + - Level: 209 + Hp: 17585 + - Level: 210 + Hp: 17760 + - Level: 211 + Hp: 17935 + - Level: 212 + Hp: 18110 + - Level: 213 + Hp: 18285 + - Level: 214 + Hp: 18460 + - Level: 215 + Hp: 18635 + - Level: 216 + Hp: 18810 + - Level: 217 + Hp: 18985 + - Level: 218 + Hp: 19160 + - Level: 219 + Hp: 19335 + - Level: 220 + Hp: 19510 + - Level: 221 + Hp: 19685 + - Level: 222 + Hp: 19860 + - Level: 223 + Hp: 20035 + - Level: 224 + Hp: 20210 + - Level: 225 + Hp: 20385 + - Level: 226 + Hp: 20560 + - Level: 227 + Hp: 20735 + - Level: 228 + Hp: 20910 + - Level: 229 + Hp: 21085 + - Level: 230 + Hp: 21260 + - Level: 231 + Hp: 21435 + - Level: 232 + Hp: 21610 + - Level: 233 + Hp: 21785 + - Level: 234 + Hp: 21960 + - Level: 235 + Hp: 22135 + - Level: 236 + Hp: 22310 + - Level: 237 + Hp: 22485 + - Level: 238 + Hp: 22660 + - Level: 239 + Hp: 22835 + - Level: 240 + Hp: 23010 + - Level: 241 + Hp: 23185 + - Level: 242 + Hp: 23360 + - Level: 243 + Hp: 23535 + - Level: 244 + Hp: 23710 + - Level: 245 + Hp: 23885 + - Level: 246 + Hp: 24060 + - Level: 247 + Hp: 24235 + - Level: 248 + Hp: 24410 + - Level: 249 + Hp: 24585 + - Level: 250 + Hp: 24760 + - Jobs: + Windhawk: true + Windhawk2: true + BaseHp: + - Level: 200 + Hp: 17685 + - Level: 201 + Hp: 17835 + - Level: 202 + Hp: 17985 + - Level: 203 + Hp: 18135 + - Level: 204 + Hp: 18285 + - Level: 205 + Hp: 18435 + - Level: 206 + Hp: 18585 + - Level: 207 + Hp: 18735 + - Level: 208 + Hp: 18885 + - Level: 209 + Hp: 19035 + - Level: 210 + Hp: 19185 + - Level: 211 + Hp: 19335 + - Level: 212 + Hp: 19485 + - Level: 213 + Hp: 19635 + - Level: 214 + Hp: 19785 + - Level: 215 + Hp: 19935 + - Level: 216 + Hp: 20085 + - Level: 217 + Hp: 20235 + - Level: 218 + Hp: 20385 + - Level: 219 + Hp: 20535 + - Level: 220 + Hp: 20685 + - Level: 221 + Hp: 20835 + - Level: 222 + Hp: 20985 + - Level: 223 + Hp: 21135 + - Level: 224 + Hp: 21285 + - Level: 225 + Hp: 21435 + - Level: 226 + Hp: 21585 + - Level: 227 + Hp: 21735 + - Level: 228 + Hp: 21885 + - Level: 229 + Hp: 22035 + - Level: 230 + Hp: 22185 + - Level: 231 + Hp: 22335 + - Level: 232 + Hp: 22485 + - Level: 233 + Hp: 22635 + - Level: 234 + Hp: 22785 + - Level: 235 + Hp: 22935 + - Level: 236 + Hp: 23085 + - Level: 237 + Hp: 23235 + - Level: 238 + Hp: 23385 + - Level: 239 + Hp: 23535 + - Level: 240 + Hp: 23685 + - Level: 241 + Hp: 23835 + - Level: 242 + Hp: 23985 + - Level: 243 + Hp: 24135 + - Level: 244 + Hp: 24285 + - Level: 245 + Hp: 24435 + - Level: 246 + Hp: 24585 + - Level: 247 + Hp: 24735 + - Level: 248 + Hp: 24885 + - Level: 249 + Hp: 25035 + - Level: 250 + Hp: 25185 + - Jobs: + Imperial_Guard: true + Imperial_Guard2: true + BaseHp: + - Level: 200 + Hp: 21755 + - Level: 201 + Hp: 21930 + - Level: 202 + Hp: 22105 + - Level: 203 + Hp: 22280 + - Level: 204 + Hp: 22455 + - Level: 205 + Hp: 22630 + - Level: 206 + Hp: 22805 + - Level: 207 + Hp: 22980 + - Level: 208 + Hp: 23155 + - Level: 209 + Hp: 23330 + - Level: 210 + Hp: 23505 + - Level: 211 + Hp: 23680 + - Level: 212 + Hp: 23855 + - Level: 213 + Hp: 24030 + - Level: 214 + Hp: 24205 + - Level: 215 + Hp: 24380 + - Level: 216 + Hp: 24555 + - Level: 217 + Hp: 24730 + - Level: 218 + Hp: 24905 + - Level: 219 + Hp: 25080 + - Level: 220 + Hp: 25255 + - Level: 221 + Hp: 25430 + - Level: 222 + Hp: 25605 + - Level: 223 + Hp: 25780 + - Level: 224 + Hp: 25955 + - Level: 225 + Hp: 26130 + - Level: 226 + Hp: 26305 + - Level: 227 + Hp: 26480 + - Level: 228 + Hp: 26655 + - Level: 229 + Hp: 26830 + - Level: 230 + Hp: 27005 + - Level: 231 + Hp: 27180 + - Level: 232 + Hp: 27355 + - Level: 233 + Hp: 27530 + - Level: 234 + Hp: 27705 + - Level: 235 + Hp: 27880 + - Level: 236 + Hp: 28055 + - Level: 237 + Hp: 28230 + - Level: 238 + Hp: 28405 + - Level: 239 + Hp: 28580 + - Level: 240 + Hp: 28755 + - Level: 241 + Hp: 28930 + - Level: 242 + Hp: 29105 + - Level: 243 + Hp: 29280 + - Level: 244 + Hp: 29455 + - Level: 245 + Hp: 29630 + - Level: 246 + Hp: 29805 + - Level: 247 + Hp: 29980 + - Level: 248 + Hp: 30155 + - Level: 249 + Hp: 30330 + - Level: 250 + Hp: 30505 + - Jobs: + Biolo: true + BaseHp: + - Level: 200 + Hp: 16875 + - Level: 201 + Hp: 17050 + - Level: 202 + Hp: 17225 + - Level: 203 + Hp: 17400 + - Level: 204 + Hp: 17575 + - Level: 205 + Hp: 17750 + - Level: 206 + Hp: 17925 + - Level: 207 + Hp: 18100 + - Level: 208 + Hp: 18275 + - Level: 209 + Hp: 18450 + - Level: 210 + Hp: 18625 + - Level: 211 + Hp: 18800 + - Level: 212 + Hp: 18975 + - Level: 213 + Hp: 19150 + - Level: 214 + Hp: 19325 + - Level: 215 + Hp: 19500 + - Level: 216 + Hp: 19675 + - Level: 217 + Hp: 19850 + - Level: 218 + Hp: 20025 + - Level: 219 + Hp: 20200 + - Level: 220 + Hp: 20375 + - Level: 221 + Hp: 20550 + - Level: 222 + Hp: 20725 + - Level: 223 + Hp: 20900 + - Level: 224 + Hp: 21075 + - Level: 225 + Hp: 21250 + - Level: 226 + Hp: 21425 + - Level: 227 + Hp: 21600 + - Level: 228 + Hp: 21775 + - Level: 229 + Hp: 21950 + - Level: 230 + Hp: 22125 + - Level: 231 + Hp: 22300 + - Level: 232 + Hp: 22475 + - Level: 233 + Hp: 22650 + - Level: 234 + Hp: 22825 + - Level: 235 + Hp: 23000 + - Level: 236 + Hp: 23175 + - Level: 237 + Hp: 23350 + - Level: 238 + Hp: 23525 + - Level: 239 + Hp: 23700 + - Level: 240 + Hp: 23875 + - Level: 241 + Hp: 24050 + - Level: 242 + Hp: 24225 + - Level: 243 + Hp: 24400 + - Level: 244 + Hp: 24575 + - Level: 245 + Hp: 24750 + - Level: 246 + Hp: 24925 + - Level: 247 + Hp: 25100 + - Level: 248 + Hp: 25275 + - Level: 249 + Hp: 25450 + - Level: 250 + Hp: 25625 + - Jobs: + Abyss_Chaser: true + BaseHp: + - Level: 200 + Hp: 18695 + - Level: 201 + Hp: 18810 + - Level: 202 + Hp: 18925 + - Level: 203 + Hp: 19040 + - Level: 204 + Hp: 19155 + - Level: 205 + Hp: 19270 + - Level: 206 + Hp: 19385 + - Level: 207 + Hp: 19500 + - Level: 208 + Hp: 19615 + - Level: 209 + Hp: 19730 + - Level: 210 + Hp: 19845 + - Level: 211 + Hp: 19960 + - Level: 212 + Hp: 20075 + - Level: 213 + Hp: 20190 + - Level: 214 + Hp: 20305 + - Level: 215 + Hp: 20420 + - Level: 216 + Hp: 20535 + - Level: 217 + Hp: 20650 + - Level: 218 + Hp: 20765 + - Level: 219 + Hp: 20880 + - Level: 220 + Hp: 20995 + - Level: 221 + Hp: 21110 + - Level: 222 + Hp: 21225 + - Level: 223 + Hp: 21340 + - Level: 224 + Hp: 21455 + - Level: 225 + Hp: 21570 + - Level: 226 + Hp: 21685 + - Level: 227 + Hp: 21800 + - Level: 228 + Hp: 21915 + - Level: 229 + Hp: 22030 + - Level: 230 + Hp: 22145 + - Level: 231 + Hp: 22260 + - Level: 232 + Hp: 22375 + - Level: 233 + Hp: 22490 + - Level: 234 + Hp: 22605 + - Level: 235 + Hp: 22720 + - Level: 236 + Hp: 22835 + - Level: 237 + Hp: 22950 + - Level: 238 + Hp: 23065 + - Level: 239 + Hp: 23180 + - Level: 240 + Hp: 23295 + - Level: 241 + Hp: 23410 + - Level: 242 + Hp: 23525 + - Level: 243 + Hp: 23640 + - Level: 244 + Hp: 23755 + - Level: 245 + Hp: 23870 + - Level: 246 + Hp: 23985 + - Level: 247 + Hp: 24100 + - Level: 248 + Hp: 24215 + - Level: 249 + Hp: 24330 + - Level: 250 + Hp: 24445 + - Jobs: + Elemental_Master: true + BaseHp: + - Level: 200 + Hp: 15210 + - Level: 201 + Hp: 15345 + - Level: 202 + Hp: 15480 + - Level: 203 + Hp: 15615 + - Level: 204 + Hp: 15750 + - Level: 205 + Hp: 15885 + - Level: 206 + Hp: 16020 + - Level: 207 + Hp: 16155 + - Level: 208 + Hp: 16290 + - Level: 209 + Hp: 16425 + - Level: 210 + Hp: 16560 + - Level: 211 + Hp: 16695 + - Level: 212 + Hp: 16830 + - Level: 213 + Hp: 16965 + - Level: 214 + Hp: 17100 + - Level: 215 + Hp: 17235 + - Level: 216 + Hp: 17370 + - Level: 217 + Hp: 17505 + - Level: 218 + Hp: 17640 + - Level: 219 + Hp: 17775 + - Level: 220 + Hp: 17910 + - Level: 221 + Hp: 18045 + - Level: 222 + Hp: 18180 + - Level: 223 + Hp: 18315 + - Level: 224 + Hp: 18450 + - Level: 225 + Hp: 18585 + - Level: 226 + Hp: 18720 + - Level: 227 + Hp: 18855 + - Level: 228 + Hp: 18990 + - Level: 229 + Hp: 19125 + - Level: 230 + Hp: 19260 + - Level: 231 + Hp: 19395 + - Level: 232 + Hp: 19530 + - Level: 233 + Hp: 19665 + - Level: 234 + Hp: 19800 + - Level: 235 + Hp: 19935 + - Level: 236 + Hp: 20070 + - Level: 237 + Hp: 20205 + - Level: 238 + Hp: 20340 + - Level: 239 + Hp: 20475 + - Level: 240 + Hp: 20610 + - Level: 241 + Hp: 20745 + - Level: 242 + Hp: 20880 + - Level: 243 + Hp: 21015 + - Level: 244 + Hp: 21150 + - Level: 245 + Hp: 21285 + - Level: 246 + Hp: 21420 + - Level: 247 + Hp: 21555 + - Level: 248 + Hp: 21690 + - Level: 249 + Hp: 21825 + - Level: 250 + Hp: 21960 + - Jobs: + Inquisitor: true + BaseHp: + - Level: 200 + Hp: 18360 + - Level: 201 + Hp: 18515 + - Level: 202 + Hp: 18670 + - Level: 203 + Hp: 18825 + - Level: 204 + Hp: 18980 + - Level: 205 + Hp: 19135 + - Level: 206 + Hp: 19290 + - Level: 207 + Hp: 19445 + - Level: 208 + Hp: 19600 + - Level: 209 + Hp: 19755 + - Level: 210 + Hp: 19910 + - Level: 211 + Hp: 20065 + - Level: 212 + Hp: 20220 + - Level: 213 + Hp: 20375 + - Level: 214 + Hp: 20530 + - Level: 215 + Hp: 20685 + - Level: 216 + Hp: 20840 + - Level: 217 + Hp: 20995 + - Level: 218 + Hp: 21150 + - Level: 219 + Hp: 21305 + - Level: 220 + Hp: 21460 + - Level: 221 + Hp: 21615 + - Level: 222 + Hp: 21770 + - Level: 223 + Hp: 21925 + - Level: 224 + Hp: 22080 + - Level: 225 + Hp: 22235 + - Level: 226 + Hp: 22390 + - Level: 227 + Hp: 22545 + - Level: 228 + Hp: 22700 + - Level: 229 + Hp: 22855 + - Level: 230 + Hp: 23010 + - Level: 231 + Hp: 23165 + - Level: 232 + Hp: 23320 + - Level: 233 + Hp: 23475 + - Level: 234 + Hp: 23630 + - Level: 235 + Hp: 23785 + - Level: 236 + Hp: 23940 + - Level: 237 + Hp: 24095 + - Level: 238 + Hp: 24250 + - Level: 239 + Hp: 24405 + - Level: 240 + Hp: 24560 + - Level: 241 + Hp: 24715 + - Level: 242 + Hp: 24870 + - Level: 243 + Hp: 25025 + - Level: 244 + Hp: 25180 + - Level: 245 + Hp: 25335 + - Level: 246 + Hp: 25490 + - Level: 247 + Hp: 25645 + - Level: 248 + Hp: 25800 + - Level: 249 + Hp: 25955 + - Level: 250 + Hp: 26110 + - Jobs: + Troubadour: true + BaseHp: + - Level: 200 + Hp: 17680 + - Level: 201 + Hp: 17830 + - Level: 202 + Hp: 17980 + - Level: 203 + Hp: 18130 + - Level: 204 + Hp: 18280 + - Level: 205 + Hp: 18430 + - Level: 206 + Hp: 18580 + - Level: 207 + Hp: 18730 + - Level: 208 + Hp: 18880 + - Level: 209 + Hp: 19030 + - Level: 210 + Hp: 19180 + - Level: 211 + Hp: 19330 + - Level: 212 + Hp: 19480 + - Level: 213 + Hp: 19630 + - Level: 214 + Hp: 19780 + - Level: 215 + Hp: 19930 + - Level: 216 + Hp: 20080 + - Level: 217 + Hp: 20230 + - Level: 218 + Hp: 20380 + - Level: 219 + Hp: 20530 + - Level: 220 + Hp: 20680 + - Level: 221 + Hp: 20830 + - Level: 222 + Hp: 20980 + - Level: 223 + Hp: 21130 + - Level: 224 + Hp: 21280 + - Level: 225 + Hp: 21430 + - Level: 226 + Hp: 21580 + - Level: 227 + Hp: 21730 + - Level: 228 + Hp: 21880 + - Level: 229 + Hp: 22030 + - Level: 230 + Hp: 22180 + - Level: 231 + Hp: 22330 + - Level: 232 + Hp: 22480 + - Level: 233 + Hp: 22630 + - Level: 234 + Hp: 22780 + - Level: 235 + Hp: 22930 + - Level: 236 + Hp: 23080 + - Level: 237 + Hp: 23230 + - Level: 238 + Hp: 23380 + - Level: 239 + Hp: 23530 + - Level: 240 + Hp: 23680 + - Level: 241 + Hp: 23830 + - Level: 242 + Hp: 23980 + - Level: 243 + Hp: 24130 + - Level: 244 + Hp: 24280 + - Level: 245 + Hp: 24430 + - Level: 246 + Hp: 24580 + - Level: 247 + Hp: 24730 + - Level: 248 + Hp: 24880 + - Level: 249 + Hp: 25030 + - Level: 250 + Hp: 25180 + - Jobs: + Trouvere: true + BaseHp: + - Level: 200 + Hp: 17680 + - Level: 201 + Hp: 17830 + - Level: 202 + Hp: 17980 + - Level: 203 + Hp: 18130 + - Level: 204 + Hp: 18280 + - Level: 205 + Hp: 18430 + - Level: 206 + Hp: 18580 + - Level: 207 + Hp: 18730 + - Level: 208 + Hp: 18880 + - Level: 209 + Hp: 19030 + - Level: 210 + Hp: 19180 + - Level: 211 + Hp: 19330 + - Level: 212 + Hp: 19480 + - Level: 213 + Hp: 19630 + - Level: 214 + Hp: 19780 + - Level: 215 + Hp: 19930 + - Level: 216 + Hp: 20080 + - Level: 217 + Hp: 20230 + - Level: 218 + Hp: 20380 + - Level: 219 + Hp: 20530 + - Level: 220 + Hp: 20680 + - Level: 221 + Hp: 20830 + - Level: 222 + Hp: 20980 + - Level: 223 + Hp: 21130 + - Level: 224 + Hp: 21280 + - Level: 225 + Hp: 21430 + - Level: 226 + Hp: 21580 + - Level: 227 + Hp: 21730 + - Level: 228 + Hp: 21880 + - Level: 229 + Hp: 22030 + - Level: 230 + Hp: 22180 + - Level: 231 + Hp: 22330 + - Level: 232 + Hp: 22480 + - Level: 233 + Hp: 22630 + - Level: 234 + Hp: 22780 + - Level: 235 + Hp: 22930 + - Level: 236 + Hp: 23080 + - Level: 237 + Hp: 23230 + - Level: 238 + Hp: 23380 + - Level: 239 + Hp: 23530 + - Level: 240 + Hp: 23680 + - Level: 241 + Hp: 23830 + - Level: 242 + Hp: 23980 + - Level: 243 + Hp: 24130 + - Level: 244 + Hp: 24280 + - Level: 245 + Hp: 24430 + - Level: 246 + Hp: 24580 + - Level: 247 + Hp: 24730 + - Level: 248 + Hp: 24880 + - Level: 249 + Hp: 25030 + - Level: 250 + Hp: 25180 + - Jobs: + Sky_Emperor: true + Sky_Emperor2: true + BaseHp: + - Level: 200 + Hp: 10762 + - Level: 201 + Hp: 10824 + - Level: 202 + Hp: 10886 + - Level: 203 + Hp: 10948 + - Level: 204 + Hp: 11010 + - Level: 205 + Hp: 11072 + - Level: 206 + Hp: 11134 + - Level: 207 + Hp: 11196 + - Level: 208 + Hp: 11258 + - Level: 209 + Hp: 11320 + - Level: 210 + Hp: 11382 + - Level: 211 + Hp: 11444 + - Level: 212 + Hp: 11506 + - Level: 213 + Hp: 11568 + - Level: 214 + Hp: 11630 + - Level: 215 + Hp: 11692 + - Level: 216 + Hp: 11754 + - Level: 217 + Hp: 11816 + - Level: 218 + Hp: 11878 + - Level: 219 + Hp: 11940 + - Level: 220 + Hp: 12002 + - Level: 221 + Hp: 12064 + - Level: 222 + Hp: 12126 + - Level: 223 + Hp: 12188 + - Level: 224 + Hp: 12250 + - Level: 225 + Hp: 12312 + - Level: 226 + Hp: 12374 + - Level: 227 + Hp: 12436 + - Level: 228 + Hp: 12498 + - Level: 229 + Hp: 12560 + - Level: 230 + Hp: 12622 + - Level: 231 + Hp: 12684 + - Level: 232 + Hp: 12746 + - Level: 233 + Hp: 12808 + - Level: 234 + Hp: 12870 + - Level: 235 + Hp: 12932 + - Level: 236 + Hp: 12994 + - Level: 237 + Hp: 13056 + - Level: 238 + Hp: 13118 + - Level: 239 + Hp: 13180 + - Level: 240 + Hp: 13242 + - Level: 241 + Hp: 13304 + - Level: 242 + Hp: 13366 + - Level: 243 + Hp: 13428 + - Level: 244 + Hp: 13490 + - Level: 245 + Hp: 13552 + - Level: 246 + Hp: 13614 + - Level: 247 + Hp: 13676 + - Level: 248 + Hp: 13738 + - Level: 249 + Hp: 13800 + - Level: 250 + Hp: 13862 + - Jobs: + Soul_Ascetic: true + BaseHp: + - Level: 200 + Hp: 9805 + - Level: 201 + Hp: 9860 + - Level: 202 + Hp: 9915 + - Level: 203 + Hp: 9970 + - Level: 204 + Hp: 10025 + - Level: 205 + Hp: 10080 + - Level: 206 + Hp: 10135 + - Level: 207 + Hp: 10190 + - Level: 208 + Hp: 10245 + - Level: 209 + Hp: 10300 + - Level: 210 + Hp: 10355 + - Level: 211 + Hp: 10410 + - Level: 212 + Hp: 10465 + - Level: 213 + Hp: 10520 + - Level: 214 + Hp: 10575 + - Level: 215 + Hp: 10630 + - Level: 216 + Hp: 10685 + - Level: 217 + Hp: 10740 + - Level: 218 + Hp: 10795 + - Level: 219 + Hp: 10850 + - Level: 220 + Hp: 10905 + - Level: 221 + Hp: 10960 + - Level: 222 + Hp: 11015 + - Level: 223 + Hp: 11070 + - Level: 224 + Hp: 11125 + - Level: 225 + Hp: 11180 + - Level: 226 + Hp: 11235 + - Level: 227 + Hp: 11290 + - Level: 228 + Hp: 11345 + - Level: 229 + Hp: 11400 + - Level: 230 + Hp: 11455 + - Level: 231 + Hp: 11510 + - Level: 232 + Hp: 11565 + - Level: 233 + Hp: 11620 + - Level: 234 + Hp: 11675 + - Level: 235 + Hp: 11730 + - Level: 236 + Hp: 11785 + - Level: 237 + Hp: 11840 + - Level: 238 + Hp: 11895 + - Level: 239 + Hp: 11950 + - Level: 240 + Hp: 12005 + - Level: 241 + Hp: 12060 + - Level: 242 + Hp: 12115 + - Level: 243 + Hp: 12170 + - Level: 244 + Hp: 12225 + - Level: 245 + Hp: 12280 + - Level: 246 + Hp: 12335 + - Level: 247 + Hp: 12390 + - Level: 248 + Hp: 12445 + - Level: 249 + Hp: 12500 + - Level: 250 + Hp: 12555 + - Jobs: + Shinkiro: true + BaseHp: + - Level: 200 + Hp: 15205 + - Level: 201 + Hp: 15360 + - Level: 202 + Hp: 15515 + - Level: 203 + Hp: 15670 + - Level: 204 + Hp: 15825 + - Level: 205 + Hp: 15980 + - Level: 206 + Hp: 16135 + - Level: 207 + Hp: 16290 + - Level: 208 + Hp: 16445 + - Level: 209 + Hp: 16600 + - Level: 210 + Hp: 16755 + - Level: 211 + Hp: 16910 + - Level: 212 + Hp: 17065 + - Level: 213 + Hp: 17220 + - Level: 214 + Hp: 17375 + - Level: 215 + Hp: 17530 + - Level: 216 + Hp: 17685 + - Level: 217 + Hp: 17840 + - Level: 218 + Hp: 17995 + - Level: 219 + Hp: 18150 + - Level: 220 + Hp: 18305 + - Level: 221 + Hp: 18460 + - Level: 222 + Hp: 18615 + - Level: 223 + Hp: 18770 + - Level: 224 + Hp: 18925 + - Level: 225 + Hp: 19080 + - Level: 226 + Hp: 19235 + - Level: 227 + Hp: 19390 + - Level: 228 + Hp: 19545 + - Level: 229 + Hp: 19700 + - Level: 230 + Hp: 19855 + - Level: 231 + Hp: 20010 + - Level: 232 + Hp: 20165 + - Level: 233 + Hp: 20320 + - Level: 234 + Hp: 20475 + - Level: 235 + Hp: 20630 + - Level: 236 + Hp: 20785 + - Level: 237 + Hp: 20940 + - Level: 238 + Hp: 21095 + - Level: 239 + Hp: 21250 + - Level: 240 + Hp: 21405 + - Level: 241 + Hp: 21560 + - Level: 242 + Hp: 21715 + - Level: 243 + Hp: 21870 + - Level: 244 + Hp: 22025 + - Level: 245 + Hp: 22180 + - Level: 246 + Hp: 22335 + - Level: 247 + Hp: 22490 + - Level: 248 + Hp: 22645 + - Level: 249 + Hp: 22800 + - Level: 250 + Hp: 22955 + - Jobs: + Shiranui: true + BaseHp: + - Level: 200 + Hp: 14905 + - Level: 201 + Hp: 15060 + - Level: 202 + Hp: 15215 + - Level: 203 + Hp: 15370 + - Level: 204 + Hp: 15525 + - Level: 205 + Hp: 15680 + - Level: 206 + Hp: 15835 + - Level: 207 + Hp: 15990 + - Level: 208 + Hp: 16145 + - Level: 209 + Hp: 16300 + - Level: 210 + Hp: 16455 + - Level: 211 + Hp: 16610 + - Level: 212 + Hp: 16765 + - Level: 213 + Hp: 16920 + - Level: 214 + Hp: 17075 + - Level: 215 + Hp: 17230 + - Level: 216 + Hp: 17385 + - Level: 217 + Hp: 17540 + - Level: 218 + Hp: 17695 + - Level: 219 + Hp: 17850 + - Level: 220 + Hp: 18005 + - Level: 221 + Hp: 18160 + - Level: 222 + Hp: 18315 + - Level: 223 + Hp: 18470 + - Level: 224 + Hp: 18625 + - Level: 225 + Hp: 18780 + - Level: 226 + Hp: 18935 + - Level: 227 + Hp: 19090 + - Level: 228 + Hp: 19245 + - Level: 229 + Hp: 19400 + - Level: 230 + Hp: 19555 + - Level: 231 + Hp: 19710 + - Level: 232 + Hp: 19865 + - Level: 233 + Hp: 20020 + - Level: 234 + Hp: 20175 + - Level: 235 + Hp: 20330 + - Level: 236 + Hp: 20485 + - Level: 237 + Hp: 20640 + - Level: 238 + Hp: 20795 + - Level: 239 + Hp: 20950 + - Level: 240 + Hp: 21105 + - Level: 241 + Hp: 21260 + - Level: 242 + Hp: 21415 + - Level: 243 + Hp: 21570 + - Level: 244 + Hp: 21725 + - Level: 245 + Hp: 21880 + - Level: 246 + Hp: 22035 + - Level: 247 + Hp: 22190 + - Level: 248 + Hp: 22345 + - Level: 249 + Hp: 22500 + - Level: 250 + Hp: 22655 + - Jobs: + Night_Watch: true + BaseHp: + - Level: 200 + Hp: 19417 + - Level: 201 + Hp: 19558 + - Level: 202 + Hp: 19699 + - Level: 203 + Hp: 19840 + - Level: 204 + Hp: 19981 + - Level: 205 + Hp: 20122 + - Level: 206 + Hp: 20263 + - Level: 207 + Hp: 20404 + - Level: 208 + Hp: 20545 + - Level: 209 + Hp: 20686 + - Level: 210 + Hp: 20827 + - Level: 211 + Hp: 20968 + - Level: 212 + Hp: 21109 + - Level: 213 + Hp: 21250 + - Level: 214 + Hp: 21391 + - Level: 215 + Hp: 21532 + - Level: 216 + Hp: 21673 + - Level: 217 + Hp: 21814 + - Level: 218 + Hp: 21955 + - Level: 219 + Hp: 22096 + - Level: 220 + Hp: 22237 + - Level: 221 + Hp: 22378 + - Level: 222 + Hp: 22519 + - Level: 223 + Hp: 22660 + - Level: 224 + Hp: 22801 + - Level: 225 + Hp: 22942 + - Level: 226 + Hp: 23083 + - Level: 227 + Hp: 23224 + - Level: 228 + Hp: 23365 + - Level: 229 + Hp: 23506 + - Level: 230 + Hp: 23647 + - Level: 231 + Hp: 23788 + - Level: 232 + Hp: 23929 + - Level: 233 + Hp: 24070 + - Level: 234 + Hp: 24211 + - Level: 235 + Hp: 24352 + - Level: 236 + Hp: 24493 + - Level: 237 + Hp: 24634 + - Level: 238 + Hp: 24775 + - Level: 239 + Hp: 24916 + - Level: 240 + Hp: 25057 + - Level: 241 + Hp: 25198 + - Level: 242 + Hp: 25339 + - Level: 243 + Hp: 25480 + - Level: 244 + Hp: 25621 + - Level: 245 + Hp: 25762 + - Level: 246 + Hp: 25903 + - Level: 247 + Hp: 26044 + - Level: 248 + Hp: 26185 + - Level: 249 + Hp: 26326 + - Level: 250 + Hp: 26467 + - Jobs: + Hyper_Novice: true + BaseHp: + - Level: 200 + Hp: 5035 + - Level: 201 + Hp: 5040 + - Level: 202 + Hp: 5045 + - Level: 203 + Hp: 5050 + - Level: 204 + Hp: 5055 + - Level: 205 + Hp: 5060 + - Level: 206 + Hp: 5065 + - Level: 207 + Hp: 5070 + - Level: 208 + Hp: 5075 + - Level: 209 + Hp: 5080 + - Level: 210 + Hp: 5085 + - Level: 211 + Hp: 5090 + - Level: 212 + Hp: 5095 + - Level: 213 + Hp: 5100 + - Level: 214 + Hp: 5105 + - Level: 215 + Hp: 5110 + - Level: 216 + Hp: 5115 + - Level: 217 + Hp: 5120 + - Level: 218 + Hp: 5125 + - Level: 219 + Hp: 5130 + - Level: 220 + Hp: 5135 + - Level: 221 + Hp: 5140 + - Level: 222 + Hp: 5145 + - Level: 223 + Hp: 5150 + - Level: 224 + Hp: 5155 + - Level: 225 + Hp: 5160 + - Level: 226 + Hp: 5165 + - Level: 227 + Hp: 5170 + - Level: 228 + Hp: 5175 + - Level: 229 + Hp: 5180 + - Level: 230 + Hp: 5185 + - Level: 231 + Hp: 5190 + - Level: 232 + Hp: 5195 + - Level: 233 + Hp: 5200 + - Level: 234 + Hp: 5205 + - Level: 235 + Hp: 5210 + - Level: 236 + Hp: 5215 + - Level: 237 + Hp: 5220 + - Level: 238 + Hp: 5225 + - Level: 239 + Hp: 5230 + - Level: 240 + Hp: 5235 + - Level: 241 + Hp: 5240 + - Level: 242 + Hp: 5245 + - Level: 243 + Hp: 5250 + - Level: 244 + Hp: 5255 + - Level: 245 + Hp: 5260 + - Level: 246 + Hp: 5265 + - Level: 247 + Hp: 5270 + - Level: 248 + Hp: 5275 + - Level: 249 + Hp: 5280 + - Level: 250 + Hp: 5285 + - Jobs: + Spirit_Handler: true + BaseHp: + - Level: 200 + Hp: 22347 + - Level: 201 + Hp: 22539 + - Level: 202 + Hp: 22731 + - Level: 203 + Hp: 22923 + - Level: 204 + Hp: 23115 + - Level: 205 + Hp: 23307 + - Level: 206 + Hp: 23499 + - Level: 207 + Hp: 23691 + - Level: 208 + Hp: 23883 + - Level: 209 + Hp: 24075 + - Level: 210 + Hp: 24267 + - Level: 211 + Hp: 24459 + - Level: 212 + Hp: 24651 + - Level: 213 + Hp: 24843 + - Level: 214 + Hp: 25035 + - Level: 215 + Hp: 25227 + - Level: 216 + Hp: 25419 + - Level: 217 + Hp: 25611 + - Level: 218 + Hp: 25803 + - Level: 219 + Hp: 25995 + - Level: 220 + Hp: 26187 + - Level: 221 + Hp: 26379 + - Level: 222 + Hp: 26571 + - Level: 223 + Hp: 26763 + - Level: 224 + Hp: 26955 + - Level: 225 + Hp: 27147 + - Level: 226 + Hp: 27339 + - Level: 227 + Hp: 27531 + - Level: 228 + Hp: 27723 + - Level: 229 + Hp: 27915 + - Level: 230 + Hp: 28107 + - Level: 231 + Hp: 28299 + - Level: 232 + Hp: 28491 + - Level: 233 + Hp: 28683 + - Level: 234 + Hp: 28875 + - Level: 235 + Hp: 29067 + - Level: 236 + Hp: 29259 + - Level: 237 + Hp: 29451 + - Level: 238 + Hp: 29643 + - Level: 239 + Hp: 29835 + - Level: 240 + Hp: 30027 + - Level: 241 + Hp: 30219 + - Level: 242 + Hp: 30411 + - Level: 243 + Hp: 30603 + - Level: 244 + Hp: 30795 + - Level: 245 + Hp: 30987 + - Level: 246 + Hp: 31179 + - Level: 247 + Hp: 31371 + - Level: 248 + Hp: 31563 + - Level: 249 + Hp: 31755 + - Level: 250 + Hp: 31947 + - Jobs: + Dragon_Knight: true + Dragon_Knight2: true + BaseSp: + - Level: 200 + Sp: 1115 + - Level: 201 + Sp: 1121 + - Level: 202 + Sp: 1127 + - Level: 203 + Sp: 1133 + - Level: 204 + Sp: 1139 + - Level: 205 + Sp: 1145 + - Level: 206 + Sp: 1151 + - Level: 207 + Sp: 1157 + - Level: 208 + Sp: 1163 + - Level: 209 + Sp: 1169 + - Level: 210 + Sp: 1175 + - Level: 211 + Sp: 1181 + - Level: 212 + Sp: 1187 + - Level: 213 + Sp: 1193 + - Level: 214 + Sp: 1199 + - Level: 215 + Sp: 1205 + - Level: 216 + Sp: 1211 + - Level: 217 + Sp: 1217 + - Level: 218 + Sp: 1223 + - Level: 219 + Sp: 1229 + - Level: 220 + Sp: 1235 + - Level: 221 + Sp: 1241 + - Level: 222 + Sp: 1247 + - Level: 223 + Sp: 1253 + - Level: 224 + Sp: 1259 + - Level: 225 + Sp: 1265 + - Level: 226 + Sp: 1271 + - Level: 227 + Sp: 1277 + - Level: 228 + Sp: 1283 + - Level: 229 + Sp: 1289 + - Level: 230 + Sp: 1295 + - Level: 231 + Sp: 1301 + - Level: 232 + Sp: 1307 + - Level: 233 + Sp: 1313 + - Level: 234 + Sp: 1319 + - Level: 235 + Sp: 1325 + - Level: 236 + Sp: 1331 + - Level: 237 + Sp: 1337 + - Level: 238 + Sp: 1343 + - Level: 239 + Sp: 1349 + - Level: 240 + Sp: 1355 + - Level: 241 + Sp: 1361 + - Level: 242 + Sp: 1367 + - Level: 243 + Sp: 1373 + - Level: 244 + Sp: 1379 + - Level: 245 + Sp: 1385 + - Level: 246 + Sp: 1391 + - Level: 247 + Sp: 1397 + - Level: 248 + Sp: 1403 + - Level: 249 + Sp: 1409 + - Level: 250 + Sp: 1415 + - Jobs: + Meister: true + Meister2: true + BaseSp: + - Level: 200 + Sp: 1495 + - Level: 201 + Sp: 1502 + - Level: 202 + Sp: 1509 + - Level: 203 + Sp: 1516 + - Level: 204 + Sp: 1523 + - Level: 205 + Sp: 1530 + - Level: 206 + Sp: 1537 + - Level: 207 + Sp: 1544 + - Level: 208 + Sp: 1551 + - Level: 209 + Sp: 1558 + - Level: 210 + Sp: 1565 + - Level: 211 + Sp: 1572 + - Level: 212 + Sp: 1579 + - Level: 213 + Sp: 1586 + - Level: 214 + Sp: 1593 + - Level: 215 + Sp: 1600 + - Level: 216 + Sp: 1607 + - Level: 217 + Sp: 1614 + - Level: 218 + Sp: 1621 + - Level: 219 + Sp: 1628 + - Level: 220 + Sp: 1635 + - Level: 221 + Sp: 1642 + - Level: 222 + Sp: 1649 + - Level: 223 + Sp: 1656 + - Level: 224 + Sp: 1663 + - Level: 225 + Sp: 1670 + - Level: 226 + Sp: 1677 + - Level: 227 + Sp: 1684 + - Level: 228 + Sp: 1691 + - Level: 229 + Sp: 1698 + - Level: 230 + Sp: 1705 + - Level: 231 + Sp: 1712 + - Level: 232 + Sp: 1719 + - Level: 233 + Sp: 1726 + - Level: 234 + Sp: 1733 + - Level: 235 + Sp: 1740 + - Level: 236 + Sp: 1747 + - Level: 237 + Sp: 1754 + - Level: 238 + Sp: 1761 + - Level: 239 + Sp: 1768 + - Level: 240 + Sp: 1775 + - Level: 241 + Sp: 1782 + - Level: 242 + Sp: 1789 + - Level: 243 + Sp: 1796 + - Level: 244 + Sp: 1803 + - Level: 245 + Sp: 1810 + - Level: 246 + Sp: 1817 + - Level: 247 + Sp: 1824 + - Level: 248 + Sp: 1831 + - Level: 249 + Sp: 1838 + - Level: 250 + Sp: 1845 + - Jobs: + Shadow_Cross: true + BaseSp: + - Level: 200 + Sp: 1070 + - Level: 201 + Sp: 1077 + - Level: 202 + Sp: 1084 + - Level: 203 + Sp: 1091 + - Level: 204 + Sp: 1098 + - Level: 205 + Sp: 1105 + - Level: 206 + Sp: 1112 + - Level: 207 + Sp: 1119 + - Level: 208 + Sp: 1126 + - Level: 209 + Sp: 1133 + - Level: 210 + Sp: 1140 + - Level: 211 + Sp: 1147 + - Level: 212 + Sp: 1154 + - Level: 213 + Sp: 1161 + - Level: 214 + Sp: 1168 + - Level: 215 + Sp: 1175 + - Level: 216 + Sp: 1182 + - Level: 217 + Sp: 1189 + - Level: 218 + Sp: 1196 + - Level: 219 + Sp: 1203 + - Level: 220 + Sp: 1210 + - Level: 221 + Sp: 1217 + - Level: 222 + Sp: 1224 + - Level: 223 + Sp: 1231 + - Level: 224 + Sp: 1238 + - Level: 225 + Sp: 1245 + - Level: 226 + Sp: 1252 + - Level: 227 + Sp: 1259 + - Level: 228 + Sp: 1266 + - Level: 229 + Sp: 1273 + - Level: 230 + Sp: 1280 + - Level: 231 + Sp: 1287 + - Level: 232 + Sp: 1294 + - Level: 233 + Sp: 1301 + - Level: 234 + Sp: 1308 + - Level: 235 + Sp: 1315 + - Level: 236 + Sp: 1322 + - Level: 237 + Sp: 1329 + - Level: 238 + Sp: 1336 + - Level: 239 + Sp: 1343 + - Level: 240 + Sp: 1350 + - Level: 241 + Sp: 1357 + - Level: 242 + Sp: 1364 + - Level: 243 + Sp: 1371 + - Level: 244 + Sp: 1378 + - Level: 245 + Sp: 1385 + - Level: 246 + Sp: 1392 + - Level: 247 + Sp: 1399 + - Level: 248 + Sp: 1406 + - Level: 249 + Sp: 1413 + - Level: 250 + Sp: 1420 + - Jobs: + Arch_Mage: true + BaseSp: + - Level: 200 + Sp: 1915 + - Level: 201 + Sp: 1927 + - Level: 202 + Sp: 1939 + - Level: 203 + Sp: 1951 + - Level: 204 + Sp: 1963 + - Level: 205 + Sp: 1975 + - Level: 206 + Sp: 1987 + - Level: 207 + Sp: 1999 + - Level: 208 + Sp: 2011 + - Level: 209 + Sp: 2023 + - Level: 210 + Sp: 2035 + - Level: 211 + Sp: 2047 + - Level: 212 + Sp: 2059 + - Level: 213 + Sp: 2071 + - Level: 214 + Sp: 2083 + - Level: 215 + Sp: 2095 + - Level: 216 + Sp: 2107 + - Level: 217 + Sp: 2119 + - Level: 218 + Sp: 2131 + - Level: 219 + Sp: 2143 + - Level: 220 + Sp: 2155 + - Level: 221 + Sp: 2167 + - Level: 222 + Sp: 2179 + - Level: 223 + Sp: 2191 + - Level: 224 + Sp: 2203 + - Level: 225 + Sp: 2215 + - Level: 226 + Sp: 2227 + - Level: 227 + Sp: 2239 + - Level: 228 + Sp: 2251 + - Level: 229 + Sp: 2263 + - Level: 230 + Sp: 2275 + - Level: 231 + Sp: 2287 + - Level: 232 + Sp: 2299 + - Level: 233 + Sp: 2311 + - Level: 234 + Sp: 2323 + - Level: 235 + Sp: 2335 + - Level: 236 + Sp: 2347 + - Level: 237 + Sp: 2359 + - Level: 238 + Sp: 2371 + - Level: 239 + Sp: 2383 + - Level: 240 + Sp: 2395 + - Level: 241 + Sp: 2407 + - Level: 242 + Sp: 2419 + - Level: 243 + Sp: 2431 + - Level: 244 + Sp: 2443 + - Level: 245 + Sp: 2455 + - Level: 246 + Sp: 2467 + - Level: 247 + Sp: 2479 + - Level: 248 + Sp: 2491 + - Level: 249 + Sp: 2503 + - Level: 250 + Sp: 2515 + - Jobs: + Cardinal: true + BaseSp: + - Level: 200 + Sp: 1915 + - Level: 201 + Sp: 1926 + - Level: 202 + Sp: 1937 + - Level: 203 + Sp: 1948 + - Level: 204 + Sp: 1959 + - Level: 205 + Sp: 1970 + - Level: 206 + Sp: 1981 + - Level: 207 + Sp: 1992 + - Level: 208 + Sp: 2003 + - Level: 209 + Sp: 2014 + - Level: 210 + Sp: 2025 + - Level: 211 + Sp: 2036 + - Level: 212 + Sp: 2047 + - Level: 213 + Sp: 2058 + - Level: 214 + Sp: 2069 + - Level: 215 + Sp: 2080 + - Level: 216 + Sp: 2091 + - Level: 217 + Sp: 2102 + - Level: 218 + Sp: 2113 + - Level: 219 + Sp: 2124 + - Level: 220 + Sp: 2135 + - Level: 221 + Sp: 2146 + - Level: 222 + Sp: 2157 + - Level: 223 + Sp: 2168 + - Level: 224 + Sp: 2179 + - Level: 225 + Sp: 2190 + - Level: 226 + Sp: 2201 + - Level: 227 + Sp: 2212 + - Level: 228 + Sp: 2223 + - Level: 229 + Sp: 2234 + - Level: 230 + Sp: 2245 + - Level: 231 + Sp: 2256 + - Level: 232 + Sp: 2267 + - Level: 233 + Sp: 2278 + - Level: 234 + Sp: 2289 + - Level: 235 + Sp: 2300 + - Level: 236 + Sp: 2311 + - Level: 237 + Sp: 2322 + - Level: 238 + Sp: 2333 + - Level: 239 + Sp: 2344 + - Level: 240 + Sp: 2355 + - Level: 241 + Sp: 2366 + - Level: 242 + Sp: 2377 + - Level: 243 + Sp: 2388 + - Level: 244 + Sp: 2399 + - Level: 245 + Sp: 2410 + - Level: 246 + Sp: 2421 + - Level: 247 + Sp: 2432 + - Level: 248 + Sp: 2443 + - Level: 249 + Sp: 2454 + - Level: 250 + Sp: 2465 + - Jobs: + Windhawk: true + Windhawk2: true + BaseSp: + - Level: 200 + Sp: 1050 + - Level: 201 + Sp: 1057 + - Level: 202 + Sp: 1064 + - Level: 203 + Sp: 1071 + - Level: 204 + Sp: 1078 + - Level: 205 + Sp: 1085 + - Level: 206 + Sp: 1092 + - Level: 207 + Sp: 1099 + - Level: 208 + Sp: 1106 + - Level: 209 + Sp: 1113 + - Level: 210 + Sp: 1120 + - Level: 211 + Sp: 1127 + - Level: 212 + Sp: 1134 + - Level: 213 + Sp: 1141 + - Level: 214 + Sp: 1148 + - Level: 215 + Sp: 1155 + - Level: 216 + Sp: 1162 + - Level: 217 + Sp: 1169 + - Level: 218 + Sp: 1176 + - Level: 219 + Sp: 1183 + - Level: 220 + Sp: 1190 + - Level: 221 + Sp: 1197 + - Level: 222 + Sp: 1204 + - Level: 223 + Sp: 1211 + - Level: 224 + Sp: 1218 + - Level: 225 + Sp: 1225 + - Level: 226 + Sp: 1232 + - Level: 227 + Sp: 1239 + - Level: 228 + Sp: 1246 + - Level: 229 + Sp: 1253 + - Level: 230 + Sp: 1260 + - Level: 231 + Sp: 1267 + - Level: 232 + Sp: 1274 + - Level: 233 + Sp: 1281 + - Level: 234 + Sp: 1288 + - Level: 235 + Sp: 1295 + - Level: 236 + Sp: 1302 + - Level: 237 + Sp: 1309 + - Level: 238 + Sp: 1316 + - Level: 239 + Sp: 1323 + - Level: 240 + Sp: 1330 + - Level: 241 + Sp: 1337 + - Level: 242 + Sp: 1344 + - Level: 243 + Sp: 1351 + - Level: 244 + Sp: 1358 + - Level: 245 + Sp: 1365 + - Level: 246 + Sp: 1372 + - Level: 247 + Sp: 1379 + - Level: 248 + Sp: 1386 + - Level: 249 + Sp: 1393 + - Level: 250 + Sp: 1400 + - Jobs: + Imperial_Guard: true + Imperial_Guard2: true + BaseSp: + - Level: 200 + Sp: 1495 + - Level: 201 + Sp: 1502 + - Level: 202 + Sp: 1509 + - Level: 203 + Sp: 1516 + - Level: 204 + Sp: 1523 + - Level: 205 + Sp: 1530 + - Level: 206 + Sp: 1537 + - Level: 207 + Sp: 1544 + - Level: 208 + Sp: 1551 + - Level: 209 + Sp: 1558 + - Level: 210 + Sp: 1565 + - Level: 211 + Sp: 1572 + - Level: 212 + Sp: 1579 + - Level: 213 + Sp: 1586 + - Level: 214 + Sp: 1593 + - Level: 215 + Sp: 1600 + - Level: 216 + Sp: 1607 + - Level: 217 + Sp: 1614 + - Level: 218 + Sp: 1621 + - Level: 219 + Sp: 1628 + - Level: 220 + Sp: 1635 + - Level: 221 + Sp: 1642 + - Level: 222 + Sp: 1649 + - Level: 223 + Sp: 1656 + - Level: 224 + Sp: 1663 + - Level: 225 + Sp: 1670 + - Level: 226 + Sp: 1677 + - Level: 227 + Sp: 1684 + - Level: 228 + Sp: 1691 + - Level: 229 + Sp: 1698 + - Level: 230 + Sp: 1705 + - Level: 231 + Sp: 1712 + - Level: 232 + Sp: 1719 + - Level: 233 + Sp: 1726 + - Level: 234 + Sp: 1733 + - Level: 235 + Sp: 1740 + - Level: 236 + Sp: 1747 + - Level: 237 + Sp: 1754 + - Level: 238 + Sp: 1761 + - Level: 239 + Sp: 1768 + - Level: 240 + Sp: 1775 + - Level: 241 + Sp: 1782 + - Level: 242 + Sp: 1789 + - Level: 243 + Sp: 1796 + - Level: 244 + Sp: 1803 + - Level: 245 + Sp: 1810 + - Level: 246 + Sp: 1817 + - Level: 247 + Sp: 1824 + - Level: 248 + Sp: 1831 + - Level: 249 + Sp: 1838 + - Level: 250 + Sp: 1845 + - Jobs: + Biolo: true + BaseSp: + - Level: 200 + Sp: 1915 + - Level: 201 + Sp: 1927 + - Level: 202 + Sp: 1939 + - Level: 203 + Sp: 1951 + - Level: 204 + Sp: 1963 + - Level: 205 + Sp: 1975 + - Level: 206 + Sp: 1987 + - Level: 207 + Sp: 1999 + - Level: 208 + Sp: 2011 + - Level: 209 + Sp: 2023 + - Level: 210 + Sp: 2035 + - Level: 211 + Sp: 2047 + - Level: 212 + Sp: 2059 + - Level: 213 + Sp: 2071 + - Level: 214 + Sp: 2083 + - Level: 215 + Sp: 2095 + - Level: 216 + Sp: 2107 + - Level: 217 + Sp: 2119 + - Level: 218 + Sp: 2131 + - Level: 219 + Sp: 2143 + - Level: 220 + Sp: 2155 + - Level: 221 + Sp: 2167 + - Level: 222 + Sp: 2179 + - Level: 223 + Sp: 2191 + - Level: 224 + Sp: 2203 + - Level: 225 + Sp: 2215 + - Level: 226 + Sp: 2227 + - Level: 227 + Sp: 2239 + - Level: 228 + Sp: 2251 + - Level: 229 + Sp: 2263 + - Level: 230 + Sp: 2275 + - Level: 231 + Sp: 2287 + - Level: 232 + Sp: 2299 + - Level: 233 + Sp: 2311 + - Level: 234 + Sp: 2323 + - Level: 235 + Sp: 2335 + - Level: 236 + Sp: 2347 + - Level: 237 + Sp: 2359 + - Level: 238 + Sp: 2371 + - Level: 239 + Sp: 2383 + - Level: 240 + Sp: 2395 + - Level: 241 + Sp: 2407 + - Level: 242 + Sp: 2419 + - Level: 243 + Sp: 2431 + - Level: 244 + Sp: 2443 + - Level: 245 + Sp: 2455 + - Level: 246 + Sp: 2467 + - Level: 247 + Sp: 2479 + - Level: 248 + Sp: 2491 + - Level: 249 + Sp: 2503 + - Level: 250 + Sp: 2515 + - Jobs: + Abyss_Chaser: true + BaseSp: + - Level: 200 + Sp: 915 + - Level: 201 + Sp: 922 + - Level: 202 + Sp: 929 + - Level: 203 + Sp: 936 + - Level: 204 + Sp: 943 + - Level: 205 + Sp: 950 + - Level: 206 + Sp: 957 + - Level: 207 + Sp: 964 + - Level: 208 + Sp: 971 + - Level: 209 + Sp: 978 + - Level: 210 + Sp: 985 + - Level: 211 + Sp: 992 + - Level: 212 + Sp: 999 + - Level: 213 + Sp: 1006 + - Level: 214 + Sp: 1013 + - Level: 215 + Sp: 1020 + - Level: 216 + Sp: 1027 + - Level: 217 + Sp: 1034 + - Level: 218 + Sp: 1041 + - Level: 219 + Sp: 1048 + - Level: 220 + Sp: 1055 + - Level: 221 + Sp: 1062 + - Level: 222 + Sp: 1069 + - Level: 223 + Sp: 1076 + - Level: 224 + Sp: 1083 + - Level: 225 + Sp: 1090 + - Level: 226 + Sp: 1097 + - Level: 227 + Sp: 1104 + - Level: 228 + Sp: 1111 + - Level: 229 + Sp: 1118 + - Level: 230 + Sp: 1125 + - Level: 231 + Sp: 1132 + - Level: 232 + Sp: 1139 + - Level: 233 + Sp: 1146 + - Level: 234 + Sp: 1153 + - Level: 235 + Sp: 1160 + - Level: 236 + Sp: 1167 + - Level: 237 + Sp: 1174 + - Level: 238 + Sp: 1181 + - Level: 239 + Sp: 1188 + - Level: 240 + Sp: 1195 + - Level: 241 + Sp: 1202 + - Level: 242 + Sp: 1209 + - Level: 243 + Sp: 1216 + - Level: 244 + Sp: 1223 + - Level: 245 + Sp: 1230 + - Level: 246 + Sp: 1237 + - Level: 247 + Sp: 1244 + - Level: 248 + Sp: 1251 + - Level: 249 + Sp: 1258 + - Level: 250 + Sp: 1265 + - Jobs: + Elemental_Master: true + BaseSp: + - Level: 200 + Sp: 1915 + - Level: 201 + Sp: 1927 + - Level: 202 + Sp: 1939 + - Level: 203 + Sp: 1951 + - Level: 204 + Sp: 1963 + - Level: 205 + Sp: 1975 + - Level: 206 + Sp: 1987 + - Level: 207 + Sp: 1999 + - Level: 208 + Sp: 2011 + - Level: 209 + Sp: 2023 + - Level: 210 + Sp: 2035 + - Level: 211 + Sp: 2047 + - Level: 212 + Sp: 2059 + - Level: 213 + Sp: 2071 + - Level: 214 + Sp: 2083 + - Level: 215 + Sp: 2095 + - Level: 216 + Sp: 2107 + - Level: 217 + Sp: 2119 + - Level: 218 + Sp: 2131 + - Level: 219 + Sp: 2143 + - Level: 220 + Sp: 2155 + - Level: 221 + Sp: 2167 + - Level: 222 + Sp: 2179 + - Level: 223 + Sp: 2191 + - Level: 224 + Sp: 2203 + - Level: 225 + Sp: 2215 + - Level: 226 + Sp: 2227 + - Level: 227 + Sp: 2239 + - Level: 228 + Sp: 2251 + - Level: 229 + Sp: 2263 + - Level: 230 + Sp: 2275 + - Level: 231 + Sp: 2287 + - Level: 232 + Sp: 2299 + - Level: 233 + Sp: 2311 + - Level: 234 + Sp: 2323 + - Level: 235 + Sp: 2335 + - Level: 236 + Sp: 2347 + - Level: 237 + Sp: 2359 + - Level: 238 + Sp: 2371 + - Level: 239 + Sp: 2383 + - Level: 240 + Sp: 2395 + - Level: 241 + Sp: 2407 + - Level: 242 + Sp: 2419 + - Level: 243 + Sp: 2431 + - Level: 244 + Sp: 2443 + - Level: 245 + Sp: 2455 + - Level: 246 + Sp: 2467 + - Level: 247 + Sp: 2479 + - Level: 248 + Sp: 2491 + - Level: 249 + Sp: 2503 + - Level: 250 + Sp: 2515 + - Jobs: + Inquisitor: true + BaseSp: + - Level: 200 + Sp: 915 + - Level: 201 + Sp: 922 + - Level: 202 + Sp: 929 + - Level: 203 + Sp: 936 + - Level: 204 + Sp: 943 + - Level: 205 + Sp: 950 + - Level: 206 + Sp: 957 + - Level: 207 + Sp: 964 + - Level: 208 + Sp: 971 + - Level: 209 + Sp: 978 + - Level: 210 + Sp: 985 + - Level: 211 + Sp: 992 + - Level: 212 + Sp: 999 + - Level: 213 + Sp: 1006 + - Level: 214 + Sp: 1013 + - Level: 215 + Sp: 1020 + - Level: 216 + Sp: 1027 + - Level: 217 + Sp: 1034 + - Level: 218 + Sp: 1041 + - Level: 219 + Sp: 1048 + - Level: 220 + Sp: 1055 + - Level: 221 + Sp: 1062 + - Level: 222 + Sp: 1069 + - Level: 223 + Sp: 1076 + - Level: 224 + Sp: 1083 + - Level: 225 + Sp: 1090 + - Level: 226 + Sp: 1097 + - Level: 227 + Sp: 1104 + - Level: 228 + Sp: 1111 + - Level: 229 + Sp: 1118 + - Level: 230 + Sp: 1125 + - Level: 231 + Sp: 1132 + - Level: 232 + Sp: 1139 + - Level: 233 + Sp: 1146 + - Level: 234 + Sp: 1153 + - Level: 235 + Sp: 1160 + - Level: 236 + Sp: 1167 + - Level: 237 + Sp: 1174 + - Level: 238 + Sp: 1181 + - Level: 239 + Sp: 1188 + - Level: 240 + Sp: 1195 + - Level: 241 + Sp: 1202 + - Level: 242 + Sp: 1209 + - Level: 243 + Sp: 1216 + - Level: 244 + Sp: 1223 + - Level: 245 + Sp: 1230 + - Level: 246 + Sp: 1237 + - Level: 247 + Sp: 1244 + - Level: 248 + Sp: 1251 + - Level: 249 + Sp: 1258 + - Level: 250 + Sp: 1265 + - Jobs: + Troubadour: true + BaseSp: + - Level: 200 + Sp: 1115 + - Level: 201 + Sp: 1122 + - Level: 202 + Sp: 1129 + - Level: 203 + Sp: 1136 + - Level: 204 + Sp: 1143 + - Level: 205 + Sp: 1150 + - Level: 206 + Sp: 1157 + - Level: 207 + Sp: 1164 + - Level: 208 + Sp: 1171 + - Level: 209 + Sp: 1178 + - Level: 210 + Sp: 1185 + - Level: 211 + Sp: 1192 + - Level: 212 + Sp: 1199 + - Level: 213 + Sp: 1206 + - Level: 214 + Sp: 1213 + - Level: 215 + Sp: 1220 + - Level: 216 + Sp: 1227 + - Level: 217 + Sp: 1234 + - Level: 218 + Sp: 1241 + - Level: 219 + Sp: 1248 + - Level: 220 + Sp: 1255 + - Level: 221 + Sp: 1262 + - Level: 222 + Sp: 1269 + - Level: 223 + Sp: 1276 + - Level: 224 + Sp: 1283 + - Level: 225 + Sp: 1290 + - Level: 226 + Sp: 1297 + - Level: 227 + Sp: 1304 + - Level: 228 + Sp: 1311 + - Level: 229 + Sp: 1318 + - Level: 230 + Sp: 1325 + - Level: 231 + Sp: 1332 + - Level: 232 + Sp: 1339 + - Level: 233 + Sp: 1346 + - Level: 234 + Sp: 1353 + - Level: 235 + Sp: 1360 + - Level: 236 + Sp: 1367 + - Level: 237 + Sp: 1374 + - Level: 238 + Sp: 1381 + - Level: 239 + Sp: 1388 + - Level: 240 + Sp: 1395 + - Level: 241 + Sp: 1402 + - Level: 242 + Sp: 1409 + - Level: 243 + Sp: 1416 + - Level: 244 + Sp: 1423 + - Level: 245 + Sp: 1430 + - Level: 246 + Sp: 1437 + - Level: 247 + Sp: 1444 + - Level: 248 + Sp: 1451 + - Level: 249 + Sp: 1458 + - Level: 250 + Sp: 1465 + - Jobs: + Trouvere: true + BaseSp: + - Level: 200 + Sp: 1115 + - Level: 201 + Sp: 1122 + - Level: 202 + Sp: 1129 + - Level: 203 + Sp: 1136 + - Level: 204 + Sp: 1143 + - Level: 205 + Sp: 1150 + - Level: 206 + Sp: 1157 + - Level: 207 + Sp: 1164 + - Level: 208 + Sp: 1171 + - Level: 209 + Sp: 1178 + - Level: 210 + Sp: 1185 + - Level: 211 + Sp: 1192 + - Level: 212 + Sp: 1199 + - Level: 213 + Sp: 1206 + - Level: 214 + Sp: 1213 + - Level: 215 + Sp: 1220 + - Level: 216 + Sp: 1227 + - Level: 217 + Sp: 1234 + - Level: 218 + Sp: 1241 + - Level: 219 + Sp: 1248 + - Level: 220 + Sp: 1255 + - Level: 221 + Sp: 1262 + - Level: 222 + Sp: 1269 + - Level: 223 + Sp: 1276 + - Level: 224 + Sp: 1283 + - Level: 225 + Sp: 1290 + - Level: 226 + Sp: 1297 + - Level: 227 + Sp: 1304 + - Level: 228 + Sp: 1311 + - Level: 229 + Sp: 1318 + - Level: 230 + Sp: 1325 + - Level: 231 + Sp: 1332 + - Level: 232 + Sp: 1339 + - Level: 233 + Sp: 1346 + - Level: 234 + Sp: 1353 + - Level: 235 + Sp: 1360 + - Level: 236 + Sp: 1367 + - Level: 237 + Sp: 1374 + - Level: 238 + Sp: 1381 + - Level: 239 + Sp: 1388 + - Level: 240 + Sp: 1395 + - Level: 241 + Sp: 1402 + - Level: 242 + Sp: 1409 + - Level: 243 + Sp: 1416 + - Level: 244 + Sp: 1423 + - Level: 245 + Sp: 1430 + - Level: 246 + Sp: 1437 + - Level: 247 + Sp: 1444 + - Level: 248 + Sp: 1451 + - Level: 249 + Sp: 1458 + - Level: 250 + Sp: 1465 + - Jobs: + Sky_Emperor: true + Sky_Emperor2: true + BaseSp: + - Level: 200 + Sp: 500 + - Level: 201 + Sp: 500 + - Level: 202 + Sp: 500 + - Level: 203 + Sp: 500 + - Level: 204 + Sp: 500 + - Level: 205 + Sp: 500 + - Level: 206 + Sp: 500 + - Level: 207 + Sp: 500 + - Level: 208 + Sp: 500 + - Level: 209 + Sp: 500 + - Level: 210 + Sp: 500 + - Level: 211 + Sp: 500 + - Level: 212 + Sp: 500 + - Level: 213 + Sp: 500 + - Level: 214 + Sp: 500 + - Level: 215 + Sp: 500 + - Level: 216 + Sp: 500 + - Level: 217 + Sp: 500 + - Level: 218 + Sp: 500 + - Level: 219 + Sp: 500 + - Level: 220 + Sp: 500 + - Level: 221 + Sp: 500 + - Level: 222 + Sp: 500 + - Level: 223 + Sp: 500 + - Level: 224 + Sp: 500 + - Level: 225 + Sp: 500 + - Level: 226 + Sp: 500 + - Level: 227 + Sp: 500 + - Level: 228 + Sp: 500 + - Level: 229 + Sp: 500 + - Level: 230 + Sp: 500 + - Level: 231 + Sp: 500 + - Level: 232 + Sp: 500 + - Level: 233 + Sp: 500 + - Level: 234 + Sp: 500 + - Level: 235 + Sp: 500 + - Level: 236 + Sp: 500 + - Level: 237 + Sp: 500 + - Level: 238 + Sp: 500 + - Level: 239 + Sp: 500 + - Level: 240 + Sp: 500 + - Level: 241 + Sp: 500 + - Level: 242 + Sp: 500 + - Level: 243 + Sp: 500 + - Level: 244 + Sp: 500 + - Level: 245 + Sp: 500 + - Level: 246 + Sp: 500 + - Level: 247 + Sp: 500 + - Level: 248 + Sp: 500 + - Level: 249 + Sp: 500 + - Level: 250 + Sp: 500 + - Jobs: + Soul_Ascetic: true + BaseSp: + - Level: 200 + Sp: 900 + - Level: 201 + Sp: 900 + - Level: 202 + Sp: 900 + - Level: 203 + Sp: 900 + - Level: 204 + Sp: 900 + - Level: 205 + Sp: 900 + - Level: 206 + Sp: 900 + - Level: 207 + Sp: 900 + - Level: 208 + Sp: 900 + - Level: 209 + Sp: 900 + - Level: 210 + Sp: 900 + - Level: 211 + Sp: 900 + - Level: 212 + Sp: 900 + - Level: 213 + Sp: 900 + - Level: 214 + Sp: 900 + - Level: 215 + Sp: 900 + - Level: 216 + Sp: 900 + - Level: 217 + Sp: 900 + - Level: 218 + Sp: 900 + - Level: 219 + Sp: 900 + - Level: 220 + Sp: 900 + - Level: 221 + Sp: 900 + - Level: 222 + Sp: 900 + - Level: 223 + Sp: 900 + - Level: 224 + Sp: 900 + - Level: 225 + Sp: 900 + - Level: 226 + Sp: 900 + - Level: 227 + Sp: 900 + - Level: 228 + Sp: 900 + - Level: 229 + Sp: 900 + - Level: 230 + Sp: 900 + - Level: 231 + Sp: 900 + - Level: 232 + Sp: 900 + - Level: 233 + Sp: 900 + - Level: 234 + Sp: 900 + - Level: 235 + Sp: 900 + - Level: 236 + Sp: 900 + - Level: 237 + Sp: 900 + - Level: 238 + Sp: 900 + - Level: 239 + Sp: 900 + - Level: 240 + Sp: 900 + - Level: 241 + Sp: 900 + - Level: 242 + Sp: 900 + - Level: 243 + Sp: 900 + - Level: 244 + Sp: 900 + - Level: 245 + Sp: 900 + - Level: 246 + Sp: 900 + - Level: 247 + Sp: 900 + - Level: 248 + Sp: 900 + - Level: 249 + Sp: 900 + - Level: 250 + Sp: 900 + - Jobs: + Shinkiro: true + BaseSp: + - Level: 200 + Sp: 1330 + - Level: 201 + Sp: 1338 + - Level: 202 + Sp: 1346 + - Level: 203 + Sp: 1354 + - Level: 204 + Sp: 1362 + - Level: 205 + Sp: 1370 + - Level: 206 + Sp: 1378 + - Level: 207 + Sp: 1386 + - Level: 208 + Sp: 1394 + - Level: 209 + Sp: 1402 + - Level: 210 + Sp: 1410 + - Level: 211 + Sp: 1418 + - Level: 212 + Sp: 1426 + - Level: 213 + Sp: 1434 + - Level: 214 + Sp: 1442 + - Level: 215 + Sp: 1450 + - Level: 216 + Sp: 1458 + - Level: 217 + Sp: 1466 + - Level: 218 + Sp: 1474 + - Level: 219 + Sp: 1482 + - Level: 220 + Sp: 1490 + - Level: 221 + Sp: 1498 + - Level: 222 + Sp: 1506 + - Level: 223 + Sp: 1514 + - Level: 224 + Sp: 1522 + - Level: 225 + Sp: 1530 + - Level: 226 + Sp: 1538 + - Level: 227 + Sp: 1546 + - Level: 228 + Sp: 1554 + - Level: 229 + Sp: 1562 + - Level: 230 + Sp: 1570 + - Level: 231 + Sp: 1578 + - Level: 232 + Sp: 1586 + - Level: 233 + Sp: 1594 + - Level: 234 + Sp: 1602 + - Level: 235 + Sp: 1610 + - Level: 236 + Sp: 1618 + - Level: 237 + Sp: 1626 + - Level: 238 + Sp: 1634 + - Level: 239 + Sp: 1642 + - Level: 240 + Sp: 1650 + - Level: 241 + Sp: 1658 + - Level: 242 + Sp: 1666 + - Level: 243 + Sp: 1674 + - Level: 244 + Sp: 1682 + - Level: 245 + Sp: 1690 + - Level: 246 + Sp: 1698 + - Level: 247 + Sp: 1706 + - Level: 248 + Sp: 1714 + - Level: 249 + Sp: 1722 + - Level: 250 + Sp: 1730 + - Jobs: + Shiranui: true + BaseSp: + - Level: 200 + Sp: 1420 + - Level: 201 + Sp: 1428 + - Level: 202 + Sp: 1436 + - Level: 203 + Sp: 1444 + - Level: 204 + Sp: 1452 + - Level: 205 + Sp: 1460 + - Level: 206 + Sp: 1468 + - Level: 207 + Sp: 1476 + - Level: 208 + Sp: 1484 + - Level: 209 + Sp: 1492 + - Level: 210 + Sp: 1500 + - Level: 211 + Sp: 1508 + - Level: 212 + Sp: 1516 + - Level: 213 + Sp: 1524 + - Level: 214 + Sp: 1532 + - Level: 215 + Sp: 1540 + - Level: 216 + Sp: 1548 + - Level: 217 + Sp: 1556 + - Level: 218 + Sp: 1564 + - Level: 219 + Sp: 1572 + - Level: 220 + Sp: 1580 + - Level: 221 + Sp: 1588 + - Level: 222 + Sp: 1596 + - Level: 223 + Sp: 1604 + - Level: 224 + Sp: 1612 + - Level: 225 + Sp: 1620 + - Level: 226 + Sp: 1628 + - Level: 227 + Sp: 1636 + - Level: 228 + Sp: 1644 + - Level: 229 + Sp: 1652 + - Level: 230 + Sp: 1660 + - Level: 231 + Sp: 1668 + - Level: 232 + Sp: 1676 + - Level: 233 + Sp: 1684 + - Level: 234 + Sp: 1692 + - Level: 235 + Sp: 1700 + - Level: 236 + Sp: 1708 + - Level: 237 + Sp: 1716 + - Level: 238 + Sp: 1724 + - Level: 239 + Sp: 1732 + - Level: 240 + Sp: 1740 + - Level: 241 + Sp: 1748 + - Level: 242 + Sp: 1756 + - Level: 243 + Sp: 1764 + - Level: 244 + Sp: 1772 + - Level: 245 + Sp: 1780 + - Level: 246 + Sp: 1788 + - Level: 247 + Sp: 1796 + - Level: 248 + Sp: 1804 + - Level: 249 + Sp: 1812 + - Level: 250 + Sp: 1820 + - Jobs: + Night_Watch: true + BaseSp: + - Level: 200 + Sp: 1062 + - Level: 201 + Sp: 1068 + - Level: 202 + Sp: 1074 + - Level: 203 + Sp: 1080 + - Level: 204 + Sp: 1086 + - Level: 205 + Sp: 1092 + - Level: 206 + Sp: 1098 + - Level: 207 + Sp: 1104 + - Level: 208 + Sp: 1110 + - Level: 209 + Sp: 1116 + - Level: 210 + Sp: 1122 + - Level: 211 + Sp: 1128 + - Level: 212 + Sp: 1134 + - Level: 213 + Sp: 1140 + - Level: 214 + Sp: 1146 + - Level: 215 + Sp: 1152 + - Level: 216 + Sp: 1158 + - Level: 217 + Sp: 1164 + - Level: 218 + Sp: 1170 + - Level: 219 + Sp: 1176 + - Level: 220 + Sp: 1182 + - Level: 221 + Sp: 1188 + - Level: 222 + Sp: 1194 + - Level: 223 + Sp: 1200 + - Level: 224 + Sp: 1206 + - Level: 225 + Sp: 1212 + - Level: 226 + Sp: 1218 + - Level: 227 + Sp: 1224 + - Level: 228 + Sp: 1230 + - Level: 229 + Sp: 1236 + - Level: 230 + Sp: 1242 + - Level: 231 + Sp: 1248 + - Level: 232 + Sp: 1254 + - Level: 233 + Sp: 1260 + - Level: 234 + Sp: 1266 + - Level: 235 + Sp: 1272 + - Level: 236 + Sp: 1278 + - Level: 237 + Sp: 1284 + - Level: 238 + Sp: 1290 + - Level: 239 + Sp: 1296 + - Level: 240 + Sp: 1302 + - Level: 241 + Sp: 1308 + - Level: 242 + Sp: 1314 + - Level: 243 + Sp: 1320 + - Level: 244 + Sp: 1326 + - Level: 245 + Sp: 1332 + - Level: 246 + Sp: 1338 + - Level: 247 + Sp: 1344 + - Level: 248 + Sp: 1350 + - Level: 249 + Sp: 1356 + - Level: 250 + Sp: 1362 + - Jobs: + Hyper_Novice: true + BaseSp: + - Level: 200 + Sp: 200 + - Level: 201 + Sp: 201 + - Level: 202 + Sp: 202 + - Level: 203 + Sp: 203 + - Level: 204 + Sp: 204 + - Level: 205 + Sp: 205 + - Level: 206 + Sp: 206 + - Level: 207 + Sp: 207 + - Level: 208 + Sp: 208 + - Level: 209 + Sp: 209 + - Level: 210 + Sp: 210 + - Level: 211 + Sp: 211 + - Level: 212 + Sp: 212 + - Level: 213 + Sp: 213 + - Level: 214 + Sp: 214 + - Level: 215 + Sp: 215 + - Level: 216 + Sp: 216 + - Level: 217 + Sp: 217 + - Level: 218 + Sp: 218 + - Level: 219 + Sp: 219 + - Level: 220 + Sp: 220 + - Level: 221 + Sp: 221 + - Level: 222 + Sp: 222 + - Level: 223 + Sp: 223 + - Level: 224 + Sp: 224 + - Level: 225 + Sp: 225 + - Level: 226 + Sp: 226 + - Level: 227 + Sp: 227 + - Level: 228 + Sp: 228 + - Level: 229 + Sp: 229 + - Level: 230 + Sp: 230 + - Level: 231 + Sp: 231 + - Level: 232 + Sp: 232 + - Level: 233 + Sp: 233 + - Level: 234 + Sp: 234 + - Level: 235 + Sp: 235 + - Level: 236 + Sp: 236 + - Level: 237 + Sp: 237 + - Level: 238 + Sp: 238 + - Level: 239 + Sp: 239 + - Level: 240 + Sp: 240 + - Level: 241 + Sp: 241 + - Level: 242 + Sp: 242 + - Level: 243 + Sp: 243 + - Level: 244 + Sp: 244 + - Level: 245 + Sp: 245 + - Level: 246 + Sp: 246 + - Level: 247 + Sp: 247 + - Level: 248 + Sp: 248 + - Level: 249 + Sp: 249 + - Level: 250 + Sp: 250 + - Jobs: + Spirit_Handler: true + BaseSp: + - Level: 200 + Sp: 505 + - Level: 201 + Sp: 508 + - Level: 202 + Sp: 510 + - Level: 203 + Sp: 513 + - Level: 204 + Sp: 515 + - Level: 205 + Sp: 518 + - Level: 206 + Sp: 520 + - Level: 207 + Sp: 523 + - Level: 208 + Sp: 525 + - Level: 209 + Sp: 528 + - Level: 210 + Sp: 530 + - Level: 211 + Sp: 533 + - Level: 212 + Sp: 535 + - Level: 213 + Sp: 538 + - Level: 214 + Sp: 540 + - Level: 215 + Sp: 543 + - Level: 216 + Sp: 545 + - Level: 217 + Sp: 548 + - Level: 218 + Sp: 550 + - Level: 219 + Sp: 553 + - Level: 220 + Sp: 555 + - Level: 221 + Sp: 558 + - Level: 222 + Sp: 560 + - Level: 223 + Sp: 563 + - Level: 224 + Sp: 565 + - Level: 225 + Sp: 568 + - Level: 226 + Sp: 570 + - Level: 227 + Sp: 573 + - Level: 228 + Sp: 575 + - Level: 229 + Sp: 578 + - Level: 230 + Sp: 580 + - Level: 231 + Sp: 583 + - Level: 232 + Sp: 585 + - Level: 233 + Sp: 588 + - Level: 234 + Sp: 590 + - Level: 235 + Sp: 593 + - Level: 236 + Sp: 595 + - Level: 237 + Sp: 598 + - Level: 238 + Sp: 600 + - Level: 239 + Sp: 603 + - Level: 240 + Sp: 605 + - Level: 241 + Sp: 608 + - Level: 242 + Sp: 610 + - Level: 243 + Sp: 613 + - Level: 244 + Sp: 615 + - Level: 245 + Sp: 618 + - Level: 246 + Sp: 620 + - Level: 247 + Sp: 623 + - Level: 248 + Sp: 625 + - Level: 249 + Sp: 628 + - Level: 250 + Sp: 630 diff --git a/db/re/job_noenter_map.txt b/db/re/job_noenter_map.txt index 2b2a66b93e..5c43d127a6 100644 --- a/db/re/job_noenter_map.txt +++ b/db/re/job_noenter_map.txt @@ -104,4 +104,33 @@ JOB_SOUL_REAPER,4112,100 JOB_BABY_STAR_EMPEROR,4112,100 JOB_BABY_SOUL_REAPER,4112,100 JOB_STAR_EMPEROR2,4112,100 -JOB_BABY_STAR_EMPEROR2,4112,100 \ No newline at end of file +JOB_BABY_STAR_EMPEROR2,4112,100 + +JOB_DRAGON_KNIGHT,4112,100 +JOB_MEISTER,4112,100 +JOB_SHADOW_CROSS,4112,100 +JOB_ARCH_MAGE,4112,100 +JOB_CARDINAL,4112,100 +JOB_WINDHAWK,4112,100 +JOB_IMPERIAL_GUARD,4112,100 +JOB_BIOLO,4112,100 +JOB_ABYSS_CHASER,4112,100 +JOB_ELEMENTAL_MASTER,4112,100 +JOB_INQUISITOR,4112,100 +JOB_TROUBADOUR,4112,100 +JOB_TROUVERE,4112,100 + +JOB_WINDHAWK2,4112,100 +JOB_MEISTER2,4112,100 +JOB_DRAGON_KNIGHT2,4112,100 +JOB_IMPERIAL_GUARD2,4112,100 + +JOB_SKY_EMPEROR,4112,100 +JOB_SOUL_ASCETIC,4112,100 +JOB_SHINKIRO,4112,100 +JOB_SHIRANUI,4112,100 +JOB_NIGHT_WATCH,4112,100 +JOB_HYPER_NOVICE,4112,100 +JOB_SPIRIT_HANDLER,4112,100 + +JOB_SKY_EMPEROR2,4112,100 diff --git a/db/re/mob_db.yml b/db/re/mob_db.yml index 38c65d5a76..92fb03b888 100644 --- a/db/re/mob_db.yml +++ b/db/re/mob_db.yml @@ -36,6 +36,8 @@ # Attack2 Maximum attack in pre-renewal and base magic attack in renewal. (Default: 0) # Defense Physical defense of the monster, reduces melee and ranged physical attack/skill damage. (Default: 0) # MagicDefense Magic defense of the monster, reduces magical skill damage. (Default: 0) +# Resistance Physical resistance of the monster, reduces melee and ranged physical attack/skill damage. (Default: 0) +# MagicResistance Magic resistance of the monster, reduces magical skill damage. (Default: 0) # Str Strength which affects attack. (Default: 1) # Agi Agility which affects flee. (Default: 1) # Vit Vitality which affects defense. (Default: 1) @@ -75,7 +77,7 @@ Header: Type: MOB_DB - Version: 2 + Version: 3 Body: - Id: 1001 @@ -88910,14 +88912,106 @@ Body: # AegisName: 4JOB_R_FALCON # - Id: 20833 # AegisName: 4JOB_WORG -# - Id: 20834 -# AegisName: MEISTER_ABR1 -# - Id: 20835 -# AegisName: MEISTER_ABR2 -# - Id: 20836 -# AegisName: MEISTER_ABR3 -# - Id: 20837 -# AegisName: MEISTER_ABR4 + - Id: 20834 + AegisName: ABR_BATTLE_WARIOR + Name: ABR Battle Warrior + Level: 200 + Hp: 20000 + Defense: 200 + MagicDefense: 40 + Str: 10 + Agi: 10 + Vit: 10 + Int: 10 + Dex: 10 + Luk: 10 + AttackRange: 1 + SkillRange: 10 + ChaseRange: 12 + Size: Medium + Race: Formless + Element: Neutral + ElementLevel: 1 + WalkSpeed: 200 + AttackDelay: 1000 + AttackMotion: 500 + DamageMotion: 300 + Ai: 20 + - Id: 20835 + AegisName: ABR_DUAL_CANNON + Name: ABR Duel Cannon + Level: 200 + Hp: 20000 + Defense: 200 + MagicDefense: 40 + Str: 10 + Agi: 10 + Vit: 10 + Int: 10 + Dex: 10 + Luk: 10 + AttackRange: 6 + SkillRange: 10 + ChaseRange: 12 + Size: Medium + Race: Formless + Element: Neutral + ElementLevel: 1 + WalkSpeed: 200 + AttackDelay: 1000 + AttackMotion: 500 + DamageMotion: 300 + Ai: 20 + - Id: 20836 + AegisName: ABR_MOTHER_NET + Name: ABR Mother Net + Level: 200 + Hp: 20000 + Defense: 200 + MagicDefense: 40 + Str: 10 + Agi: 10 + Vit: 10 + Int: 10 + Dex: 10 + Luk: 10 + AttackRange: 6 + SkillRange: 10 + ChaseRange: 12 + Size: Medium + Race: Formless + Element: Neutral + ElementLevel: 1 + WalkSpeed: 200 + AttackDelay: 1000 + AttackMotion: 500 + DamageMotion: 300 + Ai: 20 + - Id: 20837 + AegisName: ABR_INFINITY + Name: ABR Infinity + Level: 200 + Hp: 20000 + Defense: 200 + MagicDefense: 40 + Str: 10 + Agi: 10 + Vit: 10 + Int: 10 + Dex: 10 + Luk: 10 + AttackRange: 6 + SkillRange: 10 + ChaseRange: 12 + Size: Large + Race: Formless + Element: Neutral + ElementLevel: 1 + WalkSpeed: 200 + AttackDelay: 1000 + AttackMotion: 500 + DamageMotion: 300 + Ai: 20 # - Id: 20838 # AegisName: ELEMETAL_MASTER_S1 # - Id: 20839 @@ -88938,14 +89032,106 @@ Body: # AegisName: MD_HIDDEN_GROUND01 # - Id: 20847 # AegisName: MD_HIDDEN_GROUND02 -# - Id: 20848 -# AegisName: SUMMON_WOODENWARRIOR -# - Id: 20849 -# AegisName: SUMMON_WOODEN_FAIRY -# - Id: 20850 -# AegisName: SUMMON_CREEPER -# - Id: 20851 -# AegisName: SUMMON_HELLTREE + - Id: 20848 + AegisName: SUMMON_WOODENWARRIOR + Name: Wooden Warrior + Level: 200 + Hp: 20000 + Defense: 200 + MagicDefense: 40 + Str: 10 + Agi: 10 + Vit: 10 + Int: 10 + Dex: 10 + Luk: 10 + AttackRange: 3 + SkillRange: 10 + ChaseRange: 12 + Size: Medium + Race: Plant + Element: Earth + ElementLevel: 1 + WalkSpeed: 200 + AttackDelay: 1000 + AttackMotion: 500 + DamageMotion: 300 + Ai: 20 + - Id: 20849 + AegisName: SUMMON_WOODEN_FAIRY + Name: Wooden Fairy + Level: 200 + Hp: 20000 + Defense: 200 + MagicDefense: 40 + Str: 10 + Agi: 10 + Vit: 10 + Int: 10 + Dex: 10 + Luk: 10 + AttackRange: 5 + SkillRange: 10 + ChaseRange: 12 + Size: Medium + Race: Plant + Element: Earth + ElementLevel: 1 + WalkSpeed: 200 + AttackDelay: 1000 + AttackMotion: 500 + DamageMotion: 300 + Ai: 20 + - Id: 20850 + AegisName: SUMMON_CREEPER + Name: Creeper + Level: 200 + Hp: 20000 + Defense: 200 + MagicDefense: 40 + Str: 10 + Agi: 10 + Vit: 10 + Int: 10 + Dex: 10 + Luk: 10 + AttackRange: 5 + SkillRange: 10 + ChaseRange: 12 + Size: Medium + Race: Plant + Element: Earth + ElementLevel: 1 + WalkSpeed: 200 + AttackDelay: 1000 + AttackMotion: 500 + DamageMotion: 300 + Ai: 20 + - Id: 20851 + AegisName: SUMMON_HELLTREE + Name: Hell Tree + Level: 200 + Hp: 20000 + Defense: 200 + MagicDefense: 40 + Str: 10 + Agi: 10 + Vit: 10 + Int: 10 + Dex: 10 + Luk: 10 + AttackRange: 5 + SkillRange: 10 + ChaseRange: 12 + Size: Medium + Race: Plant + Element: Earth + ElementLevel: 1 + WalkSpeed: 200 + AttackDelay: 1000 + AttackMotion: 500 + DamageMotion: 300 + Ai: 20 # - Id: 20856 # AegisName: MD_N_ARENA_1 # - Id: 20857 diff --git a/db/re/mob_skill_db.txt b/db/re/mob_skill_db.txt index 46132029c0..fbb469be98 100644 --- a/db/re/mob_skill_db.txt +++ b/db/re/mob_skill_db.txt @@ -12192,3 +12192,17 @@ 3633,EP16_2_VENOM_KIMERA@NPC_WIDESIGHT,attack,669,1,10000,0,30000,yes,self,always,0,,,,,,, 3633,EP16_2_VENOM_KIMERA@NPC_ACIDBREATH,attack,657,6,10000,3000,25000,no,target,always,0,,,,,,, 3633,EP16_2_VENOM_KIMERA@RG_STRIPARMOR,attack,217,5,500,1000,5000,no,target,always,0,,,,,,, + +// Meister ABR's (Automated Battle Robot) +20834,ABR_BATTLE_WARIOR@ABR_BATTLE_BUSTER,chase,8601,1,10000,500,5000,yes,target,always,0,,,,,,, +20834,ABR_BATTLE_WARIOR@ABR_BATTLE_BUSTER,attack,8601,1,10000,500,5000,yes,target,always,0,,,,,,, +20835,ABR_DUAL_CANNON@ABR_DUAL_CANNON_FIRE,chase,8602,1,10000,500,5000,yes,target,always,0,,,,,,, +20835,ABR_DUAL_CANNON@ABR_DUAL_CANNON_FIRE,attack,8602,1,10000,500,5000,yes,target,always,0,,,,,,, +20836,ABR_MOTHER_NET@ABR_NET_REPAIR,idle,8603,1,10000,500,5000,yes,self,always,0,,,,,,, +20836,ABR_MOTHER_NET@ABR_NET_REPAIR,chase,8603,1,10000,500,5000,yes,self,always,0,,,,,,, +20836,ABR_MOTHER_NET@ABR_NET_REPAIR,attack,8603,1,10000,500,5000,yes,self,always,0,,,,,,, +20836,ABR_MOTHER_NET@ABR_NET_SUPPORT,idle,8604,1,10000,500,5000,yes,self,always,0,,,,,,, +20836,ABR_MOTHER_NET@ABR_NET_SUPPORT,chase,8604,1,10000,500,5000,yes,self,always,0,,,,,,, +20836,ABR_MOTHER_NET@ABR_NET_SUPPORT,attack,8604,1,10000,500,5000,yes,self,always,0,,,,,,, +20837,ABR_INFINITY@ABR_INFINITY_BUSTER,chase,8605,1,10000,500,5000,yes,target,always,0,,,,,,, +20837,ABR_INFINITY@ABR_INFINITY_BUSTER,attack,8605,1,10000,500,5000,yes,target,always,0,,,,,,, diff --git a/db/re/produce_db.txt b/db/re/produce_db.txt index c7cddb1a66..5271b6f120 100644 --- a/db/re/produce_db.txt +++ b/db/re/produce_db.txt @@ -694,3 +694,41 @@ 280,533,30,0,0,11058,0,514,1,519,1 // Unripe Apple (619) <-- 10 Sticky Mucus, 20 Green Herbs, 10 Apples 281,619,30,0,0,11058,0,938,10,511,20,512,10 + +//===== Manufacture Machine === ItemLV=31 ====== +// Device Capsule (1000289) <-- MT_M_MACHINE Lvl, Device Creation Guide, 5 Mini Furnace, 5 Oridecon Hammer, 50 Magic Gear Fuel +282,1000289,31,5297,1,1000352,0,612,5,615,5,6146,50 +// Auto Battle Capsule (1000290) <-- MT_M_MACHINE Lvl, Device Creation Guide, 5 Mini Furnace, 5 Oridecon Hammer, 75 Magic Gear Fuel +283,1000290,31,5297,1,1000352,0,612,5,615,5,6146,75 +//============================================== + +//===== Bionic Pharmacy === ItemLV=32 ========== +// Flame Acid Bottle (1000276) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 5 Fire Bottle, 5 Acid Bottle, 2 Bloody Red +284,1000276,32,5336,1,1000275,1,7135,5,7136,5,990,2 +// Earth Acid Bottle (1000277) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 5 Fire Bottle, 5 Acid Bottle, 2 Yellow Live +285,1000277,32,5336,1,1000275,1,7135,5,7136,5,993,2 +// Gale Acid Bottle (1000278) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 5 Fire Bottle, 5 Acid Bottle, 2 Wind of Verdure +286,1000278,32,5336,1,1000275,1,7135,5,7136,5,992,2 +// Icicle Acid Bottle (1000279) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 5 Fire Bottle, 5 Acid Bottle, 2 Crystal Blue +287,1000279,32,5336,1,1000275,1,7135,5,7136,5,991,2 +// High Coating Bottle (1000280) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 5 Empty Bottle, 10 Coating Bottle +288,1000280,32,5336,1,1000275,1,713,5,7139,10 +// High Plant Bottle (1000281) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 2 Seed Of Thorny Plant, 2 Bloodsuck Plant Seed, 5 Mandragora Flowerpot, 10 Plant Bottle +289,1000281,32,5336,1,1000275,1,6210,2,6211,2,6217,5,7137,10 +// Eye Cleaner (100516) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 10 Empty Bottle, 5 Holy Water, 3 White Herb, 3 Green Herb +290,100516,32,5336,1,1000275,1,713,10,523,5,509,3,511,3 +// Ear Cleaner (100517) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 10 Empty Bottle, 5 Holy Water, 2 Blue Herb, 3 Green Herb +291,100517,32,5336,1,1000275,1,713,10,523,5,510,2,511,3 +// Tonics (100518) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 10 Empty Bottle, 5 Holy Water, 2 Yggdrasilberry, 3 Royal Jelly +292,100518,32,5336,1,1000275,1,713,10,523,5,607,2,526,3 +// Mini Extinguisher (100519) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 10 Empty Bottle, 5 Holy Water, 5 Crystal Blue, 3 Iron +293,100519,32,5336,1,1000275,1,713,10,523,5,991,5,998,3 +// Water Of Lucky (100520) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 10 Empty Bottle, 5 Holy Water, 10 Clover, 3 Green Herb +294,100520,32,5336,1,1000275,1,713,10,523,5,705,10,511,3 +// Strong Antidote (100521) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 10 Empty Bottle, 5 Holy Water, 3 Poison Bottle, 10 Green Herb +295,100521,32,5336,1,1000275,1,713,10,523,5,678,3,511,10 +// High Energy Chocolate (100522) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 10 Empty Bottle, 3 Cacao, 3 Royal Jelly, 5 Yggdrasil Seed +296,100522,32,5336,1,1000275,1,713,10,7182,3,526,3,608,5 +// Refined Holy Water (100523) <-- BO_BIONIC_PHARMACY Lvl, 1 Beaker, 10 Empty Bottle, 10 Holy Water, 3 Royal Jelly +297,100523,32,5336,1,1000275,1,713,10,523,10,526,3 +//============================================== diff --git a/db/re/skill_db.yml b/db/re/skill_db.yml index b9c8e5af0a..62585ee382 100644 --- a/db/re/skill_db.yml +++ b/db/re/skill_db.yml @@ -49,6 +49,9 @@ # Knockback: Amount of tiles the skill knockbacks. (Default: 0) # - Level Skill level. # Amount Knockback count at specific skill level. +# GiveAp: Gives AP on successful skill cast. (Default: 0) +# - Level Skill level. +# Amount AP gained at specific skill level. # CopyFlags: Determines if the skill is copyable. (Optional) # Skill: Type of skill that can copy. # RemoveRequirement: Remove a requirement type. (Optional) @@ -87,12 +90,18 @@ # SpCost: SP required to cast. (Default: 0) # - Level Skill level. # Amount SP required at specific skill level. +# ApCost: AP required to cast. (Default: 0) +# - Level Skill level. +# Amount AP required at specific skill level. # HpRateCost: HP rate required to cast. If positive, uses current HP, else uses Max HP. (Default: 0) # - Level Skill level. # Amount HP rate required at specific skill level. # SpRateCost: SP rate required to cast. If positive, uses current SP, else uses Max SP. (Default: 0) # - Level Skill level. # Amount SP rate required at specific skill level. +# ApRateCost: AP rate required to cast. If positive, uses current AP, else uses Max AP. (Default: 0) +# - Level Skill level. +# Amount AP rate required at specific skill level. # MaxHpTrigger: Maximum amount of HP to cast the skill. (Default: 0) # - Level Skill level. # Amount Maximum HP trigger required at specific skill level. @@ -130,7 +139,7 @@ Header: Type: SKILL_DB - Version: 2 + Version: 3 Body: - Id: 1 @@ -21592,7 +21601,7 @@ Body: Flags: AllowOnMado: true Range: 11 - Hit: Single + Hit: Multi_Hit HitCount: 1 Element: Weapon CastTime: @@ -21653,7 +21662,7 @@ Body: TargetTrap: true AllowOnMado: true Range: 13 - Hit: Single + Hit: Multi_Hit HitCount: 1 Element: Weapon SplashArea: 2 @@ -21773,7 +21782,7 @@ Body: Flags: AllowOnMado: true Range: 9 - Hit: Single + Hit: Multi_Hit HitCount: 1 Element: Weapon SplashArea: @@ -22350,7 +22359,7 @@ Body: Flags: AllowOnMado: true Range: 1 - Hit: Single + Hit: Multi_Hit HitCount: 1 Element: Weapon AfterCastActDelay: @@ -27836,7 +27845,7 @@ Body: Size: 10 - Level: 5 Size: 11 - Hit: Single + Hit: Multi_Hit HitCount: 1 Element: Weapon SplashArea: @@ -33767,6 +33776,6133 @@ Body: CastTime: 5000 AfterCastActDelay: 500 FixedCastTime: 1000 + - Id: 5201 + Name: DK_SERVANTWEAPON + Description: Servant Weapon + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + GiveAp: + - Level: 1 + Amount: 6 + - Level: 2 + Amount: 12 + - Level: 3 + Amount: 18 + - Level: 4 + Amount: 24 + - Level: 5 + Amount: 30 + CastCancel: true + Duration1: + - Level: 1 + Time: 30000 + - Level: 2 + Time: 60000 + - Level: 3 + Time: 90000 + - Level: 4 + Time: 120000 + - Level: 5 + Time: 150000 + Duration2: + - Level: 1 + Time: 5000 + - Level: 2 + Time: 4000 + - Level: 3 + Time: 3000 + - Level: 4 + Time: 2000 + - Level: 5 + Time: 1000 + Cooldown: + - Level: 1 + Time: 30000 + - Level: 2 + Time: 60000 + - Level: 3 + Time: 90000 + - Level: 4 + Time: 120000 + - Level: 5 + Time: 150000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 40 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 60 + - Level: 5 + Amount: 70 + - Id: 5202 + Name: DK_SERVANTWEAPON_ATK + Description: Servant Weapon Attack + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Critical: true + Range: 1 + Hit: Single + HitCount: 1 + Element: Weapon + Requires: + SpCost: 1 + - Id: 5203 + Name: DK_SERVANT_W_SIGN + Description: Servant Weapon Sign + MaxLevel: 5 + TargetType: Attack + DamageFlags: + NoDamage: true + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: + - Level: 1 + Time: 2000 + - Level: 2 + Time: 4000 + - Level: 3 + Time: 6000 + - Level: 4 + Time: 8000 + - Level: 5 + Time: 10000 + Requires: + SpCost: 15 + SpiritSphereCost: 1 + - Id: 5204 + Name: DK_SERVANT_W_PHANTOM + Description: Servant Weapon Phantom + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Critical: true + Range: 9 + Hit: Multi_Hit + HitCount: 5 + Element: Weapon + SplashArea: 2 + CastCancel: true + AfterCastActDelay: 500 + Duration1: 20000 + Cooldown: 2000 + FixedCastTime: 500 + Requires: + SpCost: 40 + SpiritSphereCost: 5 + - Id: 5205 + Name: DK_SERVANT_W_DEMOL + Description: Servant Weapon Demolition + MaxLevel: 5 + Type: Weapon + TargetType: Self + DamageFlags: + Splash: true + Critical: true + Hit: Multi_Hit + HitCount: 5 + Element: Weapon + SplashArea: 6 + GiveAp: 3 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 3000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 35 + - Level: 3 + Amount: 40 + - Level: 4 + Amount: 45 + - Level: 5 + Amount: 50 + SpiritSphereCost: 5 + - Id: 5206 + Name: DK_CHARGINGPIERCE + Description: Charging Pierce + MaxLevel: 10 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 90000 + - Level: 2 + Time: 100000 + - Level: 3 + Time: 110000 + - Level: 4 + Time: 120000 + - Level: 5 + Time: 130000 + - Level: 6 + Time: 140000 + - Level: 7 + Time: 150000 + - Level: 8 + Time: 160000 + - Level: 9 + Time: 170000 + - Level: 10 + Time: 180000 + Duration2: 5000 + Cooldown: 60000 + Requires: + SpCost: + - Level: 1 + Amount: 25 + - Level: 2 + Amount: 30 + - Level: 3 + Amount: 35 + - Level: 4 + Amount: 40 + - Level: 5 + Amount: 45 + - Level: 6 + Amount: 50 + - Level: 7 + Amount: 55 + - Level: 8 + Amount: 60 + - Level: 9 + Amount: 65 + - Level: 10 + Amount: 70 + Weapon: + 2hSword: true + 1hSpear: true + 2hSpear: true + - Id: 5207 + Name: DK_TWOHANDDEF + Description: Two Hand Def + MaxLevel: 10 + - Id: 5208 + Name: DK_HACKANDSLASHER + Description: Hack And Slasher + MaxLevel: 10 + Type: Weapon + TargetType: Attack + Range: 2 + Hit: Single + HitCount: 1 + Element: Weapon + CastCancel: true + AfterCastActDelay: 500 + Requires: + SpCost: + - Level: 1 + Amount: 34 + - Level: 2 + Amount: 38 + - Level: 3 + Amount: 42 + - Level: 4 + Amount: 46 + - Level: 5 + Amount: 50 + - Level: 6 + Amount: 54 + - Level: 7 + Amount: 58 + - Level: 8 + Amount: 62 + - Level: 9 + Amount: 66 + - Level: 10 + Amount: 70 + Weapon: + 2hSword: true + 2hSpear: true + - Id: 5209 + Name: DK_HACKANDSLASHER_ATK + Description: Hack And Slasher Attack + MaxLevel: 10 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 2 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 1 + - Level: 4 + Area: 1 + - Level: 5 + Area: 2 + - Level: 6 + Area: 2 + - Level: 7 + Area: 2 + - Level: 8 + Area: 2 + - Level: 9 + Area: 3 + - Level: 10 + Area: 3 + Requires: + SpCost: 1 + - Id: 5210 + Name: DK_DRAGONIC_AURA + Description: Dragonic Aura + MaxLevel: 10 + Type: Weapon + TargetType: Attack + Range: 7 + Hit: Single + HitCount: 1 + Element: Weapon + CastCancel: true + AfterCastActDelay: 1000 + Duration1: 300000 + Cooldown: 60000 + Requires: + SpCost: 100 + ApCost: 150 + - Id: 5211 + Name: DK_MADNESS_CRUSHER + Description: Madness Crusher + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 7 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 2 + - Level: 3 + Area: 2 + - Level: 4 + Area: 3 + - Level: 5 + Area: 3 + GiveAp: 2 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 2000 + FixedCastTime: 500 + Requires: + SpCost: + - Level: 1 + Amount: 34 + - Level: 2 + Amount: 38 + - Level: 3 + Amount: 42 + - Level: 4 + Amount: 46 + - Level: 5 + Amount: 50 + Weapon: + 2hSword: true + 2hSpear: true + - Id: 5212 + Name: DK_VIGOR + Description: Vigor + MaxLevel: 10 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: + - Level: 1 + Time: 30000 + - Level: 2 + Time: 60000 + - Level: 3 + Time: 90000 + - Level: 4 + Time: 120000 + - Level: 5 + Time: 150000 + - Level: 6 + Time: 180000 + - Level: 7 + Time: 210000 + - Level: 8 + Time: 240000 + - Level: 9 + Time: 270000 + - Level: 10 + Time: 300000 + Cooldown: 60000 + Requires: + SpCost: 100 + ApCost: 150 + - Id: 5213 + Name: DK_STORMSLASH + Description: Storm Slash + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Critical: true + Range: 2 + Hit: Multi_Hit + HitCount: + - Level: 1 + Count: 1 + - Level: 2 + Count: 2 + - Level: 3 + Count: 3 + - Level: 4 + Count: 4 + - Level: 5 + Count: 5 + Element: Weapon + GiveAp: 1 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 35 + - Level: 3 + Amount: 40 + - Level: 4 + Amount: 45 + - Level: 5 + Amount: 50 + Weapon: + 2hSword: true + 2hAxe: true + - Id: 5214 + Name: AG_DEADLY_PROJECTION + Description: Deadly Projection + MaxLevel: 5 + Type: Magic + TargetType: Attack + Range: 9 + Hit: Single + HitCount: 1 + Element: Undead + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 4000 + - Level: 2 + Time: 5000 + - Level: 3 + Time: 6000 + - Level: 4 + Time: 7000 + - Level: 5 + Time: 8000 + Cooldown: 2000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 80 + - Level: 2 + Amount: 90 + - Level: 3 + Amount: 100 + - Level: 4 + Amount: 110 + - Level: 5 + Amount: 120 + - Id: 5215 + Name: AG_DESTRUCTIVE_HURRICANE + Description: Destructive Hurricane + MaxLevel: 5 + Type: Magic + TargetType: Self + DamageFlags: + Splash: true + Hit: Single + HitCount: 1 + Element: Wind + SplashArea: + - Level: 1 + Area: 3 + - Level: 2 + Area: 3 + - Level: 3 + Area: 4 + - Level: 4 + Area: 4 + - Level: 5 + Area: 5 + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 1000 + Duration2: 900000 + Cooldown: 6000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 80 + - Level: 2 + Amount: 90 + - Level: 3 + Amount: 100 + - Level: 4 + Amount: 110 + - Level: 5 + Amount: 120 + - Id: 5216 + Name: AG_RAIN_OF_CRYSTAL + Description: Rain Of Crystal + MaxLevel: 5 + Type: Magic + TargetType: Self + Hit: Single + HitCount: -2 + Element: Water + CastCancel: true + CastTime: 3000 + AfterCastActDelay: 500 + Duration1: 4000 + Cooldown: 5000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 50 + - Level: 3 + Amount: 60 + - Level: 4 + Amount: 70 + - Level: 5 + Amount: 80 + Unit: + Id: Rain_Of_Crystal + Range: + - Level: 1 + Size: 6 + - Level: 2 + Size: 7 + - Level: 3 + Size: 8 + - Level: 4 + Size: 9 + - Level: 5 + Size: 10 + Interval: 500 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5217 + Name: AG_MYSTERY_ILLUSION + Description: Mystery Illusion + MaxLevel: 5 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Single + HitCount: 1 + Element: Dark + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 1000 + Duration1: 4000 + Cooldown: 4000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 80 + - Level: 2 + Amount: 90 + - Level: 3 + Amount: 100 + - Level: 4 + Amount: 110 + - Level: 5 + Amount: 120 + Unit: + Id: Mystery_Illusion + Range: + - Level: 1 + Size: 4 + - Level: 2 + Size: 4 + - Level: 3 + Size: 5 + - Level: 4 + Size: 5 + - Level: 5 + Size: 6 + Interval: 300 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5218 + Name: AG_VIOLENT_QUAKE + Description: Violent Quake + MaxLevel: 5 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Single + HitCount: 1 + Element: Earth + SplashArea: + - Level: 1 + Area: 3 + - Level: 2 + Area: 3 + - Level: 3 + Area: 4 + - Level: 4 + Area: 4 + - Level: 5 + Area: 4 + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 1000 + Duration1: + - Level: 1 + Time: 1200 + - Level: 2 + Time: 2400 + - Level: 3 + Time: 3600 + - Level: 4 + Time: 4800 + - Level: 5 + Time: 6000 + Duration2: 30000 + Cooldown: 6000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 80 + - Level: 2 + Amount: 90 + - Level: 3 + Amount: 100 + - Level: 4 + Amount: 110 + - Level: 5 + Amount: 120 + Unit: + Id: Violent_Quake + Range: + - Level: 1 + Size: 3 + - Level: 2 + Size: 3 + - Level: 3 + Size: 4 + - Level: 4 + Size: 4 + - Level: 5 + Size: 4 + Interval: 300 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5219 + Name: AG_VIOLENT_QUAKE_ATK + Description: Violent Quake Attack + MaxLevel: 5 + Type: Magic + TargetType: Attack + Range: 9 + Hit: Single + HitCount: 1 + Element: Earth + Duration1: 100 + Requires: + SpCost: 1 + Unit: + Id: Dummyskill + Range: 3 + Interval: 300 + Target: Enemy + Flag: + PathCheck: true + - Id: 5220 + Name: AG_SOUL_VC_STRIKE + Description: Soul Vulcan Strike + MaxLevel: 5 + Type: Magic + TargetType: Attack + DamageFlags: + Splash: true + Range: 9 + Hit: Multi_Hit + HitCount: + - Level: 1 + Count: 3 + - Level: 2 + Count: 4 + - Level: 3 + Count: 5 + - Level: 4 + Count: 6 + - Level: 5 + Count: 7 + Element: Ghost + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 2 + - Level: 3 + Area: 3 + - Level: 4 + Area: 4 + - Level: 5 + Area: 5 + CastCancel: true + CastTime: 3000 + AfterCastActDelay: 500 + Cooldown: 700 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 80 + - Level: 2 + Amount: 90 + - Level: 3 + Amount: 100 + - Level: 4 + Amount: 110 + - Level: 5 + Amount: 120 + - Id: 5221 + Name: AG_STRANTUM_TREMOR + Description: Strantum Tremor + MaxLevel: 5 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Multi_Hit + HitCount: -2 + Element: Earth + CastCancel: true + CastTime: 3000 + AfterCastActDelay: 500 + Duration1: 4000 + Cooldown: 5000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 35 + - Level: 2 + Amount: 45 + - Level: 3 + Amount: 55 + - Level: 4 + Amount: 65 + - Level: 5 + Amount: 75 + Unit: + Id: Strantum_Tremor + Range: + - Level: 1 + Size: 2 + - Level: 2 + Size: 2 + - Level: 3 + Size: 3 + - Level: 4 + Size: 3 + - Level: 5 + Size: 4 + Interval: 400 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5222 + Name: AG_ALL_BLOOM + Description: All Bloom + MaxLevel: 5 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Single + HitCount: 1 + Element: Fire + SplashArea: + - Level: 1 + Area: 3 + - Level: 2 + Area: 3 + - Level: 3 + Area: 4 + - Level: 4 + Area: 4 + - Level: 5 + Area: 4 + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 1000 + Duration1: + - Level: 1 + Time: 1200 + - Level: 2 + Time: 2400 + - Level: 3 + Time: 3600 + - Level: 4 + Time: 4800 + - Level: 5 + Time: 6000 + Duration2: 30000 + Cooldown: 6000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 80 + - Level: 2 + Amount: 90 + - Level: 3 + Amount: 100 + - Level: 4 + Amount: 110 + - Level: 5 + Amount: 120 + Unit: + Id: All_Bloom + Range: + - Level: 1 + Size: 3 + - Level: 2 + Size: 3 + - Level: 3 + Size: 4 + - Level: 4 + Size: 4 + - Level: 5 + Size: 4 + Interval: 300 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5223 + Name: AG_ALL_BLOOM_ATK + Description: All Bloom Attack + MaxLevel: 5 + Type: Magic + TargetType: Attack + Range: 9 + Hit: Single + HitCount: 1 + Element: Fire + Duration1: 100 + Requires: + SpCost: 1 + Unit: + Id: Dummyskill + Range: 3 + Interval: 300 + Target: Enemy + Flag: + PathCheck: true + - Id: 5224 + Name: AG_ALL_BLOOM_ATK2 + Description: All Bloom Attack 2 + MaxLevel: 5 + Type: Magic + TargetType: Attack + Range: 9 + Hit: Single + HitCount: 1 + Element: Fire + Duration1: 100 + Requires: + SpCost: 1 + Unit: + Id: Dummyskill + Range: + - Level: 1 + Size: 3 + - Level: 2 + Size: 3 + - Level: 3 + Size: 4 + - Level: 4 + Size: 4 + - Level: 5 + Size: 4 + Interval: 1000 + Target: Enemy + Flag: + PathCheck: true + - Id: 5225 + Name: AG_CRYSTAL_IMPACT + Description: Crystal Impact + MaxLevel: 5 + Type: Magic + TargetType: Self + DamageFlags: + Splash: true + Hit: Multi_Hit + HitCount: 1 + Element: Water + SplashArea: + - Level: 1 + Area: 3 + - Level: 2 + Area: 4 + - Level: 3 + Area: 5 + - Level: 4 + Area: 6 + - Level: 5 + Area: 7 + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 1000 + Duration2: 900000 + Cooldown: 6000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 80 + - Level: 2 + Amount: 90 + - Level: 3 + Amount: 100 + - Level: 4 + Amount: 110 + - Level: 5 + Amount: 120 + - Id: 5226 + Name: AG_CRYSTAL_IMPACT_ATK + Description: Crystal Impact Attack + MaxLevel: 5 + Type: Magic + TargetType: Attack + DamageFlags: + Splash: true + Hit: Single + HitCount: 1 + Element: Water + Requires: + SpCost: 1 + - Id: 5227 + Name: AG_TORNADO_STORM + Description: Tornado Storm + MaxLevel: 5 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Single + HitCount: 1 + Element: Wind + CastCancel: true + CastTime: 3000 + AfterCastActDelay: 500 + Duration1: 3000 + Cooldown: 5000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 45 + - Level: 2 + Amount: 55 + - Level: 3 + Amount: 65 + - Level: 4 + Amount: 75 + - Level: 5 + Amount: 85 + Unit: + Id: Tornado_Storm + Range: + - Level: 1 + Size: 2 + - Level: 2 + Size: 2 + - Level: 3 + Size: 3 + - Level: 4 + Size: 3 + - Level: 5 + Size: 4 + Interval: 300 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5228 + Name: AG_TWOHANDSTAFF + Description: Two Hand Staff Mastery + MaxLevel: 10 + HitCount: 1 + - Id: 5229 + Name: AG_FLORAL_FLARE_ROAD + Description: Floral Flare Road + MaxLevel: 5 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Multi_Hit + HitCount: -2 + Element: Fire + CastCancel: true + CastTime: 3000 + AfterCastActDelay: 500 + Duration1: 5000 + Cooldown: 5000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 40 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 60 + - Level: 5 + Amount: 70 + Unit: + Id: Floral_Flare_Road + Range: + - Level: 1 + Size: 1 + - Level: 2 + Size: 2 + - Level: 3 + Size: 3 + - Level: 4 + Size: 4 + - Level: 5 + Size: 5 + Interval: 500 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5230 + Name: AG_ASTRAL_STRIKE + Description: Astral Strike + MaxLevel: 10 + Type: Magic + TargetType: Ground + DamageFlags: + Splash: true + Range: 9 + Hit: Single + HitCount: 1 + SplashArea: + - Level: 1 + Area: 2 + - Level: 2 + Area: 2 + - Level: 3 + Area: 2 + - Level: 4 + Area: 3 + - Level: 5 + Area: 3 + - Level: 6 + Area: 3 + - Level: 7 + Area: 4 + - Level: 8 + Area: 4 + - Level: 9 + Area: 4 + - Level: 10 + Area: 5 + CastCancel: true + CastTime: 8000 + AfterCastActDelay: 500 + Duration1: 15000 + Cooldown: 60000 + FixedCastTime: 2000 + Requires: + SpCost: 150 + ApCost: 150 + Unit: + Id: Astral_Strike + Range: + - Level: 1 + Size: 2 + - Level: 2 + Size: 2 + - Level: 3 + Size: 2 + - Level: 4 + Size: 3 + - Level: 5 + Size: 3 + - Level: 6 + Size: 3 + - Level: 7 + Size: 4 + - Level: 8 + Size: 4 + - Level: 9 + Size: 4 + - Level: 10 + Size: 5 + Interval: 300 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5231 + Name: AG_ASTRAL_STRIKE_ATK + Description: Astral Strike Attack + MaxLevel: 10 + Type: Magic + TargetType: Attack + Range: 9 + Hit: Single + HitCount: 1 + Requires: + SpCost: 1 + - Id: 5232 + Name: AG_CLIMAX + Description: Climax + MaxLevel: 5 + Type: Magic + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 300 + Duration1: 300000 + Cooldown: 300000 + FixedCastTime: 4000 + Requires: + SpCost: 60 + ApCost: 200 + - Id: 5233 + Name: AG_ROCK_DOWN + Description: Rock Down + MaxLevel: 5 + Type: Magic + TargetType: Attack + DamageFlags: + Splash: true + Range: 9 + Hit: Multi_Hit + HitCount: -5 + Element: Earth + SplashArea: 1 + GiveAp: 4 + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 1000 + Cooldown: 4000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 65 + - Level: 2 + Amount: 70 + - Level: 3 + Amount: 75 + - Level: 4 + Amount: 80 + - Level: 5 + Amount: 85 + - Id: 5234 + Name: AG_STORM_CANNON + Description: Storm Cannon + MaxLevel: 5 + Type: Magic + TargetType: Attack + Range: 9 + Hit: Single + HitCount: 1 + Element: Wind + SplashArea: 1 + ActiveInstance: 14 + GiveAp: 4 + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 1000 + Cooldown: 4000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 60 + - Level: 2 + Amount: 70 + - Level: 3 + Amount: 80 + - Level: 4 + Amount: 90 + - Level: 5 + Amount: 100 + - Id: 5235 + Name: AG_CRIMSON_ARROW + Description: Crimson Arrow + MaxLevel: 5 + Type: Magic + TargetType: Attack + Range: 9 + Hit: Single + HitCount: 1 + Element: Fire + SplashArea: 1 + ActiveInstance: 14 + GiveAp: 4 + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 1000 + Cooldown: 4000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 65 + - Level: 2 + Amount: 75 + - Level: 3 + Amount: 85 + - Level: 4 + Amount: 95 + - Level: 5 + Amount: 105 + - Id: 5236 + Name: AG_CRIMSON_ARROW_ATK + Description: Crimson Arrow Attack + MaxLevel: 5 + Type: Magic + TargetType: Attack + Range: 9 + Hit: Multi_Hit + HitCount: -2 + Element: Fire + Requires: + SpCost: 1 + - Id: 5237 + Name: AG_FROZEN_SLASH + Description: Frozen Slash + MaxLevel: 5 + Type: Magic + TargetType: Self + DamageFlags: + Splash: true + Hit: Single + HitCount: 1 + Element: Water + SplashArea: + - Level: 1 + Area: 2 + - Level: 2 + Area: 2 + - Level: 3 + Area: 3 + - Level: 4 + Area: 3 + - Level: 5 + Area: 4 + GiveAp: 4 + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 1000 + Cooldown: 4000 + FixedCastTime: 1500 + Requires: + SpCost: + - Level: 1 + Amount: 45 + - Level: 2 + Amount: 55 + - Level: 3 + Amount: 65 + - Level: 4 + Amount: 75 + - Level: 5 + Amount: 85 + - Id: 5238 + Name: IQ_POWERFUL_FAITH + Description: Powerful Faith + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 150000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 210000 + - Level: 5 + Time: 240000 + Cooldown: 60000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 54 + - Level: 2 + Amount: 58 + - Level: 3 + Amount: 62 + - Level: 4 + Amount: 66 + - Level: 5 + Amount: 70 + - Id: 5239 + Name: IQ_FIRM_FAITH + Description: Firm Faith + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 150000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 210000 + - Level: 5 + Time: 240000 + Cooldown: 60000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 54 + - Level: 2 + Amount: 58 + - Level: 3 + Amount: 62 + - Level: 4 + Amount: 66 + - Level: 5 + Amount: 70 + - Id: 5240 + Name: IQ_WILL_OF_FAITH + Description: Will Of Faith + MaxLevel: 10 + CastCancel: true + - Id: 5241 + Name: IQ_OLEUM_SANCTUM + Description: Oleum Sanctum + MaxLevel: 5 + Type: Weapon + TargetType: Self + DamageFlags: + Splash: true + Range: 9 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 3000 + - Level: 2 + Time: 4000 + - Level: 3 + Time: 5000 + - Level: 4 + Time: 6000 + - Level: 5 + Time: 7000 + Cooldown: 5000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 40 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 60 + - Level: 5 + Amount: 70 + ItemCost: + - Item: Holy_Water + Amount: 1 + - Id: 5242 + Name: IQ_SINCERE_FAITH + Description: Sincere Faith + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 150000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 210000 + - Level: 5 + Time: 240000 + Cooldown: 60000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 54 + - Level: 2 + Amount: 58 + - Level: 3 + Amount: 62 + - Level: 4 + Amount: 66 + - Level: 5 + Amount: 70 + - Id: 5243 + Name: IQ_MASSIVE_F_BLASTER + Description: Massive Flame Blaster + MaxLevel: 10 + Type: Weapon + TargetType: Self + DamageFlags: + Splash: true + Range: 9 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: 4 + CastCancel: true + AfterCastActDelay: 500 + Duration1: 300000 + Cooldown: 60000 + Requires: + SpCost: 100 + ApCost: 150 + - Id: 5244 + Name: IQ_EXPOSION_BLASTER + Description: Exposion Blaster + MaxLevel: 5 + Type: Weapon + TargetType: Self + DamageFlags: + Splash: true + Range: 9 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 2 + - Level: 2 + Area: 2 + - Level: 3 + Area: 3 + - Level: 4 + Area: 3 + - Level: 5 + Area: 4 + GiveAp: 5 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 5000 + Requires: + SpCost: + - Level: 1 + Amount: 80 + - Level: 2 + Amount: 90 + - Level: 3 + Amount: 100 + - Level: 4 + Amount: 110 + - Level: 5 + Amount: 120 + - Id: 5245 + Name: IQ_FIRST_BRAND + Description: First Brand + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 2 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + CastCancel: true + Duration1: + - Level: 1 + Time: 1000 + - Level: 2 + Time: 2000 + - Level: 3 + Time: 3000 + - Level: 4 + Time: 4000 + - Level: 5 + Time: 5000 + Cooldown: 500 + Requires: + SpCost: + - Level: 1 + Amount: 22 + - Level: 2 + Amount: 29 + - Level: 3 + Amount: 36 + - Level: 4 + Amount: 43 + - Level: 5 + Amount: 50 + - Id: 5246 + Name: IQ_FIRST_FAITH_POWER + Description: First Faith Power + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 60000 + - Level: 2 + Time: 120000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 240000 + - Level: 5 + Time: 300000 + Cooldown: 150000 + FixedCastTime: 1000 + Requires: + SpCost: 60 + - Id: 5247 + Name: IQ_JUDGE + Description: Judge + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 60000 + - Level: 2 + Time: 120000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 240000 + - Level: 5 + Time: 300000 + Cooldown: 150000 + FixedCastTime: 1000 + Requires: + SpCost: 60 + ApCost: 100 + Status: + First_Faith_Power: true + - Id: 5248 + Name: IQ_SECOND_FLAME + Description: Second Flame + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 3 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + GiveAp: 3 + CastCancel: true + Duration1: 5000 + Cooldown: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 46 + - Level: 2 + Amount: 52 + - Level: 3 + Amount: 58 + - Level: 4 + Amount: 64 + - Level: 5 + Amount: 70 + - Id: 5249 + Name: IQ_SECOND_FAITH + Description: Second Faith + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 3 + Hit: Multi_Hit + HitCount: -2 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + GiveAp: 1 + CastCancel: true + Duration1: 5000 + Cooldown: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 36 + - Level: 2 + Amount: 42 + - Level: 3 + Amount: 48 + - Level: 4 + Amount: 54 + - Level: 5 + Amount: 60 + - Id: 5250 + Name: IQ_SECOND_JUDGEMENT + Description: Second Judgement + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 3 + Hit: Multi_Hit + HitCount: -3 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + GiveAp: 2 + CastCancel: true + Duration1: 5000 + Cooldown: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 45 + - Level: 2 + Amount: 50 + - Level: 3 + Amount: 55 + - Level: 4 + Amount: 60 + - Level: 5 + Amount: 65 + - Id: 5251 + Name: IQ_THIRD_PUNISH + Description: Third Punish + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 3 + Hit: Multi_Hit + HitCount: -2 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + CastCancel: true + Duration1: 600000 + Cooldown: 2000 + Requires: + SpCost: + - Level: 1 + Amount: 56 + - Level: 2 + Amount: 62 + - Level: 3 + Amount: 68 + - Level: 4 + Amount: 74 + - Level: 5 + Amount: 80 + - Id: 5252 + Name: IQ_THIRD_FLAME_BOMB + Description: Third Flame Bomb + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 3 + Hit: Multi_Hit + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + CastCancel: true + Cooldown: 2000 + Requires: + SpCost: + - Level: 1 + Amount: 74 + - Level: 2 + Amount: 78 + - Level: 3 + Amount: 82 + - Level: 4 + Amount: 86 + - Level: 5 + Amount: 90 + - Id: 5253 + Name: IQ_THIRD_CONSECRATION + Description: Third Consecration + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 3 + Hit: Multi_Hit + HitCount: -3 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + CastCancel: true + Cooldown: 2000 + Requires: + SpCost: + - Level: 1 + Amount: 65 + - Level: 2 + Amount: 70 + - Level: 3 + Amount: 75 + - Level: 4 + Amount: 80 + - Level: 5 + Amount: 85 + - Id: 5254 + Name: IQ_THIRD_EXOR_FLAME + Description: Third Exor Flame + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 30000 + - Level: 2 + Time: 60000 + - Level: 3 + Time: 90000 + - Level: 4 + Time: 120000 + - Level: 5 + Time: 150000 + Cooldown: 150000 + FixedCastTime: 1000 + Requires: + SpCost: 60 + ApCost: 150 + Status: + Second_Judge: true + - Id: 5255 + Name: IG_GUARD_STANCE + Description: Guard Stance + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + FixedCastTime: 500 + Requires: + SpCost: 50 + State: Shield + - Id: 5256 + Name: IG_GUARDIAN_SHIELD + Description: Guardian Shield + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Splash: true + Hit: Single + HitCount: 1 + SplashArea: 10 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 60000 + Cooldown: 15000 + FixedCastTime: 1000 + Requires: + SpCost: 60 + Status: + Guard_Stance: true + - Id: 5257 + Name: IG_REBOUND_SHIELD + Description: Rebound Shield + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 60000 + Cooldown: 15000 + FixedCastTime: 1000 + Requires: + SpCost: 60 + Status: + Guard_Stance: true + - Id: 5258 + Name: IG_SHIELD_MASTERY + Description: Shield Mastery + MaxLevel: 10 + - Id: 5259 + Name: IG_SPEAR_SWORD_M + Description: Spear And Sword Mastery + MaxLevel: 10 + - Id: 5260 + Name: IG_ATTACK_STANCE + Description: Attack Stance + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + FixedCastTime: 500 + Requires: + SpCost: 50 + - Id: 5261 + Name: IG_ULTIMATE_SACRIFICE + Description: Ultimate Sacrifice + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 300000 + Cooldown: + - Level: 1 + Time: 20000 + - Level: 2 + Time: 40000 + - Level: 3 + Time: 60000 + - Level: 4 + Time: 80000 + - Level: 5 + Time: 100000 + FixedCastTime: 1000 + Requires: + SpCost: 120 + Status: + Guard_Stance: true + - Id: 5262 + Name: IG_HOLY_SHIELD + Description: Holy Shield + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 180000 + Cooldown: 120000 + FixedCastTime: 1000 + Requires: + SpCost: 60 + State: Shield + - Id: 5263 + Name: IG_GRAND_JUDGEMENT + Description: Grand Judgement + MaxLevel: 10 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 9 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: 3 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: 300000 + Cooldown: 60000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 41 + - Level: 2 + Amount: 44 + - Level: 3 + Amount: 47 + - Level: 4 + Amount: 50 + - Level: 5 + Amount: 53 + - Level: 6 + Amount: 56 + - Level: 7 + Amount: 59 + - Level: 8 + Amount: 62 + - Level: 9 + Amount: 65 + - Level: 10 + Amount: 68 + ApCost: 150 + Weapon: + 1hSpear: true + 2hSpear: true + Status: + Attack_Stance: true + - Id: 5264 + Name: IG_JUDGEMENT_CROSS + Description: Judgement Cross + MaxLevel: 10 + Type: Magic + TargetType: Attack + Range: 9 + Hit: Multi_Hit + HitCount: -10 + Element: Holy + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 1000 + Cooldown: 60000 + FixedCastTime: 1000 + Requires: + SpCost: 150 + ApCost: 150 + - Id: 5265 + Name: IG_SHIELD_SHOOTING + Description: Shield Shooting + MaxLevel: 5 + Type: Weapon + TargetType: Attack + Range: 9 + Hit: Multi_Hit + HitCount: -7 + Element: Weapon + GiveAp: 2 + CastCancel: true + CastTime: 500 + AfterCastActDelay: 500 + Duration1: 10000 + Cooldown: 2000 + FixedCastTime: 500 + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 45 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 55 + - Level: 5 + Amount: 60 + State: Shield + Status: + Attack_Stance: true + - Id: 5266 + Name: IG_OVERSLASH + Description: Overslash + MaxLevel: 10 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 1 + Hit: Multi_Hit + HitCount: 2 + Element: Weapon + SplashArea: 3 + GiveAp: 3 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Cooldown: 3000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 41 + - Level: 2 + Amount: 44 + - Level: 3 + Amount: 47 + - Level: 4 + Amount: 50 + - Level: 5 + Amount: 53 + - Level: 6 + Amount: 56 + - Level: 7 + Amount: 59 + - Level: 8 + Amount: 62 + - Level: 9 + Amount: 65 + - Level: 10 + Amount: 68 + Status: + Attack_Stance: true + - Id: 5267 + Name: IG_CROSS_RAIN + Description: Cross Rain + MaxLevel: 10 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Single + HitCount: 1 + Element: Holy + GiveAp: 5 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: 4500 + Cooldown: 5000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 50 + - Level: 2 + Amount: 54 + - Level: 3 + Amount: 58 + - Level: 4 + Amount: 62 + - Level: 5 + Amount: 66 + - Level: 6 + Amount: 70 + - Level: 7 + Amount: 74 + - Level: 8 + Amount: 78 + - Level: 9 + Amount: 82 + - Level: 10 + Amount: 86 + Unit: + Id: Cross_Rain + Range: + - Level: 1 + Size: 1 + - Level: 2 + Size: 1 + - Level: 3 + Size: 1 + - Level: 4 + Size: 2 + - Level: 5 + Size: 2 + - Level: 6 + Size: 2 + - Level: 7 + Size: 3 + - Level: 8 + Size: 3 + - Level: 9 + Size: 3 + - Level: 10 + Size: 4 + Interval: 300 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5268 + Name: CD_REPARATIO + Description: Reparatio + MaxLevel: 5 + TargetType: Support + DamageFlags: + NoDamage: true + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Cooldown: + - Level: 1 + Time: 150000 + - Level: 2 + Time: 100000 + - Level: 3 + Time: 60000 + - Level: 4 + Time: 30000 + - Level: 5 + Time: 10000 + FixedCastTime: 1000 + Requires: + SpCost: 120 + - Id: 5269 + Name: CD_MEDIALE_VOTUM + Description: Mediale Votum + MaxLevel: 5 + TargetType: Support + DamageFlags: + NoDamage: true + Splash: true + Flags: + PartyOnly: true + Range: 9 + Hit: Single + HitCount: 1 + SplashArea: 4 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 40000 + - Level: 2 + Time: 60000 + - Level: 3 + Time: 80000 + - Level: 4 + Time: 100000 + - Level: 5 + Time: 120000 + Cooldown: 60000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 40 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 60 + - Level: 5 + Amount: 70 + - Id: 5270 + Name: CD_MACE_BOOK_M + Description: Mace Book Mastery + MaxLevel: 10 + - Id: 5271 + Name: CD_ARGUTUS_VITA + Description: Argutus Vita + MaxLevel: 5 + TargetType: Support + DamageFlags: + NoDamage: true + Flags: + PartyOnly: true + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 150000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 210000 + - Level: 5 + Time: 240000 + Cooldown: 1000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 45 + - Level: 3 + Amount: 60 + - Level: 4 + Amount: 75 + - Level: 5 + Amount: 90 + - Id: 5272 + Name: CD_ARGUTUS_TELUM + Description: Argutus Telum + MaxLevel: 5 + TargetType: Support + DamageFlags: + NoDamage: true + Flags: + PartyOnly: true + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 150000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 210000 + - Level: 5 + Time: 240000 + Cooldown: 1000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 45 + - Level: 3 + Amount: 60 + - Level: 4 + Amount: 75 + - Level: 5 + Amount: 90 + - Id: 5273 + Name: CD_ARBITRIUM + Description: Arbitrium + MaxLevel: 10 + Type: Magic + TargetType: Attack + Range: 9 + Hit: Single + HitCount: 1 + Element: Holy + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 20000 + Cooldown: 3000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 50 + - Level: 2 + Amount: 60 + - Level: 3 + Amount: 70 + - Level: 4 + Amount: 80 + - Level: 5 + Amount: 90 + - Level: 6 + Amount: 100 + - Level: 7 + Amount: 110 + - Level: 8 + Amount: 120 + - Level: 9 + Amount: 130 + - Level: 10 + Amount: 140 + - Id: 5274 + Name: CD_ARBITRIUM_ATK + Description: Arbitrium Attack + MaxLevel: 10 + Type: Magic + TargetType: Attack + DamageFlags: + Splash: true + Range: 9 + Hit: Single + HitCount: 1 + Element: Holy + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 1 + - Level: 4 + Area: 2 + - Level: 5 + Area: 2 + - Level: 6 + Area: 2 + - Level: 7 + Area: 3 + - Level: 8 + Area: 3 + - Level: 9 + Area: 3 + - Level: 10 + Area: 4 + Requires: + SpCost: 1 + - Id: 5275 + Name: CD_PRESENS_ACIES + Description: Presens Acies + MaxLevel: 5 + TargetType: Support + DamageFlags: + NoDamage: true + Flags: + PartyOnly: true + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 150000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 210000 + - Level: 5 + Time: 240000 + Cooldown: 1000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 45 + - Level: 3 + Amount: 60 + - Level: 4 + Amount: 75 + - Level: 5 + Amount: 90 + - Id: 5276 + Name: CD_FIDUS_ANIMUS + Description: Fidus Animus + MaxLevel: 10 + - Id: 5277 + Name: CD_EFFLIGO + Description: Effligo + MaxLevel: 10 + Type: Weapon + TargetType: Attack + Range: 2 + Hit: Multi_Hit + HitCount: -7 + Element: Weapon + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 60000 + Requires: + SpCost: 60 + ApCost: 100 + Weapon: + Mace: true + 2hMace: true + Book: true + - Id: 5278 + Name: CD_COMPETENTIA + Description: Competentia + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Splash: true + Hit: Single + HitCount: 1 + SplashArea: 10 + CastCancel: true + CastTime: 8000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 150000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 210000 + - Level: 5 + Time: 240000 + Cooldown: 60000 + FixedCastTime: 2000 + Requires: + SpCost: 60 + ApCost: 200 + - Id: 5279 + Name: CD_PNEUMATICUS_PROCELLA + Description: Pneumaticus Procella + MaxLevel: 10 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Multi_Hit + HitCount: -10 + Element: Holy + CastCancel: true + CastTime: 3000 + AfterCastActDelay: 500 + Duration1: 12000 + Cooldown: 60000 + FixedCastTime: 2000 + Requires: + SpCost: 150 + ApCost: 150 + Unit: + Id: Pneumaticus_Procella + Range: + - Level: 1 + Size: 2 + - Level: 2 + Size: 2 + - Level: 3 + Size: 2 + - Level: 4 + Size: 3 + - Level: 5 + Size: 3 + - Level: 6 + Size: 3 + - Level: 7 + Size: 4 + - Level: 8 + Size: 4 + - Level: 9 + Size: 4 + - Level: 10 + Size: 5 + Interval: 3000 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5280 + Name: CD_DILECTIO_HEAL + Description: Dilectio Heal + MaxLevel: 5 + TargetType: Support + DamageFlags: + NoDamage: true + Splash: true + Flags: + PartyOnly: true + Range: 9 + Hit: Single + HitCount: 1 + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + GiveAp: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 50 + - Level: 2 + Amount: 55 + - Level: 3 + Amount: 60 + - Level: 4 + Amount: 65 + - Level: 5 + Amount: 70 + - Id: 5281 + Name: CD_RELIGIO + Description: Religio + MaxLevel: 5 + TargetType: Support + DamageFlags: + NoDamage: true + Range: 9 + Hit: Single + HitCount: 1 + GiveAp: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 150000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 210000 + - Level: 5 + Time: 240000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 70 + - Level: 2 + Amount: 75 + - Level: 3 + Amount: 80 + - Level: 4 + Amount: 85 + - Level: 5 + Amount: 90 + - Id: 5282 + Name: CD_BENEDICTUM + Description: Benedictum + MaxLevel: 5 + TargetType: Support + DamageFlags: + NoDamage: true + Range: 9 + Hit: Single + HitCount: 1 + GiveAp: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 150000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 210000 + - Level: 5 + Time: 240000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 70 + - Level: 2 + Amount: 75 + - Level: 3 + Amount: 80 + - Level: 4 + Amount: 85 + - Level: 5 + Amount: 90 + - Id: 5283 + Name: CD_PETITIO + Description: Petitio + MaxLevel: 10 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 2 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 1 + - Level: 4 + Area: 2 + - Level: 5 + Area: 2 + - Level: 6 + Area: 2 + - Level: 7 + Area: 3 + - Level: 8 + Area: 3 + - Level: 9 + Area: 3 + - Level: 10 + Area: 4 + GiveAp: 2 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 2000 + Requires: + SpCost: + - Level: 1 + Amount: 32 + - Level: 2 + Amount: 34 + - Level: 3 + Amount: 36 + - Level: 4 + Amount: 38 + - Level: 5 + Amount: 40 + - Level: 6 + Amount: 42 + - Level: 7 + Amount: 44 + - Level: 8 + Amount: 46 + - Level: 9 + Amount: 48 + - Level: 10 + Amount: 50 + Weapon: + Mace: true + 2hMace: true + Book: true + - Id: 5284 + Name: CD_FRAMEN + Description: Framen + MaxLevel: 5 + Type: Magic + TargetType: Attack + DamageFlags: + Splash: true + Range: 9 + Hit: Single + HitCount: 1 + Element: Holy + SplashArea: + - Level: 1 + Area: 2 + - Level: 2 + Area: 2 + - Level: 3 + Area: 2 + - Level: 4 + Area: 3 + - Level: 5 + Area: 3 + GiveAp: 3 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Cooldown: 3000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 45 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 55 + - Level: 5 + Amount: 60 + - Id: 5285 + Name: SHC_SHADOW_EXCEED + Description: Shadow Exceed + MaxLevel: 10 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 60000 + - Level: 2 + Time: 80000 + - Level: 3 + Time: 100000 + - Level: 4 + Time: 120000 + - Level: 5 + Time: 140000 + - Level: 6 + Time: 160000 + - Level: 7 + Time: 180000 + - Level: 8 + Time: 200000 + - Level: 9 + Time: 220000 + - Level: 10 + Time: 240000 + Cooldown: 60000 + FixedCastTime: 1000 + Requires: + SpCost: 100 + ApCost: 150 + - Id: 5286 + Name: SHC_DANCING_KNIFE + Description: Dancing Knife + MaxLevel: 5 + Type: Weapon + TargetType: Self + DamageFlags: + Splash: true + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: 2 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: 120000 + Cooldown: 30000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 45 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 55 + - Level: 5 + Amount: 60 + Weapon: + Dagger: true + - Id: 5287 + Name: SHC_SAVAGE_IMPACT + Description: Savage Impact + MaxLevel: 10 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Critical: true + Range: 7 + Hit: Multi_Hit + HitCount: -8 + Element: Weapon + SplashArea: 1 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 3000 + Requires: + SpCost: + - Level: 1 + Amount: 28 + - Level: 2 + Amount: 31 + - Level: 3 + Amount: 34 + - Level: 4 + Amount: 37 + - Level: 5 + Amount: 40 + - Level: 6 + Amount: 43 + - Level: 7 + Amount: 46 + - Level: 8 + Amount: 49 + - Level: 9 + Amount: 52 + - Level: 10 + Amount: 55 + Weapon: + Katar: true + State: Hidden + - Id: 5288 + Name: SHC_SHADOW_SENSE + Description: Shadow Sense + MaxLevel: 10 + - Id: 5289 + Name: SHC_ETERNAL_SLASH + Description: Eternal Slash + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Critical: true + Range: 2 + Hit: Multi_Hit + HitCount: 1 + Element: Weapon + CastCancel: true + AfterCastActDelay: 500 + Duration1: 3000 + Cooldown: 1500 + Requires: + SpCost: 40 + Status: + Weaponblock_On: true + - Id: 5290 + Name: SHC_POTENT_VENOM + Description: Potent Venom + MaxLevel: 10 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 30000 + - Level: 2 + Time: 40000 + - Level: 3 + Time: 50000 + - Level: 4 + Time: 60000 + - Level: 5 + Time: 70000 + - Level: 6 + Time: 80000 + - Level: 7 + Time: 90000 + - Level: 8 + Time: 100000 + - Level: 9 + Time: 110000 + - Level: 10 + Time: 120000 + Cooldown: 3000 + Requires: + SpCost: + - Level: 1 + Amount: 15 + - Level: 2 + Amount: 20 + - Level: 3 + Amount: 25 + - Level: 4 + Amount: 30 + - Level: 5 + Amount: 35 + - Level: 6 + Amount: 40 + - Level: 7 + Amount: 45 + - Level: 8 + Amount: 50 + - Level: 9 + Amount: 55 + - Level: 10 + Amount: 60 + Status: + Edp: true + - Id: 5291 + Name: SHC_SHADOW_STAB + Description: Shadow Stab + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + IgnoreDefense: true + Range: 2 + Hit: Multi_Hit + HitCount: 1 + Element: Weapon + GiveAp: 3 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 3000 + Requires: + SpCost: + - Level: 1 + Amount: 45 + - Level: 2 + Amount: 50 + - Level: 3 + Amount: 55 + - Level: 4 + Amount: 60 + - Level: 5 + Amount: 65 + Weapon: + Dagger: true + - Id: 5292 + Name: SHC_IMPACT_CRATER + Description: Impact Crater + MaxLevel: 5 + Type: Weapon + TargetType: Self + DamageFlags: + Splash: true + Critical: true + Hit: Multi_Hit + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + GiveAp: 5 + CastCancel: true + AfterCastActDelay: 500 + Duration1: 10000 + Cooldown: 5000 + Requires: + SpCost: + - Level: 1 + Amount: 43 + - Level: 2 + Amount: 46 + - Level: 3 + Amount: 49 + - Level: 4 + Amount: 52 + - Level: 5 + Amount: 55 + Weapon: + Katar: true + Status: + Rollingcutter: true + - Id: 5293 + Name: SHC_ENCHANTING_SHADOW + Description: Enchanting Shadow + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Duration1: 180000 + Duration2: 30000 + Cooldown: 150000 + FixedCastTime: 2000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 40 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 60 + - Level: 5 + Amount: 70 + - Id: 5294 + Name: SHC_FATAL_SHADOW_CROW + Description: Fatal Shadow Crow + MaxLevel: 10 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 9 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: 3 + CastCancel: true + AfterCastActDelay: 500 + Duration1: 20000 + Cooldown: 60000 + Requires: + SpCost: 150 + ApCost: 150 + - Id: 5295 + Name: MT_AXE_STOMP + Description: Axe Stomp + MaxLevel: 5 + Type: Weapon + TargetType: Self + DamageFlags: + Splash: true + Flags: + AllowOnMado: true + Hit: Multi_Hit + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + GiveAp: 2 + CastCancel: true + AfterCastActDelay: 500 + Duration1: 5000 + Cooldown: 2000 + Requires: + SpCost: + - Level: 1 + Amount: 25 + - Level: 2 + Amount: 30 + - Level: 3 + Amount: 35 + - Level: 4 + Amount: 40 + - Level: 5 + Amount: 45 + Weapon: + 1hAxe: true + 2hAxe: true + - Id: 5296 + Name: MT_RUSH_QUAKE + Description: Rush Quake + MaxLevel: 10 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Flags: + AllowOnMado: true + Range: 9 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 1 + - Level: 4 + Area: 1 + - Level: 5 + Area: 2 + - Level: 6 + Area: 2 + - Level: 7 + Area: 2 + - Level: 8 + Area: 2 + - Level: 9 + Area: 3 + - Level: 10 + Area: 3 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 60000 + Requires: + SpCost: 150 + ApCost: 150 + - Id: 5297 + Name: MT_M_MACHINE + Description: Manufacture Machine + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Flags: + AllowOnMado: true + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 40 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 60 + - Level: 5 + Amount: 70 + ItemCost: + - Item: Device_Creation_Guide + Amount: 0 + - Id: 5298 + Name: MT_A_MACHINE + Description: Attack Machine + MaxLevel: 5 + Type: Weapon + TargetType: Support + DamageFlags: + Splash: true + Flags: + PartyOnly: true + AllowOnMado: true + Range: 1 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 80000 + - Level: 2 + Time: 120000 + - Level: 3 + Time: 160000 + - Level: 4 + Time: 200000 + - Level: 5 + Time: 240000 + Requires: + SpCost: + - Level: 1 + Amount: 43 + - Level: 2 + Amount: 46 + - Level: 3 + Amount: 49 + - Level: 4 + Amount: 52 + - Level: 5 + Amount: 55 + ItemCost: + - Item: Device_Capsule + Amount: 1 + - Id: 5299 + Name: MT_D_MACHINE + Description: Defense Machine + MaxLevel: 5 + TargetType: Support + DamageFlags: + NoDamage: true + Flags: + PartyOnly: true + AllowOnMado: true + Range: 1 + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 80000 + - Level: 2 + Time: 120000 + - Level: 3 + Time: 160000 + - Level: 4 + Time: 200000 + - Level: 5 + Time: 240000 + Requires: + SpCost: + - Level: 1 + Amount: 43 + - Level: 2 + Amount: 46 + - Level: 3 + Amount: 49 + - Level: 4 + Amount: 52 + - Level: 5 + Amount: 55 + ItemCost: + - Item: Device_Capsule + Amount: 1 + - Id: 5300 + Name: MT_TWOAXEDEF + Description: Two Hand Axe Def + MaxLevel: 10 + - Id: 5301 + Name: MT_ABR_M + Description: ABR Mastery + MaxLevel: 10 + - Id: 5302 + Name: MT_SUMMON_ABR_BATTLE_WARIOR + Description: ABR Battle Warior + MaxLevel: 4 + TargetType: Self + DamageFlags: + NoDamage: true + Flags: + AllowOnMado: true + Hit: Single + HitCount: 1 + ActiveInstance: 1 + GiveAp: 20 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 180000 + - Level: 3 + Time: 240000 + - Level: 4 + Time: 300000 + Cooldown: 60000 + FixedCastTime: 3000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 40 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 60 + ItemCost: + - Item: Auto_Battle_Capsule + Amount: 1 + - Id: 5303 + Name: MT_SUMMON_ABR_DUAL_CANNON + Description: ABR Dual Cannon + MaxLevel: 4 + TargetType: Self + DamageFlags: + NoDamage: true + Flags: + AllowOnMado: true + Hit: Single + HitCount: 1 + ActiveInstance: 1 + GiveAp: 20 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 180000 + - Level: 3 + Time: 240000 + - Level: 4 + Time: 300000 + Cooldown: 60000 + FixedCastTime: 3000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 40 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 60 + ItemCost: + - Item: Auto_Battle_Capsule + Amount: 1 + - Id: 5304 + Name: MT_SUMMON_ABR_MOTHER_NET + Description: ABR Mother Net + MaxLevel: 4 + TargetType: Self + DamageFlags: + NoDamage: true + Flags: + AllowOnMado: true + Hit: Single + HitCount: 1 + ActiveInstance: 1 + GiveAp: 20 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 180000 + - Level: 3 + Time: 240000 + - Level: 4 + Time: 300000 + Cooldown: 60000 + FixedCastTime: 3000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 40 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 60 + ItemCost: + - Item: Auto_Battle_Capsule + Amount: 1 + - Id: 5305 + Name: MT_SUMMON_ABR_INFINITY + Description: ABR Infinity + MaxLevel: 4 + TargetType: Self + DamageFlags: + NoDamage: true + Flags: + AllowOnMado: true + Hit: Single + HitCount: 1 + ActiveInstance: 1 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 180000 + - Level: 3 + Time: 240000 + - Level: 4 + Time: 300000 + Cooldown: 60000 + FixedCastTime: 3000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 40 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 60 + ApCost: 200 + ItemCost: + - Item: Auto_Battle_Capsule + Amount: 5 + - Id: 5306 + Name: AG_DESTRUCTIVE_HURRICANE_CLIMAX + Description: Destructive Hurricane Climax + MaxLevel: 5 + Type: Magic + TargetType: Attack + Hit: Single + HitCount: 1 + Element: Wind + Requires: + SpCost: 1 + - Id: 5307 + Name: BO_ACIDIFIED_ZONE_WATER_ATK + Description: Actified Zone Water Attack + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + IgnoreFlee: true + Hit: Single + HitCount: 1 + Element: Water + Requires: + SpCost: 1 + - Id: 5308 + Name: BO_ACIDIFIED_ZONE_GROUND_ATK + Description: Actified Zone Ground Attack + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + IgnoreFlee: true + Hit: Single + HitCount: 1 + Element: Earth + Requires: + SpCost: 1 + - Id: 5309 + Name: BO_ACIDIFIED_ZONE_WIND_ATK + Description: Actified Zone Wind Attack + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + IgnoreFlee: true + Hit: Single + HitCount: 1 + Element: Wind + Requires: + SpCost: 1 + - Id: 5310 + Name: BO_ACIDIFIED_ZONE_FIRE_ATK + Description: Actified Zone Fire Attack + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + IgnoreFlee: true + Hit: Single + HitCount: 1 + Element: Fire + Requires: + SpCost: 1 + - Id: 5311 + Name: ABC_DAGGER_AND_BOW_M + Description: Dagger And Bow Mastery + MaxLevel: 10 + - Id: 5312 + Name: ABC_MAGIC_SWORD_M + Description: Magic Sword Mastery + MaxLevel: 10 + - Id: 5313 + Name: ABC_STRIP_SHADOW + Description: Strip Shadow + MaxLevel: 5 + TargetType: Attack + DamageFlags: + NoDamage: true + Range: 1 + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 1000 + Duration1: + - Level: 1 + Time: 60000 + - Level: 2 + Time: 70000 + - Level: 3 + Time: 80000 + - Level: 4 + Time: 90000 + - Level: 5 + Time: 100000 + Requires: + SpCost: + - Level: 1 + Amount: 29 + - Level: 2 + Amount: 33 + - Level: 3 + Amount: 37 + - Level: 4 + Amount: 41 + - Level: 5 + Amount: 45 + - Id: 5314 + Name: ABC_ABYSS_DAGGER + Description: Abyss Dagger + MaxLevel: 5 + Type: Weapon + TargetType: Self + DamageFlags: + Splash: true + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: 2 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 2000 + - Level: 2 + Time: 4000 + - Level: 3 + Time: 6000 + - Level: 4 + Time: 8000 + - Level: 5 + Time: 10000 + Cooldown: 3000 + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 45 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 55 + - Level: 5 + Amount: 60 + Weapon: + Dagger: true + 1hSword: true + - Id: 5315 + Name: ABC_UNLUCKY_RUSH + Description: Unlucky Rush + MaxLevel: 5 + Type: Weapon + TargetType: Attack + Range: 7 + Hit: Single + HitCount: 1 + Element: Weapon + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: 20000 + Cooldown: 2000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 35 + - Level: 3 + Amount: 40 + - Level: 4 + Amount: 45 + - Level: 5 + Amount: 50 + - Id: 5316 + Name: ABC_CHAIN_REACTION_SHOT + Description: Chain Reaction Shot + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 9 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Cooldown: 3000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 50 + - Level: 3 + Amount: 60 + - Level: 4 + Amount: 70 + - Level: 5 + Amount: 80 + Weapon: + Bow: true + Ammo: + Arrow: true + AmmoAmount: 7 + - Id: 5317 + Name: ABC_FROM_THE_ABYSS + Description: From The Abyss + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: + - Level: 1 + Time: 30000 + - Level: 2 + Time: 60000 + - Level: 3 + Time: 90000 + - Level: 4 + Time: 120000 + - Level: 5 + Time: 150000 + Duration2: + - Level: 1 + Time: 10000 + - Level: 2 + Time: 8000 + - Level: 3 + Time: 6000 + - Level: 4 + Time: 4000 + - Level: 5 + Time: 2000 + Cooldown: 60000 + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 50 + - Level: 3 + Amount: 60 + - Level: 4 + Amount: 70 + - Level: 5 + Amount: 80 + - Id: 5318 + Name: ABC_ABYSS_SLAYER + Description: Abyss Slayer + MaxLevel: 10 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 60000 + Cooldown: 60000 + FixedCastTime: 1000 + Requires: + SpCost: 100 + ApCost: 150 + - Id: 5319 + Name: ABC_ABYSS_STRIKE + Description: Abyss Strike + MaxLevel: 10 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 100 + Cooldown: 60000 + FixedCastTime: 1000 + Requires: + SpCost: 150 + ApCost: 150 + Unit: + Id: Dummyskill + Range: 4 + Interval: 1000 + Target: Enemy + Flag: + PathCheck: true + - Id: 5320 + Name: ABC_DEFT_STAB + Description: Deft Stab + MaxLevel: 10 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 2 + Hit: Multi_Hit + HitCount: -5 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 1 + - Level: 4 + Area: 1 + - Level: 5 + Area: 1 + - Level: 6 + Area: 2 + - Level: 7 + Area: 2 + - Level: 8 + Area: 2 + - Level: 9 + Area: 2 + - Level: 10 + Area: 2 + GiveAp: 2 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 2000 + Requires: + SpCost: + - Level: 1 + Amount: 28 + - Level: 2 + Amount: 31 + - Level: 3 + Amount: 34 + - Level: 4 + Amount: 37 + - Level: 5 + Amount: 40 + - Level: 6 + Amount: 43 + - Level: 7 + Amount: 46 + - Level: 8 + Amount: 49 + - Level: 9 + Amount: 52 + - Level: 10 + Amount: 55 + - Id: 5321 + Name: ABC_ABYSS_SQUARE + Description: Abyss Square + MaxLevel: 5 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Multi_Hit + HitCount: 1 + GiveAp: 4 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 4000 + Cooldown: 4000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 65 + - Level: 2 + Amount: 75 + - Level: 3 + Amount: 85 + - Level: 4 + Amount: 95 + - Level: 5 + Amount: 105 + Unit: + Id: Abyss_Square + Range: 3 + Interval: 700 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5322 + Name: ABC_FRENZY_SHOT + Description: Frenzy Shot + MaxLevel: 10 + Type: Weapon + TargetType: Attack + DamageFlags: + Critical: true + Range: 9 + Hit: Multi_Hit + HitCount: -10 + Element: Weapon + GiveAp: 2 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 2000 + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 45 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 55 + - Level: 5 + Amount: 60 + - Level: 6 + Amount: 65 + - Level: 7 + Amount: 70 + - Level: 8 + Amount: 75 + - Level: 9 + Amount: 80 + - Level: 10 + Amount: 85 + Weapon: + Bow: true + Ammo: + Arrow: true + AmmoAmount: 10 + - Id: 5323 + Name: WH_ADVANCED_TRAP + Description: Advanced Trap + MaxLevel: 5 + - Id: 5324 + Name: WH_WIND_SIGN + Description: Wind Sign + MaxLevel: 5 + TargetType: Attack + DamageFlags: + NoDamage: true + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: + - Level: 1 + Time: 20000 + - Level: 2 + Time: 30000 + - Level: 3 + Time: 40000 + - Level: 4 + Time: 50000 + - Level: 5 + Time: 60000 + Cooldown: 30000 + Requires: + SpCost: + - Level: 1 + Amount: 100 + - Level: 2 + Amount: 90 + - Level: 3 + Amount: 80 + - Level: 4 + Amount: 70 + - Level: 5 + Amount: 60 + - Id: 5325 + Name: WH_NATUREFRIENDLY + Description: Nature Friendly + MaxLevel: 5 + - Id: 5326 + Name: WH_HAWKRUSH + Description: Hawk Rush + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Critical: true + Range: 9 + Hit: Multi_Hit + HitCount: -2 + CastCancel: true + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 44 + - Level: 3 + Amount: 48 + - Level: 4 + Amount: 52 + - Level: 5 + Amount: 56 + Weapon: + Bow: true + State: Falcon + - Id: 5327 + Name: WH_HAWK_M + Description: Hawk Mastery + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 1000 + Requires: + SpCost: 5 + ItemCost: + - Item: Hawk_Flute + Amount: 0 + - Id: 5328 + Name: WH_CALAMITYGALE + Description: Calamity Gale + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Duration1: 60000 + Cooldown: 300000 + FixedCastTime: 1000 + Requires: + SpCost: 300 + ApCost: 200 + - Id: 5329 + Name: WH_HAWKBOOMERANG + Description: Hawk Boomerang + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Critical: true + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 800 + AfterCastActDelay: 500 + Cooldown: 30000 + FixedCastTime: 200 + Requires: + SpCost: 120 + ApCost: 50 + Weapon: + Bow: true + State: Falcon + - Id: 5330 + Name: WH_GALESTORM + Description: Gale Storm + MaxLevel: 10 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Critical: true + Range: 9 + Hit: Multi_Hit + HitCount: -5 + Element: Weapon + SplashArea: + - Level: 1 + Area: 2 + - Level: 2 + Area: 2 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + - Level: 6 + Area: 3 + - Level: 7 + Area: 3 + - Level: 8 + Area: 4 + - Level: 9 + Area: 4 + - Level: 10 + Area: 5 + CastCancel: true + CastTime: 3500 + AfterCastActDelay: 500 + Cooldown: 2000 + FixedCastTime: 500 + Requires: + SpCost: + - Level: 1 + Amount: 80 + - Level: 2 + Amount: 91 + - Level: 3 + Amount: 102 + - Level: 4 + Amount: 113 + - Level: 5 + Amount: 124 + - Level: 6 + Amount: 135 + - Level: 7 + Amount: 146 + - Level: 8 + Amount: 157 + - Level: 9 + Amount: 168 + - Level: 10 + Amount: 179 + Weapon: + Bow: true + Ammo: + Arrow: true + AmmoAmount: 5 + - Id: 5331 + Name: WH_DEEPBLINDTRAP + Description: Deep Blind Trap + MaxLevel: 5 + Type: Weapon + TargetType: Ground + DamageFlags: + IgnoreFlee: true + Range: 1 + Hit: Single + HitCount: 1 + Element: Dark + GiveAp: 3 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 12000 + - Level: 2 + Time: 24000 + - Level: 3 + Time: 36000 + - Level: 4 + Time: 48000 + - Level: 5 + Time: 60000 + Duration2: 20000 + Cooldown: 30000 + Requires: + SpCost: + - Level: 1 + Amount: 50 + - Level: 2 + Amount: 53 + - Level: 3 + Amount: 56 + - Level: 4 + Amount: 59 + - Level: 5 + Amount: 62 + ItemCost: + - Item: Special_Alloy_Trap + Amount: 2 + Unit: + Id: Deepblindtrap + Range: 1 + Interval: 3000 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5332 + Name: WH_SOLIDTRAP + Description: Solid Trap + MaxLevel: 5 + Type: Weapon + TargetType: Ground + DamageFlags: + IgnoreFlee: true + Range: 1 + Hit: Single + HitCount: 1 + Element: Earth + GiveAp: 3 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 12000 + - Level: 2 + Time: 24000 + - Level: 3 + Time: 36000 + - Level: 4 + Time: 48000 + - Level: 5 + Time: 60000 + Duration2: 10000 + Cooldown: 30000 + Requires: + SpCost: + - Level: 1 + Amount: 70 + - Level: 2 + Amount: 80 + - Level: 3 + Amount: 90 + - Level: 4 + Amount: 100 + - Level: 5 + Amount: 110 + ItemCost: + - Item: Special_Alloy_Trap + Amount: 2 + Unit: + Id: Solidtrap + Range: 1 + Interval: 3000 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5333 + Name: WH_SWIFTTRAP + Description: Swift Trap + MaxLevel: 5 + Type: Weapon + TargetType: Ground + DamageFlags: + IgnoreFlee: true + Range: 1 + Hit: Single + HitCount: 1 + Element: Wind + GiveAp: 3 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 12000 + - Level: 2 + Time: 24000 + - Level: 3 + Time: 36000 + - Level: 4 + Time: 48000 + - Level: 5 + Time: 60000 + Duration2: 10000 + Cooldown: 30000 + Requires: + SpCost: + - Level: 1 + Amount: 60 + - Level: 2 + Amount: 62 + - Level: 3 + Amount: 64 + - Level: 4 + Amount: 66 + - Level: 5 + Amount: 68 + ItemCost: + - Item: Special_Alloy_Trap + Amount: 2 + Unit: + Id: Swifttrap + Range: 1 + Interval: 3000 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5334 + Name: WH_CRESCIVE_BOLT + Description: Crescive Bolt + MaxLevel: 10 + Type: Weapon + TargetType: Attack + DamageFlags: + Critical: true + Range: 9 + Hit: Single + HitCount: 1 + Element: Weapon + GiveAp: 1 + CastCancel: true + CastTime: 800 + AfterCastActDelay: 500 + Duration1: 10000 + FixedCastTime: 200 + Requires: + SpCost: + - Level: 1 + Amount: 55 + - Level: 2 + Amount: 60 + - Level: 3 + Amount: 65 + - Level: 4 + Amount: 70 + - Level: 5 + Amount: 75 + - Level: 6 + Amount: 80 + - Level: 7 + Amount: 85 + - Level: 8 + Amount: 90 + - Level: 9 + Amount: 95 + - Level: 10 + Amount: 100 + Weapon: + Bow: true + Ammo: + Arrow: true + AmmoAmount: 1 + - Id: 5335 + Name: WH_FLAMETRAP + Description: Flame Trap + MaxLevel: 5 + Type: Weapon + TargetType: Ground + DamageFlags: + IgnoreFlee: true + Range: 1 + Hit: Single + HitCount: 1 + Element: Fire + GiveAp: 3 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 12000 + - Level: 2 + Time: 24000 + - Level: 3 + Time: 36000 + - Level: 4 + Time: 48000 + - Level: 5 + Time: 60000 + Duration2: 20000 + Cooldown: 30000 + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 44 + - Level: 3 + Amount: 48 + - Level: 4 + Amount: 52 + - Level: 5 + Amount: 56 + ItemCost: + - Item: Special_Alloy_Trap + Amount: 2 + Unit: + Id: Flametrap + Range: 1 + Interval: 3000 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5336 + Name: BO_BIONIC_PHARMACY + Description: Bionic Pharmacy + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Requires: + SpCost: 30 + - Id: 5337 + Name: BO_BIONICS_M + Description: Bionics Mastery + MaxLevel: 10 + - Id: 5338 + Name: BO_THE_WHOLE_PROTECTION + Description: The Whole Protection + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Splash: true + Hit: Single + HitCount: 1 + SplashArea: + - Level: 1 + Area: 7 + - Level: 2 + Area: 7 + - Level: 3 + Area: 7 + - Level: 4 + Area: 15 + - Level: 5 + Area: 15 + GiveAp: 20 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 60000 + - Level: 2 + Time: 90000 + - Level: 3 + Time: 120000 + - Level: 4 + Time: 150000 + - Level: 5 + Time: 180000 + Cooldown: 10000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 220 + - Level: 2 + Amount: 260 + - Level: 3 + Amount: 300 + - Level: 4 + Amount: 340 + - Level: 5 + Amount: 380 + ItemCost: + - Item: High_Coating_Bottle + Amount: 3 + - Id: 5339 + Name: BO_ADVANCE_PROTECTION + Description: Advance Protection + MaxLevel: 4 + TargetType: Support + DamageFlags: + NoDamage: true + Range: 1 + Hit: Single + HitCount: 1 + GiveAp: + - Level: 1 + Amount: 2 + - Level: 2 + Amount: 2 + - Level: 3 + Amount: 3 + - Level: 4 + Amount: 3 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 30000 + - Level: 2 + Time: 40000 + - Level: 3 + Time: 50000 + - Level: 4 + Time: 60000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 120 + - Level: 2 + Amount: 130 + - Level: 3 + Amount: 140 + - Level: 4 + Amount: 150 + ItemCost: + - Item: High_Coating_Bottle + Amount: 1 + - Id: 5340 + Name: BO_ACIDIFIED_ZONE_WATER + Description: Acidified Zone Water + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 7 + Hit: Multi_Hit + HitCount: -3 + Element: Water + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + GiveAp: + - Level: 1 + Amount: 4 + - Level: 2 + Amount: 4 + - Level: 3 + Amount: 4 + - Level: 4 + Amount: 5 + - Level: 5 + Amount: 5 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: 10000 + Cooldown: 2000 + FixedCastTime: 500 + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 52 + - Level: 3 + Amount: 64 + - Level: 4 + Amount: 76 + - Level: 5 + Amount: 88 + ItemCost: + - Item: Icicle_Acid_Bottle + Amount: 2 + Unit: + Id: Acidified_Zone_Water + Interval: 500 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5341 + Name: BO_ACIDIFIED_ZONE_GROUND + Description: Acidified Zone Ground + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 7 + Hit: Multi_Hit + HitCount: -3 + Element: Earth + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + GiveAp: + - Level: 1 + Amount: 4 + - Level: 2 + Amount: 4 + - Level: 3 + Amount: 4 + - Level: 4 + Amount: 5 + - Level: 5 + Amount: 5 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: 10000 + Cooldown: 2000 + FixedCastTime: 500 + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 52 + - Level: 3 + Amount: 64 + - Level: 4 + Amount: 76 + - Level: 5 + Amount: 88 + ItemCost: + - Item: Earth_Acid_Bottle + Amount: 2 + Unit: + Id: Acidified_Zone_Ground + Interval: 500 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5342 + Name: BO_ACIDIFIED_ZONE_WIND + Description: Acidified Zone Wind + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 7 + Hit: Multi_Hit + HitCount: -3 + Element: Wind + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + GiveAp: + - Level: 1 + Amount: 4 + - Level: 2 + Amount: 4 + - Level: 3 + Amount: 4 + - Level: 4 + Amount: 5 + - Level: 5 + Amount: 5 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: 10000 + Cooldown: 2000 + FixedCastTime: 500 + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 52 + - Level: 3 + Amount: 64 + - Level: 4 + Amount: 76 + - Level: 5 + Amount: 88 + ItemCost: + - Item: Gale_Acid_Bottle + Amount: 2 + Unit: + Id: Acidified_Zone_Wind + Interval: 500 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5343 + Name: BO_ACIDIFIED_ZONE_FIRE + Description: Acidified Zone Fire + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 7 + Hit: Multi_Hit + HitCount: -3 + Element: Fire + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + GiveAp: + - Level: 1 + Amount: 4 + - Level: 2 + Amount: 4 + - Level: 3 + Amount: 4 + - Level: 4 + Amount: 5 + - Level: 5 + Amount: 5 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: 10000 + Cooldown: 2000 + FixedCastTime: 500 + Requires: + SpCost: + - Level: 1 + Amount: 40 + - Level: 2 + Amount: 52 + - Level: 3 + Amount: 64 + - Level: 4 + Amount: 76 + - Level: 5 + Amount: 88 + ItemCost: + - Item: Flame_Acid_Bottle + Amount: 2 + Unit: + Id: Acidified_Zone_Fire + Interval: 500 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5344 + Name: BO_WOODENWARRIOR + Description: Wooden Warrior + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + ActiveInstance: 1 + GiveAp: 20 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 180000 + - Level: 3 + Time: 240000 + - Level: 4 + Time: 300000 + - Level: 5 + Time: 360000 + Cooldown: 30000 + FixedCastTime: 4000 + Requires: + SpCost: + - Level: 1 + Amount: 100 + - Level: 2 + Amount: 120 + - Level: 3 + Amount: 140 + - Level: 4 + Amount: 160 + - Level: 5 + Amount: 180 + ItemCost: + - Item: High_Plant_Bottle + Amount: 2 + - Id: 5345 + Name: BO_WOODEN_FAIRY + Description: Wooden Fairy + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + ActiveInstance: 1 + GiveAp: 20 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 180000 + - Level: 3 + Time: 240000 + - Level: 4 + Time: 300000 + - Level: 5 + Time: 360000 + Cooldown: 30000 + FixedCastTime: 4000 + Requires: + SpCost: + - Level: 1 + Amount: 120 + - Level: 2 + Amount: 155 + - Level: 3 + Amount: 180 + - Level: 4 + Amount: 205 + - Level: 5 + Amount: 230 + ItemCost: + - Item: High_Plant_Bottle + Amount: 2 + - Id: 5346 + Name: BO_CREEPER + Description: Creeper + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + ActiveInstance: 1 + GiveAp: 10 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 180000 + - Level: 3 + Time: 240000 + - Level: 4 + Time: 300000 + - Level: 5 + Time: 360000 + Cooldown: 30000 + FixedCastTime: 4000 + Requires: + SpCost: + - Level: 1 + Amount: 80 + - Level: 2 + Amount: 96 + - Level: 3 + Amount: 112 + - Level: 4 + Amount: 128 + - Level: 5 + Amount: 144 + ItemCost: + - Item: High_Plant_Bottle + Amount: 1 + - Id: 5347 + Name: BO_RESEARCHREPORT + Description: Research Report + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 60000 + Cooldown: 120000 + FixedCastTime: 1000 + Requires: + SpCost: 60 + ApCost: 100 + - Id: 5348 + Name: BO_HELLTREE + Description: Hell Tree + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + ActiveInstance: 1 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 60000 + - Level: 2 + Time: 90000 + - Level: 3 + Time: 120000 + - Level: 4 + Time: 150000 + - Level: 5 + Time: 180000 + Cooldown: 60000 + FixedCastTime: 4000 + Requires: + SpCost: 100 + ApCost: 100 + ItemCost: + - Item: High_Plant_Bottle + Amount: 3 + - Id: 5349 + Name: TR_STAGE_MANNER + Description: Stage Manner + MaxLevel: 5 + CastCancel: true + - Id: 5350 + Name: TR_RETROSPECTION + Description: Retrospection + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + Requires: + SpCost: 1 + - Id: 5351 + Name: TR_MYSTIC_SYMPHONY + Description: Mystic Symphony + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 60000 + Cooldown: 120000 + FixedCastTime: 1000 + Requires: + SpCost: 250 + ApCost: 100 + Weapon: + Bow: true + Musical: true + Whip: true + - Id: 5352 + Name: TR_KVASIR_SONATA + Description: Kvasir Sonata + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 60000 + Cooldown: 120000 + FixedCastTime: 1000 + Requires: + SpCost: 300 + ApCost: 100 + Weapon: + Bow: true + Musical: true + Whip: true + - Id: 5353 + Name: TR_ROSEBLOSSOM + Description: Rose Blossom + MaxLevel: 5 + Type: Weapon + TargetType: Attack + Range: 9 + Hit: Multi_Hit + HitCount: -2 + Element: Weapon + GiveAp: 5 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: 500 + Cooldown: 3000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 215 + - Level: 2 + Amount: 230 + - Level: 3 + Amount: 245 + - Level: 4 + Amount: 260 + - Level: 5 + Amount: 275 + Weapon: + Bow: true + Musical: true + Whip: true + Ammo: + Arrow: true + AmmoAmount: 1 + - Id: 5354 + Name: TR_ROSEBLOSSOM_ATK + Description: Rose Blossom Attack + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + Splash: true + Range: 9 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + Requires: + SpCost: 1 + - Id: 5355 + Name: TR_RHYTHMSHOOTING + Description: Rhythm Shooting + MaxLevel: 5 + Type: Weapon + TargetType: Attack + Range: 9 + Hit: Multi_Hit + HitCount: 3 + Element: Weapon + GiveAp: + - Level: 1 + Amount: 1 + - Level: 2 + Amount: 1 + - Level: 3 + Amount: 1 + - Level: 4 + Amount: 2 + - Level: 5 + Amount: 2 + CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Cooldown: 1000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 80 + - Level: 2 + Amount: 92 + - Level: 3 + Amount: 104 + - Level: 4 + Amount: 116 + - Level: 5 + Amount: 128 + Weapon: + Bow: true + Musical: true + Whip: true + Ammo: + Arrow: true + AmmoAmount: 1 + - Id: 5356 + Name: TR_METALIC_FURY + Description: Metalic Fury + MaxLevel: 5 + Type: Magic + TargetType: Attack + DamageFlags: + Splash: true + Range: 9 + Hit: Multi_Hit + HitCount: 1 + Element: Weapon + SplashArea: + - Level: 1 + Area: 2 + - Level: 2 + Area: 2 + - Level: 3 + Area: 2 + - Level: 4 + Area: 3 + - Level: 5 + Area: 3 + GiveAp: + - Level: 1 + Amount: 4 + - Level: 2 + Amount: 4 + - Level: 3 + Amount: 4 + - Level: 4 + Amount: 5 + - Level: 5 + Amount: 5 + CastCancel: true + Cooldown: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 120 + - Level: 2 + Amount: 132 + - Level: 3 + Amount: 144 + - Level: 4 + Amount: 156 + - Level: 5 + Amount: 168 + Weapon: + Musical: true + Whip: true + Ammo: + Arrow: true + AmmoAmount: 1 + - Id: 5357 + Name: TR_SOUNDBLEND + Description: Sound Blend + MaxLevel: 5 + Type: Magic + TargetType: Attack + DamageFlags: + NoDamage: true + Range: 9 + Hit: Single + HitCount: 1 + Element: Weapon + GiveAp: + - Level: 1 + Amount: 2 + - Level: 2 + Amount: 2 + - Level: 3 + Amount: 2 + - Level: 4 + Amount: 3 + - Level: 5 + Amount: 3 + CastCancel: true + CastTime: 1000 + Duration1: + - Level: 1 + Time: 10000 + - Level: 2 + Time: 10000 + - Level: 3 + Time: 15000 + - Level: 4 + Time: 15000 + - Level: 5 + Time: 20000 + Cooldown: 1000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 80 + - Level: 2 + Amount: 92 + - Level: 3 + Amount: 104 + - Level: 4 + Amount: 116 + - Level: 5 + Amount: 128 + Weapon: + Musical: true + Whip: true + - Id: 5358 + Name: TR_GEF_NOCTURN + Description: Geffenia Nocturn + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Splash: true + Hit: Single + HitCount: 1 + SplashArea: + - Level: 1 + Area: 7 + - Level: 2 + Area: 8 + - Level: 3 + Area: 9 + - Level: 4 + Area: 10 + - Level: 5 + Area: 11 + GiveAp: 20 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 30000 + Cooldown: 10000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 120 + - Level: 2 + Amount: 160 + - Level: 3 + Amount: 200 + - Level: 4 + Amount: 240 + - Level: 5 + Amount: 280 + Weapon: + Musical: true + Whip: true + ItemCost: + - Item: Protect_Neck_Candy + Amount: 1 + - Id: 5359 + Name: TR_ROKI_CAPRICCIO + Description: Roki Capriccio + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Splash: true + Hit: Single + HitCount: 1 + SplashArea: + - Level: 1 + Area: 7 + - Level: 2 + Area: 8 + - Level: 3 + Area: 9 + - Level: 4 + Area: 10 + - Level: 5 + Area: 11 + GiveAp: 20 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 20000 + Duration2: 20000 + Cooldown: 10000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 120 + - Level: 2 + Amount: 160 + - Level: 3 + Amount: 200 + - Level: 4 + Amount: 240 + - Level: 5 + Amount: 280 + Weapon: + Musical: true + Whip: true + ItemCost: + - Item: Protect_Neck_Candy + Amount: 1 + - Id: 5360 + Name: TR_AIN_RHAPSODY + Description: Ain Rhapsody + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Splash: true + Hit: Single + HitCount: 1 + SplashArea: + - Level: 1 + Area: 7 + - Level: 2 + Area: 8 + - Level: 3 + Area: 9 + - Level: 4 + Area: 10 + - Level: 5 + Area: 11 + GiveAp: 20 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 30000 + Cooldown: 10000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 120 + - Level: 2 + Amount: 160 + - Level: 3 + Amount: 200 + - Level: 4 + Amount: 240 + - Level: 5 + Amount: 280 + Weapon: + Musical: true + Whip: true + ItemCost: + - Item: Protect_Neck_Candy + Amount: 1 + - Id: 5361 + Name: TR_MUSICAL_INTERLUDE + Description: Musical Interlude + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Splash: true + Hit: Single + HitCount: 1 + SplashArea: + - Level: 1 + Area: 7 + - Level: 2 + Area: 8 + - Level: 3 + Area: 9 + - Level: 4 + Area: 10 + - Level: 5 + Area: 11 + GiveAp: 10 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 180000 + Cooldown: 10000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 171 + - Level: 2 + Amount: 182 + - Level: 3 + Amount: 193 + - Level: 4 + Amount: 204 + - Level: 5 + Amount: 215 + Weapon: + Musical: true + Whip: true + ItemCost: + - Item: Protect_Neck_Candy + Amount: 1 + - Id: 5362 + Name: TR_JAWAII_SERENADE + Description: Jawaii Serenade + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Splash: true + Hit: Single + HitCount: 1 + SplashArea: + - Level: 1 + Area: 7 + - Level: 2 + Area: 8 + - Level: 3 + Area: 9 + - Level: 4 + Area: 10 + - Level: 5 + Area: 11 + GiveAp: 10 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 180000 + Cooldown: 10000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 140 + - Level: 2 + Amount: 150 + - Level: 3 + Amount: 160 + - Level: 4 + Amount: 170 + - Level: 5 + Amount: 180 + Weapon: + Musical: true + Whip: true + ItemCost: + - Item: Protect_Neck_Candy + Amount: 1 + - Id: 5363 + Name: TR_NIPELHEIM_REQUIEM + Description: Nipelheim Requiem + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Splash: true + Hit: Single + HitCount: 1 + SplashArea: + - Level: 1 + Area: 7 + - Level: 2 + Area: 8 + - Level: 3 + Area: 9 + - Level: 4 + Area: 10 + - Level: 5 + Area: 11 + GiveAp: 20 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 20000 + Duration2: 20000 + Cooldown: 10000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 120 + - Level: 2 + Amount: 160 + - Level: 3 + Amount: 200 + - Level: 4 + Amount: 240 + - Level: 5 + Amount: 280 + Weapon: + Musical: true + Whip: true + ItemCost: + - Item: Protect_Neck_Candy + Amount: 1 + - Id: 5364 + Name: TR_PRON_MARCH + Description: Pron March + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Splash: true + Hit: Single + HitCount: 1 + SplashArea: + - Level: 1 + Area: 7 + - Level: 2 + Area: 8 + - Level: 3 + Area: 9 + - Level: 4 + Area: 10 + - Level: 5 + Area: 11 + GiveAp: 10 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 180000 + Cooldown: 10000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 140 + - Level: 2 + Amount: 150 + - Level: 3 + Amount: 160 + - Level: 4 + Amount: 170 + - Level: 5 + Amount: 180 + Weapon: + Musical: true + Whip: true + ItemCost: + - Item: Protect_Neck_Candy + Amount: 1 + - Id: 5365 + Name: EM_MAGIC_BOOK_M + Description: Magic Book Mastery + MaxLevel: 10 + - Id: 5366 + Name: EM_SPELL_ENCHANTING + Description: Spell Enchanting + MaxLevel: 5 + TargetType: Support + DamageFlags: + NoDamage: true + Flags: + PartyOnly: true + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 80000 + - Level: 2 + Time: 120000 + - Level: 3 + Time: 160000 + - Level: 4 + Time: 200000 + - Level: 5 + Time: 240000 + Requires: + SpCost: + - Level: 1 + Amount: 43 + - Level: 2 + Amount: 46 + - Level: 3 + Amount: 49 + - Level: 4 + Amount: 52 + - Level: 5 + Amount: 55 + - Id: 5367 + Name: EM_ACTIVITY_BURN + Description: Activity Burn + MaxLevel: 5 + TargetType: Attack + DamageFlags: + NoDamage: true + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Cooldown: 60000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 40 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 60 + - Level: 5 + Amount: 70 + - Id: 5368 + Name: EM_INCREASING_ACTIVITY + Description: Increasing Activity + MaxLevel: 5 + TargetType: Support + DamageFlags: + NoDamage: true + Flags: + NoTargetSelf: true + PartyOnly: true + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Cooldown: 5000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 30 + - Level: 2 + Amount: 40 + - Level: 3 + Amount: 50 + - Level: 4 + Amount: 60 + - Level: 5 + Amount: 70 + ApCost: 50 + - Id: 5369 + Name: EM_DIAMOND_STORM + Description: Diamond Storm + MaxLevel: 5 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Multi_Hit + HitCount: -5 + Element: Water + GiveAp: 4 + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 500 + Duration1: 100 + Duration2: 10000 + Cooldown: 4000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 84 + - Level: 2 + Amount: 88 + - Level: 3 + Amount: 92 + - Level: 4 + Amount: 96 + - Level: 5 + Amount: 100 + Unit: + Id: Dummyskill + Range: 4 + Interval: 1000 + Target: Enemy + Flag: + PathCheck: true + - Id: 5370 + Name: EM_LIGHTNING_LAND + Description: Lightning Land + MaxLevel: 5 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Single + HitCount: 1 + Element: Wind + GiveAp: 4 + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 500 + Duration1: 4000 + Duration2: 10000 + Cooldown: 4000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 65 + - Level: 2 + Amount: 70 + - Level: 3 + Amount: 80 + - Level: 4 + Amount: 85 + - Level: 5 + Amount: 95 + Unit: + Id: Lightning_Land + Range: 4 + Interval: 500 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5371 + Name: EM_VENOM_SWAMP + Description: Venom Swamp + MaxLevel: 5 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Single + HitCount: 1 + Element: Poison + GiveAp: 4 + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 500 + Duration1: 4000 + Duration2: 20000 + Cooldown: 4000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 84 + - Level: 2 + Amount: 88 + - Level: 3 + Amount: 92 + - Level: 4 + Amount: 96 + - Level: 5 + Amount: 100 + Unit: + Id: Venom_Swamp + Range: 4 + Interval: 500 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5372 + Name: EM_CONFLAGRATION + Description: Conflagration + MaxLevel: 5 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Single + HitCount: 1 + Element: Fire + GiveAp: 4 + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 500 + Duration1: 4000 + Duration2: 20000 + Cooldown: 4000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 70 + - Level: 2 + Amount: 80 + - Level: 3 + Amount: 90 + - Level: 4 + Amount: 100 + - Level: 5 + Amount: 110 + Unit: + Id: Conflagration + Range: 4 + Interval: 500 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + - Id: 5373 + Name: EM_TERRA_DRIVE + Description: Terra Drive + MaxLevel: 5 + Type: Magic + TargetType: Ground + Range: 9 + Hit: Multi_Hit + HitCount: -5 + Element: Earth + GiveAp: 4 + CastCancel: true + CastTime: 4000 + AfterCastActDelay: 500 + Duration1: 100 + Duration2: 10000 + Cooldown: 4000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 84 + - Level: 2 + Amount: 88 + - Level: 3 + Amount: 92 + - Level: 4 + Amount: 96 + - Level: 5 + Amount: 100 + Unit: + Id: Dummyskill + Range: 4 + Interval: 1000 + Target: Enemy + Flag: + PathCheck: true + - Id: 5374 + Name: EM_ELEMENTAL_SPIRIT_M + Description: Elemental Spirit Mastery + MaxLevel: 10 + - Id: 5375 + Name: EM_SUMMON_ELEMENTAL_ARDOR + Description: Summon Elemental Ardor + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 3000 + AfterCastActDelay: 500 + Duration1: 1500000 + Cooldown: 900000 + FixedCastTime: 2000 + Requires: + SpCost: 100 + ItemCost: + - Item: Flame_Stone_4th + Amount: 1 + - Id: 5376 + Name: EM_SUMMON_ELEMENTAL_DILUVIO + Description: Summon Elemental Diluvio + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 3000 + AfterCastActDelay: 500 + Duration1: 1500000 + Cooldown: 900000 + FixedCastTime: 2000 + Requires: + SpCost: 100 + ItemCost: + - Item: Ice_Stone_4th + Amount: 1 + - Id: 5377 + Name: EM_SUMMON_ELEMENTAL_PROCELLA + Description: Summon Elemental Procella + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 3000 + AfterCastActDelay: 500 + Duration1: 1500000 + Cooldown: 900000 + FixedCastTime: 2000 + Requires: + SpCost: 100 + ItemCost: + - Item: Wind_Stone_4th + Amount: 1 + - Id: 5378 + Name: EM_SUMMON_ELEMENTAL_TERREMOTUS + Description: Summon Elemental Terremotus + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 3000 + AfterCastActDelay: 500 + Duration1: 1500000 + Cooldown: 900000 + FixedCastTime: 2000 + Requires: + SpCost: 100 + ItemCost: + - Item: Earth_Stone_4th + Amount: 1 + - Id: 5379 + Name: EM_SUMMON_ELEMENTAL_SERPENS + Description: Summon Elemental Serpens + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 3000 + AfterCastActDelay: 500 + Duration1: 1500000 + Cooldown: 900000 + FixedCastTime: 2000 + Requires: + SpCost: 100 + ItemCost: + - Item: Poison_Stone_4th + Amount: 1 + - Id: 5380 + Name: EM_ELEMENTAL_BUSTER + Description: Elemental Buster + MaxLevel: 10 + Type: Magic + TargetType: Self + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 8000 + AfterCastActDelay: 500 + Cooldown: 60000 + FixedCastTime: 2000 + Requires: + SpCost: 150 + ApCost: 150 + - Id: 5381 + Name: EM_ELEMENTAL_VEIL + Description: Elemental Veil + MaxLevel: 5 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 150000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 210000 + - Level: 5 + Time: 240000 + Cooldown: 10000 + FixedCastTime: 1000 + Requires: + SpCost: + - Level: 1 + Amount: 70 + - Level: 2 + Amount: 75 + - Level: 3 + Amount: 80 + - Level: 4 + Amount: 85 + - Level: 5 + Amount: 90 + - Id: 5382 + Name: ABC_CHAIN_REACTION_SHOT_ATK + Description: Chain Reaction Shot Attack + MaxLevel: 5 + Type: Weapon + TargetType: Attack + DamageFlags: + IgnoreFlee: true + Range: 9 + Hit: Multi_Hit + HitCount: -2 + Element: Weapon + Requires: + SpCost: 1 + - Id: 5383 + Name: ABC_FROM_THE_ABYSS_ATK + Description: From The Abyss Attack + MaxLevel: 5 + Type: Magic + TargetType: Attack + DamageFlags: + Splash: true + Range: 1 + Hit: Single + HitCount: 1 + SplashArea: 3 + Requires: + SpCost: 1 + - Id: 5384 + Name: BO_WOODEN_THROWROCK + Description: Wooden Throw Rock + MaxLevel: 1 + TargetType: Attack + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 5000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 5385 + Name: BO_WOODEN_ATTACK + Description: Wooden Attack + MaxLevel: 1 + TargetType: Attack + Range: 1 + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 5000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 5386 + Name: BO_HELL_HOWLING + Description: Hell Howling + MaxLevel: 1 + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 15000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 5387 + Name: BO_HELL_DUSTY + Description: Hell Dusty + MaxLevel: 1 + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Duration1: 30000 + Cooldown: 30000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 5388 + Name: BO_FAIRY_DUSTY + Description: Fairy Dusty + MaxLevel: 1 + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 5000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 5389 + Name: EM_ELEMENTAL_BUSTER_FIRE + Description: Elemental Buster Fire + MaxLevel: 10 + Type: Magic + TargetType: Self + DamageFlags: + Splash: true + Hit: Single + HitCount: -10 + Element: Fire + SplashArea: 6 + Requires: + SpCost: 1 + - Id: 5390 + Name: EM_ELEMENTAL_BUSTER_WATER + Description: Elemental Buster Water + MaxLevel: 10 + Type: Magic + TargetType: Self + DamageFlags: + Splash: true + Hit: Single + HitCount: -10 + Element: Water + SplashArea: 6 + Requires: + SpCost: 1 + - Id: 5391 + Name: EM_ELEMENTAL_BUSTER_WIND + Description: Elemental Buster Wind + MaxLevel: 10 + Type: Magic + TargetType: Self + DamageFlags: + Splash: true + Hit: Single + HitCount: -10 + Element: Wind + SplashArea: 6 + Requires: + SpCost: 1 + - Id: 5392 + Name: EM_ELEMENTAL_BUSTER_GROUND + Description: Elemental Buster Ground + MaxLevel: 10 + Type: Magic + TargetType: Self + DamageFlags: + Splash: true + Hit: Single + HitCount: -10 + Element: Earth + SplashArea: 6 + Requires: + SpCost: 1 + - Id: 5393 + Name: EM_ELEMENTAL_BUSTER_POISON + Description: Elemental Buster Poison + MaxLevel: 10 + Type: Magic + TargetType: Self + DamageFlags: + Splash: true + Hit: Single + HitCount: -10 + Element: Poison + SplashArea: 6 + Requires: + SpCost: 1 - Id: 8001 Name: HLIF_HEAL Description: Healing Touch @@ -37459,6 +43595,315 @@ Body: SplashArea: 1 Requires: SpCost: 80 + - Id: 8443 + Name: EM_EL_FLAMETECHNIC + Description: Flame Technic + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: -1 + Requires: + SpCost: 1 + - Id: 8444 + Name: EM_EL_FLAMEARMOR + Description: Flame Armor + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: -1 + Requires: + SpCost: 1 + - Id: 8445 + Name: EM_EL_FLAMEROCK + Description: Flame Rock + MaxLevel: 1 + Type: Magic + TargetType: Attack + DamageFlags: + Splash: true + IgnoreDefense: true + Range: 6 + Hit: Multi_Hit + HitCount: -2 + Element: Fire + SplashArea: 3 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 3000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 8446 + Name: EM_EL_COLD_FORCE + Description: Cold Force + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: -1 + Requires: + SpCost: 1 + - Id: 8447 + Name: EM_EL_CRYSTAL_ARMOR + Description: Crystal Armor + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: -1 + Requires: + SpCost: 1 + - Id: 8448 + Name: EM_EL_AGE_OF_ICE + Description: Age Of Ice + MaxLevel: 1 + Type: Magic + TargetType: Attack + DamageFlags: + Splash: true + IgnoreDefense: true + Range: 9 + Hit: Multi_Hit + HitCount: -4 + Element: Water + SplashArea: 5 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 3000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 8449 + Name: EM_EL_GRACE_BREEZE + Description: Grace Breeze + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: -1 + Requires: + SpCost: 1 + - Id: 8450 + Name: EM_EL_EYES_OF_STORM + Description: Eyes Of Storm + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: -1 + Requires: + SpCost: 1 + - Id: 8451 + Name: EM_EL_STORM_WIND + Description: Storm Wind + MaxLevel: 1 + Type: Magic + TargetType: Attack + DamageFlags: + Splash: true + IgnoreDefense: true + Range: 11 + Hit: Multi_Hit + HitCount: -4 + Element: Wind + SplashArea: 2 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 3000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 8452 + Name: EM_EL_EARTH_CARE + Description: Earth Care + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: -1 + Requires: + SpCost: 1 + - Id: 8453 + Name: EM_EL_STRONG_PROTECTION + Description: Strong Protection + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: -1 + Requires: + SpCost: 1 + - Id: 8454 + Name: EM_EL_AVALANCHE + Description: Avalanche + MaxLevel: 1 + Type: Magic + TargetType: Attack + DamageFlags: + Splash: true + IgnoreDefense: true + Range: 5 + Hit: Multi_Hit + HitCount: 7 + Element: Earth + SplashArea: 4 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 3000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 8455 + Name: EM_EL_DEEP_POISONING + Description: Deep Poisoning + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: -1 + Requires: + SpCost: 1 + - Id: 8456 + Name: EM_EL_POISON_SHIELD + Description: Poison Shield + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 + CastCancel: true + Duration1: -1 + Requires: + SpCost: 1 + - Id: 8457 + Name: EM_EL_DEADLY_POISON + Description: Deadly Poison + MaxLevel: 1 + Type: Magic + TargetType: Attack + DamageFlags: + Splash: true + IgnoreDefense: true + Range: 5 + Hit: Multi_Hit + HitCount: 5 + Element: Poison + SplashArea: 4 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 3000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 8601 + Name: ABR_BATTLE_BUSTER + Description: Battle Buster + MaxLevel: 1 + Type: Weapon + TargetType: Attack + Range: 1 + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 5000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 8602 + Name: ABR_DUAL_CANNON_FIRE + Description: Dual Cannon Fire + MaxLevel: 1 + Type: Weapon + TargetType: Attack + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 5000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 8603 + Name: ABR_NET_REPAIR + Description: Net Repair + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Splash: true + Hit: Single + HitCount: 1 + SplashArea: 12 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 5000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 8604 + Name: ABR_NET_SUPPORT + Description: Net Support + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + Splash: true + Hit: Single + HitCount: 1 + SplashArea: 12 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 5000 + FixedCastTime: 500 + Requires: + SpCost: 1 + - Id: 8605 + Name: ABR_INFINITY_BUSTER + Description: Infinity Buster + MaxLevel: 1 + Type: Weapon + TargetType: Attack + Range: 9 + Hit: Single + HitCount: 1 + CastCancel: true + AfterCastActDelay: 500 + Cooldown: 5000 + FixedCastTime: 500 + Requires: + SpCost: 1 - Id: 10000 Name: GD_APPROVAL Description: Official Guild Approval diff --git a/db/re/skill_nocast_db.txt b/db/re/skill_nocast_db.txt index c530a3a99f..f3ed6c9465 100644 --- a/db/re/skill_nocast_db.txt +++ b/db/re/skill_nocast_db.txt @@ -41,6 +41,9 @@ 2433,1 //WM_BEYOND_OF_WARCRY 2455,1 //SO_ARRULLO 2299,1 //SC_MANHOLE +5359,1 //TR_ROKI_CAPRICCIO +5363,1 //TR_NIPELHEIM_REQUIEM +5367,1 //EM_ACTIVITY_BURN //---------------------------------------------------------------------------- // PVP diff --git a/db/re/skill_tree.yml b/db/re/skill_tree.yml index 8b1904bc9e..276b3e9c6e 100644 --- a/db/re/skill_tree.yml +++ b/db/re/skill_tree.yml @@ -6643,3 +6643,1190 @@ Body: Taekwon: true Star_Gladiator: true Star_Emperor: true + - Job: Dragon_Knight + Inherit: + Novice: true + Swordman: true + Knight: true + Lord_Knight: true + Rune_Knight: true + Rune_Knight_T: true + Tree: + - Name: DK_SERVANTWEAPON + MaxLevel: 5 + - Name: DK_SERVANT_W_SIGN + MaxLevel: 5 + Requires: + - Name: DK_SERVANTWEAPON + Level: 3 + - Name: DK_SERVANT_W_PHANTOM + MaxLevel: 5 + Requires: + - Name: DK_SERVANTWEAPON + Level: 5 + - Name: DK_SERVANT_W_SIGN + Level: 5 + - Name: DK_SERVANT_W_DEMOL + MaxLevel: 5 + Requires: + - Name: DK_SERVANT_W_PHANTOM + Level: 5 + - Name: DK_CHARGINGPIERCE + MaxLevel: 10 + Requires: + - Name: RK_HUNDREDSPEAR + Level: 5 + - Name: DK_TWOHANDDEF + MaxLevel: 10 + - Name: DK_HACKANDSLASHER + MaxLevel: 10 + Requires: + - Name: DK_TWOHANDDEF + Level: 5 + - Name: DK_DRAGONIC_AURA + MaxLevel: 10 + Requires: + - Name: DK_CHARGINGPIERCE + Level: 10 + - Name: RK_DRAGONBREATH + Level: 10 + - Name: RK_DRAGONBREATH_WATER + Level: 10 + - Name: DK_MADNESS_CRUSHER + MaxLevel: 5 + Requires: + - Name: DK_CHARGINGPIERCE + Level: 5 + - Name: DK_HACKANDSLASHER + Level: 10 + - Name: DK_VIGOR + MaxLevel: 10 + Requires: + - Name: DK_SERVANT_W_DEMOL + Level: 3 + - Name: DK_STORMSLASH + Level: 5 + - Name: DK_STORMSLASH + MaxLevel: 5 + Requires: + - Name: DK_HACKANDSLASHER + Level: 5 + - Name: DK_TWOHANDDEF + Level: 10 + - Job: Meister + Inherit: + Novice: true + Merchant: true + Blacksmith: true + Whitesmith: true + Mechanic: true + Mechanic_T: true + Tree: + - Name: MT_AXE_STOMP + MaxLevel: 5 + Requires: + - Name: MT_TWOAXEDEF + Level: 5 + - Name: MT_RUSH_QUAKE + MaxLevel: 10 + Requires: + - Name: MT_AXE_STOMP + Level: 5 + - Name: MT_M_MACHINE + MaxLevel: 5 + - Name: MT_A_MACHINE + MaxLevel: 5 + Requires: + - Name: MT_AXE_STOMP + Level: 3 + - Name: MT_M_MACHINE + Level: 3 + - Name: MT_D_MACHINE + MaxLevel: 5 + Requires: + - Name: MT_M_MACHINE + Level: 1 + - Name: MT_TWOAXEDEF + MaxLevel: 10 + - Name: MT_ABR_M + MaxLevel: 10 + Requires: + - Name: MT_M_MACHINE + Level: 1 + - Name: MT_SUMMON_ABR_BATTLE_WARIOR + MaxLevel: 4 + Requires: + - Name: MT_ABR_M + Level: 1 + - Name: MT_SUMMON_ABR_DUAL_CANNON + MaxLevel: 4 + Requires: + - Name: MT_ABR_M + Level: 3 + - Name: MT_SUMMON_ABR_BATTLE_WARIOR + Level: 2 + - Name: MT_SUMMON_ABR_MOTHER_NET + MaxLevel: 4 + Requires: + - Name: MT_ABR_M + Level: 5 + - Name: MT_SUMMON_ABR_BATTLE_WARIOR + Level: 3 + - Name: MT_SUMMON_ABR_DUAL_CANNON + Level: 3 + - Name: MT_SUMMON_ABR_INFINITY + MaxLevel: 4 + Requires: + - Name: MT_ABR_M + Level: 10 + - Name: MT_SUMMON_ABR_BATTLE_WARIOR + Level: 4 + - Name: MT_SUMMON_ABR_DUAL_CANNON + Level: 4 + - Name: MT_SUMMON_ABR_MOTHER_NET + Level: 4 + - Job: Shadow_Cross + Inherit: + Novice: true + Thief: true + Assassin: true + Assassin_Cross: true + Guillotine_Cross: true + Guillotine_Cross_T: true + Tree: + - Name: SHC_SHADOW_EXCEED + MaxLevel: 10 + Requires: + - Name: SHC_ENCHANTING_SHADOW + Level: 5 + - Name: SHC_POTENT_VENOM + Level: 3 + - Name: SHC_SHADOW_SENSE + Level: 7 + - Name: SHC_DANCING_KNIFE + MaxLevel: 5 + Requires: + - Name: SHC_SHADOW_SENSE + Level: 3 + - Name: SHC_SAVAGE_IMPACT + MaxLevel: 10 + Requires: + - Name: GC_CROSSIMPACT + Level: 5 + - Name: SHC_SHADOW_SENSE + Level: 3 + - Name: SHC_SHADOW_SENSE + MaxLevel: 10 + - Name: SHC_ETERNAL_SLASH + MaxLevel: 5 + Requires: + - Name: GC_WEAPONBLOCKING + Level: 3 + - Name: SHC_DANCING_KNIFE + Level: 3 + - Name: SHC_SHADOW_SENSE + Level: 5 + - Name: SHC_POTENT_VENOM + MaxLevel: 10 + Requires: + - Name: SHC_ENCHANTING_SHADOW + Level: 3 + - Name: SHC_SHADOW_SENSE + Level: 5 + - Name: SHC_SHADOW_STAB + MaxLevel: 5 + Requires: + - Name: GC_CLOAKINGEXCEED + Level: 5 + - Name: SHC_DANCING_KNIFE + Level: 5 + - Name: SHC_ETERNAL_SLASH + Level: 3 + - Name: SHC_SHADOW_SENSE + Level: 5 + - Name: SHC_IMPACT_CRATER + MaxLevel: 5 + Requires: + - Name: GC_ROLLINGCUTTER + Level: 5 + - Name: GC_WEAPONBLOCKING + Level: 3 + - Name: SHC_SAVAGE_IMPACT + Level: 5 + - Name: SHC_SHADOW_SENSE + Level: 5 + - Name: SHC_ENCHANTING_SHADOW + MaxLevel: 5 + Requires: + - Name: GC_POISONINGWEAPON + Level: 5 + - Name: SHC_SHADOW_SENSE + Level: 3 + - Name: SHC_FATAL_SHADOW_CROW + MaxLevel: 10 + Requires: + - Name: SHC_IMPACT_CRATER + Level: 5 + - Name: SHC_SHADOW_STAB + Level: 5 + - Job: Arch_Mage + Inherit: + Novice: true + Mage: true + Wizard: true + High_Wizard: true + Warlock: true + Warlock_T: true + Tree: + - Name: AG_DEADLY_PROJECTION + MaxLevel: 5 + Requires: + - Name: AG_MYSTERY_ILLUSION + Level: 3 + - Name: AG_DESTRUCTIVE_HURRICANE + MaxLevel: 5 + Requires: + - Name: AG_TORNADO_STORM + Level: 3 + - Name: AG_RAIN_OF_CRYSTAL + MaxLevel: 5 + Requires: + - Name: WL_FROSTMISTY + Level: 3 + - Name: AG_MYSTERY_ILLUSION + MaxLevel: 5 + Requires: + - Name: AG_SOUL_VC_STRIKE + Level: 3 + - Name: WL_HELLINFERNO + Level: 3 + - Name: AG_VIOLENT_QUAKE + MaxLevel: 5 + Requires: + - Name: AG_STRANTUM_TREMOR + Level: 3 + - Name: AG_SOUL_VC_STRIKE + MaxLevel: 5 + Requires: + - Name: AG_TWOHANDSTAFF + Level: 3 + - Name: WL_SOULEXPANSION + Level: 5 + - Name: AG_STRANTUM_TREMOR + MaxLevel: 5 + Requires: + - Name: WL_SIENNAEXECRATE + Level: 3 + - Name: AG_ALL_BLOOM + MaxLevel: 5 + Requires: + - Name: AG_FLORAL_FLARE_ROAD + Level: 3 + - Name: AG_CRYSTAL_IMPACT + MaxLevel: 5 + Requires: + - Name: AG_RAIN_OF_CRYSTAL + Level: 3 + - Name: AG_TORNADO_STORM + MaxLevel: 5 + Requires: + - Name: WL_CHAINLIGHTNING + Level: 3 + - Name: AG_TWOHANDSTAFF + MaxLevel: 10 + - Name: AG_FLORAL_FLARE_ROAD + MaxLevel: 5 + Requires: + - Name: WL_CRIMSONROCK + Level: 3 + - Name: AG_ASTRAL_STRIKE + MaxLevel: 10 + Requires: + - Name: AG_DEADLY_PROJECTION + Level: 3 + - Name: AG_MYSTERY_ILLUSION + Level: 3 + - Name: WL_COMET + Level: 5 + - Name: AG_CLIMAX + MaxLevel: 5 + Requires: + - Name: AG_TWOHANDSTAFF + Level: 3 + - Name: WL_TETRAVORTEX + Level: 5 + - Name: AG_ROCK_DOWN + MaxLevel: 5 + Requires: + - Name: AG_STRANTUM_TREMOR + Level: 1 + - Name: AG_STORM_CANNON + MaxLevel: 5 + Requires: + - Name: AG_TORNADO_STORM + Level: 1 + - Name: AG_CRIMSON_ARROW + MaxLevel: 5 + Requires: + - Name: AG_FLORAL_FLARE_ROAD + Level: 1 + - Name: AG_FROZEN_SLASH + MaxLevel: 5 + Requires: + - Name: AG_RAIN_OF_CRYSTAL + Level: 1 + - Job: Cardinal + Inherit: + Novice: true + Acolyte: true + Priest: true + High_Priest: true + Arch_Bishop: true + Arch_Bishop_T: true + Tree: + - Name: CD_REPARATIO + MaxLevel: 5 + Requires: + - Name: CD_MEDIALE_VOTUM + Level: 3 + - Name: CD_MEDIALE_VOTUM + MaxLevel: 5 + Requires: + - Name: CD_DILECTIO_HEAL + Level: 3 + - Name: CD_MACE_BOOK_M + MaxLevel: 10 + - Name: CD_ARGUTUS_VITA + MaxLevel: 5 + Requires: + - Name: CD_MEDIALE_VOTUM + Level: 3 + - Name: CD_REPARATIO + Level: 3 + - Name: CD_ARGUTUS_TELUM + MaxLevel: 5 + Requires: + - Name: CD_MEDIALE_VOTUM + Level: 3 + - Name: CD_REPARATIO + Level: 3 + - Name: CD_ARBITRIUM + MaxLevel: 10 + Requires: + - Name: AB_ADORAMUS + Level: 5 + - Name: CD_FRAMEN + Level: 3 + - Name: CD_PRESENS_ACIES + MaxLevel: 5 + Requires: + - Name: CD_MEDIALE_VOTUM + Level: 3 + - Name: CD_REPARATIO + Level: 3 + - Name: CD_FIDUS_ANIMUS + MaxLevel: 10 + - Name: CD_EFFLIGO + MaxLevel: 10 + Requires: + - Name: AB_ORATIO + Level: 5 + - Name: CD_PETITIO + Level: 10 + - Name: CD_COMPETENTIA + MaxLevel: 5 + Requires: + - Name: CD_ARGUTUS_TELUM + Level: 2 + - Name: CD_ARGUTUS_VITA + Level: 2 + - Name: CD_PRESENS_ACIES + Level: 2 + - Name: CD_PNEUMATICUS_PROCELLA + MaxLevel: 10 + Requires: + - Name: CD_ARBITRIUM + Level: 10 + - Name: CD_FRAMEN + Level: 5 + - Name: CD_DILECTIO_HEAL + MaxLevel: 5 + Requires: + - Name: AB_CHEAL + Level: 3 + - Name: AB_HIGHNESSHEAL + Level: 3 + - Name: CD_RELIGIO + MaxLevel: 5 + Requires: + - Name: AB_CLEMENTIA + Level: 3 + - Name: CD_DILECTIO_HEAL + Level: 2 + - Name: CD_BENEDICTUM + MaxLevel: 5 + Requires: + - Name: AB_CANTO + Level: 3 + - Name: CD_DILECTIO_HEAL + Level: 2 + - Name: CD_PETITIO + MaxLevel: 10 + Requires: + - Name: AB_DUPLELIGHT + Level: 10 + - Name: CD_MACE_BOOK_M + Level: 5 + - Name: CD_FRAMEN + MaxLevel: 5 + Requires: + - Name: AB_JUDEX + Level: 10 + - Name: CD_FIDUS_ANIMUS + Level: 5 + - Job: Windhawk + Inherit: + Novice: true + Archer: true + Hunter: true + Sniper: true + Ranger: true + Ranger_T: true + Tree: + - Name: WH_ADVANCED_TRAP + MaxLevel: 5 + Requires: + - Name: RA_RESEARCHTRAP + Level: 3 + - Name: WH_WIND_SIGN + MaxLevel: 5 + Requires: + - Name: WH_NATUREFRIENDLY + Level: 5 + - Name: WH_NATUREFRIENDLY + MaxLevel: 5 + - Name: WH_HAWKRUSH + MaxLevel: 5 + Requires: + - Name: WH_HAWK_M + Level: 1 + - Name: WH_HAWK_M + MaxLevel: 1 + Requires: + - Name: HT_STEELCROW + Level: 1 + - Name: WH_CALAMITYGALE + MaxLevel: 1 + Requires: + - Name: WH_GALESTORM + Level: 5 + - Name: WH_WIND_SIGN + Level: 5 + - Name: WH_HAWKBOOMERANG + MaxLevel: 5 + Requires: + - Name: WH_HAWKRUSH + Level: 5 + - Name: WH_GALESTORM + MaxLevel: 10 + Requires: + - Name: WH_CRESCIVE_BOLT + Level: 3 + - Name: WH_DEEPBLINDTRAP + MaxLevel: 5 + Requires: + - Name: WH_ADVANCED_TRAP + Level: 3 + - Name: WH_SOLIDTRAP + MaxLevel: 5 + Requires: + - Name: WH_ADVANCED_TRAP + Level: 3 + - Name: WH_SWIFTTRAP + MaxLevel: 5 + Requires: + - Name: WH_DEEPBLINDTRAP + Level: 1 + - Name: WH_CRESCIVE_BOLT + MaxLevel: 10 + Requires: + - Name: RA_AIMEDBOLT + Level: 5 + - Name: WH_FLAMETRAP + MaxLevel: 5 + Requires: + - Name: WH_SOLIDTRAP + Level: 1 + - Job: Imperial_Guard + Inherit: + Novice: true + Swordman: true + Crusader: true + Paladin: true + Royal_Guard: true + Royal_Guard_T: true + Tree: + - Name: IG_GUARD_STANCE + MaxLevel: 5 + Requires: + - Name: IG_SHIELD_MASTERY + Level: 3 + - Name: IG_GUARDIAN_SHIELD + MaxLevel: 5 + Requires: + - Name: IG_GUARD_STANCE + Level: 2 + - Name: IG_REBOUND_SHIELD + MaxLevel: 5 + Requires: + - Name: IG_GUARD_STANCE + Level: 4 + - Name: IG_SHIELD_MASTERY + MaxLevel: 10 + - Name: IG_SPEAR_SWORD_M + MaxLevel: 10 + - Name: IG_ATTACK_STANCE + MaxLevel: 5 + Requires: + - Name: IG_SPEAR_SWORD_M + Level: 3 + - Name: IG_ULTIMATE_SACRIFICE + MaxLevel: 5 + Requires: + - Name: IG_GUARDIAN_SHIELD + Level: 3 + - Name: IG_REBOUND_SHIELD + Level: 3 + - Name: IG_HOLY_SHIELD + MaxLevel: 5 + Requires: + - Name: IG_CROSS_RAIN + Level: 3 + - Name: IG_SHIELD_MASTERY + Level: 5 + - Name: IG_GRAND_JUDGEMENT + MaxLevel: 10 + Requires: + - Name: IG_OVERSLASH + Level: 5 + - Name: IG_SPEAR_SWORD_M + Level: 5 + - Name: IG_JUDGEMENT_CROSS + MaxLevel: 10 + Requires: + - Name: IG_CROSS_RAIN + Level: 5 + - Name: IG_HOLY_SHIELD + Level: 3 + - Name: IG_SHIELD_SHOOTING + MaxLevel: 5 + Requires: + - Name: IG_ATTACK_STANCE + Level: 2 + - Name: IG_SHIELD_MASTERY + Level: 5 + - Name: IG_OVERSLASH + MaxLevel: 10 + Requires: + - Name: IG_ATTACK_STANCE + Level: 3 + - Name: IG_CROSS_RAIN + MaxLevel: 10 + Requires: + - Name: IG_SHIELD_MASTERY + Level: 1 + - Job: Biolo + Inherit: + Novice: true + Merchant: true + Alchemist: true + Creator: true + Genetic: true + Genetic_T: true + Tree: + - Name: BO_BIONIC_PHARMACY + MaxLevel: 5 + Requires: + - Name: GN_S_PHARMACY + Level: 5 + - Name: BO_BIONICS_M + MaxLevel: 10 + - Name: BO_THE_WHOLE_PROTECTION + MaxLevel: 5 + Requires: + - Name: BO_BIONIC_PHARMACY + Level: 5 + - Name: BO_ADVANCE_PROTECTION + MaxLevel: 4 + Requires: + - Name: BO_BIONIC_PHARMACY + Level: 5 + - Name: BO_ACIDIFIED_ZONE_WATER + MaxLevel: 5 + Requires: + - Name: BO_ACIDIFIED_ZONE_WIND + Level: 1 + - Name: BO_ACIDIFIED_ZONE_GROUND + MaxLevel: 5 + Requires: + - Name: BO_BIONICS_M + Level: 3 + - Name: BO_BIONIC_PHARMACY + Level: 5 + - Name: BO_ACIDIFIED_ZONE_WIND + MaxLevel: 5 + Requires: + - Name: BO_BIONICS_M + Level: 3 + - Name: BO_BIONIC_PHARMACY + Level: 5 + - Name: BO_ACIDIFIED_ZONE_FIRE + MaxLevel: 5 + Requires: + - Name: BO_ACIDIFIED_ZONE_GROUND + Level: 1 + - Name: BO_WOODENWARRIOR + MaxLevel: 5 + Requires: + - Name: BO_CREEPER + Level: 3 + - Name: BO_WOODEN_FAIRY + MaxLevel: 5 + Requires: + - Name: BO_CREEPER + Level: 3 + - Name: BO_CREEPER + MaxLevel: 5 + Requires: + - Name: BO_BIONICS_M + Level: 5 + - Name: BO_RESEARCHREPORT + MaxLevel: 1 + Requires: + - Name: BO_ACIDIFIED_ZONE_FIRE + Level: 3 + - Name: BO_ACIDIFIED_ZONE_WATER + Level: 3 + - Name: BO_HELLTREE + MaxLevel: 5 + Requires: + - Name: BO_WOODENWARRIOR + Level: 3 + - Name: BO_WOODEN_FAIRY + Level: 3 + - Job: Abyss_Chaser + Inherit: + Novice: true + Thief: true + Rogue: true + Stalker: true + Shadow_Chaser: true + Shadow_Chaser_T: true + Tree: + - Name: ABC_DAGGER_AND_BOW_M + MaxLevel: 10 + - Name: ABC_MAGIC_SWORD_M + MaxLevel: 10 + Requires: + - Name: SC_AUTOSHADOWSPELL + Level: 5 + - Name: SC_REPRODUCE + Level: 5 + - Name: ABC_STRIP_SHADOW + MaxLevel: 5 + Requires: + - Name: ABC_DAGGER_AND_BOW_M + Level: 7 + - Name: SC_STRIPACCESSARY + Level: 1 + - Name: ABC_ABYSS_DAGGER + MaxLevel: 5 + Requires: + - Name: ABC_DAGGER_AND_BOW_M + Level: 3 + - Name: SC_FATALMENACE + Level: 5 + - Name: ABC_UNLUCKY_RUSH + MaxLevel: 5 + Requires: + - Name: ABC_ABYSS_DAGGER + Level: 3 + - Name: ABC_DAGGER_AND_BOW_M + Level: 4 + - Name: ABC_CHAIN_REACTION_SHOT + MaxLevel: 5 + Requires: + - Name: ABC_DAGGER_AND_BOW_M + Level: 3 + - Name: SC_TRIANGLESHOT + Level: 5 + - Name: ABC_FROM_THE_ABYSS + MaxLevel: 5 + Requires: + - Name: ABC_MAGIC_SWORD_M + Level: 3 + - Name: ABC_ABYSS_SLAYER + MaxLevel: 10 + Requires: + - Name: ABC_ABYSS_DAGGER + Level: 5 + - Name: ABC_DEFT_STAB + Level: 5 + - Name: ABC_ABYSS_STRIKE + MaxLevel: 10 + Requires: + - Name: ABC_ABYSS_SQUARE + Level: 3 + - Name: ABC_FROM_THE_ABYSS + Level: 3 + - Name: ABC_DEFT_STAB + MaxLevel: 10 + Requires: + - Name: ABC_ABYSS_DAGGER + Level: 3 + - Name: ABC_DAGGER_AND_BOW_M + Level: 5 + - Name: ABC_ABYSS_SQUARE + MaxLevel: 5 + Requires: + - Name: ABC_FROM_THE_ABYSS + Level: 1 + - Name: ABC_MAGIC_SWORD_M + Level: 5 + - Name: ABC_FRENZY_SHOT + MaxLevel: 10 + Requires: + - Name: ABC_CHAIN_REACTION_SHOT + Level: 3 + - Name: ABC_DAGGER_AND_BOW_M + Level: 5 + - Job: Elemental_Master + Inherit: + Novice: true + Mage: true + Sage: true + Professor: true + Sorcerer: true + Sorcerer_T: true + Tree: + - Name: EM_MAGIC_BOOK_M + MaxLevel: 10 + - Name: EM_SPELL_ENCHANTING + MaxLevel: 5 + Requires: + - Name: EM_MAGIC_BOOK_M + Level: 5 + - Name: EM_ACTIVITY_BURN + MaxLevel: 5 + Requires: + - Name: EM_SPELL_ENCHANTING + Level: 3 + - Name: EM_INCREASING_ACTIVITY + MaxLevel: 5 + Requires: + - Name: EM_ACTIVITY_BURN + Level: 5 + - Name: EM_DIAMOND_STORM + MaxLevel: 5 + Requires: + - Name: EM_MAGIC_BOOK_M + Level: 2 + - Name: EM_LIGHTNING_LAND + MaxLevel: 5 + Requires: + - Name: EM_MAGIC_BOOK_M + Level: 2 + - Name: EM_VENOM_SWAMP + MaxLevel: 5 + Requires: + - Name: EM_MAGIC_BOOK_M + Level: 2 + - Name: EM_CONFLAGRATION + MaxLevel: 5 + Requires: + - Name: EM_MAGIC_BOOK_M + Level: 2 + - Name: EM_TERRA_DRIVE + MaxLevel: 5 + Requires: + - Name: EM_MAGIC_BOOK_M + Level: 2 + - Name: EM_ELEMENTAL_SPIRIT_M + MaxLevel: 10 + Requires: + - Name: SO_EL_SYMPATHY + Level: 1 + - Name: EM_SUMMON_ELEMENTAL_ARDOR + MaxLevel: 1 + Requires: + - Name: EM_CONFLAGRATION + Level: 1 + - Name: EM_ELEMENTAL_SPIRIT_M + Level: 1 + - Name: SO_SUMMON_AGNI + Level: 3 + - Name: EM_SUMMON_ELEMENTAL_DILUVIO + MaxLevel: 1 + Requires: + - Name: EM_DIAMOND_STORM + Level: 1 + - Name: EM_ELEMENTAL_SPIRIT_M + Level: 1 + - Name: SO_SUMMON_AQUA + Level: 3 + - Name: EM_SUMMON_ELEMENTAL_PROCELLA + MaxLevel: 1 + Requires: + - Name: EM_ELEMENTAL_SPIRIT_M + Level: 1 + - Name: EM_LIGHTNING_LAND + Level: 1 + - Name: SO_SUMMON_VENTUS + Level: 3 + - Name: EM_SUMMON_ELEMENTAL_TERREMOTUS + MaxLevel: 1 + Requires: + - Name: EM_ELEMENTAL_SPIRIT_M + Level: 1 + - Name: EM_TERRA_DRIVE + Level: 1 + - Name: SO_SUMMON_TERA + Level: 3 + - Name: EM_SUMMON_ELEMENTAL_SERPENS + MaxLevel: 1 + Requires: + - Name: EM_ELEMENTAL_SPIRIT_M + Level: 1 + - Name: EM_VENOM_SWAMP + Level: 1 + - Name: SO_SUMMON_AGNI + Level: 3 + - Name: SO_SUMMON_AQUA + Level: 3 + - Name: SO_SUMMON_TERA + Level: 3 + - Name: SO_SUMMON_VENTUS + Level: 3 + - Name: EM_ELEMENTAL_BUSTER + MaxLevel: 10 + Requires: + - Name: EM_ELEMENTAL_SPIRIT_M + Level: 5 + - Name: EM_SUMMON_ELEMENTAL_ARDOR + Level: 1 + - Name: EM_SUMMON_ELEMENTAL_DILUVIO + Level: 1 + - Name: EM_SUMMON_ELEMENTAL_PROCELLA + Level: 1 + - Name: EM_SUMMON_ELEMENTAL_SERPENS + Level: 1 + - Name: EM_SUMMON_ELEMENTAL_TERREMOTUS + Level: 1 + - Name: EM_ELEMENTAL_VEIL + MaxLevel: 5 + Requires: + - Name: EM_ELEMENTAL_SPIRIT_M + Level: 3 + - Job: Inquisitor + Inherit: + Novice: true + Acolyte: true + Monk: true + Champion: true + Sura: true + Sura_T: true + Tree: + - Name: IQ_POWERFUL_FAITH + MaxLevel: 5 + Requires: + - Name: IQ_WILL_OF_FAITH + Level: 1 + - Name: IQ_FIRM_FAITH + MaxLevel: 5 + Requires: + - Name: IQ_WILL_OF_FAITH + Level: 1 + - Name: IQ_WILL_OF_FAITH + MaxLevel: 10 + - Name: IQ_OLEUM_SANCTUM + MaxLevel: 5 + Requires: + - Name: AL_HOLYWATER + Level: 1 + - Name: IQ_WILL_OF_FAITH + Level: 3 + - Name: IQ_SINCERE_FAITH + MaxLevel: 5 + Requires: + - Name: IQ_WILL_OF_FAITH + Level: 1 + - Name: IQ_MASSIVE_F_BLASTER + MaxLevel: 10 + Requires: + - Name: IQ_EXPOSION_BLASTER + Level: 3 + - Name: IQ_OLEUM_SANCTUM + Level: 3 + - Name: IQ_WILL_OF_FAITH + Level: 5 + - Name: IQ_EXPOSION_BLASTER + MaxLevel: 5 + Requires: + - Name: IQ_OLEUM_SANCTUM + Level: 1 + - Name: IQ_FIRST_BRAND + MaxLevel: 5 + Requires: + - Name: IQ_WILL_OF_FAITH + Level: 2 + - Name: IQ_FIRST_FAITH_POWER + MaxLevel: 5 + Requires: + - Name: IQ_FIRST_BRAND + Level: 1 + - Name: IQ_WILL_OF_FAITH + Level: 3 + - Name: IQ_JUDGE + MaxLevel: 5 + Requires: + - Name: IQ_FIRST_FAITH_POWER + Level: 1 + - Name: IQ_SECOND_FLAME + MaxLevel: 5 + Requires: + - Name: IQ_THIRD_EXOR_FLAME + Level: 1 + - Name: IQ_SECOND_FAITH + MaxLevel: 5 + Requires: + - Name: IQ_FIRST_FAITH_POWER + Level: 1 + - Name: IQ_SECOND_JUDGEMENT + MaxLevel: 5 + Requires: + - Name: IQ_JUDGE + Level: 1 + - Name: IQ_THIRD_PUNISH + MaxLevel: 5 + Requires: + - Name: IQ_SECOND_FAITH + Level: 2 + - Name: IQ_THIRD_FLAME_BOMB + MaxLevel: 5 + Requires: + - Name: IQ_SECOND_FLAME + Level: 2 + - Name: IQ_THIRD_CONSECRATION + MaxLevel: 5 + Requires: + - Name: IQ_SECOND_JUDGEMENT + Level: 2 + - Name: IQ_THIRD_EXOR_FLAME + MaxLevel: 5 + Requires: + - Name: IQ_JUDGE + Level: 1 + - Job: Troubadour + Inherit: + Novice: true + Archer: true + Bard: true + Clown: true + Minstrel: true + Minstrel_T: true + Tree: + - Name: TR_STAGE_MANNER + MaxLevel: 5 + - Name: TR_RETROSPECTION + MaxLevel: 1 + Requires: + - Name: TR_STAGE_MANNER + Level: 1 + - Name: TR_MYSTIC_SYMPHONY + MaxLevel: 1 + Requires: + - Name: TR_METALIC_FURY + Level: 1 + - Name: TR_ROSEBLOSSOM + Level: 5 + - Name: TR_KVASIR_SONATA + MaxLevel: 1 + Requires: + - Name: TR_NIPELHEIM_REQUIEM + Level: 1 + - Name: TR_ROKI_CAPRICCIO + Level: 1 + - Name: TR_ROSEBLOSSOM + MaxLevel: 5 + Requires: + - Name: TR_RHYTHMSHOOTING + Level: 3 + - Name: TR_RHYTHMSHOOTING + MaxLevel: 5 + - Name: TR_METALIC_FURY + MaxLevel: 5 + Requires: + - Name: TR_SOUNDBLEND + Level: 1 + - Name: TR_SOUNDBLEND + MaxLevel: 5 + Requires: + - Name: WM_METALICSOUND + Level: 5 + - Name: TR_GEF_NOCTURN + MaxLevel: 5 + Requires: + - Name: TR_STAGE_MANNER + Level: 3 + - Name: TR_ROKI_CAPRICCIO + MaxLevel: 5 + Requires: + - Name: TR_JAWAII_SERENADE + Level: 1 + - Name: TR_AIN_RHAPSODY + MaxLevel: 5 + Requires: + - Name: TR_STAGE_MANNER + Level: 3 + - Name: TR_MUSICAL_INTERLUDE + MaxLevel: 5 + Requires: + - Name: TR_AIN_RHAPSODY + Level: 1 + - Name: TR_JAWAII_SERENADE + MaxLevel: 5 + Requires: + - Name: TR_GEF_NOCTURN + Level: 1 + - Name: TR_NIPELHEIM_REQUIEM + MaxLevel: 5 + Requires: + - Name: TR_MUSICAL_INTERLUDE + Level: 1 + - Name: TR_PRON_MARCH + Level: 1 + - Name: TR_PRON_MARCH + MaxLevel: 5 + Requires: + - Name: TR_AIN_RHAPSODY + Level: 1 + - Job: Trouvere + Inherit: + Novice: true + Archer: true + Dancer: true + Gypsy: true + Wanderer: true + Wanderer_T: true + Tree: + - Name: TR_STAGE_MANNER + MaxLevel: 5 + - Name: TR_RETROSPECTION + MaxLevel: 1 + Requires: + - Name: TR_STAGE_MANNER + Level: 1 + - Name: TR_MYSTIC_SYMPHONY + MaxLevel: 1 + Requires: + - Name: TR_METALIC_FURY + Level: 1 + - Name: TR_ROSEBLOSSOM + Level: 5 + - Name: TR_KVASIR_SONATA + MaxLevel: 1 + Requires: + - Name: TR_NIPELHEIM_REQUIEM + Level: 1 + - Name: TR_ROKI_CAPRICCIO + Level: 1 + - Name: TR_ROSEBLOSSOM + MaxLevel: 5 + Requires: + - Name: TR_RHYTHMSHOOTING + Level: 3 + - Name: TR_RHYTHMSHOOTING + MaxLevel: 5 + - Name: TR_METALIC_FURY + MaxLevel: 5 + Requires: + - Name: TR_SOUNDBLEND + Level: 1 + - Name: TR_SOUNDBLEND + MaxLevel: 5 + Requires: + - Name: WM_METALICSOUND + Level: 5 + - Name: TR_GEF_NOCTURN + MaxLevel: 5 + Requires: + - Name: TR_STAGE_MANNER + Level: 3 + - Name: TR_ROKI_CAPRICCIO + MaxLevel: 5 + Requires: + - Name: TR_JAWAII_SERENADE + Level: 1 + - Name: TR_AIN_RHAPSODY + MaxLevel: 5 + Requires: + - Name: TR_STAGE_MANNER + Level: 3 + - Name: TR_MUSICAL_INTERLUDE + MaxLevel: 5 + Requires: + - Name: TR_AIN_RHAPSODY + Level: 1 + - Name: TR_JAWAII_SERENADE + MaxLevel: 5 + Requires: + - Name: TR_GEF_NOCTURN + Level: 1 + - Name: TR_NIPELHEIM_REQUIEM + MaxLevel: 5 + Requires: + - Name: TR_MUSICAL_INTERLUDE + Level: 1 + - Name: TR_PRON_MARCH + Level: 1 + - Name: TR_PRON_MARCH + MaxLevel: 5 + Requires: + - Name: TR_AIN_RHAPSODY + Level: 1 + - Job: Windhawk2 + Inherit: + Novice: true + Archer: true + Hunter: true + Sniper: true + Ranger: true + Ranger_T: true + Windhawk: true + - Job: Meister2 + Inherit: + Novice: true + Merchant: true + Blacksmith: true + Whitesmith: true + Mechanic: true + Mechanic_T: true + Meister: true + - Job: Dragon_Knight2 + Inherit: + Novice: true + Swordman: true + Knight: true + Lord_Knight: true + Rune_Knight: true + Rune_Knight_T: true + Dragon_Knight: true + - Job: Imperial_Guard2 + Inherit: + Novice: true + Swordman: true + Crusader: true + Paladin: true + Royal_Guard: true + Royal_Guard_T: true + Imperial_Guard: true diff --git a/db/re/statpoint.yml b/db/re/statpoint.yml index 13519b2e51..e940c4a03b 100644 --- a/db/re/statpoint.yml +++ b/db/re/statpoint.yml @@ -24,11 +24,12 @@ ########################################################################### # - Level BaseLevel required. # Points Total status points given from BaseLevel 1 to 'Level'. +# TraitPoints Total trait points given from BaseLevel 1 to 'Level'. ########################################################################### Header: Type: STATPOINT_DB - Version: 1 + Version: 2 Body: - Level: 1 @@ -382,152 +383,202 @@ Body: - Level: 175 Points: 3278 - Level: 176 - Points: 3295 + Points: 3309 - Level: 177 - Points: 3325 + Points: 3340 - Level: 178 - Points: 3355 + Points: 3371 - Level: 179 - Points: 3385 + Points: 3403 - Level: 180 - Points: 3415 + Points: 3435 - Level: 181 - Points: 3446 + Points: 3467 - Level: 182 - Points: 3477 + Points: 3499 - Level: 183 - Points: 3508 + Points: 3531 - Level: 184 - Points: 3539 + Points: 3563 - Level: 185 - Points: 3570 + Points: 3595 - Level: 186 - Points: 3601 + Points: 3628 - Level: 187 - Points: 3632 + Points: 3661 - Level: 188 - Points: 3663 - - Level: 189 Points: 3694 + - Level: 189 + Points: 3727 - Level: 190 - Points: 3725 + Points: 3760 - Level: 191 - Points: 3757 + Points: 3793 - Level: 192 - Points: 3789 + Points: 3826 - Level: 193 - Points: 3821 + Points: 3860 - Level: 194 - Points: 3853 + Points: 3894 - Level: 195 - Points: 3885 + Points: 3928 - Level: 196 - Points: 3917 + Points: 3962 - Level: 197 - Points: 3949 + Points: 3996 - Level: 198 - Points: 3981 + Points: 4030 - Level: 199 - Points: 4013 + Points: 4064 - Level: 200 - Points: 4045 + Points: 4099 - Level: 201 - Points: 4045 + Points: 4099 + TraitPoints: 3 - Level: 202 - Points: 4045 + Points: 4099 + TraitPoints: 6 - Level: 203 - Points: 4045 + Points: 4099 + TraitPoints: 9 - Level: 204 - Points: 4045 + Points: 4099 + TraitPoints: 12 - Level: 205 - Points: 4045 + Points: 4099 + TraitPoints: 19 - Level: 206 - Points: 4045 + Points: 4099 + TraitPoints: 22 - Level: 207 - Points: 4045 + Points: 4099 + TraitPoints: 25 - Level: 208 - Points: 4045 + Points: 4099 + TraitPoints: 28 - Level: 209 - Points: 4045 + Points: 4099 + TraitPoints: 31 - Level: 210 - Points: 4045 + Points: 4099 + TraitPoints: 38 - Level: 211 - Points: 4045 + Points: 4099 + TraitPoints: 41 - Level: 212 - Points: 4045 + Points: 4099 + TraitPoints: 44 - Level: 213 - Points: 4045 + Points: 4099 + TraitPoints: 47 - Level: 214 - Points: 4045 + Points: 4099 + TraitPoints: 50 - Level: 215 - Points: 4045 + Points: 4099 + TraitPoints: 57 - Level: 216 - Points: 4045 + Points: 4099 + TraitPoints: 60 - Level: 217 - Points: 4045 + Points: 4099 + TraitPoints: 63 - Level: 218 - Points: 4045 + Points: 4099 + TraitPoints: 66 - Level: 219 - Points: 4045 + Points: 4099 + TraitPoints: 69 - Level: 220 - Points: 4045 + Points: 4099 + TraitPoints: 76 - Level: 221 - Points: 4045 + Points: 4099 + TraitPoints: 79 - Level: 222 - Points: 4045 + Points: 4099 + TraitPoints: 82 - Level: 223 - Points: 4045 + Points: 4099 + TraitPoints: 85 - Level: 224 - Points: 4045 + Points: 4099 + TraitPoints: 88 - Level: 225 - Points: 4045 + Points: 4099 + TraitPoints: 95 - Level: 226 - Points: 4045 + Points: 4099 + TraitPoints: 98 - Level: 227 - Points: 4045 + Points: 4099 + TraitPoints: 101 - Level: 228 - Points: 4045 + Points: 4099 + TraitPoints: 104 - Level: 229 - Points: 4045 + Points: 4099 + TraitPoints: 107 - Level: 230 - Points: 4045 + Points: 4099 + TraitPoints: 114 - Level: 231 - Points: 4045 + Points: 4099 + TraitPoints: 117 - Level: 232 - Points: 4045 + Points: 4099 + TraitPoints: 120 - Level: 233 - Points: 4045 + Points: 4099 + TraitPoints: 123 - Level: 234 - Points: 4045 + Points: 4099 + TraitPoints: 126 - Level: 235 - Points: 4045 + Points: 4099 + TraitPoints: 133 - Level: 236 - Points: 4045 + Points: 4099 + TraitPoints: 136 - Level: 237 - Points: 4045 + Points: 4099 + TraitPoints: 139 - Level: 238 - Points: 4045 + Points: 4099 + TraitPoints: 142 - Level: 239 - Points: 4045 + Points: 4099 + TraitPoints: 145 - Level: 240 - Points: 4045 + Points: 4099 + TraitPoints: 152 - Level: 241 - Points: 4045 + Points: 4099 + TraitPoints: 155 - Level: 242 - Points: 4045 + Points: 4099 + TraitPoints: 158 - Level: 243 - Points: 4045 + Points: 4099 + TraitPoints: 161 - Level: 244 - Points: 4045 + Points: 4099 + TraitPoints: 164 - Level: 245 - Points: 4045 + Points: 4099 + TraitPoints: 171 - Level: 246 - Points: 4045 + Points: 4099 + TraitPoints: 174 - Level: 247 - Points: 4045 + Points: 4099 + TraitPoints: 177 - Level: 248 - Points: 4045 + Points: 4099 + TraitPoints: 180 - Level: 249 - Points: 4045 + Points: 4099 + TraitPoints: 183 - Level: 250 - Points: 4045 + Points: 4099 + TraitPoints: 190 diff --git a/db/skill_db.yml b/db/skill_db.yml index d5cb78d6fc..ced4e2195f 100644 --- a/db/skill_db.yml +++ b/db/skill_db.yml @@ -49,6 +49,9 @@ # Knockback: Amount of tiles the skill knockbacks. (Default: 0) # - Level Skill level. # Amount Knockback count at specific skill level. +# GiveAp: Gives AP on successful skill cast. (Default: 0) +# - Level Skill level. +# Amount AP gained at specific skill level. # CopyFlags: Determines if the skill is copyable. (Optional) # Skill: Type of skill that can copy. # RemoveRequirement: Remove a requirement type. (Optional) @@ -87,12 +90,18 @@ # SpCost: SP required to cast. (Default: 0) # - Level Skill level. # Amount SP required at specific skill level. +# ApCost: AP required to cast. (Default: 0) +# - Level Skill level. +# Amount AP required at specific skill level. # HpRateCost: HP rate required to cast. If positive, uses current HP, else uses Max HP. (Default: 0) # - Level Skill level. # Amount HP rate required at specific skill level. # SpRateCost: SP rate required to cast. If positive, uses current SP, else uses Max SP. (Default: 0) # - Level Skill level. # Amount SP rate required at specific skill level. +# ApRateCost: AP rate required to cast. If positive, uses current AP, else uses Max AP. (Default: 0) +# - Level Skill level. +# Amount AP rate required at specific skill level. # MaxHpTrigger: Maximum amount of HP to cast the skill. (Default: 0) # - Level Skill level. # Amount Maximum HP trigger required at specific skill level. @@ -130,7 +139,7 @@ Header: Type: SKILL_DB - Version: 2 + Version: 3 Footer: Imports: diff --git a/db/statpoint.yml b/db/statpoint.yml index 690192de2e..f6f3e95fcb 100644 --- a/db/statpoint.yml +++ b/db/statpoint.yml @@ -24,11 +24,12 @@ ########################################################################### # - Level BaseLevel required. # Points Total status points given from BaseLevel 1 to 'Level'. +# TraitPoints Total trait points given from BaseLevel 1 to 'Level'. ########################################################################### Header: Type: STATPOINT_DB - Version: 1 + Version: 2 Footer: Imports: diff --git a/db/status_disabled.txt b/db/status_disabled.txt index 6a5005ff0b..b27788ea9a 100644 --- a/db/status_disabled.txt +++ b/db/status_disabled.txt @@ -363,3 +363,143 @@ SC_FREEZING,16 SC_TEARGAS_SOB,16 SC__FEINTBOMB,16 SC__CHAOS,16 + +// 4th Job Common Status +SC_HANDICAPSTATE_DEEPBLIND,16 +SC_HANDICAPSTATE_DEEPSILENCE,16 +SC_HANDICAPSTATE_LASSITUDE,16 +SC_HANDICAPSTATE_FROSTBITE,16 +SC_HANDICAPSTATE_SWOONING,16 +SC_HANDICAPSTATE_LIGHTNINGSTRIKE,16 +SC_HANDICAPSTATE_CRYSTALLIZATION,16 +SC_HANDICAPSTATE_CONFLAGRATION,16 +SC_HANDICAPSTATE_MISFORTUNE,16 +SC_HANDICAPSTATE_DEADLYPOISON,16 +SC_HANDICAPSTATE_DEPRESSION,16 +SC_HANDICAPSTATE_HOLYFLAME,16 + +// Dragon Knight +SC_SERVANTWEAPON,16 +SC_SERVANT_SIGN,16 +SC_CHARGINGPIERCE,16 +SC_CHARGINGPIERCE_COUNT,16 +SC_DRAGONIC_AURA,16 +SC_VIGOR,16 + +// Arch Mage +SC_DEADLY_DEFEASANCE,16 +SC_CLIMAX_DES_HU,16 +SC_CLIMAX,16 +SC_CLIMAX_EARTH,16 +SC_CLIMAX_BLOOM,16 +SC_CLIMAX_CRYIMP,16 + +// Windhawk +SC_WINDSIGN,16 +SC_CRESCIVEBOLT,16 +SC_CALAMITYGALE,16 + +// Cardinal +SC_MEDIALE,16 +SC_A_VITA,16 +SC_A_TELUM,16 +SC_PRE_ACIES,16 +SC_COMPETENTIA,16 +SC_RELIGIO,16 +SC_BENEDICTUM,16 + +// Meister +SC_AXE_STOMP,16 +SC_A_MACHINE,16 +SC_D_MACHINE,16 +SC_ABR_BATTLE_WARIOR,16 +SC_ABR_DUAL_CANNON,16 +SC_ABR_MOTHER_NET,16 +SC_ABR_INFINITY,16 + +// Shadow Cross +SC_SHADOW_EXCEED,16 +SC_DANCING_KNIFE,16 +SC_POTENT_VENOM,16 +SC_SHADOW_SCAR,16 +SC_E_SLASH_COUNT,16 +SC_SHADOW_WEAPON,16 + +// Imperial Guard +SC_GUARD_STANCE,16 +SC_ATTACK_STANCE,16 +SC_GUARDIAN_S,16 +SC_REBOUND_S,16 +SC_HOLY_S,16 +SC_ULTIMATE_S,16 +SC_SPEAR_SCAR,16 +SC_SHIELD_POWER,16 + +// Elemental Master +SC_SPELL_ENCHANTING,16 +SC_SUMMON_ELEMENTAL_ARDOR,16 +SC_SUMMON_ELEMENTAL_DILUVIO,16 +SC_SUMMON_ELEMENTAL_PROCELLA,16 +SC_SUMMON_ELEMENTAL_TERREMOTUS,16 +SC_SUMMON_ELEMENTAL_SERPENS,16 +SC_ELEMENTAL_VEIL,16 + +// Troubadour/Trouvere +SC_MYSTIC_SYMPHONY,16 +SC_KVASIR_SONATA,16 +SC_SOUNDBLEND,16 +SC_GEF_NOCTURN,16 +SC_AIN_RHAPSODY,16 +SC_MUSICAL_INTERLUDE,16 +SC_JAWAII_SERENADE,16 +SC_PRON_MARCH,16 +SC_ROSEBLOSSOM,16 + +// Inquisitor +SC_POWERFUL_FAITH,16 +SC_SINCERE_FAITH,16 +SC_FIRM_FAITH,16 +SC_HOLY_OIL,16 +SC_FIRST_BRAND,16 +SC_SECOND_BRAND,16 +SC_SECOND_JUDGE,16 +SC_THIRD_EXOR_FLAME,16 +SC_FIRST_FAITH_POWER,16 +SC_MASSIVE_F_BLASTER,16 + +// Biolo +SC_PROTECTSHADOWEQUIP,16 +SC_RESEARCHREPORT,16 +SC_BO_HELL_DUSTY,16 +SC_BIONIC_WOODENWARRIOR,16 +SC_BIONIC_WOODEN_FAIRY,16 +SC_BIONIC_CREEPER,16 +SC_BIONIC_HELLTREE,16 + +// Abyss Chaser +SC_SHADOW_STRIP,16 +SC_ABYSS_DAGGER,16 +SC_ABYSSFORCEWEAPON,16 +SC_ABYSS_SLAYER,16 + +// Super Elementals +SC_FLAMETECHNIC,16 +SC_FLAMETECHNIC_OPTION,16 +SC_FLAMEARMOR,16 +SC_FLAMEARMOR_OPTION,16 +SC_COLD_FORCE,16 +SC_COLD_FORCE_OPTION,16 +SC_CRYSTAL_ARMOR,16 +SC_CRYSTAL_ARMOR_OPTION,16 +SC_GRACE_BREEZE,16 +SC_GRACE_BREEZE_OPTION,16 +SC_EYES_OF_STORM,16 +SC_EYES_OF_STORM_OPTION,16 +SC_EARTH_CARE,16 +SC_EARTH_CARE_OPTION,16 +SC_STRONG_PROTECTION,16 +SC_STRONG_PROTECTION_OPTION,16 +SC_DEEP_POISONING,16 +SC_DEEP_POISONING_OPTION,16 +SC_POISON_SHIELD,16 +SC_POISON_SHIELD_OPTION,16 diff --git a/doc/item_bonus.txt b/doc/item_bonus.txt index 00fcde6a0d..73abcfa058 100644 --- a/doc/item_bonus.txt +++ b/doc/item_bonus.txt @@ -106,22 +106,16 @@ bonus bWis,n; WIS + n bonus bSpl,n; SPL + n bonus bCon,n; CON + n bonus bCrt,n; CRT + n +bonus bAllTraitStats,n; POW + n, STA + n, WIS + n, SPL + n, CON + n, CRT + n -Sub-Trait Stats ---------------- -bonus bPatk,n; Power Attack (P.ATK) + n -bonus bSmatk,n; Spell Magic Attack (S.MATK) + n -bonus bHplus,n; Heal Plus (H.PLUS) + n -bonus bCrate,n; Critical Rate (C.RATE) + n -bonus bRes,n; Physical Resistance (RES) + n -bonus bMres,n; Magic Resistance (MRES) + n - -HP/SP +HP/SP/AP ----- bonus bMaxHP,n; MaxHP + n bonus bMaxHPrate,n; MaxHP + n% bonus bMaxSP,n; MaxSP + n bonus bMaxSPrate,n; MaxSP + n% +bonus bMaxAP,n; MaxAP + n +bonus bMaxAPrate,n; MaxAP + n% Atk/Def ------- @@ -162,6 +156,18 @@ bonus bAspd,n; Attack speed + n bonus bAspdRate,n; Attack speed + n% bonus bAtkRange,n; Attack range + n bonus bAddMaxWeight,n; MaxWeight + n (in units of 0.1) +bonus bPAtk,n; PAtk + n +bonus bPAtkRate,n; PAtk + n% +bonus bSMatk,n; SMatk + n +bonus bSMatkRate,n; SMatk + n% +bonus bRes,n; Res + n +bonus bResRate,n; Res + n% +bonus bMRes,n; MRes + n +bonus bMResRate,n; MRes + n% +bonus bHPlus,n; HPlus + n +bonus bHPlusRate,n; HPlus + n% +bonus bCRate,n; CRate + n +bonus bCRateRate,n; CRate + n% ======================= | 2. Extended Bonuses | @@ -264,7 +270,8 @@ bonus2 bSubClass,c,x; +x% damage reduction against class c bonus2 bAddSize,s,x; +x% physical damage against size s bonus2 bMagicAddSize,s,x; +x% magical damage against size s bonus2 bSubSize,s,x; +x% damage reduction against size s -bonus2 bMagicSubSize,s,x; +x% magic damage reduction against size s +bonus2 bWeaponSubSize,s,x; +x% physical damage reduction against size s +bonus2 bMagicSubSize,s,x; +x% magic damage reduction against size s bonus bNoSizeFix; Ignores the size modifier when calculating damage bonus2 bAddDamageClass,mid,x; +x% physical damage against monster mid diff --git a/doc/item_db.txt b/doc/item_db.txt index f0f29d8c74..120643cdbe 100644 --- a/doc/item_db.txt +++ b/doc/item_db.txt @@ -159,10 +159,10 @@ Baby - Baby classes (no Third-Baby classes). Third - Third classes (no Transcedent-Third or Third-Baby classes). Third_Upper - Transcedent-Third classes. Third_Baby - Third-Baby classes. +Fourth - Fourth classes. All_Upper - All Transcedent classes All_Baby - All baby classes All_Third - Applies to all Third classes. -Fourth - Fourth classes. --------------------------------------- diff --git a/doc/mob_db.txt b/doc/mob_db.txt index 88f3900ec6..0dce617cbb 100644 --- a/doc/mob_db.txt +++ b/doc/mob_db.txt @@ -68,6 +68,14 @@ MagicDefense: Magic defense of the monster, reduce magical skill. --------------------------------------- +Resistance: Physical resistance of the monster, reduce melee and ranged physical attack/skill. + +--------------------------------------- + +MagicResistance: Magic resistance of the monster, reduce magical skill. + +--------------------------------------- + Str: Strength of the monster. Affects ATK. --------------------------------------- diff --git a/doc/script_commands.txt b/doc/script_commands.txt index df2e094406..42ff1eea56 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -3586,6 +3586,8 @@ Valid types are: MOB_ATK2 - monster's atk2 MOB_DEF - monster's def MOB_MDEF - monster's mdef + MOB_RES - monster's res + MOB_MRES - monster's mres MOB_STR - monster's str MOB_AGI - monster's agi MOB_VIT - monster's vit @@ -6031,6 +6033,30 @@ specified amount permanently. The amount can be negative. See 'statusup'. // This will decrease a character's Vit forever. statusup2 bVit,-1; +--------------------------------------- + +*traitstatusup {,}; + +This command will change a specified trait stat of the invoking character up by one +permanently. Trait stats are to be given as number, but you can use these constants to +replace them: + +bPow - Power +bSta - Stamina +bWis - Wisdom +bSpl - Spell +bCon - Concentration +bCrt - Creative + +--------------------------------------- + +*traitstatusup2 ,{,}; + +This command will change a specified trait stat of the invoking character by the +specified amount permanently. The amount can be negative. See 'statusup'. + + // This will decrease a character's Sta forever. + traitstatusup2 bSta,-1; --------------------------------------- @@ -8269,6 +8295,8 @@ Parameters (indexes) for monsters are: UMOB_BODY2 UMOB_GROUP_ID UMOB_IGNORE_CELL_STACK_LIMIT + UMOB_RES + UMOB_MRES ----- diff --git a/doc/skill_db.txt b/doc/skill_db.txt index aca6fb30a5..e24cec7e74 100644 --- a/doc/skill_db.txt +++ b/doc/skill_db.txt @@ -525,6 +525,27 @@ Sequence Map Form ------------------ +ApCost: AP required to cast. + +Can be defined in scalar form or sequence map form: +Scalar Form + ApCost: 10 + +Sequence Map Form + ApCost: + - Level: 1 + Amount: 10 + - Level: 2 + Amount: 20 + - Level: 3 + Amount: 30 + - Level: 4 + Amount: 40 + - Level: 5 + Amount: 50 + +------------------ + HpRateCost: HP rate required to cast. If positive, uses current HP, else uses Max HP. Can be defined in scalar form or sequence map form: @@ -567,6 +588,27 @@ Sequence Map Form ------------------ +ApRateCost: AP rate required to cast. If positive, uses current AP, else uses Max AP. + +Can be defined in scalar form or sequence map form: +Scalar Form + ApRateCost: 10 + +Sequence Map Form + ApRateCost: + - Level: 1 + Amount: 10 + - Level: 2 + Amount: 20 + - Level: 3 + Amount: 30 + - Level: 4 + Amount: 40 + - Level: 5 + Amount: 50 + +------------------ + MaxHpTrigger: Maximum amount of HP to cast the skill. Can be defined in scalar form or sequence map form: @@ -754,6 +796,27 @@ Levels 1 - 5 have no item cost but levels 6 - 10 require a Blue Gemstone. ------------------ +GiveAp: AP given on successful casting. + +Can be defined in scalar form or sequence map form: +Scalar Form + GiveAp: 10 + +Sequence Map Form + GiveAp: + - Level: 1 + Amount: 10 + - Level: 2 + Amount: 20 + - Level: 3 + Amount: 30 + - Level: 4 + Amount: 40 + - Level: 5 + Amount: 50 + +------------------ + Equipment: Equipped item required to cast. --------------------------------------- diff --git a/doc/yaml/db/mob_db.yml b/doc/yaml/db/mob_db.yml index a9a5bc5fda..d4d8939469 100644 --- a/doc/yaml/db/mob_db.yml +++ b/doc/yaml/db/mob_db.yml @@ -19,6 +19,8 @@ # Attack2 Maximum attack in pre-renewal and base magic attack in renewal. (Default: 0) # Defense Physical defense of the monster, reduces melee and ranged physical attack/skill damage. (Default: 0) # MagicDefense Magic defense of the monster, reduces magical skill damage. (Default: 0) +# Resistance Physical resistance of the monster, reduces melee and ranged physical attack/skill damage. (Default: 0) +# MagicResistance Magic resistance of the monster, reduces magical skill damage. (Default: 0) # Str Strength which affects attack. (Default: 1) # Agi Agility which affects flee. (Default: 1) # Vit Vitality which affects defense. (Default: 1) diff --git a/doc/yaml/db/skill_db.yml b/doc/yaml/db/skill_db.yml index 45e46115f9..0cb6392bd0 100644 --- a/doc/yaml/db/skill_db.yml +++ b/doc/yaml/db/skill_db.yml @@ -32,6 +32,9 @@ # Knockback: Amount of tiles the skill knockbacks. (Default: 0) # - Level Skill level. # Amount Knockback count at specific skill level. +# GiveAp: Gives AP on successful skill cast. (Default: 0) +# - Level Skill level. +# Amount AP gained at specific skill level. # CopyFlags: Determines if the skill is copyable. (Optional) # Skill: Type of skill that can copy. # RemoveRequirement: Remove a requirement type. (Optional) @@ -70,12 +73,18 @@ # SpCost: SP required to cast. (Default: 0) # - Level Skill level. # Amount SP required at specific skill level. +# ApCost: AP required to cast. (Default: 0) +# - Level Skill level. +# Amount AP required at specific skill level. # HpRateCost: HP rate required to cast. If positive, uses current HP, else uses Max HP. (Default: 0) # - Level Skill level. # Amount HP rate required at specific skill level. # SpRateCost: SP rate required to cast. If positive, uses current SP, else uses Max SP. (Default: 0) # - Level Skill level. # Amount SP rate required at specific skill level. +# ApRateCost: AP rate required to cast. If positive, uses current AP, else uses Max AP. (Default: 0) +# - Level Skill level. +# Amount AP rate required at specific skill level. # MaxHpTrigger: Maximum amount of HP to cast the skill. (Default: 0) # - Level Skill level. # Amount Maximum HP trigger required at specific skill level. diff --git a/doc/yaml/db/statpoint.yml b/doc/yaml/db/statpoint.yml index 3d5a497082..ab32bfe14e 100644 --- a/doc/yaml/db/statpoint.yml +++ b/doc/yaml/db/statpoint.yml @@ -7,4 +7,5 @@ ########################################################################### # - Level BaseLevel required. # Points Total status points given from BaseLevel 1 to 'Level'. +# TraitPoints Total trait points given from BaseLevel 1 to 'Level'. ########################################################################### diff --git a/doc/yaml/sql/mob_db2_re.sql b/doc/yaml/sql/mob_db2_re.sql index c036545c03..d9649f6481 100644 --- a/doc/yaml/sql/mob_db2_re.sql +++ b/doc/yaml/sql/mob_db2_re.sql @@ -18,6 +18,8 @@ CREATE TABLE `mob_db2_re` ( `attack2` smallint(6) unsigned DEFAULT NULL, `defense` smallint(6) unsigned DEFAULT NULL, `magic_defense` smallint(6) unsigned DEFAULT NULL, + `resistance` smallint(6) unsigned DEFAULT NULL, + `magic_resistance` smallint(6) unsigned DEFAULT NULL, `str` smallint(6) unsigned DEFAULT NULL, `agi` smallint(6) unsigned DEFAULT NULL, `vit` smallint(6) unsigned DEFAULT NULL, diff --git a/doc/yaml/sql/mob_db_re.sql b/doc/yaml/sql/mob_db_re.sql index 223ac2d5df..1e9a97a137 100644 --- a/doc/yaml/sql/mob_db_re.sql +++ b/doc/yaml/sql/mob_db_re.sql @@ -18,6 +18,8 @@ CREATE TABLE `mob_db_re` ( `attack2` smallint(6) unsigned DEFAULT NULL, `defense` smallint(6) unsigned DEFAULT NULL, `magic_defense` smallint(6) unsigned DEFAULT NULL, + `resistance` smallint(6) unsigned DEFAULT NULL, + `magic_resistance` smallint(6) unsigned DEFAULT NULL, `str` smallint(6) unsigned DEFAULT NULL, `agi` smallint(6) unsigned DEFAULT NULL, `vit` smallint(6) unsigned DEFAULT NULL, diff --git a/npc/custom/jobmaster.txt b/npc/custom/jobmaster.txt index 59c4589a21..f3c0389ab4 100644 --- a/npc/custom/jobmaster.txt +++ b/npc/custom/jobmaster.txt @@ -13,6 +13,7 @@ //= 1.7 Readability changes. Also added BabyExpanded and BabySummoner classes. [Jey] //= 1.8 Added option to disable Baby Novice Only but Baby Class can be Enabled [mazvi] //= 1.9 Migrate/Integrate to Global Functions Platinum Skills. [mazvi] +//= 2.0 Added 4th class [Lemongrass] //============================================================ prontera,153,193,6 script Job Master 123,{ @@ -42,6 +43,22 @@ function Is_Baby { return ((getarg(0, eaclass())&EAJL_BABY)>0); } +// Checks if the player can change to fourth class. +// Note: This does not include the level checks. +function Can_Change_Fourth { + // To change to third class you need to be: + // * Transcendent Third Class + if( !.FourthClass ) + return false; // Fourth job change disabled + if( (eaclass()&(EAJL_THIRD|EAJL_UPPER)) != (EAJL_THIRD|EAJL_UPPER) ) + return false; // Not Transcendent Third Class + if( eaclass()&EAJL_FOURTH ) + return false; // Already Fourth Class + if( roclass(eaclass()|EAJL_FOURTH) < 0 ) + return false; // Job has no Fourth Class + return true; +} + // Checks if the player can change to third class. // Note: This does not include the level checks. function Can_Change_Third { @@ -127,6 +144,7 @@ function Job_Options { // initialisation .@eac = eaclass(); + .@fourth_possible = Can_Change_Fourth(); .@third_possible = Can_Change_Third(); .@rebirth_possible = Can_Rebirth(); .@first_eac = .@eac&EAJ_BASEMASK; @@ -150,6 +168,11 @@ function Job_Options { Require_Level(.Req_Third[0], .Req_Third[1]); Job_Options(.@job_opt, roclass(.@eac|EAJL_THIRD)); } + if( .@fourth_possible ) { + // Fourth Job change (displayed below rebirth) + Require_Level(.Req_Fourth[0], .Req_Fourth[1]); + Job_Options(.@job_opt, roclass(.@eac|EAJL_FOURTH)); + } if (.SecondExpanded && (.@eac&EAJ_UPPERMASK) == EAJ_SUPER_NOVICE && // is Super Novice @@ -353,7 +376,10 @@ function Get_Job_Equip { // Note: The item is dropping, when the player can't hold it. // But that's better than not giving the item at all. .@eac = eaclass(); - if( .@eac&EAJL_THIRD ) { + if( .@eac&EAJL_FOURTH ) { + // Fourth Class Items + getitem 490087,1; // Hourglass Necklace + } else if( .@eac&EAJL_THIRD ) { // Third Class Items getitem 2795,1; // Green Apple Ring for every 3rd Class switch(BaseJob) { @@ -456,24 +482,26 @@ OnInit: .NPCName$ = "[Job Master]"; // Settings - .ThirdClass = true; // Enable third classes? - .RebirthClass = true; // Enable rebirth classes? - .SecondExpanded = true; // Enable new expanded second classes: Ex. Super Novice, Kagerou/Oboro, Rebellion? - .BabyNovice = true; // Enable Baby novice classes? Disable it if you like player must have parent to get job baby. - .BabyClass = true; // Enable Baby classes? - .BabyThird = true; // Enable Baby third classes? - .BabyExpanded = true; // Enable Baby Expanded classes: Ex. Baby Ninja, Baby Taekwon, etc. - .BabySummoner = true; // Enable Baby Summoner? - .LastJob = true; // Enforce linear class changes? - .SkillPointCheck = true; // Force player to use up all skill points? - .Platinum = true; // Get platinum skills automatically? - .GetJobEquip = false; // Get job equipment (mostly weapons) on job change? + .FourthClass = true; // Enable fourth classes? + .ThirdClass = true; // Enable third classes? + .RebirthClass = true; // Enable rebirth classes? + .SecondExpanded = true; // Enable new expanded second classes: Ex. Super Novice, Kagerou/Oboro, Rebellion? + .BabyNovice = true; // Enable Baby novice classes? Disable it if you like player must have parent to get job baby. + .BabyClass = true; // Enable Baby classes? + .BabyThird = true; // Enable Baby third classes? + .BabyExpanded = true; // Enable Baby Expanded classes: Ex. Baby Ninja, Baby Taekwon, etc. + .BabySummoner = true; // Enable Baby Summoner? + .LastJob = true; // Enforce linear class changes? + .SkillPointCheck = true; // Force player to use up all skill points? + .Platinum = true; // Get platinum skills automatically? + .GetJobEquip = false; // Get job equipment (mostly weapons) on job change? // Level Requirements setarray .Req_First[0],1,10; // Minimum base level, job level to turn into 1st class setarray .Req_Second[0],1,40; // Minimum base level, job level to turn into 2nd class setarray .Req_Rebirth[0],99,50; // Minimum base level, job level to rebirth setarray .Req_Third[0],99,50; // Minimum base level, job level to change to third class + setarray .Req_Fourth[0],200,70; // Minimum base level, job level to change to fourth class setarray .Req_Exp_NJ_GS[0],99,70; // Minimum base level, job level to turn into Expanded Ninja and Gunslinger setarray .Req_Exp_SNOVI[0],99,99; // Minimum base level, job level to turn into Expanded Super Novice .SNovice = 45; // Minimum base level to turn into Super Novice diff --git a/npc/other/CashShop_Functions.txt b/npc/other/CashShop_Functions.txt index e05724088c..78c65ed122 100644 --- a/npc/other/CashShop_Functions.txt +++ b/npc/other/CashShop_Functions.txt @@ -328,3 +328,28 @@ function script F_CashReduceStat { statusup2 .@type,.@amount; return; } + +// Trait Status reduction potion +//============================================================ +// - Permanently reduces base trait stat by . +// - Returns trait status points equals to points needed to raise +// that trait stat to original value. +// - Doesn't work if base trait status would become lower than 0 after reduction. +// * callfunc("F_CashReduceTraitStat",{,,}); +function script F_CashReduceTraitStat { + .@type = getarg(0); + .@amount = getarg(1, -1); + .@itemid = getarg(2, 0); + + if((readparam(.@type) + .@amount) < 0) return; + + if(.@itemid) { + if(countitem(.@itemid)) + delitem .@itemid,1; + else + return; + } + TraitPoint += needed_trait_point(.@type, .@amount); + traitstatusup2 .@type,.@amount; + return; +} diff --git a/sql-files/main.sql b/sql-files/main.sql index 017d3dcd9d..dbb1b0fb98 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -212,12 +212,21 @@ CREATE TABLE IF NOT EXISTS `char` ( `int` smallint(4) unsigned NOT NULL default '0', `dex` smallint(4) unsigned NOT NULL default '0', `luk` smallint(4) unsigned NOT NULL default '0', + `pow` smallint(4) unsigned NOT NULL default '0', + `sta` smallint(4) unsigned NOT NULL default '0', + `wis` smallint(4) unsigned NOT NULL default '0', + `spl` smallint(4) unsigned NOT NULL default '0', + `con` smallint(4) unsigned NOT NULL default '0', + `crt` smallint(4) unsigned NOT NULL default '0', `max_hp` int(11) unsigned NOT NULL default '0', `hp` int(11) unsigned NOT NULL default '0', `max_sp` int(11) unsigned NOT NULL default '0', `sp` int(11) unsigned NOT NULL default '0', + `max_ap` int(11) unsigned NOT NULL default '0', + `ap` int(11) unsigned NOT NULL default '0', `status_point` int(11) unsigned NOT NULL default '0', `skill_point` int(11) unsigned NOT NULL default '0', + `trait_point` int(11) unsigned NOT NULL default '0', `option` int(11) NOT NULL default '0', `karma` tinyint(3) NOT NULL default '0', `manner` smallint(6) NOT NULL default '0', diff --git a/sql-files/mob_db2_re.sql b/sql-files/mob_db2_re.sql index 33c5656b0b..20722c5504 100644 --- a/sql-files/mob_db2_re.sql +++ b/sql-files/mob_db2_re.sql @@ -18,6 +18,8 @@ CREATE TABLE `mob_db2_re` ( `attack2` smallint(6) unsigned DEFAULT NULL, `defense` smallint(6) unsigned DEFAULT NULL, `magic_defense` smallint(6) unsigned DEFAULT NULL, + `resistance` smallint(6) unsigned DEFAULT NULL, + `magic_resistance` smallint(6) unsigned DEFAULT NULL, `str` smallint(6) unsigned DEFAULT NULL, `agi` smallint(6) unsigned DEFAULT NULL, `vit` smallint(6) unsigned DEFAULT NULL, diff --git a/sql-files/mob_db_re.sql b/sql-files/mob_db_re.sql index 1f9f22bb26..3de39427d8 100644 --- a/sql-files/mob_db_re.sql +++ b/sql-files/mob_db_re.sql @@ -18,6 +18,8 @@ CREATE TABLE `mob_db_re` ( `attack2` smallint(6) unsigned DEFAULT NULL, `defense` smallint(6) unsigned DEFAULT NULL, `magic_defense` smallint(6) unsigned DEFAULT NULL, + `resistance` smallint(6) unsigned DEFAULT NULL, + `magic_resistance` smallint(6) unsigned DEFAULT NULL, `str` smallint(6) unsigned DEFAULT NULL, `agi` smallint(6) unsigned DEFAULT NULL, `vit` smallint(6) unsigned DEFAULT NULL, diff --git a/sql-files/upgrades/upgrade_20211230.sql b/sql-files/upgrades/upgrade_20211230.sql new file mode 100644 index 0000000000..a600c5244a --- /dev/null +++ b/sql-files/upgrades/upgrade_20211230.sql @@ -0,0 +1,11 @@ +ALTER TABLE `char` + ADD COLUMN `pow` SMALLINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `luk`, + ADD COLUMN `sta` SMALLINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `pow`, + ADD COLUMN `wis` SMALLINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `sta`, + ADD COLUMN `spl` SMALLINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `wis`, + ADD COLUMN `con` SMALLINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `spl`, + ADD COLUMN `crt` SMALLINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `con`, + ADD COLUMN `max_ap` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `sp`, + ADD COLUMN `ap` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `max_ap`, + ADD COLUMN `trait_point` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `status_point +; diff --git a/src/char/char.cpp b/src/char/char.cpp index 3aea9bfeb3..f6c49ea036 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -299,7 +299,10 @@ int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){ (p->rename != cp->rename) || (p->robe != cp->robe) || (p->character_moves != cp->character_moves) || (p->unban_time != cp->unban_time) || (p->font != cp->font) || (p->uniqueitem_counter != cp->uniqueitem_counter) || (p->hotkey_rowshift != cp->hotkey_rowshift) || (p->clan_id != cp->clan_id ) || (p->title_id != cp->title_id) || - (p->show_equip != cp->show_equip) || (p->hotkey_rowshift2 != cp->hotkey_rowshift2) + (p->show_equip != cp->show_equip) || (p->hotkey_rowshift2 != cp->hotkey_rowshift2) || + (p->max_ap != cp->max_ap) || (p->ap != cp->ap) || (p->trait_point != cp->trait_point) || + (p->pow != cp->pow) || (p->sta != cp->sta) || (p->wis != cp->wis) || + (p->spl != cp->spl) || (p->con != cp->con) || (p->crt != cp->crt) ) { //Save status if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d'," @@ -310,7 +313,9 @@ int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){ "`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'," "`delete_date`='%lu',`robe`='%d',`moves`='%d',`font`='%u',`uniqueitem_counter`='%u'," - "`hotkey_rowshift`='%d', `clan_id`='%d', `title_id`='%lu', `show_equip`='%d', `hotkey_rowshift2`='%d'" + "`hotkey_rowshift`='%d', `clan_id`='%d', `title_id`='%lu', `show_equip`='%d', `hotkey_rowshift2`='%d'," + "`max_ap`='%u',`ap`='%u',`trait_point`='%d'," + "`pow`='%d',`sta`='%d',`wis`='%d',`spl`='%d',`con`='%d',`crt`='%d'" " WHERE `account_id`='%d' AND `char_id` = '%d'", schema_config.char_db, p->base_level, p->job_level, p->base_exp, p->job_exp, p->zeny, @@ -323,6 +328,8 @@ int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){ (unsigned long)p->delete_date, // FIXME: platform-dependent size p->robe, p->character_moves, p->font, p->uniqueitem_counter, p->hotkey_rowshift, p->clan_id, p->title_id, p->show_equip, p->hotkey_rowshift2, + p->max_ap, p->ap, p->trait_point, + p->pow, p->sta, p->wis, p->spl, p->con, p->crt, p->account_id, p->char_id) ) { Sql_ShowDebug(sql_handle); @@ -924,7 +931,8 @@ int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf, uint8* coun "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," "`clothes_color`,`body`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`," "`robe`,`moves`,`unban_time`,`font`,`uniqueitem_counter`,`sex`,`hotkey_rowshift`,`title_id`,`show_equip`," - "`hotkey_rowshift2`" + "`hotkey_rowshift2`," + "`max_ap`,`ap`,`trait_point`,`pow`,`sta`,`wis`,`spl`,`con`,`crt`" " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", schema_config.char_db, sd->account_id, MAX_CHARS) || SQL_ERROR == SqlStmt_Execute(stmt) || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) @@ -973,6 +981,15 @@ int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf, uint8* coun || SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_ULONG, &p.title_id, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_UINT16, &p.show_equip, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_UCHAR, &p.hotkey_rowshift2, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_UINT, &p.max_ap, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_UINT, &p.ap, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_UINT, &p.trait_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_SHORT, &p.pow, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_SHORT, &p.sta, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 51, SQLDT_SHORT, &p.wis, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 52, SQLDT_SHORT, &p.spl, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 53, SQLDT_SHORT, &p.con, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 54, SQLDT_SHORT, &p.crt, 0, NULL, NULL) ) { SqlStmt_ShowDebug(stmt); @@ -1040,7 +1057,8 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`," "`hair_color`,`clothes_color`,`body`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`, `moves`," - "`unban_time`,`font`,`uniqueitem_counter`,`sex`,`hotkey_rowshift`,`clan_id`,`title_id`,`show_equip`,`hotkey_rowshift2`" + "`unban_time`,`font`,`uniqueitem_counter`,`sex`,`hotkey_rowshift`,`clan_id`,`title_id`,`show_equip`,`hotkey_rowshift2`," + "`max_ap`,`ap`,`trait_point`,`pow`,`sta`,`wis`,`spl`,`con`,`crt`" " FROM `%s` WHERE `char_id`=? LIMIT 1", schema_config.char_db) || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SqlStmt_Execute(stmt) @@ -1107,6 +1125,15 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev || SQL_ERROR == SqlStmt_BindColumn(stmt, 60, SQLDT_ULONG, &p->title_id, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 61, SQLDT_UINT16, &p->show_equip, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 62, SQLDT_UCHAR, &p->hotkey_rowshift2, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 63, SQLDT_UINT, &p->max_ap, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 64, SQLDT_UINT, &p->ap, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 65, SQLDT_UINT, &p->trait_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 66, SQLDT_SHORT, &p->pow, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 67, SQLDT_SHORT, &p->sta, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 68, SQLDT_SHORT, &p->wis, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 69, SQLDT_SHORT, &p->spl, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 70, SQLDT_SHORT, &p->con, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 71, SQLDT_SHORT, &p->crt, 0, NULL, NULL) ) { SqlStmt_ShowDebug(stmt); @@ -2017,7 +2044,7 @@ void char_read_fame_list(void) memset(chemist_fame_list, 0, sizeof(chemist_fame_list)); memset(taekwon_fame_list, 0, sizeof(taekwon_fame_list)); // Build Blacksmith ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", schema_config.char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, JOB_MECHANIC, JOB_MECHANIC_T, JOB_BABY_MECHANIC, fame_list_size_smith) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", schema_config.char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, JOB_MECHANIC, JOB_MECHANIC_T, JOB_BABY_MECHANIC, JOB_MEISTER, fame_list_size_smith) ) Sql_ShowDebug(sql_handle); for( i = 0; i < fame_list_size_smith && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) { @@ -2032,7 +2059,7 @@ void char_read_fame_list(void) memcpy(smith_fame_list[i].name, data, zmin(len, NAME_LENGTH)); } // Build Alchemist ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", schema_config.char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, JOB_GENETIC, JOB_GENETIC_T, JOB_BABY_GENETIC, fame_list_size_chemist) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", schema_config.char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, JOB_GENETIC, JOB_GENETIC_T, JOB_BABY_GENETIC, JOB_BIOLO, fame_list_size_chemist) ) Sql_ShowDebug(sql_handle); for( i = 0; i < fame_list_size_chemist && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) { @@ -2316,7 +2343,8 @@ bool char_checkdb(void){ "`shield`,`head_top`,`head_mid`,`head_bottom`,`robe`,`last_map`,`last_x`,`last_y`,`save_map`," "`save_x`,`save_y`,`partner_id`,`online`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`," "`moves`,`unban_time`,`font`,`sex`,`hotkey_rowshift`,`clan_id`,`last_login`,`title_id`,`show_equip`," - "`hotkey_rowshift2`" + "`hotkey_rowshift2`," + "`max_ap`,`ap`,`trait_point`,`pow`,`sta`,`wis`,`spl`,`con`,`crt`" " FROM `%s` LIMIT 1;", schema_config.char_db) ){ Sql_ShowDebug(sql_handle); return false; diff --git a/src/char/char_logif.cpp b/src/char/char_logif.cpp index 908cf9dc40..2bc9936c2c 100644 --- a/src/char/char_logif.cpp +++ b/src/char/char_logif.cpp @@ -414,6 +414,10 @@ void chlogif_parse_change_sex_sub(int sex, int acc, int char_id, int class_, int class_ = (sex == SEX_MALE ? JOB_KAGEROU : JOB_OBORO); else if (class_ == JOB_BABY_KAGEROU || class_ == JOB_BABY_OBORO) class_ = (sex == SEX_MALE ? JOB_BABY_KAGEROU : JOB_BABY_OBORO); + else if (class_ == JOB_TROUBADOUR || class_ == JOB_TROUVERE) + class_ = (sex == SEX_MALE ? JOB_TROUBADOUR : JOB_TROUVERE); + else if (class_ == JOB_SHINKIRO || class_ == JOB_SHIRANUI) + class_ = (sex == SEX_MALE ? JOB_SHINKIRO : JOB_SHIRANUI); if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `equip` = '0' WHERE `char_id` = '%d'", schema_config.inventory_db, char_id)) Sql_ShowDebug(sql_handle); diff --git a/src/char/inter.cpp b/src/char/inter.cpp index 8e4d4678b2..2e143df3fc 100644 --- a/src/char/inter.cpp +++ b/src/char/inter.cpp @@ -356,7 +356,10 @@ const char* job_name(int class_) { case JOB_NIGHT_WATCH: case JOB_HYPER_NOVICE: case JOB_SPIRIT_HANDLER: - return msg_txt( 143 - JOB_SKY_EMPEROR + class_ ); + return msg_txt( 135 - JOB_SKY_EMPEROR + class_ ); + + case JOB_SKY_EMPEROR2: + return msg_txt( 135 ); default: return msg_txt(199); diff --git a/src/common/mmo.hpp b/src/common/mmo.hpp index 746dc69185..e98f1ba9ee 100644 --- a/src/common/mmo.hpp +++ b/src/common/mmo.hpp @@ -63,7 +63,7 @@ typedef uint32 t_itemid; #define MAX_BANK_ZENY SINT32_MAX ///Max zeny in Bank #define MAX_FAME 1000000000 ///Max fame points #define MAX_CART 100 ///Maximum item in cart -#define MAX_SKILL 1250 ///Maximum skill can be hold by Player, Homunculus, & Mercenary (skill list) AND skill_db limit +#define MAX_SKILL 1450 ///Maximum skill can be hold by Player, Homunculus, & Mercenary (skill list) AND skill_db limit #define DEFAULT_WALK_SPEED 150 ///Default walk speed #define MIN_WALK_SPEED 20 ///Min walk speed #define MAX_WALK_SPEED 1000 ///Max walk speed @@ -165,9 +165,13 @@ const t_itemid WEDDING_RING_F = 2635; #define MAX_MERCSKILL 41 //Elemental System -#define MAX_ELEMENTALSKILL 42 +#define MAX_ELEMENTALSKILL 57 #define EL_SKILLBASE 8401 +//Automated Battle Robot System +#define ABR_SKILLBASE 8601 +#define MAX_ABRSKILL 5 + //Achievement System #define MAX_ACHIEVEMENT_OBJECTIVES 10 /// Maximum different objectives in achievement_db.yml #define MAX_ACHIEVEMENT_DEPENDENTS 20 /// Maximum different dependents in achievement_db.yml @@ -516,8 +520,8 @@ struct mmo_charstatus { int zeny; short class_; ///< Player's JobID - unsigned int status_point,skill_point; - int hp,max_hp,sp,max_sp; + unsigned int status_point,skill_point,trait_point; + int hp,max_hp,sp,max_sp,ap,max_ap; unsigned int option; short manner; // Defines how many minutes a char will be muted, each negative point is equivalent to a minute. unsigned char karma; @@ -1022,6 +1026,8 @@ enum e_job { JOB_HYPER_NOVICE, JOB_SPIRIT_HANDLER, + JOB_SKY_EMPEROR2 = 4316, + JOB_MAX, }; diff --git a/src/config/packets.hpp b/src/config/packets.hpp index 91e6d37ee1..be9d11186f 100644 --- a/src/config/packets.hpp +++ b/src/config/packets.hpp @@ -13,13 +13,13 @@ /// Do NOT edit this line! To set your client version, please do this instead: /// In Windows: Add this line in your src\custom\defines_pre.hpp file: #define PACKETVER YYYYMMDD /// In Linux: The same as above or run the following command: ./configure --enable-packetver=YYYYMMDD - #define PACKETVER 20200401 + #define PACKETVER 20200902 #endif #ifndef PACKETVER_RE /// From November 2015 only RagexeRE are supported. /// After July 2018 only Ragexe are supported. - #if PACKETVER > 20151104 && PACKETVER < 20180704 + #if ( PACKETVER > 20151104 && PACKETVER < 20180704 ) || PACKETVER >= 20200902 #define PACKETVER_RE #endif #endif diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index e83a462477..7feac26420 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1170,7 +1170,7 @@ ACMD_FUNC(jobchange) } } - // High Jobs, Babys and Third + // High Jobs, Babys, Third, and Fourth for( i = JOB_NOVICE_HIGH; i < JOB_MAX && !found; i++ ) { if (strncmpi(message, job_name(i), 16) == 0) { job = i; @@ -1189,7 +1189,8 @@ ACMD_FUNC(jobchange) if (job == JOB_KNIGHT2 || job == JOB_CRUSADER2 || job == JOB_WEDDING || job == JOB_XMAS || job == JOB_SUMMER || job == JOB_HANBOK || job == JOB_OKTOBERFEST || job == JOB_LORD_KNIGHT2 || job == JOB_PALADIN2 || job == JOB_BABY_KNIGHT2 || job == JOB_BABY_CRUSADER2 || job == JOB_STAR_GLADIATOR2 || (job >= JOB_RUNE_KNIGHT2 && job <= JOB_MECHANIC_T2) || (job >= JOB_BABY_RUNE_KNIGHT2 && job <= JOB_BABY_MECHANIC2) || job == JOB_BABY_STAR_GLADIATOR2 - || job == JOB_STAR_EMPEROR2 || job == JOB_BABY_STAR_EMPEROR2 || job == JOB_SUMMER2) + || job == JOB_STAR_EMPEROR2 || job == JOB_BABY_STAR_EMPEROR2 || job == JOB_SUMMER2 + || (job >= JOB_WINDHAWK2 && job <= JOB_IMPERIAL_GUARD2) || job == JOB_SKY_EMPEROR2) { // Deny direct transformation into dummy jobs clif_displaymessage(fd, msg_txt(sd,923)); //"You can not change to this job by command." return 0; @@ -1336,6 +1337,38 @@ ACMD_FUNC(heal) return 0; } +/*========================================== +* Recover's AP and allows exact adjustments. [Rytech] +*------------------------------------------*/ +ACMD_FUNC(healap) +{ + int ap = 0; + nullpo_retr(-1, sd); + + sscanf(message, "%11d", &ap); + + // Overflow check. + if (ap == INT_MIN) ap++; + + if (ap == 0) { + if (!status_percent_heal(&sd->bl, 0, 0, 100)) + clif_displaymessage(fd, msg_txt(sd, 823));// AP have already been recovered. + else + clif_displaymessage(fd, msg_txt(sd, 821));// AP recovered. + return 0; + }else if (ap > 0) { + if (!status_heal(&sd->bl, 0, 0, ap, 0)) + clif_displaymessage(fd, msg_txt(sd, 823));// AP have already been recovered. + else + clif_displaymessage(fd, msg_txt(sd, 821));// AP recovered. + return 0; + }else{ + status_damage(NULL, &sd->bl, 0, 0, -ap, 0, 0, 0); + clif_displaymessage(fd, msg_txt(sd, 822));// AP modified. + return 0; + } +} + /*========================================== * @item command (usage: @item ) (modified by [Yor] for pet_egg) * @itembound command (usage: @itembound ) @@ -1544,7 +1577,7 @@ ACMD_FUNC(itemreset) *------------------------------------------*/ ACMD_FUNC(baselevelup) { - int level=0, i=0, status_point=0; + int level=0, i=0, status_point=0, trait_point=0; nullpo_retr(-1, sd); level = atoi(message); @@ -1561,9 +1594,12 @@ ACMD_FUNC(baselevelup) if ((unsigned int)level > pc_maxbaselv(sd) || (unsigned int)level > pc_maxbaselv(sd) - sd->status.base_level) // fix positive overflow level = pc_maxbaselv(sd) - sd->status.base_level; for (i = 0; i < level; i++) + { status_point += statpoint_db.pc_gets_status_point(sd->status.base_level + i); - + trait_point += statpoint_db.pc_gets_trait_point(sd->status.base_level + i); + } sd->status.status_point += status_point; + sd->status.trait_point += trait_point; sd->status.base_level += (unsigned int)level; status_calc_pc(sd, SCO_FORCE); status_percent_heal(&sd->bl, 100, 100); @@ -1582,13 +1618,20 @@ ACMD_FUNC(baselevelup) if ((unsigned int)level >= sd->status.base_level) level = sd->status.base_level-1; for (i = 0; i > -level; i--) + { status_point += statpoint_db.pc_gets_status_point(sd->status.base_level + i - 1); - if (sd->status.status_point < status_point) + trait_point += statpoint_db.pc_gets_trait_point(sd->status.base_level + i - 1); + } + if (sd->status.status_point < status_point || sd->status.trait_point < trait_point) pc_resetstate(sd); if (sd->status.status_point < status_point) sd->status.status_point = 0; else sd->status.status_point -= status_point; + if (sd->status.trait_point < trait_point) + sd->status.trait_point = 0; + else + sd->status.trait_point -= trait_point; sd->status.base_level -= (unsigned int)level; clif_displaymessage(fd, msg_txt(sd,22)); // Base level lowered. status_calc_pc(sd, SCO_FORCE); @@ -1596,6 +1639,7 @@ ACMD_FUNC(baselevelup) } sd->status.base_exp = 0; clif_updatestatus(sd, SP_STATUSPOINT); + clif_updatestatus(sd, SP_TRAITPOINT); clif_updatestatus(sd, SP_BASELEVEL); clif_updatestatus(sd, SP_BASEEXP); clif_updatestatus(sd, SP_NEXTBASEEXP); @@ -1842,7 +1886,7 @@ ACMD_FUNC(bodystyle) memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!(sd->class_ & JOBL_THIRD) || (sd->class_ & MAPID_THIRDMASK) == MAPID_SUPER_NOVICE_E || (sd->class_ & MAPID_THIRDMASK) == MAPID_STAR_EMPEROR || (sd->class_ & MAPID_THIRDMASK) == MAPID_SOUL_REAPER) { + if ( (sd->class_ & JOBL_FOURTH) || !(sd->class_ & JOBL_THIRD) || (sd->class_ & MAPID_THIRDMASK) == MAPID_SUPER_NOVICE_E || (sd->class_ & MAPID_THIRDMASK) == MAPID_STAR_EMPEROR || (sd->class_ & MAPID_THIRDMASK) == MAPID_SOUL_REAPER) { clif_displaymessage(fd, msg_txt(sd,740)); // This job has no alternate body styles. return -1; } @@ -2574,6 +2618,55 @@ ACMD_FUNC(statuspoint) return 0; } +/*========================================== +* @trpoint +*------------------------------------------*/ +ACMD_FUNC(traitpoint) +{ + int point; + unsigned int new_trait_point; + + if (!message || !*message || (point = atoi(message)) == 0) { + clif_displaymessage(fd, msg_txt(sd, 820)); // Please enter a number (usage: @trpoint ). + return -1; + } + + if (point < 0) + { + if (sd->status.trait_point < (unsigned int)(-point)) + { + new_trait_point = 0; + } + else + { + new_trait_point = sd->status.trait_point + point; + } + } + else if (UINT_MAX - sd->status.trait_point < (unsigned int)point) + { + new_trait_point = UINT_MAX; + } + else + { + new_trait_point = sd->status.trait_point + point; + } + + if (new_trait_point != sd->status.trait_point) { + sd->status.trait_point = new_trait_point; + clif_updatestatus(sd, SP_TRAITPOINT); + clif_displaymessage(fd, msg_txt(sd, 174)); // Number of status points changed. + } + else { + if (point < 0) + clif_displaymessage(fd, msg_txt(sd, 41)); // Unable to decrease the number/value. + else + clif_displaymessage(fd, msg_txt(sd, 149)); // Unable to increase the number/value. + return -1; + } + + return 0; +} + /*========================================== * @skpoint (Rewritten by [Yor]) *------------------------------------------*/ @@ -2757,7 +2850,7 @@ ACMD_FUNC(stat_all) } count = 0; - for (i = PARAM_STR; i <= PARAM_LUK; i++) { + for (i = PARAM_STR; i < PARAM_POW; i++) { short new_value; if (value > 0 && status[i] + value >= max_status[i]) @@ -2842,7 +2935,7 @@ ACMD_FUNC(trait_all) { new_value = status[i] + value; if (new_value != status[i]) { - pc_setstat( sd, SP_POW + i, new_value ); + pc_setstat( sd, SP_POW + i - PARAM_POW, new_value ); clif_updatestatus(sd, SP_POW + i - PARAM_POW); clif_updatestatus(sd, SP_UPOW + i - PARAM_POW); count++; @@ -4536,7 +4629,7 @@ ACMD_FUNC(mount_peco) } return 0; } - if( (sd->class_&MAPID_THIRDMASK) == MAPID_RANGER && pc_checkskill(sd,RA_WUGRIDER) > 0 && (!pc_isfalcon(sd) || battle_config.warg_can_falcon) ) { + if( (sd->class_&MAPID_THIRDMASK) == MAPID_RANGER && pc_checkskill(sd,RA_WUGRIDER) > 0 && (!pc_isfalcon(sd) || (pc_checkskill(sd, WH_HAWK_M) || battle_config.warg_can_falcon)) ) { if( !pc_isridingwug(sd) ) { clif_displaymessage(sd->fd,msg_txt(sd,1121)); // You have mounted your Warg. pc_setoption(sd, sd->sc.option|OPTION_WUGRIDER); @@ -6035,18 +6128,76 @@ ACMD_FUNC(displayskill) t_tick tick; uint16 skill_id; uint16 skill_lv = 1; + uint16 type = 0; nullpo_retr(-1, sd); - if (!message || !*message || sscanf(message, "%6hu %6hu", &skill_id, &skill_lv) < 1) + if (!message || !*message || sscanf(message, "%6hu %6hu %6hu", &skill_id, &skill_lv, &type) < 1) { - clif_displaymessage(fd, msg_txt(sd,1166)); // Usage: @displayskill {} + clif_displaymessage(fd, msg_txt(sd,1166));// Usage: @displayskill { } + clif_displaymessage(fd, msg_txt(sd,825));// Effect Types: 0: All, 1: Damage, 2: Splash Dmg, 3: No Damage, 4: Ground return -1; } status = status_get_status_data(&sd->bl); tick = gettick(); - clif_skill_damage(&sd->bl,&sd->bl, tick, status->amotion, status->dmotion, 1, 1, skill_id, skill_lv, DMG_SPLASH); - clif_skill_nodamage(&sd->bl, &sd->bl, skill_id, skill_lv, 1); - clif_skill_poseffect(&sd->bl, skill_id, skill_lv, sd->bl.x, sd->bl.y, tick); + if (type == 0 || type == 1) + clif_skill_damage(&sd->bl, &sd->bl, tick, status->amotion, status->dmotion, 1, 1, skill_id, skill_lv, DMG_SINGLE); + if (type == 0 || type == 2) + clif_skill_damage(&sd->bl, &sd->bl, tick, status->amotion, status->dmotion, 1, 1, skill_id, skill_lv, DMG_SPLASH); + if (type == 0 || type == 3) + clif_skill_nodamage(&sd->bl, &sd->bl, skill_id, skill_lv, 1); + if (type == 0 || type == 4) + clif_skill_poseffect(&sd->bl, skill_id, skill_lv, sd->bl.x, sd->bl.y, tick); + return 0; +} + +/*========================================== +* @displayskillcast by [Rytech] +* Debug command to view casting animations for skills. +* Can target self or the ground. Ground target can be +* useful for seeing casting circle size. +*------------------------------------------*/ +ACMD_FUNC(displayskillcast) +{ + uint16 skill_id; + uint16 skill_lv = 1; + uint16 cast_time = 5000; + uint16 target_type = 0; + nullpo_retr(-1, sd); + + if (!message || !*message || sscanf(message, "%6hu %6hu %6hu %6hu", &skill_id, &skill_lv, &target_type, &cast_time) < 1) + { + clif_displaymessage(fd, msg_txt(sd, 824));// Usage: @displayskillcast { } + return -1; + } + + if ( target_type == 1) + clif_skillcasting(&sd->bl, sd->bl.id, 0, sd->bl.x, sd->bl.y, skill_id, skill_lv, 0, cast_time); + else + clif_skillcasting(&sd->bl, sd->bl.id, sd->bl.id, 0, 0, skill_id, skill_lv, 0, cast_time); + + return 0; +} + +/*========================================== +* @displayskillunit by [Rytech] +* Debug command to view unit animations for skills. +*------------------------------------------*/ +ACMD_FUNC(displayskillunit) +{ + uint16 unit_id; + uint16 range = 0; + uint16 skill_lv = 1; + + nullpo_retr(-1, sd); + + if (!message || !*message || sscanf(message, "%6hu %6hu %6hu", &unit_id, &skill_lv, &range) < 1) + { + clif_displaymessage(fd, msg_txt(sd, 826));// Usage: @displayskillunit { } + return -1; + } + + clif_skill_unit_test(&sd->bl, sd->bl.x, sd->bl.y, unit_id, range, skill_lv); + return 0; } @@ -7538,6 +7689,10 @@ ACMD_FUNC(mobinfo) mob->range2 , mob->range3, msize[mob->status.size], mrace[mob->status.race], melement[mob->status.def_ele], mob->status.ele_lv); clif_displaymessage(fd, atcmd_output); +#ifdef RENEWAL + sprintf(atcmd_output, msg_txt(sd, 827), mob->status.res, mob->status.mres);// MDEF:%d RES:%d MRES:%d + clif_displaymessage(fd, atcmd_output); +#endif // drops clif_displaymessage(fd, msg_txt(sd,1245)); // Drops: strcpy(atcmd_output, " "); @@ -9209,16 +9364,27 @@ ACMD_FUNC(stats) { "MaxHp - %d", 0 }, { "Sp - %d", 0 }, { "MaxSp - %d", 0 }, + { "Ap - %d", 0 }, + { "MaxAp - %d", 0 }, { "Str - %3d", 0 }, { "Agi - %3d", 0 }, { "Vit - %3d", 0 }, { "Int - %3d", 0 }, { "Dex - %3d", 0 }, { "Luk - %3d", 0 }, + { "Pow - %3d", 0 }, + { "Sta - %3d", 0 }, + { "Wis - %3d", 0 }, + { "Spl - %3d", 0 }, + { "Con - %3d", 0 }, + { "Crt - %3d", 0 }, { "Zeny - %d", 0 }, - { "Free SK Points - %d", 0 }, + { "Free Status Points - %d", 0 }, + { "Free Trait Points - %d", 0 }, + { "Free Skill Points - %d", 0 }, { "JobChangeLvl (2nd) - %d", 0 }, { "JobChangeLvl (3rd) - %d", 0 }, + { "JobChangeLvl (4th) - %d", 0 }, { NULL, 0 } }; @@ -9233,16 +9399,27 @@ ACMD_FUNC(stats) output_table[3].value = sd->status.max_hp; output_table[4].value = sd->status.sp; output_table[5].value = sd->status.max_sp; - output_table[6].value = sd->status.str; - output_table[7].value = sd->status.agi; - output_table[8].value = sd->status.vit; - output_table[9].value = sd->status.int_; - output_table[10].value = sd->status.dex; - output_table[11].value = sd->status.luk; - output_table[12].value = sd->status.zeny; - output_table[13].value = sd->status.skill_point; - output_table[14].value = sd->change_level_2nd; - output_table[15].value = sd->change_level_3rd; + output_table[6].value = sd->status.ap; + output_table[7].value = sd->status.max_ap; + output_table[8].value = sd->status.str; + output_table[9].value = sd->status.agi; + output_table[10].value = sd->status.vit; + output_table[11].value = sd->status.int_; + output_table[12].value = sd->status.dex; + output_table[13].value = sd->status.luk; + output_table[14].value = sd->status.pow; + output_table[15].value = sd->status.sta; + output_table[16].value = sd->status.wis; + output_table[17].value = sd->status.spl; + output_table[18].value = sd->status.con; + output_table[19].value = sd->status.crt; + output_table[20].value = sd->status.zeny; + output_table[21].value = sd->status.status_point; + output_table[22].value = sd->status.trait_point; + output_table[23].value = sd->status.skill_point; + output_table[24].value = sd->change_level_2nd; + output_table[25].value = sd->change_level_3rd; + output_table[26].value = sd->change_level_4th; sprintf(job_jobname, "Job - %s %s", job_name(sd->status.class_), "(level %d)"); sprintf(output, msg_txt(sd,53), sd->status.name); // '%s' stats: @@ -10521,6 +10698,7 @@ void atcommand_basecommands(void) { ACMD_DEF2("kamic", kami), ACMD_DEF2("lkami", kami), ACMD_DEF(heal), + ACMD_DEF(healap), ACMD_DEF(item), ACMD_DEF(item2), ACMD_DEF2("itembound",item), @@ -10549,6 +10727,7 @@ void atcommand_basecommands(void) { ACMD_DEF(gat), ACMD_DEF(displaystatus), ACMD_DEF2("stpoint", statuspoint), + ACMD_DEF2("trpoint", traitpoint), ACMD_DEF2("skpoint", skillpoint), ACMD_DEF(zeny), ACMD_DEF2("str", param), @@ -10655,6 +10834,8 @@ void atcommand_basecommands(void) { ACMD_DEF(skillid), ACMD_DEF(useskill), ACMD_DEF(displayskill), + ACMD_DEF(displayskillcast), + ACMD_DEF(displayskillunit), ACMD_DEF(snow), ACMD_DEF(sakura), ACMD_DEF(clouds), diff --git a/src/map/battle.cpp b/src/map/battle.cpp index 4134659a64..fc9f0a82a3 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -693,6 +693,8 @@ int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_li } cardfix = cardfix * (100 + sd->indexed_bonus.magic_addsize[tstatus->size] + sd->indexed_bonus.magic_addsize[SZ_ALL]) / 100; cardfix = cardfix * (100 + sd->indexed_bonus.magic_addclass[tstatus->class_] + sd->indexed_bonus.magic_addclass[CLASS_ALL]) / 100; + if (sd->status.weapon == W_2HSTAFF)// 2-Handed Staff Mastery + cardfix = cardfix * (100 + pc_checkskill(sd, AG_TWOHANDSTAFF)) / 100; for (const auto &it : sd->add_mdmg) { if (it.id == t_class) { cardfix = cardfix * (100 + it.val) / 100; @@ -949,6 +951,7 @@ int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_li int32 race_fix = 0; cardfix = cardfix * (100 - tsd->indexed_bonus.subsize[sstatus->size] - tsd->indexed_bonus.subsize[SZ_ALL]) / 100; + cardfix = cardfix * (100 - tsd->indexed_bonus.weapon_subsize[sstatus->size] - tsd->indexed_bonus.weapon_subsize[SZ_ALL]) / 100; for (const auto &raceit : s_race2) race_fix += tsd->indexed_bonus.subrace2[raceit]; cardfix = cardfix * (100 - race_fix) / 100; @@ -1143,6 +1146,19 @@ bool battle_status_block_damage(struct block_list *src, struct block_list *targe return false; } + if ((sce = sc->data[SC_GUARDIAN_S]) && damage > 0) { + clif_specialeffect(target, EF_GUARD3, AREA);// Not official but we gotta show some way the barrier is working. [Rytech] + sce->val2 -= static_cast(cap_value(damage, INT_MIN, INT_MAX)); + if (flag & BF_WEAPON) { + if (sce->val2 >= 0) + damage = 0; + else + damage = -sce->val2; + } + if (sce->val2 <= 0) + status_change_end(target, SC_GUARDIAN_S, INVALID_TIMER); + } + if (damage == 0) return false; @@ -1203,6 +1219,7 @@ bool battle_status_block_damage(struct block_list *src, struct block_list *targe if (skill_id == MG_NAPALMBEAT || skill_id == MG_SOULSTRIKE || skill_id == WL_SOULEXPANSION || + skill_id == AG_SOUL_VC_STRIKE || (skill_id && skill_get_ele(skill_id, skill_lv) == ELE_GHOST) || (skill_id == 0 && (status_get_status_data(src))->rhw.ele == ELE_GHOST)) { @@ -1504,6 +1521,10 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam damage += damage * bonus / 100; } + if (sc->data[SC_HOLY_OIL] && (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON)) + damage += damage * 50 / 100;// Need official adjustment. [Rytech] + if (sc->data[SC_SHADOW_SCAR])// Need official adjustment for this too. + damage += damage * (10 * sc->data[SC_SHADOW_SCAR]->val1) / 100; // Damage reductions // Assumptio increases DEF on RE mode, otherwise gives a reduction on the final damage. [Igniz] @@ -2320,24 +2341,29 @@ static int64 battle_calc_base_damage(struct block_list *src, struct status_data case ELEMENTALID_AGNI_S: case ELEMENTALID_AGNI_M: case ELEMENTALID_AGNI_L: + case ELEMENTALID_ARDOR: if (ele_sc->data[SC_FIRE_INSIGNIA] && ele_sc->data[SC_FIRE_INSIGNIA]->val1 == 1) damage += damage * 20 / 100; break; case ELEMENTALID_AQUA_S: case ELEMENTALID_AQUA_M: case ELEMENTALID_AQUA_L: + case ELEMENTALID_DILUVIO: if (ele_sc->data[SC_WATER_INSIGNIA] && ele_sc->data[SC_WATER_INSIGNIA]->val1 == 1) damage += damage * 20 / 100; break; case ELEMENTALID_VENTUS_S: case ELEMENTALID_VENTUS_M: case ELEMENTALID_VENTUS_L: + case ELEMENTALID_PROCELLA: if (ele_sc->data[SC_WIND_INSIGNIA] && ele_sc->data[SC_WIND_INSIGNIA]->val1 == 1) damage += damage * 20 / 100; break; case ELEMENTALID_TERA_S: case ELEMENTALID_TERA_M: case ELEMENTALID_TERA_L: + case ELEMENTALID_TERREMOTUS: + case ELEMENTALID_SERPENS: if (ele_sc->data[SC_EARTH_INSIGNIA] && ele_sc->data[SC_EARTH_INSIGNIA]->val1 == 1) damage += damage * 20 / 100; break; @@ -2406,12 +2432,23 @@ static int battle_range_type(struct block_list *src, struct block_list *target, // Renewal changes to ranged physical damage #endif case SR_RAMPAGEBLASTER: + case DK_HACKANDSLASHER_ATK: // 2 cell cast range. return BF_LONG; - case NJ_KIRIKAGE: - // Cast range mimics NJ_SHADOWJUMP but damage is considered melee - case GC_CROSSIMPACT: - // Cast range is 7 cells and player jumps to target but skill is considered melee + case NJ_KIRIKAGE: // Cast range mimics NJ_SHADOWJUMP but damage is considered melee + case GC_CROSSIMPACT: // Cast range is 7 cells and player jumps to target but skill is considered melee + case DK_SERVANT_W_PHANTOM: // 9 cell cast range. + case SHC_SAVAGE_IMPACT: // 7 cell cast range. + case SHC_FATAL_SHADOW_CROW: // 9 cell cast range. + case MT_RUSH_QUAKE: // 9 cell cast range. + case ABC_UNLUCKY_RUSH: // 7 cell cast range. + //case ABC_DEFT_STAB: // 2 cell cast range??? return BF_SHORT; + case CD_PETITIO: { // Skill range is 2 but damage is melee with books and ranged with mace. + map_session_data *sd = BL_CAST(BL_PC, src); + + if (sd && (sd->status.weapon == W_MACE || sd->status.weapon == W_2HMACE)) + return BF_LONG; + } } //Skill Range Criteria @@ -2750,8 +2787,14 @@ static bool is_attack_critical(struct Damage* wd, struct block_list *src, struct #endif case LG_CANNONSPEAR: case GC_CROSSIMPACT: + case SHC_SAVAGE_IMPACT: + case SHC_ETERNAL_SLASH: + case SHC_IMPACT_CRATER: cri /= 2; break; + case WH_GALESTORM: + if (sc && !sc->data[SC_CALAMITYGALE]) + return false; } if(tsd && tsd->bonus.critical_def) cri = cri * ( 100 - tsd->bonus.critical_def ) / 100; @@ -3555,6 +3598,8 @@ static void battle_calc_skill_base_damage(struct Damage* wd, struct block_list * damagevalue = damagevalue * status_get_lv(src) / 100; if(sd) damagevalue = damagevalue * (90 + 10 * pc_checkskill(sd, RK_DRAGONTRAINING)) / 100; + if (sc && sc->data[SC_DRAGONIC_AURA])// Need official damage increase. [Rytech] + damagevalue += damagevalue * 50 / 100; ATK_ADD(wd->damage, wd->damage2, damagevalue); #ifdef RENEWAL ATK_ADD(wd->weaponAtk, wd->weaponAtk2, damagevalue); @@ -3830,6 +3875,8 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * skillratio += 2 * sc->data[SC_TRUESIGHT]->val1; if (sc->data[SC_CONCENTRATION] && (skill_id != RK_DRAGONBREATH && skill_id != RK_DRAGONBREATH_WATER && skill_id != NPC_DRAGONBREATH)) skillratio += sc->data[SC_CONCENTRATION]->val2; + if (sc && sc->data[SC_VIGOR])// Lacking info on how damage is increased. Guessing for now. [Rytech] + skillratio += skillratio * 50 / 100; #endif if (!skill_id || skill_id == KN_AUTOCOUNTER) { if (sc->data[SC_CRUSHSTRIKE]) { @@ -3894,6 +3941,10 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * break; #endif case KN_PIERCE: + skillratio += 10 * skill_lv; + if (sc && sc->data[SC_CHARGINGPIERCE_COUNT] && sc->data[SC_CHARGINGPIERCE_COUNT]->val1 >= 10) + skillratio *= 2; + break; case ML_PIERCE: skillratio += 10 * skill_lv; break; @@ -4131,6 +4182,11 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * #ifdef RENEWAL // Renewal: skill ratio applies to entire damage [helvetica] case LK_SPIRALPIERCE: + skillratio += 50 + 50 * skill_lv; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_CHARGINGPIERCE_COUNT] && sc->data[SC_CHARGINGPIERCE_COUNT]->val1 >= 10) + skillratio *= 2; + break; case ML_SPIRALPIERCE: skillratio += 50 + 50 * skill_lv; RE_LVL_DMOD(100); @@ -4204,6 +4260,8 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * #else skillratio += 30 * skill_lv; #endif + if (sc && sc->data[SC_SHIELD_POWER])// Whats the official increase? [Rytech] + skillratio += skillratio * 50 / 100; break; case WS_CARTTERMINATION: i = 10 * (16 - skill_lv); @@ -4349,6 +4407,12 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * if (sd) skillratio += 50 * pc_checkskill(sd,LK_SPIRALPIERCE); RE_LVL_DMOD(100); + if (sc) { + if (sc->data[SC_CHARGINGPIERCE_COUNT] && sc->data[SC_CHARGINGPIERCE_COUNT]->val1 >= 10) + skillratio *= 2; + if (sc->data[SC_DRAGONIC_AURA])// Need official damage increase. [Rytech] + skillratio += skillratio * 50 / 100; + } break; case RK_WINDCUTTER: if (sd) { @@ -4495,6 +4559,8 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * case NC_POWERSWING: // According to current sources, only the str + dex gets modified by level [Akinari] skillratio += -100 + ((sstatus->str + sstatus->dex)/ 2) + 300 + 100 * skill_lv; RE_LVL_DMOD(100); + if (sc && sc->data[SC_ABR_BATTLE_WARIOR]) + skillratio *= 2; break; case NC_MAGMA_ERUPTION: // 'Slam' damage skillratio += 350 + 50 * skill_lv; @@ -4502,10 +4568,14 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * case NC_AXETORNADO: skillratio += -100 + 200 + 180 * skill_lv + sstatus->vit / 6; // !TODO: What's the VIT bonus? RE_LVL_DMOD(100); + if (sc && sc->data[SC_AXE_STOMP])// Whats the official increase? [Rytech] + skillratio += skillratio * 50 / 100; break; case SC_FATALMENACE: skillratio += 120 * skill_lv + sstatus->agi / 6; // !TODO: What's the AGI bonus? RE_LVL_DMOD(100); + if (sc && sc->data[SC_ABYSS_DAGGER]) + skillratio += skillratio * 50 / 100; break; case SC_TRIANGLESHOT: skillratio += -100 + 230 * skill_lv + 3 * sstatus->agi; @@ -4518,10 +4588,14 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * case LG_CANNONSPEAR: skillratio += -100 + skill_lv * (50 + sstatus->str); RE_LVL_DMOD(100); + if (sc && sc->data[SC_SPEAR_SCAR])// Whats the official increase? [Rytech] + skillratio += skillratio * 50 / 100; break; case LG_BANISHINGPOINT: skillratio += -100 + (80 * skill_lv) + ((sd) ? pc_checkskill(sd,SM_BASH) * 30 : 0); RE_LVL_DMOD(100); + if (sc && sc->data[SC_SPEAR_SCAR])// Whats the official increase? [Rytech] + skillratio += skillratio * 50 / 100; break; case LG_SHIELDPRESS: skillratio += -100 + 200 * skill_lv + sstatus->str; @@ -4532,6 +4606,8 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * skillratio += sd->inventory_data[index]->weight / 10; } RE_LVL_DMOD(100); + if (sc && sc->data[SC_SHIELD_POWER])// Whats the official increase? [Rytech] + skillratio += skillratio * 50 / 100; break; case LG_PINPOINTATTACK: skillratio += -100 + 100 * skill_lv + 5 * status_get_agi(src); @@ -4559,6 +4635,8 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * case LG_EARTHDRIVE: skillratio += -100 + 380 * skill_lv + ((sstatus->str + sstatus->vit) / 6); // !TODO: What's the STR/VIT bonus? RE_LVL_DMOD(100); + if (sc && sc->data[SC_SHIELD_POWER])// Whats the official increase? [Rytech] + skillratio += skillratio * 50 / 100; break; case LG_HESPERUSLIT: if (sc && sc->data[SC_INSPIRATION]) @@ -4686,6 +4764,8 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * skillratio += -100 + 200 * skill_lv; if(sd && sd->cart_weight) skillratio += sd->cart_weight / 10 / (150 - min(sd->status.str,120)) + pc_checkskill(sd,GN_REMODELING_CART) * 50; + if (sc && sc->data[SC_BIONIC_WOODENWARRIOR]) + skillratio *= 2; } break; case GN_CARTCANNON: @@ -4695,6 +4775,8 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * case GN_SPORE_EXPLOSION: skillratio += -100 + 400 + 200 * skill_lv; RE_LVL_DMOD(100); + if (sc && sc->data[SC_BIONIC_WOODEN_FAIRY]) + skillratio *= 2; break; case GN_WALLOFTHORN: skillratio += 10 * skill_lv; @@ -4932,6 +5014,284 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * if (sc && sc->data[SC_LIGHTOFSTAR]) skillratio += skillratio * sc->data[SC_LIGHTOFSTAR]->val2 / 100; break; + case DK_SERVANTWEAPON_ATK: + skillratio += 50 + 50 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case DK_SERVANT_W_PHANTOM: + skillratio += 100 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case DK_SERVANT_W_DEMOL: + skillratio += 600 + 120 * skill_lv; + RE_LVL_DMOD(100); + break; + case DK_HACKANDSLASHER: + skillratio += -100 + 500 + 250 * skill_lv; + if (sd && sd->status.weapon == W_2HSWORD) { + skillratio += 5 * sstatus->pow; + RE_LVL_DMOD(100); // Only takes place with 2h Sword + } + break; + case DK_HACKANDSLASHER_ATK: + skillratio += 600 + 120 * skill_lv; + if (sd && sd->status.weapon == W_2HSPEAR) { + skillratio += 5 * sstatus->pow; + RE_LVL_DMOD(100); // Only takes place with 2h Spear + } + break; + case DK_DRAGONIC_AURA: + skillratio += 950 * skill_lv + 10 * sstatus->pow; + if (tstatus->race == RC_DEMIHUMAN || tstatus->race == RC_ANGEL) + skillratio += 450 * skill_lv; + RE_LVL_DMOD(100); + break; + case DK_MADNESS_CRUSHER:// How does weight affect the damage? [Rytech] + skillratio += -100 + 450 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_CHARGINGPIERCE_COUNT] && sc->data[SC_CHARGINGPIERCE_COUNT]->val1 >= 10) + skillratio *= 2; + break; + case DK_STORMSLASH: + skillratio += -100 + 120 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_GIANTGROWTH]) + skillratio *= 2; + break; + case IQ_OLEUM_SANCTUM: + skillratio += -100 + 400 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case IQ_MASSIVE_F_BLASTER: + skillratio += -100 + 800 * skill_lv + 10 * sstatus->pow; + if (tstatus->race == RC_BRUTE || tstatus->race == RC_DEMON) + skillratio += 300 * skill_lv; + RE_LVL_DMOD(100); + break; + case IQ_EXPOSION_BLASTER: + skillratio += -100 + 450 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + if (tsc && tsc->data[SC_HOLY_OIL]) + skillratio += skillratio * 50 / 100; + break; + case IQ_FIRST_BRAND: + skillratio += -100 + 450 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case IQ_SECOND_FLAME: + skillratio += -100 + 550 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case IQ_SECOND_FAITH: + skillratio += -100 + 500 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case IQ_SECOND_JUDGEMENT: + skillratio += -100 + 500 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case IQ_THIRD_PUNISH: + skillratio += -100 + 550 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case IQ_THIRD_FLAME_BOMB: + skillratio += -100 + 650 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case IQ_THIRD_CONSECRATION: + skillratio += -100 + 650 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case IG_GRAND_JUDGEMENT: + skillratio += -100 + 750 * skill_lv + 10 * sstatus->pow; + if (tstatus->race == RC_PLANT || tstatus->race == RC_INSECT) + skillratio += 350 * skill_lv; + RE_LVL_DMOD(100); + if ((i = pc_checkskill_imperial_guard(sd, 3)) > 0) + skillratio += skillratio * i / 100; + break; + case IG_SHIELD_SHOOTING: + skillratio += -100 + 600 * skill_lv + 5 * sstatus->pow; + if (sd) { // Damage affected by the shield's weight and refine. Need official formula. [Rytech] + short index = sd->equip_index[EQI_HAND_L]; + + if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR) + skillratio += sd->inventory_data[index]->weight / 20 * sd->inventory.u.items_inventory[index].refine; + } + RE_LVL_DMOD(100); + if ((i = pc_checkskill_imperial_guard(sd, 3)) > 0) + skillratio += skillratio * i / 100; + break; + case IG_OVERSLASH: + skillratio += -100 + 60 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + if ((i = pc_checkskill_imperial_guard(sd, 3)) > 0) + skillratio += skillratio * i / 100; + break; + case CD_EFFLIGO: + skillratio += -100 + 800 * skill_lv + 5 * sstatus->pow; + if (tstatus->race == RC_UNDEAD || tstatus->race == RC_DEMON) + skillratio += 400 * skill_lv; + RE_LVL_DMOD(100); + break; + case CD_PETITIO: + skillratio += -100 + 270 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case SHC_DANCING_KNIFE: + skillratio += -100 + 200 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case SHC_SAVAGE_IMPACT: + skillratio += -100 + 350 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case SHC_ETERNAL_SLASH: + skillratio += -100 + 350 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case SHC_SHADOW_STAB: + skillratio += -100 + 750 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case SHC_IMPACT_CRATER: + skillratio += -100 + 65 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case SHC_FATAL_SHADOW_CROW: + skillratio += -100 + 650 * skill_lv + 10 * sstatus->pow; + if (tstatus->race == RC_DEMIHUMAN || tstatus->race == RC_DRAGON) + skillratio += 300 * skill_lv; + RE_LVL_DMOD(100); + break; + case MT_AXE_STOMP: + skillratio += -100 + 350 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case MT_RUSH_QUAKE: + skillratio += -100 + 750 * skill_lv + 10 * sstatus->pow; + if (tstatus->race == RC_FORMLESS || tstatus->race == RC_INSECT) + skillratio += 350 * skill_lv; + RE_LVL_DMOD(100); + break; + case MT_A_MACHINE:// Formula unknown. Using Dancing Knife's formula for now. [Rytech] + skillratio += -100 + 200 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case ABC_ABYSS_DAGGER: + skillratio += -100 + 550 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case ABC_UNLUCKY_RUSH: + skillratio += -100 + 500 * skill_lv + 5 * sstatus->crt; + RE_LVL_DMOD(100); + break; + case ABC_CHAIN_REACTION_SHOT: + case ABC_CHAIN_REACTION_SHOT_ATK:// Same damage formula? [Rytech] + skillratio += -100 + 600 * skill_lv + 5 * sstatus->con; + RE_LVL_DMOD(100); + break; + case ABC_DEFT_STAB: + skillratio += -100 + 360 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + break; + case ABC_FRENZY_SHOT: + skillratio += -100 + 350 * skill_lv + 5 * sstatus->con; + RE_LVL_DMOD(100); + break; + case WH_HAWKRUSH: + skillratio += -100 + 100 * skill_lv + 5 * sstatus->con; + RE_LVL_DMOD(100); + break; + case WH_HAWKBOOMERANG:// Affected by trait stats??? CON for sure but the other one unknown. Likely POW. [Rytech] + skillratio += -100 + 500 * skill_lv + 10 * sstatus->pow + 10 * sstatus->con; + if (tstatus->race == RC_BRUTE || tstatus->race == RC_FISH) + skillratio += 250 * skill_lv; + RE_LVL_DMOD(100); + break; + case WH_GALESTORM: + skillratio += -100 + 250 * skill_lv + 5 * sstatus->con; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_CALAMITYGALE] && (tstatus->race == RC_BRUTE || tstatus->race == RC_FISH)) + skillratio += skillratio * 50 / 100; + break; + case WH_CRESCIVE_BOLT: + skillratio += -100 + 300 * skill_lv + 5 * sstatus->con; + RE_LVL_DMOD(100); + if (sc) { // At level 10 the SP usage of 100 increased by 20 on each count. So maybe damage increase is 20%??? [Rytech] + if (sc->data[SC_CRESCIVEBOLT]) + skillratio += skillratio * (20 * sc->data[SC_CRESCIVEBOLT]->val1) / 100; + + if (sc->data[SC_CALAMITYGALE]) { + skillratio += skillratio * 20 / 100; + + if (tstatus->race == RC_BRUTE || tstatus->race == RC_FISH) + skillratio += skillratio * 50 / 100; + } + } + break; + case WH_DEEPBLINDTRAP: + case WH_SOLIDTRAP: + case WH_SWIFTTRAP: + case WH_FLAMETRAP: + skillratio += -100 + 250 * skill_lv + 5 * sstatus->con; + RE_LVL_DMOD(100); + skillratio += skillratio * (20 * (sd ? pc_checkskill(sd, WH_ADVANCED_TRAP) : 5)) / 100; + break; + case BO_ACIDIFIED_ZONE_WATER: + case BO_ACIDIFIED_ZONE_GROUND: + case BO_ACIDIFIED_ZONE_WIND: + case BO_ACIDIFIED_ZONE_FIRE: + case BO_ACIDIFIED_ZONE_WATER_ATK:// These deal the same damage? [Rytech] + case BO_ACIDIFIED_ZONE_GROUND_ATK: + case BO_ACIDIFIED_ZONE_WIND_ATK: + case BO_ACIDIFIED_ZONE_FIRE_ATK: + skillratio += -100 + 250 * skill_lv + 5 * sstatus->pow; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_RESEARCHREPORT]) { // Does this also affect skills like acid demo? [Rytech] + skillratio += skillratio * 50 / 100; + + if (tstatus->race == RC_FORMLESS || tstatus->race == RC_PLANT) + skillratio += skillratio * 50 / 100; + + // Skill description is sounding a bit too crazy. + // I need more info on this before allowing this part to work to avoid overpowered issues. [Rytech] + //skillratio += 5 * sstatus->pow; + //RE_LVL_DMOD(100); + } + break; + case TR_ROSEBLOSSOM: + case TR_ROSEBLOSSOM_ATK:// Same damage formula? [Rytech] + skillratio += -100 + 500 * skill_lv + (sd ? pc_checkskill(sd, TR_STAGE_MANNER) : 5) * sstatus->con; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_MYSTIC_SYMPHONY]) { + skillratio += skillratio * 40 / 100; + + if (tstatus->race == RC_FISH || tstatus->race == RC_DEMIHUMAN) + skillratio += skillratio * 50 / 100; + } + if (tsc && tsc->data[SC_SOUNDBLEND]) + skillratio += skillratio * 50 / 100; + break; + case TR_RHYTHMSHOOTING: + skillratio += -100 + 120 * skill_lv + (sd ? pc_checkskill(sd, TR_STAGE_MANNER) : 5) * sstatus->con; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_MYSTIC_SYMPHONY]) { + skillratio += skillratio * 40 / 100; + + if (tstatus->race == RC_FISH || tstatus->race == RC_DEMIHUMAN) + skillratio += skillratio * 50 / 100; + } + if (tsc && tsc->data[SC_SOUNDBLEND]) + skillratio += skillratio * 50 / 100; + break; + case ABR_BATTLE_BUSTER:// Need official formula. + case ABR_DUAL_CANNON_FIRE:// Need official formula. + skillratio += -100 + 8000; + break; + case ABR_INFINITY_BUSTER:// Need official formula. + skillratio += -100 + 50000; + break; } return skillratio; } @@ -5663,6 +6023,8 @@ static void battle_calc_weapon_final_atk_modifiers(struct Damage* wd, struct blo hp = 2*hp/100; //2% hp loss per hit status_zap(src, hp, 0); } + if (sc->data[SC_VIGOR]) + status_zap(src, sc->data[SC_VIGOR]->val2, 0); // Only affecting non-skills if (!skill_id && wd->dmg_lv > ATK_BLOCK) { if (sc->data[SC_ENCHANTBLADE]) { @@ -5802,6 +6164,48 @@ static struct Damage initialize_weapon_data(struct block_list *src, struct block case RK_WINDCUTTER: if (sd && (sd->status.weapon == W_1HSPEAR || sd->status.weapon == W_2HSPEAR)) wd.flag |= BF_LONG; + break; + case NC_BOOSTKNUCKLE: + case NC_VULCANARM: + case NC_ARMSCANNON: + if (sc && sc->data[SC_ABR_DUAL_CANNON]) + wd.div_ = 2; + break; + case NC_POWERSWING: + if (sc && sc->data[SC_ABR_BATTLE_WARIOR]) + wd.div_ = -2; + break; + case GN_CARTCANNON: + if (sc && sc->data[SC_BIONIC_WOODENWARRIOR]) + wd.div_ = 2; + break; + case DK_SERVANT_W_PHANTOM: + case DK_SERVANT_W_DEMOL: + if (sd && (sd->servantball + sd->servantball_old) < wd.div_) + wd.div_ = sd->servantball + sd->servantball_old; + break; + case IQ_THIRD_FLAME_BOMB: + wd.div_ = min(wd.div_ + wd.miscflag, 3); // Number of hits doesn't go above 3. + break; + case IG_OVERSLASH: + wd.div_ = min(wd.div_ + wd.miscflag, 5); // Number of hits doesn't appear to go above 5. + break; + case SHC_ETERNAL_SLASH: + if (sc && sc->data[SC_E_SLASH_COUNT]) + wd.div_ = sc->data[SC_E_SLASH_COUNT]->val1; + break; + case SHC_SHADOW_STAB: + if (wd.miscflag == 2) + wd.div_ = 2; + break; + case SHC_IMPACT_CRATER: + if (sc && sc->data[SC_ROLLINGCUTTER]) + wd.div_ = sc->data[SC_ROLLINGCUTTER]->val1; + break; + case MT_AXE_STOMP: + if (sd && sd->status.weapon == W_2HAXE) + wd.div_ = 2; + break; } } else { bool is_long = false; @@ -5881,6 +6285,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl struct Damage wd; struct status_change *sc = status_get_sc(src); struct status_change *tsc = status_get_sc(target); + struct status_data *sstatus = status_get_status_data(src); struct status_data *tstatus = status_get_status_data(target); int right_element, left_element; bool infdef = false; @@ -6001,14 +6406,44 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl battle_attack_sc_bonus(&wd, src, target, skill_id, skill_lv); if (sd) { //monsters, homuns and pets have their damage computed directly - wd.damage = wd.statusAtk + wd.weaponAtk + wd.equipAtk + wd.masteryAtk + bonus_damage; + wd.damage = (wd.statusAtk + wd.weaponAtk + wd.equipAtk) * (100 + sstatus->patk) / 100 + wd.masteryAtk + bonus_damage; if (is_attack_left_handed(src, skill_id)) - wd.damage2 = wd.statusAtk2 + wd.weaponAtk2 + wd.equipAtk2 + wd.masteryAtk2 + bonus_damage; + wd.damage2 = (wd.statusAtk2 + wd.weaponAtk2 + wd.equipAtk2) * (100 + sstatus->patk) / 100 + wd.masteryAtk2 + bonus_damage; if (wd.flag & BF_SHORT) ATK_ADDRATE(wd.damage, wd.damage2, sd->bonus.short_attack_atk_rate); if(wd.flag&BF_LONG && (skill_id != RA_WUGBITE && skill_id != RA_WUGSTRIKE)) //Long damage rate addition doesn't use weapon + equip attack ATK_ADDRATE(wd.damage, wd.damage2, sd->bonus.long_attack_atk_rate); } + + // Res reduces physical damage by a percentage and + // is calculated before DEF and other reductions. + // This should be the official formula. [Rytech] + if ((wd.damage + wd.damage2) && tstatus->res > 0) { + short res = tstatus->res; + short ignore_res = 0;// Value used as a percentage. + + // Attacker status's that pierce Res. + if (sc) { + if (sc->data[SC_A_TELUM]) + ignore_res += sc->data[SC_A_TELUM]->val2; + if (sc->data[SC_POTENT_VENOM]) + ignore_res += sc->data[SC_POTENT_VENOM]->val2; + } + + ignore_res = min(ignore_res, 100); + + if (ignore_res > 0) + res -= res * ignore_res / 100; + + // Max damage reduction from Res is officially 50%. + // That means 625 Res is needed to hit that cap. + if (res > battle_config.max_res_mres_reduction) + res = battle_config.max_res_mres_reduction; + + // Apply damage reduction. + wd.damage = wd.damage * (5000 + res) / (5000 + 10 * res); + wd.damage2 = wd.damage2 * (5000 + res) / (5000 + 10 * res); + } #else // final attack bonuses that aren't affected by cards battle_attack_sc_bonus(&wd, src, target, skill_id, skill_lv); @@ -6031,14 +6466,14 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl if (is_attack_critical(&wd, src, target, skill_id, skill_lv, false)) { if (sd) { //Check for player so we don't crash out, monsters don't have bonus crit rates [helvetica] if (skill_id > 0) - wd.damage = (int64)floor((float)((wd.damage * 140) / 100 * (100 + (sd->bonus.crit_atk_rate / 2))) / 100); + wd.damage = (int64)floor((float)((wd.damage * (140 + sstatus->crate)) / 100 * (100 + (sd->bonus.crit_atk_rate / 2))) / 100); else - wd.damage = (int64)floor((float)((wd.damage * 140) / 100 * (100 + sd->bonus.crit_atk_rate)) / 100); + wd.damage = (int64)floor((float)((wd.damage * (140 + sstatus->crate)) / 100 * (100 + sd->bonus.crit_atk_rate)) / 100); if (is_attack_left_handed(src, skill_id)) { if (skill_id > 0) - wd.damage2 = (int64)floor((float)((wd.damage2 * 140) / 100 * (100 + (sd->bonus.crit_atk_rate / 2))) / 100); + wd.damage2 = (int64)floor((float)((wd.damage2 * (140 + sstatus->crate)) / 100 * (100 + (sd->bonus.crit_atk_rate / 2))) / 100); else - wd.damage2 = (int64)floor((float)((wd.damage2 * 140) / 100 * (100 + sd->bonus.crit_atk_rate)) / 100); + wd.damage2 = (int64)floor((float)((wd.damage2 * (140 + sstatus->crate)) / 100 * (100 + sd->bonus.crit_atk_rate)) / 100); } } else wd.damage = (int64)floor((float)(wd.damage * 140) / 100); @@ -6230,6 +6665,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list sd = BL_CAST(BL_PC, src); tsd = BL_CAST(BL_PC, target); + s_elemental_data* ed = BL_CAST(BL_ELEM, src); sc = status_get_sc(src); tsc = status_get_sc(target); @@ -6272,6 +6708,16 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list s_ele = sc->data[SC_BLAST_OPTION]->val3; else if( sc->data[SC_CURSED_SOIL_OPTION] ) s_ele = sc->data[SC_CURSED_SOIL_OPTION]->val3; + else if( sc->data[SC_FLAMETECHNIC_OPTION] ) + s_ele = sc->data[SC_FLAMETECHNIC_OPTION]->val3; + else if( sc->data[SC_COLD_FORCE_OPTION] ) + s_ele = sc->data[SC_COLD_FORCE_OPTION]->val3; + else if( sc->data[SC_GRACE_BREEZE_OPTION] ) + s_ele = sc->data[SC_GRACE_BREEZE_OPTION]->val3; + else if( sc->data[SC_EARTH_CARE_OPTION] ) + s_ele = sc->data[SC_EARTH_CARE_OPTION]->val3; + else if( sc->data[SC_DEEP_POISONING_OPTION] ) + s_ele = sc->data[SC_DEEP_POISONING_OPTION]->val3; } break; case KO_KAIHOU: @@ -6286,6 +6732,25 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list if (sc && sc->data[SC_INSPIRATION]) s_ele = ELE_NEUTRAL; break; + case AG_DESTRUCTIVE_HURRICANE: + if (sc && sc->data[SC_CLIMAX] && sc->data[SC_CLIMAX]->val1 == 2) + ad.blewcount = 2; + break; + case AG_CRYSTAL_IMPACT: + if (sc && sc->data[SC_CLIMAX] && sc->data[SC_CLIMAX]->val1 == 2) + ad.div_ = 2; + break; + case ABC_ABYSS_SQUARE: + if (mflag == 2) + ad.div_ = 2; + break; + case TR_METALIC_FURY:// Deals up to 5 additional hits. But what affects the number of hits? [Rytech] + ad.div_ = min(ad.div_ + mflag, 5); // Number of hits doesn't go above 5. + // Fall through and check arrow element + case TR_SOUNDBLEND: + if (sd) + s_ele = sd->bonus.arrow_ele; + break; } //Set miscellaneous data that needs be filled @@ -6431,11 +6896,18 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list case MG_FIREBOLT: case MG_COLDBOLT: case MG_LIGHTNINGBOLT: - if (sc && sc->data[SC_SPELLFIST] && mflag&BF_SHORT) { - skillratio += (sc->data[SC_SPELLFIST]->val3 * 100) + (sc->data[SC_SPELLFIST]->val1 * 50 - 50) - 100; // val3 = used bolt level, val1 = used spellfist level. [Rytech] - ad.div_ = 1; // ad mods, to make it work similar to regular hits [Xazax] - ad.flag = BF_WEAPON|BF_SHORT; - ad.type = DMG_NORMAL; + if (sc) { + if ((skill_id == MG_FIREBOLT && sc->data[SC_FLAMETECHNIC_OPTION]) || + (skill_id == MG_COLDBOLT && sc->data[SC_COLD_FORCE_OPTION]) || + (skill_id == MG_LIGHTNINGBOLT && sc->data[SC_GRACE_BREEZE_OPTION])) + skillratio *= 2; + + if (sc->data[SC_SPELLFIST] && mflag & BF_SHORT) { + skillratio += (sc->data[SC_SPELLFIST]->val3 * 100) + (sc->data[SC_SPELLFIST]->val1 * 50 - 50) - 100; // val3 = used bolt level, val1 = used spellfist level. [Rytech] + ad.div_ = 1; // ad mods, to make it work similar to regular hits [Xazax] + ad.flag = BF_WEAPON | BF_SHORT; + ad.type = DMG_NORMAL; + } } break; case MG_THUNDERSTORM: @@ -6480,6 +6952,8 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list #ifdef RENEWAL case WZ_EARTHSPIKE: skillratio += 100; + if (sc && sc->data[SC_EARTH_CARE_OPTION]) + skillratio += skillratio * 80 / 100; break; #endif case HW_NAPALMVULCAN: @@ -6677,11 +7151,15 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list if (tsc && tsc->data[SC_SLEEP]) skillratio += 100; // !TODO: Confirm target sleeping bonus RE_LVL_DMOD(100); + if (tsc && tsc->data[SC_SOUNDBLEND]) + skillratio += skillratio * 50 / 100; break; case WM_REVERBERATION: // MATK [{(Skill Level x 300) + 400} x Casters Base Level / 100] % skillratio += -100 + 700 + 300 * skill_lv; RE_LVL_DMOD(100); + if (tsc && tsc->data[SC_SOUNDBLEND]) + skillratio += skillratio * 50 / 100; break; case SO_FIREWALK: skillratio += -100 + 60 * skill_lv; @@ -6735,8 +7213,13 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list case SO_CLOUD_KILL: skillratio += -100 + 40 * skill_lv; RE_LVL_DMOD(100); - if (sc && sc->data[SC_CURSED_SOIL_OPTION]) - skillratio += (sd ? sd->status.job_level : 0); + if (sc) { + if (sc->data[SC_CURSED_SOIL_OPTION]) + skillratio += (sd ? sd->status.job_level : 0); + + if (sc->data[SC_DEEP_POISONING_OPTION]) + skillratio += skillratio * 50 / 100; + } break; case NPC_CLOUD_KILL: skillratio += -100 + 50 * skill_lv; @@ -6835,6 +7318,247 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list case NPC_STORMGUST2: skillratio += 200 * skill_lv; break; + case AG_DEADLY_PROJECTION: + skillratio += -100 + 600 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case AG_DESTRUCTIVE_HURRICANE: + skillratio += -100 + 1600 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_CLIMAX]) + { + if (sc->data[SC_CLIMAX]->val1 == 3) + skillratio *= 2; + else if (sc->data[SC_CLIMAX]->val1 == 5) + skillratio += skillratio * 70 / 100; + } + break; + case AG_RAIN_OF_CRYSTAL: + skillratio += -100 + 150 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case AG_MYSTERY_ILLUSION: + skillratio += -100 + 250 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case AG_VIOLENT_QUAKE_ATK: + skillratio += -100 + 120 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_CLIMAX]) { + if (sc->data[SC_CLIMAX]->val1 == 1) + skillratio /= 2; + else if (sc->data[SC_CLIMAX]->val1 == 3) + skillratio *= 2; + } + break; + case AG_SOUL_VC_STRIKE: + skillratio += -100 + 180 * skill_lv + 3 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case AG_STRANTUM_TREMOR: + skillratio += -100 + 250 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case AG_ALL_BLOOM_ATK: + skillratio += -100 + 100 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_CLIMAX]) { + if (sc->data[SC_CLIMAX]->val1 == 2) + skillratio /= 2; + else if (sc->data[SC_CLIMAX]->val1 == 3) + skillratio *= 2; + } + break; + case AG_ALL_BLOOM_ATK2:// Is this affected by BaseLV and SPL too??? [Rytech] + skillratio += -100 + 7000 + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case AG_CRYSTAL_IMPACT: + skillratio += -100 + 800 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_CLIMAX]) { + if (sc->data[SC_CLIMAX]->val1 == 3) + skillratio += skillratio * 50 / 100; + else if (sc->data[SC_CLIMAX]->val1 == 4) + skillratio /= 2; + } + break; + case AG_CRYSTAL_IMPACT_ATK:// Said to deal the same damage as the main attack. + skillratio += -100 + 800 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_CLIMAX] && sc->data[SC_CLIMAX]->val1 == 4) + skillratio += skillratio * 150 / 100; + break; + case AG_TORNADO_STORM: + skillratio += -100 + 90 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case AG_FLORAL_FLARE_ROAD: + skillratio += -100 + 200 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case AG_ASTRAL_STRIKE: + skillratio += -100 + 500 * skill_lv + 10 * sstatus->spl; + if (tstatus->race == RC_UNDEAD || tstatus->race == RC_DRAGON) + skillratio += 600 * skill_lv; + RE_LVL_DMOD(100); + break; + case AG_ASTRAL_STRIKE_ATK: + skillratio += -100 + 200 * skill_lv + 10 * sstatus->spl; + // Not confirmed, but if the main hit deal additional damage + // on certain races then the repeated damage should too right? + // Guessing a formula here for now. [Rytech] + if (tstatus->race == RC_UNDEAD || tstatus->race == RC_DRAGON) + skillratio += 200 * skill_lv; + RE_LVL_DMOD(100); + break; + case AG_ROCK_DOWN: + skillratio += -100 + 750 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case AG_STORM_CANNON: + skillratio += -100 + 600 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case AG_CRIMSON_ARROW: + case AG_CRIMSON_ARROW_ATK: + skillratio += -100 + 300 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case AG_FROZEN_SLASH: + skillratio += -100 + 750 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case IG_JUDGEMENT_CROSS: + skillratio += -100 + 750 * skill_lv + 10 * sstatus->spl; + if (tstatus->race == RC_PLANT || tstatus->race == RC_INSECT) + skillratio += 350 * skill_lv; + RE_LVL_DMOD(100); + if ((i = pc_checkskill_imperial_guard(sd, 3)) > 0) + skillratio += skillratio * i / 100; + break; + case IG_CROSS_RAIN:// Need official damage increase from Spear and Sword Mastery. [Rytech] + skillratio += -100 + 30 * skill_lv + 5 * sstatus->spl + 5 * pc_checkskill(sd, IG_SPEAR_SWORD_M); + RE_LVL_DMOD(100); + if ((i = pc_checkskill_imperial_guard(sd, 3)) > 0) + skillratio += skillratio * i / 100; + if (sc && sc->data[SC_HOLY_S]) + skillratio += 20 * skill_lv; + break; + case CD_ARBITRIUM: + case CD_ARBITRIUM_ATK: + skillratio += -100 + 200 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case CD_PNEUMATICUS_PROCELLA: + skillratio += -100 + 200 * skill_lv + 10 * sstatus->spl; + if (tstatus->race == RC_UNDEAD || tstatus->race == RC_DEMON) + skillratio += 100 * skill_lv; + RE_LVL_DMOD(100); + break; + case CD_FRAMEN: + skillratio += -100 + 500 * skill_lv + 5 * sstatus->spl; + if (tstatus->race == RC_UNDEAD || tstatus->race == RC_DEMON) + skillratio += 150 * skill_lv; + RE_LVL_DMOD(100); + break; + case AG_DESTRUCTIVE_HURRICANE_CLIMAX:// Is this affected by BaseLV and SPL too??? [Rytech] + skillratio += -100 + 500 + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case ABC_ABYSS_STRIKE: + skillratio += -100 + 600 * skill_lv + 10 * sstatus->spl; + if (tstatus->race == RC_DEMON || tstatus->race == RC_ANGEL) + skillratio += 550 * skill_lv; + RE_LVL_DMOD(100); + break; + case ABC_ABYSS_SQUARE: + skillratio += -100 + 140 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case TR_METALIC_FURY: + skillratio += -100 + 600 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case TR_SOUNDBLEND: + skillratio += -100 + 120 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_MYSTIC_SYMPHONY]) { + skillratio += skillratio * 40 / 100; + + if (tstatus->race == RC_FISH || tstatus->race == RC_DEMIHUMAN) + skillratio += skillratio * 50 / 100; + } + break; + case EM_DIAMOND_STORM: + skillratio += -100 + 700 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_SUMMON_ELEMENTAL_DILUVIO]) + skillratio += skillratio * 30 / 100; + break; + case EM_LIGHTNING_LAND: + skillratio += -100 + 150 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_SUMMON_ELEMENTAL_PROCELLA]) + skillratio += skillratio * 30 / 100; + break; + case EM_VENOM_SWAMP: + skillratio += -100 + 150 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_SUMMON_ELEMENTAL_SERPENS]) + skillratio += skillratio * 30 / 100; + break; + case EM_CONFLAGRATION: + skillratio += -100 + 150 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_SUMMON_ELEMENTAL_ARDOR]) + skillratio += skillratio * 30 / 100; + break; + case EM_TERRA_DRIVE: + skillratio += -100 + 700 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_SUMMON_ELEMENTAL_TERREMOTUS]) + skillratio += skillratio * 30 / 100; + break; + case ABC_FROM_THE_ABYSS_ATK: + skillratio += 50 + 70 * skill_lv + 5 * sstatus->spl; + RE_LVL_DMOD(100); + break; + case EM_ELEMENTAL_BUSTER_FIRE: + case EM_ELEMENTAL_BUSTER_WATER: + case EM_ELEMENTAL_BUSTER_WIND: + case EM_ELEMENTAL_BUSTER_GROUND: + case EM_ELEMENTAL_BUSTER_POISON: + skillratio += -100 + 480 * skill_lv + 10 * sstatus->spl; + if (tstatus->race == RC_FORMLESS || tstatus->race == RC_DRAGON) + skillratio += 620 * skill_lv; + RE_LVL_DMOD(100); + break; + case EM_EL_FLAMEROCK: + skillratio += -100 + 2400; + if (ed) + skillratio += skillratio * status_get_lv(&ed->master->bl) / 100; + break; + case EM_EL_AGE_OF_ICE: + skillratio += -100 + 3700; + if (ed) + skillratio += skillratio * status_get_lv(&ed->master->bl) / 100; + break; + case EM_EL_STORM_WIND: + skillratio += -100 + 2600; + if (ed) + skillratio += skillratio * status_get_lv(&ed->master->bl) / 100; + break; + case EM_EL_AVALANCHE: + skillratio += -100 + 450; + if (ed) + skillratio += skillratio * status_get_lv(&ed->master->bl) / 100; + break; + case EM_EL_DEADLY_POISON: + skillratio += -100 + 700; + if (ed) + skillratio += skillratio * status_get_lv(&ed->master->bl) / 100; + break; } if (sc) {// Insignia's increases the damage of offensive magic by a fixed percentage depending on the element. @@ -6874,6 +7598,36 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list if (tsd && (i = pc_sub_skillatk_bonus(tsd, skill_id))) ad.damage -= (int64)ad.damage*i/100; +#ifdef RENEWAL + if (sd && sstatus->smatk > 0) + ad.damage += ad.damage * sstatus->smatk / 100; + + // MRes reduces magical damage by a percentage and + // is calculated before MDEF and other reductions. + // This should be the official formula. [Rytech] + if (ad.damage && tstatus->mres > 0) { + short mres = tstatus->mres; + short ignore_mres = 0;// Value used as percentage. + + // Attacker status's that pierce MRes. + if (sc && sc->data[SC_A_VITA]) + ignore_mres += sc->data[SC_A_VITA]->val2; + + ignore_mres = min(ignore_mres, 100); + + if (ignore_mres > 0) + mres -= mres * ignore_mres / 100; + + // Max damage reduction from MRes is officially 50%. + // That means 625 MRes is needed to hit that cap. + if (mres > battle_config.max_res_mres_reduction) + mres = battle_config.max_res_mres_reduction; + + // Apply damage reduction. + ad.damage = ad.damage * (5000 + mres) / (5000 + 10 * mres); + } +#endif + if(!flag.imdef){ defType mdef = tstatus->mdef; int mdef2= tstatus->mdef2; @@ -7707,6 +8461,51 @@ int battle_damage_area(struct block_list *bl, va_list ap) { return 0; } +/** + * Triggers aftercast delay for autocasted skills. + * @param src: Source data + * @param skill_id: Skill used + * @param skill_lv: Skill level used + * @param tick: Server tick + */ +void battle_autocast_aftercast(struct block_list* src, uint16 skill_id, uint16 skill_lv, t_tick tick) +{ + unit_data *ud = unit_bl2ud(src); + + if (ud) { + int autocast_tick = skill_delayfix(src, skill_id, skill_lv); + + if (DIFF_TICK(ud->canact_tick, tick + autocast_tick) < 0) { + ud->canact_tick = i64max(tick + autocast_tick, ud->canact_tick); + + if (battle_config.display_status_timers && src->type == BL_PC) + clif_status_change(src, EFST_POSTDELAY, 1, autocast_tick, 0, 0, 0); + } + } +} + +/** + * Triggers autocasted skills from super elemental supportive buffs. + * @param sd: Player data + * @param target: Target data + * @param skill_id: Skill used + * @param tick: Server tick + * @param flag: Special skill flags + */ +void battle_autocast_elembuff_skill(struct map_session_data* sd, struct block_list* target, uint16 skill_id, t_tick tick, int flag) +{ + uint16 skill_lv = pc_checkskill(sd, skill_id); + + skill_lv = max(1, skill_lv); + + sd->state.autocast = 1; + if (status_charge(&sd->bl, 0, skill_get_sp(skill_id, skill_lv))) { + skill_castend_damage_id(&sd->bl, target, skill_id, skill_lv, tick, flag); + battle_autocast_aftercast(&sd->bl, skill_id, skill_lv, tick); + } + sd->state.autocast = 0; +} + /*========================================== * Do a basic physical attack (call through unit_attack_timer) *------------------------------------------*/ @@ -7947,14 +8746,14 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t damage = wd.damage + wd.damage2; if( damage > 0 && src != target ) { - if( sc && sc->data[SC_DUPLELIGHT] && (wd.flag&BF_SHORT) && rnd()%100 <= 10+2*sc->data[SC_DUPLELIGHT]->val1 ) - { // Activates it only from melee damage - uint16 skill_id; - if( rnd()%2 == 1 ) - skill_id = AB_DUPLELIGHT_MELEE; - else - skill_id = AB_DUPLELIGHT_MAGIC; - skill_attack(skill_get_type(skill_id), src, src, target, skill_id, sc->data[SC_DUPLELIGHT]->val1, tick, SD_LEVEL); + if (sc && sc->data[SC_DUPLELIGHT] && (wd.flag & BF_SHORT)) { // Activates only from regular melee damage. Success chance is seperate for both duple light attacks. + uint16 duple_rate = 10 + 2 * sc->data[SC_DUPLELIGHT]->val1; + + if (rand() % 100 < duple_rate) + skill_castend_damage_id(src, target, AB_DUPLELIGHT_MELEE, sc->data[SC_DUPLELIGHT]->val1, tick, flag | SD_LEVEL); + + if (rand() % 100 < duple_rate) + skill_castend_damage_id(src, target, AB_DUPLELIGHT_MAGIC, sc->data[SC_DUPLELIGHT]->val1, tick, flag | SD_LEVEL); } } @@ -7996,16 +8795,23 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t { // Only trigger if the devoted player was hit if( damage > 0 ){ + int64 devotion_damage = damage; struct map_session_data* dsd = BL_CAST( BL_PC, d_bl ); + // Needed to check the devotion master for Rebound Shield status. + struct status_change *d_sc = status_get_sc(d_bl); + // The devoting player needs to stand up if( dsd && pc_issit( dsd ) ){ pc_setstand( dsd, true ); skill_sit( dsd, 0 ); } - clif_damage(d_bl, d_bl, gettick(), wd.amotion, wd.dmotion, damage, 1, DMG_NORMAL, 0, false); - status_fix_damage(NULL, d_bl, damage, 0, CR_DEVOTION); + if (d_sc && d_sc->data[SC_REBOUND_S]) + devotion_damage -= devotion_damage * d_sc->data[SC_REBOUND_S]->val2 / 100; + + clif_damage(d_bl, d_bl, gettick(), wd.amotion, wd.dmotion, devotion_damage, 1, DMG_NORMAL, 0, false); + status_fix_damage(NULL, d_bl, devotion_damage, 0, CR_DEVOTION); } } else @@ -8131,6 +8937,69 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t if (sd) sd->state.autocast = 0; } + + if( sc ){ + // It has a success chance of triggering even tho the description says nothing about it. + // TODO: Need to find out what the official success chance is. [Rytech] + if( sc->data[SC_SERVANTWEAPON] && sd->servantball > 0 && rnd() % 100 < 20 ){ + uint16 skill_id = DK_SERVANTWEAPON_ATK; + uint16 skill_lv = sc->data[SC_SERVANTWEAPON]->val1; + + sd->state.autocast = 1; + pc_delservantball( *sd ); + skill_castend_damage_id( src, target, skill_id, skill_lv, tick, flag ); + battle_autocast_aftercast( src, skill_id, skill_lv, tick ); + sd->state.autocast = 0; + } + + // TODO: Whats the official success chance? Is SP consumed for every autocast? [Rytech] + if( sc->data[SC_DUPLELIGHT] && pc_checkskill(sd, CD_PETITIO) > 0 && rnd() % 100 < 20 ){ + uint16 skill_id = CD_PETITIO; + uint16 skill_lv = pc_checkskill( sd, CD_PETITIO ); + + sd->state.autocast = 1; + skill_castend_damage_id( src, target, skill_id, skill_lv, tick, flag ); + battle_autocast_aftercast( src, skill_id, skill_lv, tick ); + sd->state.autocast = 0; + } + + // It has a success chance of triggering even tho the description says nothing about it. + // TODO: Need to find out what the official success chance is. [Rytech] + if( sc->data[SC_ABYSSFORCEWEAPON] && sd->abyssball > 0 && rnd() % 100 < 20 ){ + uint16 skill_id = ABC_FROM_THE_ABYSS_ATK; + uint16 skill_lv = sc->data[SC_ABYSSFORCEWEAPON]->val1; + + sd->state.autocast = 1; + pc_delabyssball( *sd ); + skill_castend_damage_id( src, target, skill_id, skill_lv, tick, flag ); + battle_autocast_aftercast( src, skill_id, skill_lv, tick ); + sd->state.autocast = 0; + } + + // It has a success chance of triggering even tho the description says nothing about it. + // TODO: Need to find out what the official success chance is. [Rytech] + if( sc->data[SC_ABYSSFORCEWEAPON] && rnd() % 100 < 20 ){ + uint16 skill_id = ABC_ABYSS_SQUARE; + uint16 skill_lv = pc_checkskill(sd, ABC_ABYSS_SQUARE); + + sd->state.autocast = 1; + skill_castend_pos2( src, target->x, target->y, skill_id, skill_lv, tick, flag ); + battle_autocast_aftercast( src, skill_id, skill_lv, tick ); + sd->state.autocast = 0; + } + + // Autocasted skills from super elemental supportive buffs. + if (sc->data[SC_FLAMETECHNIC_OPTION] && rnd() % 100 < 7) + battle_autocast_elembuff_skill(sd, target, MG_FIREBOLT, tick, flag); + if (sc->data[SC_COLD_FORCE_OPTION] && rnd() % 100 < 7) + battle_autocast_elembuff_skill(sd, target, MG_COLDBOLT, tick, flag); + if (sc->data[SC_GRACE_BREEZE_OPTION] && rnd() % 100 < 7) + battle_autocast_elembuff_skill(sd, target, MG_LIGHTNINGBOLT, tick, flag); + if (sc->data[SC_EARTH_CARE_OPTION] && rnd() % 100 < 7) + battle_autocast_elembuff_skill(sd, target, WZ_EARTHSPIKE, tick, flag); + if (sc->data[SC_DEEP_POISONING_OPTION] && rnd() % 100 < 7) + battle_autocast_elembuff_skill(sd, target, SO_POISON_BUSTER, tick, flag); + } if (wd.flag & BF_WEAPON && src != target && damage > 0) { if (battle_config.left_cardfix_to_right) battle_drain(sd, target, wd.damage, wd.damage, tstatus->race, tstatus->class_); @@ -8158,6 +9027,10 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t status_change_end(target, SC_POISONREACT, INVALID_TIMER); } } + + if (sd && tsc && wd.flag&BF_LONG && tsc->data[SC_WINDSIGN] && rand()%100 < tsc->data[SC_WINDSIGN]->val2) + status_heal(src, 0, 0, 1, 0); + map_freeblock_unlock(); return wd.dmg_lv; } @@ -8989,7 +9862,7 @@ static const struct _battle_data { { "auction_maximumprice", &battle_config.auction_maximumprice, 500000000, 0, MAX_ZENY, }, { "homunculus_auto_vapor", &battle_config.homunculus_auto_vapor, 80, 0, 100, }, { "display_status_timers", &battle_config.display_status_timers, 1, 0, 1, }, - { "skill_add_heal_rate", &battle_config.skill_add_heal_rate, 7, 0, INT_MAX, }, + { "skill_add_heal_rate", &battle_config.skill_add_heal_rate, 487, 0, INT_MAX, }, { "eq_single_target_reflectable", &battle_config.eq_single_target_reflectable, 1, 0, 1, }, { "invincible.nodamage", &battle_config.invincible_nodamage, 0, 0, 1, }, { "mob_slave_keep_target", &battle_config.mob_slave_keep_target, 0, 0, 1, }, @@ -9023,7 +9896,6 @@ static const struct _battle_data { { "max_extended_parameter", &battle_config.max_extended_parameter, 125, 10, SHRT_MAX, }, { "max_summoner_parameter", &battle_config.max_summoner_parameter, 120, 10, SHRT_MAX, }, { "max_fourth_parameter", &battle_config.max_fourth_parameter, 135, 10, SHRT_MAX, }, - { "max_fourth_trait", &battle_config.max_fourth_trait, 100, 0, SHRT_MAX, }, { "skill_amotion_leniency", &battle_config.skill_amotion_leniency, 0, 0, 300 }, { "mvp_tomb_enabled", &battle_config.mvp_tomb_enabled, 1, 0, 1 }, { "mvp_tomb_delay", &battle_config.mvp_tomb_delay, 9000, 0, INT_MAX, }, @@ -9189,6 +10061,19 @@ static const struct _battle_data { { "feature.refineui", &battle_config.feature_refineui, 1, 0, 1, }, { "rndopt_drop_pillar", &battle_config.rndopt_drop_pillar, 1, 0, 1, }, + // 4th Job Stuff + { "use_traitpoint_table", &battle_config.use_traitpoint_table, 1, 0, 1, }, + { "trait_points_job_change", &battle_config.trait_points_job_change, 7, 1, 1000, }, + { "max_trait_parameter", &battle_config.max_trait_parameter, 100, 10, SHRT_MAX, }, + { "max_res_mres_reduction", &battle_config.max_res_mres_reduction, 625, 1, SHRT_MAX, }, + { "max_ap", &battle_config.max_ap, 200, 100, 1000000000, }, + { "ap_rate", &battle_config.ap_rate, 100, 1, INT_MAX, }, + { "restart_ap_rate", &battle_config.restart_ap_rate, 0, 0, 100, }, + { "loose_ap_on_death", &battle_config.loose_ap_on_death, 1, 0, 1, }, + { "loose_ap_on_map", &battle_config.loose_ap_on_map, 1, 0, 1, }, + { "keep_ap_on_logout", &battle_config.keep_ap_on_logout, 1, 0, 1, }, + { "attack_machine_level_difference", &battle_config.attack_machine_level_difference, 15, 0, INT_MAX, }, + #include "../custom/battle_config_init.inc" }; diff --git a/src/map/battle.hpp b/src/map/battle.hpp index fd4973460f..b56f99349f 100644 --- a/src/map/battle.hpp +++ b/src/map/battle.hpp @@ -525,7 +525,6 @@ struct Battle_Config int max_extended_parameter; int max_summoner_parameter; int max_fourth_parameter; - int max_fourth_trait; int max_third_aspd; int max_summoner_aspd; int vcast_stat_scale; @@ -693,6 +692,19 @@ struct Battle_Config int feature_refineui; int rndopt_drop_pillar; + // 4th Jobs Stuff + int trait_points_job_change; + int use_traitpoint_table; + int max_trait_parameter; + int max_res_mres_reduction; + int max_ap; + int ap_rate; + int restart_ap_rate; + int loose_ap_on_death; + int loose_ap_on_map; + int keep_ap_on_logout; + int attack_machine_level_difference; + #include "../custom/battle_config_struct.inc" }; diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp index e3f358498c..35a9cfd21e 100644 --- a/src/map/chrif.cpp +++ b/src/map/chrif.cpp @@ -1000,34 +1000,45 @@ int chrif_changedsex(int fd) { return 0; //Do nothing? Likely safe. sd->status.sex = !sd->status.sex; - // reset skill of some job - if ((sd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER) { - int i; - // remove specifical skills of Bard classes - for(i = BA_MUSICALLESSON; i <= BA_APPLEIDUN; i++) { - uint16 sk_idx = skill_get_index(i); - if (sd->status.skill[sk_idx].id > 0 && sd->status.skill[sk_idx].flag == SKILL_FLAG_PERMANENT) { - sd->status.skill_point += sd->status.skill[sk_idx].lv; - sd->status.skill[sk_idx].id = 0; - sd->status.skill[sk_idx].lv = 0; - } - } - // remove specifical skills of Dancer classes - for(i = DC_DANCINGLESSON; i <= DC_SERVICEFORYOU; i++) { - uint16 sk_idx = skill_get_index(i); - if (sd->status.skill[sk_idx].id > 0 && sd->status.skill[sk_idx].flag == SKILL_FLAG_PERMANENT) { - sd->status.skill_point += sd->status.skill[sk_idx].lv; - sd->status.skill[sk_idx].id = 0; - sd->status.skill[sk_idx].lv = 0; + // Reset skills of gender split jobs. + if ((sd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER || (sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO) { + const static struct { + e_skill start; + e_skill end; + } ranges[] = { + // Bard class exclusive skills + { BA_MUSICALLESSON, BA_APPLEIDUN }, + // Dancer class exclusive skills + { DC_DANCINGLESSON, DC_SERVICEFORYOU }, + // Minstrel class exclusive skills + { MI_RUSH_WINDMILL, MI_HARMONIZE }, + // Wanderer class exclusive skills + { WA_SWING_DANCE, WA_MOONLIT_SERENADE }, + // Kagerou class exclusive skills + { KG_KAGEHUMI, KG_KAGEMUSYA }, + // Oboro class exclusive skills + { OB_ZANGETSU, OB_AKAITSUKI }, + }; + + for( const auto& range : ranges ){ + for( uint16 skill_id = range.start; skill_id <= range.end; skill_id++ ){ + uint16 sk_idx = skill_get_index( skill_id ); + + if( sd->status.skill[sk_idx].id > 0 && sd->status.skill[sk_idx].flag == SKILL_FLAG_PERMANENT ){ + sd->status.skill_point += sd->status.skill[sk_idx].lv; + sd->status.skill[sk_idx].id = 0; + sd->status.skill[sk_idx].lv = 0; + } } } + clif_updatestatus(sd, SP_SKILLPOINT); - // change job if necessary - if (sd->status.sex) //Changed from Dancer + // Change to other gender version of the job if needed. + if (sd->status.sex)// Changed from female version of job. sd->status.class_ -= 1; - else //Changed from Bard + else// Changed from male version of job. sd->status.class_ += 1; - //sd->class_ needs not be updated as both Dancer/Bard are the same. + //sd->class_ Does not need to be updated as both versions of the job are the same. } // save character sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 1cb516e1ae..fbf1ca38fc 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -358,7 +358,19 @@ static inline unsigned char clif_bl_type(struct block_list *bl, bool walking) { case BL_ITEM: return 0x2; //ITEM_TYPE case BL_SKILL: return 0x3; //SKILL_TYPE case BL_CHAT: return 0x4; //UNKNOWN_TYPE - case BL_MOB: return pcdb_checkid(status_get_viewdata(bl)->class_)?0x0:0x5; //NPC_MOB_TYPE + case BL_MOB: + if( pcdb_checkid( status_get_viewdata( bl )->class_ ) ){ + return 0x0; //PC_TYPE + }else{ + switch( ( (mob_data*)bl )->special_state.ai ){ + case AI_ABR: + return 0xd; //NPC_ABR_TYPE + case AI_BIONIC: + return 0xe; //NPC_BIONIC_TYPE + default: + return 0x5; //NPC_MOB_TYPE + } + } case BL_NPC: // From 2017-07-26 on NPC type units can also use player sprites. // There is one exception and this is if they are walking. @@ -1511,6 +1523,34 @@ void clif_class_change_target(struct block_list *bl,int class_,int type, enum se } } +void clif_servantball( struct map_session_data& sd, struct block_list* target, enum send_target send_target ){ + struct PACKET_ZC_SPIRITS p = {}; + + p.packetType = HEADER_ZC_SPIRITS; + p.GID = sd.bl.id; + p.amount = sd.servantball; + + if( target == nullptr ){ + target = &sd.bl; + } + + clif_send( &p, sizeof( p ), target, send_target ); +} + +void clif_abyssball( struct map_session_data& sd, struct block_list* target, enum send_target send_target ){ + struct PACKET_ZC_SPIRITS p = {}; + + p.packetType = HEADER_ZC_SPIRITS; + p.GID = sd.bl.id; + p.amount = sd.abyssball; + + if( target == nullptr ){ + target = &sd.bl; + } + + clif_send( &p, sizeof( p ), target, send_target ); +} + /// Notifies the client of an object's Millenium Shields. static void clif_millenniumshield_single(int fd, map_session_data *sd) { @@ -1649,6 +1689,10 @@ int clif_spawn( struct block_list *bl, bool walking ){ clif_millenniumshield(&sd->bl, sd->sc.data[SC_MILLENNIUMSHIELD]->val2); if (sd->soulball > 0) clif_soulball(sd); + if (sd->servantball > 0) + clif_servantball( *sd ); + if (sd->abyssball > 0) + clif_abyssball( *sd ); if(sd->state.size==SZ_BIG) // tiny/big players [Valaris] clif_specialeffect(bl,EF_GIANTBODY2,AREA); else if(sd->state.size==SZ_MEDIUM) @@ -3522,6 +3566,115 @@ void clif_updatestatus(struct map_session_data *sd,int type) len=14; break; +#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724 + case SP_AP: + WFIFOL(fd, 4) = sd->battle_status.ap; + break; + case SP_TRAITPOINT: + WFIFOL(fd, 4) = sd->status.trait_point; + break; + case SP_MAXAP: + WFIFOL(fd, 4) = sd->battle_status.max_ap; + break; + + case SP_POW: + WFIFOW(fd, 0) = 0x141; + WFIFOL(fd, 2) = type; + WFIFOL(fd, 6) = sd->status.pow; + WFIFOL(fd, 10) = sd->battle_status.pow - sd->status.pow; + len = 14; + break; + case SP_STA: + WFIFOW(fd, 0) = 0x141; + WFIFOL(fd, 2) = type; + WFIFOL(fd, 6) = sd->status.sta; + WFIFOL(fd, 10) = sd->battle_status.sta - sd->status.sta; + len = 14; + break; + case SP_WIS: + WFIFOW(fd, 0) = 0x141; + WFIFOL(fd, 2) = type; + WFIFOL(fd, 6) = sd->status.wis; + WFIFOL(fd, 10) = sd->battle_status.wis - sd->status.wis; + len = 14; + break; + case SP_SPL: + WFIFOW(fd, 0) = 0x141; + WFIFOL(fd, 2) = type; + WFIFOL(fd, 6) = sd->status.spl; + WFIFOL(fd, 10) = sd->battle_status.spl - sd->status.spl; + len = 14; + break; + case SP_CON: + WFIFOW(fd, 0) = 0x141; + WFIFOL(fd, 2) = type; + WFIFOL(fd, 6) = sd->status.con; + WFIFOL(fd, 10) = sd->battle_status.con - sd->status.con; + len = 14; + break; + case SP_CRT: + WFIFOW(fd, 0) = 0x141; + WFIFOL(fd, 2) = type; + WFIFOL(fd, 6) = sd->status.crt; + WFIFOL(fd, 10) = sd->battle_status.crt - sd->status.crt; + len = 14; + break; + + case SP_UPOW: + case SP_USTA: + case SP_UWIS: + case SP_USPL: + case SP_UCON: + case SP_UCRT: + WFIFOW(fd, 0) = 0xbe; + WFIFOB(fd, 4) = pc_need_trait_point(sd,type-SP_UPOW+SP_POW, 1); + len = 5; + break; + + case SP_PATK: + WFIFOL(fd, 4) = sd->battle_status.patk; + break; + case SP_SMATK: + WFIFOL(fd, 4) = sd->battle_status.smatk; + break; + case SP_RES: + WFIFOL(fd, 4) = sd->battle_status.res; + break; + case SP_MRES: + WFIFOL(fd, 4) = sd->battle_status.mres; + break; + case SP_HPLUS: + WFIFOL(fd, 4) = sd->battle_status.hplus; + break; + case SP_CRATE: + WFIFOL(fd, 4) = sd->battle_status.crate; + break; +#else + case SP_AP: + case SP_TRAITPOINT: + case SP_MAXAP: + case SP_POW: + case SP_STA: + case SP_WIS: + case SP_SPL: + case SP_CON: + case SP_CRT: + case SP_UPOW: + case SP_USTA: + case SP_UWIS: + case SP_USPL: + case SP_UCON: + case SP_UCRT: + case SP_PATK: + case SP_SMATK: + case SP_RES: + case SP_MRES: + case SP_HPLUS: + case SP_CRATE: + // 4th job status are not supported by older clients + return; +#endif + default: ShowError("clif_updatestatus : unrecognized type %d\n",type); return; @@ -3824,6 +3977,30 @@ void clif_initialstatus(struct map_session_data *sd) { clif_updatestatus(sd, SP_ATTACKRANGE); clif_updatestatus(sd, SP_ASPD); + +#ifdef RENEWAL + clif_updatestatus(sd, SP_POW); + clif_updatestatus(sd, SP_STA); + clif_updatestatus(sd, SP_WIS); + clif_updatestatus(sd, SP_SPL); + clif_updatestatus(sd, SP_CON); + clif_updatestatus(sd, SP_CRT); + clif_updatestatus(sd, SP_PATK); + clif_updatestatus(sd, SP_SMATK); + clif_updatestatus(sd, SP_RES); + clif_updatestatus(sd, SP_MRES); + clif_updatestatus(sd, SP_HPLUS); + clif_updatestatus(sd, SP_CRATE); + clif_updatestatus(sd, SP_TRAITPOINT); + clif_updatestatus(sd, SP_AP); + clif_updatestatus(sd, SP_MAXAP); + clif_updatestatus(sd, SP_UPOW); + clif_updatestatus(sd, SP_USTA); + clif_updatestatus(sd, SP_UWIS); + clif_updatestatus(sd, SP_USPL); + clif_updatestatus(sd, SP_UCON); + clif_updatestatus(sd, SP_UCRT); +#endif } @@ -3916,7 +4093,7 @@ void clif_arrow_create_list( struct map_session_data *sd ){ /// Notifies the client, about the result of an status change request (ZC_STATUS_CHANGE_ACK). /// 00bc .W .B .B /// status id: -/// SP_STR ~ SP_LUK +/// SP_STR ~ SP_LUK and SP_POW ~ SP_CRT /// result: /// 0 = failure /// 1 = success @@ -4732,6 +4909,10 @@ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_d clif_spiritcharm_single(sd->fd, dstsd); if (dstsd->soulball > 0) clif_soulball( dstsd, &sd->bl, SELF ); + if (dstsd->servantball > 0) + clif_servantball( *dstsd, &sd->bl, SELF ); + if (dstsd->abyssball > 0) + clif_abyssball( *dstsd, &sd->bl, SELF ); if( (sd->status.party_id && dstsd->status.party_id == sd->status.party_id) || //Party-mate, or hpdisp setting. (sd->bg_id && sd->bg_id == dstsd->bg_id) || //BattleGround pc_has_permission(sd, PC_PERM_VIEW_HPMETER) @@ -5209,6 +5390,25 @@ void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit *unit, clif_changemapcell(fd, unit->bl.m, unit->bl.x, unit->bl.y, 5, SELF); } +/// 09ca .W L .L .W .W .L .B .B .B (ZC_SKILL_ENTRY5) +void clif_skill_unit_test(struct block_list *bl, short x, short y, int unit_id, short range, short skill_lv) { + unsigned char buf[128]; + + nullpo_retv(bl); + + WBUFW(buf, 0) = 0x09ca; + WBUFW(buf, 2) = packet_len(0x09ca); + WBUFL(buf, 4) = 1000; + WBUFL(buf, 8) = 2000; + WBUFW(buf, 12) = x; + WBUFW(buf, 14) = y; + WBUFL(buf, 16) = unit_id; + WBUFB(buf, 20) = (unsigned char)range; + WBUFB(buf, 21) = 1; + WBUFB(buf, 22) = (unsigned char)skill_lv; + + clif_send(buf, packet_len(0x09ca), bl, AREA); +} /*========================================== * Server tells client to remove unit of id 'unit->bl.id' @@ -6096,6 +6296,8 @@ void clif_skill_produce_mix_list( struct map_session_data *sd, int skill_id, int /// 4 = GN_MIX_COOKING /// 5 = GN_MAKEBOMB /// 6 = GN_S_PHARMACY +/// 7 = MT_M_MACHINE - Unconfirmed +/// 8 = BO_BIONIC_PHARMACY - Unconfirmed void clif_cooking_list( struct map_session_data *sd, int trigger, uint16 skill_id, int qty, int list_type ){ nullpo_retv( sd ); @@ -8368,7 +8570,6 @@ void clif_spiritball( struct block_list *bl, struct block_list* target, enum sen clif_send( &p, sizeof( p ), target == nullptr ? bl : target, send_target ); } - /// Notifies clients in area of a character's combo delay (ZC_COMBODELAY). /// 01d2 .L .L void clif_combo_delay(struct block_list *bl,t_tick wait) @@ -9714,6 +9915,14 @@ void clif_refresh(struct map_session_data *sd) clif_updatestatus(sd,SP_INT); clif_updatestatus(sd,SP_DEX); clif_updatestatus(sd,SP_LUK); +#ifdef RENEWAL + clif_updatestatus(sd,SP_POW); + clif_updatestatus(sd,SP_STA); + clif_updatestatus(sd,SP_WIS); + clif_updatestatus(sd,SP_SPL); + clif_updatestatus(sd,SP_CON); + clif_updatestatus(sd,SP_CRT); +#endif if (sd->spiritball) clif_spiritball( &sd->bl, &sd->bl, SELF ); if (sd->sc.data[SC_MILLENNIUMSHIELD]) @@ -9722,6 +9931,10 @@ void clif_refresh(struct map_session_data *sd) clif_spiritcharm_single(sd->fd, sd); if (sd->soulball) clif_soulball( sd, &sd->bl, SELF ); + if (sd->servantball) + clif_servantball( *sd, &sd->bl, SELF ); + if (sd->abyssball) + clif_abyssball( *sd, &sd->bl, SELF ); if (sd->vd.cloth_color) clif_refreshlook(&sd->bl,sd->bl.id,LOOK_CLOTHES_COLOR,sd->vd.cloth_color,SELF); if (sd->vd.body_style) @@ -10810,6 +11023,14 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) clif_updatestatus(sd,SP_INT); clif_updatestatus(sd,SP_DEX); clif_updatestatus(sd,SP_LUK); +#ifdef RENEWAL + clif_updatestatus(sd,SP_POW); + clif_updatestatus(sd,SP_STA); + clif_updatestatus(sd,SP_WIS); + clif_updatestatus(sd,SP_SPL); + clif_updatestatus(sd,SP_CON); + clif_updatestatus(sd,SP_CRT); +#endif // abort currently running script sd->state.using_fake_npc = 0; @@ -11208,6 +11429,7 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) if (sd->sc.data[SC_CLOAKING]) skill_check_cloaking(&sd->bl, sd->sc.data[SC_CLOAKING]); status_change_end(&sd->bl, SC_ROLLINGCUTTER, INVALID_TIMER); // If you move, you lose your counters. [malufett] + status_change_end(&sd->bl, SC_CRESCIVEBOLT, INVALID_TIMER); pc_delinvincibletimer(sd); @@ -12488,6 +12710,26 @@ void clif_parse_StatusUp(int fd,struct map_session_data *sd) } +/// Request to increase trait status. +/// 0b24 .W .W +/// status id: +/// SP_POW ~ SP_CON +/// amount: +/// The amount to increase the trait status +void clif_parse_traitstatus_up( int fd, struct map_session_data *sd ){ +#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724 + struct PACKET_CZ_UNCONFIRMED_TSTATUS_UP* p = (struct PACKET_CZ_UNCONFIRMED_TSTATUS_UP*)RFIFOP( fd, 0 ); + + if( p->amount < 0 ){ + ShowDebug( "clif_parse_traitstatus_up: Negative 'increase' value sent by client! %s (AID: %d, CID: %d, value: %d)\n", sd->status.name, sd->status.account_id, sd->status.char_id, p->amount ); + return; + } + + pc_traitstatusup( sd, p->type, p->amount ); +#endif +} + + /// Request to increase level of a skill (CZ_UPGRADE_SKILLLEVEL). /// 0112 .W void clif_parse_SkillUp(int fd,struct map_session_data *sd) @@ -12947,6 +13189,8 @@ void clif_parse_ProduceMix(int fd,struct map_session_data *sd){ /// 4 = GN_MIX_COOKING /// 5 = GN_MAKEBOMB /// 6 = GN_S_PHARMACY +/// 7 = MT_M_MACHINE - Unconfirmed +/// 8 = BO_BIONIC_PHARMACY - Unconfirmed void clif_parse_Cooking(int fd,struct map_session_data *sd) { const struct PACKET_CZ_REQ_MAKINGITEM *p = (struct PACKET_CZ_REQ_MAKINGITEM *)RFIFOP( fd, 0 ); diff --git a/src/map/clif.hpp b/src/map/clif.hpp index 77ff94f435..4ddad74006 100644 --- a/src/map/clif.hpp +++ b/src/map/clif.hpp @@ -478,7 +478,8 @@ enum useskill_fail_cause : uint8_t USESKILL_FAIL_THERE_ARE_NPC_AROUND = 83, USESKILL_FAIL_NEED_MORE_BULLET = 84, USESKILL_FAIL_COINS = 85, - + // 86-99 unknown + USESKILL_FAIL_AP_INSUFFICIENT = 100, USESKILL_FAIL_MAX }; @@ -719,10 +720,14 @@ void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit *unit, void clif_skill_delunit(struct skill_unit *unit); void clif_skillunit_update(struct block_list* bl); +void clif_skill_unit_test(struct block_list *bl, short x, short y, int unit_id, short range, short skill_lv); + void clif_autospell(struct map_session_data *sd,uint16 skill_lv); void clif_devotion(struct block_list *src, struct map_session_data *tsd); void clif_spiritball( struct block_list *bl, struct block_list* target = nullptr, enum send_target send_target = AREA ); void clif_soulball( struct map_session_data *sd, struct block_list* target = nullptr, enum send_target send_target = AREA ); +void clif_servantball( struct map_session_data& sd, struct block_list* target = nullptr, enum send_target send_target = AREA ); +void clif_abyssball( struct map_session_data& sd, struct block_list* target = nullptr, enum send_target send_target = AREA ); void clif_combo_delay(struct block_list *bl,t_tick wait); void clif_bladestop(struct block_list *src, int dst_id, int active); void clif_changemapcell(int fd, int16 m, int x, int y, int type, enum send_target target); diff --git a/src/map/clif_packetdb.hpp b/src/map/clif_packetdb.hpp index d8d7441991..e0e25c8dfb 100644 --- a/src/map/clif_packetdb.hpp +++ b/src/map/clif_packetdb.hpp @@ -2431,4 +2431,8 @@ parseable_packet( HEADER_CZ_SE_CASHSHOP_OPEN2, sizeof( struct PACKET_CZ_SE_CASHSHOP_OPEN2 ), clif_parse_cashshop_open_request, 0 ); #endif +#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724 + parseable_packet( HEADER_CZ_UNCONFIRMED_TSTATUS_UP, sizeof( PACKET_CZ_UNCONFIRMED_TSTATUS_UP ), clif_parse_traitstatus_up, 0 ); +#endif + #endif /* CLIF_PACKETDB_HPP */ diff --git a/src/map/elemental.cpp b/src/map/elemental.cpp index 75cedab0d5..1d580db885 100644 --- a/src/map/elemental.cpp +++ b/src/map/elemental.cpp @@ -79,24 +79,33 @@ int elemental_create(map_session_data *sd, int class_, unsigned int lifetime) { //per individual bonuses switch(db->class_){ - case ELEMENTALID_AGNI_S: case ELEMENTALID_AGNI_M: - case ELEMENTALID_AGNI_L: //ATK + (Summon Agni Skill Level x 20) / HIT + (Summon Agni Skill Level x 10) + case ELEMENTALID_AGNI_S: + case ELEMENTALID_AGNI_M: + case ELEMENTALID_AGNI_L: + case ELEMENTALID_ARDOR://ATK + (Summon Agni Skill Level x 20) / HIT + (Summon Agni Skill Level x 10) ele.atk += i * 20; ele.atk2 += i * 20; ele.hit += i * 10; break; - case ELEMENTALID_AQUA_S: case ELEMENTALID_AQUA_M: - case ELEMENTALID_AQUA_L: //MDEF + (Summon Aqua Skill Level x 10) / MATK + (Summon Aqua Skill Level x 20) + case ELEMENTALID_AQUA_S: + case ELEMENTALID_AQUA_M: + case ELEMENTALID_AQUA_L: + case ELEMENTALID_DILUVIO://MDEF + (Summon Aqua Skill Level x 10) / MATK + (Summon Aqua Skill Level x 20) ele.mdef += i * 10; ele.matk += i * 20; break; - case ELEMENTALID_VENTUS_S: case ELEMENTALID_VENTUS_M: - case ELEMENTALID_VENTUS_L: //FLEE + (Summon Ventus Skill Level x 20) / MATK + (Summon Ventus Skill Level x 10) + case ELEMENTALID_VENTUS_S: + case ELEMENTALID_VENTUS_M: + case ELEMENTALID_VENTUS_L: + case ELEMENTALID_PROCELLA://FLEE + (Summon Ventus Skill Level x 20) / MATK + (Summon Ventus Skill Level x 10) ele.flee += i * 20; ele.matk += i * 10; break; - case ELEMENTALID_TERA_S: case ELEMENTALID_TERA_M: - case ELEMENTALID_TERA_L: //DEF + (Summon Tera Skill Level x 25) / ATK + (Summon Tera Skill Level x 5) + case ELEMENTALID_TERA_S: + case ELEMENTALID_TERA_M: + case ELEMENTALID_TERA_L: + case ELEMENTALID_TERREMOTUS: + case ELEMENTALID_SERPENS://DEF + (Summon Tera Skill Level x 25) / ATK + (Summon Tera Skill Level x 5) ele.def += i * 25; ele.atk += i * 5; ele.atk2 += i * 5; @@ -111,6 +120,17 @@ int elemental_create(map_session_data *sd, int class_, unsigned int lifetime) { ele.matk += 25 * i; } + if ((i = pc_checkskill(sd, EM_ELEMENTAL_SPIRIT_M)) > 0 && db->class_ >= ELEMENTALID_DILUVIO && db->class_ <= ELEMENTALID_SERPENS) { + ele.hp = ele.max_hp += 10000 + 3000 * i; + ele.sp = ele.max_sp += 100 * i; + ele.atk += 100 + 20 * i; + ele.atk2 += 100 + 20 * i; + ele.matk += 20 * i; + ele.def += 20 * i; + ele.mdef += 4 * i; + ele.flee += 10 * i; + } + ele.life_time = lifetime; // Request Char Server to create this elemental @@ -296,6 +316,16 @@ int elemental_clean_single_effect(s_elemental_data *ed, uint16 skill_id) { case SC_UPHEAVAL_OPTION: case SC_CIRCLE_OF_FIRE_OPTION: case SC_TIDAL_WEAPON_OPTION: + case SC_FLAMETECHNIC_OPTION: + case SC_FLAMEARMOR_OPTION: + case SC_COLD_FORCE_OPTION: + case SC_CRYSTAL_ARMOR_OPTION: + case SC_GRACE_BREEZE_OPTION: + case SC_EYES_OF_STORM_OPTION: + case SC_EARTH_CARE_OPTION: + case SC_STRONG_PROTECTION_OPTION: + case SC_DEEP_POISONING_OPTION: + case SC_POISON_SHIELD_OPTION: if( bl ) status_change_end(bl,type,INVALID_TIMER); // Master status_change_end(&ed->bl,static_cast(type-1),INVALID_TIMER); // Elemental Spirit break; @@ -338,6 +368,16 @@ int elemental_clean_effect(s_elemental_data *ed) { status_change_end(&ed->bl, SC_UPHEAVAL, INVALID_TIMER); status_change_end(&ed->bl, SC_CIRCLE_OF_FIRE, INVALID_TIMER); status_change_end(&ed->bl, SC_TIDAL_WEAPON, INVALID_TIMER); + status_change_end(&ed->bl, SC_FLAMETECHNIC, INVALID_TIMER); + status_change_end(&ed->bl, SC_FLAMEARMOR, INVALID_TIMER); + status_change_end(&ed->bl, SC_COLD_FORCE, INVALID_TIMER); + status_change_end(&ed->bl, SC_CRYSTAL_ARMOR, INVALID_TIMER); + status_change_end(&ed->bl, SC_GRACE_BREEZE, INVALID_TIMER); + status_change_end(&ed->bl, SC_EYES_OF_STORM, INVALID_TIMER); + status_change_end(&ed->bl, SC_EARTH_CARE, INVALID_TIMER); + status_change_end(&ed->bl, SC_STRONG_PROTECTION, INVALID_TIMER); + status_change_end(&ed->bl, SC_DEEP_POISONING, INVALID_TIMER); + status_change_end(&ed->bl, SC_POISON_SHIELD, INVALID_TIMER); if( (sd = ed->master) == NULL ) return 0; @@ -367,6 +407,16 @@ int elemental_clean_effect(s_elemental_data *ed) { status_change_end(&sd->bl, SC_UPHEAVAL_OPTION, INVALID_TIMER); status_change_end(&sd->bl, SC_CIRCLE_OF_FIRE_OPTION, INVALID_TIMER); status_change_end(&sd->bl, SC_TIDAL_WEAPON_OPTION, INVALID_TIMER); + status_change_end(&sd->bl, SC_FLAMETECHNIC_OPTION, INVALID_TIMER); + status_change_end(&sd->bl, SC_FLAMEARMOR_OPTION, INVALID_TIMER); + status_change_end(&sd->bl, SC_COLD_FORCE_OPTION, INVALID_TIMER); + status_change_end(&sd->bl, SC_CRYSTAL_ARMOR_OPTION, INVALID_TIMER); + status_change_end(&sd->bl, SC_GRACE_BREEZE_OPTION, INVALID_TIMER); + status_change_end(&sd->bl, SC_EYES_OF_STORM_OPTION, INVALID_TIMER); + status_change_end(&sd->bl, SC_EARTH_CARE_OPTION, INVALID_TIMER); + status_change_end(&sd->bl, SC_STRONG_PROTECTION_OPTION, INVALID_TIMER); + status_change_end(&sd->bl, SC_DEEP_POISONING_OPTION, INVALID_TIMER); + status_change_end(&sd->bl, SC_POISON_SHIELD_OPTION, INVALID_TIMER); return 1; } @@ -745,8 +795,8 @@ uint64 ElementalDatabase::parseBodyNode(const YAML::Node &node) { if (!this->asInt32(node, "Id", id)) return 0; - if (id < ELEMENTALID_AGNI_S || id > ELEMENTALID_TERA_L) { - this->invalidWarning(node["Id"], "Invalid Id %d (valid range: %d-%d).\n", id, ELEMENTALID_AGNI_S, ELEMENTALID_TERA_L); + if( !( ( id >= ELEMENTALID_AGNI_S && id <= ELEMENTALID_TERA_L ) || ( id >= ELEMENTALID_DILUVIO && id <= ELEMENTALID_SERPENS ) ) ) { + this->invalidWarning( node["Id"], "Invalid Id %d (valid ranges: %d-%d and %d-%d).\n", id, ELEMENTALID_AGNI_S, ELEMENTALID_TERA_L, ELEMENTALID_DILUVIO, ELEMENTALID_SERPENS ); return 0; } diff --git a/src/map/elemental.hpp b/src/map/elemental.hpp index dfa2d0110f..48d157cc82 100644 --- a/src/map/elemental.hpp +++ b/src/map/elemental.hpp @@ -28,6 +28,7 @@ enum e_elemental_skillmode : uint8 { ///Enum of Elemental ID enum elemental_elementalid : uint16 { + // Sorcerer's Elementals ELEMENTALID_AGNI_S = 2114, ELEMENTALID_AGNI_M, ELEMENTALID_AGNI_L, @@ -40,6 +41,13 @@ enum elemental_elementalid : uint16 { ELEMENTALID_TERA_S, ELEMENTALID_TERA_M, ELEMENTALID_TERA_L, + + // Elemental Master's Elementals + ELEMENTALID_DILUVIO = 20816, + ELEMENTALID_ARDOR, + ELEMENTALID_PROCELLA, + ELEMENTALID_TERREMOTUS, + ELEMENTALID_SERPENS, }; struct s_elemental_skill { diff --git a/src/map/itemdb.hpp b/src/map/itemdb.hpp index 1a0eef440a..85a3e33345 100644 --- a/src/map/itemdb.hpp +++ b/src/map/itemdb.hpp @@ -230,7 +230,7 @@ enum e_item_job : uint16 ITEMJ_FOURTH = 0x40, ITEMJ_MAX = 0xFF, - ITEMJ_ALL_UPPER = ITEMJ_UPPER | ITEMJ_THIRD_UPPER, + ITEMJ_ALL_UPPER = ITEMJ_UPPER | ITEMJ_THIRD_UPPER | ITEMJ_FOURTH, ITEMJ_ALL_BABY = ITEMJ_BABY | ITEMJ_THIRD_BABY, ITEMJ_ALL_THIRD = ITEMJ_THIRD | ITEMJ_THIRD_UPPER | ITEMJ_THIRD_BABY, diff --git a/src/map/map.cpp b/src/map/map.cpp index e9ecc29101..735bfc6788 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -2112,6 +2112,8 @@ int map_quit(struct map_session_data *sd) { status_change_end(&sd->bl, SC_EQC, INVALID_TIMER); status_change_end(&sd->bl, SC_SPRITEMABLE, INVALID_TIMER); status_change_end(&sd->bl, SC_SV_ROOTTWIST, INVALID_TIMER); + status_change_end(&sd->bl, SC_GUARD_STANCE, INVALID_TIMER); + status_change_end(&sd->bl, SC_ATTACK_STANCE, INVALID_TIMER); // Remove visuals effect from headgear status_change_end(&sd->bl, SC_MOONSTAR, INVALID_TIMER); status_change_end(&sd->bl, SC_SUPER_STAR, INVALID_TIMER); @@ -2135,6 +2137,7 @@ int map_quit(struct map_session_data *sd) { status_change_end(&sd->bl, SC_H_MINE, INVALID_TIMER); status_change_end(&sd->bl, SC_ANTI_M_BLAST, INVALID_TIMER); status_change_end(&sd->bl, SC_B_TRAP, INVALID_TIMER); + status_change_end(&sd->bl, SC_SHADOW_STRIP, INVALID_TIMER); } if (battle_config.debuff_on_logout&2) { //Remove positive buffs status_change_end(&sd->bl, SC_MAXIMIZEPOWER, INVALID_TIMER); diff --git a/src/map/map.hpp b/src/map/map.hpp index a0d93df080..0712741093 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -75,6 +75,7 @@ void map_msg_reload(void); #define MAPID_BASEMASK 0x00ff #define MAPID_UPPERMASK 0x0fff #define MAPID_THIRDMASK (JOBL_THIRD|MAPID_UPPERMASK) +#define MAPID_FOURTHMASK (JOBL_FOURTH|MAPID_THIRDMASK|JOBL_UPPER) //First Jobs //Note the oddity of the novice: @@ -403,6 +404,8 @@ enum mob_ai { AI_FAW, AI_GUILD, AI_WAVEMODE, + AI_ABR, + AI_BIONIC, AI_MAX }; @@ -517,6 +520,7 @@ enum _sp { SP_DELAYRATE,SP_HP_DRAIN_VALUE_RACE, SP_SP_DRAIN_VALUE_RACE, // 1083-1085 SP_IGNORE_MDEF_RACE_RATE,SP_IGNORE_DEF_RACE_RATE,SP_SKILL_HEAL2,SP_ADDEFF_ONSKILL, //1086-1089 SP_ADD_HEAL_RATE,SP_ADD_HEAL2_RATE, SP_EQUIP_ATK, //1090-1092 + SP_PATK_RATE,SP_SMATK_RATE,SP_RES_RATE,SP_MRES_RATE,SP_HPLUS_RATE,SP_CRATE_RATE,SP_ALL_TRAIT_STATS,SP_MAXAPRATE,// 1093-1100 SP_RESTART_FULL_RECOVER=2000,SP_NO_CASTCANCEL,SP_NO_SIZEFIX,SP_NO_MAGIC_DAMAGE,SP_NO_WEAPON_DAMAGE,SP_NO_GEMSTONE, // 2000-2005 SP_NO_CASTCANCEL2,SP_NO_MISC_DAMAGE,SP_UNBREAKABLE_WEAPON,SP_UNBREAKABLE_ARMOR, SP_UNBREAKABLE_HELM, // 2006-2010 @@ -544,6 +548,7 @@ enum _sp { SP_IGNORE_DEF_CLASS_RATE, SP_REGEN_PERCENT_HP, SP_REGEN_PERCENT_SP, SP_SKILL_DELAY, SP_NO_WALK_DELAY, //2088-2092 SP_LONG_SP_GAIN_VALUE, SP_LONG_HP_GAIN_VALUE, SP_SHORT_ATK_RATE, SP_MAGIC_SUBSIZE, SP_CRIT_DEF_RATE, // 2093-2097 SP_MAGIC_SUBDEF_ELE, SP_REDUCE_DAMAGE_RETURN, SP_ADD_ITEM_SPHEAL_RATE, SP_ADD_ITEMGROUP_SPHEAL_RATE, // 2098-2101 + SP_WEAPON_SUBSIZE // 2102 }; enum _look { diff --git a/src/map/mob.cpp b/src/map/mob.cpp index 0f10970a9b..bd12630d58 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -1437,7 +1437,7 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,t_tick tick) // Distance with between slave and master is measured. md->master_dist = distance_bl(&md->bl, bl); - if (battle_config.slave_stick_with_master) { + if (battle_config.slave_stick_with_master || md->special_state.ai == AI_ABR || md->special_state.ai == AI_BIONIC) { // Since the master was in near immediately before, teleport is carried out and it pursues. if (bl->m != md->bl.m || (old_dist < 10 && md->master_dist > 18) || md->master_dist > MAX_MINCHASE) { md->master_dist = 0; @@ -3056,7 +3056,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) //Emperium destroyed by script. Discard mvp character. [Skotlex] mvp_sd = NULL; - rebirth = ( md->sc.data[SC_KAIZEL] || (md->sc.data[SC_REBIRTH] && !md->state.rebirth) ); + rebirth = ( md->sc.data[SC_KAIZEL] || md->sc.data[SC_ULTIMATE_S] || (md->sc.data[SC_REBIRTH] && !md->state.rebirth) ); if( !rebirth ) { // Only trigger event on final kill if( src ) { switch( src->type ) { //allowed type @@ -4509,6 +4509,32 @@ uint64 MobDatabase::parseBodyNode(const YAML::Node &node) { mob->status.mdef = 0; } + if (this->nodeExists(node, "Resistance")) { + uint16 res; + + if (!this->asUInt16(node, "Resistance", res)) + return 0; + + mob->status.res = res; + } + else { + if (!exists) + mob->status.res = 0; + } + + if (this->nodeExists(node, "MagicResistance")) { + uint16 mres; + + if (!this->asUInt16(node, "MagicResistance", mres)) + return 0; + + mob->status.mres = mres; + } + else { + if (!exists) + mob->status.mres = 0; + } + if (this->nodeExists(node, "Str")) { uint16 stat; @@ -5140,6 +5166,13 @@ static bool mob_read_sqldb_sub(std::vector str) { node["Drops"][i] = drops; } +#ifdef RENEWAL + if (!str[++index].empty()) + node["Resistance"] = std::stoi(str[index]); + if (!str[++index].empty()) + node["MagicResistance"] = std::stoi(str[index]); +#endif + return mob_db.parseBodyNode(node) > 0; } @@ -5161,6 +5194,9 @@ static int mob_read_sqldb(void) "`mode_canmove`,`mode_looter`,`mode_aggressive`,`mode_assist`,`mode_castsensoridle`,`mode_norandomwalk`,`mode_nocast`,`mode_canattack`,`mode_castsensorchase`,`mode_changechase`,`mode_angry`,`mode_changetargetmelee`,`mode_changetargetchase`,`mode_targetweak`,`mode_randomtarget`,`mode_ignoremelee`,`mode_ignoremagic`,`mode_ignoreranged`,`mode_mvp`,`mode_ignoremisc`,`mode_knockbackimmune`,`mode_teleportblock`,`mode_fixeditemdrop`,`mode_detector`,`mode_statusimmune`,`mode_skillimmune`," "`mvpdrop1_item`,`mvpdrop1_rate`,`mvpdrop1_option`,`mvpdrop1_index`,`mvpdrop2_item`,`mvpdrop2_rate`,`mvpdrop2_option`,`mvpdrop2_index`,`mvpdrop3_item`,`mvpdrop3_rate`,`mvpdrop3_option`,`mvpdrop3_index`," "`drop1_item`,`drop1_rate`,`drop1_nosteal`,`drop1_option`,`drop1_index`,`drop2_item`,`drop2_rate`,`drop2_nosteal`,`drop2_option`,`drop2_index`,`drop3_item`,`drop3_rate`,`drop3_nosteal`,`drop3_option`,`drop3_index`,`drop4_item`,`drop4_rate`,`drop4_nosteal`,`drop4_option`,`drop4_index`,`drop5_item`,`drop5_rate`,`drop5_nosteal`,`drop5_option`,`drop5_index`,`drop6_item`,`drop6_rate`,`drop6_nosteal`,`drop6_option`,`drop6_index`,`drop7_item`,`drop7_rate`,`drop7_nosteal`,`drop7_option`,`drop7_index`,`drop8_item`,`drop8_rate`,`drop8_nosteal`,`drop8_option`,`drop8_index`,`drop9_item`,`drop9_rate`,`drop9_nosteal`,`drop9_option`,`drop9_index`,`drop10_item`,`drop10_rate`,`drop10_nosteal`,`drop10_option`,`drop10_index`" +#ifdef RENEWAL + ",`resistance`,`magic_resistance`" +#endif " FROM `%s`", mob_db_name[fi]) ) { Sql_ShowDebug(mmysql_handle); continue; diff --git a/src/map/mob.hpp b/src/map/mob.hpp index 671f29bcb0..9fde194a40 100644 --- a/src/map/mob.hpp +++ b/src/map/mob.hpp @@ -74,6 +74,14 @@ enum MOBID { MOBID_S_GIANT_HORNET, MOBID_S_LUCIOLA_VESPA, MOBID_GUILD_SKILL_FLAG = 20269, + MOBID_ABR_BATTLE_WARIOR = 20834, + MOBID_ABR_DUAL_CANNON, + MOBID_ABR_MOTHER_NET, + MOBID_ABR_INFINITY, + MOBID_BIONIC_WOODENWARRIOR = 20848, + MOBID_BIONIC_WOODEN_FAIRY, + MOBID_BIONIC_CREEPER, + MOBID_BIONIC_HELLTREE, }; ///Mob skill states. @@ -265,7 +273,7 @@ private: bool parseDropNode(std::string nodeName, YAML::Node node, uint8 max, s_mob_drop *drops); public: - MobDatabase() : TypesafeCachedYamlDatabase("MOB_DB", 2, 1) { + MobDatabase() : TypesafeCachedYamlDatabase("MOB_DB", 3, 1) { } diff --git a/src/map/packets.hpp b/src/map/packets.hpp index e49f36e8b9..53776bf0b2 100644 --- a/src/map/packets.hpp +++ b/src/map/packets.hpp @@ -159,6 +159,12 @@ struct PACKET_ZC_ACK_GUILDSTORAGE_LOG{ struct PACKET_ZC_ACK_GUILDSTORAGE_LOG_sub items[]; } __attribute__((packed)); +struct PACKET_CZ_UNCONFIRMED_TSTATUS_UP{ + int16 packetType; + int16 type; + int16 amount; +} __attribute__((packed)); + struct PACKET_CZ_GUILD_EMBLEM_CHANGE2 { int16 packetType; uint32 guild_id; @@ -265,6 +271,7 @@ DEFINE_PACKET_HEADER(ZC_ACK_GUILDSTORAGE_LOG, 0x9da) DEFINE_PACKET_HEADER(CZ_NPC_MARKET_PURCHASE, 0x9d6) DEFINE_PACKET_HEADER(CZ_REQ_APPLY_BARGAIN_SALE_ITEM2, 0xa3d) DEFINE_PACKET_HEADER(ZC_REMOVE_EFFECT, 0x0b0d) +DEFINE_PACKET_HEADER(CZ_UNCONFIRMED_TSTATUS_UP, 0x0b24) DEFINE_PACKET_HEADER(CZ_GUILD_EMBLEM_CHANGE2, 0x0b46) DEFINE_PACKET_HEADER(ZC_UNCONFIRMED_SPIRITS3, 0xb73) diff --git a/src/map/party.cpp b/src/map/party.cpp index f9e70b1310..4093d83f9c 100644 --- a/src/map/party.cpp +++ b/src/map/party.cpp @@ -242,18 +242,21 @@ static void party_check_state(struct party_data *p) case JOB_SURA: case JOB_SURA_T: case JOB_BABY_SURA: + case JOB_INQUISITOR: p->state.monk = 1; break; case JOB_STAR_GLADIATOR: case JOB_BABY_STAR_GLADIATOR: case JOB_STAR_EMPEROR: case JOB_BABY_STAR_EMPEROR: + case JOB_SKY_EMPEROR: p->state.sg = 1; break; case JOB_SUPER_NOVICE: case JOB_SUPER_BABY: case JOB_SUPER_NOVICE_E: case JOB_SUPER_BABY_E: + case JOB_HYPER_NOVICE: p->state.snovice = 1; break; case JOB_TAEKWON: diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 9433fae64d..36d6f23a35 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -707,6 +707,50 @@ int pc_delsoulball(map_session_data *sd, int count, bool type) return 0; } +/** +* Adds servantballs to a player +* @param sd: Player data +* @param amount: Amount to add +*/ +void pc_addservantball( struct map_session_data& sd, int count ){ + sd.servantball = cap_value( sd.servantball + count, 0, MAX_SERVANTBALL ); + + clif_servantball( sd ); +} + +/** +* Removes number of servantballs from player +* @param sd: Player data +* @param count: Amount to remove +*/ +void pc_delservantball( struct map_session_data& sd, int count ){ + sd.servantball = cap_value( sd.servantball - count, 0, MAX_SERVANTBALL ); + + clif_servantball( sd ); +} + +/** +* Adds abyssballs to a player +* @param sd: Player data +* @param amount: Amount to add +*/ +void pc_addabyssball( struct map_session_data& sd, int count ){ + sd.abyssball = cap_value( sd.abyssball + count, 0, MAX_ABYSSBALL ); + + clif_abyssball( sd ); +} + +/** +* Removes number of abyssballs from player +* @param sd: Player data +* @param count: Amount to remove +*/ +void pc_delabyssball( struct map_session_data& sd, int count ){ + sd.abyssball = cap_value( sd.abyssball - count, 0, MAX_ABYSSBALL ); + + clif_abyssball( sd ); +} + /** * Increases a player's fame points and displays a notice to him * @param sd Player @@ -787,6 +831,7 @@ void pc_setrestartvalue(struct map_session_data *sd, char type) { } else { //Just for saving on the char-server (with values as if respawned) sd->status.hp = b_status->hp; sd->status.sp = (status->sp < b_status->sp)?b_status->sp:status->sp; + sd->status.ap = (status->ap < b_status->ap)?b_status->ap:status->ap; } } @@ -1005,6 +1050,7 @@ void pc_makesavestatus(struct map_session_data *sd) { } else { sd->status.hp = sd->battle_status.hp; sd->status.sp = sd->battle_status.sp; + sd->status.ap = sd->battle_status.ap; } sd->status.last_point.map = sd->mapindex; sd->status.last_point.x = sd->bl.x; @@ -1018,6 +1064,7 @@ void pc_makesavestatus(struct map_session_data *sd) { } else { sd->status.hp = sd->battle_status.hp; sd->status.sp = sd->battle_status.sp; + sd->status.ap = sd->battle_status.ap; sd->status.last_point.map = sd->mapindex; sd->status.last_point.x = sd->bl.x; sd->status.last_point.y = sd->bl.y; @@ -1401,7 +1448,7 @@ static bool pc_job_can_use_item( struct map_session_data* sd, struct item_data* *------------------------------------------*/ static bool pc_isItemClass (struct map_session_data *sd, struct item_data* item) { while (1) { - if (item->class_upper&ITEMJ_NORMAL && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY))) //normal classes (no upper, no baby, no third) + if (item->class_upper&ITEMJ_NORMAL && !(sd->class_&(JOBL_UPPER|JOBL_BABY|JOBL_THIRD|JOBL_FOURTH))) //normal classes (no upper, no baby, no third, no fourth) break; #ifndef RENEWAL //allow third classes to use trans. class items @@ -1421,14 +1468,14 @@ static bool pc_isItemClass (struct map_session_data *sd, struct item_data* item) //baby classes (exl. third-baby) if (item->class_upper&ITEMJ_BABY && sd->class_&JOBL_BABY && !(sd->class_&JOBL_THIRD)) break; - //third classes (exl. third-trans. and baby-third) - if (item->class_upper&ITEMJ_THIRD && sd->class_&JOBL_THIRD && !(sd->class_&(JOBL_UPPER|JOBL_BABY))) + //third classes (exl. third-trans. and baby-third and fourth) + if (item->class_upper&ITEMJ_THIRD && sd->class_&JOBL_THIRD && !(sd->class_&(JOBL_UPPER|JOBL_BABY)) && !(sd->class_&JOBL_FOURTH)) break; - //trans-third classes - if (item->class_upper&ITEMJ_THIRD_UPPER && sd->class_&JOBL_THIRD && sd->class_&JOBL_UPPER) + //trans-third classes (exl. fourth) + if (item->class_upper&ITEMJ_THIRD_UPPER && sd->class_&JOBL_THIRD && sd->class_&JOBL_UPPER && !(sd->class_&JOBL_FOURTH)) break; - //third-baby classes - if (item->class_upper&ITEMJ_THIRD_BABY && sd->class_&JOBL_THIRD && sd->class_&JOBL_BABY) + //third-baby classes (exl. fourth) + if (item->class_upper&ITEMJ_THIRD_BABY && sd->class_&JOBL_THIRD && sd->class_&JOBL_BABY && !(sd->class_&JOBL_FOURTH)) break; //fourth classes if (item->class_upper&ITEMJ_FOURTH && sd->class_&JOBL_FOURTH) @@ -1527,6 +1574,8 @@ uint8 pc_isequip(struct map_session_data *sd,int n) return ITEM_EQUIP_ACK_FAIL; if (item->equip & EQP_ARMS && sd->sc.data[SC__WEAKNESS]) return ITEM_EQUIP_ACK_FAIL; + if (item->equip & EQP_SHADOW_GEAR && sd->sc.data[SC_SHADOW_STRIP]) + return ITEM_EQUIP_ACK_FAIL; if(item->equip && (sd->sc.data[SC_KYOUGAKU] || sd->sc.data[SC_SUHIDE])) return ITEM_EQUIP_ACK_FAIL; @@ -1836,6 +1885,7 @@ void pc_reg_received(struct map_session_data *sd) sd->change_level_2nd = static_cast(pc_readglobalreg(sd, add_str(JOBCHANGE2ND_VAR))); sd->change_level_3rd = static_cast(pc_readglobalreg(sd, add_str(JOBCHANGE3RD_VAR))); + sd->change_level_4th = static_cast(pc_readglobalreg(sd, add_str(JOBCHANGE4TH_VAR))); sd->die_counter = static_cast(pc_readglobalreg(sd, add_str(PCDIECOUNTER_VAR))); sd->langtype = static_cast(pc_readaccountreg(sd, add_str(LANGTYPE_VAR))); @@ -2375,69 +2425,44 @@ uint64 pc_calc_skilltree_normalize_job(struct map_session_data *sd) skill_point = pc_calc_skillpoint(sd); + // Novice's skill points for basic skill. std::shared_ptr novice_job = job_db.find(JOB_NOVICE); novice_skills = novice_job->max_job_level - 1; - // limit 1st class and above to novice job levels - if(skill_point < novice_skills && (sd->class_&MAPID_BASEMASK) != MAPID_SUMMONER) - { + // 1st Class Job LV Check + if (sd->class_ & JOBL_2 && (sd->class_ & MAPID_UPPERMASK) != MAPID_SUPER_NOVICE && !sd->change_level_2nd) { + sd->change_level_2nd = job_db.find(pc_mapid2jobid(sd->class_ & MAPID_BASEMASK, sd->status.sex))->max_job_level; + pc_setglobalreg(sd, add_str(JOBCHANGE2ND_VAR), sd->change_level_2nd); + } + + // 2nd Class Job LV Check + if (sd->class_ & JOBL_THIRD && (sd->class_ & MAPID_THIRDMASK) != MAPID_SUPER_NOVICE_E && !sd->change_level_3rd) { + sd->change_level_3rd = job_db.find(pc_mapid2jobid(sd->class_ & MAPID_UPPERMASK, sd->status.sex))->max_job_level; + pc_setglobalreg(sd, add_str(JOBCHANGE3RD_VAR), sd->change_level_3rd); + } + + // 3rd Class Job LV Check + if (sd->class_ & JOBL_FOURTH && !sd->change_level_4th) { + sd->change_level_4th = job_db.find(pc_mapid2jobid(sd->class_ & MAPID_THIRDMASK | JOBL_THIRD, sd->status.sex))->max_job_level; + pc_setglobalreg(sd, add_str(JOBCHANGE4TH_VAR), sd->change_level_4th); + } + + // Check the skill tree the player has access to depending on the used number of skill points. + if (skill_point < novice_skills && (sd->class_&MAPID_BASEMASK) != MAPID_SUMMONER) // Novice Skill Tree c = MAPID_NOVICE; - } - // limit 2nd class and above to first class job levels (super novices are exempt) - else if (sd->class_&JOBL_2 && (sd->class_&MAPID_UPPERMASK) != MAPID_SUPER_NOVICE) - { - // regenerate change_level_2nd - if (!sd->change_level_2nd) - { - if (sd->class_&JOBL_THIRD) - { - // if neither 2nd nor 3rd jobchange levels are known, we have to assume a default for 2nd - if (!sd->change_level_3rd) { - std::shared_ptr job = job_db.find(pc_mapid2jobid(sd->class_&MAPID_UPPERMASK, sd->status.sex)); + else if (skill_point < novice_skills + (sd->change_level_2nd - 1) && (sd->class_&MAPID_UPPERMASK) != MAPID_SUPER_NOVICE) // 1st Job Skill Tree + c &= MAPID_BASEMASK; + else if (skill_point < novice_skills + (sd->change_level_2nd - 1) + (sd->change_level_3rd - 1) && (sd->class_&MAPID_THIRDMASK) != MAPID_SUPER_NOVICE_E) // 2nd Job Skill Tree + c &= MAPID_UPPERMASK; + else if (skill_point < novice_skills + (sd->change_level_2nd - 1) + (sd->change_level_3rd - 1) + (sd->change_level_4th - 1)) // 3rd Job Skill Tree + c &= MAPID_THIRDMASK; - sd->change_level_2nd = job->max_job_level; - } else - sd->change_level_2nd = 1 + skill_point + sd->status.skill_point - - (sd->status.job_level - 1) - - (sd->change_level_3rd - 1) - - novice_skills; - } - else - { - sd->change_level_2nd = 1 + skill_point + sd->status.skill_point - - (sd->status.job_level - 1) - - novice_skills; - - } - - pc_setglobalreg(sd, add_str(JOBCHANGE2ND_VAR), sd->change_level_2nd); - } - - if (skill_point < novice_skills + (sd->change_level_2nd - 1)) - { - c &= MAPID_BASEMASK; - } - // limit 3rd class to 2nd class/trans job levels - else if(sd->class_&JOBL_THIRD) - { - // regenerate change_level_3rd - if (!sd->change_level_3rd) - { - sd->change_level_3rd = 1 + skill_point + sd->status.skill_point - - (sd->status.job_level - 1) - - (sd->change_level_2nd - 1) - - novice_skills; - pc_setglobalreg(sd, add_str(JOBCHANGE3RD_VAR), sd->change_level_3rd); - } - - if (skill_point < novice_skills + (sd->change_level_2nd - 1) + (sd->change_level_3rd - 1)) - c &= MAPID_UPPERMASK; - } - } - - // restore non-limiting flags - c |= sd->class_&(JOBL_UPPER|JOBL_BABY); + // Special Masks + if (sd->class_&JOBL_UPPER) + c |= JOBL_UPPER;// Rebirth Job + if (sd->class_&JOBL_BABY) + c |= JOBL_BABY;// Baby Job return c; } @@ -3290,6 +3315,42 @@ void pc_bonus(struct map_session_data *sd,int type,int val) } else sd->bonus.arrow_cri += val*10; break; + case SP_PATK: + if (sd->state.lr_flag != 2) { + bonus = status->patk + val; + status->patk = cap_value(bonus, SHRT_MIN, SHRT_MAX); + } + break; + case SP_SMATK: + if (sd->state.lr_flag != 2) { + bonus = status->smatk + val; + status->smatk = cap_value(bonus, SHRT_MIN, SHRT_MAX); + } + break; + case SP_RES: + if (sd->state.lr_flag != 2) { + bonus = status->res + val; + status->res = cap_value(bonus, SHRT_MIN, SHRT_MAX); + } + break; + case SP_MRES: + if (sd->state.lr_flag != 2) { + bonus = status->mres + val; + status->mres = cap_value(bonus, SHRT_MIN, SHRT_MAX); + } + break; + case SP_HPLUS: + if (sd->state.lr_flag != 2) { + bonus = status->hplus + val; + status->hplus = cap_value(bonus, SHRT_MIN, SHRT_MAX); + } + break; + case SP_CRATE: + if (sd->state.lr_flag != 2) { + bonus = status->crate + val; + status->crate = cap_value(bonus, SHRT_MIN, SHRT_MAX); + } + break; case SP_ATKELE: PC_BONUS_CHK_ELEMENT(val,SP_ATKELE); switch (sd->state.lr_flag) @@ -3333,6 +3394,11 @@ void pc_bonus(struct map_session_data *sd,int type,int val) break; sd->bonus.sp += val; break; + case SP_MAXAP: + if (sd->state.lr_flag == 2) + break; + sd->bonus.ap += val; + break; case SP_MAXHPRATE: if(sd->state.lr_flag != 2) sd->hprate+=val; @@ -3341,6 +3407,10 @@ void pc_bonus(struct map_session_data *sd,int type,int val) if(sd->state.lr_flag != 2) sd->sprate+=val; break; + case SP_MAXAPRATE: + if (sd->state.lr_flag != 2) + sd->aprate += val; + break; case SP_SPRATE: if(sd->state.lr_flag != 2) sd->dsprate+=val; @@ -3522,6 +3592,30 @@ void pc_bonus(struct map_session_data *sd,int type,int val) if(sd->state.lr_flag != 2) sd->mdef2_rate += val; break; + case SP_PATK_RATE: + if (sd->state.lr_flag != 2) + sd->patk_rate += val; + break; + case SP_SMATK_RATE: + if (sd->state.lr_flag != 2) + sd->smatk_rate += val; + break; + case SP_RES_RATE: + if (sd->state.lr_flag != 2) + sd->res_rate += val; + break; + case SP_MRES_RATE: + if (sd->state.lr_flag != 2) + sd->mres_rate += val; + break; + case SP_HPLUS_RATE: + if (sd->state.lr_flag != 2) + sd->hplus_rate += val; + break; + case SP_CRATE_RATE: + if (sd->state.lr_flag != 2) + sd->crate_rate += val; + break; case SP_RESTART_FULL_RECOVER: if(sd->state.lr_flag != 2) sd->special_state.restart_full_recover = 1; @@ -3603,6 +3697,16 @@ void pc_bonus(struct map_session_data *sd,int type,int val) sd->indexed_bonus.param_bonus[SP_LUK-SP_STR]+=val; } break; + case SP_ALL_TRAIT_STATS: + if (sd->state.lr_flag != 2) { + sd->indexed_bonus.param_bonus[PARAM_POW] += val; + sd->indexed_bonus.param_bonus[PARAM_STA] += val; + sd->indexed_bonus.param_bonus[PARAM_WIS] += val; + sd->indexed_bonus.param_bonus[PARAM_SPL] += val; + sd->indexed_bonus.param_bonus[PARAM_CON] += val; + sd->indexed_bonus.param_bonus[PARAM_CRT] += val; + } + break; case SP_AGI_VIT: // [Valaris] if(sd->state.lr_flag!=2) { sd->indexed_bonus.param_bonus[SP_AGI-SP_STR]+=val; @@ -4143,6 +4247,11 @@ void pc_bonus2(struct map_session_data *sd,int type,int type2,int val) if(sd->state.lr_flag != 2) sd->indexed_bonus.subsize[type2]+=val; break; + case SP_WEAPON_SUBSIZE: // bonus2 bWeaponSubSize,s,x; + PC_BONUS_CHK_SIZE(type2, SP_WEAPON_SUBSIZE); + if (sd->state.lr_flag != 2) + sd->indexed_bonus.weapon_subsize[type2] += val; + break; case SP_MAGIC_SUBSIZE: // bonus2 bMagicSubSize,s,x; PC_BONUS_CHK_SIZE(type2,SP_MAGIC_SUBSIZE); if(sd->state.lr_flag != 2) @@ -5624,7 +5733,11 @@ bool pc_isUseitem(struct map_session_data *sd,int n) sd->sc.data[SC_KAGEHUMI] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM) || sd->sc.data[SC_KINGS_GRACE] || - sd->sc.data[SC_SUHIDE])) + sd->sc.data[SC_SUHIDE] || + sd->sc.data[SC_HANDICAPSTATE_FROSTBITE] || + sd->sc.data[SC_HANDICAPSTATE_SWOONING] || + sd->sc.data[SC_HANDICAPSTATE_LIGHTNINGSTRIKE] || + sd->sc.data[SC_HANDICAPSTATE_CRYSTALLIZATION])) return false; if (!pc_isItemClass(sd,item)) @@ -6081,7 +6194,9 @@ int pc_steal_coin(struct map_session_data *sd,struct block_list *target) md = (TBL_MOB*)target; target_lv = status_get_lv(target); - if (md->state.steal_coin_flag || md->sc.data[SC_STONE] || md->sc.data[SC_FREEZE] || status_bl_has_mode(target,MD_STATUSIMMUNE) || util::vector_exists(status_get_race2(&md->bl), RC2_TREASURE)) + if (md->state.steal_coin_flag || md->sc.data[SC_STONE] || md->sc.data[SC_FREEZE] || md->sc.data[SC_HANDICAPSTATE_FROSTBITE] || + md->sc.data[SC_HANDICAPSTATE_SWOONING] || md->sc.data[SC_HANDICAPSTATE_LIGHTNINGSTRIKE] || md->sc.data[SC_HANDICAPSTATE_CRYSTALLIZATION] || + status_bl_has_mode(target,MD_STATUSIMMUNE) || util::vector_exists(status_get_race2(&md->bl), RC2_TREASURE)) return 0; rate = sd->battle_status.dex / 2 + 2 * (sd->status.base_level - target_lv) + (10 * pc_checkskill(sd, RG_STEALCOIN)) + sd->battle_status.luk / 2; @@ -6180,6 +6295,9 @@ enum e_setpos pc_setpos(struct map_session_data* sd, unsigned short mapindex, in } if (battle_config.clear_unit_onwarp&BL_PC) skill_clear_unitgroup(&sd->bl); + if( battle_config.loose_ap_on_map && mapdata_flag_vs( mapdata ) ){ + status_percent_damage( nullptr, &sd->bl, 0, 0, 100, 0 ); + } party_send_dot_remove(sd); //minimap dot fix [Kevin] guild_send_dot_remove(sd); bg_send_dot_remove(sd); @@ -6505,6 +6623,28 @@ uint8 pc_checkskill_summoner(map_session_data *sd, e_summoner_power_type type) { return count; } +/** + * Checks for Imperial Guard's passive skills. + * @param sd: Player data + * @param flag: + * Flag&1 = IG_SHIELD_MASTERY + * Flag&2 = IG_SPEAR_SWORD_M + */ +uint8 pc_checkskill_imperial_guard(struct map_session_data *sd, short flag) +{ + nullpo_retr(0, sd); + + uint8 count = 0; + + if (flag&1 && sd->status.shield > 0) + count += pc_checkskill(sd, IG_SHIELD_MASTERY); + + if (flag&2 && (sd->status.weapon == W_1HSWORD || sd->status.weapon == W_1HSPEAR || sd->status.weapon == W_2HSPEAR)) + count += pc_checkskill(sd, IG_SPEAR_SWORD_M); + + return count; +} + /** * Check if we still have the correct weapon to continue the skill (actually status) * If not ending it @@ -6523,6 +6663,7 @@ static void pc_checkallowskill(struct map_session_data *sd) SC_ADRENALINE2, SC_DANCING, SC_GATLINGFEVER, + SC_DANCING_KNIFE, }; uint8 i; nullpo_retv(sd); @@ -7247,6 +7388,9 @@ const char* job_name(int class_) case JOB_SPIRIT_HANDLER: return msg_txt( nullptr, 813 - JOB_SKY_EMPEROR + class_ ); + case JOB_SKY_EMPEROR2: + return msg_txt( nullptr, 813 ); + default: return msg_txt(NULL,655); } @@ -7341,7 +7485,9 @@ int pc_checkbaselevelup(struct map_session_data *sd) { if( ( !battle_config.multi_level_up || ( battle_config.multi_level_up_base > 0 && sd->status.base_level >= battle_config.multi_level_up_base ) ) && sd->status.base_exp > next-1 ) sd->status.base_exp = next-1; - sd->status.status_point += statpoint_db.pc_gets_status_point(sd->status.base_level++); + sd->status.status_point += statpoint_db.pc_gets_status_point(sd->status.base_level); + sd->status.trait_point += statpoint_db.pc_gets_trait_point(sd->status.base_level); + sd->status.base_level++; if( pc_is_maxbaselv(sd) ){ sd->status.base_exp = u64min(sd->status.base_exp,MAX_LEVEL_BASE_EXP); @@ -7353,6 +7499,7 @@ int pc_checkbaselevelup(struct map_session_data *sd) { status_calc_pet(sd->pd,SCO_NONE); clif_updatestatus(sd,SP_STATUSPOINT); + clif_updatestatus(sd,SP_TRAITPOINT); clif_updatestatus(sd,SP_BASELEVEL); clif_updatestatus(sd,SP_BASEEXP); clif_updatestatus(sd,SP_NEXTBASEEXP); @@ -7812,7 +7959,13 @@ int pc_setstat(struct map_session_data* sd, int type, int val) * @return Total number of status points at specific base level. */ uint32 PlayerStatPointDatabase::get_table_point(uint16 level) { - return this->statpoint_table[level]; + std::shared_ptr entry = this->find( level ); + + if( entry != nullptr ){ + return entry->statpoints; + }else{ + return 0; + } } /** @@ -7822,9 +7975,46 @@ uint32 PlayerStatPointDatabase::get_table_point(uint16 level) { * @return Status points at specific base level. */ uint32 PlayerStatPointDatabase::pc_gets_status_point(uint16 level) { - if (this->statpoint_table[level+1] > this->statpoint_table[level]) - return (this->statpoint_table[level+1] - this->statpoint_table[level]); - return 0; + uint32 next_level = this->get_table_point( level + 1 ); + uint32 current_level = this->get_table_point( level ); + + if( next_level > current_level ){ + return next_level - current_level; + }else{ + return 0; + } +} + +/** +* Gets the total number of trait points at the provided level. +* @param level: Player base level. +* @return Total number of trait points at specific base level. +*/ +uint32 PlayerStatPointDatabase::get_trait_table_point(uint16 level) { + std::shared_ptr entry = this->find( level ); + + if( entry != nullptr ){ + return entry->traitpoints; + }else{ + return 0; + } +} + +/** +* Calculates the number of trait points PC gets when leveling up (from level to level+1) +* @param level: Player base level. +* @param table: Use table value or formula. +* @return Trait points at specific base level. +*/ +uint32 PlayerStatPointDatabase::pc_gets_trait_point(uint16 level) { + uint32 next_level = this->get_trait_table_point( level + 1 ); + uint32 current_level = this->get_trait_table_point( level ); + + if( next_level > current_level ){ + return next_level - current_level; + }else{ + return 0; + } } #ifdef RENEWAL_STAT @@ -7993,6 +8183,167 @@ int pc_statusup2(struct map_session_data* sd, int type, int val) return val; } +/// Returns the number of trait stat points needed to change the specified trait stat by val. +/// If val is negative, returns the number of trait stat points that would be needed to +/// raise the specified trait stat from (current value - val) to current value. +int pc_need_trait_point(struct map_session_data* sd, int type, int val) +{ + nullpo_retr(0, sd); + + if (val == 0 || type < SP_POW || type > SP_CRT) + return 0; + + int low = pc_getstat(sd, type); + int max = pc_maxparameter(sd, (e_params)(PARAM_POW + type - SP_POW)); + + if (low >= max && val > 0) + return 0; // Official servers show '0' when max is reached + + int high = low + val, sp = 0; + + if (val < 0) + SWAP(low, high); + + for (; low < high; low++) + sp += 1; + + return sp; +} + +/** +* Returns the value the specified trait stat can be increased by with the current +* amount of available trait status points for the current character's class. +* +* @param sd The target character. +* @param type Trait stat to verify. +* @return Maximum value the stat could grow by. +*/ +int pc_maxtraitparameterincrease(struct map_session_data* sd, int type) +{ + nullpo_ret(sd); + + if( type < SP_POW || type > SP_CRT ){ + return 0; + } + + int base, final_val = pc_getstat(sd, type); + int trait_points = sd->status.trait_point; + int max_param = pc_maxparameter(sd, (enum e_params)(PARAM_POW + type - SP_POW)); + + base = final_val; + + while (final_val <= max_param && trait_points >= 0) { + trait_points -= 1; + final_val++; + } + final_val--; + + return (final_val > base ? final_val - base : 0); +} + +/** +* Raises a trait stat by the specified amount. +* +* Obeys max_traitparameter limits. +* Subtracts trait status points according to the cost of the increased trait stat points. +* +* @param sd The target character. +* @param type The stat to change (see enum _sp) +* @param increase The stat increase (strictly positive) amount. +* @retval true if the trait stat was increased by any amount. +* @retval false if there were no changes. +*/ +bool pc_traitstatusup(struct map_session_data* sd, int type, int increase) +{ + nullpo_ret(sd); + + // check conditions + if (type < SP_POW || type > SP_CRT || increase <= 0) { + clif_statusupack(sd, type, 0, 0); + return false; + } + + // check limits + int current = pc_getstat(sd, type); + int max_increase = pc_maxtraitparameterincrease(sd, type); + + increase = cap_value(increase, 0, max_increase); // cap to the maximum status points available + if (increase <= 0 || current + increase > pc_maxparameter(sd, (enum e_params)(PARAM_POW + type - SP_POW))) { + clif_statusupack(sd, type, 0, 0); + return false; + } + + // check status points + int needed_points = pc_need_trait_point(sd, type, increase); + + if (needed_points < 0 || needed_points > sd->status.trait_point) { // Sanity check + clif_statusupack(sd, type, 0, 0); + return false; + } + + // set new values + int final_value = pc_setstat(sd, type, current + increase); + + sd->status.trait_point -= needed_points; + + status_calc_pc(sd, SCO_NONE); + + // update increase cost indicator + clif_updatestatus(sd, SP_UPOW + type - SP_POW); + + // update statpoint count + clif_updatestatus(sd, SP_TRAITPOINT); + + // update stat value + clif_statusupack(sd, type, 1, final_value); // required + if (final_value > 255) + clif_updatestatus(sd, type); // send after the 'ack' to override the truncated value + + //achievement_update_objective(sd, AG_GOAL_STATUS, 1, final_value); + + return true; +} + +/** +* Raises a trait stat by the specified amount. +* +* Obeys max_trait_parameter limits. +* Does not subtract status points for the cost of the modified stat points. +* +* @param sd The target character. +* @param type The stat to change (see enum _sp) +* @param val The stat increase (or decrease) amount. +* @return the stat increase amount. +* @retval 0 if no changes were made. +*/ +int pc_traitstatusup2(struct map_session_data* sd, int type, int val) +{ + nullpo_ret(sd); + + if (type < SP_POW || type > SP_CRT) { + clif_statusupack(sd, type, 0, 0); + return 0; + } + + int need = pc_need_trait_point(sd, type, 1); + int max = pc_maxparameter(sd, (enum e_params)(PARAM_POW + type - SP_POW)); // set new value + + val = pc_setstat(sd, type, cap_value(pc_getstat(sd, type) + val, 0, max)); + + status_calc_pc(sd, SCO_NONE); + + // update increase cost indicator + if (need != pc_need_trait_point(sd, type, 1)) + clif_updatestatus(sd, SP_UPOW + type - SP_POW); + + // update stat value + clif_statusupack(sd, type, 1, val); // required + if (val > 255) + clif_updatestatus(sd, type); // send after the 'ack' to override the truncated value + + return val; +} + /*========================================== * Update skill_lv for player sd * Skill point allocation @@ -8117,6 +8468,7 @@ int pc_resetlvl(struct map_session_data* sd,int type) if(type == 1){ sd->status.skill_point=0; + sd->status.trait_point = 0; sd->status.base_level=1; sd->status.job_level=1; sd->status.base_exp=0; @@ -8162,12 +8514,19 @@ int pc_resetlvl(struct map_session_data* sd,int type) } clif_updatestatus(sd,SP_STATUSPOINT); + clif_updatestatus(sd,SP_TRAITPOINT); clif_updatestatus(sd,SP_STR); clif_updatestatus(sd,SP_AGI); clif_updatestatus(sd,SP_VIT); clif_updatestatus(sd,SP_INT); clif_updatestatus(sd,SP_DEX); clif_updatestatus(sd,SP_LUK); + clif_updatestatus(sd,SP_POW); + clif_updatestatus(sd,SP_STA); + clif_updatestatus(sd,SP_WIS); + clif_updatestatus(sd,SP_SPL); + clif_updatestatus(sd,SP_CON); + clif_updatestatus(sd,SP_CRT); clif_updatestatus(sd,SP_BASELEVEL); clif_updatestatus(sd,SP_JOBLEVEL); clif_updatestatus(sd,SP_STATUSPOINT); @@ -8183,6 +8542,12 @@ int pc_resetlvl(struct map_session_data* sd,int type) clif_updatestatus(sd,SP_UINT); clif_updatestatus(sd,SP_UDEX); clif_updatestatus(sd,SP_ULUK); // End Addition + clif_updatestatus(sd,SP_UPOW); + clif_updatestatus(sd,SP_USTA); + clif_updatestatus(sd,SP_UWIS); + clif_updatestatus(sd,SP_USPL); + clif_updatestatus(sd,SP_UCON); + clif_updatestatus(sd,SP_UCRT); for(i=0;iequip_index[i] >= 0) @@ -8213,17 +8578,28 @@ int pc_resetstate(struct map_session_data* sd) } sd->status.status_point = statpoint_db.get_table_point( sd->status.base_level ); + sd->status.trait_point = statpoint_db.get_trait_table_point(sd->status.base_level); if( ( sd->class_&JOBL_UPPER ) != 0 ){ sd->status.status_point += battle_config.transcendent_status_points; } + if ((sd->class_&JOBL_FOURTH) != 0) { + sd->status.trait_point += battle_config.trait_points_job_change; + } + pc_setstat(sd, SP_STR, 1); pc_setstat(sd, SP_AGI, 1); pc_setstat(sd, SP_VIT, 1); pc_setstat(sd, SP_INT, 1); pc_setstat(sd, SP_DEX, 1); pc_setstat(sd, SP_LUK, 1); + pc_setstat(sd, SP_POW, 0); + pc_setstat(sd, SP_STA, 0); + pc_setstat(sd, SP_WIS, 0); + pc_setstat(sd, SP_SPL, 0); + pc_setstat(sd, SP_CON, 0); + pc_setstat(sd, SP_CRT, 0); clif_updatestatus(sd,SP_STR); clif_updatestatus(sd,SP_AGI); @@ -8231,6 +8607,12 @@ int pc_resetstate(struct map_session_data* sd) clif_updatestatus(sd,SP_INT); clif_updatestatus(sd,SP_DEX); clif_updatestatus(sd,SP_LUK); + clif_updatestatus(sd,SP_POW); + clif_updatestatus(sd,SP_STA); + clif_updatestatus(sd,SP_WIS); + clif_updatestatus(sd,SP_SPL); + clif_updatestatus(sd,SP_CON); + clif_updatestatus(sd,SP_CRT); clif_updatestatus(sd,SP_USTR); // Updates needed stat points - Valaris clif_updatestatus(sd,SP_UAGI); @@ -8238,8 +8620,15 @@ int pc_resetstate(struct map_session_data* sd) clif_updatestatus(sd,SP_UINT); clif_updatestatus(sd,SP_UDEX); clif_updatestatus(sd,SP_ULUK); // End Addition + clif_updatestatus(sd,SP_UPOW); + clif_updatestatus(sd,SP_USTA); + clif_updatestatus(sd,SP_UWIS); + clif_updatestatus(sd,SP_USPL); + clif_updatestatus(sd,SP_UCON); + clif_updatestatus(sd,SP_UCRT); clif_updatestatus(sd,SP_STATUSPOINT); + clif_updatestatus(sd,SP_TRAITPOINT); if( sd->mission_mobid ) { //bugreport:2200 sd->mission_mobid = 0; @@ -8451,6 +8840,10 @@ int pc_skillheal_bonus(struct map_session_data *sd, uint16 skill_id) { case AM_POTIONPITCHER: if( !(battle_config.skill_add_heal_rate&4) ) bonus = 0; break; case CR_SLIMPITCHER: if( !(battle_config.skill_add_heal_rate&8) ) bonus = 0; break; case BA_APPLEIDUN: if( !(battle_config.skill_add_heal_rate&16)) bonus = 0; break; + case AB_CHEAL: if (!(battle_config.skill_add_heal_rate & 32)) bonus = 0; break; + case AB_HIGHNESSHEAL: if (!(battle_config.skill_add_heal_rate & 64)) bonus = 0; break; + case CD_MEDIALE_VOTUM: if (!(battle_config.skill_add_heal_rate & 128)) bonus = 0; break; + case CD_DILECTIO_HEAL: if (!(battle_config.skill_add_heal_rate & 256)) bonus = 0; break; } } @@ -8507,8 +8900,9 @@ static TIMER_FUNC(pc_respawn_timer){ /*========================================== * Invoked when a player has received damage *------------------------------------------*/ -void pc_damage(struct map_session_data *sd,struct block_list *src,unsigned int hp, unsigned int sp) +void pc_damage(struct map_session_data *sd,struct block_list *src,unsigned int hp, unsigned int sp, unsigned int ap) { + if (ap) clif_updatestatus(sd,SP_AP); if (sp) clif_updatestatus(sd,SP_SP); if (hp) clif_updatestatus(sd,SP_HP); else return; @@ -8645,6 +9039,16 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) } } + for (k = 0; k < MAX_SERVANT_SIGN; k++) { + if (sd->servant_sign[k]) { + struct map_session_data *ssignsd = map_id2sd(sd->servant_sign[k]); + + if (ssignsd) + status_change_end(&ssignsd->bl, SC_SERVANT_SIGN, INVALID_TIMER); + sd->servant_sign[k] = 0; + } + } + if(sd->shadowform_id) { //if we were target of shadowform status_change_end(map_id2bl(sd->shadowform_id), SC__SHADOWFORM, INVALID_TIMER); sd->shadowform_id = 0; //should be remove on status end anyway @@ -8698,6 +9102,9 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) pc_setparam(sd, SP_PCDIECOUNTER, sd->die_counter+1); pc_setparam(sd, SP_KILLERRID, src?src->id:0); + if (battle_config.loose_ap_on_death == 1) + status_percent_damage( nullptr, &sd->bl, 0, 0, 100, 0 ); + //Reset menu skills/item skills if ((sd->skillitem) != 0) sd->skillitem = sd->skillitemlv = 0; @@ -8710,6 +9117,10 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) pc_delspiritball(sd,sd->spiritball,0); if (sd->soulball != 0) pc_delsoulball(sd, sd->soulball, false); + if (sd->servantball != 0) + pc_delservantball( *sd, sd->servantball ); + if (sd->abyssball != 0) + pc_delabyssball( *sd, sd->abyssball ); if (sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0) pc_delspiritcharm(sd,sd->spiritcharm,sd->spiritcharm_type); @@ -8943,9 +9354,10 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) return 1; } -void pc_revive(struct map_session_data *sd,unsigned int hp, unsigned int sp) { +void pc_revive(struct map_session_data *sd,unsigned int hp, unsigned int sp, unsigned int ap) { if(hp) clif_updatestatus(sd,SP_HP); if(sp) clif_updatestatus(sd,SP_SP); + if(ap) clif_updatestatus(sd,SP_AP); pc_setstand(sd, true); if(battle_config.pc_invincible_time > 0) @@ -9007,6 +9419,7 @@ int64 pc_readparam(struct map_session_data* sd,int64 type) switch(type) { case SP_SKILLPOINT: val = sd->status.skill_point; break; case SP_STATUSPOINT: val = sd->status.status_point; break; + case SP_TRAITPOINT: val = sd->status.trait_point; break; case SP_ZENY: val = sd->status.zeny; break; case SP_BASELEVEL: val = sd->status.base_level; break; case SP_JOBLEVEL: val = sd->status.job_level; break; @@ -9025,6 +9438,8 @@ int64 pc_readparam(struct map_session_data* sd,int64 type) case SP_MAXHP: val = sd->battle_status.max_hp; break; case SP_SP: val = sd->battle_status.sp; break; case SP_MAXSP: val = sd->battle_status.max_sp; break; + case SP_AP: val = sd->battle_status.ap; break; + case SP_MAXAP: val = sd->battle_status.max_ap; break; case SP_STR: val = sd->status.str; break; case SP_AGI: val = sd->status.agi; break; case SP_VIT: val = sd->status.vit; break; @@ -9072,9 +9487,16 @@ int64 pc_readparam(struct map_session_data* sd,int64 type) case SP_HIT: val = sd->battle_status.hit; break; case SP_FLEE1: val = sd->battle_status.flee; break; case SP_FLEE2: val = sd->battle_status.flee2; break; + case SP_PATK: val = sd->battle_status.patk; break; + case SP_SMATK: val = sd->battle_status.smatk; break; + case SP_RES: val = sd->battle_status.res; break; + case SP_MRES: val = sd->battle_status.mres; break; + case SP_HPLUS: val = sd->battle_status.hplus; break; + case SP_CRATE: val = sd->battle_status.crate; break; case SP_DEFELE: val = sd->battle_status.def_ele; break; case SP_MAXHPRATE: val = sd->hprate; break; case SP_MAXSPRATE: val = sd->sprate; break; + case SP_MAXAPRATE: val = sd->aprate; break; case SP_SPRATE: val = sd->dsprate; break; case SP_SPEED_RATE: val = sd->bonus.speed_rate; break; case SP_SPEED_ADDRATE: val = sd->bonus.speed_add_rate; break; @@ -9106,6 +9528,12 @@ int64 pc_readparam(struct map_session_data* sd,int64 type) case SP_DEF2_RATE: val = sd->def2_rate; break; case SP_MDEF_RATE: val = sd->mdef_rate; break; case SP_MDEF2_RATE: val = sd->mdef2_rate; break; + case SP_PATK_RATE: val = sd->patk_rate; break; + case SP_SMATK_RATE: val = sd->smatk_rate; break; + case SP_RES_RATE: val = sd->res_rate; break; + case SP_MRES_RATE: val = sd->mres_rate; break; + case SP_HPLUS_RATE: val = sd->hplus_rate; break; + case SP_CRATE_RATE: val = sd->crate_rate; break; case SP_RESTART_FULL_RECOVER: val = sd->special_state.restart_full_recover?1:0; break; case SP_NO_CASTCANCEL: val = sd->special_state.no_castcancel?1:0; break; case SP_NO_CASTCANCEL2: val = sd->special_state.no_castcancel2?1:0; break; @@ -9191,17 +9619,17 @@ bool pc_setparam(struct map_session_data *sd,int64 type,int64 val_tmp) if (val > pc_maxbaselv(sd)) //Capping to max val = pc_maxbaselv(sd); if (val > sd->status.base_level) { - int i = 0; - int stat=0; - for (i = 0; i < (int)(val - sd->status.base_level); i++) - stat += statpoint_db.pc_gets_status_point(sd->status.base_level + i); - sd->status.status_point += stat; + for( int i = 0; i < (int)( val - sd->status.base_level ); i++ ){ + sd->status.status_point += statpoint_db.pc_gets_status_point( sd->status.base_level + i ); + sd->status.trait_point += statpoint_db.pc_gets_trait_point( sd->status.base_level + i ); + } } sd->status.base_level = val; sd->status.base_exp = 0; // clif_updatestatus(sd, SP_BASELEVEL); // Gets updated at the bottom clif_updatestatus(sd, SP_NEXTBASEEXP); clif_updatestatus(sd, SP_STATUSPOINT); + clif_updatestatus(sd, SP_TRAITPOINT); clif_updatestatus(sd, SP_BASEEXP); status_calc_pc(sd, SCO_FORCE); if(sd->status.party_id) @@ -9226,6 +9654,9 @@ bool pc_setparam(struct map_session_data *sd,int64 type,int64 val_tmp) case SP_STATUSPOINT: sd->status.status_point = val; break; + case SP_TRAITPOINT: + sd->status.trait_point = val; + break; case SP_ZENY: if( val < 0 ) return false;// can't set negative zeny @@ -9284,6 +9715,17 @@ bool pc_setparam(struct map_session_data *sd,int64 type,int64 val_tmp) clif_updatestatus(sd, SP_SP); } break; + case SP_AP: + sd->battle_status.ap = cap_value(val, 0, (int)sd->battle_status.max_ap); + break; + case SP_MAXAP: + sd->battle_status.max_ap = cap_value(val, 1, battle_config.max_ap); + + if (sd->battle_status.max_ap < sd->battle_status.ap) { + sd->battle_status.ap = sd->battle_status.max_ap; + clif_updatestatus(sd, SP_AP); + } + break; case SP_STR: sd->status.str = cap_value(val, 1, pc_maxparameter(sd,PARAM_STR)); break; @@ -9418,20 +9860,24 @@ bool pc_setparam(struct map_session_data *sd,int64 type,int64 val_tmp) } /*========================================== - * HP/SP Healing. If flag is passed, the heal type is through clif_heal, otherwise update status. + * HP/SP/AP Healing. If flag is passed, the heal type is through clif_heal, otherwise update status. *------------------------------------------*/ -void pc_heal(struct map_session_data *sd,unsigned int hp,unsigned int sp, int type) -{ +void pc_heal(struct map_session_data *sd,unsigned int hp,unsigned int sp, unsigned int ap, int type) +{// Is there going to be a effect for gaining AP soon??? [Rytech] if (type&2) { if (hp || type&4) clif_heal(sd->fd,SP_HP,hp); if (sp) clif_heal(sd->fd,SP_SP,sp); + if (ap) + clif_heal(sd->fd,SP_AP,ap); } else { if(hp) clif_updatestatus(sd,SP_HP); if(sp) clif_updatestatus(sd,SP_SP); + if (ap) + clif_updatestatus(sd,SP_AP); } return; } @@ -9642,6 +10088,11 @@ bool pc_jobchange(struct map_session_data *sd,int job, char upper) sd->change_level_3rd = sd->status.job_level; pc_setglobalreg(sd, add_str(JOBCHANGE3RD_VAR), sd->change_level_3rd); } + // changing from 3rd to 4th job + else if ((b_class&JOBL_FOURTH) && !(sd->class_&JOBL_FOURTH)) { + sd->change_level_4th = sd->status.job_level; + pc_setglobalreg(sd, add_str(JOBCHANGE4TH_VAR), sd->change_level_4th); + } if(sd->cloneskill_idx > 0) { if( sd->status.skill[sd->cloneskill_idx].flag == SKILL_FLAG_PLAGIARIZED ) { @@ -9667,20 +10118,6 @@ bool pc_jobchange(struct map_session_data *sd,int job, char upper) pc_setglobalreg(sd, add_str(SKILL_VAR_REPRODUCE_LV), 0); } - // Give or reduce transcendent status points - if( (b_class&JOBL_UPPER) && !(sd->class_&JOBL_UPPER) ){ // Change from a non t class to a t class -> give points - sd->status.status_point += battle_config.transcendent_status_points; - clif_updatestatus(sd,SP_STATUSPOINT); - }else if( !(b_class&JOBL_UPPER) && (sd->class_&JOBL_UPPER) ){ // Change from a t class to a non t class -> remove points - if( sd->status.status_point < battle_config.transcendent_status_points ){ - // The player already used his bonus points, so we have to reset his status points - pc_resetstate(sd); - }else{ - sd->status.status_point -= battle_config.transcendent_status_points; - clif_updatestatus(sd,SP_STATUSPOINT); - } - } - if ( (b_class&MAPID_UPPERMASK) != (sd->class_&MAPID_UPPERMASK) ) { //Things to remove when changing class tree. std::shared_ptr tree = skill_tree_db.find(sd->status.class_); @@ -9707,6 +10144,7 @@ bool pc_jobchange(struct map_session_data *sd,int job, char upper) sd->status.class_ = job; fame_flag = pc_famerank(sd->status.char_id,sd->class_&MAPID_UPPERMASK); + uint64 previous_class = sd->class_; sd->class_ = (unsigned short)b_class; sd->status.job_level=1; sd->status.job_exp=0; @@ -9716,11 +10154,52 @@ bool pc_jobchange(struct map_session_data *sd,int job, char upper) sd->status.base_exp=0; pc_resetstate(sd); clif_updatestatus(sd,SP_STATUSPOINT); + clif_updatestatus(sd,SP_TRAITPOINT); clif_updatestatus(sd,SP_BASELEVEL); clif_updatestatus(sd,SP_BASEEXP); clif_updatestatus(sd,SP_NEXTBASEEXP); } + // Give or reduce transcendent status points + if( (b_class&JOBL_UPPER) && !(previous_class&JOBL_UPPER) ){ // Change from a non t class to a t class -> give points + sd->status.status_point += battle_config.transcendent_status_points; + clif_updatestatus(sd,SP_STATUSPOINT); + }else if( !(b_class&JOBL_UPPER) && (previous_class&JOBL_UPPER) ){ // Change from a t class to a non t class -> remove points + if( sd->status.status_point < battle_config.transcendent_status_points ){ + // The player already used his bonus points, so we have to reset his status points + pc_resetstate(sd); + }else{ + sd->status.status_point -= battle_config.transcendent_status_points; + clif_updatestatus(sd,SP_STATUSPOINT); + } + } + + // Give or reduce trait status points + if ((b_class & JOBL_FOURTH) && !(previous_class & JOBL_FOURTH)) {// Change to a 4th job. + sd->status.trait_point += battle_config.trait_points_job_change; + clif_updatestatus(sd, SP_TRAITPOINT); + clif_updatestatus(sd, SP_UPOW); + clif_updatestatus(sd, SP_USTA); + clif_updatestatus(sd, SP_UWIS); + clif_updatestatus(sd, SP_USPL); + clif_updatestatus(sd, SP_UCON); + clif_updatestatus(sd, SP_UCRT); + } else if (!(b_class & JOBL_FOURTH) && (previous_class & JOBL_FOURTH)) {// Change to a non 4th job. + if (sd->status.trait_point < battle_config.trait_points_job_change) { + // Player may have already used the trait status points. Force a reset. + pc_resetstate(sd); + } else { + sd->status.trait_point = 0; + clif_updatestatus(sd, SP_TRAITPOINT); + clif_updatestatus(sd, SP_UPOW); + clif_updatestatus(sd, SP_USTA); + clif_updatestatus(sd, SP_UWIS); + clif_updatestatus(sd, SP_USPL); + clif_updatestatus(sd, SP_UCON); + clif_updatestatus(sd, SP_UCRT); + } + } + clif_updatestatus(sd,SP_JOBLEVEL); clif_updatestatus(sd,SP_JOBEXP); clif_updatestatus(sd,SP_NEXTJOBEXP); @@ -12487,7 +12966,7 @@ static unsigned int pc_calc_basehp(uint16 level, uint16 job_id) { #endif for (uint16 i = 2; i <= level; i++) base_hp += floor(((job->hp_factor / 100.) * i) + 0.5); //Don't have round() - if (job_id == JOB_SUMMONER) + if (job_id == JOB_SUMMONER || job_id == JOB_SPIRIT_HANDLER) base_hp += floor((base_hp / 2) + 0.5); return (unsigned int)base_hp; } @@ -12517,6 +12996,7 @@ static unsigned int pc_calc_basesp(uint16 level, uint16 job_id) { base_sp = 9 + 3*level; break; case JOB_SUMMONER: + case JOB_SPIRIT_HANDLER: base_sp -= floor(base_sp / 2); break; } @@ -12995,7 +13475,7 @@ void JobDatabase::loadingFinished() { // Set trait status limit if( class_ & JOBL_FOURTH ){ - max = battle_config.max_fourth_trait; + max = battle_config.max_trait_parameter; }else{ max = 0; } @@ -13072,7 +13552,32 @@ uint64 PlayerStatPointDatabase::parseBodyNode(const YAML::Node &node) { return 0; } - this->statpoint_table[level] = point; + std::shared_ptr entry = this->find( level ); + bool exists = entry != nullptr; + + if( !exists ){ + entry = std::make_shared(); + entry->level = level; + entry->statpoints = point; + } + + if( this->nodeExists( node, "TraitPoints" ) ){ + uint32 traitpoints; + + if( !this->asUInt32( node, "TraitPoints", traitpoints ) ){ + return 0; + } + + entry->traitpoints = traitpoints; + }else{ + if( !exists ){ + entry->traitpoints = 0; + } + } + + if( !exists ){ + this->put( level, entry ); + } return 1; } @@ -13080,22 +13585,69 @@ uint64 PlayerStatPointDatabase::parseBodyNode(const YAML::Node &node) { /** * Generate the remaining parts of the db if necessary. */ -void PlayerStatPointDatabase::loadingFinished() { - if( battle_config.use_statpoint_table ){ - this->statpoint_table[1] = start_status_points; - } +void PlayerStatPointDatabase::loadingFinished(){ + const uint16 trait_start_level = 200; + std::shared_ptr level_one = this->find( 1 ); - if( this->statpoint_table[1] != start_status_points ){ - ShowError( "Status points for Level 1 (=%d) do not match inter_athena.conf value (=%d).\n", this->statpoint_table[1], start_status_points ); - this->statpoint_table[1] = start_status_points; - } - - for (uint16 level = 2; level <= MAX_LEVEL; level++) { - if (!battle_config.use_statpoint_table || util::umap_find(this->statpoint_table, level) == nullptr) { - if (battle_config.use_statpoint_table) - ShowError("Missing status points for Level %d\n", level); - this->statpoint_table[level] = this->statpoint_table[level-1] + ((level-1+15) / 5); + if( level_one == nullptr ){ + if( battle_config.use_statpoint_table ){ + ShowError( "Missing status points for Level 1\n" ); } + + level_one = std::make_shared(); + + level_one->level = 1; + level_one->statpoints = start_status_points; + level_one->traitpoints = 0; + + this->put( 1, level_one ); + }else if( battle_config.use_statpoint_table ){ + if( level_one->statpoints != start_status_points ){ + ShowError( "Status points for Level 1 (=%u) do not match inter_athena.conf value (=%u).\n", level_one->statpoints, start_status_points ); + level_one->statpoints = start_status_points; + } + }else{ + level_one->statpoints = start_status_points; + level_one->traitpoints = 0; + } + + std::shared_ptr last_level = level_one; + for( uint16 level = 2; level <= MAX_LEVEL; level++ ){ + std::shared_ptr entry = this->find( level ); + bool exists = entry != nullptr; + + if( !exists ){ + entry = std::make_shared(); + entry->level = level; + this->put( level, entry ); + } + + if( !battle_config.use_statpoint_table || !exists ){ + if( battle_config.use_statpoint_table ){ + ShowError("Missing status points for Level %hu\n", level); + } + + if( level <= trait_start_level ){ + entry->statpoints = last_level->statpoints + ( ( level - 1 + 15 ) / 5 ); + }else{ + entry->statpoints = last_level->statpoints; + } + } + + if( !battle_config.use_traitpoint_table || !exists ){ + if( battle_config.use_traitpoint_table && level > trait_start_level ){ + ShowError( "Missing trait points for Level %hu\n", level ); + } + + if( level > trait_start_level ){ + entry->traitpoints = ( level - trait_start_level ) * 3 + ( level - trait_start_level ) / 5 * 4; + }else{ + entry->traitpoints = 0; + } + } + + // Store it for next iteration + last_level = entry; } } diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 91584a2c1e..982e9f3927 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -40,6 +40,9 @@ enum sc_type : int16; #define MAX_SOUL_BALL 20 /// Max soul ball #define MAX_STELLAR_MARKS 5 /// Max stellar marks #define MAX_UNITED_SOULS 12 /// Max united souls +#define MAX_SERVANTBALL 5 /// Max servant weapons +#define MAX_SERVANT_SIGN 5 /// Max servant signs +#define MAX_ABYSSBALL 5 /// Max abyss spheres #define LANGTYPE_VAR "#langtype" #define CASHPOINT_VAR "#CASHPOINTS" @@ -52,6 +55,7 @@ enum sc_type : int16; #define PCDIECOUNTER_VAR "PC_DIE_COUNTER" #define JOBCHANGE2ND_VAR "jobchange_level" #define JOBCHANGE3RD_VAR "jobchange_level_3rd" +#define JOBCHANGE4TH_VAR "jobchange_level_4th" #define TKMISSIONID_VAR "TK_MISSION_ID" #define TKMISSIONCOUNT_VAR "TK_MISSION_COUNT" #define ATTENDANCE_DATE_VAR "#AttendanceDate" @@ -449,6 +453,7 @@ struct map_session_data { bool skillitem_keep_requirement; uint16 skill_id_old,skill_lv_old; uint16 skill_id_dance,skill_lv_dance; + uint16 skill_id_song, skill_lv_song; short cook_mastery; // range: [0,1999] [Inkfish] struct skill_cooldown_entry * scd[MAX_SKILLCOOLDOWN]; // Skill Cooldown uint16 cloneskill_idx, ///Stores index of copied skill by Intimidate/Plagiarism @@ -503,6 +508,7 @@ struct map_session_data { int magic_addclass[CLASS_MAX]; int magic_addsize[SZ_MAX]; int magic_atk_ele[ELE_MAX]; + int weapon_subsize[SZ_MAX]; int magic_subsize[SZ_MAX]; int critaddrace[RC_MAX]; int expaddrace[RC_MAX]; @@ -549,7 +555,7 @@ struct map_session_data { // zeroed vars start here. struct s_bonus { - int hp, sp; + int hp, sp, ap; int atk_rate; int arrow_atk,arrow_ele,arrow_cri,arrow_hit; int nsshealhp,nsshealsp; @@ -594,10 +600,11 @@ struct map_session_data { } bonus; // zeroed vars end here. - int castrate,hprate,sprate,dsprate; + int castrate,hprate,sprate,aprate,dsprate; int hprecov_rate,sprecov_rate; int matk_rate; int critical_rate,hit_rate,flee_rate,flee2_rate,def_rate,def2_rate,mdef_rate,mdef2_rate; + int patk_rate,smatk_rate,res_rate,mres_rate,hplus_rate,crate_rate; t_itemid itemid; short itemindex; //Used item's index in sd->inventory [Skotlex] @@ -610,6 +617,8 @@ struct map_session_data { int spiritcharm_type; //Spirit type int spiritcharm_timer[MAX_SPIRITCHARM]; int8 soulball, soulball_old; + int8 servantball, servantball_old; + int8 abyssball, abyssball_old; unsigned char potion_success_counter; //Potion successes in row counter unsigned char mission_count; //Stores the bounty kill count for TK_MISSION @@ -618,6 +627,7 @@ struct map_session_data { int devotion[MAX_DEVOTION]; //Stores the account IDs of chars devoted to. int stellar_mark[MAX_STELLAR_MARKS]; // Stores the account ID's of character's with a stellar mark. int united_soul[MAX_UNITED_SOULS]; // Stores the account ID's of character's who's soul is united. + int servant_sign[MAX_SERVANT_SIGN]; // Stores the account ID's of character's with a servant sign. int trade_partner; struct s_deal { @@ -676,6 +686,7 @@ struct map_session_data { uint16 change_level_2nd; // job level when changing from 1st to 2nd class [jobchange_level in global_reg_value] uint16 change_level_3rd; // job level when changing from 2nd to 3rd class [jobchange_level_3rd in global_reg_value] + uint16 change_level_4th; // job level when changing from 3rd to 4th class [jobchange_level_4rd in global_reg_value] char fakename[NAME_LENGTH]; // fake names [Valaris] @@ -1110,7 +1121,8 @@ enum e_mado_type : uint16 { ( (class_) >= JOB_BABY_STAR_GLADIATOR2 && (class_) <= JOB_BABY_STAR_EMPEROR2 ) || \ ( (class_) >= JOB_DRAGON_KNIGHT && (class_) <= JOB_TROUVERE ) || \ ( (class_) >= JOB_WINDHAWK2 && (class_) <= JOB_IMPERIAL_GUARD2 ) || \ - ( (class_) >= JOB_SKY_EMPEROR && (class_) <= JOB_SPIRIT_HANDLER ) \ + ( (class_) >= JOB_SKY_EMPEROR && (class_) <= JOB_SPIRIT_HANDLER ) || \ + (class_) == JOB_SKY_EMPEROR2 \ ) #define pcdb_checkid(class_) pcdb_checkid_sub((unsigned int)class_) @@ -1168,24 +1180,26 @@ public: extern AttendanceDatabase attendance_db; -class PlayerStatPointDatabase : public YamlDatabase { -private: - std::unordered_map statpoint_table; +struct s_statpoint_entry{ + uint16 level; + uint32 statpoints; + uint32 traitpoints; +}; +class PlayerStatPointDatabase : public TypesafeCachedYamlDatabase{ public: - PlayerStatPointDatabase() : YamlDatabase("STATPOINT_DB", 1) { + PlayerStatPointDatabase() : TypesafeCachedYamlDatabase("STATPOINT_DB", 2, 1) { } - void clear(){ - statpoint_table.clear(); - } const std::string getDefaultLocation(); uint64 parseBodyNode(const YAML::Node& node); void loadingFinished(); uint32 pc_gets_status_point(uint16 level); uint32 get_table_point(uint16 level); + uint32 pc_gets_trait_point(uint16 level); + uint32 get_trait_table_point(uint16 level); }; extern PlayerStatPointDatabase statpoint_db; @@ -1229,6 +1243,7 @@ void pc_setinventorydata(struct map_session_data *sd); int pc_get_skillcooldown(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv); uint8 pc_checkskill(struct map_session_data *sd,uint16 skill_id); uint8 pc_checkskill_summoner(map_session_data *sd, e_summoner_power_type type); +uint8 pc_checkskill_imperial_guard(struct map_session_data *sd, short flag); short pc_checkequip(struct map_session_data *sd,int pos,bool checkall=false); bool pc_checkequip2(struct map_session_data *sd, t_itemid nameid, int min, int max); @@ -1339,6 +1354,10 @@ bool pc_statusup(struct map_session_data*,int,int); int pc_statusup2(struct map_session_data*,int,int); int pc_getstat(map_session_data *sd, int type); int pc_setstat(struct map_session_data* sd, int type, int val); +int pc_need_trait_point(struct map_session_data *, int, int); +int pc_maxtraitparameterincrease(struct map_session_data*, int); +bool pc_traitstatusup(struct map_session_data*, int, int); +int pc_traitstatusup2(struct map_session_data*, int, int); void pc_skillup(struct map_session_data*,uint16 skill_id); int pc_allskillup(struct map_session_data*); int pc_resetlvl(struct map_session_data*,int type); @@ -1359,11 +1378,11 @@ int pc_sub_skillatk_bonus(struct map_session_data *sd, uint16 skill_id); int pc_skillheal_bonus(struct map_session_data *sd, uint16 skill_id); int pc_skillheal2_bonus(struct map_session_data *sd, uint16 skill_id); -void pc_damage(struct map_session_data *sd,struct block_list *src,unsigned int hp, unsigned int sp); +void pc_damage(struct map_session_data *sd,struct block_list *src,unsigned int hp, unsigned int sp, unsigned int ap); int pc_dead(struct map_session_data *sd,struct block_list *src); -void pc_revive(struct map_session_data *sd,unsigned int hp, unsigned int sp); +void pc_revive(struct map_session_data *sd,unsigned int hp, unsigned int sp, unsigned int ap = 0); bool pc_revive_item(struct map_session_data *sd); -void pc_heal(struct map_session_data *sd,unsigned int hp,unsigned int sp, int type); +void pc_heal(struct map_session_data *sd,unsigned int hp,unsigned int sp, unsigned int ap, int type); int pc_itemheal(struct map_session_data *sd, t_itemid itemid, int hp,int sp); int pc_percentheal(struct map_session_data *sd,int,int); bool pc_jobchange(struct map_session_data *sd, int job, char upper); @@ -1479,6 +1498,10 @@ void pc_addspiritball(struct map_session_data *sd,int interval,int max); void pc_delspiritball(struct map_session_data *sd,int count,int type); int pc_addsoulball(map_session_data *sd, int max); int pc_delsoulball(map_session_data *sd, int count, bool type); +void pc_addservantball( struct map_session_data& sd, int count = 1 ); +void pc_delservantball( struct map_session_data& sd, int count = 1 ); +void pc_addabyssball( struct map_session_data& sd, int count = 1 ); +void pc_delabyssball( struct map_session_data& sd, int count = 1 ); void pc_addfame(struct map_session_data *sd,int count); unsigned char pc_famerank(uint32 char_id, int job); diff --git a/src/map/script.cpp b/src/map/script.cpp index 3fb0ce159a..e45e3b1c7e 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -9583,6 +9583,50 @@ BUILDIN_FUNC(statusup2) return SCRIPT_CMD_SUCCESS; } +/** +* traitstatusup {,}; +**/ +BUILDIN_FUNC(traitstatusup) +{ + struct map_session_data *sd; + + if (!script_charid2sd(3, sd)) + return SCRIPT_CMD_FAILURE; + + int type = script_getnum( st, 2 ); + + if( type < SP_POW || type > SP_CRT ){ + ShowError( "buildin_traitstatusup: Unknown trait type %d\n", type ); + return SCRIPT_CMD_FAILURE; + } + + pc_traitstatusup( sd, type, 1 ); + + return SCRIPT_CMD_SUCCESS; +} + +/** +* traitstatusup2 ,{,}; +**/ +BUILDIN_FUNC(traitstatusup2) +{ + struct map_session_data *sd; + + if (!script_charid2sd(4, sd)) + return SCRIPT_CMD_FAILURE; + + int type = script_getnum( st, 2 ); + + if( type < SP_POW || type > SP_CRT ){ + ShowError( "buildin_traitstatusup2: Unknown trait type %d\n", type ); + return SCRIPT_CMD_FAILURE; + } + + pc_traitstatusup2( sd, type, script_getnum( st, 3 ) ); + + return SCRIPT_CMD_SUCCESS; +} + /// See 'doc/item_bonus.txt' /// /// bonus ,; @@ -17842,6 +17886,8 @@ BUILDIN_FUNC(getmonsterinfo) case MOB_ATK2: script_pushint(st,mob->status.rhw.atk2); break; case MOB_DEF: script_pushint(st,mob->status.def); break; case MOB_MDEF: script_pushint(st,mob->status.mdef); break; + case MOB_RES: script_pushint(st, mob->status.res); break; + case MOB_MRES: script_pushint(st, mob->status.mres); break; case MOB_STR: script_pushint(st,mob->status.str); break; case MOB_AGI: script_pushint(st,mob->status.agi); break; case MOB_VIT: script_pushint(st,mob->status.vit); break; @@ -18267,6 +18313,8 @@ BUILDIN_FUNC(getunitdata) getunitdata_sub(UMOB_BODY2, md->vd->body_style); getunitdata_sub(UMOB_GROUP_ID, md->ud.group_id); getunitdata_sub(UMOB_IGNORE_CELL_STACK_LIMIT, md->ud.state.ignore_cell_stack_limit); + getunitdata_sub(UMOB_RES, md->status.res); + getunitdata_sub(UMOB_MRES, md->status.mres); break; case BL_HOM: @@ -18672,6 +18720,8 @@ BUILDIN_FUNC(setunitdata) case UMOB_BODY2: clif_changelook(bl, LOOK_BODY2, (unsigned short)value); break; case UMOB_GROUP_ID: md->ud.group_id = value; unit_refresh(bl); break; case UMOB_IGNORE_CELL_STACK_LIMIT: md->ud.state.ignore_cell_stack_limit = value > 0; break; + case UMOB_RES: md->base_status->res = (short)value; calc_status = true; break; + case UMOB_MRES: md->base_status->mres = (short)value; calc_status = true; break; default: ShowError("buildin_setunitdata: Unknown data identifier %d for BL_MOB.\n", type); return SCRIPT_CMD_FAILURE; @@ -23863,6 +23913,28 @@ BUILDIN_FUNC(needed_status_point) { return SCRIPT_CMD_SUCCESS; } +/// Returns the number of trait stat points needed to change the specified trait stat by val. +/// If val is negative, returns the number of trait stat points that would be needed to +/// raise the specified trait stat from (current value - val) to current value. +/// *needed_trait_point(,{,}); +BUILDIN_FUNC(needed_trait_point) { + struct map_session_data *sd; + + if (!script_charid2sd(4, sd)) + return SCRIPT_CMD_FAILURE; + + int type = script_getnum( st, 2 ); + + if( type < SP_POW || type > SP_CRT ){ + ShowError( "buildin_needed_trait_point: Unknown trait type %d\n", type ); + return SCRIPT_CMD_FAILURE; + } + + script_pushint( st, pc_need_trait_point( sd, type, script_getnum( st, 3 ) ) ); + + return SCRIPT_CMD_SUCCESS; +} + /** * jobcanentermap(""{,}); * Check if (player with) JobID can enter the map. @@ -25664,6 +25736,8 @@ struct script_function buildin_func[] = { BUILDIN_DEF(downrefitem,"i??"), BUILDIN_DEF(statusup,"i?"), BUILDIN_DEF(statusup2,"ii?"), + BUILDIN_DEF(traitstatusup,"i?"), + BUILDIN_DEF(traitstatusup2,"ii?"), BUILDIN_DEF(bonus,"i?"), BUILDIN_DEF2(bonus,"bonus2","ivi"), BUILDIN_DEF2(bonus,"bonus3","ivii"), @@ -26146,6 +26220,7 @@ struct script_function buildin_func[] = { BUILDIN_DEF(getequiprandomoption, "iii?"), BUILDIN_DEF(setrandomoption,"iiiii?"), BUILDIN_DEF(needed_status_point,"ii?"), + BUILDIN_DEF(needed_trait_point, "ii?"), BUILDIN_DEF(jobcanentermap,"s?"), BUILDIN_DEF(openstorage2,"ii?"), BUILDIN_DEF(unloadnpc, "s"), diff --git a/src/map/script.hpp b/src/map/script.hpp index 0f9bc24f3d..72cabbe231 100644 --- a/src/map/script.hpp +++ b/src/map/script.hpp @@ -356,6 +356,8 @@ enum monsterinfo_types { MOB_ATK2, MOB_DEF, MOB_MDEF, + MOB_RES, + MOB_MRES, MOB_STR, MOB_AGI, MOB_VIT, @@ -481,6 +483,8 @@ enum unitdata_mobtypes { UMOB_BODY2, UMOB_GROUP_ID, UMOB_IGNORE_CELL_STACK_LIMIT, + UMOB_RES, + UMOB_MRES, }; enum unitdata_homuntypes { diff --git a/src/map/script_constants.hpp b/src/map/script_constants.hpp index d2744e2acc..f1ea429fcb 100644 --- a/src/map/script_constants.hpp +++ b/src/map/script_constants.hpp @@ -256,6 +256,8 @@ export_constant(JOB_HYPER_NOVICE); export_constant(JOB_SPIRIT_HANDLER); + export_constant(JOB_SKY_EMPEROR2); + /* EA jobs */ export_constant2("EAJL_2_1",JOBL_2_1); export_constant2("EAJL_2_2",JOBL_2_2); @@ -263,10 +265,12 @@ export_constant2("EAJL_UPPER",JOBL_UPPER); export_constant2("EAJL_BABY",JOBL_BABY); export_constant2("EAJL_THIRD",JOBL_THIRD); + export_constant2("EAJL_FOURTH",JOBL_FOURTH); export_constant2("EAJ_BASEMASK",MAPID_BASEMASK); export_constant2("EAJ_UPPERMASK",MAPID_UPPERMASK); export_constant2("EAJ_THIRDMASK",MAPID_THIRDMASK); + export_constant2("EAJ_FOURTHMASK",MAPID_FOURTHMASK); export_constant2("EAJ_NOVICE",MAPID_NOVICE); export_constant2("EAJ_SWORDMAN",MAPID_SWORDMAN); @@ -603,6 +607,7 @@ export_constant2("bMaxHP",SP_MAXHP); export_constant2("bMaxSP",SP_MAXSP); + export_constant2("bMaxAP",SP_MAXAP); export_constant2("bStr",SP_STR); export_constant2("bAgi",SP_AGI); export_constant2("bVit",SP_VIT); @@ -696,6 +701,12 @@ export_constant2("bDef2Rate",SP_DEF2_RATE); export_constant2("bMdefRate",SP_MDEF_RATE); export_constant2("bMdef2Rate",SP_MDEF2_RATE); + export_constant2("bPAtkRate", SP_PATK_RATE); + export_constant2("bSMatkRate", SP_SMATK_RATE); + export_constant2("bResRate", SP_RES_RATE); + export_constant2("bMResRate", SP_MRES_RATE); + export_constant2("bHPlusRate", SP_HPLUS_RATE); + export_constant2("bCRateRate", SP_CRATE_RATE); export_constant2("bSplashRange",SP_SPLASH_RANGE); export_constant2("bSplashAddRange",SP_SPLASH_ADD_RANGE); export_constant2("bAutoSpell",SP_AUTOSPELL); @@ -711,6 +722,7 @@ export_constant2("bAddStealRate",SP_ADD_STEAL_RATE); export_constant2("bMagicDamageReturn",SP_MAGIC_DAMAGE_RETURN); export_constant2("bAllStats",SP_ALL_STATS); + export_constant2("bAllTraitStats", SP_ALL_TRAIT_STATS); export_constant2("bAgiVit",SP_AGI_VIT); export_constant2("bAgiDexStr",SP_AGI_DEX_STR); export_constant2("bPerfectHide",SP_PERFECT_HIDE); @@ -1698,6 +1710,119 @@ export_constant(SC_WIDEWEB); export_constant(SC_BURNT); export_constant(SC_CHILL); + export_constant(SC_HANDICAPSTATE_DEEPBLIND); + export_constant(SC_HANDICAPSTATE_DEEPSILENCE); + export_constant(SC_HANDICAPSTATE_LASSITUDE); + export_constant(SC_HANDICAPSTATE_FROSTBITE); + export_constant(SC_HANDICAPSTATE_SWOONING); + export_constant(SC_HANDICAPSTATE_LIGHTNINGSTRIKE); + export_constant(SC_HANDICAPSTATE_CRYSTALLIZATION); + export_constant(SC_HANDICAPSTATE_CONFLAGRATION); + export_constant(SC_HANDICAPSTATE_MISFORTUNE); + export_constant(SC_HANDICAPSTATE_DEADLYPOISON); + export_constant(SC_HANDICAPSTATE_DEPRESSION); + export_constant(SC_HANDICAPSTATE_HOLYFLAME); + export_constant(SC_SERVANTWEAPON); + export_constant(SC_SERVANT_SIGN); + export_constant(SC_CHARGINGPIERCE); + export_constant(SC_CHARGINGPIERCE_COUNT); + export_constant(SC_DRAGONIC_AURA); + export_constant(SC_VIGOR); + export_constant(SC_DEADLY_DEFEASANCE); + export_constant(SC_CLIMAX_DES_HU); + export_constant(SC_CLIMAX); + export_constant(SC_CLIMAX_EARTH); + export_constant(SC_CLIMAX_BLOOM); + export_constant(SC_CLIMAX_CRYIMP); + export_constant(SC_WINDSIGN); + export_constant(SC_CRESCIVEBOLT); + export_constant(SC_CALAMITYGALE); + export_constant(SC_MEDIALE); + export_constant(SC_A_VITA); + export_constant(SC_A_TELUM); + export_constant(SC_PRE_ACIES); + export_constant(SC_COMPETENTIA); + export_constant(SC_RELIGIO); + export_constant(SC_BENEDICTUM); + export_constant(SC_AXE_STOMP); + export_constant(SC_A_MACHINE); + export_constant(SC_D_MACHINE); + export_constant(SC_ABR_BATTLE_WARIOR); + export_constant(SC_ABR_DUAL_CANNON); + export_constant(SC_ABR_MOTHER_NET); + export_constant(SC_ABR_INFINITY); + export_constant(SC_SHADOW_EXCEED); + export_constant(SC_DANCING_KNIFE); + export_constant(SC_POTENT_VENOM); + export_constant(SC_SHADOW_SCAR); + export_constant(SC_E_SLASH_COUNT); + export_constant(SC_SHADOW_WEAPON); + export_constant(SC_GUARD_STANCE); + export_constant(SC_ATTACK_STANCE); + export_constant(SC_GUARDIAN_S); + export_constant(SC_REBOUND_S); + export_constant(SC_HOLY_S); + export_constant(SC_ULTIMATE_S); + export_constant(SC_SPEAR_SCAR); + export_constant(SC_SHIELD_POWER); + export_constant(SC_SPELL_ENCHANTING); + export_constant(SC_SUMMON_ELEMENTAL_ARDOR); + export_constant(SC_SUMMON_ELEMENTAL_DILUVIO); + export_constant(SC_SUMMON_ELEMENTAL_PROCELLA); + export_constant(SC_SUMMON_ELEMENTAL_TERREMOTUS); + export_constant(SC_SUMMON_ELEMENTAL_SERPENS); + export_constant(SC_ELEMENTAL_VEIL); + export_constant(SC_MYSTIC_SYMPHONY); + export_constant(SC_KVASIR_SONATA); + export_constant(SC_SOUNDBLEND); + export_constant(SC_GEF_NOCTURN); + export_constant(SC_AIN_RHAPSODY); + export_constant(SC_MUSICAL_INTERLUDE); + export_constant(SC_JAWAII_SERENADE); + export_constant(SC_PRON_MARCH); + export_constant(SC_ROSEBLOSSOM); + export_constant(SC_POWERFUL_FAITH); + export_constant(SC_SINCERE_FAITH); + export_constant(SC_FIRM_FAITH); + export_constant(SC_HOLY_OIL); + export_constant(SC_FIRST_BRAND); + export_constant(SC_SECOND_BRAND); + export_constant(SC_SECOND_JUDGE); + export_constant(SC_THIRD_EXOR_FLAME); + export_constant(SC_FIRST_FAITH_POWER); + export_constant(SC_MASSIVE_F_BLASTER); + export_constant(SC_PROTECTSHADOWEQUIP); + export_constant(SC_RESEARCHREPORT); + export_constant(SC_BO_HELL_DUSTY); + export_constant(SC_BIONIC_WOODENWARRIOR); + export_constant(SC_BIONIC_WOODEN_FAIRY); + export_constant(SC_BIONIC_CREEPER); + export_constant(SC_BIONIC_HELLTREE); + export_constant(SC_SHADOW_STRIP); + export_constant(SC_ABYSS_DAGGER); + export_constant(SC_ABYSSFORCEWEAPON); + export_constant(SC_ABYSS_SLAYER); + export_constant(SC_FLAMETECHNIC); + export_constant(SC_FLAMETECHNIC_OPTION); + export_constant(SC_FLAMEARMOR); + export_constant(SC_FLAMEARMOR_OPTION); + export_constant(SC_COLD_FORCE); + export_constant(SC_COLD_FORCE_OPTION); + export_constant(SC_CRYSTAL_ARMOR); + export_constant(SC_CRYSTAL_ARMOR_OPTION); + export_constant(SC_GRACE_BREEZE); + export_constant(SC_GRACE_BREEZE_OPTION); + export_constant(SC_EYES_OF_STORM); + export_constant(SC_EYES_OF_STORM_OPTION); + export_constant(SC_EARTH_CARE); + export_constant(SC_EARTH_CARE_OPTION); + export_constant(SC_STRONG_PROTECTION); + export_constant(SC_STRONG_PROTECTION_OPTION); + export_constant(SC_DEEP_POISONING); + export_constant(SC_DEEP_POISONING_OPTION); + export_constant(SC_POISON_SHIELD); + export_constant(SC_POISON_SHIELD_OPTION); + #ifdef RENEWAL export_constant(SC_EXTREMITYFIST2); #endif @@ -3967,6 +4092,8 @@ export_constant(AI_FAW); export_constant(AI_GUILD); export_constant(AI_WAVEMODE); + export_constant(AI_ABR); + export_constant(AI_BIONIC); /* battle flags */ export_constant(BF_NONE); @@ -4294,6 +4421,8 @@ export_constant(MOB_ATK2); export_constant(MOB_DEF); export_constant(MOB_MDEF); + export_constant(MOB_RES); + export_constant(MOB_MRES); export_constant(MOB_STR); export_constant(MOB_AGI); export_constant(MOB_VIT); @@ -4506,6 +4635,8 @@ export_constant(UMOB_BODY2); export_constant(UMOB_GROUP_ID); export_constant(UMOB_IGNORE_CELL_STACK_LIMIT); + export_constant(UMOB_RES); + export_constant(UMOB_MRES); /* unit control - homunculus */ export_constant(UHOM_SIZE); @@ -8113,6 +8244,8 @@ export_constant(SKILL_REQ_SPIRITSPHERECOST); export_constant(SKILL_REQ_ITEMCOST); export_constant(SKILL_REQ_EQUIPMENT); + export_constant(SKILL_REQ_APCOST); + export_constant(SKILL_REQ_APRATECOST); /* skill require state */ export_constant(ST_NONE); @@ -8302,6 +8435,32 @@ export_constant(UNT_CATNIPPOWDER); export_constant(UNT_NYANGGRASS); export_constant(UNT_CREATINGSTAR); + export_constant(UNT_DUMMY_0); + export_constant(UNT_RAIN_OF_CRYSTAL); + export_constant(UNT_MYSTERY_ILLUSION); + export_constant(UNT_UNKNOWN_1); + export_constant(UNT_STRANTUM_TREMOR); + export_constant(UNT_VIOLENT_QUAKE); + export_constant(UNT_ALL_BLOOM); + export_constant(UNT_TORNADO_STORM); + export_constant(UNT_FLORAL_FLARE_ROAD); + export_constant(UNT_ASTRAL_STRIKE); + export_constant(UNT_CROSS_RAIN); + export_constant(UNT_PNEUMATICUS_PROCELLA); + export_constant(UNT_ABYSS_SQUARE); + export_constant(UNT_ACIDIFIED_ZONE_WATER); + export_constant(UNT_ACIDIFIED_ZONE_GROUND); + export_constant(UNT_ACIDIFIED_ZONE_WIND); + export_constant(UNT_ACIDIFIED_ZONE_FIRE); + export_constant(UNT_LIGHTNING_LAND); + export_constant(UNT_VENOM_SWAMP); + export_constant(UNT_CONFLAGRATION); + + export_constant(UNT_DEEPBLINDTRAP); + export_constant(UNT_SOLIDTRAP); + export_constant(UNT_SWIFTTRAP); + export_constant(UNT_FLAMETRAP); + export_constant(UNT_GD_LEADERSHIP); export_constant(UNT_GD_GLORYWOUNDS); export_constant(UNT_GD_SOULCOLD); @@ -8323,10 +8482,10 @@ export_constant(ITEMJ_THIRD); export_constant(ITEMJ_THIRD_UPPER); export_constant(ITEMJ_THIRD_BABY); + export_constant(ITEMJ_FOURTH); export_constant(ITEMJ_ALL_UPPER); export_constant(ITEMJ_ALL_BABY); export_constant(ITEMJ_ALL_THIRD); - export_constant(ITEMJ_FOURTH); /* item drop effects */ export_constant(DROPEFFECT_NONE); diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 53843a8371..f9219dc2aa 100755 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -58,7 +58,9 @@ using namespace rathena; #define MC_SKILLRANGEMAX MC_SKILLRANGEMIN + MAX_MERCSKILL #define EL_SKILLRANGEMIN MC_SKILLRANGEMAX + 1 #define EL_SKILLRANGEMAX EL_SKILLRANGEMIN + MAX_ELEMENTALSKILL -#define GD_SKILLRANGEMIN EL_SKILLRANGEMAX + 1 +#define ABR_SKILLRANGEMIN EL_SKILLRANGEMAX + 1 +#define ABR_SKILLRANGEMAX ABR_SKILLRANGEMIN + MAX_ABRSKILL +#define GD_SKILLRANGEMIN ABR_SKILLRANGEMAX + 1 #define GD_SKILLRANGEMAX GD_SKILLRANGEMIN + MAX_GUILDSKILL #if GD_SKILLRANGEMAX > 999 #error GD_SKILLRANGEMAX is greater than 999 @@ -233,6 +235,7 @@ int skill_get_unit_target( uint16 skill_id ) { skill_get(s int skill_get_unit_bl_target( uint16 skill_id ) { skill_get(skill_id, skill_db.find(skill_id)->unit_target&BL_ALL); } int skill_get_unit_layout_type( uint16 skill_id ,uint16 skill_lv ) { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->unit_layout_type); } int skill_get_cooldown( uint16 skill_id, uint16 skill_lv ) { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->cooldown); } +int skill_get_giveap( uint16 skill_id, uint16 skill_lv ) { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->giveap); } #ifdef RENEWAL_CAST int skill_get_fixed_cast( uint16 skill_id ,uint16 skill_lv ) { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->fixed_cast); } #endif @@ -240,8 +243,10 @@ int skill_get_fixed_cast( uint16 skill_id ,uint16 skill_lv ) { skill_get_l int skill_get_hp( uint16 skill_id ,uint16 skill_lv ) { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->require.hp); } int skill_get_mhp( uint16 skill_id ,uint16 skill_lv ) { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->require.mhp); } int skill_get_sp( uint16 skill_id ,uint16 skill_lv ) { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->require.sp); } +int skill_get_ap( uint16 skill_id, uint16 skill_lv ) { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->require.ap); } int skill_get_hp_rate( uint16 skill_id, uint16 skill_lv ) { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->require.hp_rate); } int skill_get_sp_rate( uint16 skill_id, uint16 skill_lv ) { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->require.sp_rate); } +int skill_get_ap_rate(uint16 skill_id, uint16 skill_lv) { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->require.ap_rate); } int skill_get_zeny( uint16 skill_id ,uint16 skill_lv ) { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->require.zeny); } int skill_get_weapontype( uint16 skill_id ) { skill_get(skill_id, skill_db.find(skill_id)->require.weapon); } int skill_get_ammotype( uint16 skill_id ) { skill_get(skill_id, skill_db.find(skill_id)->require.ammo); } @@ -452,6 +457,45 @@ unsigned short skill_dummy2skill_id(unsigned short skill_id) { return NPC_MAGMA_ERUPTION; case NPC_DANCINGBLADE_ATK: return NPC_DANCINGBLADE; + case DK_SERVANTWEAPON_ATK: + return DK_SERVANTWEAPON; + case DK_HACKANDSLASHER_ATK: + return DK_HACKANDSLASHER; + case AG_DESTRUCTIVE_HURRICANE_CLIMAX: + return AG_DESTRUCTIVE_HURRICANE; + case AG_VIOLENT_QUAKE_ATK: + return AG_VIOLENT_QUAKE; + case AG_ALL_BLOOM_ATK: + case AG_ALL_BLOOM_ATK2: + return AG_ALL_BLOOM; + case AG_CRYSTAL_IMPACT_ATK: + return AG_CRYSTAL_IMPACT; + case AG_ASTRAL_STRIKE_ATK: + return AG_ASTRAL_STRIKE; + case AG_CRIMSON_ARROW_ATK: + return AG_CRIMSON_ARROW; + case CD_ARBITRIUM_ATK: + return CD_ARBITRIUM; + case ABC_CHAIN_REACTION_SHOT_ATK: + return ABC_CHAIN_REACTION_SHOT; + case ABC_FROM_THE_ABYSS_ATK: + return ABC_FROM_THE_ABYSS; + case BO_ACIDIFIED_ZONE_WATER_ATK: + return BO_ACIDIFIED_ZONE_WATER; + case BO_ACIDIFIED_ZONE_GROUND_ATK: + return BO_ACIDIFIED_ZONE_GROUND; + case BO_ACIDIFIED_ZONE_WIND_ATK: + return BO_ACIDIFIED_ZONE_WIND; + case BO_ACIDIFIED_ZONE_FIRE_ATK: + return BO_ACIDIFIED_ZONE_FIRE; + case TR_ROSEBLOSSOM_ATK: + return TR_ROSEBLOSSOM; + case EM_ELEMENTAL_BUSTER_FIRE: + case EM_ELEMENTAL_BUSTER_WATER: + case EM_ELEMENTAL_BUSTER_WIND: + case EM_ELEMENTAL_BUSTER_GROUND: + case EM_ELEMENTAL_BUSTER_POISON: + return EM_ELEMENTAL_BUSTER; } return skill_id; } @@ -552,6 +596,15 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk case SU_BUNCHOFSHRIMP: hp = (status_get_lv(src) + status_get_int(src)) / 5 * 15; break; + case CD_MEDIALE_VOTUM:// Does the learned level of heal affect this skill? + case CD_DILECTIO_HEAL:// Same question for this one too. [Rytech] + //hp = (status_get_lv(src) + status_get_int(src)) / 5 * 30 * pc_checkskill(sd, AL_HEAL) / 10; + hp = (status_get_lv(src) + status_get_int(src)) / 5 * 30; +#ifdef RENEWAL + if (sd && ((skill = pc_checkskill(sd, HP_MEDITATIO)) > 0)) + hp_bonus += skill * 2; +#endif + break; default: if (skill_lv >= battle_config.max_heal_lv) return battle_config.max_heal; @@ -631,7 +684,8 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk #endif if (sc && sc->count) { - if (sc->data[SC_OFFERTORIUM] && (skill_id == AB_HIGHNESSHEAL || skill_id == AB_CHEAL || skill_id == NPC_CHEAL || skill_id == PR_SANCTUARY || skill_id == AL_HEAL)) + if (sc->data[SC_OFFERTORIUM] && (skill_id == AB_HIGHNESSHEAL || skill_id == AB_CHEAL || skill_id == NPC_CHEAL || skill_id == PR_SANCTUARY || skill_id == AL_HEAL || + skill_id == CD_DILECTIO_HEAL || skill_id == CD_MEDIALE_VOTUM )) #ifdef RENEWAL hp_bonus += sc->data[SC_OFFERTORIUM]->val2; #else @@ -642,6 +696,10 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk hp_bonus += sc->data[SC_GLASTHEIM_HEAL]->val1; #else hp += hp * sc->data[SC_GLASTHEIM_HEAL]->val1 / 100; +#endif +#ifdef RENEWAL + if (sc->data[SC_MEDIALE] && skill_id == CD_MEDIALE_VOTUM) + hp_bonus += sc->data[SC_MEDIALE]->val2; #endif } @@ -725,6 +783,8 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk if (skill_id == AB_HIGHNESSHEAL) global_bonus *= 2 + 0.3f * (skill_lv - 1); + else if (skill_id == CD_DILECTIO_HEAL)// Description says its 10% on Lv 1 but thats clearly a typo. [Rytech] + global_bonus *= 1 + 0.15f + 0.05f * skill_lv; #endif if (heal && tsc && tsc->count) { @@ -749,6 +809,11 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk #ifdef RENEWAL hp = (int)(hp * global_bonus); + // Final heal increased by HPlus. + // Is this the right place for this??? [Rytech] + if ( sd && status_get_hplus(src) > 0 ) + hp += hp * status_get_hplus(src) / 100; + return (heal) ? max(1, hp) : hp; #else return hp; @@ -1299,14 +1364,33 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 break; // If a normal attack is a skill, it's splash damage. [Inkfish] if(sd) { // Automatic trigger of Blitz Beat - if (pc_isfalcon(sd) && sd->status.weapon == W_BOW && (skill=pc_checkskill(sd,HT_BLITZBEAT))>0 && - rnd()%1000 <= sstatus->luk*10/3+1 ) { - rate=(sd->status.job_level+9)/10; - skill_castend_damage_id(src,bl,HT_BLITZBEAT,(skillstatus.weapon == W_BOW && (skill = pc_checkskill(sd, HT_BLITZBEAT)) > 0 && rnd() % 1000 <= sstatus->luk * 10 / 3 + 1) { + if ((sd->class_ & MAPID_THIRDMASK) == MAPID_RANGER) + rate = 5; + else + rate = (sd->status.job_level + 9) / 10; + + skill_castend_damage_id(src, bl, HT_BLITZBEAT, (skill < rate) ? skill : rate, tick, SD_LEVEL); + } + // Automatic trigger of Warg Strike + if (pc_iswug(sd) && (skill = pc_checkskill(sd, RA_WUGSTRIKE)) > 0) { + rate = sstatus->luk * 10 / 3 + 1; + + if (pc_isfalcon(sd)) + rate = rate / 3; + + if (rnd() % 1000 <= rate) + skill_castend_damage_id(src, bl, RA_WUGSTRIKE, skill, tick, 0); + } + // Automatic trigger of Hawk Rush + if (pc_isfalcon(sd) && sd->status.weapon == W_BOW && (skill = pc_checkskill(sd, WH_HAWKRUSH)) > 0) { + rate = sstatus->con * 10 / 3 + 1; + + rate += rate * (20 * pc_checkskill(sd, WH_NATUREFRIENDLY)) / 100; + + if (rnd() % 1000 <= rate) + skill_castend_damage_id(src, bl, WH_HAWKRUSH, skill, tick, 0); } - // Automatic trigger of Warg Strike [Jobbie] - if( pc_iswug(sd) && (skill = pc_checkskill(sd,RA_WUGSTRIKE)) > 0 && rnd()%1000 <= sstatus->luk*10/3+1 ) - skill_castend_damage_id(src,bl,RA_WUGSTRIKE,skill,tick,0); // Gank if(dstmd && sd->status.weapon != W_BOW && (skill=pc_checkskill(sd,RG_SNATCHER)) > 0 && @@ -1328,7 +1412,18 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 if((sce=sc->data[SC_EDP])) sc_start4(src,bl,SC_DPOISON,sce->val2, sce->val1,src->id,0,0, skill_get_time2(ASC_EDP,sce->val1)); + // Enchanting Shadow gives a chance to inflict shadow wounds to the enemy. + if ((sce = sc->data[SC_SHADOW_WEAPON]) && rnd() % 100 < sce->val2) { + if (tsc && tsc->data[SC_SHADOW_SCAR]) { + uint16 count = 1 + tsc->data[SC_SHADOW_SCAR]->val1; + // Need official stack limit. [Rytech] + count = min(5, count); + + sc_start(src, bl, SC_SHADOW_SCAR, 100, count, skill_get_time2(SHC_ENCHANTING_SHADOW, sce->val1)); + } else + sc_start(src, bl, SC_SHADOW_SCAR, 100, 1, skill_get_time2(SHC_ENCHANTING_SHADOW, sce->val1)); + } if ((sce = sc->data[SC_LUXANIMA]) && rnd() % 100 < sce->val2) skill_castend_nodamage_id(src, bl, RK_STORMBLAST, 1, tick, 0); } @@ -2004,6 +2099,10 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 case SC_SOULUNITY: case SC_SOULSHADOW: case SC_SOULFAIRY: case SC_SOULFALCON: case SC_SOULGOLEM: case SC_USE_SKILL_SP_SPA: case SC_USE_SKILL_SP_SHA: case SC_SP_SHA: + // 4th Jobs + case SC_SERVANTWEAPON: case SC_SERVANT_SIGN: case SC_GUARD_STANCE: + case SC_ATTACK_STANCE: case SC_PROTECTSHADOWEQUIP: case SC_SHADOW_STRIP: + case SC_ABYSSFORCEWEAPON: #ifdef RENEWAL case SC_EXTREMITYFIST2: #endif @@ -2088,9 +2187,83 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 case SP_SHA: sc_start(src, bl, SC_SP_SHA, 100, skill_lv, skill_get_time(skill_id, skill_lv)); break; + case DK_SERVANT_W_PHANTOM: + sc_start(src, bl, SC_HANDICAPSTATE_DEEPBLIND, 30 + 10 * skill_lv, skill_lv, skill_get_time(skill_id, skill_lv)); + break; + case AG_DESTRUCTIVE_HURRICANE:// Targets hit are dealt a additional hit through Climax. + if (sc && sc->data[SC_CLIMAX] && sc->data[SC_CLIMAX]->val1 == 1) + skill_castend_damage_id(src, bl, AG_DESTRUCTIVE_HURRICANE_CLIMAX, skill_lv, tick, SD_LEVEL|SD_ANIMATION); + break; + case AG_CRYSTAL_IMPACT:// Targets hit are dealt aftershock damage. + skill_castend_damage_id(src, bl, AG_CRYSTAL_IMPACT_ATK, skill_lv, tick, SD_LEVEL); + break; + case IQ_OLEUM_SANCTUM: + sc_start(src, bl, SC_HOLY_OIL, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + break; + case IQ_FIRST_BRAND: + sc_start(src, bl, SC_FIRST_BRAND, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + break; + case IQ_SECOND_FLAME: + case IQ_SECOND_FAITH: + case IQ_SECOND_JUDGEMENT: + sc_start(src, bl, SC_SECOND_BRAND, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + break; + case IQ_THIRD_PUNISH: + case IQ_THIRD_FLAME_BOMB: + case IQ_THIRD_CONSECRATION: + status_change_end(bl, SC_SECOND_BRAND, INVALID_TIMER); + break; + case CD_ARBITRIUM:// Target is Deep Silenced by chance and is then dealt a 2nd splash hit. + sc_start(src, bl, SC_HANDICAPSTATE_DEEPSILENCE, 20 + 5 * skill_lv, skill_lv, skill_get_time(skill_id, skill_lv)); + skill_castend_damage_id(src, bl, CD_ARBITRIUM_ATK, skill_lv, tick, SD_LEVEL); + break; + case SHC_FATAL_SHADOW_CROW: + sc_start( src, bl, SC_DARKCROW, 100, max( 1, pc_checkskill( sd, GC_DARKCROW ) ), skill_get_time( skill_id, skill_lv ) ); + break; + case ABC_UNLUCKY_RUSH: + sc_start(src, bl, SC_HANDICAPSTATE_MISFORTUNE, 30 + 10 * skill_lv, skill_lv, skill_get_time(skill_id, skill_lv)); + break; + case ABC_CHAIN_REACTION_SHOT: + skill_castend_damage_id(src, bl, ABC_CHAIN_REACTION_SHOT_ATK, skill_lv, tick, SD_LEVEL); + break; + case WH_DEEPBLINDTRAP:// Need official success chances for all 4 Windhawk traps. + sc_start(src, bl, SC_HANDICAPSTATE_DEEPBLIND, 50, skill_lv, skill_get_time2(skill_id, skill_lv)); + break; + case WH_SOLIDTRAP: + sc_start(src, bl, SC_HANDICAPSTATE_CRYSTALLIZATION, 50, skill_lv, skill_get_time2(skill_id, skill_lv)); + break; + case WH_SWIFTTRAP: + sc_start(src, bl, SC_HANDICAPSTATE_LIGHTNINGSTRIKE, 50, skill_lv, skill_get_time2(skill_id, skill_lv)); + break; + case WH_FLAMETRAP: + sc_start(src, bl, SC_HANDICAPSTATE_CONFLAGRATION, 50, skill_lv, skill_get_time2(skill_id, skill_lv)); + break; + case TR_ROSEBLOSSOM:// Rose blossom seed can only bloom if the target is hit. + sc_start4(src, bl, SC_ROSEBLOSSOM, 100, skill_lv, TR_ROSEBLOSSOM_ATK, src->id, 0, skill_get_time(skill_id, skill_lv)); + case WM_METALICSOUND: + case WM_REVERBERATION: + case TR_RHYTHMSHOOTING: + case TR_METALIC_FURY: + status_change_end(bl, SC_SOUNDBLEND, INVALID_TIMER); + break; + case EM_DIAMOND_STORM: + sc_start(src, bl, SC_HANDICAPSTATE_FROSTBITE, 40 + 10 * skill_lv, skill_lv, skill_get_time2(skill_id, skill_lv)); + break; + case EM_LIGHTNING_LAND: + sc_start(src, bl, SC_HANDICAPSTATE_LIGHTNINGSTRIKE, 10 + 10 * skill_lv, skill_lv, skill_get_time2(skill_id, skill_lv)); + break; + case EM_VENOM_SWAMP: + sc_start(src, bl, SC_HANDICAPSTATE_DEADLYPOISON, 10 + 10 * skill_lv, skill_lv, skill_get_time2(skill_id, skill_lv)); + break; + case EM_CONFLAGRATION: + sc_start(src, bl, SC_HANDICAPSTATE_CONFLAGRATION, 10 + 10 * skill_lv, skill_lv, skill_get_time2(skill_id, skill_lv)); + break; + case EM_TERRA_DRIVE: + sc_start(src, bl, SC_HANDICAPSTATE_CRYSTALLIZATION, 40 + 10 * skill_lv, skill_lv, skill_get_time2(skill_id, skill_lv)); + break; } //end switch skill_id - if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai) + if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai && md->special_state.ai != AI_ABR && md->special_state.ai != AI_BIONIC) { //Pass heritage to Master for status causing effects. [Skotlex] sd = map_id2sd(md->master_id); src = sd?&sd->bl:src; @@ -2617,9 +2790,9 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * --------------------------------------------------------------------------*/ int skill_break_equip(struct block_list *src, struct block_list *bl, unsigned short where, int rate, int flag) { - const int where_list[4] = {EQP_WEAPON, EQP_ARMOR, EQP_SHIELD, EQP_HELM}; - const enum sc_type scatk[4] = {SC_STRIPWEAPON, SC_STRIPARMOR, SC_STRIPSHIELD, SC_STRIPHELM}; - const enum sc_type scdef[4] = {SC_CP_WEAPON, SC_CP_ARMOR, SC_CP_SHIELD, SC_CP_HELM}; + const int where_list[6] = { EQP_WEAPON, EQP_ARMOR, EQP_SHIELD, EQP_HELM, EQP_ACC, EQP_SHADOW_GEAR }; + const enum sc_type scatk[6] = { SC_STRIPWEAPON, SC_STRIPARMOR, SC_STRIPSHIELD, SC_STRIPHELM, SC__STRIPACCESSORY, SC_SHADOW_STRIP }; + const enum sc_type scdef[6] = { SC_CP_WEAPON, SC_CP_ARMOR, SC_CP_SHIELD, SC_CP_HELM, SC_NONE, SC_PROTECTSHADOWEQUIP }; struct status_change *sc = status_get_sc(bl); int i; TBL_PC *sd; @@ -2658,7 +2831,7 @@ int skill_break_equip(struct block_list *src, struct block_list *bl, unsigned sh rate = rate*battle_config.equip_self_break_rate/100; } - for (i = 0; i < 4; i++) { + for (i = 0; i < 6; i++) { if (where&where_list[i]) { if (sc && sc->count && sc->data[scdef[i]]) where&=~where_list[i]; @@ -2695,6 +2868,30 @@ int skill_break_equip(struct block_list *src, struct block_list *bl, unsigned sh case EQI_GARMENT: flag = (where&EQP_GARMENT); break; + case EQI_ACC_L: + flag = (where&EQP_ACC_L); + break; + case EQI_ACC_R: + flag = (where&EQP_ACC_R); + break; + case EQI_SHADOW_ARMOR: + flag = (where&EQP_SHADOW_ARMOR); + break; + case EQI_SHADOW_WEAPON: + flag = (where&EQP_SHADOW_WEAPON); + break; + case EQI_SHADOW_SHIELD: + flag = (where&EQP_SHADOW_SHIELD); + break; + case EQI_SHADOW_SHOES: + flag = (where&EQP_SHADOW_SHOES); + break; + case EQI_SHADOW_ACC_R: + flag = (where&EQP_SHADOW_ACC_R); + break; + case EQI_SHADOW_ACC_L: + flag = (where&EQP_SHADOW_ACC_L); + break; default: continue; } @@ -2727,9 +2924,9 @@ bool skill_strip_equip(struct block_list *src, struct block_list *target, uint16 if (!tsc || tsc->option&OPTION_MADOGEAR) // Mado Gear cannot be divested [Ind] return false; - const int pos[5] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HELM, EQP_ACC}; - const enum sc_type sc_atk[5] = {SC_STRIPWEAPON, SC_STRIPSHIELD, SC_STRIPARMOR, SC_STRIPHELM, SC__STRIPACCESSORY}; - const enum sc_type sc_def[5] = {SC_CP_WEAPON, SC_CP_SHIELD, SC_CP_ARMOR, SC_CP_HELM, SC_NONE}; + const int pos[6] = { EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HELM, EQP_ACC, EQP_SHADOW_GEAR }; + const enum sc_type sc_atk[6] = { SC_STRIPWEAPON, SC_STRIPSHIELD, SC_STRIPARMOR, SC_STRIPHELM, SC__STRIPACCESSORY, SC_SHADOW_STRIP }; + const enum sc_type sc_def[6] = { SC_CP_WEAPON, SC_CP_SHIELD, SC_CP_ARMOR, SC_CP_HELM, SC_NONE, SC_PROTECTSHADOWEQUIP }; struct status_data *sstatus = status_get_status_data(src), *tstatus = status_get_status_data(target); int rate, time, location, mod = 100; @@ -2765,6 +2962,10 @@ bool skill_strip_equip(struct block_list *src, struct block_list *target, uint16 case SC_STRIPACCESSARY: rate = 12 + 2 * skill_lv; break; + case ABC_STRIP_SHADOW: + rate = 50 * (skill_lv + 3) + 2 * (sstatus->dex - tstatus->dex); + mod = 1000; + break; default: return false; } @@ -2784,6 +2985,7 @@ bool skill_strip_equip(struct block_list *src, struct block_list *target, uint16 case RG_STRIPHELM: case GC_WEAPONCRUSH: case ST_FULLSTRIP: + case ABC_STRIP_SHADOW: if (skill_id == WL_EARTHSTRAIN) time = skill_get_time2(skill_id, skill_lv); else @@ -2819,6 +3021,9 @@ bool skill_strip_equip(struct block_list *src, struct block_list *target, uint16 case SC_STRIPACCESSARY: location = EQP_ACC; break; + case ABC_STRIP_SHADOW: + location = EQP_SHADOW_GEAR; + break; } for (uint8 i = 0; i < ARRAYLENGTH(pos); i++) { @@ -2895,6 +3100,8 @@ short skill_blown(struct block_list* src, struct block_list* target, char count, status_change_end(target, SC_SU_STOOP, INVALID_TIMER); if (tsc->data[SC_ROLLINGCUTTER]) status_change_end(target, SC_ROLLINGCUTTER, INVALID_TIMER); + if (tsc->data[SC_CRESCIVEBOLT]) + status_change_end(target, SC_CRESCIVEBOLT, INVALID_TIMER); if (tsc->data[SC_SV_ROOTTWIST]) // Shouldn't move. return 0; } @@ -2912,6 +3119,10 @@ static int skill_magic_reflect(struct block_list* src, struct block_list* bl, in struct status_change *sc = status_get_sc(bl); struct map_session_data* sd = BL_CAST(BL_PC, bl); + // Deadly Projection null's all magic reflection. + if (sc && sc->data[SC_DEADLY_DEFEASANCE]) + return 0; + if (!sc || !sc->data[SC_KYOMU]) { // Kyomu doesn't reflect // Item-based reflection - Bypasses Boss check if (sd && sd->bonus.magic_damage_return && type && rnd()%100 < sd->bonus.magic_damage_return) @@ -3529,6 +3740,25 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * sc_start(src,src,SC_SMA,100,skill_lv,skill_get_time(SL_SMA, skill_lv)); } break; + case DK_SERVANT_W_DEMOL:// Only give servant's per target after damage calculation. + pc_addservantball( *sd ); + break; + case KN_PIERCE: + case LK_SPIRALPIERCE: + case RK_HUNDREDSPEAR: + case DK_MADNESS_CRUSHER: + if (sc && sc->data[SC_CHARGINGPIERCE]) { + if (sc->data[SC_CHARGINGPIERCE_COUNT]) { + if (sc->data[SC_CHARGINGPIERCE_COUNT]->val1 < 10) // If the charge count is below 10, add 1. + sc_start(src, src, SC_CHARGINGPIERCE_COUNT, 100, sc->data[SC_CHARGINGPIERCE_COUNT]->val1 + 1, skill_get_time2(DK_CHARGINGPIERCE, 1)); + else { // If charge count is 10, bonus damage is applied for 1 attack and then the count status ends. + clif_specialeffect(bl, 1767, AREA); + status_change_end(src, SC_CHARGINGPIERCE_COUNT, INVALID_TIMER); + } + } else // No count status detected? Start charge count at 1. + sc_start(src, src, SC_CHARGINGPIERCE_COUNT, 100, 1, skill_get_time2(DK_CHARGINGPIERCE, 1)); + } + break; } //combo handling @@ -3659,6 +3889,23 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * case SJ_NOVAEXPLOSING: dmg.dmotion = clif_skill_damage(dsrc,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, -2, DMG_SINGLE); break; + case DK_HACKANDSLASHER_ATK: + dmg.dmotion = clif_skill_damage(dsrc, bl, tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, -1, dmg_type); + break; + case AG_STORM_CANNON: + case AG_CRIMSON_ARROW: + dmg.dmotion = clif_skill_damage(dsrc, bl, tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, skill_lv, DMG_SPLASH); + break; + case TR_ROSEBLOSSOM_ATK: + case ABC_FROM_THE_ABYSS_ATK: + dmg.dmotion = clif_skill_damage(dsrc, bl, tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, -1, DMG_SPLASH); + break; + case TR_SOUNDBLEND: + if (flag&SD_ANIMATION)// For some reason the caster reacts on the splash flag. Best reduce amotion to minimize it for now. [Rytech] + dmg.dmotion = clif_skill_damage(dsrc, bl, tick, 10, dmg.dmotion, damage, dmg.div_, skill_id, -1, DMG_SPLASH); + else + dmg.dmotion = clif_skill_damage(dsrc, bl, tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, skill_lv, dmg_type); + break; case AB_DUPLELIGHT_MELEE: case AB_DUPLELIGHT_MAGIC: dmg.amotion = 300;/* makes the damage value not overlap with previous damage (when displayed by the client) */ @@ -3735,9 +3982,17 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * (d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce->val2] == bl->id) ) && check_distance_bl(bl, d_bl, sce->val3) ) { + int64 devotion_damage = damage; + + // Needed to check the devotion master for Rebound Shield status. + struct status_change *d_sc = status_get_sc(d_bl); + + if (d_sc && d_sc->data[SC_REBOUND_S]) + devotion_damage -= devotion_damage * d_sc->data[SC_REBOUND_S]->val2 / 100; + if (!rmdamage) { - clif_damage(d_bl, d_bl, gettick(), 0, 0, damage, 0, DMG_NORMAL, 0, false); - status_fix_damage(NULL, d_bl, damage, 0, 0); + clif_damage(d_bl, d_bl, gettick(), 0, 0, devotion_damage, 0, DMG_NORMAL, 0, false); + status_fix_damage(NULL, d_bl, devotion_damage, 0, 0); } else { bool isDevotRdamage = false; @@ -3746,8 +4001,8 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * // If !isDevotRdamage, reflected magics are done directly on the target not on paladin // This check is only for magical skill. // For BF_WEAPON skills types track var rdamage and function battle_calc_return_damage - clif_damage(bl, (!isDevotRdamage) ? bl : d_bl, gettick(), 0, 0, damage, 0, DMG_NORMAL, 0, false); - status_fix_damage(bl, (!isDevotRdamage) ? bl : d_bl, damage, 0, 0); + clif_damage(bl, (!isDevotRdamage) ? bl : d_bl, gettick(), 0, 0, devotion_damage, 0, DMG_NORMAL, 0, false); + status_fix_damage(bl, (!isDevotRdamage) ? bl : d_bl, devotion_damage, 0, 0); } } else { status_change_end(bl, SC_DEVOTION, INVALID_TIMER); @@ -3797,6 +4052,9 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * battle_drain(sd, bl, dmg.damage, dmg.damage2, tstatus->race, tstatus->class_); } + if (sd && tsc && dmg.flag&BF_LONG && tsc->data[SC_WINDSIGN] && rand()%100 < tsc->data[SC_WINDSIGN]->val2) + status_heal(src, 0, 0, 1, 0); + if( damage > 0 ) { // Post-damage effects switch( skill_id ) { case GC_VENOMPRESSURE: { @@ -3830,6 +4088,14 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * if (status_get_lv(src) > 29 && rnd() % 100 < 10 * status_get_lv(src) / 30) skill_addtimerskill(src, tick + dmg.amotion + skill_get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, attack_type, flag|2); break; + case ABC_DEFT_STAB: + if (skill_area_temp[1] == bl->id && rnd()%100 < 4 * skill_lv)// Need official autocast chance. [Rytech] + skill_addtimerskill(src, tick + dmg.amotion, bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, 2); + break; + case ABC_FRENZY_SHOT: + if (rnd()%100 < 4 * skill_lv)// Need official autocast chance. [Rytech] + skill_addtimerskill(src, tick + dmg.amotion, bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, 2); + break; } } @@ -4412,6 +4678,10 @@ static TIMER_FUNC(skill_timerskill){ case NPC_PULSESTRIKE2: skill_castend_damage_id(src,target,skl->skill_id,skl->skill_lv,tick,skl->flag); break; + case ABC_DEFT_STAB: + case ABC_FRENZY_SHOT: + skill_castend_damage_id(src, target, skl->skill_id, skl->skill_lv, tick, skl->flag); + break; default: skill_attack(skl->type,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag); break; @@ -4730,7 +5000,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint if (status_isdead(bl)) return 1; - if (skill_id && skill_get_type(skill_id) == BF_MAGIC && status_isimmune(bl) == 100) + if (skill_id && skill_id != AG_DEADLY_PROJECTION && skill_get_type(skill_id) == BF_MAGIC && status_isimmune(bl) == 100) { //GTB makes all targetted magic display miss with a single bolt. sc_type sct = status_skill2sc(skill_id); if(sct != SC_NONE) @@ -4869,9 +5139,78 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case RL_BANISHING_BUSTER: case RL_SLUGSHOT: case RL_AM_BLAST: + case DK_SERVANTWEAPON_ATK: + case BO_ACIDIFIED_ZONE_WATER_ATK: + case BO_ACIDIFIED_ZONE_GROUND_ATK: + case BO_ACIDIFIED_ZONE_WIND_ATK: + case BO_ACIDIFIED_ZONE_FIRE_ATK: + case ABC_CHAIN_REACTION_SHOT_ATK: + case ABR_BATTLE_BUSTER: + case ABR_DUAL_CANNON_FIRE: + case ABR_INFINITY_BUSTER: skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); break; + case IG_SHIELD_SHOOTING: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); + sc_start(src, src, SC_SHIELD_POWER, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + break; + case DK_DRAGONIC_AURA: + case DK_STORMSLASH: + case IG_GRAND_JUDGEMENT: + case CD_EFFLIGO: + case ABC_FRENZY_SHOT: + case WH_HAWKRUSH: + case WH_HAWKBOOMERANG: + case TR_ROSEBLOSSOM: + case TR_RHYTHMSHOOTING: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); + if (skill_id == DK_DRAGONIC_AURA) + sc_start(src, src, SC_DRAGONIC_AURA, 100, skill_lv, skill_get_time(skill_id,skill_lv)); + else if (skill_id == IG_GRAND_JUDGEMENT) + sc_start(src, src, SC_SPEAR_SCAR, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + break; + + case SHC_ETERNAL_SLASH: + if( sc && sc->data[SC_E_SLASH_COUNT] ) + sc_start(src, src, SC_E_SLASH_COUNT, 100, min( 5, 1 + sc->data[SC_E_SLASH_COUNT]->val1 ), skill_get_time(skill_id, skill_lv)); + else + sc_start(src, src, SC_E_SLASH_COUNT, 100, 1, skill_get_time(skill_id, skill_lv)); + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); + break; + + case SHC_SHADOW_STAB: + if (sc && (sc->data[SC_CLOAKING] || sc->data[SC_CLOAKINGEXCEED])) + flag |= 2;// Flag to deal 2 hits. + + status_change_end(src, SC_CLOAKING, INVALID_TIMER); + status_change_end(src, SC_CLOAKINGEXCEED, INVALID_TIMER); + + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); + break; + + case WH_CRESCIVE_BOLT: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); + if( sc && sc->data[SC_CRESCIVEBOLT] ) + sc_start(src, src, SC_CRESCIVEBOLT, 100, min( 3, 1 + sc->data[SC_CRESCIVEBOLT]->val1 ), skill_get_time(skill_id, skill_lv)); + else + sc_start(src, src, SC_CRESCIVEBOLT, 100, 1, skill_get_time(skill_id, skill_lv)); + break; + + case ABC_UNLUCKY_RUSH: + // Jump to the target before attacking. + if (skill_check_unit_movepos(5, src, bl->x, bl->y, 0, 1)) + skill_blown(src, src, 1, (map_calc_dir(bl, src->x, src->y) + 4) % 8, BLOWN_NONE); + + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); + break; + case MO_TRIPLEATTACK: skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag|SD_ANIMATION); break; @@ -4960,7 +5299,11 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case NPC_FIREBREATH: case NPC_ICEBREATH: case NPC_THUNDERBREATH: + case AG_STORM_CANNON: + case AG_CRIMSON_ARROW: skill_area_temp[1] = bl->id; + if (skill_id == AG_STORM_CANNON || skill_id == AG_CRIMSON_ARROW) + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); if (battle_config.skill_eightpath_algorithm) { //Use official AoE algorithm if (!(map_foreachindir(skill_attack_area, src->m, src->x, src->y, bl->x, bl->y, @@ -4979,6 +5322,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint skill_get_splash(skill_id, skill_lv), skill_get_maxcount(skill_id, skill_lv), splash_target(src), skill_get_type(skill_id), src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); } + if (skill_id == AG_CRIMSON_ARROW) + skill_attack(skill_get_type(AG_CRIMSON_ARROW_ATK), src, src, bl, AG_CRIMSON_ARROW_ATK, skill_lv, tick, flag|SD_LEVEL|SD_ANIMATION); break; case MO_INVESTIGATE: @@ -5192,6 +5537,57 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case SP_CURSEEXPLOSION: case SP_SHA: case SP_SWHOO: + case DK_SERVANT_W_PHANTOM: + case DK_SERVANT_W_DEMOL: + case DK_MADNESS_CRUSHER: + case AG_DESTRUCTIVE_HURRICANE: + case AG_SOUL_VC_STRIKE: + case AG_CRYSTAL_IMPACT: + case AG_CRYSTAL_IMPACT_ATK: + case AG_ROCK_DOWN: + case AG_FROZEN_SLASH: + case IQ_OLEUM_SANCTUM: + case IQ_MASSIVE_F_BLASTER: + case IQ_EXPOSION_BLASTER: + case IQ_FIRST_BRAND: + case IQ_SECOND_FLAME: + case IQ_SECOND_FAITH: + case IQ_SECOND_JUDGEMENT: + case IQ_THIRD_PUNISH: + case IQ_THIRD_FLAME_BOMB: + case IQ_THIRD_CONSECRATION: + case IG_OVERSLASH: + case CD_ARBITRIUM_ATK: + case CD_PETITIO: + case CD_FRAMEN: + case SHC_DANCING_KNIFE: + case SHC_SAVAGE_IMPACT: + case SHC_IMPACT_CRATER: + case SHC_FATAL_SHADOW_CROW: + case MT_AXE_STOMP: + case MT_RUSH_QUAKE: + case MT_A_MACHINE: + case ABC_ABYSS_DAGGER: + case ABC_CHAIN_REACTION_SHOT: + case ABC_DEFT_STAB: + case WH_GALESTORM: + case BO_ACIDIFIED_ZONE_WATER: + case BO_ACIDIFIED_ZONE_GROUND: + case BO_ACIDIFIED_ZONE_WIND: + case BO_ACIDIFIED_ZONE_FIRE: + case TR_ROSEBLOSSOM_ATK: + case TR_METALIC_FURY: + case ABC_FROM_THE_ABYSS_ATK: + case EM_ELEMENTAL_BUSTER_FIRE: + case EM_ELEMENTAL_BUSTER_WATER: + case EM_ELEMENTAL_BUSTER_WIND: + case EM_ELEMENTAL_BUSTER_GROUND: + case EM_ELEMENTAL_BUSTER_POISON: + case EM_EL_FLAMEROCK: + case EM_EL_AGE_OF_ICE: + case EM_EL_STORM_WIND: + case EM_EL_AVALANCHE: + case EM_EL_DEADLY_POISON: if( flag&1 ) {//Recursive invocation int sflag = skill_area_temp[0] & 0xFFF; int heal = 0; @@ -5203,6 +5599,14 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint if (skill_id == AB_ADORAMUS && map_getcell(bl->m, bl->x, bl->y, CELL_CHKLANDPROTECTOR)) break; // No damage should happen if the target is on Land Protector + // Servant Weapon - Demol only hits if the target is marked with a sign by the attacking caster. + if (skill_id == DK_SERVANT_W_DEMOL && !(tsc && tsc->data[SC_SERVANT_SIGN] && tsc->data[SC_SERVANT_SIGN]->val1 == src->id)) + break; + + // Deft Stab - Make sure the flag of 2 is passed on when the skill is double casted. + if (skill_id == ABC_DEFT_STAB && flag&2) + sflag |= 2; + 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 && !inf2[INF2_ISNPC] ) @@ -5231,7 +5635,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint break; } } else { - int starget = BL_CHAR|BL_SKILL; + int starget = BL_CHAR|BL_SKILL, splash_size = skill_get_splash(skill_id, skill_lv); skill_area_temp[0] = 0; skill_area_temp[1] = bl->id; @@ -5272,16 +5676,86 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint if (sd && pc_search_inventory(sd, skill_db.find(SU_LUNATICCARROTBEAT)->require.itemid[0]) >= 0) skill_id = SU_LUNATICCARROTBEAT2; break; + case DK_SERVANT_W_PHANTOM: + case SHC_SAVAGE_IMPACT: + case SHC_FATAL_SHADOW_CROW: + case MT_RUSH_QUAKE: + // Jump to the target before attacking. + if (skill_check_unit_movepos(5, src, bl->x, bl->y, 0, 1)) + skill_blown(src, src, 1, (map_calc_dir(bl, src->x, src->y) + 4) % 8, BLOWN_NONE); + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);// Trigger animation on servants. + break; + case AG_CRYSTAL_IMPACT_ATK: + if (sc && sc->data[SC_CLIMAX] && sc->data[SC_CLIMAX]->val1 == 5) + splash_size = 2;// Gives the aftershock hit a 5x5 splash AoE. + break; + case AG_ROCK_DOWN: + case IQ_FIRST_BRAND: + case IQ_SECOND_FLAME: + case IQ_SECOND_FAITH: + case IQ_SECOND_JUDGEMENT: + case CD_PETITIO: + case CD_FRAMEN: + case ABC_DEFT_STAB: + case ABC_CHAIN_REACTION_SHOT: + case EM_EL_FLAMEROCK: + case EM_EL_AGE_OF_ICE: + case EM_EL_STORM_WIND: + case EM_EL_AVALANCHE: + case EM_EL_DEADLY_POISON: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + break; + case IQ_THIRD_PUNISH: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + if (sd) { + uint8 limit = 5; + + if (sc && sc->data[SC_RAISINGDRAGON]) + limit += sc->data[SC_RAISINGDRAGON]->val1; + for (uint8 i = 0; i < limit; i++) + pc_addspiritball(sd, skill_get_time(skill_id, skill_lv), limit); + } + break; + case IQ_THIRD_FLAME_BOMB: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + if (sd && sd->spiritball / 5 > 1) + skill_area_temp[0] = sd->spiritball / 5 - 1; + break; + case IQ_THIRD_CONSECRATION: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + status_heal(src, status_get_max_hp(src) * skill_lv / 100, status_get_max_sp(src) * skill_lv / 100, 0); + break; + case IG_OVERSLASH: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + skill_area_temp[0] = map_foreachinallrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill_area_sub_count); + break; + case WH_GALESTORM:// Give AP if 3 or more targets are hit. + if (sd && map_foreachinallrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill_area_sub_count) >= 3) + status_heal(src, 0, 0, 10, 0); + break; + case BO_ACIDIFIED_ZONE_WATER: + case BO_ACIDIFIED_ZONE_GROUND: + case BO_ACIDIFIED_ZONE_WIND: + case BO_ACIDIFIED_ZONE_FIRE: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + if (bl->type == BL_PC)// Place single cell AoE if hitting a player. + skill_castend_pos2(src, bl->x, bl->y, skill_id, skill_lv, tick, 0); + break; + case TR_METALIC_FURY: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + if (tsc && tsc->data[SC_SOUNDBLEND]) + skill_area_temp[0] = 1 + rnd()%4; + break; } // if skill damage should be split among targets, count them //SD_LEVEL -> Forced splash damage for Auto Blitz-Beat -> count targets //special case: Venom Splasher uses a different range for searching than for splashing if( flag&SD_LEVEL || skill_get_nk(skill_id, NK_SPLASHSPLIT) ) - skill_area_temp[0] = map_foreachinallrange(skill_area_sub, bl, (skill_id == AS_SPLASHER)?1:skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill_area_sub_count); + skill_area_temp[0] = map_foreachinallrange(skill_area_sub, bl, (skill_id == AS_SPLASHER)?1:splash_size, BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill_area_sub_count); // recursive invocation of skill_castend_damage_id() with flag|1 - map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), starget, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); + map_foreachinrange(skill_area_sub, bl, splash_size, starget, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); if (skill_id == RA_ARROWSTORM) status_change_end(src, SC_CAMOUFLAGE, INVALID_TIMER); @@ -5292,6 +5766,21 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint } break; + case DK_HACKANDSLASHER: + case DK_HACKANDSLASHER_ATK: + if (flag & 1) { + skill_addtimerskill(src, tick + (200 + status_get_amotion(src)), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag); + } else { + skill_area_temp[0] = 0; + skill_area_temp[1] = bl->id; + skill_area_temp[2] = 0; + + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); + map_foreachinrange(skill_area_sub, bl, skill_get_splash(DK_HACKANDSLASHER_ATK, skill_lv), BL_CHAR|BL_SKILL, src, DK_HACKANDSLASHER_ATK, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); + } + break; + //Place units around target case NJ_BAKUENRYU: clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); @@ -5484,9 +5973,24 @@ 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 AG_ASTRAL_STRIKE: + case AG_ASTRAL_STRIKE_ATK: + case AG_DESTRUCTIVE_HURRICANE_CLIMAX: + case CD_ARBITRIUM: skill_attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag); break; + case IG_JUDGEMENT_CROSS: + case TR_SOUNDBLEND: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + skill_attack(BF_MAGIC, src, src, bl, skill_id, skill_lv, tick, flag); + break; + + case AG_DEADLY_PROJECTION: + sc_start(src, bl, SC_DEADLY_DEFEASANCE, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + skill_attack(BF_MAGIC, src, src, bl, skill_id, skill_lv, tick, flag); + break; + case NPC_MAGICALATTACK: skill_attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag); sc_start(src,src,status_skill2sc(skill_id),100,skill_lv,skill_get_time(skill_id,skill_lv)); @@ -6594,6 +7098,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } type = status_skill2sc(skill_id); + status_change *sc = status_get_sc(src); tsc = status_get_sc(bl); tsce = (tsc && type != -1)?tsc->data[type]:NULL; @@ -6645,6 +7150,23 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } break; + case CD_REPARATIO: { + if (bl->type != BL_PC) { // Only works on players. + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + break; + } + + int heal_amount = 0; + + if (!status_isimmune(bl)) + heal_amount = tstatus->max_hp; + + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + clif_skill_nodamage(nullptr, bl, AL_HEAL, heal_amount, 1); + status_heal(bl, heal_amount, 0, 0); + } + break; + case PR_REDEMPTIO: if (sd && !(flag&1)) { if (sd->status.party_id == 0) { @@ -7153,6 +7675,33 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SJ_LIGHTOFSUN: case SJ_BOOKOFDIMENSION: case NPC_HALLUCINATIONWALK: + case DK_CHARGINGPIERCE: + case DK_VIGOR: + case AG_CLIMAX: + case IQ_POWERFUL_FAITH: + case IQ_FIRM_FAITH: + case IQ_SINCERE_FAITH: + case IQ_FIRST_FAITH_POWER: + case IQ_JUDGE: + case IQ_THIRD_EXOR_FLAME: + case IG_REBOUND_SHIELD: + case IG_HOLY_SHIELD: + case CD_ARGUTUS_VITA: + case CD_ARGUTUS_TELUM: + case CD_PRESENS_ACIES: + case CD_RELIGIO: + case CD_BENEDICTUM: + case SHC_SHADOW_EXCEED: + case SHC_POTENT_VENOM: + case SHC_ENCHANTING_SHADOW: + case MT_D_MACHINE: + case ABC_ABYSS_SLAYER: + case WH_WIND_SIGN: + case WH_CALAMITYGALE: + case BO_RESEARCHREPORT: + case TR_MYSTIC_SYMPHONY: + case TR_KVASIR_SONATA: + case EM_SPELL_ENCHANTING: clif_skill_nodamage(src,bl,skill_id,skill_lv, sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv))); break; @@ -7169,6 +7718,117 @@ 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))); break; + case DK_SERVANTWEAPON: + case ABC_FROM_THE_ABYSS: + clif_skill_nodamage(src, bl, skill_id, skill_lv, sc_start2(src, bl, type, 100, skill_lv, src->id, skill_get_time(skill_id, skill_lv))); + break; + + case TR_SOUNDBLEND: + skill_castend_damage_id(src, bl, skill_id, skill_lv, tick, 0); + clif_skill_nodamage(src, bl, skill_id, skill_lv, sc_start2(src, bl, type, 100, skill_lv, src->id, skill_get_time(skill_id, skill_lv))); + break; + + case AG_VIOLENT_QUAKE: + case AG_ALL_BLOOM: + sc_start(src, bl, type, 100, skill_lv, skill_get_time2(skill_id, skill_lv)); + break; + + case AG_DESTRUCTIVE_HURRICANE: + case AG_CRYSTAL_IMPACT: + if (flag&1) { // Buff from Crystal Impact with level 1 Climax. + sc_start(src, bl, type, 100, skill_lv, skill_get_time2(skill_id, skill_lv)); + } else { + uint16 climax_lv = 0, splash_size = skill_get_splash(skill_id, skill_lv); + + if (sc && sc->data[SC_CLIMAX]) + climax_lv = sc->data[SC_CLIMAX]->val1; + + if (climax_lv == 5) { // Adjusts splash AoE size depending on skill. + if (skill_id == AG_DESTRUCTIVE_HURRICANE) + splash_size = 9; // 19x19 + else if(skill_id == AG_CRYSTAL_IMPACT) + splash_size = AREA_SIZE; // 29x29 - Entire screen. + } + + skill_area_temp[1] = 0; + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + + if (skill_id == AG_DESTRUCTIVE_HURRICANE && climax_lv == 4) // Buff for caster instead of damage AoE. + sc_start(src, bl, type, 100, skill_lv, skill_get_time2(skill_id, skill_lv)); + else if (skill_id == AG_CRYSTAL_IMPACT && climax_lv == 1) // Buffs the caster and allies instead of doing damage AoE. + map_foreachinrange(skill_area_sub, bl, splash_size, BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ALLY|SD_SPLASH|1, skill_castend_nodamage_id); + else { + if (skill_id == AG_DESTRUCTIVE_HURRICANE && climax_lv == 1) // Display extra animation for the additional hit cast. + clif_skill_nodamage(src, bl, AG_DESTRUCTIVE_HURRICANE_CLIMAX, skill_lv, 1); + + map_foreachinrange(skill_area_sub, bl, splash_size, BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id); + } + } + break; + + case CD_MEDIALE_VOTUM: + case CD_DILECTIO_HEAL: + if (flag & 1) { + if (sd == nullptr || sd->status.party_id == 0 || (flag & 2)) { + int heal_amount = skill_calc_heal(src, bl, skill_id, skill_lv, 1); + + clif_skill_nodamage( nullptr, bl, AL_HEAL, heal_amount, 1 ); + status_heal(bl, heal_amount, 0, 0); + } else if (sd) + party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag | BCT_PARTY | 3, skill_castend_nodamage_id); + } else { + if (skill_id == CD_MEDIALE_VOTUM) + clif_skill_nodamage(src, bl, skill_id, skill_lv, sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv))); + else { // Dilectio Heal + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); // Placed here to display animation on target only. + skill_castend_nodamage_id(bl, bl, skill_id, skill_lv, tick, 1); + } + } + break; + + case CD_COMPETENTIA: + if (sd == nullptr || sd->status.party_id == 0 || (flag & 1)) { + int hp_amount = tstatus->max_hp * (20 * skill_lv) / 100; + int sp_amount = tstatus->max_sp * (20 * skill_lv) / 100; + + clif_skill_nodamage( nullptr, bl, AL_HEAL, hp_amount, 1 ); + status_heal(bl, hp_amount, 0, 0); + + clif_skill_nodamage( nullptr, bl, MG_SRECOVERY, sp_amount, 1 ); + status_heal(bl, 0, sp_amount, 0); + + clif_skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv))); + } else if (sd) + party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id); + break; + + case BO_ADVANCE_PROTECTION: + if( sd && ( !dstsd || pc_checkequip( dstsd, EQP_SHADOW_GEAR ) < 0 ) ){ + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + map_freeblock_unlock(); // Don't consume item requirements + return 0; + } + clif_skill_nodamage( src, bl, skill_id, skill_lv, sc_start( src, bl, type, 100, skill_lv, skill_get_time( skill_id, skill_lv ) ) ); + break; + + case EM_ACTIVITY_BURN: + if (bl->type == BL_PC && rnd() % 100 < 20 + 10 * skill_lv) { + uint8 ap_burn[5] = { 20, 30, 50, 60, 70 }; + + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + status_fix_apdamage(src, bl, ap_burn[skill_lv - 1], 0, skill_id); + } else + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + break; + + case EM_INCREASING_ACTIVITY: + if (bl->type == BL_PC) { + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + status_heal(bl, 0, 0, 20 + 5 * skill_lv, 0); + } else + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + break; + case SJ_GRAVITYCONTROL: { int fall_damage = sstatus->batk + sstatus->rhw.atk - tstatus->def2; @@ -7455,6 +8115,47 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } break; + case DK_SERVANT_W_SIGN: // Max allowed targets to be marked. + // Only players and monsters can be marked....I think??? [Rytech] + // Lets only allow players and monsters to use this skill for safety reasons. + if ((!dstsd && !dstmd) || !sd && !md) { + if (sd) + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + break; + } + + // Check if the target is already marked by another source. + if (tsc && tsc->data[type] && tsc->data[type]->val1 != src->id) { + if (sd) + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + map_freeblock_unlock(); + return 1; + } + + + // Mark the target. + if( sd ){ + int8 count = MAX_SERVANT_SIGN; + + ARR_FIND(0, count, i, sd->servant_sign[i] == bl->id); + if (i == count) { + ARR_FIND(0, count, i, sd->servant_sign[i] == 0); + if (i == count) { // Max number of targets marked. Fail the skill. + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + map_freeblock_unlock(); + return 1; + } + + // Add the ID of the marked target to the player's sign list. + sd->servant_sign[i] = bl->id; + } + + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + sc_start4(src, bl, type, 100, src->id, i, skill_lv, 0, skill_get_time(skill_id, skill_lv)); + } else if (md) // Monster's cant track with this skill. Just give the status. + clif_skill_nodamage(src, bl, skill_id, skill_lv, sc_start4(src, bl, type, 100, 0, 0, skill_lv, 0, skill_get_time(skill_id, skill_lv))); + break; + case MO_CALLSPIRITS: if(sd) { int limit = skill_lv; @@ -7581,6 +8282,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SJ_SOLARBURST: case SJ_STAREMPEROR: case SJ_FALLINGSTAR_ATK: + case DK_SERVANT_W_DEMOL: + case AG_FROZEN_SLASH: + case IQ_OLEUM_SANCTUM: + case IQ_MASSIVE_F_BLASTER: + case IQ_EXPOSION_BLASTER: + case SHC_IMPACT_CRATER: + case MT_AXE_STOMP: + case ABC_ABYSS_DAGGER: { struct status_change *sc = status_get_sc(src); int starget = BL_CHAR|BL_SKILL; @@ -7604,6 +8313,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } status_change_end(src, SC_DIMENSION, INVALID_TIMER); } + if (skill_id == IQ_MASSIVE_F_BLASTER || skill_id == SHC_IMPACT_CRATER || skill_id == MT_AXE_STOMP || skill_id == ABC_ABYSS_DAGGER) + sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)); skill_area_temp[1] = 0; clif_skill_nodamage(src,bl,skill_id,skill_lv,1); @@ -7614,6 +8325,70 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } break; + case SHC_DANCING_KNIFE: + case MT_A_MACHINE: + if (flag & 1) { + skill_area_temp[1] = 0; + + if (sd && pc_issit(sd)) { // Force player to stand before attacking + pc_setstand(sd, true); + skill_sit(sd, false); + } + + 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 | SD_LEVEL | SD_SPLASH, skill_castend_damage_id); + } else { + if (skill_id == MT_A_MACHINE && dstsd) { + int lv = abs( status_get_lv( src ) - status_get_lv( bl ) ); + + if (lv > battle_config.attack_machine_level_difference) { + if (sd) + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + map_freeblock_unlock(); + return 0; + } + } + + clif_skill_nodamage(src, bl, skill_id, skill_lv, sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv))); + } + break; + + case EM_ELEMENTAL_BUSTER: { + if (sd == nullptr) + break; + + if (!sd->ed || !(sd->ed->elemental.class_ >= ELEMENTALID_DILUVIO && sd->ed->elemental.class_ <= ELEMENTALID_SERPENS)) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + map_freeblock_unlock(); + return 0; + } + + uint16 buster_element; + + switch (sd->ed->elemental.class_) { + case ELEMENTALID_ARDOR: + buster_element = EM_ELEMENTAL_BUSTER_FIRE; + break; + case ELEMENTALID_DILUVIO: + buster_element = EM_ELEMENTAL_BUSTER_WATER; + break; + case ELEMENTALID_PROCELLA: + buster_element = EM_ELEMENTAL_BUSTER_WIND; + break; + case ELEMENTALID_TERREMOTUS: + buster_element = EM_ELEMENTAL_BUSTER_GROUND; + break; + case ELEMENTALID_SERPENS: + buster_element = EM_ELEMENTAL_BUSTER_POISON; + break; + } + + skill_area_temp[1] = 0; + clif_skill_nodamage(src, bl, buster_element, skill_lv, 1);// Animation for the triggered blaster element. + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);// Triggered after blaster animation to make correct skill name scream appear. + map_foreachinrange(skill_area_sub, bl, 6, BL_CHAR | BL_SKILL, src, buster_element, skill_lv, tick, flag | BCT_ENEMY | SD_LEVEL | SD_SPLASH | 1, skill_castend_damage_id); + } + break; + case NPC_IGNITIONBREAK: case RK_IGNITIONBREAK: skill_area_temp[1] = 0; @@ -7735,11 +8510,18 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case CASH_ASSUMPTIO: case WM_FRIGG_SONG: case NV_HELPANGEL: + case IG_GUARDIAN_SHIELD: + case IG_ULTIMATE_SACRIFICE:// Is the animation on this skill correct? Check if its on caster only or all affected. [Rytech] if( sd == NULL || sd->status.party_id == 0 || (flag & 1) ) clif_skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv))); - else if( sd ) + else if (sd) + { + if (skill_id == IG_ULTIMATE_SACRIFICE) + status_set_hp(src, 1, 0); party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id); + } break; + case MER_MAGNIFICAT: if( mer != NULL ) { @@ -7788,6 +8570,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SJ_UNIVERSESTANCE: case SJ_SUNSTANCE: case SP_SOULCOLLECT: + case IG_GUARD_STANCE: + case IG_ATTACK_STANCE: if( tsce ) { clif_skill_nodamage(src,bl,skill_id,skill_lv,status_change_end(bl, type, INVALID_TIMER)); @@ -8256,7 +9040,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case RG_STRIPHELM: case ST_FULLSTRIP: case GC_WEAPONCRUSH: - case SC_STRIPACCESSARY: { + case SC_STRIPACCESSARY: + case ABC_STRIP_SHADOW: { bool i; //Special message when trying to use strip on FCP [Jobbie] @@ -8363,6 +9148,13 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui hp += hp * j / 100; sp += sp * j / 100; } + // Final heal increased by HPlus. + // Is this the right place for this??? [Rytech] + // Can HPlus also affect SP recovery??? + if (sd && sstatus->hplus > 0) { + hp += hp * sstatus->hplus / 100; + sp += sp * sstatus->hplus / 100; + } if (tsc && tsc->count) { uint8 penalty = 0; @@ -8541,6 +9333,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SC_SOULUNITY: case SC_SOULSHADOW: case SC_SOULFAIRY: case SC_SOULFALCON: case SC_SOULGOLEM: case SC_USE_SKILL_SP_SPA: case SC_USE_SKILL_SP_SHA: case SC_SP_SHA: + // 4th Jobs + case SC_SERVANTWEAPON: case SC_SERVANT_SIGN: case SC_GUARD_STANCE: + case SC_ATTACK_STANCE: case SC_PROTECTSHADOWEQUIP: case SC_SHADOW_STRIP: + case SC_ABYSSFORCEWEAPON: #ifdef RENEWAL case SC_EXTREMITYFIST2: #endif @@ -9150,6 +9946,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui unit_skilluse_id(src,src->id,sd->skill_id_dance,sd->skill_lv_dance); break; + case TR_RETROSPECTION: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + if (sd) + unit_skilluse_id(src, src->id, sd->skill_id_song, sd->skill_lv_song); + break; + case AS_SPLASHER: if( status_has_mode(tstatus,MD_STATUSIMMUNE) // Renewal dropped the 3/4 hp requirement @@ -10118,6 +10920,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SC_STRANGELIGHTS: case SC_DECORATION_OF_MUSIC: case SC_GN_CARTBOOST: case SC_RECOGNIZEDSPELL: case SC_CHASEWALK2: case SC_ACTIVE_MONSTER_TRANSFORM: case SC_SPORE_EXPLOSION: + // 4th Jobs + case SC_SERVANTWEAPON: case SC_SERVANT_SIGN: case SC_GUARD_STANCE: + case SC_ATTACK_STANCE: case SC_PROTECTSHADOWEQUIP: case SC_SHADOW_STRIP: + case SC_ABYSSFORCEWEAPON: #ifdef RENEWAL case SC_EXTREMITYFIST2: #endif @@ -11141,7 +11947,18 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case EL_WIND_CURTAIN: case EL_SOLID_SKIN: case EL_STONE_SHIELD: - case EL_WIND_STEP: { + case EL_WIND_STEP: + case EM_EL_FLAMETECHNIC: + case EM_EL_FLAMEARMOR: + case EM_EL_COLD_FORCE: + case EM_EL_CRYSTAL_ARMOR: + case EM_EL_GRACE_BREEZE: + case EM_EL_EYES_OF_STORM: + case EM_EL_EARTH_CARE: + case EM_EL_STRONG_PROTECTION: + case EM_EL_DEEP_POISONING: + case EM_EL_POISON_SHIELD: + { s_elemental_data *ele = BL_CAST(BL_ELEM, src); if( ele ) { sc_type type2 = (sc_type)(type-1); @@ -11151,7 +11968,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui elemental_clean_single_effect(ele, skill_id); } else { clif_skill_nodamage(src,src,skill_id,skill_lv,1); - clif_skill_damage(src, ( skill_id == EL_GUST || skill_id == EL_BLAST || skill_id == EL_WILD_STORM )?src:bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, DMG_SINGLE); + if (!(skill_id >= EM_EL_FLAMETECHNIC && skill_id <= EM_EL_DEADLY_POISON)) + clif_skill_damage(src, ( skill_id == EL_GUST || skill_id == EL_BLAST || skill_id == EL_WILD_STORM )?src:bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, DMG_SINGLE); if( skill_id == EL_WIND_STEP ) // There aren't teleport, just push the master away. skill_blown(src,bl,(rnd()%skill_get_blewcount(skill_id,skill_lv))+1,rnd()%8,BLOWN_NONE); sc_start(src,src,type2,100,skill_lv,skill_get_time(skill_id,skill_lv)); @@ -11215,6 +12033,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } } break; + case KO_KYOUGAKU: if( dstsd && tsc && !tsc->data[type] && rnd()%100 < tstatus->int_/2 ){ clif_skill_nodamage(src,bl,skill_id,skill_lv, @@ -11645,6 +12464,220 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui skill_addtimerskill(src, tick + (t_tick)skill_get_time(skill_id, skill_lv) * i, bl->id, 0, 0, skill_id, skill_lv, skill_get_type(skill_id), flag); break; + case BO_THE_WHOLE_PROTECTION: + if (sd == nullptr || sd->status.party_id == 0 || (flag & 1)) { + unsigned int equip[] = { EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HEAD_TOP }; + + for (uint8 i_eqp = 0; i_eqp < 4; i_eqp++) { + if (bl->type != BL_PC || (dstsd && pc_checkequip(dstsd, equip[i_eqp]) < 0)) + continue; + sc_start(src, bl, (sc_type)(SC_CP_WEAPON + i_eqp), 100, skill_lv, skill_get_time(skill_id, skill_lv)); + } + } else if (sd) { + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag | BCT_PARTY | 1, skill_castend_nodamage_id); + } + break; + + case TR_MUSICAL_INTERLUDE: + case TR_JAWAII_SERENADE: + case TR_PRON_MARCH: + if (sd == nullptr || sd->status.party_id == 0 || (flag & 1)) + sc_start4(src, bl, type, 100, skill_lv, 0, flag, 0, skill_get_time(skill_id, skill_lv)); + else if (sd) { + clif_skill_nodamage(bl, bl, skill_id, skill_lv, 1); + + sd->skill_id_song = skill_id; + sd->skill_lv_song = skill_lv; + + if (skill_check_pc_partner(sd, skill_id, &skill_lv, AREA_SIZE, 0) > 0) + flag |= 2; + + party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag | BCT_PARTY | 1, skill_castend_nodamage_id); + } + break; + + case TR_GEF_NOCTURN: + case TR_AIN_RHAPSODY: + if (flag & 1) + sc_start4(src, bl, type, 100, skill_lv, 0, flag, 0, skill_get_time(skill_id, skill_lv)); + else if (sd) { + clif_skill_nodamage(bl, bl, skill_id, skill_lv, 1); + + sd->skill_id_song = skill_id; + sd->skill_lv_song = skill_lv; + + if (skill_check_pc_partner(sd, skill_id, &skill_lv, AREA_SIZE, 0) > 0) + flag |= 2; + + map_foreachinallrange(skill_area_sub, src, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ENEMY | 1, skill_castend_nodamage_id); + } + break; + + case TR_ROKI_CAPRICCIO: + case TR_NIPELHEIM_REQUIEM: + if (flag & 1) { // Need official success chances. + uint16 success_chance = 5 * skill_lv; + + if (flag & 2) + success_chance *= 2; + + // Is it a chance to inflect so and so, or seprate chances for inflicting each status? [Rytech] + if (skill_id == TR_ROKI_CAPRICCIO) { + sc_start(src, bl, SC_CONFUSION, 4 * skill_lv, skill_lv, skill_get_time(skill_id, skill_lv)); + sc_start(src, bl, SC_HANDICAPSTATE_MISFORTUNE, success_chance, skill_lv, skill_get_time2(skill_id, skill_lv)); + } else { // TR_NIPELHEIM_REQUIEM + sc_start(src, bl, SC_CURSE, 4 * skill_lv, skill_lv, skill_get_time(skill_id, skill_lv)); + sc_start(src, bl, SC_HANDICAPSTATE_DEPRESSION, success_chance, skill_lv, skill_get_time2(skill_id, skill_lv)); + } + } else if (sd) { + clif_skill_nodamage(bl, bl, skill_id, skill_lv, 1); + + sd->skill_id_song = skill_id; + sd->skill_lv_song = skill_lv; + + if (skill_check_pc_partner(sd, skill_id, &skill_lv, AREA_SIZE, 0) > 0) + flag |= 2; + + map_foreachinallrange(skill_area_sub, src, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ENEMY | 1, skill_castend_nodamage_id); + } + break; + + case ABR_NET_REPAIR: + case ABR_NET_SUPPORT: + if (flag & 1) { + int heal_amount; + + if (skill_id == ABR_NET_REPAIR) { + heal_amount = tstatus->max_hp * 10 / 100; + clif_skill_nodamage( nullptr, bl, AL_HEAL, heal_amount, 1 ); + status_heal(bl, heal_amount, 0, 0); + } else { // ABR_NET_SUPPORT + heal_amount = tstatus->max_sp * 3 / 100; + clif_skill_nodamage( nullptr, bl, MG_SRECOVERY, heal_amount, 1 ); + status_heal(bl, 0, heal_amount, 0); + } + } else { + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ALLY | SD_SPLASH | 1, skill_castend_nodamage_id); + } + break; + + case WH_HAWK_M: + if (sd) { + if (!pc_isfalcon(sd)) + pc_setoption(sd, sd->sc.option | OPTION_FALCON); + else + pc_setoption(sd, sd->sc.option&~OPTION_FALCON); + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + } + break; + + case EM_SUMMON_ELEMENTAL_ARDOR: + case EM_SUMMON_ELEMENTAL_DILUVIO: + case EM_SUMMON_ELEMENTAL_PROCELLA: + case EM_SUMMON_ELEMENTAL_TERREMOTUS: + case EM_SUMMON_ELEMENTAL_SERPENS: { + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + + if (sd == nullptr) + break; + + uint16 em_elem[5] = { ELEMENTALID_ARDOR, ELEMENTALID_DILUVIO, ELEMENTALID_PROCELLA, ELEMENTALID_TERREMOTUS, ELEMENTALID_SERPENS }; + uint16 so_elem[5] = { ELEMENTALID_AGNI_L, ELEMENTALID_AQUA_L, ELEMENTALID_VENTUS_L, ELEMENTALID_TERA_L, 0 }; + uint8 elem_value = 4 - (EM_SUMMON_ELEMENTAL_SERPENS - skill_id); + + if (sd->ed && ((skill_id >= EM_SUMMON_ELEMENTAL_ARDOR && skill_id <= EM_SUMMON_ELEMENTAL_TERREMOTUS && sd->ed->elemental.class_ == so_elem[elem_value]) || + (skill_id == EM_SUMMON_ELEMENTAL_SERPENS && + (sd->ed->elemental.class_ == ELEMENTALID_AGNI_L || sd->ed->elemental.class_ == ELEMENTALID_AQUA_L || + sd->ed->elemental.class_ == ELEMENTALID_VENTUS_L || sd->ed->elemental.class_ == ELEMENTALID_TERA_L)))) { + // Remove the old elemental before summoning the super one. + elemental_delete(sd->ed); + + if (!elemental_create(sd, em_elem[elem_value], skill_get_time(skill_id, skill_lv))) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + break; + } else // Elemental summoned. Buff the player with the bonus. + sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + } else { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + break; + } + } + break; + + case EM_ELEMENTAL_VEIL: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + + if (sd == nullptr) + break; + + if (sd->ed && sd->ed->elemental.class_ >= ELEMENTALID_DILUVIO && sd->ed->elemental.class_ <= ELEMENTALID_SERPENS) + sc_start(src, &sd->ed->bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + else + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + break; + + case MT_M_MACHINE: + case BO_BIONIC_PHARMACY: + if (sd) { + sd->skill_id_old = skill_id; + sd->skill_lv_old = skill_lv; + + if (skill_id == MT_M_MACHINE) + clif_cooking_list(sd, 31, skill_id, 1, 7); + else // BO_BIONIC_PHARMACY + clif_cooking_list(sd, 32, skill_id, 1, 8); + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + } + break; + + case MT_SUMMON_ABR_BATTLE_WARIOR: + case MT_SUMMON_ABR_DUAL_CANNON: + case MT_SUMMON_ABR_MOTHER_NET: + case MT_SUMMON_ABR_INFINITY: { + uint32 abrs[4] = { MOBID_ABR_BATTLE_WARIOR, MOBID_ABR_DUAL_CANNON, MOBID_ABR_MOTHER_NET, MOBID_ABR_INFINITY }; + + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + + mob_data *md = mob_once_spawn_sub(src, src->m, src->x, src->y, "--ja--", abrs[3 - (MT_SUMMON_ABR_INFINITY - skill_id)], "", SZ_SMALL, AI_ABR); + + if (md) { + md->master_id = src->id; + md->special_state.ai = AI_ABR; + + if (md->deletetimer != INVALID_TIMER) + delete_timer(md->deletetimer, mob_timer_delete); + md->deletetimer = add_timer(gettick() + skill_get_time(skill_id, skill_lv), mob_timer_delete, md->bl.id, 0); + mob_spawn(md); + } + } + break; + + case BO_WOODENWARRIOR: + case BO_WOODEN_FAIRY: + case BO_CREEPER: + case BO_HELLTREE: { // A poring is used in the 4th slot as a dummy since the Research Report skill is in between the Creeper and Hell Tree skills. + uint32 bionics[5] = { MOBID_BIONIC_WOODENWARRIOR, MOBID_BIONIC_WOODEN_FAIRY, MOBID_BIONIC_CREEPER, MOBID_PORING, MOBID_BIONIC_HELLTREE }; + + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + + mob_data *md = mob_once_spawn_sub(src, src->m, src->x, src->y, "--ja--", bionics[4 - (BO_HELLTREE - skill_id)], "", SZ_SMALL, AI_BIONIC); + + if (md) { + md->master_id = src->id; + md->special_state.ai = AI_BIONIC; + + if (md->deletetimer != INVALID_TIMER) + delete_timer(md->deletetimer, mob_timer_delete); + md->deletetimer = add_timer(gettick() + skill_get_time(skill_id, skill_lv), mob_timer_delete, md->bl.id, 0); + mob_spawn(md); + } + } + break; + default: ShowWarning("skill_castend_nodamage_id: Unknown skill used:%d\n",skill_id); clif_skill_nodamage(src,bl,skill_id,skill_lv,1); @@ -11758,6 +12791,18 @@ static int8 skill_castend_id_check(struct block_list *src, struct block_list *ta return USESKILL_FAIL_MAX; } break; + case IQ_SECOND_FLAME: + case IQ_SECOND_FAITH: + case IQ_SECOND_JUDGEMENT: + if (!tsc || !(tsc->data[SC_FIRST_BRAND] || tsc->data[SC_SECOND_BRAND])) + return USESKILL_FAIL_LEVEL; + break; + case IQ_THIRD_PUNISH: + case IQ_THIRD_FLAME_BOMB: + case IQ_THIRD_CONSECRATION: + if (!tsc || !tsc->data[SC_SECOND_BRAND]) + return USESKILL_FAIL_LEVEL; + break; } if (inf&INF_ATTACK_SKILL || @@ -11925,6 +12970,7 @@ TIMER_FUNC(skill_castend_id){ case SC_ESCAPE: case WL_FROSTMISTY: case SU_CN_POWDERING: + case AG_RAIN_OF_CRYSTAL: ud->skillx = target->x; ud->skilly = target->y; ud->skilltimer = tid; @@ -11974,6 +13020,35 @@ TIMER_FUNC(skill_castend_id){ break; else { skill_consume_requirement(sd,ud->skill_id,ud->skill_lv,1); + + int add_ap = skill_get_giveap( ud->skill_id, ud->skill_lv ); + + // Give AP + if (add_ap > 0) { + switch (ud->skill_id) { + case TR_ROSEBLOSSOM: + case TR_RHYTHMSHOOTING: + case TR_METALIC_FURY: // Don't know the official increase. For now lets do up to 50% increase. + case TR_SOUNDBLEND: // Retrospection does the same for song skills. [Rytech] + add_ap += add_ap * (10 * pc_checkskill(sd, TR_STAGE_MANNER)) / 100; + break; + case TR_GEF_NOCTURN: + case TR_ROKI_CAPRICCIO: + case TR_AIN_RHAPSODY: + case TR_MUSICAL_INTERLUDE: + case TR_JAWAII_SERENADE: + case TR_NIPELHEIM_REQUIEM: + case TR_PRON_MARCH: + if (sd->skill_id_old == TR_RETROSPECTION) { + add_ap += add_ap * 50 / 100; + sd->skill_id_old = ud->skill_id; // Prevents AP bonus on non Retro Spection use. + } + break; + } + + status_heal(&sd->bl, 0, 0, add_ap, 0); + } + if (src != target && (status_bl_has_mode(target,MD_SKILLIMMUNE) || (status_get_class(target) == MOBID_EMPERIUM && !skill_get_inf2(ud->skill_id, INF2_TARGETEMPERIUM))) && skill_get_casttype(ud->skill_id) == CAST_DAMAGE) { clif_skill_fail(sd, ud->skill_id, USESKILL_FAIL_LEVEL, 0); break; // Show a skill fail message (Damage type consumes requirements) @@ -12191,8 +13266,25 @@ TIMER_FUNC(skill_castend_pos){ { if( ud->skill_id != AL_WARP && !skill_check_condition_castend(sd, ud->skill_id, ud->skill_lv) ) break; - else - skill_consume_requirement(sd,ud->skill_id,ud->skill_lv,1); + else { + skill_consume_requirement(sd, ud->skill_id, ud->skill_lv, 1); + + int add_ap = skill_get_giveap(ud->skill_id, ud->skill_lv); + + // Give AP + if (add_ap > 0) { + switch (ud->skill_id) { + case WH_DEEPBLINDTRAP: + case WH_SOLIDTRAP: + case WH_SWIFTTRAP: + case WH_FLAMETRAP: + if (pc_checkskill(sd, WH_ADVANCED_TRAP) >= 3) + add_ap += 1; + break; + } + status_heal(&sd->bl, 0, 0, add_ap, 0); + } + } } if( (src->type == BL_MER || src->type == BL_HOM) && !skill_check_condition_mercenary(src, ud->skill_id, ud->skill_lv, 1) ) @@ -12291,6 +13383,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui sd = BL_CAST(BL_PC, src); sc = status_get_sc(src); + status_data *sstatus = status_get_status_data(src); type = status_skill2sc(skill_id); sce = (sc && type != -1)?sc->data[type]:NULL; @@ -12490,12 +13583,35 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case SJ_BOOKOFCREATINGSTAR: case RL_B_TRAP: case NPC_STORMGUST2: + case AG_RAIN_OF_CRYSTAL: + case AG_MYSTERY_ILLUSION: + case AG_STRANTUM_TREMOR: + case AG_TORNADO_STORM: + case AG_FLORAL_FLARE_ROAD: + case IG_CROSS_RAIN: + case CD_PNEUMATICUS_PROCELLA: + case ABC_ABYSS_STRIKE: + case ABC_ABYSS_SQUARE: + case WH_DEEPBLINDTRAP: + case WH_SOLIDTRAP: + case WH_SWIFTTRAP: + case WH_FLAMETRAP: + case BO_ACIDIFIED_ZONE_WATER: + case BO_ACIDIFIED_ZONE_GROUND: + case BO_ACIDIFIED_ZONE_WIND: + case BO_ACIDIFIED_ZONE_FIRE: + case EM_DIAMOND_STORM: + case EM_LIGHTNING_LAND: + case EM_VENOM_SWAMP: + case EM_CONFLAGRATION: + case EM_TERRA_DRIVE: 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: case GN_DEMONIC_FIRE: skill_unitsetting(src,skill_id,skill_lv,x,y,0); break; + case WZ_ICEWALL: flag|=1; if(skill_unitsetting(src,skill_id,skill_lv,x,y,0)) @@ -12568,18 +13684,19 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui sc_start(src, src, SC_DORAM_SVSP, 100, 100, skill_get_time(SU_SPIRITOFLAND, 1)); } // Fall through - case WZ_METEOR: { - int area = skill_get_splash(skill_id, skill_lv); - short tmpx = 0, tmpy = 0; + case WZ_METEOR: + { + int area = skill_get_splash(skill_id, skill_lv); + short tmpx = 0, tmpy = 0; - for (i = 1; i <= skill_get_time(skill_id, skill_lv)/skill_get_unit_interval(skill_id); i++) { - // Creates a random Cell in the Splash Area - tmpx = x - area + rnd()%(area * 2 + 1); - tmpy = y - area + rnd()%(area * 2 + 1); - skill_unitsetting(src, skill_id, skill_lv, tmpx, tmpy, flag+i*skill_get_unit_interval(skill_id)); - } + for (i = 1; i <= skill_get_time(skill_id, skill_lv) / skill_get_unit_interval(skill_id); i++) { + // Creates a random Cell in the Splash Area + tmpx = x - area + rnd() % (area * 2 + 1); + tmpy = y - area + rnd() % (area * 2 + 1); + skill_unitsetting(src, skill_id, skill_lv, tmpx, tmpy, flag + i * skill_get_unit_interval(skill_id)); } - break; + } + break; case AL_WARP: if(sd) @@ -12657,6 +13774,14 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui potion_hp = potion_hp * (100+i_lv)/100; potion_sp = potion_sp * (100+i_lv)/100; + // Final heal increased by HPlus. + // Is this the right place for this??? [Rytech] + // Can HPlus also affect SP recovery??? + if (sd && sstatus->hplus > 0) { + potion_hp += potion_hp * sstatus->hplus / 100; + potion_sp += potion_sp * sstatus->hplus / 100; + } + if(potion_hp > 0 || potion_sp > 0) { i_lv = skill_get_splash(skill_id, skill_lv); map_foreachinallarea(skill_area_sub, @@ -13089,6 +14214,65 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui } break; + case AG_ASTRAL_STRIKE: + i = skill_get_splash(skill_id, skill_lv); + map_foreachinallarea(skill_area_sub, src->m, x-i, y-i, x+i, y+i, BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill_castend_damage_id); + flag |= 1; + skill_unitsetting(src, skill_id, skill_lv, x, y, 0); + break; + + case AG_VIOLENT_QUAKE: + case AG_ALL_BLOOM: { + int area = skill_get_splash(skill_id, skill_lv); + int unit_time = skill_get_time(skill_id, skill_lv); + int unit_interval = skill_get_unit_interval(skill_id); + uint16 tmpx = 0, tmpy = 0, sub_skill = 0, climax_lv = 0; + + // Grab Climax's effect level if active. + // This affects the behavior of certain skills in certain ways. + if (sc && sc->data[SC_CLIMAX]) + climax_lv = sc->data[SC_CLIMAX]->val1; + + if (skill_id == AG_VIOLENT_QUAKE) { + sub_skill = AG_VIOLENT_QUAKE_ATK; + + // Fixes rising rocks spawn area to 7x7. + if (climax_lv == 5) + area = 3; + } else { // AG_ALL_BLOOM + sub_skill = AG_ALL_BLOOM_ATK; + + if (climax_lv == 1) { // Rose buds spawn at double the speed. + unit_time /= 2; + unit_interval /= 2; + } + } + + // Displays the earthquake / flower garden. + skill_unitsetting(src, skill_id, skill_lv, x, y, 0); + + if (climax_lv == 4) { // Deals no damage and instead inflicts a status on the enemys in range. + i = skill_get_splash(skill_id, skill_lv); + map_foreachinallarea(skill_area_sub, src->m, x - i, y - i, x + i, y + i, BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ENEMY | 1, skill_castend_nodamage_id); + } else for (i = 1; i <= unit_time / unit_interval; i++) { // Spawn the rising rocks / rose buds on random spots at seperate intervals + tmpx = x - area + rnd() % (area * 2 + 1); + tmpy = y - area + rnd() % (area * 2 + 1); + skill_unitsetting(src, sub_skill, skill_lv, tmpx, tmpy, flag + i * unit_interval); + + if ((skill_id == AG_VIOLENT_QUAKE && climax_lv == 1) || (skill_id == AG_ALL_BLOOM && climax_lv == 2)) { // Spwan a 2nd rising rock / rose bud along with the 1st one. + tmpx = x - area + rnd() % (area * 2 + 1); + tmpy = y - area + rnd() % (area * 2 + 1); + skill_unitsetting(src, sub_skill, skill_lv, tmpx, tmpy, flag + i * unit_interval); + } + } + + // One final attack the size of the flower garden is dealt after + // all rose buds explode if Climax level 5 is active. + if (skill_id == AG_ALL_BLOOM && climax_lv == 5) + skill_unitsetting(src, AG_ALL_BLOOM_ATK2, skill_lv, x, y, flag + i * unit_interval); + } + break; + default: ShowWarning("skill_castend_pos2: Unknown skill used:%d\n",skill_id); return 1; @@ -13723,6 +14907,29 @@ std::shared_ptr skill_unitsetting(struct block_list *src, ui if (!map_flag_vs(src->m)) target = BCT_ENEMY; break; + case AG_VIOLENT_QUAKE: + case AG_ALL_BLOOM: + if (sc && sc->data[SC_CLIMAX]) { + if (skill_id == AG_ALL_BLOOM && sc->data[SC_CLIMAX]->val1 == 1) + limit /= 2; // Rose buds spawn at double the speed, so rose garden duration must be halved. + else if (sc->data[SC_CLIMAX]->val1 == 4) + limit = 3000; // Show main AoE for fixed duration on status giving effect. + } + break; + case AG_VIOLENT_QUAKE_ATK: + case AG_ALL_BLOOM_ATK: + case AG_ALL_BLOOM_ATK2: + limit = flag; + flag = 0; + if (skill_id == AG_VIOLENT_QUAKE_ATK && sc && sc->data[SC_CLIMAX] && sc->data[SC_CLIMAX]->val1 == 2) + range = 4; // Rising rocks splash is increased to 9x9. + break; + case WH_DEEPBLINDTRAP: + case WH_SOLIDTRAP: + case WH_SWIFTTRAP: + case WH_FLAMETRAP: + limit += 3000 * (sd ? pc_checkskill(sd, WH_ADVANCED_TRAP) : 5); + break; } // Init skill unit group @@ -14347,6 +15554,20 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, t_t case UNT_ICEMINE: case UNT_FLAMECROSS: case UNT_HELLBURNING: + case UNT_RAIN_OF_CRYSTAL: + case UNT_MYSTERY_ILLUSION: + case UNT_STRANTUM_TREMOR: + case UNT_TORNADO_STORM: + case UNT_FLORAL_FLARE_ROAD: + case UNT_CROSS_RAIN: + case UNT_PNEUMATICUS_PROCELLA: + case UNT_LIGHTNING_LAND: + case UNT_VENOM_SWAMP: + case UNT_CONFLAGRATION: + case UNT_DEEPBLINDTRAP: + case UNT_SOLIDTRAP: + case UNT_SWIFTTRAP: + case UNT_FLAMETRAP: skill_attack(skill_get_type(sg->skill_id),ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,0); break; @@ -14984,6 +16205,37 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, t_t else skill_attack(skill_get_type(NPC_MAGMA_ERUPTION_DOTDAMAGE), ss, &unit->bl, bl, NPC_MAGMA_ERUPTION_DOTDAMAGE, sg->skill_lv, tick, 0); break; + + case UNT_ACIDIFIED_ZONE_WATER: + skill_attack(skill_get_type(BO_ACIDIFIED_ZONE_WATER_ATK), ss, &unit->bl, bl, BO_ACIDIFIED_ZONE_WATER_ATK, sg->skill_lv, tick, 0); + break; + + case UNT_ACIDIFIED_ZONE_GROUND: + skill_attack(skill_get_type(BO_ACIDIFIED_ZONE_GROUND_ATK), ss, &unit->bl, bl, BO_ACIDIFIED_ZONE_GROUND_ATK, sg->skill_lv, tick, 0); + break; + + case UNT_ACIDIFIED_ZONE_WIND: + skill_attack(skill_get_type(BO_ACIDIFIED_ZONE_WIND_ATK), ss, &unit->bl, bl, BO_ACIDIFIED_ZONE_WIND_ATK, sg->skill_lv, tick, 0); + break; + + case UNT_ACIDIFIED_ZONE_FIRE: + skill_attack(skill_get_type(BO_ACIDIFIED_ZONE_FIRE_ATK), ss, &unit->bl, bl, BO_ACIDIFIED_ZONE_FIRE_ATK, sg->skill_lv, tick, 0); + break; + + case UNT_ASTRAL_STRIKE: + skill_attack(skill_get_type(AG_ASTRAL_STRIKE_ATK), ss, &unit->bl, bl, AG_ASTRAL_STRIKE_ATK, sg->skill_lv, tick, 0); + break; + + case UNT_ABYSS_SQUARE: { + short flag = 0; + + // Check to see if the caster is in the AoE. + if (distance_bl(ss, &unit->bl) <= unit->range) + flag |= 2; // If yes, skill hits twice. + + skill_attack(skill_get_type(sg->skill_id), ss, &unit->bl, bl, sg->skill_id, sg->skill_lv, tick, flag); + } + break; } if (bl->type == BL_MOB && ss != bl) @@ -15364,6 +16616,17 @@ int skill_check_condition_char_sub (struct block_list *bl, va_list ap) if( (tsd->class_&MAPID_UPPERMASK) == MAPID_PRIEST ) p_sd[(*c)++] = tsd->bl.id; return 1; + case TR_GEF_NOCTURN: + case TR_ROKI_CAPRICCIO: + case TR_AIN_RHAPSODY: + case TR_MUSICAL_INTERLUDE: + case TR_JAWAII_SERENADE: + case TR_NIPELHEIM_REQUIEM: + case TR_PRON_MARCH:// Does the partner's learned skill level affects anything? [Rytech] + if (sd->status.sex != tsd->status.sex && (tsd->class_&MAPID_FOURTHMASK) == MAPID_TROUBADOURTROUVERE && + sd->status.party_id && tsd->status.party_id && sd->status.party_id == tsd->status.party_id) + p_sd[(*c)++] = tsd->bl.id; + return 1; default: //Warning: Assuming Ensemble Dance/Songs for code speed. [Skotlex] { uint16 skill_lv; @@ -15451,7 +16714,8 @@ int skill_check_pc_partner(struct map_session_data *sd, uint16 skill_id, uint16 memset (p_sd, 0, sizeof(p_sd)); i = map_foreachinallrange(skill_check_condition_char_sub, &sd->bl, range, BL_PC, &sd->bl, &c, &p_sd, skill_id); - if ( skill_id != PR_BENEDICTIO && skill_id != AB_ADORAMUS && skill_id != WM_GREAT_ECHO ) //Apply the average lv to encore skills. + if ( skill_id != PR_BENEDICTIO && skill_id != AB_ADORAMUS && skill_id != WM_GREAT_ECHO && + !(skill_id >= TR_GEF_NOCTURN && skill_id <= TR_PRON_MARCH)) //Apply the average lv to encore skills. *skill_lv = (i+(*skill_lv))/(c+1); //I know c should be one, but this shows how it could be used for the average of n partners. return c; } @@ -15476,7 +16740,40 @@ static int skill_check_condition_mob_master_sub(struct block_list *bl, va_list a skill=va_arg(ap,int); c=va_arg(ap,int *); - ai = (unsigned)(skill == AM_SPHEREMINE?AI_SPHERE:skill == KO_ZANZOU?AI_ZANZOU:skill == MH_SUMMON_LEGION?AI_LEGION:skill == NC_SILVERSNIPER?AI_FAW:skill == NC_MAGICDECOY?AI_FAW:AI_FLORA); + switch (skill) { + case AM_SPHEREMINE: + ai = AI_SPHERE; + break; + case AM_CANNIBALIZE: + ai = AI_FLORA; + break; + case KO_ZANZOU: + ai = AI_ZANZOU; + break; + case MH_SUMMON_LEGION: + ai = AI_LEGION; + break; + case NC_SILVERSNIPER: + case NC_MAGICDECOY: + ai = AI_FAW; + break; + case MT_SUMMON_ABR_BATTLE_WARIOR: + case MT_SUMMON_ABR_DUAL_CANNON: + case MT_SUMMON_ABR_MOTHER_NET: + case MT_SUMMON_ABR_INFINITY: + ai = AI_ABR; + break; + case BO_WOODENWARRIOR: + case BO_WOODEN_FAIRY: + case BO_CREEPER: + case BO_HELLTREE: + ai = AI_BIONIC; + break; + default: + ai = AI_FLORA; + break; + } + if( md->master_id != src_id || md->special_state.ai != ai) return 0; //Non alchemist summoned mobs have nothing to do here. @@ -15584,6 +16881,8 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i sd->state.arrow_atk = skill_get_ammotype(skill_id)?1:0; //Need to do arrow state check. sd->spiritball_old = sd->spiritball; //Need to do Spiritball check. sd->soulball_old = sd->soulball; //Need to do Soulball check. + sd->servantball_old = sd->servantball; //Need to do Servantball check. + sd->abyssball_old = sd->abyssball; //Need to do Abyssball check. return true; } @@ -15603,6 +16902,8 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i case GN_MAKEBOMB: case GN_S_PHARMACY: case GN_CHANGEMATERIAL: + case MT_M_MACHINE: + case BO_BIONIC_PHARMACY: if( sd->menuskill_id != skill_id ) return false; break; @@ -15684,7 +16985,7 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i } } else if(inf2[INF2_ISENSEMBLE]) { - if (skill_check_pc_partner(sd, skill_id, &skill_lv, 1, 0) < 1) { + if (skill_check_pc_partner(sd, skill_id, &skill_lv, 1, 0) < 1 && !(sc && sc->data[SC_KVASIR_SONATA])) { clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return false; } @@ -16113,7 +17414,7 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i } break; case RA_WUGMASTERY: - if( (pc_isfalcon(sd) && !battle_config.warg_can_falcon) || pc_isridingwug(sd) || sd->sc.data[SC__GROOMY]) { + if( (pc_isfalcon(sd) && (!pc_checkskill(sd, WH_HAWK_M) && !battle_config.warg_can_falcon)) || pc_isridingwug(sd) || sd->sc.data[SC__GROOMY]) { clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return false; } @@ -16125,7 +17426,7 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i } break; case RA_WUGRIDER: - if( (pc_isfalcon(sd) && !battle_config.warg_can_falcon) || ( !pc_isridingwug(sd) && !pc_iswug(sd) ) ) { + if( (pc_isfalcon(sd) && (!pc_checkskill(sd, WH_HAWK_M) && !battle_config.warg_can_falcon)) || ( !pc_isridingwug(sd) && !pc_iswug(sd) ) ) { clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return false; } @@ -16291,6 +17592,28 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i if (!(sc && sc->data[SC_USE_SKILL_SP_SPA])) return false; break; + case DK_SERVANT_W_PHANTOM: + case DK_SERVANT_W_DEMOL: + if (sd->servantball > 0 && sd->servantball < require.spiritball) + sd->servantball_old = require.spiritball = sd->servantball; + else + sd->servantball_old = require.spiritball; + break; + case IQ_SECOND_FAITH: + case IQ_THIRD_PUNISH: + if (!(sc && (sc->data[SC_FIRST_FAITH_POWER] || sc->data[SC_SECOND_JUDGE] || sc->data[SC_THIRD_EXOR_FLAME]))) + return false; + break; + case IQ_SECOND_JUDGEMENT: + case IQ_THIRD_CONSECRATION: + if (!(sc && (sc->data[SC_SECOND_JUDGE] || sc->data[SC_THIRD_EXOR_FLAME]))) + return false; + break; + case IQ_SECOND_FLAME: + case IQ_THIRD_FLAME_BOMB: + if (!(sc && sc->data[SC_THIRD_EXOR_FLAME])) + return false; + break; } /* check state required */ @@ -16519,6 +17842,11 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i return false; } + if (require.ap > 0 && status->ap < (unsigned int)require.ap) { + clif_skill_fail(sd,skill_id,USESKILL_FAIL_AP_INSUFFICIENT,0); + return false; + } + if( require.zeny > 0 && sd->status.zeny < require.zeny ) { clif_skill_fail(sd,skill_id,USESKILL_FAIL_MONEY,0); return false; @@ -16545,6 +17873,16 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i } break; + // Skills that requires servants. + case DK_SERVANT_W_SIGN: + case DK_SERVANT_W_PHANTOM: + case DK_SERVANT_W_DEMOL: + if (sd->servantball < require.spiritball) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_SPIRITS, 0); + return false; + } + break; + default: // Skills that require spirit/coin spheres. if (sd->spiritball < require.spiritball) { if ((sd->class_&MAPID_BASEMASK) == MAPID_GUNSLINGER || (sd->class_&MAPID_UPPERMASK) == MAPID_REBELLION) @@ -16585,6 +17923,8 @@ bool skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, sd->state.arrow_atk = skill_get_ammotype(skill_id)?1:0; //Need to do arrow state check. sd->spiritball_old = sd->spiritball; //Need to do Spiritball check. sd->soulball_old = sd->soulball; //Need to do Soulball check. + sd->servantball_old = sd->servantball; //Need to do Servantball check. + sd->abyssball_old = sd->abyssball; //Need to do Abyssball check. return true; } @@ -16604,6 +17944,8 @@ bool skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, case GN_MAKEBOMB: case GN_S_PHARMACY: case GN_CHANGEMATERIAL: + case MT_M_MACHINE: + case BO_BIONIC_PHARMACY: if( sd->menuskill_id != skill_id ) return false; break; @@ -16669,6 +18011,38 @@ bool skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, } } break; + case MT_SUMMON_ABR_BATTLE_WARIOR: + case MT_SUMMON_ABR_DUAL_CANNON: + case MT_SUMMON_ABR_MOTHER_NET: + case MT_SUMMON_ABR_INFINITY: { + uint32 abrs[4] = { MOBID_ABR_BATTLE_WARIOR, MOBID_ABR_DUAL_CANNON, MOBID_ABR_MOTHER_NET, MOBID_ABR_INFINITY }; + int maxcount = skill_get_maxcount(skill_id, skill_lv), c = 0; + + if (battle_config.land_skill_limit && maxcount > 0 && (battle_config.land_skill_limit & BL_PC)) { + map_foreachinmap(skill_check_condition_mob_master_sub, sd->bl.m, BL_MOB, sd->bl.id, abrs[3 - (MT_SUMMON_ABR_INFINITY - skill_id)], skill_id, &c); + if (c >= maxcount) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + return false; + } + } + break; + } + case BO_WOODENWARRIOR: + case BO_WOODEN_FAIRY: + case BO_CREEPER: + case BO_HELLTREE: { + uint32 bionics[5] = { MOBID_BIONIC_WOODENWARRIOR, MOBID_BIONIC_WOODEN_FAIRY, MOBID_BIONIC_CREEPER, MOBID_PORING, MOBID_BIONIC_HELLTREE }; + int maxcount = skill_get_maxcount(skill_id, skill_lv), c = 0; + + if (battle_config.land_skill_limit && maxcount > 0 && (battle_config.land_skill_limit & BL_PC)) { + map_foreachinmap(skill_check_condition_mob_master_sub, sd->bl.m, BL_MOB, sd->bl.id, bionics[4 - (BO_HELLTREE - skill_id)], skill_id, &c); + if (c >= maxcount) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + return false; + } + } + break; + } } status = &sd->battle_status; @@ -16795,8 +18169,8 @@ void skill_consume_requirement(struct map_session_data *sd, uint16 skill_id, uin require.sp = 0; break; } - if(require.hp || require.sp) - status_zap(&sd->bl, require.hp, require.sp); + if(require.hp || require.sp || require.ap) + status_zap(&sd->bl, require.hp, require.sp, require.ap); if(require.spiritball > 0) { // Skills that require certain types of spheres to use switch (skill_id) { // Skills that require soul spheres. @@ -16816,6 +18190,16 @@ void skill_consume_requirement(struct map_session_data *sd, uint16 skill_id, uin pc_delsoulball(sd, require.spiritball, false); break; + // Skills that require servants. + // Note: We don't update the servants display here + // since using these skills auto trigger an animation + // with them in unique ways that makes them vanish. + case DK_SERVANT_W_SIGN: + case DK_SERVANT_W_PHANTOM: + case DK_SERVANT_W_DEMOL: + pc_delservantball( *sd, require.spiritball ); + break; + default: // Skills that require spirit/coin spheres. pc_delspiritball(sd, require.spiritball, 0); break; @@ -16891,7 +18275,7 @@ struct s_skill_condition skill_get_requirement(struct map_session_data* sd, uint struct s_skill_condition req; struct status_data *status; struct status_change *sc; - int i,hp_rate,sp_rate, sp_skill_rate_bonus = 100; + int i,hp_rate,sp_rate, ap_rate, sp_skill_rate_bonus = 100; memset(&req,0,sizeof(req)); @@ -16925,6 +18309,8 @@ struct s_skill_condition skill_get_requirement(struct map_session_data* sd, uint req.sp = skill->require.sp[skill_lv-1]; if((sd->skill_id_old == BD_ENCORE) && skill_id == sd->skill_id_dance) req.sp /= 2; + if ((sd->skill_id_old == TR_RETROSPECTION) && skill_id == sd->skill_id_song) + req.sp -= req.sp * 30 / 100; sp_rate = skill->require.sp_rate[skill_lv-1]; if(sp_rate > 0) req.sp += (status->sp * sp_rate)/100; @@ -16969,8 +18355,17 @@ struct s_skill_condition skill_get_requirement(struct map_session_data* sd, uint #endif if (sc->data[SC_GLOOMYDAY]) req.sp += req.sp * (skill_lv * 10) / 100; + if (sc->data[SC_CRESCIVEBOLT]) + req.sp += req.sp * (20 * sc->data[SC_CRESCIVEBOLT]->val1) / 100; } + req.ap = skill->require.ap[skill_lv - 1]; + ap_rate = skill->require.ap_rate[skill_lv - 1]; + if (ap_rate > 0) + req.ap += (status->ap * ap_rate) / 100; + else + req.ap += (status->max_ap * (-ap_rate)) / 100; + req.zeny = skill->require.zeny[skill_lv-1]; if( sc && sc->data[SC__UNLUCKY] ) { @@ -17153,10 +18548,27 @@ struct s_skill_condition skill_get_requirement(struct map_session_data* sd, uint case LG_RAGEBURST: req.spiritball = sd->spiritball?sd->spiritball:1; break; + case SR_FALLENEMPIRE: + if (sc && (sc->data[SC_FIRST_FAITH_POWER] || sc->data[SC_SECOND_JUDGE] || sc->data[SC_THIRD_EXOR_FLAME])) + req.spiritball = 0; + break; + case SR_TIGERCANNON: + if (sc && sc->data[SC_THIRD_EXOR_FLAME]) + req.spiritball = 0; + break; + case SR_RAMPAGEBLASTER: + case SR_RIDEINLIGHTNING: + if (sc && sc->data[SC_MASSIVE_F_BLASTER]) + req.spiritball = 0; + break; case SR_GATEOFHELL: if( sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE ) req.sp -= req.sp * 10 / 100; break; + case SR_FLASHCOMBO: + if (sc && (sc->data[SC_SECOND_JUDGE] || sc->data[SC_THIRD_EXOR_FLAME])) + req.spiritball = 0; + break; case SO_SUMMON_AGNI: case SO_SUMMON_AQUA: case SO_SUMMON_VENTUS: @@ -17214,6 +18626,10 @@ struct s_skill_condition skill_get_requirement(struct map_session_data* sd, uint req.eqItem.clear(); req.eqItem.shrink_to_fit(); } + if (req_opt & SKILL_REQ_APCOST) + req.ap = 0; + if (req_opt & SKILL_REQ_APRATECOST) + req.ap_rate = 0; } return req; @@ -19474,7 +20890,8 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) break; default: - if (group->val2 == 1 && (group->skill_id == WZ_METEOR || group->skill_id == SU_CN_METEOR || group->skill_id == SU_CN_METEOR2)) { + if (group->val2 == 1 && (group->skill_id == WZ_METEOR || group->skill_id == SU_CN_METEOR || group->skill_id == SU_CN_METEOR2 || + group->skill_id == AG_VIOLENT_QUAKE_ATK || group->skill_id == AG_ALL_BLOOM_ATK || group->skill_id == AG_ALL_BLOOM_ATK2)) { // Deal damage before expiration break; } @@ -19529,12 +20946,17 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) } break; default: - if (group->skill_id == WZ_METEOR || group->skill_id == SU_CN_METEOR || group->skill_id == SU_CN_METEOR2) { + if (group->skill_id == WZ_METEOR || group->skill_id == SU_CN_METEOR || group->skill_id == SU_CN_METEOR2 || + group->skill_id == AG_VIOLENT_QUAKE_ATK || group->skill_id == AG_ALL_BLOOM_ATK || group->skill_id == AG_ALL_BLOOM_ATK2) { if (group->val2 == 0 && (DIFF_TICK(tick, group->tick) >= group->limit - group->interval || DIFF_TICK(tick, group->tick) >= unit->limit - group->interval)) { // Unit will expire the next interval, start dropping Meteor - struct block_list* src; - if ((src = map_id2bl(group->src_id)) != NULL) { - clif_skill_poseffect(src, group->skill_id, group->skill_lv, bl->x, bl->y, tick); + block_list *src = map_id2bl(group->src_id); + + if (src != nullptr) { + if (group->skill_id == AG_VIOLENT_QUAKE_ATK || group->skill_id == AG_ALL_BLOOM_ATK || group->skill_id == AG_ALL_BLOOM_ATK2) + clif_skill_poseffect(src, group->skill_id, -1, bl->x, bl->y, tick); // Don't yell a blank skill name. + else + clif_skill_poseffect(src, group->skill_id, group->skill_lv, bl->x, bl->y, tick); group->val2 = 1; } } @@ -19565,7 +20987,8 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) group->bl_flag= BL_NUL; } } - else if (group->skill_id == WZ_METEOR || group->skill_id == SU_CN_METEOR || group->skill_id == SU_CN_METEOR2) { + else if (group->skill_id == WZ_METEOR || group->skill_id == SU_CN_METEOR || group->skill_id == SU_CN_METEOR2 || + group->skill_id == AG_VIOLENT_QUAKE_ATK || group->skill_id == AG_ALL_BLOOM_ATK || group->skill_id == AG_ALL_BLOOM_ATK2) { skill_delunit(unit); return 0; } @@ -20268,6 +21691,14 @@ bool skill_produce_mix(struct map_session_data *sd, uint16 skill_id, t_itemid na make_per = 100000; // Adjust success back to 100% for crafting } break; + case MT_M_MACHINE: + case BO_BIONIC_PHARMACY: // Difficulty formula unknown. Making it 100% success for now. [Rytech] + if (skill_id == MT_M_MACHINE) + qty = 7 + skill_lv; + else // BO_BIONIC_PHARMACY + qty = 10 + skill_lv; + make_per = 100000; + break; default: if (sd->menuskill_id == AM_PHARMACY && sd->menuskill_val > 10 && sd->menuskill_val <= 20) @@ -20382,7 +21813,7 @@ bool skill_produce_mix(struct map_session_data *sd, uint16 skill_id, t_itemid na tmp_item.amount = 0; for (i = 0; i < qty; i++) { //Apply quantity modifiers. - if ((skill_id == GN_MIX_COOKING || skill_id == GN_MAKEBOMB || skill_id == GN_S_PHARMACY) && make_per > 1) { + if ((skill_id == GN_MIX_COOKING || skill_id == GN_MAKEBOMB || skill_id == GN_S_PHARMACY || skill_id == MT_M_MACHINE || skill_id == BO_BIONIC_PHARMACY) && make_per > 1) { tmp_item.amount = qty; break; } @@ -20493,6 +21924,16 @@ bool skill_produce_mix(struct map_session_data *sd, uint16 skill_id, t_itemid na clif_misceffect(&sd->bl, 5); clif_msg_skill(sd, skill_id, ITEM_PRODUCE_SUCCESS); break; + case MT_M_MACHINE: + clif_produceeffect(sd, 0, nameid); + clif_misceffect(&sd->bl, 3); + clif_msg_skill(sd, skill_id, ITEM_PRODUCE_SUCCESS); + break; + case BO_BIONIC_PHARMACY: + clif_produceeffect(sd, 2, nameid); + clif_misceffect(&sd->bl, 5); + clif_msg_skill(sd, skill_id, ITEM_PRODUCE_SUCCESS); + break; } return true; } @@ -20569,6 +22010,16 @@ bool skill_produce_mix(struct map_session_data *sd, uint16 skill_id, t_itemid na clif_misceffect(&sd->bl,6); clif_msg_skill(sd,skill_id,ITEM_PRODUCE_FAIL); break; + case MT_M_MACHINE: + clif_produceeffect(sd, 1, nameid); + clif_misceffect(&sd->bl, 2); + clif_msg_skill(sd, skill_id, ITEM_PRODUCE_FAIL); + break; + case BO_BIONIC_PHARMACY: + clif_produceeffect(sd, 3, nameid); + clif_misceffect(&sd->bl, 6); + clif_msg_skill(sd, skill_id, ITEM_PRODUCE_FAIL); + break; default: if (skill_produce_db[idx].itemlv > 10 && skill_produce_db[idx].itemlv <= 20 ) { //Cooking items. clif_specialeffect(&sd->bl, EF_COOKING_FAIL, AREA); @@ -21748,6 +23199,8 @@ int skill_disable_check(struct status_change *sc, uint16 skill_id) case SJ_UNIVERSESTANCE: case SJ_SUNSTANCE: case SP_SOULCOLLECT: + case IG_GUARD_STANCE: + case IG_ATTACK_STANCE: if( sc->data[status_skill2sc(skill_id)] ) return 1; break; @@ -22405,6 +23858,14 @@ uint64 SkillDatabase::parseBodyNode(const YAML::Node &node) { memset(skill->require.sp, 0, sizeof(skill->require.sp)); } + if (this->nodeExists(requireNode, "ApCost")) { + if (!this->parseNode("ApCost", "Amount", requireNode, skill->require.ap)) + return 0; + } else { + if (!exists) + memset(skill->require.ap, 0, sizeof(skill->require.ap)); + } + if (this->nodeExists(requireNode, "HpRateCost")) { if (!this->parseNode("HpRateCost", "Amount", requireNode, skill->require.hp_rate)) return 0; @@ -22421,6 +23882,14 @@ uint64 SkillDatabase::parseBodyNode(const YAML::Node &node) { memset(skill->require.sp_rate, 0, sizeof(skill->require.sp_rate)); } + if (this->nodeExists(requireNode, "ApRateCost")) { + if (!this->parseNode("ApRateCost", "Amount", requireNode, skill->require.ap_rate)) + return 0; + } else { + if (!exists) + memset(skill->require.ap_rate, 0, sizeof(skill->require.ap_rate)); + } + if (this->nodeExists(requireNode, "MaxHpTrigger")) { if (!this->parseNode("MaxHpTrigger", "Amount", requireNode, skill->require.mhp)) return 0; @@ -22647,6 +24116,14 @@ uint64 SkillDatabase::parseBodyNode(const YAML::Node &node) { } } + if (this->nodeExists(node, "GiveAp")) { + if (!this->parseNode("GiveAp", "Amount", node, skill->giveap)) + return 0; + } else { + if (!exists) + memset(skill->giveap, 0, sizeof(skill->giveap)); + } + if (this->nodeExists(node, "Unit")) { const YAML::Node &unitNode = node["Unit"]; diff --git a/src/map/skill.hpp b/src/map/skill.hpp index f55c58ba98..12b876ab63 100644 --- a/src/map/skill.hpp +++ b/src/map/skill.hpp @@ -27,7 +27,7 @@ struct skill_unit; struct s_skill_unit_group; struct status_change_entry; -#define MAX_SKILL_PRODUCE_DB 282 /// Max Produce DB +#define MAX_SKILL_PRODUCE_DB 300 /// Max Produce DB #define MAX_PRODUCE_RESOURCE 12 /// Max Produce requirements #define MAX_SKILL_LEVEL 13 /// Max Skill Level (for skill_db storage) #define MAX_MOBSKILL_LEVEL 100 /// Max monster skill level (on skill usage) @@ -125,6 +125,8 @@ enum e_skill_require : uint16 { SKILL_REQ_SPIRITSPHERECOST = 0x400, SKILL_REQ_ITEMCOST = 0x800, SKILL_REQ_EQUIPMENT = 0x1000, + SKILL_REQ_APCOST = 0x2000, + SKILL_REQ_APRATECOST = 0x4000, }; /// Constants for skill cast near NPC. @@ -197,8 +199,10 @@ struct s_skill_condition { int32 hp; ///< HP cost int32 mhp; ///< Max HP to trigger int32 sp; /// SP cost + int32 ap; /// AP cost int32 hp_rate; /// HP cost (%) int32 sp_rate; /// SP cost (%) + int32 ap_rate; /// AP cost (%) int32 zeny; /// Zeny cost int32 weapon; /// Weapon type. Combined bitmask of enum weapon_type (1< { public: - SkillDatabase() : TypesafeCachedYamlDatabase("SKILL_DB", 2, 1) { + SkillDatabase() : TypesafeCachedYamlDatabase("SKILL_DB", 3, 1) { } @@ -517,6 +525,7 @@ int skill_get_castcancel( uint16 skill_id ); int skill_get_maxcount( uint16 skill_id ,uint16 skill_lv ); int skill_get_blewcount( uint16 skill_id ,uint16 skill_lv ); int skill_get_cooldown( uint16 skill_id, uint16 skill_lv ); +int skill_get_giveap( uint16 skill_id, uint16 skill_lv ); int skill_get_unit_target( uint16 skill_id ); #define skill_get_nk(skill_id, nk) skill_get_nk_(skill_id, { nk }) bool skill_get_nk_(uint16 skill_id, std::vector nk); @@ -529,9 +538,11 @@ int skill_get_unit_range(uint16 skill_id, uint16 skill_lv); int skill_get_hp( uint16 skill_id ,uint16 skill_lv ); int skill_get_mhp( uint16 skill_id ,uint16 skill_lv ); int skill_get_sp( uint16 skill_id ,uint16 skill_lv ); +int skill_get_ap( uint16 skill_id, uint16 skill_lv ); int skill_get_status_count( uint16 skill_id ); int skill_get_hp_rate( uint16 skill_id, uint16 skill_lv ); int skill_get_sp_rate( uint16 skill_id, uint16 skill_lv ); +int skill_get_ap_rate( uint16 skill_id, uint16 skill_lv ); int skill_get_zeny( uint16 skill_id ,uint16 skill_lv ); int skill_get_weapontype( uint16 skill_id ); int skill_get_ammotype( uint16 skill_id ); @@ -1983,6 +1994,213 @@ enum e_skill { NV_TRANSCENDENCE, WL_READING_SB_READING, + DK_SERVANTWEAPON = 5201, + DK_SERVANTWEAPON_ATK, + DK_SERVANT_W_SIGN, + DK_SERVANT_W_PHANTOM, + DK_SERVANT_W_DEMOL, + DK_CHARGINGPIERCE, + DK_TWOHANDDEF, + DK_HACKANDSLASHER, + DK_HACKANDSLASHER_ATK, + DK_DRAGONIC_AURA, + DK_MADNESS_CRUSHER, + DK_VIGOR, + DK_STORMSLASH, + + AG_DEADLY_PROJECTION, + AG_DESTRUCTIVE_HURRICANE, + AG_RAIN_OF_CRYSTAL, + AG_MYSTERY_ILLUSION, + AG_VIOLENT_QUAKE, + AG_VIOLENT_QUAKE_ATK, + AG_SOUL_VC_STRIKE, + AG_STRANTUM_TREMOR, + AG_ALL_BLOOM, + AG_ALL_BLOOM_ATK, + AG_ALL_BLOOM_ATK2, + AG_CRYSTAL_IMPACT, + AG_CRYSTAL_IMPACT_ATK, + AG_TORNADO_STORM, + AG_TWOHANDSTAFF, + AG_FLORAL_FLARE_ROAD, + AG_ASTRAL_STRIKE, + AG_ASTRAL_STRIKE_ATK, + AG_CLIMAX, + AG_ROCK_DOWN, + AG_STORM_CANNON, + AG_CRIMSON_ARROW, + AG_CRIMSON_ARROW_ATK, + AG_FROZEN_SLASH, + + IQ_POWERFUL_FAITH, + IQ_FIRM_FAITH, + IQ_WILL_OF_FAITH, + IQ_OLEUM_SANCTUM, + IQ_SINCERE_FAITH, + IQ_MASSIVE_F_BLASTER, + IQ_EXPOSION_BLASTER, + IQ_FIRST_BRAND, + IQ_FIRST_FAITH_POWER, + IQ_JUDGE, + IQ_SECOND_FLAME, + IQ_SECOND_FAITH, + IQ_SECOND_JUDGEMENT, + IQ_THIRD_PUNISH, + IQ_THIRD_FLAME_BOMB, + IQ_THIRD_CONSECRATION, + IQ_THIRD_EXOR_FLAME, + + IG_GUARD_STANCE, + IG_GUARDIAN_SHIELD, + IG_REBOUND_SHIELD, + IG_SHIELD_MASTERY, + IG_SPEAR_SWORD_M, + IG_ATTACK_STANCE, + IG_ULTIMATE_SACRIFICE, + IG_HOLY_SHIELD, + IG_GRAND_JUDGEMENT, + IG_JUDGEMENT_CROSS, + IG_SHIELD_SHOOTING, + IG_OVERSLASH, + IG_CROSS_RAIN, + + CD_REPARATIO, + CD_MEDIALE_VOTUM, + CD_MACE_BOOK_M, + CD_ARGUTUS_VITA, + CD_ARGUTUS_TELUM, + CD_ARBITRIUM, + CD_ARBITRIUM_ATK, + CD_PRESENS_ACIES, + CD_FIDUS_ANIMUS, + CD_EFFLIGO, + CD_COMPETENTIA, + CD_PNEUMATICUS_PROCELLA, + CD_DILECTIO_HEAL, + CD_RELIGIO, + CD_BENEDICTUM, + CD_PETITIO, + CD_FRAMEN, + + SHC_SHADOW_EXCEED, + SHC_DANCING_KNIFE, + SHC_SAVAGE_IMPACT, + SHC_SHADOW_SENSE, + SHC_ETERNAL_SLASH, + SHC_POTENT_VENOM, + SHC_SHADOW_STAB, + SHC_IMPACT_CRATER, + SHC_ENCHANTING_SHADOW, + SHC_FATAL_SHADOW_CROW, + + MT_AXE_STOMP, + MT_RUSH_QUAKE, + MT_M_MACHINE, + MT_A_MACHINE, + MT_D_MACHINE, + MT_TWOAXEDEF, + MT_ABR_M, + MT_SUMMON_ABR_BATTLE_WARIOR, + MT_SUMMON_ABR_DUAL_CANNON, + MT_SUMMON_ABR_MOTHER_NET, + MT_SUMMON_ABR_INFINITY, + + AG_DESTRUCTIVE_HURRICANE_CLIMAX, + BO_ACIDIFIED_ZONE_WATER_ATK, + BO_ACIDIFIED_ZONE_GROUND_ATK, + BO_ACIDIFIED_ZONE_WIND_ATK, + BO_ACIDIFIED_ZONE_FIRE_ATK, + + ABC_DAGGER_AND_BOW_M, + ABC_MAGIC_SWORD_M, + ABC_STRIP_SHADOW, + ABC_ABYSS_DAGGER, + ABC_UNLUCKY_RUSH, + ABC_CHAIN_REACTION_SHOT, + ABC_FROM_THE_ABYSS, + ABC_ABYSS_SLAYER, + ABC_ABYSS_STRIKE, + ABC_DEFT_STAB, + ABC_ABYSS_SQUARE, + ABC_FRENZY_SHOT, + + WH_ADVANCED_TRAP, + WH_WIND_SIGN, + WH_NATUREFRIENDLY, + WH_HAWKRUSH, + WH_HAWK_M, + WH_CALAMITYGALE, + WH_HAWKBOOMERANG, + WH_GALESTORM, + WH_DEEPBLINDTRAP, + WH_SOLIDTRAP, + WH_SWIFTTRAP, + WH_CRESCIVE_BOLT, + WH_FLAMETRAP, + + BO_BIONIC_PHARMACY, + BO_BIONICS_M, + BO_THE_WHOLE_PROTECTION, + BO_ADVANCE_PROTECTION, + BO_ACIDIFIED_ZONE_WATER, + BO_ACIDIFIED_ZONE_GROUND, + BO_ACIDIFIED_ZONE_WIND, + BO_ACIDIFIED_ZONE_FIRE, + BO_WOODENWARRIOR, + BO_WOODEN_FAIRY, + BO_CREEPER, + BO_RESEARCHREPORT, + BO_HELLTREE, + + TR_STAGE_MANNER, + TR_RETROSPECTION, + TR_MYSTIC_SYMPHONY, + TR_KVASIR_SONATA, + TR_ROSEBLOSSOM, + TR_ROSEBLOSSOM_ATK, + TR_RHYTHMSHOOTING, + TR_METALIC_FURY, + TR_SOUNDBLEND, + TR_GEF_NOCTURN, + TR_ROKI_CAPRICCIO, + TR_AIN_RHAPSODY, + TR_MUSICAL_INTERLUDE, + TR_JAWAII_SERENADE, + TR_NIPELHEIM_REQUIEM, + TR_PRON_MARCH, + + EM_MAGIC_BOOK_M, + EM_SPELL_ENCHANTING, + EM_ACTIVITY_BURN, + EM_INCREASING_ACTIVITY, + EM_DIAMOND_STORM, + EM_LIGHTNING_LAND, + EM_VENOM_SWAMP, + EM_CONFLAGRATION, + EM_TERRA_DRIVE, + EM_ELEMENTAL_SPIRIT_M, + EM_SUMMON_ELEMENTAL_ARDOR, + EM_SUMMON_ELEMENTAL_DILUVIO, + EM_SUMMON_ELEMENTAL_PROCELLA, + EM_SUMMON_ELEMENTAL_TERREMOTUS, + EM_SUMMON_ELEMENTAL_SERPENS, + EM_ELEMENTAL_BUSTER, + EM_ELEMENTAL_VEIL, + + ABC_CHAIN_REACTION_SHOT_ATK, + ABC_FROM_THE_ABYSS_ATK, + BO_WOODEN_THROWROCK, + BO_WOODEN_ATTACK, + BO_HELL_HOWLING, + BO_HELL_DUSTY, + BO_FAIRY_DUSTY, + EM_ELEMENTAL_BUSTER_FIRE, + EM_ELEMENTAL_BUSTER_WATER, + EM_ELEMENTAL_BUSTER_WIND, + EM_ELEMENTAL_BUSTER_GROUND, + EM_ELEMENTAL_BUSTER_POISON, + HLIF_HEAL = 8001, HLIF_AVOID, HLIF_BRAIN, @@ -2111,6 +2329,27 @@ enum e_skill { EL_ROCK_CRUSHER, EL_ROCK_CRUSHER_ATK, EL_STONE_RAIN, + EM_EL_FLAMETECHNIC, + EM_EL_FLAMEARMOR, + EM_EL_FLAMEROCK, + EM_EL_COLD_FORCE, + EM_EL_CRYSTAL_ARMOR, + EM_EL_AGE_OF_ICE, + EM_EL_GRACE_BREEZE, + EM_EL_EYES_OF_STORM, + EM_EL_STORM_WIND, + EM_EL_EARTH_CARE, + EM_EL_STRONG_PROTECTION, + EM_EL_AVALANCHE, + EM_EL_DEEP_POISONING, + EM_EL_POISON_SHIELD, + EM_EL_DEADLY_POISON, + + ABR_BATTLE_BUSTER = 8601, + ABR_DUAL_CANNON_FIRE, + ABR_NET_REPAIR, + ABR_NET_SUPPORT, + ABR_INFINITY_BUSTER, }; /// The client view ids for land skills. @@ -2256,7 +2495,34 @@ enum e_skill_unit_id : uint16 { UNT_CATNIPPOWDER, UNT_NYANGGRASS, - UNT_CREATINGSTAR, + UNT_CREATINGSTAR,// Should be GROUNDDRIFT_NEUTRAL + UNT_DUMMY_0,// CREATINGSTAR + + UNT_RAIN_OF_CRYSTAL, + UNT_MYSTERY_ILLUSION, + UNT_UNKNOWN_1,// No idea. Makes a old style plant appear for a second. + UNT_STRANTUM_TREMOR, + UNT_VIOLENT_QUAKE, + UNT_ALL_BLOOM, + UNT_TORNADO_STORM, + UNT_FLORAL_FLARE_ROAD, + UNT_ASTRAL_STRIKE, + UNT_CROSS_RAIN, + UNT_PNEUMATICUS_PROCELLA, + UNT_ABYSS_SQUARE, + UNT_ACIDIFIED_ZONE_WATER, + UNT_ACIDIFIED_ZONE_GROUND, + UNT_ACIDIFIED_ZONE_WIND, + UNT_ACIDIFIED_ZONE_FIRE, + UNT_LIGHTNING_LAND, + UNT_VENOM_SWAMP, + UNT_CONFLAGRATION, + + // Skill units outside the normal unit range. + UNT_DEEPBLINDTRAP = 20852, + UNT_SOLIDTRAP, + UNT_SWIFTTRAP, + UNT_FLAMETRAP, /** * Guild Auras @@ -2373,6 +2639,7 @@ int skill_get_time3(struct map_data *mapdata, uint16 skill_id, uint16 skill_lv); #define SKILL_CHK_HOMUN(skill_id) ( (skill_id) >= HM_SKILLBASE && (skill_id) < HM_SKILLBASE+MAX_HOMUNSKILL ) #define SKILL_CHK_MERC(skill_id) ( (skill_id) >= MC_SKILLBASE && (skill_id) < MC_SKILLBASE+MAX_MERCSKILL ) #define SKILL_CHK_ELEM(skill_id) ( (skill_id) >= EL_SKILLBASE && (skill_id) < EL_SKILLBASE+MAX_ELEMENTALSKILL ) +#define SKILL_CHK_ABR(skill_id) ( (skill_id) >= ABR_SKILLBASE && (skill_id) < ABR_SKILLBASE+MAX_ABRSKILL ) #define SKILL_CHK_GUILD(skill_id) ( (skill_id) >= GD_SKILLBASE && (skill_id) < GD_SKILLBASE+MAX_GUILDSKILL ) #endif /* SKILL_HPP */ diff --git a/src/map/status.cpp b/src/map/status.cpp index ec0a85d0e6..9d25faebf8 100644 --- a/src/map/status.cpp +++ b/src/map/status.cpp @@ -61,7 +61,7 @@ unsigned int SCDisabled[SC_MAX]; ///< List of disabled SC on map zones. [Cydh] sc_type SkillStatusChangeTable[MAX_SKILL]; int StatusIconChangeTable[SC_MAX]; -unsigned int StatusChangeFlagTable[SC_MAX]; +uint64 StatusChangeFlagTable[SC_MAX]; int StatusSkillChangeTable[SC_MAX]; int StatusRelevantBLTypes[EFST_MAX]; unsigned int StatusChangeStateTable[SC_MAX]; @@ -73,6 +73,12 @@ static unsigned short status_calc_vit(struct block_list *,struct status_change * static unsigned short status_calc_int(struct block_list *,struct status_change *,int); static unsigned short status_calc_dex(struct block_list *,struct status_change *,int); static unsigned short status_calc_luk(struct block_list *,struct status_change *,int); +static unsigned short status_calc_pow(struct block_list *, struct status_change *, int); +static unsigned short status_calc_sta(struct block_list *, struct status_change *, int); +static unsigned short status_calc_wis(struct block_list *, struct status_change *, int); +static unsigned short status_calc_spl(struct block_list *, struct status_change *, int); +static unsigned short status_calc_con(struct block_list *, struct status_change *, int); +static unsigned short status_calc_crt(struct block_list *, struct status_change *, int); static unsigned short status_calc_batk(struct block_list *,struct status_change *,int); static unsigned short status_calc_watk(struct block_list *,struct status_change *,int); static unsigned short status_calc_matk(struct block_list *,struct status_change *,int); @@ -91,8 +97,15 @@ static unsigned short status_calc_dmotion(struct block_list *bl, struct status_c static short status_calc_aspd(struct block_list *bl, struct status_change *sc, bool fixed); #endif static short status_calc_fix_aspd(struct block_list *bl, struct status_change *sc, int); +static signed short status_calc_patk(struct block_list *, struct status_change *, int); +static signed short status_calc_smatk(struct block_list *, struct status_change *, int); +static signed short status_calc_res(struct block_list *, struct status_change *, int); +static signed short status_calc_mres(struct block_list *, struct status_change *, int); +static signed short status_calc_hplus(struct block_list *, struct status_change *, int); +static signed short status_calc_crate(struct block_list *, struct status_change *, int); static unsigned int status_calc_maxhp(struct block_list *bl, uint64 maxhp); static unsigned int status_calc_maxsp(struct block_list *bl, uint64 maxsp); +static unsigned int status_calc_maxap(struct block_list *bl, uint64 maxap); static unsigned char status_calc_element(struct block_list *bl, struct status_change *sc, int element); static unsigned char status_calc_element_lv(struct block_list *bl, struct status_change *sc, int lv); static int status_calc_mode(struct block_list *bl, struct status_change *sc, int mode); @@ -101,7 +114,9 @@ static unsigned short status_calc_ematk(struct block_list *,struct status_change #endif static int status_get_hpbonus(struct block_list *bl, enum e_status_bonus type); static int status_get_spbonus(struct block_list *bl, enum e_status_bonus type); +static int status_get_apbonus(struct block_list *bl, enum e_status_bonus type); static unsigned int status_calc_maxhpsp_pc(struct map_session_data* sd, unsigned int stat, bool isHP); +static unsigned int status_calc_maxap_pc(struct map_session_data* sd); static int status_get_sc_interval(enum sc_type type); static bool status_change_isDisabledOnMap_(sc_type type, bool mapIsVS, bool mapIsPVP, bool mapIsGVG, bool mapIsBG, unsigned int mapZone, bool mapIsTE); @@ -571,7 +586,7 @@ int status_sc2skill(sc_type sc) * @param sc The status to look up * @return The scb_flag registered for this status (see enum scb_flag) */ -unsigned int status_sc2scb_flag(sc_type sc) +uint64 status_sc2scb_flag(sc_type sc) { if( sc < 0 || sc >= SC_MAX ) { ShowError("status_sc2scb_flag: Unsupported status change id %d\n", sc); @@ -600,7 +615,7 @@ int status_type2relevant_bl_types(int type) // Indicates that the status displays a visual effect for the affected unit, and should be sent to the client for all supported units #define set_sc_with_vfx(skill, sc, icon, flag) set_sc((skill), (sc), (icon), (flag)); if((icon) < EFST_MAX) StatusRelevantBLTypes[(icon)] |= BL_SCEFFECT -static void set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int flag) +static void set_sc(uint16 skill_id, sc_type sc, int icon, uint64 flag) { uint16 idx = skill_get_index(skill_id); if( idx == 0 ) { @@ -622,7 +637,7 @@ static void set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int flag) SkillStatusChangeTable[idx] = sc; } -static void set_sc_with_vfx_noskill(sc_type sc, int icon, unsigned flag) { +static void set_sc_with_vfx_noskill(sc_type sc, int icon, uint64 flag) { if (sc > SC_NONE && sc < SC_MAX) { if (StatusIconChangeTable[sc] == EFST_BLANK) StatusIconChangeTable[sc] = icon; @@ -1443,6 +1458,135 @@ void initChangeTables(void) #ifdef RENEWAL set_sc( NV_HELPANGEL , SC_HELPANGEL , EFST_HELPANGEL , SCB_NONE ); + + // Dragon Knight + set_sc( DK_SERVANTWEAPON , SC_SERVANTWEAPON , EFST_SERVANTWEAPON , SCB_NONE ); + set_sc_with_vfx( DK_SERVANT_W_SIGN , SC_SERVANT_SIGN , EFST_SERVANT_SIGN , SCB_NONE ); + set_sc_with_vfx( DK_SERVANT_W_PHANTOM, SC_HANDICAPSTATE_DEEPBLIND, EFST_HANDICAPSTATE_DEEPBLIND, SCB_FLEE|SCB_FLEE2 ); + set_sc( DK_CHARGINGPIERCE , SC_CHARGINGPIERCE , EFST_CHARGINGPIERCE , SCB_NONE ); + set_sc_with_vfx( DK_DRAGONIC_AURA , SC_DRAGONIC_AURA , EFST_DRAGONIC_AURA , SCB_NONE ); + set_sc_with_vfx( DK_VIGOR , SC_VIGOR , EFST_VIGOR , SCB_ALL ); + + // Arch Mage + set_sc_with_vfx( AG_DEADLY_PROJECTION , SC_DEADLY_DEFEASANCE, EFST_DEADLY_DEFEASANCE, SCB_ALL ); + set_sc( AG_DESTRUCTIVE_HURRICANE, SC_CLIMAX_DES_HU , EFST_CLIMAX_DES_HU , SCB_MATK ); + set_sc( AG_VIOLENT_QUAKE , SC_CLIMAX_EARTH , EFST_CLIMAX_EARTH , SCB_ALL ); + set_sc( AG_ALL_BLOOM , SC_CLIMAX_BLOOM , EFST_CLIMAX_BLOOM , SCB_ALL ); + set_sc( AG_CRYSTAL_IMPACT , SC_CLIMAX_CRYIMP , EFST_CLIMAX_CRYIMP , SCB_ALL ); + set_sc_with_vfx( AG_CLIMAX , SC_CLIMAX , EFST_CLIMAX , SCB_NONE ); + + // Windhawk + set_sc_with_vfx( WH_WIND_SIGN , SC_WINDSIGN , EFST_WINDSIGN , SCB_NONE ); + set_sc_with_vfx( WH_CALAMITYGALE , SC_CALAMITYGALE , EFST_CALAMITYGALE , SCB_NONE ); + set_sc ( WH_CRESCIVE_BOLT, SC_CRESCIVEBOLT , EFST_CRESCIVEBOLT , SCB_NONE ); + set_sc_with_vfx( WH_DEEPBLINDTRAP, SC_HANDICAPSTATE_DEEPBLIND , EFST_HANDICAPSTATE_DEEPBLIND , SCB_FLEE|SCB_FLEE2 ); + set_sc_with_vfx( WH_SOLIDTRAP , SC_HANDICAPSTATE_CRYSTALLIZATION, EFST_HANDICAPSTATE_CRYSTALLIZATION, SCB_MDEF|SCB_DEF_ELE); + set_sc_with_vfx( WH_SWIFTTRAP , SC_HANDICAPSTATE_LIGHTNINGSTRIKE, EFST_HANDICAPSTATE_LIGHTNINGSTRIKE, SCB_DEF_ELE); + set_sc_with_vfx( WH_FLAMETRAP , SC_HANDICAPSTATE_CONFLAGRATION , EFST_HANDICAPSTATE_CONFLAGRATION , SCB_NONE ); + + // Cardinal + set_sc_with_vfx( CD_MEDIALE_VOTUM, SC_MEDIALE , EFST_MEDIALE , SCB_NONE ); + set_sc( CD_ARGUTUS_VITA , SC_A_VITA , EFST_A_VITA , SCB_NONE ); + set_sc( CD_ARGUTUS_TELUM, SC_A_TELUM , EFST_A_TELUM , SCB_NONE ); + set_sc_with_vfx( CD_ARBITRIUM , SC_HANDICAPSTATE_DEEPSILENCE, EFST_HANDICAPSTATE_DEEPSILENCE, SCB_ASPD); + set_sc_with_vfx( CD_PRESENS_ACIES, SC_PRE_ACIES , EFST_PRE_ACIES , SCB_CRATE ); + set_sc_with_vfx( CD_COMPETENTIA , SC_COMPETENTIA , EFST_COMPETENTIA , SCB_PATK|SCB_SMATK ); + set_sc_with_vfx( CD_RELIGIO , SC_RELIGIO , EFST_RELIGIO , SCB_STA|SCB_WIS|SCB_SPL ); + set_sc_with_vfx( CD_BENEDICTUM , SC_BENEDICTUM , EFST_BENEDICTUM , SCB_POW|SCB_CON|SCB_CRT ); + + // Meister + set_sc( MT_AXE_STOMP , SC_AXE_STOMP , EFST_AXE_STOMP , SCB_NONE ); + set_sc_with_vfx( MT_A_MACHINE , SC_A_MACHINE , EFST_A_MACHINE , SCB_NONE ); + set_sc_with_vfx( MT_D_MACHINE , SC_D_MACHINE , EFST_D_MACHINE , SCB_DEF|SCB_RES ); + set_sc( MT_SUMMON_ABR_BATTLE_WARIOR, SC_ABR_BATTLE_WARIOR, EFST_ABR_BATTLE_WARIOR, SCB_NONE ); + set_sc( MT_SUMMON_ABR_DUAL_CANNON , SC_ABR_DUAL_CANNON , EFST_ABR_DUAL_CANNON , SCB_NONE ); + set_sc( MT_SUMMON_ABR_MOTHER_NET , SC_ABR_MOTHER_NET , EFST_ABR_MOTHER_NET , SCB_NONE ); + set_sc( MT_SUMMON_ABR_INFINITY , SC_ABR_INFINITY , EFST_ABR_INFINITY , SCB_NONE ); + + // Shadow Cross + set_sc_with_vfx( SHC_SHADOW_EXCEED , SC_SHADOW_EXCEED , EFST_SHADOW_EXCEED , SCB_NONE ); + set_sc_with_vfx( SHC_DANCING_KNIFE , SC_DANCING_KNIFE , EFST_DANCING_KNIFE , SCB_NONE ); + set_sc_with_vfx( SHC_ETERNAL_SLASH , SC_E_SLASH_COUNT , EFST_E_SLASH_COUNT , SCB_NONE ); + set_sc( SHC_POTENT_VENOM , SC_POTENT_VENOM , EFST_POTENT_VENOM , SCB_NONE ); + set_sc( SHC_IMPACT_CRATER , SC_WEAPONBLOCK_ON, EFST_WEAPONBLOCK_ON, SCB_NONE ); + set_sc( SHC_ENCHANTING_SHADOW, SC_SHADOW_WEAPON , EFST_SHADOW_WEAPON , SCB_NONE ); + set_sc_with_vfx( SHC_FATAL_SHADOW_CROW, SC_DARKCROW , EFST_DARKCROW , SCB_NONE ); + + // Imperial Guard + set_sc( IG_GUARD_STANCE , SC_GUARD_STANCE , EFST_GUARD_STANCE , SCB_WATK|SCB_DEF ); + set_sc( IG_GUARDIAN_SHIELD , SC_GUARDIAN_S , EFST_GUARDIAN_S , SCB_NONE ); + set_sc( IG_REBOUND_SHIELD , SC_REBOUND_S , EFST_REBOUND_S , SCB_NONE ); + set_sc( IG_ATTACK_STANCE , SC_ATTACK_STANCE, EFST_ATTACK_STANCE, SCB_WATK|SCB_DEF ); + set_sc( IG_ULTIMATE_SACRIFICE, SC_ULTIMATE_S , EFST_ULTIMATE_S , SCB_NONE ); + set_sc_with_vfx( IG_HOLY_SHIELD , SC_HOLY_S , EFST_HOLY_S , SCB_ALL ); + set_sc_with_vfx( IG_GRAND_JUDGEMENT , SC_SPEAR_SCAR , EFST_SPEAR_SCAR , SCB_NONE ); + set_sc( IG_SHIELD_SHOOTING , SC_SHIELD_POWER , EFST_SHIELD_POWER , SCB_NONE ); + + // Elemental Master + set_sc( EM_SPELL_ENCHANTING , SC_SPELL_ENCHANTING , EFST_SPELL_ENCHANTING , SCB_SMATK ); + set_sc_with_vfx( EM_DIAMOND_STORM , SC_HANDICAPSTATE_FROSTBITE , EFST_HANDICAPSTATE_FROSTBITE , SCB_DEF|SCB_MDEF|SCB_DEF_ELE); + set_sc_with_vfx( EM_LIGHTNING_LAND , SC_HANDICAPSTATE_LIGHTNINGSTRIKE, EFST_HANDICAPSTATE_LIGHTNINGSTRIKE, SCB_DEF_ELE); + set_sc_with_vfx( EM_VENOM_SWAMP , SC_HANDICAPSTATE_DEADLYPOISON , EFST_HANDICAPSTATE_DEADLYPOISON , SCB_DEF); + set_sc_with_vfx( EM_CONFLAGRATION , SC_HANDICAPSTATE_CONFLAGRATION , EFST_HANDICAPSTATE_CONFLAGRATION , SCB_NONE ); + set_sc_with_vfx( EM_TERRA_DRIVE , SC_HANDICAPSTATE_CRYSTALLIZATION, EFST_HANDICAPSTATE_CRYSTALLIZATION, SCB_MDEF|SCB_DEF_ELE); + set_sc( EM_SUMMON_ELEMENTAL_ARDOR , SC_SUMMON_ELEMENTAL_ARDOR , EFST_SUMMON_ELEMENTAL_ARDOR , SCB_NONE ); + set_sc( EM_SUMMON_ELEMENTAL_DILUVIO , SC_SUMMON_ELEMENTAL_DILUVIO , EFST_SUMMON_ELEMENTAL_DILUVIO , SCB_NONE ); + set_sc( EM_SUMMON_ELEMENTAL_PROCELLA , SC_SUMMON_ELEMENTAL_PROCELLA , EFST_SUMMON_ELEMENTAL_PROCELLA , SCB_NONE ); + set_sc( EM_SUMMON_ELEMENTAL_TERREMOTUS, SC_SUMMON_ELEMENTAL_TERREMOTUS , EFST_SUMMON_ELEMENTAL_TERREMOTUS , SCB_NONE ); + set_sc( EM_SUMMON_ELEMENTAL_SERPENS , SC_SUMMON_ELEMENTAL_SERPENS , EFST_SUMMON_ELEMENTAL_SERPENS , SCB_NONE ); + set_sc_with_vfx( EM_ELEMENTAL_VEIL , SC_ELEMENTAL_VEIL , EFST_ELEMENTAL_VEIL , SCB_NONE ); + + // Troubadour/Trouvere + set_sc_with_vfx( TR_MYSTIC_SYMPHONY , SC_MYSTIC_SYMPHONY , EFST_MYSTIC_SYMPHONY , SCB_NONE ); + set_sc( TR_KVASIR_SONATA , SC_KVASIR_SONATA , EFST_KVASIR_SONATA , SCB_NONE ); + set_sc( TR_ROSEBLOSSOM , SC_ROSEBLOSSOM , EFST_ROSEBLOSSOM , SCB_NONE ); + set_sc_with_vfx( TR_SOUNDBLEND , SC_SOUNDBLEND , EFST_SOUNDBLEND , SCB_NONE ); + set_sc( TR_GEF_NOCTURN , SC_GEF_NOCTURN , EFST_GEF_NOCTURN , SCB_MRES ); + set_sc( TR_AIN_RHAPSODY , SC_AIN_RHAPSODY , EFST_AIN_RHAPSODY , SCB_RES ); + set_sc( TR_MUSICAL_INTERLUDE, SC_MUSICAL_INTERLUDE, EFST_MUSICAL_INTERLUDE, SCB_RES ); + set_sc( TR_JAWAII_SERENADE , SC_JAWAII_SERENADE , EFST_JAWAII_SERENADE , SCB_SMATK ); + set_sc( TR_PRON_MARCH , SC_PRON_MARCH , EFST_PRON_MARCH , SCB_PATK ); + + // Inquisitor + set_sc( IQ_POWERFUL_FAITH , SC_POWERFUL_FAITH , EFST_POWERFUL_FAITH , SCB_WATK|SCB_PATK ); + set_sc( IQ_FIRM_FAITH , SC_FIRM_FAITH , EFST_FIRM_FAITH , SCB_MAXHP|SCB_RES ); + set_sc_with_vfx( IQ_OLEUM_SANCTUM , SC_HOLY_OIL , EFST_HOLY_OIL , SCB_NONE ); + set_sc( IQ_SINCERE_FAITH , SC_SINCERE_FAITH , EFST_SINCERE_FAITH , SCB_ALL ); + set_sc( IQ_MASSIVE_F_BLASTER, SC_MASSIVE_F_BLASTER, EFST_MASSIVE_F_BLASTER, SCB_NONE ); + set_sc_with_vfx( IQ_FIRST_BRAND , SC_FIRST_BRAND , EFST_FIRST_BRAND , SCB_NONE ); + set_sc_with_vfx( IQ_FIRST_FAITH_POWER, SC_FIRST_FAITH_POWER, EFST_FIRST_FAITH_POWER, SCB_NONE ); + set_sc_with_vfx( IQ_JUDGE , SC_SECOND_JUDGE , EFST_SECOND_JUDGE , SCB_NONE ); + set_sc_with_vfx( IQ_SECOND_FLAME , SC_SECOND_BRAND , EFST_SECOND_BRAND , SCB_NONE ); + set_sc_with_vfx( IQ_SECOND_FAITH , SC_SECOND_BRAND , EFST_SECOND_BRAND , SCB_NONE ); + set_sc_with_vfx( IQ_SECOND_JUDGEMENT , SC_SECOND_BRAND , EFST_SECOND_BRAND , SCB_NONE ); + set_sc_with_vfx( IQ_THIRD_EXOR_FLAME , SC_THIRD_EXOR_FLAME , EFST_THIRD_EXOR_FLAME , SCB_NONE ); + + // Biolo + set_sc( BO_ADVANCE_PROTECTION, SC_PROTECTSHADOWEQUIP , EFST_PROTECTSHADOWEQUIP, SCB_NONE ); + set_sc( BO_WOODENWARRIOR , SC_BIONIC_WOODENWARRIOR, EFST_BLANK , SCB_NONE ); + set_sc( BO_WOODEN_FAIRY , SC_BIONIC_WOODEN_FAIRY , EFST_BLANK , SCB_NONE ); + set_sc( BO_CREEPER , SC_BIONIC_CREEPER , EFST_BLANK , SCB_NONE ); + set_sc( BO_RESEARCHREPORT , SC_RESEARCHREPORT , EFST_RESEARCHREPORT , SCB_NONE ); + set_sc( BO_HELLTREE , SC_BIONIC_HELLTREE , EFST_BLANK , SCB_NONE ); + + // Abyss Chaser + set_sc( ABC_STRIP_SHADOW , SC_SHADOW_STRIP , EFST_SHADOW_STRIP , SCB_RES|SCB_MRES ); + set_sc( ABC_ABYSS_DAGGER , SC_ABYSS_DAGGER , EFST_ABYSS_DAGGER , SCB_NONE ); + set_sc_with_vfx( ABC_UNLUCKY_RUSH , SC_HANDICAPSTATE_MISFORTUNE, EFST_HANDICAPSTATE_MISFORTUNE, SCB_HIT); + set_sc( ABC_FROM_THE_ABYSS, SC_ABYSSFORCEWEAPON , EFST_ABYSSFORCEWEAPON , SCB_NONE ); + set_sc_with_vfx( ABC_ABYSS_SLAYER , SC_ABYSS_SLAYER , EFST_ABYSS_SLAYER , SCB_HIT|SCB_PATK|SCB_SMATK ); + + // Super Elementals + set_sc( EM_EL_FLAMETECHNIC , SC_FLAMETECHNIC_OPTION , EFST_FLAMETECHNIC_OPTION , SCB_NONE ); + set_sc( EM_EL_FLAMEARMOR , SC_FLAMEARMOR_OPTION , EFST_FLAMEARMOR_OPTION , SCB_ALL ); + set_sc( EM_EL_COLD_FORCE , SC_COLD_FORCE_OPTION , EFST_COLD_FORCE_OPTION , SCB_NONE ); + set_sc( EM_EL_CRYSTAL_ARMOR , SC_CRYSTAL_ARMOR_OPTION , EFST_CRYSTAL_ARMOR_OPTION , SCB_ALL ); + set_sc( EM_EL_GRACE_BREEZE , SC_GRACE_BREEZE_OPTION , EFST_GRACE_BREEZE_OPTION , SCB_NONE ); + set_sc( EM_EL_EYES_OF_STORM , SC_EYES_OF_STORM_OPTION , EFST_EYES_OF_STORM_OPTION , SCB_ALL ); + set_sc( EM_EL_EARTH_CARE , SC_EARTH_CARE_OPTION , EFST_EARTH_CARE_OPTION , SCB_NONE ); + set_sc( EM_EL_STRONG_PROTECTION, SC_STRONG_PROTECTION_OPTION, EFST_STRONG_PROTECTION_OPTION, SCB_ALL ); + set_sc( EM_EL_DEEP_POISONING , SC_DEEP_POISONING_OPTION , EFST_DEEP_POISONING_OPTION , SCB_NONE ); + set_sc( EM_EL_POISON_SHIELD , SC_POISON_SHIELD_OPTION , EFST_POISON_SHIELD_OPTION , SCB_ALL ); #endif /* Storing the target job rather than simply SC_SPIRIT simplifies code later on */ @@ -1764,6 +1908,23 @@ void initChangeTables(void) StatusIconChangeTable[SC_PACKING_ENVELOPE9] = EFST_PACKING_ENVELOPE9; StatusIconChangeTable[SC_PACKING_ENVELOPE10] = EFST_PACKING_ENVELOPE10; + // 4th Jobs + StatusIconChangeTable[SC_CHARGINGPIERCE_COUNT] = EFST_CHARGINGPIERCE_COUNT; + StatusIconChangeTable[SC_SHADOW_SCAR] = EFST_SHADOW_SCAR; + StatusIconChangeTable[SC_BO_HELL_DUSTY] = EFST_BO_HELL_DUSTY; + + // Super Elementals + StatusIconChangeTable[SC_FLAMETECHNIC] = EFST_FLAMETECHNIC; + StatusIconChangeTable[SC_FLAMEARMOR] = EFST_FLAMEARMOR; + StatusIconChangeTable[SC_COLD_FORCE] = EFST_COLD_FORCE; + StatusIconChangeTable[SC_CRYSTAL_ARMOR] = EFST_CRYSTAL_ARMOR; + StatusIconChangeTable[SC_GRACE_BREEZE] = EFST_GRACE_BREEZE; + StatusIconChangeTable[SC_EYES_OF_STORM] = EFST_EYES_OF_STORM; + StatusIconChangeTable[SC_EARTH_CARE] = EFST_EARTH_CARE; + StatusIconChangeTable[SC_STRONG_PROTECTION] = EFST_STRONG_PROTECTION; + StatusIconChangeTable[SC_DEEP_POISONING] = EFST_DEEP_POISONING; + StatusIconChangeTable[SC_POISON_SHIELD] = EFST_POISON_SHIELD; + /* Other SC which are not necessarily associated to skills */ StatusChangeFlagTable[SC_ASPDPOTION0] |= SCB_ASPD; StatusChangeFlagTable[SC_ASPDPOTION1] |= SCB_ASPD; @@ -1944,6 +2105,25 @@ void initChangeTables(void) StatusChangeFlagTable[SC_EP16_2_BUFF_SC] |= SCB_CRI; StatusChangeFlagTable[SC_EP16_2_BUFF_AC] |= SCB_NONE; + // 4th Job Common Status + StatusChangeFlagTable[SC_HANDICAPSTATE_DEEPBLIND] |= SCB_FLEE|SCB_FLEE2; + StatusChangeFlagTable[SC_HANDICAPSTATE_DEEPSILENCE] |= SCB_ASPD; + StatusChangeFlagTable[SC_HANDICAPSTATE_LASSITUDE] |= SCB_SPEED|SCB_CRI; + StatusChangeFlagTable[SC_HANDICAPSTATE_FROSTBITE] |= SCB_DEF|SCB_MDEF|SCB_DEF_ELE; + StatusChangeFlagTable[SC_HANDICAPSTATE_SWOONING] |= SCB_NONE; + StatusChangeFlagTable[SC_HANDICAPSTATE_LIGHTNINGSTRIKE] |= SCB_NONE|SCB_DEF_ELE; + StatusChangeFlagTable[SC_HANDICAPSTATE_CRYSTALLIZATION] |= SCB_MDEF|SCB_DEF_ELE; + StatusChangeFlagTable[SC_HANDICAPSTATE_CONFLAGRATION] |= SCB_NONE; + StatusChangeFlagTable[SC_HANDICAPSTATE_MISFORTUNE] |= SCB_HIT; + StatusChangeFlagTable[SC_HANDICAPSTATE_DEADLYPOISON] |= SCB_DEF; + StatusChangeFlagTable[SC_HANDICAPSTATE_DEPRESSION] |= SCB_NONE; + StatusChangeFlagTable[SC_HANDICAPSTATE_HOLYFLAME] |= SCB_NONE; + + // 4th Jobs + StatusChangeFlagTable[SC_CHARGINGPIERCE_COUNT] |= SCB_NONE; + StatusChangeFlagTable[SC_SHADOW_SCAR] |= SCB_NONE; + StatusChangeFlagTable[SC_BO_HELL_DUSTY] |= SCB_NONE; + #ifdef RENEWAL // renewal EDP increases your weapon atk StatusChangeFlagTable[SC_EDP] |= SCB_WATK; @@ -2025,6 +2205,52 @@ void initChangeTables(void) StatusDisplayType[SC_CLAN_INFO] = BL_PC|BL_NPC; StatusDisplayType[SC_DRESSUP] = BL_PC; + // 4th Job Common Status + StatusDisplayType[SC_HANDICAPSTATE_DEEPBLIND] = BL_PC; + StatusDisplayType[SC_HANDICAPSTATE_DEEPSILENCE] = BL_PC; + StatusDisplayType[SC_HANDICAPSTATE_LASSITUDE] = BL_PC; + StatusDisplayType[SC_HANDICAPSTATE_FROSTBITE] = BL_PC; + StatusDisplayType[SC_HANDICAPSTATE_SWOONING] = BL_PC; + StatusDisplayType[SC_HANDICAPSTATE_LIGHTNINGSTRIKE] = BL_PC; + StatusDisplayType[SC_HANDICAPSTATE_CRYSTALLIZATION] = BL_PC; + StatusDisplayType[SC_HANDICAPSTATE_CONFLAGRATION] = BL_PC; + StatusDisplayType[SC_HANDICAPSTATE_MISFORTUNE] = BL_PC; + StatusDisplayType[SC_HANDICAPSTATE_DEADLYPOISON] = BL_PC; + StatusDisplayType[SC_HANDICAPSTATE_DEPRESSION] = BL_PC; + StatusDisplayType[SC_HANDICAPSTATE_HOLYFLAME] = BL_PC; + + // 4th Jobs + StatusDisplayType[SC_SERVANT_SIGN] = BL_PC; + StatusDisplayType[SC_CHARGINGPIERCE_COUNT] = BL_PC; + StatusDisplayType[SC_DRAGONIC_AURA] = BL_PC; + StatusDisplayType[SC_VIGOR] = BL_PC; + StatusDisplayType[SC_DEADLY_DEFEASANCE] = BL_PC; + StatusDisplayType[SC_CLIMAX] = BL_PC; + StatusDisplayType[SC_MEDIALE] = BL_PC; + StatusDisplayType[SC_PRE_ACIES] = BL_PC; + StatusDisplayType[SC_COMPETENTIA] = BL_PC; + StatusDisplayType[SC_RELIGIO] = BL_PC; + StatusDisplayType[SC_BENEDICTUM] = BL_PC; + StatusDisplayType[SC_WINDSIGN] = BL_PC; + StatusDisplayType[SC_CALAMITYGALE] = BL_PC; + StatusDisplayType[SC_A_MACHINE] = BL_PC; + StatusDisplayType[SC_D_MACHINE] = BL_PC; + StatusDisplayType[SC_SHADOW_EXCEED] = BL_PC; + StatusDisplayType[SC_DANCING_KNIFE] = BL_PC; + StatusDisplayType[SC_E_SLASH_COUNT] = BL_PC; + StatusDisplayType[SC_HOLY_S] = BL_PC; + StatusDisplayType[SC_SPEAR_SCAR] = BL_PC; + StatusDisplayType[SC_ELEMENTAL_VEIL] = BL_PC; + StatusDisplayType[SC_MYSTIC_SYMPHONY] = BL_PC; + StatusDisplayType[SC_SOUNDBLEND] = BL_PC; + StatusDisplayType[SC_HOLY_OIL] = BL_PC; + StatusDisplayType[SC_FIRST_BRAND] = BL_PC; + StatusDisplayType[SC_SECOND_BRAND] = BL_PC; + StatusDisplayType[SC_FIRST_FAITH_POWER] = BL_PC; + StatusDisplayType[SC_SECOND_JUDGE] = BL_PC; + StatusDisplayType[SC_THIRD_EXOR_FLAME] = BL_PC; + StatusDisplayType[SC_ABYSS_SLAYER] = BL_PC; + /* StatusChangeState (SCS_) NOMOVE */ StatusChangeStateTable[SC_ANKLE] |= SCS_NOMOVE; StatusChangeStateTable[SC_AUTOCOUNTER] |= SCS_NOMOVE; @@ -2063,6 +2289,10 @@ void initChangeTables(void) StatusChangeStateTable[SC_SUHIDE] |= SCS_NOMOVE; StatusChangeStateTable[SC_SV_ROOTTWIST] |= SCS_NOMOVE; StatusChangeStateTable[SC_GRAVITYCONTROL] |= SCS_NOMOVE; + //StatusChangeStateTable[SC_HANDICAPSTATE_FROSTBITE] |= SCS_NOMOVE; + //StatusChangeStateTable[SC_HANDICAPSTATE_SWOONING] |= SCS_NOMOVE; + //StatusChangeStateTable[SC_HANDICAPSTATE_LIGHTNINGSTRIKE] |= SCS_NOMOVE; + //StatusChangeStateTable[SC_HANDICAPSTATE_CRYSTALLIZATION] |= SCS_NOMOVE; /* StatusChangeState (SCS_) NOPICKUPITEMS */ StatusChangeStateTable[SC_HIDING] |= SCS_NOPICKITEM; @@ -2103,6 +2333,11 @@ void initChangeTables(void) StatusChangeStateTable[SC_CURSEDCIRCLE_TARGET] |= SCS_NOCAST; StatusChangeStateTable[SC_KINGS_GRACE] |= SCS_NOCAST; StatusChangeStateTable[SC_GRAVITYCONTROL] |= SCS_NOCAST; + //StatusChangeStateTable[SC_HANDICAPSTATE_DEEPSILENCE] |= SCS_NOCAST; + //StatusChangeStateTable[SC_HANDICAPSTATE_FROSTBITE] |= SCS_NOCAST; + //StatusChangeStateTable[SC_HANDICAPSTATE_SWOONING] |= SCS_NOCAST; + //StatusChangeStateTable[SC_HANDICAPSTATE_LIGHTNINGSTRIKE] |= SCS_NOCAST; + //StatusChangeStateTable[SC_HANDICAPSTATE_CRYSTALLIZATION] |= SCS_NOCAST; /* StatusChangeState (SCS_) NOCHAT (skills) */ StatusChangeStateTable[SC_BERSERK] |= SCS_NOCHAT; @@ -2133,13 +2368,13 @@ static void initDummyData(void) } /** - * For copying a status_data structure from b to a, without overwriting current Hp and Sp + * For copying a status_data structure from b to a, without overwriting current Hp, Sp, and Ap. * @param a: Status data structure to copy from * @param b: Status data structure to copy to */ static inline void status_cpy(struct status_data* a, const struct status_data* b) { - memcpy((void*)&a->max_hp, (const void*)&b->max_hp, sizeof(struct status_data)-(sizeof(a->hp)+sizeof(a->sp))); + memcpy((void*)&a->max_hp, (const void*)&b->max_hp, sizeof(struct status_data)-(sizeof(a->hp)+sizeof(a->sp)+sizeof(a->ap))); } /** @@ -2255,6 +2490,59 @@ int status_set_maxsp(struct block_list *bl, unsigned int maxsp, int flag) return maxsp; } +/** +* Sets AP to a given value +* @param bl: Object whose AP will be set [PC|HOM|MER|ELEM] +* @param ap: What the AP is to be set as +* @param flag: Used in case final value is higher than current +* Use 2 to display healing effect +* @return heal or zapped AP if valid +*/ +int status_set_ap(struct block_list *bl, unsigned int ap, int flag) +{ + status_data *status = status_get_status_data(bl); + + if (status == &dummy_status) + return 0; + + if (ap > status->max_ap) + ap = status->max_ap; + if (ap == status->ap) + return 0; + if (ap > status->ap) + return status_heal(bl, 0, 0, ap - status->ap, 1 | flag); + return status_zap(bl, 0, 0, status->ap - ap); +} + +/** +* Sets Max AP to a given value +* @param bl: Object whose Max AP will be set [PC|HOM|MER|ELEM] +* @param maxap: What the Max AP is to be set as +* @param flag: Used in case final value is higher than current +* Use 2 to display healing effect +* @return heal or zapped AP if valid +*/ +int status_set_maxap(struct block_list *bl, unsigned int maxap, int flag) +{ + if (maxap < 1) + return 0; + + status_data *status = status_get_status_data(bl); + + if (status == &dummy_status) + return 0; + + if (maxap == status->max_ap) + return 0; + if (maxap > status->max_ap) + status_heal(bl, 0, 0, maxap - status->max_ap, 1 | flag); + else + status_zap(bl, 0, 0, status->max_ap - maxap); + + status->max_ap = maxap; + return maxap; +} + /** * Takes HP/SP from an Object * @param bl: Object who will have HP/SP taken [PC|MOB|HOM|MER|ELEM] @@ -2277,28 +2565,33 @@ int64 status_charge(struct block_list* bl, int64 hp, int64 sp) * @param target: Target of the damage * @param dhp: How much damage to HP * @param dsp: How much damage to SP + * @param dap: How much damage to AP * @param walkdelay: Amount of time before object can walk again * @param flag: Damage flag decides various options * flag&1: Passive damage - Does not trigger cancelling status changes * flag&2: Fail if there is not enough to subtract * flag&4: Mob does not give EXP/Loot if killed * flag&8: Used to damage SP of a dead character - * @return hp+sp - * Note: HP/SP are integer values, not percentages. Values should be + * @return hp+sp+ap + * Note: HP/SP/AP are integer values, not percentages. Values should be * calculated either within function call or before */ -int status_damage(struct block_list *src,struct block_list *target,int64 dhp, int64 dsp, t_tick walkdelay, int flag, uint16 skill_id) +int status_damage(struct block_list *src,struct block_list *target,int64 dhp, int64 dsp, int64 dap, t_tick walkdelay, int flag, uint16 skill_id) { struct status_data *status; struct status_change *sc; int hp = (int)cap_value(dhp,INT_MIN,INT_MAX); int sp = (int)cap_value(dsp,INT_MIN,INT_MAX); + int ap = (int)cap_value(dap,INT_MIN,INT_MAX); nullpo_ret(target); if(sp && !(target->type&BL_CONSUME)) sp = 0; // Not a valid SP target. + if (ap && !(target->type&BL_CONSUME)) + ap = 0; // Not a valid AP target. + if (hp < 0) { // Assume absorbed damage. status_heal(target, -hp, 0, 1); hp = 0; @@ -2309,6 +2602,11 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in sp = 0; } + if (ap < 0) { + status_heal(target, 0, 0, -ap, 1); + ap = 0; + } + if (target->type == BL_SKILL) { if (!src || src->type&battle_config.can_damage_skill) return (int)skill_unit_ondamaged((struct skill_unit *)target, hp); @@ -2329,7 +2627,12 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in sp = status->sp; } - if (!hp && !sp) + if ((unsigned int)ap > status->ap) { + if (flag & 2) return 0; + ap = status->ap; + } + + if (!hp && !sp && !ap) return 0; if( !status->hp ) @@ -2356,6 +2659,10 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in status_change_end(target, SC_DEEPSLEEP, INVALID_TIMER); status_change_end(target, SC_SUHIDE, INVALID_TIMER); status_change_end(target, SC_NEWMOON, INVALID_TIMER); + status_change_end(target, SC_HANDICAPSTATE_FROSTBITE, INVALID_TIMER); + status_change_end(target, SC_HANDICAPSTATE_SWOONING, INVALID_TIMER); + status_change_end(target, SC_HANDICAPSTATE_LIGHTNINGSTRIKE, INVALID_TIMER); + status_change_end(target, SC_HANDICAPSTATE_CRYSTALLIZATION, INVALID_TIMER); if ((sce=sc->data[SC_ENDURE]) && !sce->val4) { /** [Skotlex] * Endure count is only reduced by non-players on non-gvg maps. @@ -2390,6 +2697,7 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in status->hp-= hp; status->sp-= sp; + status->ap-= ap; if (sc && hp && status->hp) { if (sc->data[SC_AUTOBERSERK] && @@ -2405,7 +2713,7 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in } switch (target->type) { - case BL_PC: pc_damage((TBL_PC*)target,src,hp,sp); break; + case BL_PC: pc_damage((TBL_PC*)target,src,hp,sp,ap); break; case BL_MOB: mob_damage((TBL_MOB*)target, src, hp); break; case BL_HOM: hom_damage((TBL_HOM*)target); break; case BL_MER: mercenary_heal((TBL_MER*)target,hp,sp); break; @@ -2419,7 +2727,7 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in if( status->hp || (flag&8) ) { // Still lives or has been dead before this damage. if (walkdelay) unit_set_walkdelay(target, gettick(), walkdelay, 0); - return (int)(hp+sp); + return (int)(hp+sp+ap); } status->hp = 0; @@ -2442,7 +2750,7 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in } if(!flag) // Death cancelled. - return (int)(hp+sp); + return (int)(hp+sp+ap); // Normal death if (battle_config.clear_unit_ondeath && @@ -2474,14 +2782,27 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in if( target->type == BL_MOB ) ((TBL_MOB*)target)->state.rebirth = 1; - return (int)(hp+sp); + return (int)(hp+sp+ap); } + + // Disable Ultimate Sacrifice on GVG maps + if (sc && sc->data[SC_ULTIMATE_S] && !map_flag_gvg2(target->m)) { + status_revive(target, 100, 100); + status_change_clear(target, 0); + clif_skill_nodamage(target, target, ALL_RESURRECTION, 1, 1); + + if (target->type == BL_MOB) + ((TBL_MOB*)target)->state.rebirth = 1; + + return (int)(hp+sp+ap); + } + if (target->type == BL_MOB && sc && sc->data[SC_REBIRTH] && !((TBL_MOB*) target)->state.rebirth) { // Ensure the monster has not already rebirthed before doing so. status_revive(target, sc->data[SC_REBIRTH]->val2, 0); status_change_clear(target,0); ((TBL_MOB*)target)->state.rebirth = 1; - return (int)(hp+sp); + return (int)(hp+sp+ap); } status_change_clear(target,0); @@ -2514,7 +2835,7 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in npc_script_event(sd,NPCE_DIE); } - return (int)(hp+sp); + return (int)(hp+sp+ap); } /** @@ -2522,17 +2843,19 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in * @param bl: Object to heal [PC|MOB|HOM|MER|ELEM] * @param hhp: How much HP to heal * @param hsp: How much SP to heal - * @param flag: Whether it's Forced(&1), gives HP/SP(&2) heal effect, + * @param hap: How much AP to heal + * @param flag: Whether it's Forced(&1), gives HP/SP/AP(&2) heal effect, * or gives HP(&4) heal effect with 0 heal * Forced healing overrides heal impedement statuses (Berserk) - * @return hp+sp + * @return hp+sp+ap */ -int status_heal(struct block_list *bl,int64 hhp,int64 hsp, int flag) +int status_heal(struct block_list *bl,int64 hhp,int64 hsp, int64 hap, int flag) { struct status_data *status; struct status_change *sc; int hp = (int)cap_value(hhp,INT_MIN,INT_MAX); int sp = (int)cap_value(hsp,INT_MIN,INT_MAX); + int ap = (int)cap_value(hap,INT_MIN,INT_MAX); status = status_get_status_data(bl); @@ -2574,11 +2897,24 @@ int status_heal(struct block_list *bl,int64 hhp,int64 hsp, int flag) sp = status->max_sp - status->sp; } - if(!sp && !hp && !(flag&4)) + if (ap < 0) { + if (ap == INT_MIN) + ap++; + status_damage(nullptr, bl, 0, 0, -ap, 0, 1, 0); + ap = 0; + } + + if (ap) { + if ((unsigned int)ap > status->max_ap - status->ap) + ap = status->max_ap - status->ap; + } + + if(!ap && !sp && !hp && !(flag&4)) return 0; status->hp += hp; status->sp += sp; + status->ap += ap; if(hp && sc && sc->data[SC_AUTOBERSERK] && @@ -2590,33 +2926,34 @@ int status_heal(struct block_list *bl,int64 hhp,int64 hsp, int flag) // Send HP update to client switch(bl->type) { - case BL_PC: pc_heal((TBL_PC*)bl,hp,sp,flag); break; + case BL_PC: pc_heal((TBL_PC*)bl,hp,sp,ap,flag); break; case BL_MOB: mob_heal((TBL_MOB*)bl,hp); break; case BL_HOM: hom_heal((TBL_HOM*)bl); break; case BL_MER: mercenary_heal((TBL_MER*)bl,hp,sp); break; case BL_ELEM: elemental_heal((TBL_ELEM*)bl,hp,sp); break; } - return (int)hp+sp; + return (int)hp+sp+ap; } /** * Applies percentage based damage to a unit. * If a mob is killed this way and there is no src, no EXP/Drops will be awarded. - * @param src: Object initiating HP/SP modification [PC|MOB|PET|HOM|MER|ELEM] - * @param target: Object to modify HP/SP + * @param src: Object initiating HP/SP/AP modification [PC|MOB|PET|HOM|MER|ELEM] + * @param target: Object to modify HP/SP/AP * @param hp_rate: Percentage of HP to modify. If > 0:percent is of current HP, if < 0:percent is of max HP * @param sp_rate: Percentage of SP to modify. If > 0:percent is of current SP, if < 0:percent is of max SP + * @param ap_rate: Percentage of AP to modify. If > 0:percent is of current AP, if < 0:percent is of max AP * @param flag: \n * 0: Heal target \n * 1: Use status_damage \n * 2: Use status_damage and make sure target must not die from subtraction - * @return hp+sp through status_heal() + * @return hp+sp+ap through status_heal() */ -int status_percent_change(struct block_list *src, struct block_list *target, int8 hp_rate, int8 sp_rate, uint8 flag) +int status_percent_change(struct block_list *src, struct block_list *target, int8 hp_rate, int8 sp_rate, int8 ap_rate, uint8 flag) { struct status_data *status; - unsigned int hp = 0, sp = 0; + unsigned int hp = 0, sp = 0, ap = 0; status = status_get_status_data(target); @@ -2647,6 +2984,17 @@ int status_percent_change(struct block_list *src, struct block_list *target, int if (sp_rate && !sp) sp = 1; + if (ap_rate > 99) + ap = status->ap; + else if (ap_rate > 0) + ap = apply_rate(status->ap, ap_rate); + else if (ap_rate < -99) + ap = status->max_ap; + else if (ap_rate < 0) + ap = (apply_rate(status->max_ap, -ap_rate)); + if (ap_rate && !ap) + ap = 1; + // Ugly check in case damage dealt is too much for the received args of // status_heal / status_damage. [Skotlex] if (hp > INT_MAX) { @@ -2663,9 +3011,16 @@ int status_percent_change(struct block_list *src, struct block_list *target, int else status_heal(target, 0, INT_MAX, 0); } + if (ap > INT_MAX) { + ap -= INT_MAX; + if (flag) + status_damage(src, target, 0, 0, INT_MAX, 0, (!src || src == target ? 5 : 1), 0); + else + status_heal(target, 0, 0, INT_MAX, 0); + } if (flag) - return status_damage(src, target, hp, sp, 0, (!src||src==target?5:1), 0); - return status_heal(target, hp, sp, 0); + return status_damage(src, target, hp, sp, ap, 0, (!src||src==target?5:1), 0); + return status_heal(target, hp, sp, ap, 0); } /** @@ -2673,12 +3028,13 @@ int status_percent_change(struct block_list *src, struct block_list *target, int * @param bl: Object to revive [PC|MOB|HOM] * @param per_hp: Percentage of HP to revive with * @param per_sp: Percentage of SP to revive with + * @param per_ap: Percentage of AP to revive with * @return Successful (1) or Invalid target (0) */ -int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per_sp) +int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per_sp, unsigned char per_ap) { struct status_data *status; - unsigned int hp, sp; + unsigned int hp, sp, ap; if (!status_isdead(bl)) return 0; status = status_get_status_data(bl); @@ -2687,6 +3043,7 @@ int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per hp = (int64)status->max_hp * per_hp/100; sp = (int64)status->max_sp * per_sp/100; + ap = (int64)status->max_ap * per_ap/100; if(hp > status->max_hp - status->hp) hp = status->max_hp - status->hp; @@ -2698,13 +3055,19 @@ int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per else if (per_sp && !sp) sp = 1; + if (ap > status->max_ap - status->ap) + ap = status->max_ap - status->ap; + else if (per_ap && !ap) + ap = 1; + status->hp += hp; status->sp += sp; + status->ap += ap; if (bl->prev) // Animation only if character is already on a map. clif_resurrection(bl, 1); switch (bl->type) { - case BL_PC: pc_revive((TBL_PC*)bl, hp, sp); break; + case BL_PC: pc_revive((TBL_PC*)bl, hp, sp, ap); break; case BL_MOB: mob_revive((TBL_MOB*)bl, hp); break; case BL_HOM: hom_revive((TBL_HOM*)bl, hp, sp); break; } @@ -2956,6 +3319,8 @@ bool status_check_skilluse(struct block_list *src, struct block_list *target, ui return false; // Can't use Weapon endow skills on Mercenary (only Master) if( skill_id == AM_POTIONPITCHER && ( target->type == BL_MER || target->type == BL_ELEM) ) return false; // Can't use Potion Pitcher on Mercenaries + if (tsc && tsc->data[SC_ELEMENTAL_VEIL] && !(src && status_get_class_(src) == CLASS_BOSS) && !status_has_mode(status, MD_DETECTOR)) + return false; default: // Check for chase-walk/hiding/cloaking opponents. if( tsc ) { @@ -3011,6 +3376,10 @@ int status_check_visibility(struct block_list *src, struct block_list *target) return 0; } break; + case BL_ELEM: + if (tsc->data[SC_ELEMENTAL_VEIL] && !is_boss && !is_detector) + return 0; + break; default: if (((tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK)) || tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_STEALTHFIELD] || tsc->data[SC_SUHIDE]) && !is_boss && !is_detector) return 0; @@ -3153,7 +3522,7 @@ unsigned short status_base_atk(const struct block_list *bl, const struct status_ break; case BL_PC: #ifdef RENEWAL - str = (dstr * 10 + dex * 10 / 5 + status->luk * 10 / 3 + level * 10 / 4) / 10; + str = (dstr * 10 + dex * 10 / 5 + status->luk * 10 / 3 + level * 10 / 4) / 10 + 5 * status->pow; #else dstr = str / 10; str += dstr*dstr; @@ -3244,7 +3613,7 @@ unsigned short status_base_matk_min(struct block_list *bl, const struct status_d return status_get_homint(bl) + level + (status_get_homint(bl) + status_get_homdex(bl)) / 5; case BL_PC: default: - return status->int_ + (status->int_ / 2) + (status->dex / 5) + (status->luk / 3) + (level / 4); + return status->int_ + (status->int_ / 2) + (status->dex / 5) + (status->luk / 3) + (level / 4) + 5 * status->spl; } } @@ -3263,7 +3632,7 @@ unsigned short status_base_matk_max(struct block_list *bl, const struct status_d return status_get_homint(bl) + level + (status_get_homluk(bl) + status_get_homint(bl) + status_get_homdex(bl)) / 3; case BL_PC: default: - return status->int_ + (status->int_ / 2) + (status->dex / 5) + (status->luk / 3) + (level / 4); + return status->int_ + (status->int_ / 2) + (status->dex / 5) + (status->luk / 3) + (level / 4) + 5 * status->spl; } } #endif @@ -3282,7 +3651,10 @@ void status_calc_misc(struct block_list *bl, struct status_data *status, int lev status->batk = status->hit = status->flee = status->def2 = status->mdef2 = - status->cri = status->flee2 = 0; + status->cri = status->flee2 = + status->patk = status->smatk = + status->hplus = status->crate = + status->res = status->mres = 0; #ifdef RENEWAL // Renewal formulas if (bl->type == BL_HOM) { @@ -3309,10 +3681,12 @@ void status_calc_misc(struct block_list *bl, struct status_data *status, int lev // Hit stat = status->hit; stat += level + status->dex + (bl->type == BL_PC ? status->luk / 3 + 175 : 150); //base level + ( every 1 dex = +1 hit ) + (every 3 luk = +1 hit) + 175 + stat += 2 * status->con; status->hit = cap_value(stat, 1, SHRT_MAX); // Flee stat = status->flee; stat += level + status->agi + (bl->type == BL_MER ? 0 : bl->type == BL_PC ? status->luk / 5 : 0) + 100; //base level + ( every 1 agi = +1 flee ) + (every 5 luk = +1 flee) + 100 + stat += 2 * status->con; status->flee = cap_value(stat, 1, SHRT_MAX); // Def2 if (bl->type == BL_MER) @@ -3330,6 +3704,30 @@ void status_calc_misc(struct block_list *bl, struct status_data *status, int lev stat += (int)(bl->type == BL_PC ? (status->int_ + ((float)level / 4) + ((float)(status->dex + status->vit) / 5)) : ((float)(status->int_ + level) / 4)); //(every 4 base level = +1 mdef) + (every 1 int = +1 mdef) + (every 5 dex = +1 mdef) + (every 5 vit = +1 mdef) } status->mdef2 = cap_value(stat, 0, SHRT_MAX); + // PAtk + stat = status->patk; + stat += status->pow / 3 + status->con / 5; + status->patk = cap_value(stat, 0, SHRT_MAX); + // SMatk + stat = status->smatk; + stat += status->spl / 3 + status->con / 5; + status->smatk = cap_value(stat, 0, SHRT_MAX); + // Res + stat = status->res; + stat += status->sta + status->sta / 3 * 5; + status->res = cap_value(stat, 0, SHRT_MAX); + // Mres + stat = status->mres; + stat += status->wis + status->wis / 3 * 5; + status->mres = cap_value(stat, 0, SHRT_MAX); + // HPlus + stat = status->hplus; + stat += status->crt; + status->hplus = cap_value(stat, 0, SHRT_MAX); + // CRate + stat = status->crate; + stat += status->crt / 3; + status->crate = cap_value(stat, 0, SHRT_MAX); } // ATK @@ -3607,6 +4005,77 @@ int status_calc_mob_(struct mob_data* md, enum e_status_calc_opt opt) status->matk_min = status->matk_max = 250 + 50*((TBL_PC*)mbl)->menuskill_val; break; } + case MT_SUMMON_ABR_BATTLE_WARIOR: + case MT_SUMMON_ABR_DUAL_CANNON: + case MT_SUMMON_ABR_MOTHER_NET: + case MT_SUMMON_ABR_INFINITY: { + map_session_data *msd = BL_CAST(BL_PC, mbl); + status_data *mstatus = status_get_status_data(mbl); + + if (msd == nullptr || mstatus == nullptr) + break; + + uint8 abr_mastery = pc_checkskill(msd, MT_ABR_M); + + // Custom formulas for ABR's. + // Its unknown how the summoner's stats affects the ABR's stats. + // I decided to do something similar to elementals for now until I know. + // Also added hit increase from ABR-Mastery for balance reasons. [Rytech] + status->max_hp = (5000 + 2000 * abr_mastery) * mstatus->vit / 100; + status->rhw.atk = (2 * mstatus->batk + 500 + 200 * abr_mastery) * 70 / 100; + status->rhw.atk2 = 2 * mstatus->batk + 500 + 200 * abr_mastery; + status->def = mstatus->def + 20 * abr_mastery; + status->mdef = mstatus->mdef + 4 * abr_mastery; + status->hit = mstatus->hit + 5 * abr_mastery / 2; + status->flee = mstatus->flee + 10 * abr_mastery; + status->speed = mstatus->speed; + + // The Infinity ABR appears to have a much higher attack then other + // ABR's and im guessing has a much higher MaxHP due to it being a AP + // costing summon. [Rytech] + if (ud->skill_id == MT_SUMMON_ABR_INFINITY) { + status->max_hp += 20000; + status->rhw.atk += 1400; // 70% of 2000 + status->rhw.atk2 += 2000; + } + } + break; + case BO_WOODENWARRIOR: + case BO_WOODEN_FAIRY: + case BO_CREEPER: + case BO_HELLTREE: { + map_session_data *msd = BL_CAST(BL_PC, mbl); + status_data *mstatus = status_get_status_data(mbl); + + if (msd == nullptr || mstatus == nullptr) + break; + + uint8 bionic_mastery = pc_checkskill(msd, BO_BIONICS_M); + + // Custom formulas for bionic's. + // Its unknown how the summoner's stats affects the bionic's stats. + // I decided to do something similar to elementals for now until I know. + // Also added hit increase from Bionic-Mastery for balance reasons. [Rytech] + status->max_hp = (5000 + 2000 * bionic_mastery) * mstatus->vit / 100; + //status->max_sp = (50 + 20 * bionic_mastery) * mstatus->int_ / 100;// Wait what??? Bionic Mastery increases MaxSP? They have SP??? + status->rhw.atk = (2 * mstatus->batk + 200 * bionic_mastery) * 70 / 100; + status->rhw.atk2 = 2 * mstatus->batk + 200 * bionic_mastery; + status->def = mstatus->def + 20 * bionic_mastery; + status->mdef = mstatus->mdef + 4 * bionic_mastery; + status->hit = mstatus->hit + 5 * bionic_mastery / 2; + status->flee = mstatus->flee + 10 * bionic_mastery; + status->speed = mstatus->speed; + + // The Hell Tree bionic appears to have a much higher attack then other + // bionic's and im guessing has a much higher MaxHP due to it being a AP + // costing summon. [Rytech] + if (ud->skill_id == BO_HELLTREE) { + status->max_hp += 20000; + status->rhw.atk += 1400; // 70% of 2000 + status->rhw.atk2 += 2000; + } + } + break; } status->hp = status->max_hp; } @@ -3808,6 +4277,8 @@ static int status_get_hpbonus(struct block_list *bl, enum e_status_bonus type) { bonus += sc->data[SC_LUXANIMA]->val3; if (sc->data[SC_MTF_MHP]) bonus += sc->data[SC_MTF_MHP]->val1; + if (sc->data[SC_FIRM_FAITH]) + bonus += sc->data[SC_FIRM_FAITH]->val2; //Decreasing if (sc->data[SC_VENOMBLEED] && sc->data[SC_VENOMBLEED]->val3 == 1) @@ -4001,6 +4472,90 @@ static int status_get_spbonus_item(block_list *bl) { return cap_value(bonus, -100, INT_MAX); } +/** + * Get AP bonus modifiers + * @param bl: block_list that will be checked + * @param type: type of e_status_bonus (STATUS_BONUS_FIX or STATUS_BONUS_RATE) + * @return bonus: total bonus for AP + */ +static int status_get_apbonus(struct block_list *bl, enum e_status_bonus type) { + int bonus = 0; + + if (type == STATUS_BONUS_FIX) { + struct status_change *sc = status_get_sc(bl); + + //Only for BL_PC + if (bl->type == BL_PC) { + struct map_session_data *sd = map_id2sd(bl->id); + //uint16 skill_lv; + + bonus += sd->bonus.ap; + //if ((skill_lv = pc_checkskill(sd, NV_BASIC)) > 0) + // bonus += 100 * skill_lv; + } + + //Bonus by SC + if (sc) { + //if (sc->data[SC_NONE]) + // bonus += sc->data[SC_NONE]->val1; + } + } else if (type == STATUS_BONUS_RATE) { + struct status_change *sc = status_get_sc(bl); + + //Only for BL_PC + if (bl->type == BL_PC) { + struct map_session_data *sd = map_id2sd(bl->id); + //uint8 i; + + //if ((i = pc_checkskill(sd, NV_BASIC)) > 0) + // bonus += 100 * i; + } + + //Bonus by SC + if (sc) { + //if (sc->data[SC_NONE]) + // bonus += sc->data[SC_NONE]->val1; + } + // Max rate reduce is -100% + bonus = cap_value(bonus, -100, INT_MAX); + } + + return min(bonus, INT_MAX); +} + +/** + * AP bonus rate from equipment + * @param sd: Player data + * @return AP rate + */ +static int status_get_apbonus_equip(TBL_PC *sd) { + int bonus = 0; + + bonus += sd->aprate; + + return bonus -= 100; //Default aprate is 100, so it should be add 0% +} + +/** + * AP bonus rate from usable items + * @param bl: Object to check against + * @return AP bonus + */ +static int status_get_apbonus_item(block_list *bl) { + int bonus = 0; + + struct status_change *sc = status_get_sc(bl); + + //Bonus by SC + if (sc) { + //if (sc->data[SC_NONE]) + // bonus += sc->data[SC_NONE]->val1; + } + + // Max rate reduce is -100% + return cap_value(bonus, -100, INT_MAX); +} + /** * Get final MaxHP or MaxSP for player. References: http://irowiki.org/wiki/Max_HP and http://irowiki.org/wiki/Max_SP * The calculation needs base_level, base_status/battle_status (vit or int), additive modifier, and multiplicative modifier @@ -4044,6 +4599,29 @@ static unsigned int status_calc_maxhpsp_pc(struct map_session_data* sd, unsigned return cap_value((unsigned int)dmax,1,UINT_MAX); } +/** + * Get final MaxAP for player. + * @param sd: Player data + * @return AP amount + */ +static unsigned int status_calc_maxap_pc(struct map_session_data* sd) { + double dmax = 0, equip_bonus = 0, item_bonus = 0; + + nullpo_ret(sd); + + dmax = (sd->class_&JOBL_FOURTH) ? 200 : 0; + dmax += status_get_apbonus(&sd->bl, STATUS_BONUS_FIX); + equip_bonus = (dmax * status_get_apbonus_equip(sd) / 100); + item_bonus = (dmax * status_get_apbonus_item(&sd->bl) / 100); + dmax += equip_bonus + item_bonus; + dmax += (int64)(dmax * status_get_apbonus(&sd->bl, STATUS_BONUS_RATE) / 100);// Aegis accuracy + + //Make sure it's not negative before casting to unsigned int + if (dmax < 0) dmax = 0; + + return cap_value((unsigned int)dmax, 0, UINT_MAX); +} + /** * Calculates player's weight * @param sd: Player object @@ -4174,6 +4752,8 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) // Load Hp/SP from char-received data. sd->battle_status.hp = sd->status.hp; sd->battle_status.sp = sd->status.sp; + if (battle_config.keep_ap_on_logout == 1) + sd->battle_status.ap = sd->status.ap; sd->regen.sregen = &sd->sregen; sd->regen.ssregen = &sd->ssregen; } @@ -4182,6 +4762,7 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) // These are not zeroed. [zzo] sd->hprate = 100; sd->sprate = 100; + sd->aprate = 100; sd->castrate = 100; sd->dsprate = 100; sd->hprecov_rate = 100; @@ -4189,6 +4770,9 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) sd->matk_rate = 100; sd->critical_rate = sd->hit_rate = sd->flee_rate = sd->flee2_rate = 100; sd->def_rate = sd->def2_rate = sd->mdef_rate = sd->mdef2_rate = 100; + sd->patk_rate = sd->smatk_rate = 100; + sd->res_rate = sd->mres_rate = 100; + sd->hplus_rate = sd->crate_rate = 100; sd->regen.state.block = 0; sd->add_max_weight = 0; @@ -4209,12 +4793,12 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) sd->special_state.no_gemstone = battle_config.vip_gemstone; if (!sd->state.permanent_speed) { - memset(&base_status->max_hp, 0, sizeof(struct status_data)-(sizeof(base_status->hp)+sizeof(base_status->sp))); + memset(&base_status->max_hp, 0, sizeof(struct status_data)-(sizeof(base_status->hp)+sizeof(base_status->sp)+sizeof(base_status->ap))); base_status->speed = DEFAULT_WALK_SPEED; } else { int pSpeed = base_status->speed; - memset(&base_status->max_hp, 0, sizeof(struct status_data)-(sizeof(base_status->hp)+sizeof(base_status->sp))); + memset(&base_status->max_hp, 0, sizeof(struct status_data)-(sizeof(base_status->hp)+sizeof(base_status->sp)+sizeof(base_status->ap))); base_status->speed = pSpeed; } @@ -4342,8 +4926,8 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) // TODO: additional grade bonus if( wlv == 5 ){ - // TODO: P.ATK += sd->inventory.u.items_inventory[index].refine * 2; - // TODO: S.MATK += sd->inventory.u.items_inventory[index].refine * 2; + base_status->patk += sd->inventory.u.items_inventory[index].refine * 2; + base_status->smatk += sd->inventory.u.items_inventory[index].refine * 2; } #endif } @@ -4393,8 +4977,8 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) #ifdef RENEWAL if( sd->inventory_data[index]->armor_level == 2 ){ - // TODO: RES += sd->inventory.u.items_inventory[index].refine * 2; - // TODO: MRES += sd->inventory.u.items_inventory[index].refine * 2; + base_status->res += sd->inventory.u.items_inventory[index].refine * 2; + base_status->mres += sd->inventory.u.items_inventory[index].refine * 2; } #endif } @@ -4666,6 +5250,18 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) base_status->dex = cap_value(i,0,USHRT_MAX); i = base_status->luk + sd->status.luk + sd->indexed_bonus.param_bonus[5] + sd->indexed_bonus.param_equip[5]; base_status->luk = cap_value(i,0,USHRT_MAX); + i = base_status->pow + sd->status.pow + sd->indexed_bonus.param_bonus[PARAM_POW] + sd->indexed_bonus.param_equip[PARAM_POW]; + base_status->pow = cap_value(i, 0, USHRT_MAX); + i = base_status->sta + sd->status.sta + sd->indexed_bonus.param_bonus[PARAM_STA] + sd->indexed_bonus.param_equip[PARAM_STA]; + base_status->sta = cap_value(i, 0, USHRT_MAX); + i = base_status->wis + sd->status.wis + sd->indexed_bonus.param_bonus[PARAM_WIS] + sd->indexed_bonus.param_equip[PARAM_WIS]; + base_status->wis = cap_value(i, 0, USHRT_MAX); + i = base_status->spl + sd->status.spl + sd->indexed_bonus.param_bonus[PARAM_SPL] + sd->indexed_bonus.param_equip[PARAM_SPL]; + base_status->spl = cap_value(i, 0, USHRT_MAX); + i = base_status->con + sd->status.con + sd->indexed_bonus.param_bonus[PARAM_CON] + sd->indexed_bonus.param_equip[PARAM_CON]; + base_status->con = cap_value(i, 0, USHRT_MAX); + i = base_status->crt + sd->status.crt + sd->indexed_bonus.param_bonus[PARAM_CRT] + sd->indexed_bonus.param_equip[PARAM_CRT]; + base_status->crt = cap_value(i, 0, USHRT_MAX); if (sd->special_state.no_walk_delay) { if (sc->data[SC_ENDURE]) { @@ -4714,7 +5310,15 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) base_status->max_sp = cap_value(base_status->max_sp,1,(unsigned int)battle_config.max_sp); -// ----- RESPAWN HP/SP ----- +// ----- AP MAX CALCULATION ----- + base_status->max_ap = sd->status.max_ap = status_calc_maxap_pc(sd); + + if (battle_config.ap_rate != 100) + base_status->max_ap = (unsigned int)(battle_config.ap_rate * (base_status->max_ap / 100.)); + + base_status->max_ap = cap_value(base_status->max_ap, 0, (unsigned int)battle_config.max_ap); + +// ----- RESPAWN HP/SP/AP ----- // Calc respawn hp and store it on base_status if (sd->special_state.restart_full_recover) { @@ -4733,6 +5337,8 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) if( !base_status->sp ) // The minimum for the respawn setting is SP:1 base_status->sp = 1; + + base_status->ap = (int64)base_status->max_ap * battle_config.restart_ap_rate / 100; } // ----- MISC CALCULATION ----- @@ -4779,6 +5385,36 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) if(sd->flee2_rate != 100) base_status->flee2 = base_status->flee2 * sd->flee2_rate/100; + if (sd->patk_rate < 0) + sd->patk_rate = 0; + if (sd->patk_rate != 100) + base_status->patk = base_status->patk * sd->patk_rate / 100; + + if (sd->smatk_rate < 0) + sd->smatk_rate = 0; + if (sd->smatk_rate != 100) + base_status->smatk = base_status->smatk * sd->smatk_rate / 100; + + if (sd->res_rate < 0) + sd->res_rate = 0; + if (sd->res_rate != 100) + base_status->res = base_status->res * sd->res_rate / 100; + + if (sd->mres_rate < 0) + sd->mres_rate = 0; + if (sd->mres_rate != 100) + base_status->mres = base_status->mres * sd->mres_rate / 100; + + if (sd->hplus_rate < 0) + sd->hplus_rate = 0; + if (sd->hplus_rate != 100) + base_status->hplus = base_status->hplus * sd->hplus_rate / 100; + + if (sd->crate_rate < 0) + sd->crate_rate = 0; + if (sd->crate_rate != 100) + base_status->crate = base_status->crate * sd->crate_rate / 100; + // ----- HIT CALCULATION ----- // Absolute modifiers from passive skills @@ -4807,6 +5443,8 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) base_status->hit += skill * 2; if (pc_checkskill(sd, SU_POWEROFLIFE) > 0) base_status->hit += 20; + if ((skill = pc_checkskill_imperial_guard(sd, 2)) > 0)// IG_SPEAR_SWORD_M + base_status->hit += skill * 3; if ((skill = pc_checkskill(sd, SU_SOULATTACK)) > 0) base_status->rhw.range += skill_get_range2(&sd->bl, SU_SOULATTACK, skill, true); @@ -4820,6 +5458,8 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) base_status->flee += (skill*3)>>1; if (pc_checkskill(sd, SU_POWEROFLIFE) > 0) base_status->flee += 20; + if ((skill = pc_checkskill(sd, SHC_SHADOW_SENSE)) > 0) + base_status->flee += skill * 10; // ----- CRITICAL CALCULATION ----- @@ -4829,6 +5469,24 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) if ((skill = pc_checkskill(sd, PR_MACEMASTERY)) > 0 && (sd->status.weapon == W_MACE || sd->status.weapon == W_2HMACE)) base_status->cri += skill * 10; #endif + if ((skill = pc_checkskill(sd, SHC_SHADOW_SENSE)) > 0) + { + if (sd->status.weapon == W_DAGGER || sd->status.weapon == W_DOUBLE_DD || + sd->status.weapon == W_DOUBLE_DS || sd->status.weapon == W_DOUBLE_DA) + base_status->cri += 100 + skill * 40; + else if (sd->status.weapon == W_KATAR) + base_status->cri += 50 + skill * 20; + } + +// ----- P.Atk/S.Matk CALCULATION ----- + if ((skill = pc_checkskill(sd, TR_STAGE_MANNER)) > 0 && (sd->status.weapon == W_BOW || sd->status.weapon == W_MUSICAL || sd->status.weapon == W_WHIP)) { + base_status->patk += skill * 3; + base_status->smatk += skill * 3; + } + +// ----- PHYSICAL RESISTANCE CALCULATION ----- + if ((skill = pc_checkskill_imperial_guard(sd, 1)) > 0)// IG_SHIELD_MASTERY + base_status->res += skill * 3; // ----- EQUIPMENT-DEF CALCULATION ----- @@ -4959,6 +5617,91 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) sd->indexed_bonus.subrace[RC_DEMON] += skill; sd->indexed_bonus.subele[ELE_DARK] += skill; } + if ((skill = pc_checkskill(sd, DK_TWOHANDDEF)) > 0 && (sd->status.weapon == W_2HSWORD || sd->status.weapon == W_2HSPEAR || sd->status.weapon == W_2HAXE)) { + uint8 defense_bonus[SZ_MAX][10] = { + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, // SZ_SMALL + { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM + { 3, 5, 7, 9, 10, 12, 13, 15, 16, 18 }, // SZ_BIG + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL + }; + + for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){ + sd->indexed_bonus.weapon_subsize[size] += defense_bonus[size][skill - 1]; + } + } + if ((skill = pc_checkskill(sd, IQ_WILL_OF_FAITH)) > 0 && sd->status.weapon == W_KNUCKLE) { + uint8 race_atk[10] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; + uint8 race_def[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + sd->right_weapon.addrace[RC_UNDEAD] += race_atk[skill - 1]; + sd->right_weapon.addrace[RC_DEMON] += race_atk[skill - 1]; + sd->left_weapon.addrace[RC_UNDEAD] += race_atk[skill - 1]; + sd->left_weapon.addrace[RC_DEMON] += race_atk[skill - 1]; + sd->indexed_bonus.subrace[RC_UNDEAD] += race_def[skill - 1]; + sd->indexed_bonus.subrace[RC_DEMON] += race_def[skill - 1]; + } + if ((skill = pc_checkskill(sd, CD_MACE_BOOK_M)) > 0 && (sd->status.weapon == W_MACE || sd->status.weapon == W_2HMACE || sd->status.weapon == W_BOOK)) { + uint8 attack_bonus[SZ_MAX][10] = { + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, // SZ_SMALL + { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM + { 3, 5, 7, 9, 10, 12, 13, 15, 16, 18 }, // SZ_BIG + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL + }; + + for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){ + sd->right_weapon.addsize[size] += attack_bonus[size][skill - 1]; + sd->left_weapon.addsize[size] += attack_bonus[size][skill - 1]; + } + } + if ((skill = pc_checkskill(sd, CD_FIDUS_ANIMUS)) > 0) { + uint8 holy_matk[10] = { 1, 3, 4, 6, 7, 9, 10, 12, 13, 15 }; + + sd->indexed_bonus.magic_atk_ele[ELE_HOLY] += holy_matk[skill - 1]; + } + if ((skill = pc_checkskill(sd, MT_TWOAXEDEF)) > 0 && sd->status.weapon == W_2HAXE) { + uint8 defense_bonus[SZ_MAX][10] = { + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, // SZ_SMALL + { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM + { 3, 5, 7, 9, 10, 12, 13, 15, 16, 18 }, // SZ_BIG + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL + }; + + for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){ + sd->indexed_bonus.weapon_subsize[size] += defense_bonus[size][skill - 1]; + } + } + if ((skill = pc_checkskill(sd, ABC_DAGGER_AND_BOW_M)) > 0 && (sd->status.weapon == W_DAGGER || sd->status.weapon == W_BOW || sd->status.weapon == W_DOUBLE_DD || sd->status.weapon == W_DOUBLE_DS || sd->status.weapon == W_DOUBLE_DA)) { + uint8 attack_bonus[SZ_MAX][10] = { + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, // SZ_SMALL + { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM + { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }, // SZ_BIG + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL + }; + + for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){ + sd->right_weapon.addsize[size] += attack_bonus[size][skill - 1]; + sd->left_weapon.addsize[size] += attack_bonus[size][skill - 1]; + } + } + if ((skill = pc_checkskill(sd, ABC_MAGIC_SWORD_M)) > 0 && (sd->status.weapon == W_DAGGER || sd->status.weapon == W_1HSWORD || sd->status.weapon == W_DOUBLE_DD || sd->status.weapon == W_DOUBLE_SS || sd->status.weapon == W_DOUBLE_DS || sd->status.weapon == W_DOUBLE_DA || sd->status.weapon == W_DOUBLE_SA)) { + uint8 attack_bonus[SZ_MAX][10] = { + { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_SMALL + { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM + { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_BIG + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL + }; + + for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){ + sd->indexed_bonus.magic_addsize[size] += attack_bonus[size][skill - 1]; + } + } + if ((skill = pc_checkskill(sd, EM_MAGIC_BOOK_M)) > 0 && sd->status.weapon == W_BOOK) { + sd->indexed_bonus.magic_atk_ele[ELE_WATER] += skill; + sd->indexed_bonus.magic_atk_ele[ELE_EARTH] += skill; + sd->indexed_bonus.magic_atk_ele[ELE_FIRE] += skill; + sd->indexed_bonus.magic_atk_ele[ELE_WIND] += skill; + sd->indexed_bonus.magic_atk_ele[ELE_POISON] += skill; + } if(sc->count) { if(sc->data[SC_CONCENTRATE]) { // Update the card-bonus data @@ -5093,6 +5836,61 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) } if (sc->data[SC_STRIKING]) sd->bonus.perfect_hit += 20 + 10 * pc_checkskill(sd, SO_STRIKING); + if (sc->data[SC_VIGOR]) { + // Skill desc says increases physical damage. Supposed to affect damage from base ATK right??? + // Because this is only boosting the ATK from the equipped weapon and not from base ATK. [Rytech] + sd->right_weapon.addrace[RC_DEMIHUMAN] += 50; + sd->left_weapon.addrace[RC_ANGEL] += 50; + } + if (sc->data[SC_DEADLY_DEFEASANCE]) + sd->special_state.no_magic_damage = 0; + if (sc->data[SC_CLIMAX_DES_HU]) + sd->indexed_bonus.magic_atk_ele[ELE_WIND] += 30; + if (sc->data[SC_CLIMAX_EARTH]) + sd->indexed_bonus.subele[ELE_EARTH] -= 100; + if (sc->data[SC_CLIMAX_BLOOM]) + sd->indexed_bonus.subele[ELE_FIRE] -= 100; + if (sc->data[SC_CLIMAX_CRYIMP]) { + sd->indexed_bonus.subele[ELE_WATER] += 30; + sd->indexed_bonus.magic_atk_ele[ELE_WATER] += 30; + } + if (sc->data[SC_SINCERE_FAITH]) + sd->bonus.perfect_hit += sc->data[SC_SINCERE_FAITH]->val3; + if (sc->data[SC_HOLY_S]) { + sd->indexed_bonus.subele[ELE_DARK] += sc->data[SC_HOLY_S]->val2; + sd->indexed_bonus.subele[ELE_UNDEAD] += sc->data[SC_HOLY_S]->val2; + sd->indexed_bonus.magic_atk_ele[ELE_HOLY] += sc->data[SC_HOLY_S]->val2; + } + if (sc->data[SC_SUMMON_ELEMENTAL_ARDOR]) + sd->indexed_bonus.magic_atk_ele[ELE_FIRE] += 10; + if (sc->data[SC_SUMMON_ELEMENTAL_DILUVIO]) + sd->indexed_bonus.magic_atk_ele[ELE_WATER] += 10; + if (sc->data[SC_SUMMON_ELEMENTAL_PROCELLA]) + sd->indexed_bonus.magic_atk_ele[ELE_WIND] += 10; + if (sc->data[SC_SUMMON_ELEMENTAL_TERREMOTUS]) + sd->indexed_bonus.magic_atk_ele[ELE_EARTH] += 10; + if (sc->data[SC_SUMMON_ELEMENTAL_SERPENS]) + sd->indexed_bonus.magic_atk_ele[ELE_POISON] += 10; + if (sc->data[SC_FLAMEARMOR_OPTION]) { + sd->indexed_bonus.subele[ELE_FIRE] += 100; + sd->indexed_bonus.subele[ELE_WATER] -= 30; + } + if (sc->data[SC_CRYSTAL_ARMOR_OPTION]) { + sd->indexed_bonus.subele[ELE_WATER] += 100; + sd->indexed_bonus.subele[ELE_WIND] -= 30; + } + if (sc->data[SC_EYES_OF_STORM_OPTION]) { + sd->indexed_bonus.subele[ELE_WIND] += 100; + sd->indexed_bonus.subele[ELE_EARTH] -= 30; + } + if (sc->data[SC_STRONG_PROTECTION_OPTION]) { + sd->indexed_bonus.subele[ELE_EARTH] += 100; + sd->indexed_bonus.subele[ELE_FIRE] -= 30; + } + if (sc->data[SC_POISON_SHIELD_OPTION]) { + sd->indexed_bonus.subele[ELE_POISON] += 100; + sd->indexed_bonus.subele[ELE_HOLY] -= 30; + } } status_cpy(&sd->battle_status, base_status); @@ -5567,24 +6365,29 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str case ELEMENTALID_AGNI_S: case ELEMENTALID_AGNI_M: case ELEMENTALID_AGNI_L: + case ELEMENTALID_ARDOR: if (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 1) regen->rate.hp += 100; break; case ELEMENTALID_AQUA_S: case ELEMENTALID_AQUA_M: case ELEMENTALID_AQUA_L: + case ELEMENTALID_DILUVIO: if (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 1) regen->rate.hp += 100; break; case ELEMENTALID_VENTUS_S: case ELEMENTALID_VENTUS_M: case ELEMENTALID_VENTUS_L: + case ELEMENTALID_PROCELLA: if (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 1) regen->rate.hp += 100; break; case ELEMENTALID_TERA_S: case ELEMENTALID_TERA_M: case ELEMENTALID_TERA_L: + case ELEMENTALID_TERREMOTUS: + case ELEMENTALID_SERPENS: if (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 1) regen->rate.hp += 100; break; @@ -5684,7 +6487,7 @@ void status_calc_state( struct block_list *bl, struct status_change *sc, enum sc * @param bl: Object whose status has changed [PC|MOB|HOM|MER|ELEM] * @param flag: Which status has changed on bl */ -void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) +void status_calc_bl_main(struct block_list *bl, uint64 flag) { const struct status_data *b_status = status_get_base_status(bl); // Base Status struct status_data *status = status_get_status_data(bl); // Battle Status @@ -5768,6 +6571,38 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) ; } +#ifdef RENEWAL + if (flag&SCB_POW) { + status->pow = status_calc_pow(bl, sc, b_status->pow); + flag |= SCB_BATK|SCB_PATK; + } + + if (flag&SCB_STA) { + status->sta = status_calc_sta(bl, sc, b_status->sta); + flag |= SCB_RES; + } + + if (flag&SCB_WIS) { + status->wis = status_calc_wis(bl, sc, b_status->wis); + flag |= SCB_MRES; + } + + if (flag&SCB_SPL) { + status->spl = status_calc_spl(bl, sc, b_status->spl); + flag |= SCB_MATK|SCB_SMATK; + } + + if (flag&SCB_CON) { + status->con = status_calc_con(bl, sc, b_status->con); + flag |= SCB_HIT|SCB_FLEE|SCB_PATK|SCB_SMATK; + } + + if (flag&SCB_CRT) { + status->crt = status_calc_crt(bl, sc, b_status->crt); + flag |= SCB_HPLUS|SCB_CRATE; + } +#endif + if(flag&SCB_BATK && b_status->batk) { int lv = status_get_lv(bl); status->batk = status_base_atk(bl, status, lv); @@ -5809,14 +6644,14 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) if(flag&SCB_HIT) { if (status->dex == b_status->dex #ifdef RENEWAL - && status->luk == b_status->luk + && status->luk == b_status->luk && status->con == b_status->con #endif ) status->hit = status_calc_hit(bl, sc, b_status->hit); else status->hit = status_calc_hit(bl, sc, b_status->hit + (status->dex - b_status->dex) #ifdef RENEWAL - + (status->luk/3 - b_status->luk/3) + + (status->luk/3 - b_status->luk/3) + 2 * (status->con - b_status->con) #endif ); } @@ -5824,14 +6659,14 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) if(flag&SCB_FLEE) { if (status->agi == b_status->agi #ifdef RENEWAL - && status->luk == b_status->luk + && status->luk == b_status->luk && status->con == b_status->con #endif ) status->flee = status_calc_flee(bl, sc, b_status->flee); else status->flee = status_calc_flee(bl, sc, b_status->flee +(status->agi - b_status->agi) #ifdef RENEWAL - + (status->luk/5 - b_status->luk/5) + + (status->luk/5 - b_status->luk/5) + 2 * (status->con - b_status->con) #endif ); } @@ -6165,6 +7000,67 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) } } +#ifdef RENEWAL + if (flag&SCB_PATK) { + if (status->pow == b_status->pow && status->con == b_status->con) + status->patk = status_calc_patk(bl, sc, b_status->patk); + else + status->patk = status_calc_patk(bl, sc, b_status->patk + (status->pow - b_status->pow) / 3 + (status->con - b_status->con) / 5); + } + + if (flag&SCB_SMATK) { + if (status->spl == b_status->spl && status->con == b_status->con) + status->smatk = status_calc_smatk(bl, sc, b_status->smatk); + else + status->smatk = status_calc_smatk(bl, sc, b_status->smatk) + (status->spl - b_status->spl) / 3 + (status->con - b_status->con) / 5; + } + + if (flag&SCB_RES) { + if (status->sta == b_status->sta) + status->res = status_calc_res(bl, sc, b_status->res); + else + status->res = status_calc_res(bl, sc, b_status->res + (status->sta - b_status->sta) + (status->sta - b_status->sta) / 3 * 5); + } + + if (flag&SCB_MRES) { + if (status->wis == b_status->wis) + status->mres = status_calc_mres(bl, sc, b_status->mres); + else + status->mres = status_calc_mres(bl, sc, b_status->mres + (status->wis - b_status->wis) + (status->wis - b_status->wis) / 3 * 5); + } + + if (flag&SCB_HPLUS) { + if (status->crt == b_status->crt) + status->hplus = status_calc_hplus(bl, sc, b_status->hplus); + else + status->hplus = status_calc_hplus(bl, sc, b_status->hplus + (status->crt - b_status->crt)); + } + + if (flag&SCB_CRATE) { + if (status->crt == b_status->crt) + status->crate = status_calc_crate(bl, sc, b_status->crate); + else + status->crate = status_calc_crate(bl, sc, b_status->crate + (status->crt - b_status->crt) / 3); + } + + if (flag&SCB_MAXAP) { + if (bl->type&BL_PC) { + status->max_ap = status_calc_maxap_pc(sd); + + if (battle_config.ap_rate != 100) + status->max_ap = (unsigned int)(battle_config.ap_rate * (status->max_ap / 100.)); + + status->max_ap = umin(status->max_ap, (unsigned int)battle_config.max_ap); + } else + status->max_ap = status_calc_maxap(bl, b_status->max_ap); + + if (status->ap > status->max_ap) { + status->ap = status->max_ap; + if (sd) clif_updatestatus(sd, SP_AP); + } + } +#endif + if(flag&(SCB_VIT|SCB_MAXHP|SCB_INT|SCB_MAXSP) && bl->type&BL_REGEN) status_calc_regen(bl, status, status_get_regen_data(bl)); @@ -6316,6 +7212,36 @@ void status_calc_bl_(struct block_list* bl, enum scb_flag flag, enum e_status_ca clif_updatestatus(sd,SP_HP); if(b_status.sp != status->sp) clif_updatestatus(sd,SP_SP); +#ifdef RENEWAL + if (b_status.pow != status->pow) + clif_updatestatus(sd,SP_POW); + if (b_status.sta != status->sta) + clif_updatestatus(sd,SP_STA); + if (b_status.wis != status->wis) + clif_updatestatus(sd,SP_WIS); + if (b_status.spl != status->spl) + clif_updatestatus(sd,SP_SPL); + if (b_status.con != status->con) + clif_updatestatus(sd,SP_CON); + if (b_status.crt != status->crt) + clif_updatestatus(sd,SP_CRT); + if (b_status.patk != status->patk) + clif_updatestatus(sd, SP_PATK); + if (b_status.smatk != status->smatk) + clif_updatestatus(sd, SP_SMATK); + if (b_status.res != status->res) + clif_updatestatus(sd, SP_RES); + if (b_status.mres != status->mres) + clif_updatestatus(sd, SP_MRES); + if (b_status.hplus != status->hplus) + clif_updatestatus(sd, SP_HPLUS); + if (b_status.crate != status->crate) + clif_updatestatus(sd, SP_CRATE); + if (b_status.max_ap != status->max_ap) + clif_updatestatus(sd, SP_MAXAP); + if (b_status.ap != status->ap) + clif_updatestatus(sd, SP_AP); +#endif } else if( bl->type == BL_HOM ) { TBL_HOM* hd = BL_CAST(BL_HOM, bl); @@ -6847,6 +7773,114 @@ static unsigned short status_calc_luk(struct block_list *bl, struct status_chang return (unsigned short)cap_value(luk,0,USHRT_MAX); } +/** +* Adds power modifications based on status changes +* @param bl: Object to change pow [PC|MOB|HOM|MER|ELEM] +* @param sc: Object's status change information +* @param pow: Initial pow +* @return modified pow with cap_value(pow,0,USHRT_MAX) +*/ +static unsigned short status_calc_pow(struct block_list *bl, struct status_change *sc, int pow) +{ + if (!sc || !sc->count) + return cap_value(pow, 0, USHRT_MAX); + + if (sc->data[SC_BENEDICTUM]) + pow += sc->data[SC_BENEDICTUM]->val2; + + return (unsigned short)cap_value(pow, 0, USHRT_MAX); +} + +/** +* Adds stamina modifications based on status changes +* @param bl: Object to change sta [PC|MOB|HOM|MER|ELEM] +* @param sc: Object's status change information +* @param sta: Initial sta +* @return modified sta with cap_value(sta,0,USHRT_MAX) +*/ +static unsigned short status_calc_sta(struct block_list *bl, struct status_change *sc, int sta) +{ + if (!sc || !sc->count) + return cap_value(sta, 0, USHRT_MAX); + + if (sc->data[SC_RELIGIO]) + sta += sc->data[SC_RELIGIO]->val2; + + return (unsigned short)cap_value(sta, 0, USHRT_MAX); +} + +/** +* Adds wisdom modifications based on status changes +* @param bl: Object to change wis [PC|MOB|HOM|MER|ELEM] +* @param sc: Object's status change information +* @param wis: Initial wis +* @return modified wis with cap_value(wis,0,USHRT_MAX) +*/ +static unsigned short status_calc_wis(struct block_list *bl, struct status_change *sc, int wis) +{ + if (!sc || !sc->count) + return cap_value(wis, 0, USHRT_MAX); + + if (sc->data[SC_RELIGIO]) + wis += sc->data[SC_RELIGIO]->val2; + + return (unsigned short)cap_value(wis, 0, USHRT_MAX); +} + +/** +* Adds spell modifications based on status changes +* @param bl: Object to change spl [PC|MOB|HOM|MER|ELEM] +* @param sc: Object's status change information +* @param spl: Initial spl +* @return modified spl with cap_value(spl,0,USHRT_MAX) +*/ +static unsigned short status_calc_spl(struct block_list *bl, struct status_change *sc, int spl) +{ + if (!sc || !sc->count) + return cap_value(spl, 0, USHRT_MAX); + + if (sc->data[SC_RELIGIO]) + spl += sc->data[SC_RELIGIO]->val2; + + return (unsigned short)cap_value(spl, 0, USHRT_MAX); +} + +/** +* Adds concentration modifications based on status changes +* @param bl: Object to change con [PC|MOB|HOM|MER|ELEM] +* @param sc: Object's status change information +* @param con: Initial con +* @return modified con with cap_value(con,0,USHRT_MAX) +*/ +static unsigned short status_calc_con(struct block_list *bl, struct status_change *sc, int con) +{ + if (!sc || !sc->count) + return cap_value(con, 0, USHRT_MAX); + + if (sc->data[SC_BENEDICTUM]) + con += sc->data[SC_BENEDICTUM]->val2; + + return (unsigned short)cap_value(con, 0, USHRT_MAX); +} + +/** +* Adds creative modifications based on status changes +* @param bl: Object to change crt [PC|MOB|HOM|MER|ELEM] +* @param sc: Object's status change information +* @param crt: Initial crt +* @return modified crt with cap_value(crt,0,USHRT_MAX) +*/ +static unsigned short status_calc_crt(struct block_list *bl, struct status_change *sc, int crt) +{ + if (!sc || !sc->count) + return cap_value(crt, 0, USHRT_MAX); + + if (sc->data[SC_BENEDICTUM]) + crt += sc->data[SC_BENEDICTUM]->val2; + + return (unsigned short)cap_value(crt, 0, USHRT_MAX); +} + /** * Adds base attack modifications based on status changes * @param bl: Object to change batk [PC|MOB|HOM|MER|ELEM] @@ -7024,6 +8058,12 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan watk += sc->data[SC_SOULFALCON]->val2; if (sc->data[SC_PACKING_ENVELOPE1]) watk += sc->data[SC_PACKING_ENVELOPE1]->val1; + if (sc->data[SC_POWERFUL_FAITH]) + watk += sc->data[SC_POWERFUL_FAITH]->val2; + if (sc->data[SC_GUARD_STANCE]) + watk -= sc->data[SC_GUARD_STANCE]->val3; + if (sc->data[SC_ATTACK_STANCE]) + watk += sc->data[SC_ATTACK_STANCE]->val3; return (unsigned short)cap_value(watk,0,USHRT_MAX); } @@ -7164,6 +8204,8 @@ static unsigned short status_calc_matk(struct block_list *bl, struct status_chan #endif if (sc->data[SC_SHIELDSPELL_ATK]) matk += sc->data[SC_SHIELDSPELL_ATK]->val2; + if (sc->data[SC_CLIMAX_DES_HU]) + matk += 100; return (unsigned short)cap_value(matk,0,USHRT_MAX); } @@ -7282,6 +8324,8 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change hit -= 50 + 50 * sc->data[SC_SATURDAYNIGHTFEVER]->val1; if (sc->data[SC_PACKING_ENVELOPE10]) hit += sc->data[SC_PACKING_ENVELOPE10]->val1; + if (sc->data[SC_ABYSS_SLAYER]) + hit += sc->data[SC_ABYSS_SLAYER]->val3; return (short)cap_value(hit,1,SHRT_MAX); } @@ -7524,6 +8568,14 @@ static defType status_calc_def(struct block_list *bl, struct status_change *sc, def += sc->data[SC_STONE_WALL]->val2; if( sc->data[SC_PACKING_ENVELOPE7] ) def += sc->data[SC_PACKING_ENVELOPE7]->val1; + if (sc->data[SC_D_MACHINE]) + def += sc->data[SC_D_MACHINE]->val2; + if (sc->data[SC_CLIMAX_CRYIMP]) + def += 300; + if (sc->data[SC_GUARD_STANCE]) + def += sc->data[SC_GUARD_STANCE]->val2; + if (sc->data[SC_ATTACK_STANCE]) + def -= sc->data[SC_ATTACK_STANCE]->val2; return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX); } @@ -7654,6 +8706,8 @@ static defType status_calc_mdef(struct block_list *bl, struct status_change *sc, mdef += sc->data[SC_STONE_WALL]->val3; if (sc->data[SC_PACKING_ENVELOPE8]) mdef += sc->data[SC_PACKING_ENVELOPE8]->val1; + if (sc->data[SC_CLIMAX_CRYIMP]) + mdef += 100; return (defType)cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX); } @@ -8077,6 +9131,8 @@ static short status_calc_fix_aspd(struct block_list *bl, struct status_change *s aspd -= 100; // +10 ASPD if (sc->data[SC_PACKING_ENVELOPE6]) aspd -= sc->data[SC_PACKING_ENVELOPE6]->val1 * 10; + if (sc->data[SC_SINCERE_FAITH]) + aspd -= 10 * sc->data[SC_SINCERE_FAITH]->val2; return cap_value(aspd, 0, 2000); // Will be recap for proper bl anyway } @@ -8256,6 +9312,133 @@ static unsigned short status_calc_dmotion(struct block_list *bl, struct status_c return (unsigned short)cap_value(dmotion,0,USHRT_MAX); } +/** +* Adds power atk modifications based on status changes +* @param bl: Object to change patk [PC|MOB|HOM|MER|ELEM] +* @param sc: Object's status change information +* @param patk: Initial patk +* @return modified patk with cap_value(patk,0,USHRT_MAX) +*/ +static signed short status_calc_patk(struct block_list *bl, struct status_change *sc, int patk) +{ + if (!sc || !sc->count) + return cap_value(patk, 0, SHRT_MAX); + + if (sc->data[SC_POWERFUL_FAITH]) + patk += sc->data[SC_POWERFUL_FAITH]->val3; + if (sc->data[SC_COMPETENTIA]) + patk += sc->data[SC_COMPETENTIA]->val2; + if (sc->data[SC_ABYSS_SLAYER]) + patk += sc->data[SC_ABYSS_SLAYER]->val2; + if (sc->data[SC_PRON_MARCH]) + patk += sc->data[SC_PRON_MARCH]->val2; + + return (short)cap_value(patk, 0, SHRT_MAX); +} + +/** +* Adds spell matk modifications based on status changes +* @param bl: Object to change smatk [PC|MOB|HOM|MER|ELEM] +* @param sc: Object's status change information +* @param smatk: Initial smatk +* @return modified smatk with cap_value(smatk,0,USHRT_MAX) +*/ +static signed short status_calc_smatk(struct block_list *bl, struct status_change *sc, int smatk) +{ + if (!sc || !sc->count) + return cap_value(smatk, 0, SHRT_MAX); + + if (sc->data[SC_COMPETENTIA]) + smatk += sc->data[SC_COMPETENTIA]->val2; + if (sc->data[SC_ABYSS_SLAYER]) + smatk += sc->data[SC_ABYSS_SLAYER]->val2; + if (sc->data[SC_JAWAII_SERENADE]) + smatk += sc->data[SC_JAWAII_SERENADE]->val2; + if (sc->data[SC_SPELL_ENCHANTING]) + smatk += sc->data[SC_SPELL_ENCHANTING]->val2; + + return (short)cap_value(smatk, 0, SHRT_MAX); +} + +/** +* Adds resist modifications based on status changes +* @param bl: Object to change res [PC|MOB|HOM|MER|ELEM] +* @param sc: Object's status change information +* @param res: Initial res +* @return modified res with cap_value(res,0,USHRT_MAX) +*/ +static signed short status_calc_res(struct block_list *bl, struct status_change *sc, int res) +{ + if (!sc || !sc->count) + return cap_value(res, 0, SHRT_MAX); + + if (sc->data[SC_FIRM_FAITH]) + res += sc->data[SC_FIRM_FAITH]->val3; + if (sc->data[SC_D_MACHINE]) + res += sc->data[SC_D_MACHINE]->val3; + if (sc->data[SC_MUSICAL_INTERLUDE]) + res += sc->data[SC_MUSICAL_INTERLUDE]->val2; + if (sc->data[SC_SHADOW_STRIP] && bl->type != BL_PC) + res -= res * sc->data[SC_SHADOW_STRIP]->val2 / 100; + if (sc->data[SC_AIN_RHAPSODY]) + res -= sc->data[SC_AIN_RHAPSODY]->val2; + + return (short)cap_value(res, 0, SHRT_MAX); +} + +/** +* Adds magic resist modifications based on status changes +* @param bl: Object to change mres [PC|MOB|HOM|MER|ELEM] +* @param sc: Object's status change information +* @param mres: Initial mres +* @return modified mres with cap_value(mres,0,USHRT_MAX) +*/ +static signed short status_calc_mres(struct block_list *bl, struct status_change *sc, int mres) +{ + if (!sc || !sc->count) + return cap_value(mres, 0, SHRT_MAX); + + if (sc->data[SC_SHADOW_STRIP] && bl->type != BL_PC) + mres -= mres * sc->data[SC_SHADOW_STRIP]->val2 / 100; + if (sc->data[SC_GEF_NOCTURN]) + mres -= sc->data[SC_GEF_NOCTURN]->val2; + + return (short)cap_value(mres, 0, SHRT_MAX); +} + +/** +* Adds heal plus modifications based on status changes +* @param bl: Object to change hplus [PC|MOB|HOM|MER|ELEM] +* @param sc: Object's status change information +* @param hplus: Initial hplus +* @return modified hplus with cap_value(hplus,0,USHRT_MAX) +*/ +static signed short status_calc_hplus(struct block_list *bl, struct status_change *sc, int hplus) +{ + if (!sc || !sc->count) + return cap_value(hplus, 0, SHRT_MAX); + + return (short)cap_value(hplus, 0, SHRT_MAX); +} + +/** +* Adds critical damage rate modifications based on status changes +* @param bl: Object to change crate [PC|MOB|HOM|MER|ELEM] +* @param sc: Object's status change information +* @param crate: Initial crate +* @return modified crate with cap_value(crate,0,USHRT_MAX) +*/ +static signed short status_calc_crate(struct block_list *bl, struct status_change *sc, int crate) +{ + if (!sc || !sc->count) + return cap_value(crate, 0, SHRT_MAX); + + if (sc->data[SC_PRE_ACIES]) + crate += sc->data[SC_PRE_ACIES]->val2; + + return (short)cap_value(crate, 0, SHRT_MAX); +} + /** * Calculates a max HP based on status changes * Values can either be percentages or fixed, based on how equations are formulated @@ -8294,6 +9477,25 @@ static unsigned int status_calc_maxsp(struct block_list *bl, uint64 maxsp) return (unsigned int)cap_value(maxsp,1,UINT_MAX); } +/** +* Calculates a max AP based on status changes +* Values can either be percentages or fixed, bas ed on how equations are formulated +* @param bl: Object's block_list data +* @param maxap: Object's current max AP +* @return modified maxap +*/ +static unsigned int status_calc_maxap(struct block_list *bl, uint64 maxap) +{ + int rate = 100; + + maxap += status_get_apbonus(bl, STATUS_BONUS_FIX); + + if ((rate += status_get_apbonus(bl, STATUS_BONUS_RATE)) != 100) + maxap = maxap * rate / 100; + + return (unsigned int)cap_value(maxap, 0, UINT_MAX); +} + /** * Changes a player's element based on status changes * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM] @@ -8306,10 +9508,16 @@ static unsigned char status_calc_element(struct block_list *bl, struct status_ch if(!sc || !sc->count) return cap_value(element, 0, UCHAR_MAX); - if(sc->data[SC_FREEZE]) + if(sc->data[SC_FREEZE] || sc->data[SC_CRYSTAL_ARMOR_OPTION]) return ELE_WATER; - if(sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) + if((sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) || sc->data[SC_STRONG_PROTECTION_OPTION]) return ELE_EARTH; + if(sc->data[SC_FLAMEARMOR_OPTION]) + return ELE_FIRE; + if(sc->data[SC_EYES_OF_STORM_OPTION]) + return ELE_WIND; + if(sc->data[SC_POISON_SHIELD_OPTION]) + return ELE_POISON; if(sc->data[SC_BENEDICTIO]) return ELE_HOLY; if(sc->data[SC_CHANGEUNDEAD]) @@ -8348,6 +9556,9 @@ static unsigned char status_calc_element_lv(struct block_list *bl, struct status return 1; if(sc->data[SC__INVISIBILITY]) return 1; + if (sc->data[SC_FLAMEARMOR_OPTION] || sc->data[SC_CRYSTAL_ARMOR_OPTION] || sc->data[SC_EYES_OF_STORM_OPTION] || + sc->data[SC_STRONG_PROTECTION_OPTION] || sc->data[SC_POISON_SHIELD_OPTION]) + return 1; return (unsigned char)cap_value(lv,1,4); } @@ -8767,8 +9978,14 @@ int status_isdead(struct block_list *bl) int status_isimmune(struct block_list *bl) { struct status_change *sc =status_get_sc(bl); - if (sc && sc->data[SC_HERMODE]) - return 100; + + if (sc) { + if (sc->data[SC_HERMODE]) + return 100; + + if (sc->data[SC_DEADLY_DEFEASANCE]) + return 0; + } if (bl->type == BL_PC && ((TBL_PC*)bl)->special_state.no_magic_damage >= battle_config.gtb_sc_immunity) @@ -9061,7 +10278,7 @@ t_tick status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_ if (status_isimmune(bl)) { std::shared_ptr skill = skill_db.find(battle_getcurrentskill(src)); - if (skill != nullptr && skill->skill_type == BF_MAGIC) + if (skill != nullptr && skill->nameid != AG_DEADLY_PROJECTION && skill->skill_type == BF_MAGIC) return 0; } @@ -9515,7 +10732,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty struct status_change_entry* sce; struct status_data *status; struct view_data *vd; - int calc_flag, undead_flag, val_flag = 0, tick_time = 0; + int undead_flag, val_flag = 0, tick_time = 0; + uint64 calc_flag; bool sc_isnew = true; nullpo_ret(bl); @@ -9731,6 +10949,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty break; case SC_KYRIE: case SC_TUNAPARTY: + case SC_GUARDIAN_S: if (bl->type == BL_MOB) return 0; break; @@ -9858,6 +11077,28 @@ 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_SHADOW_STRIP: + if (sd && !(flag&SCSTART_LOADED)) { + if (sd->bonus.unstripable_equip&EQP_SHADOW_GEAR) + return 0; + + bool successFlag = false; + + for( int i = EQI_SHADOW_ARMOR; i <= EQI_SHADOW_ACC_L; i++ ){ + int index = sd->equip_index[i]; + + if( index >= 0 && sd->inventory_data[index] != nullptr ){ + pc_unequipitem( sd, index, 3 ); + successFlag = true; + } + } + + if (!successFlag) + return 0; + } + if (tick == 1) + return 1; + break; case SC_MERC_FLEEUP: case SC_MERC_ATKUP: case SC_MERC_HPUP: @@ -10060,6 +11301,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_BITESCAR: case SC_SP_SHA: case SC_FRESHSHRIMP: + case SC_SHADOW_STRIP: return 0; } } @@ -10459,6 +11701,31 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty status_change_end(bl,SC_FOOD_DEX_CASH,INVALID_TIMER); status_change_end(bl,SC_FOOD_LUK_CASH,INVALID_TIMER); break; + case SC_POWERFUL_FAITH: + case SC_FIRM_FAITH: + case SC_SINCERE_FAITH: + status_change_end(bl, SC_POWERFUL_FAITH, INVALID_TIMER); + status_change_end(bl, SC_FIRM_FAITH, INVALID_TIMER); + status_change_end(bl, SC_SINCERE_FAITH, INVALID_TIMER); + break; + case SC_FIRST_FAITH_POWER: + case SC_SECOND_JUDGE: + case SC_THIRD_EXOR_FLAME: + status_change_end(bl, SC_FIRST_FAITH_POWER, INVALID_TIMER); + status_change_end(bl, SC_SECOND_JUDGE, INVALID_TIMER); + status_change_end(bl, SC_THIRD_EXOR_FLAME, INVALID_TIMER); + break; + case SC_FIRST_BRAND: + case SC_SECOND_BRAND: + status_change_end(bl, SC_FIRST_BRAND, INVALID_TIMER); + status_change_end(bl, SC_SECOND_BRAND, INVALID_TIMER); + break; + case SC_GUARD_STANCE: + status_change_end(bl, SC_ATTACK_STANCE, INVALID_TIMER); + break; + case SC_ATTACK_STANCE: + status_change_end(bl, SC_GUARD_STANCE, INVALID_TIMER); + break; case SC_FIGHTINGSPIRIT: case SC_OVERED_BOOST: case SC_MAGICPOWER: @@ -10594,6 +11861,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_LHZ_DUN_N4: case SC_FLASHKICK: case SC_SOULUNITY: + case SC_SERVANT_SIGN: break; case SC_GOSPEL: // Must not override a casting gospel char. @@ -12606,6 +13874,171 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_SP_SHA: val2 = 50; // Move speed reduction break; + case SC_SERVANTWEAPON: + if( sd ){ + // Generate 5 servants on start + pc_addservantball( *sd, MAX_SERVANTBALL ); + } + tick_time = skill_get_time2(DK_SERVANTWEAPON,val1); // Servant Regen Interval + if (tick_time < 500) + tick_time = 500; // Avoid being brought down to 0. + val4 = tick - tick_time; // Remaining Time + break; + case SC_VIGOR: { + uint8 hp_loss[10] = { 15, 14, 12, 11, 9, 8, 6, 5, 3, 2 }; + + val2 = hp_loss[val1- 1]; + } + break; + case SC_POWERFUL_FAITH: + val2 = 5 + 5 * val1;// ATK Increase + val3 = 5 + 2 * val1;// PAtk Increase + break; + case SC_FIRM_FAITH: + val2 = 2 * val1;// MaxHP Increase + val3 = 8 * val1;// Res Increase + break; + case SC_SINCERE_FAITH: + val2 = (1 + val1) / 2;// ASPD Increase + val3 = 4 * val1;// Perfect Hit Increase + break; + case SC_GUARD_STANCE: + val2 = 50 + 50 * val1;// DEF Increase + val3 = 50 * val1;// ATK Decrease + tick = INFINITE_TICK; + break; + case SC_GUARDIAN_S: + val2 = status->max_hp * (50 * val1) / 100;// Barrier HP + break; + case SC_REBOUND_S: + val2 = 10 * val1;// Reduced Damage From Devotion + if (val2 > 99) + val2 = 99;// Lets not let it reduce above 99. + break; + case SC_ATTACK_STANCE: + val2 = 40 * val1;// DEF Decrease + val3 = 5 + 5 * val1;// ATK Increase + tick = INFINITE_TICK; + break; + case SC_HOLY_S: + val2 = 5 + 2 * val1;// Damage Reduction / Holy Damage Increase + break; + case SC_MEDIALE: + val2 = 2 * val1;// Heal Rate + val4 = tick / 2000; + tick_time = 2000; + break; + case SC_A_VITA: + case SC_A_TELUM: + val2 = 5 * val1;// Res/MRes Pierce Percentage + break; + case SC_PRE_ACIES: + val2 = 2 * val1;// CRate Increase + break; + case SC_COMPETENTIA: + val2 = 10 * val1;// PAtk/SMatk Increase - Unconfirmed if this is official formula but its 50 at Lv 5. [Rytech] + break; + case SC_RELIGIO: + case SC_BENEDICTUM: + val2 = 2 * val1;// Trait Stats Increase + break; + case SC_DANCING_KNIFE: + val4 = tick / 300; + tick_time = 300; + break; + case SC_POTENT_VENOM: + val2 = 3 * val1;// Res Pierce Percentage + break; + case SC_SHADOW_WEAPON: + val2 = val1;// Success Chance of Shadow Scar + break; + case SC_A_MACHINE: + val4 = tick / 1000; + tick_time = 1000; + break; + case SC_D_MACHINE: + val2 = 200 + 50 * val1;// DEF Increase + val3 = 20 * val1;// Res Increase + break; + case SC_SHADOW_STRIP: + if (!sd)// Res/MRes on mobs only. + val2 = 25;// Need official reduction amount. + break; + case SC_ABYSSFORCEWEAPON: + if( sd ){ + // Generate 5 abyss spheres on start. + pc_addabyssball( *sd, MAX_ABYSSBALL ); + } + tick_time = skill_get_time2(ABC_FROM_THE_ABYSS, val1);// Abyss Regen Interval + if (tick_time < 500) + tick_time = 500;// Avoid being brought down to 0. + val4 = tick - tick_time;// Remaining Time + break; + case SC_ABYSS_SLAYER: + val2 = 10 + 2 * val1;// PAtk/SMatk Increase + val3 = 100 + 20 * val1;// Hit Increase + break; + case SC_WINDSIGN: + val2 = 8 + 6 * val1;// Chance to gain AP on attack. + if (val1 == 5)// Its 40% on level 5. + val2 += 2; + break; + case SC_CALAMITYGALE:// Unlimit runs along with this. + sc_start(bl, bl, SC_UNLIMIT, 100, 5, skill_get_time(RA_UNLIMIT, 5)); + break; + case SC_GEF_NOCTURN:// MRes Reduction. Official formula unknown. + case SC_AIN_RHAPSODY:// Res Reduction. Official formula unknown. + val2 = 10 * val1;// Res/MRes Decrease + if (val3&2)// Bonus if partner is found in party. + val2 *= 2; + break; + case SC_MUSICAL_INTERLUDE: + val2 = 5 + 5 * val1;// Res Increase + if (val3&2)// Bonus if partner is found in party. + val2 *= 2; + break; + case SC_JAWAII_SERENADE: + val2 = 3 * val1;// SMatk Increase + if (val3 & 2)// Bonus if partner is found in party. + val2 *= 2; + break; + case SC_PRON_MARCH: + val2 = 3 * val1;// PAtk Increase + if (val3 & 2)// Bonus if partner is found in party. + val2 *= 2; + break; + case SC_SPELL_ENCHANTING: + val2 = 4 * val1;// SMatk Increase + break; + case SC_FLAMETECHNIC: + case SC_FLAMEARMOR: + case SC_COLD_FORCE: + case SC_CRYSTAL_ARMOR: + case SC_GRACE_BREEZE: + case SC_EYES_OF_STORM: + case SC_EARTH_CARE: + case SC_STRONG_PROTECTION: + case SC_DEEP_POISONING: + case SC_POISON_SHIELD: + val2 += 10; + val3 += 10000; + tick_time = val3; + break; + case SC_FLAMETECHNIC_OPTION: + val3 = ELE_FIRE; + break; + case SC_COLD_FORCE_OPTION: + val3 = ELE_WATER; + break; + case SC_GRACE_BREEZE_OPTION: + val3 = ELE_WIND; + break; + case SC_EARTH_CARE_OPTION: + val3 = ELE_EARTH; + break; + case SC_DEEP_POISONING_OPTION: + val3 = ELE_POISON; + break; default: if( calc_flag == SCB_NONE && StatusSkillChangeTable[type] == -1 && StatusIconChangeTable[type] == EFST_BLANK ) { @@ -12665,6 +14098,11 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty return 0; } break; + case SC_SERVANTWEAPON: + case SC_ABYSSFORCEWEAPON: + tick_time = tick; + tick = tick_time + max(val4, 0); + break; } // Values that must be set regardless of flag&4 e.g. val_flag [Ind] @@ -12695,6 +14133,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_DRESSUP: case SC_MISTY_FROST: case SC_MADOGEAR: + case SC_CHARGINGPIERCE_COUNT: + case SC_CLIMAX: + case SC_E_SLASH_COUNT: val_flag |= 1; break; // Start |1|2 val_flag setting @@ -13348,6 +14789,8 @@ int status_change_clear(struct block_list* bl, int type) case SC_PACKING_ENVELOPE9: case SC_PACKING_ENVELOPE10: case SC_SOULATTACK: + case SC_GUARD_STANCE: + case SC_ATTACK_STANCE: // Costumes case SC_MOONSTAR: case SC_SUPER_STAR: @@ -13694,8 +15137,10 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const } break; case SC_SPLASHER: + case SC_ROSEBLOSSOM: { struct block_list *src=map_id2bl(sce->val3); + if(src && tid != INVALID_TIMER) skill_castend_damage_id(src, bl, sce->val2, sce->val1, gettick(), SD_LEVEL ); } @@ -14044,6 +15489,33 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const if (sd && hom_is_active(sd->hd)) hom_vaporize(sd, HOM_ST_REST); break; + case SC_SERVANT_SIGN: { + map_session_data *tsd = map_id2sd(sce->val1); + + if( tsd != nullptr ) + tsd->servant_sign[sce->val2] = 0; + } + break; + case SC_SOUNDBLEND: { + block_list *src = map_id2bl(sce->val2); + + if (src && tid != INVALID_TIMER) + skill_castend_damage_id(src, bl, TR_SOUNDBLEND, sce->val1, gettick(), SD_LEVEL|SD_ANIMATION); + } + break; + case SC_SERVANTWEAPON: + if( sd ){ + pc_delservantball( *sd, sd->servantball ); + } + break; + case SC_CHARGINGPIERCE: + status_change_end(bl, SC_CHARGINGPIERCE_COUNT, INVALID_TIMER); + break; + case SC_ABYSSFORCEWEAPON: + if( sd ){ + pc_delabyssball( *sd, sd->abyssball ); + } + break; } uint16 opt_flag = OCF_SEND_OPTION; @@ -14979,6 +16451,16 @@ TIMER_FUNC(status_change_timer){ case SC_WIND_STEP: case SC_STONE_SHIELD: case SC_SOLID_SKIN: + case SC_FLAMETECHNIC: + case SC_FLAMEARMOR: + case SC_COLD_FORCE: + case SC_CRYSTAL_ARMOR: + case SC_GRACE_BREEZE: + case SC_EYES_OF_STORM: + case SC_EARTH_CARE: + case SC_STRONG_PROTECTION: + case SC_DEEP_POISONING: + case SC_POISON_SHIELD: if( !status_charge(bl,0,sce->val2) ) { struct block_list *s_bl = battle_get_master(bl); if (bl->type == BL_ELEM) @@ -15266,6 +16748,50 @@ TIMER_FUNC(status_change_timer){ return 0; } break; + case SC_MEDIALE: + if (--(sce->val4) >= 0) { + clif_specialeffect(bl, 1808, AREA); + skill_castend_nodamage_id(bl, bl, CD_MEDIALE_VOTUM, sce->val1, tick, 1); + sc_timer_next(2000 + tick); + return 0; + } + break; + + case SC_DANCING_KNIFE: + if (--(sce->val4) >= 0) { + skill_castend_nodamage_id(bl, bl, SHC_DANCING_KNIFE, sce->val1, tick, 1); + sc_timer_next(300 + tick); + return 0; + } + break; + + case SC_A_MACHINE: + if (--(sce->val4) >= 0) { + skill_castend_nodamage_id(bl, bl, MT_A_MACHINE, sce->val1, tick, 1); + sc_timer_next(1000 + tick); + return 0; + } + break; + case SC_SERVANTWEAPON: + if (sce->val4 >= 0) { + if( sd && sd->servantball < MAX_SERVANTBALL ){ + pc_addservantball( *sd, MAX_SERVANTBALL ); + } + interval = max(500, skill_get_time2(DK_SERVANTWEAPON, sce->val1)); + map_freeblock_lock(); + dounlock = true; + } + break; + case SC_ABYSSFORCEWEAPON: + if (sce->val4 >= 0) { + if( sd && sd->abyssball < MAX_ABYSSBALL ){ + pc_addabyssball( *sd ); + } + interval = max(500, skill_get_time2(ABC_FROM_THE_ABYSS, sce->val1)); + map_freeblock_lock(); + dounlock = true; + } + break; } // If status has an interval and there is at least 100ms remaining time, wait for next interval @@ -15539,6 +17065,7 @@ void status_change_clear_buffs(struct block_list* bl, uint8 type) case SC_CP_SHIELD: case SC_CP_ARMOR: case SC_CP_HELM: + case SC_PROTECTSHADOWEQUIP: if(!(type&SCCB_CHEM_PROTECT)) continue; break; @@ -15580,6 +17107,7 @@ void status_change_clear_buffs(struct block_list* bl, uint8 type) case SC_MAGNETICFIELD: case SC_NETHERWORLD: case SC_CREATINGSTAR: + case SC_SHADOW_STRIP: if (!(type&SCCB_DEBUFFS)) continue; break; diff --git a/src/map/status.hpp b/src/map/status.hpp index 838e372b53..420d665b48 100644 --- a/src/map/status.hpp +++ b/src/map/status.hpp @@ -1027,6 +1027,146 @@ enum sc_type : int16 { SC_BURNT, SC_CHILL, + // 4th Job Common Status + SC_HANDICAPSTATE_DEEPBLIND, + SC_HANDICAPSTATE_DEEPSILENCE, + SC_HANDICAPSTATE_LASSITUDE, + SC_HANDICAPSTATE_FROSTBITE, + SC_HANDICAPSTATE_SWOONING, + SC_HANDICAPSTATE_LIGHTNINGSTRIKE, + SC_HANDICAPSTATE_CRYSTALLIZATION, + SC_HANDICAPSTATE_CONFLAGRATION, + SC_HANDICAPSTATE_MISFORTUNE, + SC_HANDICAPSTATE_DEADLYPOISON, + SC_HANDICAPSTATE_DEPRESSION, + SC_HANDICAPSTATE_HOLYFLAME, + + // Dragon Knight + SC_SERVANTWEAPON, + SC_SERVANT_SIGN, + SC_CHARGINGPIERCE, + SC_CHARGINGPIERCE_COUNT, + SC_DRAGONIC_AURA, + SC_VIGOR, + + // Arch Mage + SC_DEADLY_DEFEASANCE, + SC_CLIMAX_DES_HU, + SC_CLIMAX, + SC_CLIMAX_EARTH, + SC_CLIMAX_BLOOM, + SC_CLIMAX_CRYIMP, + + // Windhawk + SC_WINDSIGN, + SC_CRESCIVEBOLT, + SC_CALAMITYGALE, + + // Cardinal + SC_MEDIALE, + SC_A_VITA, + SC_A_TELUM, + SC_PRE_ACIES, + SC_COMPETENTIA, + SC_RELIGIO, + SC_BENEDICTUM, + + // Meister + SC_AXE_STOMP, + SC_A_MACHINE, + SC_D_MACHINE, + SC_ABR_BATTLE_WARIOR, + SC_ABR_DUAL_CANNON, + SC_ABR_MOTHER_NET, + SC_ABR_INFINITY, + + // Shadow Cross + SC_SHADOW_EXCEED, + SC_DANCING_KNIFE, + SC_POTENT_VENOM, + SC_SHADOW_SCAR, + SC_E_SLASH_COUNT, + SC_SHADOW_WEAPON, + + // Imperial Guard + SC_GUARD_STANCE, + SC_ATTACK_STANCE, + SC_GUARDIAN_S, + SC_REBOUND_S, + SC_HOLY_S, + SC_ULTIMATE_S, + SC_SPEAR_SCAR, + SC_SHIELD_POWER, + + // Elemental Master + SC_SPELL_ENCHANTING, + SC_SUMMON_ELEMENTAL_ARDOR, + SC_SUMMON_ELEMENTAL_DILUVIO, + SC_SUMMON_ELEMENTAL_PROCELLA, + SC_SUMMON_ELEMENTAL_TERREMOTUS, + SC_SUMMON_ELEMENTAL_SERPENS, + SC_ELEMENTAL_VEIL, + + // Troubadour/Trouvere + SC_MYSTIC_SYMPHONY, + SC_KVASIR_SONATA, + SC_SOUNDBLEND, + SC_GEF_NOCTURN, + SC_AIN_RHAPSODY, + SC_MUSICAL_INTERLUDE, + SC_JAWAII_SERENADE, + SC_PRON_MARCH, + SC_ROSEBLOSSOM, + + // Inquisitor + SC_POWERFUL_FAITH, + SC_SINCERE_FAITH, + SC_FIRM_FAITH, + SC_HOLY_OIL, + SC_FIRST_BRAND, + SC_SECOND_BRAND, + SC_SECOND_JUDGE, + SC_THIRD_EXOR_FLAME, + SC_FIRST_FAITH_POWER, + SC_MASSIVE_F_BLASTER, + + // Biolo + SC_PROTECTSHADOWEQUIP, + SC_RESEARCHREPORT, + SC_BO_HELL_DUSTY, + SC_BIONIC_WOODENWARRIOR, + SC_BIONIC_WOODEN_FAIRY, + SC_BIONIC_CREEPER, + SC_BIONIC_HELLTREE, + + // Abyss Chaser + SC_SHADOW_STRIP, + SC_ABYSS_DAGGER, + SC_ABYSSFORCEWEAPON, + SC_ABYSS_SLAYER, + + // Super Elementals + SC_FLAMETECHNIC, + SC_FLAMETECHNIC_OPTION, + SC_FLAMEARMOR, + SC_FLAMEARMOR_OPTION, + SC_COLD_FORCE, + SC_COLD_FORCE_OPTION, + SC_CRYSTAL_ARMOR, + SC_CRYSTAL_ARMOR_OPTION, + SC_GRACE_BREEZE, + SC_GRACE_BREEZE_OPTION, + SC_EYES_OF_STORM, + SC_EYES_OF_STORM_OPTION, + SC_EARTH_CARE, + SC_EARTH_CARE_OPTION, + SC_STRONG_PROTECTION, + SC_STRONG_PROTECTION_OPTION, + SC_DEEP_POISONING, + SC_DEEP_POISONING_OPTION, + SC_POISON_SHIELD, + SC_POISON_SHIELD_OPTION, + #ifdef RENEWAL SC_EXTREMITYFIST2, //! NOTE: This SC should be right before SC_MAX, so it doesn't disturb if RENEWAL is disabled #endif @@ -2532,8 +2672,8 @@ enum scs_flag { }; ///Define flags for the status_calc_bl function. [Skotlex] -enum scb_flag -{ +enum scb_flag : uint64 +{ // Main Flags SCB_NONE = 0x00000000, SCB_BASE = 0x00000001, SCB_MAXHP = 0x00000002, @@ -2565,10 +2705,29 @@ enum scb_flag SCB_RACE = 0x08000000, SCB_RANGE = 0x10000000, SCB_REGEN = 0x20000000, - SCB_DYE = 0x40000000, // force cloth-dye change to 0 to avoid client crashes. - SCB_BATTLE = 0x3FFFFFFE, - SCB_ALL = 0x3FFFFFFF + // 4th Job T.Stat/T.Sub-Stat Flags + SCB_MAXAP = 0x40000000, + SCB_POW = 0x80000000, + SCB_STA = 0x000100000000, + SCB_WIS = 0x000200000000, + SCB_SPL = 0x000400000000, + SCB_CON = 0x000800000000, + SCB_CRT = 0x001000000000, + SCB_PATK = 0x002000000000, + SCB_SMATK = 0x004000000000, + SCB_RES = 0x008000000000, + SCB_MRES = 0x010000000000, + SCB_HPLUS = 0x020000000000, + SCB_CRATE = 0x040000000000, + + // Extra Flags + // These are flags not sent through battle/all flags. Always keep these last. + SCB_DYE = 0x080000000000, // force cloth-dye change to 0 to avoid client crashes. + + // Special flags for updating all stat/sub-stat stuff on request. + SCB_BATTLE = 0x07FFFFFFFFFE,// All except BASE and extra flags. + SCB_ALL = 0x07FFFFFFFFFF// All except extra flags. }; enum e_status_calc_opt { @@ -2664,7 +2823,7 @@ struct weapon_atk { extern sc_type SkillStatusChangeTable[MAX_SKILL]; /// skill -> status extern int StatusIconChangeTable[SC_MAX]; /// status -> "icon" (icon is a bit of a misnomer, since there exist values with no icon associated) -extern unsigned int StatusChangeFlagTable[SC_MAX]; /// status -> flags +extern uint64 StatusChangeFlagTable[SC_MAX]; /// status -> flags extern int StatusSkillChangeTable[SC_MAX]; /// status -> skill extern int StatusRelevantBLTypes[EFST_MAX]; /// "icon" -> enum bl_type (for clif->status_change to identify for which bl types to send packets) extern unsigned int StatusChangeStateTable[SC_MAX]; /// status -> flags @@ -2673,10 +2832,11 @@ extern unsigned int StatusDisplayType[SC_MAX]; ///For holding basic status (which can be modified by status changes) struct status_data { unsigned int - hp, sp, // see status_cpy before adding members before hp and sp - max_hp, max_sp; + hp, sp, ap, // see status_cpy before adding members before hp and sp + max_hp, max_sp, max_ap; short str, agi, vit, int_, dex, luk, + pow, sta, wis, spl, con, crt, eatk; unsigned short batk, @@ -2694,7 +2854,10 @@ struct status_data { #ifdef RENEWAL_ASPD aspd_rate2, #endif - aspd_rate; + aspd_rate, + patk, smatk, + res, mres, + hplus, crate; /** * defType is RENEWAL dependent and defined in src/config/const.hpp **/ @@ -2707,8 +2870,6 @@ struct status_data { class_; /// see enum e_classAE struct weapon_atk rhw, lhw; //Right Hand/Left Hand Weapon. - - uint16 pow, sta, wis, spl, con, crt; }; ///Additional regen data that only players have. @@ -2807,32 +2968,59 @@ static const std::vector mado_statuses = { // for looking up associated data sc_type status_skill2sc(int skill); int status_sc2skill(sc_type sc); -unsigned int status_sc2scb_flag(sc_type sc); +uint64 status_sc2scb_flag(sc_type sc); int status_type2relevant_bl_types(int type); -int status_damage(struct block_list *src,struct block_list *target,int64 dhp,int64 dsp, t_tick walkdelay, int flag, uint16 skill_id); +int status_damage( struct block_list *src, struct block_list *target, int64 dhp, int64 dsp, int64 dap, t_tick walkdelay, int flag, uint16 skill_id ); +static int status_damage( struct block_list *src, struct block_list *target, int64 dhp, int64 dsp, t_tick walkdelay, int flag, uint16 skill_id ){ + return status_damage( src, target, dhp, dsp, 0, walkdelay, flag, skill_id ); +} //Define for standard HP damage attacks. -#define status_fix_damage(src, target, hp, walkdelay, skill) status_damage(src, target, hp, 0, walkdelay, 0, skill) +static int status_fix_damage( struct block_list *src, struct block_list *target, int64 hp, t_tick walkdelay, uint16 skill_id ){ + return status_damage( src, target, hp, 0, walkdelay, 0, skill_id ); +} //Define for standard SP damage attacks. -#define status_fix_spdamage(src, target, sp, walkdelay, skill) status_damage(src, target, 0, sp, walkdelay, 0, skill) -//Define for standard HP/SP damage triggers. -#define status_zap(bl, hp, sp) status_damage(NULL, bl, hp, sp, 0, 1, 0) -//Define for standard HP/SP skill-related cost triggers (mobs require no HP/SP to use skills) +static int status_fix_spdamage( struct block_list *src, struct block_list *target, int64 sp, t_tick walkdelay, uint16 skill_id ){ + return status_damage( src, target, 0, sp, walkdelay, 0, skill_id ); +} +//Define for standard AP damage attacks. +static int status_fix_apdamage( struct block_list *src, struct block_list *target, int64 ap, t_tick walkdelay, uint16 skill_id ){ + return status_damage( src, target, 0, 0, ap, walkdelay, 0, skill_id ); +} +//Define for standard HP/SP/AP damage triggers. +static int status_zap( struct block_list* bl, int64 hp, int64 sp, int64 ap = 0 ){ + return status_damage( nullptr, bl, hp, sp, ap, 0, 1, 0 ); +} +//Define for standard HP/SP skill-related cost triggers (mobs require no HP/SP/AP to use skills) int64 status_charge(struct block_list* bl, int64 hp, int64 sp); -int status_percent_change(struct block_list *src, struct block_list *target, int8 hp_rate, int8 sp_rate, uint8 flag); +int status_percent_change(struct block_list *src, struct block_list *target, int8 hp_rate, int8 sp_rate, int8 ap_rate, uint8 flag); //Easier handling of status_percent_change -#define status_percent_heal(bl, hp_rate, sp_rate) status_percent_change(NULL, bl, -(hp_rate), -(sp_rate), 0) -/// Deals % damage from 'src' to 'target'. If rate is > 0 is % of current HP/SP, < 0 % of MaxHP/MaxSP -#define status_percent_damage(src, target, hp_rate, sp_rate, kill) status_percent_change(src, target, hp_rate, sp_rate, (kill)?1:2) +static int status_percent_heal( struct block_list* bl, int8 hp_rate, int8 sp_rate, int8 ap_rate = 0 ){ + return status_percent_change( nullptr, bl, -(hp_rate), -(sp_rate), -(ap_rate), 0 ); +} +/// Deals % damage from 'src' to 'target'. If rate is > 0 is % of current HP/SP/AP, < 0 % of MaxHP/MaxSP/MaxAP +static int status_percent_damage( struct block_list* src, struct block_list* target, int8 hp_rate, int8 sp_rate, bool kill ){ + return status_percent_change( src, target, hp_rate, sp_rate, 0, kill ? 1 : 2 ); +} +static int status_percent_damage( struct block_list* src, struct block_list* target, int8 hp_rate, int8 sp_rate, int8 ap_rate, bool kill ){ + return status_percent_change( src, target, hp_rate, sp_rate, ap_rate, kill ? 1 : 2 ); +} //Instant kill with no drops/exp/etc -#define status_kill(bl) status_percent_damage(NULL, bl, 100, 0, true) -//Used to set the hp/sp of an object to an absolute value (can't kill) +static int status_kill( struct block_list* bl ){ + return status_percent_damage( nullptr, bl, 100, 0, 0, true ); +} +//Used to set the hp/sp/ap of an object to an absolute value (can't kill) int status_set_hp(struct block_list *bl, unsigned int hp, int flag); int status_set_maxhp(struct block_list *bl, unsigned int hp, int flag); int status_set_sp(struct block_list *bl, unsigned int sp, int flag); int status_set_maxsp(struct block_list *bl, unsigned int hp, int flag); -int status_heal(struct block_list *bl,int64 hhp,int64 hsp, int flag); -int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per_sp); +int status_set_ap(struct block_list *bl, unsigned int ap, int flag); +int status_set_maxap(struct block_list *bl, unsigned int ap, int flag); +int status_heal( struct block_list *bl,int64 hhp,int64 hsp, int64 hap, int flag ); +static int status_heal( struct block_list *bl,int64 hhp,int64 hsp, int flag ){ + return status_heal( bl, hhp, hsp, 0, flag ); +} +int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per_sp, unsigned char per_ap = 0); struct regen_data *status_get_regen_data(struct block_list *bl); struct status_data *status_get_status_data(struct block_list *bl); @@ -2845,12 +3033,20 @@ int status_get_lv(struct block_list *bl); #define status_get_max_hp(bl) status_get_status_data(bl)->max_hp #define status_get_sp(bl) status_get_status_data(bl)->sp #define status_get_max_sp(bl) status_get_status_data(bl)->max_sp +#define status_get_ap(bl) status_get_status_data(bl)->ap +#define status_get_max_ap(bl) status_get_status_data(bl)->max_ap #define status_get_str(bl) status_get_status_data(bl)->str #define status_get_agi(bl) status_get_status_data(bl)->agi #define status_get_vit(bl) status_get_status_data(bl)->vit #define status_get_int(bl) status_get_status_data(bl)->int_ #define status_get_dex(bl) status_get_status_data(bl)->dex #define status_get_luk(bl) status_get_status_data(bl)->luk +#define status_get_pow(bl) status_get_status_data(bl)->pow +#define status_get_sta(bl) status_get_status_data(bl)->sta +#define status_get_wis(bl) status_get_status_data(bl)->wis +#define status_get_spl(bl) status_get_status_data(bl)->spl +#define status_get_con(bl) status_get_status_data(bl)->con +#define status_get_crt(bl) status_get_status_data(bl)->crt #define status_get_hit(bl) status_get_status_data(bl)->hit #define status_get_flee(bl) status_get_status_data(bl)->flee defType status_get_def(struct block_list *bl); @@ -2870,6 +3066,12 @@ unsigned short status_get_speed(struct block_list *bl); #define status_get_adelay(bl) status_get_status_data(bl)->adelay #define status_get_amotion(bl) status_get_status_data(bl)->amotion #define status_get_dmotion(bl) status_get_status_data(bl)->dmotion +#define status_get_patk(bl) status_get_status_data(bl)->patk +#define status_get_smatk(bl) status_get_status_data(bl)->smatk +#define status_get_res(bl) status_get_status_data(bl)->res +#define status_get_mres(bl) status_get_status_data(bl)->mres +#define status_get_hplus(bl) status_get_status_data(bl)->hplus +#define status_get_crate(bl) status_get_status_data(bl)->crate #define status_get_element(bl) status_get_status_data(bl)->def_ele #define status_get_element_level(bl) status_get_status_data(bl)->ele_lv unsigned char status_calc_attack_element(struct block_list *bl, struct status_change *sc, int element); diff --git a/src/map/unit.cpp b/src/map/unit.cpp index 48e59d3c2f..74c46c602c 100644 --- a/src/map/unit.cpp +++ b/src/map/unit.cpp @@ -1815,6 +1815,34 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui } } break; + case DK_SERVANT_W_SIGN: { + uint8 i = 0, count = min(skill_lv, MAX_SERVANT_SIGN); + + ARR_FIND( 0, count, i, sd->servant_sign[i] == target_id ); + + // Already targetted + if( i < count ){ + break; + } + + ARR_FIND( 0, count, i, sd->servant_sign[i] == 0 ); + + // No free slots + if( i == count ){ + clif_skill_fail( sd, skill_id, USESKILL_FAIL_LEVEL, 0 ); + return 0; + } + } + break; + case TR_RETROSPECTION: + // Prevent using the song skill if you no longer have the skill in your tree. + if (!sd->skill_id_song || pc_checkskill(sd, sd->skill_id_song) <= 0) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + return 0; + } + + sd->skill_id_old = skill_id; + break; } if (!skill_check_condition_castbegin(sd, skill_id, skill_lv)) @@ -1935,6 +1963,16 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui if (sc && sc->data[SC_WUGDASH]) casttime = -1; break; + case DK_SERVANT_W_PHANTOM: { // Stops servants from being consumed on unmarked targets. + status_change *tsc = status_get_sc(target); + + // Only allow to attack if the enemy has a sign mark given by the caster. + if( tsc == nullptr || tsc->data[SC_SERVANT_SIGN] == nullptr || tsc->data[SC_SERVANT_SIGN]->val1 != src->id ){ + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + return 0; + } + } + break; case EL_WIND_SLASH: case EL_HURRICANE: case EL_TYPOON_MIS: @@ -2023,12 +2061,12 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui if( sc ) { // These 3 status do not stack, so it's efficient to use if-else - if( sc->data[SC_CLOAKING] && !(sc->data[SC_CLOAKING]->val4&4) && skill_id != AS_CLOAKING ) { + if( sc->data[SC_CLOAKING] && !(sc->data[SC_CLOAKING]->val4&4) && skill_id != AS_CLOAKING && skill_id != SHC_SHADOW_STAB) { status_change_end(src, SC_CLOAKING, INVALID_TIMER); if (!src->prev) return 0; // Warped away! - } else if( sc->data[SC_CLOAKINGEXCEED] && !(sc->data[SC_CLOAKINGEXCEED]->val4&4) && skill_id != GC_CLOAKINGEXCEED ) { + } else if( sc->data[SC_CLOAKINGEXCEED] && !(sc->data[SC_CLOAKINGEXCEED]->val4&4) && skill_id != GC_CLOAKINGEXCEED && skill_id != SHC_SHADOW_STAB) { status_change_end(src,SC_CLOAKINGEXCEED, INVALID_TIMER); if (!src->prev) @@ -3041,6 +3079,7 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, status_change_end(bl, SC_TINDER_BREAKER, INVALID_TIMER); status_change_end(bl, SC_TINDER_BREAKER2, INVALID_TIMER); status_change_end(bl, SC_FLASHKICK, INVALID_TIMER); + status_change_end(bl, SC_SERVANT_SIGN, INVALID_TIMER); status_change_end(bl, SC_HIDING, INVALID_TIMER); // Ensure the bl is a PC; if so, we'll handle the removal of cloaking and cloaking exceed later if ( bl->type != BL_PC ) { diff --git a/src/tool/csv2yaml.cpp b/src/tool/csv2yaml.cpp index d12e0d9ee5..65a537eb85 100644 --- a/src/tool/csv2yaml.cpp +++ b/src/tool/csv2yaml.cpp @@ -275,14 +275,14 @@ int do_init( int argc, char** argv ){ } skill_txt_data( path_db_mode, path_db ); - if (!process("SKILL_DB", 2, { path_db_mode }, "skill_db", [](const std::string& path, const std::string& name_ext) -> bool { + if (!process("SKILL_DB", 3, { path_db_mode }, "skill_db", [](const std::string& path, const std::string& name_ext) -> bool { return sv_readdb(path.c_str(), name_ext.c_str(), ',', 18, 18, -1, &skill_parse_row_skilldb, false); })){ return 0; } skill_txt_data( path_db_import, path_db_import ); - if (!process("SKILL_DB", 2, { path_db_import }, "skill_db", [](const std::string& path, const std::string& name_ext) -> bool { + if (!process("SKILL_DB", 3, { path_db_import }, "skill_db", [](const std::string& path, const std::string& name_ext) -> bool { return sv_readdb(path.c_str(), name_ext.c_str(), ',', 18, 18, -1, &skill_parse_row_skilldb, false); })){ return 0; @@ -345,14 +345,14 @@ int do_init( int argc, char** argv ){ #endif mob_txt_data(path_db_mode, path_db); - if (!process("MOB_DB", 2, { path_db_mode }, "mob_db", [](const std::string &path, const std::string &name_ext) -> bool { + if (!process("MOB_DB", 3, { path_db_mode }, "mob_db", [](const std::string &path, const std::string &name_ext) -> bool { return sv_readdb(path.c_str(), name_ext.c_str(), ',', 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, -1, &mob_readdb_sub, false); })) { return 0; } mob_txt_data(path_db_import, path_db_import); - if (!process("MOB_DB", 2, { path_db_import }, "mob_db", [](const std::string &path, const std::string &name_ext) -> bool { + if (!process("MOB_DB", 3, { path_db_import }, "mob_db", [](const std::string &path, const std::string &name_ext) -> bool { return sv_readdb(path.c_str(), name_ext.c_str(), ',', 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, -1, &mob_readdb_sub, false); })) { return 0; diff --git a/src/tool/yaml2sql.cpp b/src/tool/yaml2sql.cpp index 04f6de9995..aa4c03aeb3 100644 --- a/src/tool/yaml2sql.cpp +++ b/src/tool/yaml2sql.cpp @@ -756,6 +756,12 @@ static bool mob_db_yaml2sql(const std::string &file, const std::string &table) { column.append("`defense`,"); if (appendEntry(input["MagicDefense"], value)) column.append("`magic_defense`,"); +#ifdef RENEWAL + if (appendEntry(input["Resistance"], value)) + column.append("`resistance`,"); + if (appendEntry(input["MagicResistance"], value)) + column.append("`magic_resistance`,"); +#endif if (appendEntry(input["Str"], value)) column.append("`str`,"); if (appendEntry(input["Agi"], value))