Implementation of Status Changes in YAML (#1685)

* Removes the initialization of Status Changes via hard-code and puts it into YAML form.
* From this database it is much easier to delegate icons, calc flags, opt flags, miscellaneous flags, and several other things for all stats changes.
* Statuses can quickly be reloaded via atcommand reloadstatus.
Thanks to @cydh, @Atemo, @Lemongrass3110, and the others who helped!
Signed-off-by: Cydh Ramdh <cydh@pservero.com>
Co-authored-by: atemo <capucrath@gmail.com>
Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
This commit is contained in:
Cydh Ramdh 2022-03-11 01:11:59 +07:00 committed by GitHub
parent e74bbfd37e
commit f28d207274
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 18120 additions and 5011 deletions

View File

@ -220,9 +220,6 @@ backstab_bow_penalty: yes
// Use 0 to disable (max allowed value is 255)
skill_steal_max_tries: 0
// Does Berserk/Frenzy cancel other self-buffs when used?
berserk_cancels_buffs: no
// Level and Strength of "MVP heal". When someone casts a heal of this level or
// above, the heal formula is bypassed and this value is used instead.
max_heal: 9999

View File

@ -13,13 +13,11 @@
status_cast_cancel: 0
// Will certain skill status-changes be removed on logout?
// This mimics official servers, where Extremity Fist's no SP regen,
// Strip Equipment, and some other buffs are removed when you logout. Setting is:
// 0 = remove nothing.
// 1 = remove negative buffs (stripping, EF)
// 2 = remove positive buffs (maximize power, steel body...)
// 3 = remove both negative and positive buffs.
debuff_on_logout: 3
// 0 = (Default) Only remove status that has the SCF_NO_SAVE flag.
// 1 = Remove negative buffs (status that are flagged as debuff)
// 2 = Remove positive buffs.
// 3 = Remove all.
debuff_on_logout: 0
// Adjustment for the natural rate of resistance from status changes.
// If 50, status defense is halved, and you need twice as much stats to block

View File

@ -135,6 +135,7 @@
# Interval Skill unit interval in milliseconds. (Default: 0)
# Target Skill unit target type. (Default: All)
# Flag: Skill unit flags. (Default: None)
# Status Status Change that is associated to the skill. (Optional)
###########################################################################
Header:

44
db/import-tmpl/status.yml Normal file
View File

@ -0,0 +1,44 @@
# This file is a part of rAthena.
# Copyright(C) 2022 rAthena Development Team
# https://rathena.org - https://github.com/rathena
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###########################################################################
# Status Change Database
###########################################################################
#
# Status Change Settings
#
###########################################################################
# - Status Status change name.
# Icon Status change icon. (Default: EFST_BLANK)
# DurationLookup Default status change duration. (Default: 0)
# States: Status change state to determine player states. (Default: None)
# CalcFlags: Status change calculation to indicate which stat is adjusted. (Default: None)
# Opt1 Special effect when a status change is active. Non-stackable. (Default: None)
# Opt2: Special options/client effects when a status change is active. (Default: None)
# Opt3: Special options/client effects when a status change is active. (Default: Normal)
# Options: Special options/client effects when a status change is active. (Default: Nothing)
# Flags: Special flags which trigger during certain events. (Default: None)
# MinRate Minimum rate after status change reduction (10000 = 100%). (Default: 0)
# MinDuration Minimum duration in milliseconds after status change reduction. (Default: 1)
# Fail: List of Status Changes that causes the status to fail to activate. (Optional)
# End: List of Status Changes that will end when the status activates. (Optional)
# EndReturn If the status has an End list and succeeds to remove these status changes, it won't give its effect. (Default: false)
###########################################################################
Header:
Type: STATUS_DB
Version: 1

File diff suppressed because it is too large Load Diff

6817
db/pre-re/status.yml Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

7946
db/re/status.yml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -135,6 +135,7 @@
# Interval Skill unit interval in milliseconds. (Default: 0)
# Target Skill unit target type. (Default: All)
# Flag: Skill unit flags. (Default: None)
# Status Status Change that is associated to the skill. (Optional)
###########################################################################
Header:

52
db/status.yml Normal file
View File

@ -0,0 +1,52 @@
# This file is a part of rAthena.
# Copyright(C) 2022 rAthena Development Team
# https://rathena.org - https://github.com/rathena
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###########################################################################
# Status Change Database
###########################################################################
#
# Status Change Settings
#
###########################################################################
# - Status Status change name.
# Icon Status change icon. (Default: EFST_BLANK)
# DurationLookup Default status change duration. (Default: 0)
# States: Status change state to determine player states. (Default: None)
# CalcFlags: Status change calculation to indicate which stat is adjusted. (Default: None)
# Opt1 Special effect when a status change is active. Non-stackable. (Default: None)
# Opt2: Special options/client effects when a status change is active. (Default: None)
# Opt3: Special options/client effects when a status change is active. (Default: Normal)
# Options: Special options/client effects when a status change is active. (Default: Nothing)
# Flags: Special flags which trigger during certain events. (Default: None)
# MinRate Minimum rate after status change reduction (10000 = 100%). (Default: 0)
# MinDuration Minimum duration in milliseconds after status change reduction. (Default: 1)
# Fail: List of Status Changes that causes the status to fail to activate. (Optional)
# End: List of Status Changes that will end when the status activates. (Optional)
# EndReturn If the status has an End list and succeeds to remove these status changes, it won't give its effect. (Default: false)
###########################################################################
Header:
Type: STATUS_DB
Version: 1
Footer:
Imports:
- Path: db/pre-re/status.yml
Mode: Prerenewal
- Path: db/re/status.yml
Mode: Renewal
- Path: db/import/status.yml

View File

@ -925,3 +925,7 @@ CrazyWeedImmune - Immune to GN_CRAZYWEED.
RemovedByFireRain - Removed by RL_FIRE_RAIN.
KnockbackGroup - Knock back a whole skill group (by default, skill unit is knocked back by each unit).
HiddenTrap - Hidden trap. See battle_config::traps_setting to enable this flag.
------------------
Status: Status Change that is associated to the skill. The status is used in association with the status.yml database.

297
doc/status.txt Normal file
View File

@ -0,0 +1,297 @@
//===== rAthena Documentation ================================
//= Status Change Database Structure
//===== By: ==================================================
//= rAthena Dev Team
//===== Last Updated: ========================================
//= 20220222
//===== Description: =========================================
//= Explanation of the status.yml file and structure.
//============================================================
---------------------------------------
Status: Status change name.
See src/map/script_constants.hpp for SC_ constants.
---------------------------------------
Icon: Status change icon or client effect that will be displayed client-side.
See src/map/script_constants.hpp for EFST_ constants.
---------------------------------------
DurationLookup: Used for default duration lookup in skill_db.yml. The lookup is used for some item bonuses as default duration.
---------------------------------------
States: Specified states given when the SC is active.
None - No special state. (Default)
NoMove - Cannot move.
NoMoveCond - Condition check for SCS_NOMOVE.
NoPickItem - Cannot pick item.
NoPickItemCond - Condition check for SCS_NOPICKITEM.
NoDropItem - Cannot drop item.
NoDropItemCond - Condition check for SCS_NODROPITEM.
NoCast - Cannot cast a skill.
NoCastCond - Condition check for SCS_NOCAST.
NoChat - Cannot chat and open chat room.
NoChatCond - Condition check for SCS_NOCHATCOND.
NoEquipItem - Cannot put on equipment.
NoEquipItemCond - Condition check for SCS_NOEQUIPITEM.
NoUnEquipItem - Cannot put off equipment.
NoUnEquipItemCond - Condition check for SCS_NOUNEQUIPITEM.
NoConsumeItem - Cannot consume item.
NoConsumeItemCond - Condition check for SCS_NOCONSUMEITEM.
NoAttack - Cannot attack.
NoAttackCond - Condition check for SCS_NOATTACK.
NoWarp - Cannot warp.
NoWarpCond - Condition check for SCS_NOWARP.
NoDeathPenalty - Cannot lose experience on death.
NoDeathPenaltyCond - Condition check for SCS_NODEATHPENALTY.
NoInteract - Cannot interact with client (sit/stand or talk with NPC).
NoInteractCond - Condition check for SCS_NOINTERACT.
States that have a suffix of "Cond" means the State has hard coded conditions in status.cpp::status_calc_state
---------------------------------------
CalcFlags: Flag that indicates which status calculation needs to be performed. Even if the value is changed in the status_db.yml the SC must have the respective bonus defined in source.
None - Calculates nothing. (Default)
Base - Base status
MaxHp - Maximum HP
MaxSp - Maximum SP
Str - STR
Agi - AGI
Vit - VIT
Int - INT
Dex - DEX
Luk - LUK
Batk - Base Attack
Watk - Weapon Attack
Matk - Magic Attack
Hit - Hit/accuracy rate
Flee - Flee/dodge rate
Def - Equipment Defense
Def2 - Defense
Mdef - Equipment Magic Defense
Mdef2 - Magic Defense
Speed - Walk speed
Aspd - Attack speed
Dspd - Damage delay speed
Cri - Critical rate
Flee2 - Perfect dodge rate
Atk_Ele - Attack Element
Def_Ele - Defense Element
Mode - Mode
Size - Size
Race - Race
Range - Range
Regen - Regeneration
MaxAp - Maximum AP
Pow - POW
Sta - STA
Wis - WIS
Spl - SPL
Con - CON
Crt - CRT
Patk - Physical Power
Smatk - Spell Magic Attack
Res - Physical Resistance
Mres - Magic Resistance
Hplus - Heal Plus
Crate - Critical Rate
Dye - Dye
All - Calculates all CalcFlags
---------------------------------------
Opt1: Special effect when status is active (Aegis: BODYSTATE_*). This option is not stackable. These effects also apply their special behaviors.
None - No effect (Default)
Stone - Stone curse effect
Freeze - Freeze effect
Stun - Stun effect
Sleep - Sleep effect
StoneWait - Effect before Stone is really applied
Burning - Burning effect
Imprison - Imprison effect
Crystalize - Crystalize effect
---------------------------------------
Opt2: Special option/client effect when status is active (Aegis: HEALTHSTATE_*).
None - No effect (Default)
Poison - Posioned effect
Curse - Cursed effect
Silence - Silenced effect
SignumCrucis - Signum Crucis effect
Blind - Blind effect
Angelus - Angelus effect
Bleeding - Bleeding effect
Dpoison - Heavy Poisoned effect
Fear - Fear effect
---------------------------------------
Opt3: Special option/client effect when status is active (Aegis: SHOW_EFST_*)
Normal - No effect (Default)
Quicken - Quicken effect
OverThrust - Overthrust effect
EnergyCoat - Energy Coat effect
ExplosionSpirits - Explosion Spirits effect
SteelBody - Steel Body effect
BladeStop - Blade Stop effect
AuraBlade - Aura Blade effect
Berserk - Berserk effect
LightBlade - Light Blade effect
Moonlit - Moonlit effect
Marionette - Marionette effect
Assumptio - Assumptio effect
Warm - Warm effect
Kaite - Kaite effect
Bunsin - Bunshin effect
SoulLink - Soul Link effect
Undead - Undead effect
Contract - Contract effect
---------------------------------------
Options: Special option/client effect state when status is active.
Nothing - No effect (Default)
Sight - Sight effect
Hide - Hide effect
Cloak - Cloaking effect
Falcon - Falcon effect
Riding - Riding effect
Invisible - Invisible effect
Orcish - Orcish effect, the ugly face!
Wedding - Wedding costume
Ruwach - Ruwach effect
ChaseWalk - Chasewalk effect
Flying - Flying effect (Star Gladiator's Union)
Xmas - Christmas costume
Transform - Transformation
Summer - Summer costume
Dragon1 - Dragon
Dragon2 - Dragon
Dragon3 - Dragon
Dragon4 - Dragon
Dragon5 - Dragon
Wug - Wug
WugRider - Riding a Wug
Madogear - Madogear
Hanbok - Hanbok costume
Oktoberfest - Oktoberfest costume
---------------------------------------
Flags: Various status flags for specific status change events.
None - No special flag. (Default)
BlEffect - Status should have BL_SCEFFECT as relevant effect, must have an EFST (displays on BL_PC, BL_HOM, BL_MER, BL_MOB, BL_ELEM). BL_PC is the default value.
DisplayPc - Displays status effect when player logs in.
DislpayNpc - Displays status effect on a NPC.
Debuff - Status is considered a debuff. Used in combination with 'battle_config.debuff_on_logout'.
SetStand - Sets player to standing state.
OverlapFail - The status will fail to activate if the status is already active.
OverlapIgnoreLevel - The status will successfully activate for any level if the status is already active.
FailedMado - Cannot be applied if Madogear is active.
MadoCancel - Cancels the status when mounting Madogear.
MadoEndCancel - Cancels the status when unmounting Madogear.
MobLoseTarget - When active on a monster it will lose the target.
RestartOnMapWarp - Restarts the timer of a status when warping to another map.
SpreadEffect - Passes the status onto a target when SC_DEADLYINFECT is active.
SendVal1 - Notifies the client of a status change (val1).
SendVal2 - Notifies the client of a status change (val2).
SendVal3 - Notifies the client of a status change (val3).
NoClearbuff - Cannot be removed by 'status_change_clear_buffs()', 'sc_end SC_ALL', 'status_change_clear(3)', etc.
NoRemoveOnDead - Cannot be removed when a player dies.
NoDispell - Cannot be removed by SA_DISPELL.
NoClearance - Cannot be removed by AB_CLEARANCE.
NoBanishingBuster - Cannot be removed by RL_BANISHING_BUSTER.
NoSave - Won't be saved when player logs out.
NoSaveInfinite - Infinite duration status won't be saved when player logs out.
RemoveOnDamaged - Removed when receiving damage.
RemoveOnRefresh - Removed by RK_REFRESH.
RemoveOnLuxAnima - Removed by RK_LUXANIMA.
RemoveOnMapWarp - Removed when warping to another map.
RemoveOnChangeMap - Removed when changing map-server.
RemoveChemicalProtect - Removed by AM_CP_ARMOR/AM_CP_HELM/AM_CP_SHIELD/AM_CP_WEAPON.
RemoveElementalOption - Removed by elemental changing modes/quitting/EL_TIDAL_WEAPON/EL_WATER_SCREEN on the master and elemental.
StopAttacking - Makes the unit stop attacking.
StopCasting - Makes the unit stop casting skills.
StopWalking - Makes the unit stop walking.
BossResist - Cannot be applied to Boss Monster (Mob has mode MD_STATUS_IMMUNE).
MvpResist - Cannot be applied to MvP (Mob has mode MD_MVP).
SendOption - Sends the STATE_CHANGE packet. For statuses that have Opt1, Opt2, or Opt3 values.
SendLook - Sends the STATE_CHANGE packet. For statuses that have body/look changes through 'Option' flags (only for players).
OnTouch - Triggers OnTouch_ NPC events. For statuses that have an invisible effect.
UnitMove - Triggers when the player has moved location and invokes the skill unit on place.
NonPlayer - Sends the NPC_SHOWEFST_UPDATE packet. Used to send effects to NPC/monsters.
RequireWeapon - Status requires a weapon to be equipped.
RequireShield - Status requires a shield to be equipped.
SuperNoviceAngel - Status that is given from Super Novice Angel.
TaekwonAngel - Status that is given from Taekwon Angel.
---------------------------------------
MinDuration: Minimum duration, in milliseconds, after reduction calculation for status resistance.
---------------------------------------
MinRate: Minimum success rate, at n/10000, after reduction calculation for status resistance.
---------------------------------------
Fail: List of status that causes the status to fail to activate.
---------------------------------------
End: List of status that will end if the status activates.
---------------------------------------
EndReturn: If the status has any 'End' and succeeds to end other status in the list, it won't give its effect.
---------------------------------------
Notes:
By default, statuses are 'Buff' (those that aren't explicitely given the 'Debuff' flag) which are removable by 'map_quit' in combination with 'battle_config.debuff_on_logout'.
The NoClearbuff flag prevents some permanent and non-permanent statuses that cannot be removed by 'status_change_clear', 'status_change_clear_buffs', 'map_quit', or other
clearing means.
The function 'status_change_clear_buffs' is called by CG_TAROTCARD, RK_REFRESH, RK_LUXANIMA, CG_HERMODE, PA_GOSPEL, and LG_INSPIRATION.
CG_TAROTCARD and CG_HERMODE only remove buffs while PA_GOSPEL and LG_INSPIRATION remove buffs and debuffs.
RK_REFRESH and RK_LUXANIMA only remove statuses that have the Rem_On_Rerfresh or RemoveOnLuxAnima flag. Works just like SA_DISPELL, AB_CLEARANCE, RL_BANISHING_BUSTER that has the
effect to remove buffs or debuffs.
---- Removed comments from source ----
- Mado is immune to increase agi, wind walk, cart boost, etc (others above) [Ind]
- Cart Boost cannot be affected by Slow grace. Assumed if player got Slow Grace first, Cart Boost is failed since Cart Boost doesn't cancel Slow Grace effect
http://irowiki.org/wiki/Cart_Boost_%28Genetic%29 (view date: 2014-01-26)
http://irowiki.org/wiki/Cart_Boost (view date: 2014-01-26)
- kRO Update 2014-02-12: Cannot be stacked with Platinum Alter and Madness Canceler (and otherwise?) [Cydh]
- SC_BERSERK, SC_SATURDAYNIGHTFEVER, and SC__BLOODYLUST are all like berserk, do not everlap each other.
- SC_STONE, SC_FREEZE, SC_DEEPSLEEP, SC_SLEEP, SC_STUN, SC_FREEZING, and SC_CRYSTALIZE cannot override other opt1 status changes. [Skotlex]
TODO: SC that has OPT1: SC_STONE, SC_FREEZE, SC_STUN, SC_SLEEP, SC_BURNING, SC_WHITEIMPRISON, SC_CRYSTALIZE
- Immune to Frozen and Freezing status if under Warmer status. [Jobbie]
- SC_ONEHAND removes the Aspd potion effect, as reported by Vicious. [Skotlex]
- SC_ALL_RIDING. Already mounted, just dismount.
- SC_GN_CARTBOOST andSC_CARTBOOST cancel Decrease Agi, but take no further effect [Skotlex]

View File

@ -45,7 +45,7 @@ SC_POISON ()
desc: DEF -25%; if HP>25% lose 1.5% + 2 HP/sec; SP Regeneration is disabled
val1: Skill Level
val2: Caster's object ID
val3:
val3:
val4: Remaining tick
SC_CURSE ()
@ -75,7 +75,7 @@ SC_DPOISON ()
desc: DEF -25%; if HP>25% lose 10/15% HP/sec
val1: Skill Level
val2: Caster's object ID (for mob_log_damage)
val3:
val3:
val4: Remaining tick
SC_PROVOKE (EFST_PROVOKE)
@ -1760,7 +1760,7 @@ SC_RAISINGDRAGON ()
val1:
SC_GT_ENERGYGAIN (EFST_GENTLETOUCH_ENERGYGAIN)
desc:
desc:
val1: SR_GENTLETOUCH_ENERGYGAIN Skill Level
val2: Sphere Gain Chance
@ -2368,7 +2368,7 @@ SC_REBOUND (EFST_REBOUND)
val1:
SC_UNLIMIT (EFST_UNLIMIT)
desc: Increase attak rate & set Def/MDef to 1,
desc: Increase attak rate & set Def/MDef to 1,
val1:
val2: +% Attack
@ -2710,13 +2710,81 @@ SC_LHZ_DUN_N4 (EFST_LHZ_DUN_N4)
desc: Increases and reduces damage against MVPs of Biolab 5.
val1: +% Damage
val2: +% Defense
SC_DORAM_BUF_01 ()
desc: Recovers 10 HP every 10 seconds.
SC_DORAM_BUF_02 ()
desc: Recovers 5 SP every 10 seconds.
SC_INCREASE_MAXHP (EFST_ATKER_ASPD)
desc: Increases MaxHP. Increases natural HP regeneration.
val1: + HP
val2: +% HP regeneration
SC_INCREASE_MAXSP (EFST_ATKER_MOVESPEED)
desc: Increases MaxSP. Increases natural SP regeneration.
val1: + SP
val2: +% SP regeneration
SC_REF_T_POTION (EFST_REF_T_POTION)
desc: Decreases reflected damage by 100%.
SC_ADD_ATK_DAMAGE (EFST_ADD_ATK_DAMAGE)
desc: Increases melee physical damage by 15%. Increases ranged physical damage by 15%.
val1:
SC_ADD_MATK_DAMAGE (EFST_ADD_MATK_DAMAGE)
desc: Increases all elemental magical damage by 15%.
SC_HELPANGEL (EFST_HELPANGEL)
desc: Recover 1000 HP every second. Recover 350 SP every second.
val1:
val2:
val3:
val4: Tick time (milliseconds)
SC_SOUNDOFDESTRUCTION (EFST_SOUND_OF_DESTRUCTION)
desc: Doubles incoming damage for 10 seconds.
SC_LUXANIMA (EFST_LUXANIMA)
desc: Physical attacks has the chance to activate Storm Blast Level 1. Increases physical damage against all sizes.
Increases Critical Damage. Increases Melee and Ranged Physical Damage.
val1:
val2: Storm Blast success 15% (hardcoded)
val3: Damage/HP/SP 30% increase (hardcoded)
SC_REUSE_LIMIT_LUXANIMA ()
desc:
val1:
SC_ENSEMBLEFATIGUE (EFST_ENSEMBLEFATIGUE)
desc: Disables skill use. Movement and attack speed reduced by 30%.
val1:
val2: + 30 Speed and ASPD rates penalty (hardcoded)
SC_MISTY_FROST (EFST_MISTY_FROST)
desc: Freezing.
SC_MAGIC_POISON (EFST_MAGIC_POISON)
desc: Decreases resistance against all elemental attacks by 50%.
val1:
val2: Attribute Reduction (50, hardcoded).
SC_EP16_2_BUFF_SS (EFST_EP16_2_BUFF_SS)
desc: ASPD +10.
SC_EP16_2_BUFF_SC (EFST_EP16_2_BUFF_SC)
desc: CRIT +30.
SC_EP16_2_BUFF_AC (EFST_EP16_2_BUFF_AC)
desc: Reduce variable cast time by 80%.
SC_EMERGENCY_MOVE (EFST_INC_AGI)
desc: Increase AGI and walkspeed, AL_INCAGI effect.
val1:
val2: Movement speed +25 (hardcoded)
SC_PACKING_ENVELOPE1 (EFST_PACKING_ENVELOPE1)
desc: Increases ATK
val1: + watk

View File

@ -118,4 +118,5 @@
# Interval Skill unit interval in milliseconds. (Default: 0)
# Target Skill unit target type. (Default: All)
# Flag: Skill unit flags. (Default: None)
# Status Status Change that is associated to the skill. (Optional)
###########################################################################

View File

@ -150,12 +150,7 @@ public:
void clear() override{
TypesafeYamlDatabase<keytype, datatype>::clear();
// Restore size after clearing
size_t cap = cache.capacity();
cache.clear();
cache.resize(cap, nullptr);
}
std::shared_ptr<datatype> find( keytype key ) override{

View File

@ -1704,7 +1704,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
}
if( sc->data[SC__DEADLYINFECT] && (flag&(BF_SHORT|BF_MAGIC)) == BF_SHORT && damage > 0 && rnd()%100 < 30 + 10 * sc->data[SC__DEADLYINFECT]->val1 )
status_change_spread(bl, src, 1); // Deadly infect attacked side
status_change_spread(bl, src);
} //End of target SC_ check
@ -1771,7 +1771,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
}
if( sc->data[SC__DEADLYINFECT] && (flag&(BF_SHORT|BF_MAGIC)) == BF_SHORT && damage > 0 && rnd()%100 < 30 + 10 * sc->data[SC__DEADLYINFECT]->val1 )
status_change_spread(src, bl, 0);
status_change_spread(src, bl);
if (sc->data[SC_STYLE_CHANGE] && sc->data[SC_STYLE_CHANGE]->val1 == MH_MD_FIGHTING) {
TBL_HOM *hd = BL_CAST(BL_HOM,src); //when attacking
@ -9803,9 +9803,8 @@ static const struct _battle_data {
{ "display_version", &battle_config.display_version, 1, 0, 1, },
{ "display_hallucination", &battle_config.display_hallucination, 1, 0, 1, },
{ "use_statpoint_table", &battle_config.use_statpoint_table, 1, 0, 1, },
{ "berserk_cancels_buffs", &battle_config.berserk_cancels_buffs, 0, 0, 1, },
{ "debuff_on_logout", &battle_config.debuff_on_logout, 1|2, 0, 1|2, },
{ "monster_ai", &battle_config.mob_ai, 0x000, 0x000, 0xFFF, },
{ "debuff_on_logout", &battle_config.debuff_on_logout, 0, 0, 1|2, },
{ "monster_ai", &battle_config.mob_ai, 0x000, 0x000, 0x77F, },
{ "hom_setting", &battle_config.hom_setting, 0xFFFF, 0x0000, 0xFFFF, },
{ "dynamic_mobs", &battle_config.dynamic_mobs, 1, 0, 1, },
{ "mob_remove_damaged", &battle_config.mob_remove_damaged, 1, 0, 1, },

View File

@ -423,7 +423,6 @@ struct Battle_Config
int display_hallucination; // [Skotlex]
int use_statpoint_table; // [Skotlex]
int berserk_cancels_buffs; // [Aru]
int debuff_on_logout; // Removes a few "official" negative Scs on logout. [Skotlex]
int mob_ai; //Configures various mob_ai settings to make them smarter or dumber(official). [Skotlex]
int hom_setting; //Configures various homunc settings which make them behave unlike normal characters.. [Skotlex]

View File

@ -1656,7 +1656,8 @@ int chrif_bsdata_save(struct map_session_data *sd, bool quit) {
// Removing...
if (quit && sd->bonus_script.head) {
uint16 flag = BSF_REM_ON_LOGOUT; //Remove bonus when logout
uint32 flag = BSF_REM_ON_LOGOUT; //Remove bonus when logout
if (battle_config.debuff_on_logout&1) //Remove negative buffs
flag |= BSF_REM_DEBUFF;
if (battle_config.debuff_on_logout&2) //Remove positive buffs
@ -1734,7 +1735,7 @@ int chrif_bsdata_received(int fd) {
if (bs->script_str[0] == '\0' || !bs->tick)
continue;
if (!(entry = pc_bonus_script_add(sd, bs->script_str, bs->tick, (enum efst_types)bs->icon, bs->flag, bs->type)))
if (!(entry = pc_bonus_script_add(sd, bs->script_str, bs->tick, (enum efst_type)bs->icon, bs->flag, bs->type)))
continue;
linkdb_insert(&sd->bonus_script.head, (void *)((intptr_t)entry), entry);

View File

@ -4288,7 +4288,7 @@ void clif_changeoption_target( struct block_list* bl, struct block_list* target
if( sc->data[SC_PROVOKE] ){
const struct TimerData *td = get_timer( sc->data[SC_PROVOKE]->timer );
clif_status_change( bl, StatusIconChangeTable[SC_PROVOKE], 1, ( !td ? INFINITE_TICK : DIFF_TICK( td->tick, gettick() ) ), 0, 0, 0 );
clif_status_change( bl, status_db.getIcon(SC_PROVOKE), 1, ( !td ? INFINITE_TICK : DIFF_TICK( td->tick, gettick() ) ), 0, 0, 0 );
}
}else{
if( disguised( bl ) ){
@ -6371,7 +6371,7 @@ void clif_cooking_list( struct map_session_data *sd, int trigger, uint16 skill_i
/// 0983 <index>.W <id>.L <state>.B <total msec>.L <remain msec>.L { <val>.L }*3 (ZC_MSG_STATE_CHANGE3) (PACKETVER >= 20120618)
/// @param bl Sends packet to clients around this object
/// @param id ID of object that has this effect
/// @param type Status icon see enum efst_types
/// @param type Status icon see enum efst_type
/// @param flag 1:Active, 0:Deactive
/// @param tick Duration in ms
/// @param val1
@ -6433,7 +6433,7 @@ void clif_status_change_sub(struct block_list *bl, int id, int type, int flag, t
/* Sends status effect to clients around the bl
* @param bl Object that has the effect
* @param type Status icon see enum efst_types
* @param type Status icon see enum efst_type
* @param flag 1:Active, 0:Deactive
* @param tick Duration in ms
* @param val1
@ -6452,11 +6452,17 @@ void clif_status_change(struct block_list *bl, int type, int flag, t_tick tick,
if (type == EFST_ILLUSION && !battle_config.display_hallucination) // Disable Hallucination.
return;
#if PACKETVER_MAIN_NUM < 20191120 || PACKETVER_RE_NUM < 20191106
// Older clients display normal riding icon.
if (type == EFST_MADOGEAR)
type = EFST_RIDING;
#endif
nullpo_retv(bl);
sd = BL_CAST(BL_PC, bl);
if (!(status_type2relevant_bl_types(type)&bl->type)) // only send status changes that actually matter to the client
if (!(status_efst_get_bl_type((efst_type)type)&bl->type)) // only send status changes that actually matter to the client
return;
clif_status_change_sub(bl, bl->id, type, flag, tick, val1, val2, val3, ((sd ? (pc_isinvisible(sd) ? SELF : AREA) : AREA_WOS)));
@ -6525,9 +6531,9 @@ void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl,
}
#if PACKETVER > 20120418
clif_efst_status_change(tbl, bl->id, target, StatusIconChangeTable[type], tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3);
clif_efst_status_change(tbl, bl->id, target, status_db.getIcon(type), tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3);
#else
clif_status_change_sub(tbl, bl->id, StatusIconChangeTable[type], 1, tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3, target);
clif_status_change_sub(tbl, bl->id, status_db.getIcon(type), 1, tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3, target);
#endif
}
}
@ -11724,19 +11730,12 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type,
return;
}
// Statuses that don't let the player sit / attack / talk with NPCs(targeted)
// (not all are included in pc_can_attack)
if (sd->sc.count &&
(sd->sc.data[SC_TRICKDEAD] ||
(sd->sc.data[SC_AUTOCOUNTER] && action_type != 0x07) ||
sd->sc.data[SC_BLADESTOP] ||
sd->sc.data[SC__MANHOLE] ||
sd->sc.data[SC_SUHIDE] ||
sd->sc.data[SC_GRAVITYCONTROL]))
return;
if(action_type != 0x00 && action_type != 0x07)
// Statuses that don't let the player sit / stand / talk with NPCs (targeted)
if (action_type != 0x00 && action_type != 0x07) {
if (sd->sc.cant.interact)
return;
pc_stop_walking(sd, 1);
}
pc_stop_attack(sd);
if(target_id<0 && -target_id == sd->bl.id) // for disguises [Valaris]
@ -11747,10 +11746,7 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type,
case 0x00: // once attack
case 0x07: // continuous attack
if( pc_cant_act(sd) || sd->sc.option&OPTION_HIDE )
return;
if( sd->sc.option&OPTION_COSTUME )
if( pc_cant_act(sd) )
return;
if (!battle_config.sdelay_attack_enable && pc_checkskill(sd, SA_FREECAST) <= 0) {
@ -12073,11 +12069,7 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd){
if (pc_cant_act2(sd) || sd->npc_id)
break;
if (sd->sc.count && (
sd->sc.data[SC_AUTOCOUNTER] ||
sd->sc.data[SC_BLADESTOP] ||
(sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM)
))
if (sd->sc.cant.drop)
break;
if (!pc_dropitem(sd, item_index, item_amount))
@ -15176,7 +15168,7 @@ void clif_parse_NoviceExplosionSpirits(int fd, struct map_session_data *sd)
int percent = (int)( ( (double)sd->status.base_exp/(double)next )*1000. );
if( percent && ( percent%100 ) == 0 ) {// 10.0%, 20.0%, ..., 90.0%
sc_start(&sd->bl,&sd->bl, status_skill2sc(MO_EXPLOSIONSPIRITS), 100, 17, skill_get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex]
sc_start(&sd->bl,&sd->bl, SC_EXPLOSIONSPIRITS, 100, 17, skill_get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex]
clif_skill_nodamage(&sd->bl, &sd->bl, MO_EXPLOSIONSPIRITS, 5, 1); // prayer always shows successful Lv5 cast and disregards noskill restrictions
}
}

View File

@ -286,137 +286,11 @@ int elemental_data_received(s_elemental *ele, bool flag) {
return 1;
}
int elemental_clean_single_effect(s_elemental_data *ed, uint16 skill_id) {
nullpo_ret(ed);
sc_type type = status_skill2sc(skill_id);
block_list *bl = battle_get_master(&ed->bl);
if( type ) {
switch( type ) {
// Just remove status change.
case SC_PYROTECHNIC_OPTION:
case SC_HEATER_OPTION:
case SC_TROPIC_OPTION:
case SC_FIRE_CLOAK_OPTION:
case SC_AQUAPLAY_OPTION:
case SC_WATER_SCREEN_OPTION:
case SC_COOLER_OPTION:
case SC_CHILLY_AIR_OPTION:
case SC_GUST_OPTION:
case SC_WIND_STEP_OPTION:
case SC_BLAST_OPTION:
case SC_WATER_DROP_OPTION:
case SC_WIND_CURTAIN_OPTION:
case SC_WILD_STORM_OPTION:
case SC_PETROLOGY_OPTION:
case SC_SOLID_SKIN_OPTION:
case SC_CURSED_SOIL_OPTION:
case SC_STONE_SHIELD_OPTION:
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<sc_type>(type-1),INVALID_TIMER); // Elemental Spirit
break;
case SC_ZEPHYR:
if( bl ) status_change_end(bl,type,INVALID_TIMER);
break;
default:
ShowWarning("Invalid SC=%d in elemental_clean_single_effect\n",type);
break;
}
}
return 1;
}
int elemental_clean_effect(s_elemental_data *ed) {
nullpo_ret(ed);
map_session_data *sd;
// Elemental side
status_change_end(&ed->bl, SC_TROPIC, INVALID_TIMER);
status_change_end(&ed->bl, SC_HEATER, INVALID_TIMER);
status_change_end(&ed->bl, SC_AQUAPLAY, INVALID_TIMER);
status_change_end(&ed->bl, SC_COOLER, INVALID_TIMER);
status_change_end(&ed->bl, SC_CHILLY_AIR, INVALID_TIMER);
status_change_end(&ed->bl, SC_PYROTECHNIC, INVALID_TIMER);
status_change_end(&ed->bl, SC_FIRE_CLOAK, INVALID_TIMER);
status_change_end(&ed->bl, SC_WATER_DROP, INVALID_TIMER);
status_change_end(&ed->bl, SC_WATER_SCREEN, INVALID_TIMER);
status_change_end(&ed->bl, SC_GUST, INVALID_TIMER);
status_change_end(&ed->bl, SC_WIND_STEP, INVALID_TIMER);
status_change_end(&ed->bl, SC_BLAST, INVALID_TIMER);
status_change_end(&ed->bl, SC_WIND_CURTAIN, INVALID_TIMER);
status_change_end(&ed->bl, SC_WILD_STORM, INVALID_TIMER);
status_change_end(&ed->bl, SC_PETROLOGY, INVALID_TIMER);
status_change_end(&ed->bl, SC_SOLID_SKIN, INVALID_TIMER);
status_change_end(&ed->bl, SC_CURSED_SOIL, INVALID_TIMER);
status_change_end(&ed->bl, SC_STONE_SHIELD, INVALID_TIMER);
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;
// Master side
status_change_end(&sd->bl, SC_TROPIC_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_HEATER_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_AQUAPLAY_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_COOLER_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_CHILLY_AIR_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_PYROTECHNIC_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_FIRE_CLOAK_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_WATER_DROP_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_WATER_SCREEN_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_GUST_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_WIND_STEP_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_BLAST_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_WATER_DROP_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_WIND_CURTAIN_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_WILD_STORM_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_ZEPHYR, INVALID_TIMER);
status_change_end(&sd->bl, SC_WIND_STEP_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_PETROLOGY_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_SOLID_SKIN_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_CURSED_SOIL_OPTION, INVALID_TIMER);
status_change_end(&sd->bl, SC_STONE_SHIELD_OPTION, INVALID_TIMER);
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);
status_db.removeByStatusFlag(&ed->bl, { SCF_REMOVEELEMENTALOPTION });
status_db.removeByStatusFlag(battle_get_master(&ed->bl), { SCF_REMOVEELEMENTALOPTION });
return 1;
}

View File

@ -125,7 +125,6 @@ t_tick elemental_get_lifetime(s_elemental_data *ed);
int elemental_unlocktarget(s_elemental_data *ed);
bool elemental_skillnotok(uint16 skill_id, s_elemental_data *ed);
int elemental_set_target( map_session_data *sd, block_list *bl );
int elemental_clean_single_effect(s_elemental_data *ed, uint16 skill_id);
int elemental_clean_effect(s_elemental_data *ed);
int elemental_action(s_elemental_data *ed, block_list *bl, t_tick tick);
struct s_skill_condition elemental_skill_get_requirements(uint16 skill_id, uint16 skill_lv);
@ -133,7 +132,6 @@ struct s_skill_condition elemental_skill_get_requirements(uint16 skill_id, uint1
#define elemental_stop_walking(ed, type) unit_stop_walking(&(ed)->bl, type)
#define elemental_stop_attack(ed) unit_stop_attack(&(ed)->bl)
void read_elemental_skilldb(void);
void do_init_elemental(void);
void do_final_elemental(void);

View File

@ -1529,14 +1529,15 @@ void guild_guildaura_refresh(struct map_session_data *sd, uint16 skill_id, uint1
if( !skill_lv )
return;
std::shared_ptr<s_skill_unit_group> group;
sc_type type = status_skill2sc(skill_id);
sc_type type = skill_get_sc(skill_id);
if (type == SC_NONE)
return;
status_change_end(&sd->bl, type, INVALID_TIMER);
std::shared_ptr<s_skill_unit_group> group = skill_unitsetting(&sd->bl,skill_id,skill_lv,sd->bl.x,sd->bl.y,0);
if( sd->sc.data[type] && (group = skill_id2group(sd->sc.data[type]->val4)) ) {
skill_delunitgroup(group);
status_change_end(&sd->bl,type,INVALID_TIMER);
}
group = skill_unitsetting(&sd->bl,skill_id,skill_lv,sd->bl.x,sd->bl.y,0);
if( group )
sc_start4(NULL,&sd->bl,type,100,(battle_config.guild_aura&16)?0:skill_lv,0,0,group->group_id,600000);//duration doesn't matter these status never end with val4
return;

View File

@ -270,7 +270,7 @@ int hom_dead(struct homun_data *hd)
clif_emotion(&sd->bl, ET_CRY);
#ifdef RENEWAL
status_change_end(&sd->bl, status_skill2sc(AM_CALLHOMUN), INVALID_TIMER);
status_change_end(&sd->bl, SC_HOMUN_TIME, INVALID_TIMER);
#endif
//Remove from map (if it has no intimacy, it is auto-removed from memory)
@ -310,7 +310,7 @@ int hom_vaporize(struct map_session_data *sd, int flag)
hom_save(hd);
#ifdef RENEWAL
status_change_end(&sd->bl, status_skill2sc(AM_CALLHOMUN), INVALID_TIMER);
status_change_end(&sd->bl, SC_HOMUN_TIME, INVALID_TIMER);
#endif
return unit_remove_map(&hd->bl, CLR_OUTSIGHT);
@ -1183,7 +1183,7 @@ bool hom_call(struct map_session_data *sd)
unit_warp(&hd->bl,sd->bl.m, sd->bl.x, sd->bl.y,CLR_OUTSIGHT);
#ifdef RENEWAL
sc_start(&sd->bl, &sd->bl, status_skill2sc(AM_CALLHOMUN), 100, 1, skill_get_time(AM_CALLHOMUN, 1));
sc_start(&sd->bl, &sd->bl, SC_HOMUN_TIME, 100, 1, skill_get_time(AM_CALLHOMUN, 1));
#endif
return true;
@ -1243,7 +1243,7 @@ int hom_recv_data(uint32 account_id, struct s_homunculus *sh, int flag)
}
#ifdef RENEWAL
sc_start(&sd->bl, &sd->bl, status_skill2sc(AM_CALLHOMUN), 100, 1, skill_get_time(AM_CALLHOMUN, 1));
sc_start(&sd->bl, &sd->bl, SC_HOMUN_TIME, 100, 1, skill_get_time(AM_CALLHOMUN, 1));
#endif
return 1;
@ -1332,7 +1332,7 @@ int hom_ressurect(struct map_session_data* sd, unsigned char per, short x, short
}
#ifdef RENEWAL
sc_start(&sd->bl, &sd->bl, status_skill2sc(AM_CALLHOMUN), 100, 1, skill_get_time(AM_CALLHOMUN, 1));
sc_start(&sd->bl, &sd->bl, SC_HOMUN_TIME, 100, 1, skill_get_time(AM_CALLHOMUN, 1));
#endif
return status_revive(&hd->bl, per, 0);

View File

@ -345,6 +345,7 @@
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\spellbook_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\spellbook_db.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\statpoint.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\statpoint.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\status_disabled.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\status_disabled.txt')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\status.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\status.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\stylist.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\stylist.yml')" />
</Target>
</Project>

View File

@ -2084,85 +2084,27 @@ int map_quit(struct map_session_data *sd) {
//map_quit handles extra specific data which is related to quitting normally
//(changing map-servers invokes unit_free but bypasses map_quit)
if( sd->sc.count ) {
//Status that are not saved...
status_change_end(&sd->bl, SC_BOSSMAPINFO, INVALID_TIMER);
status_change_end(&sd->bl, SC_AUTOTRADE, INVALID_TIMER);
status_change_end(&sd->bl, SC_SPURT, INVALID_TIMER);
status_change_end(&sd->bl, SC_BERSERK, INVALID_TIMER);
status_change_end(&sd->bl, SC__BLOODYLUST, INVALID_TIMER);
status_change_end(&sd->bl, SC_TRICKDEAD, INVALID_TIMER);
status_change_end(&sd->bl, SC_LEADERSHIP, INVALID_TIMER);
status_change_end(&sd->bl, SC_GLORYWOUNDS, INVALID_TIMER);
status_change_end(&sd->bl, SC_SOULCOLD, INVALID_TIMER);
status_change_end(&sd->bl, SC_HAWKEYES, INVALID_TIMER);
status_change_end(&sd->bl, SC_EMERGENCY_MOVE, INVALID_TIMER);
status_change_end(&sd->bl, SC_CHASEWALK2, INVALID_TIMER);
if(sd->sc.data[SC_PROVOKE] && sd->sc.data[SC_PROVOKE]->timer == INVALID_TIMER)
status_change_end(&sd->bl, SC_PROVOKE, INVALID_TIMER); //Infinite provoke ends on logout
status_change_end(&sd->bl, SC_WEIGHT50, INVALID_TIMER);
status_change_end(&sd->bl, SC_WEIGHT90, INVALID_TIMER);
status_change_end(&sd->bl, SC_SATURDAYNIGHTFEVER, INVALID_TIMER);
status_change_end(&sd->bl, SC_KYOUGAKU, INVALID_TIMER);
status_change_end(&sd->bl, SC_C_MARKER, INVALID_TIMER);
status_change_end(&sd->bl, SC_READYSTORM, INVALID_TIMER);
status_change_end(&sd->bl, SC_READYDOWN, INVALID_TIMER);
status_change_end(&sd->bl, SC_READYTURN, INVALID_TIMER);
status_change_end(&sd->bl, SC_READYCOUNTER, INVALID_TIMER);
status_change_end(&sd->bl, SC_DODGE, INVALID_TIMER);
status_change_end(&sd->bl, SC_CBC, INVALID_TIMER);
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);
status_change_end(&sd->bl, SC_STRANGELIGHTS, INVALID_TIMER);
status_change_end(&sd->bl, SC_DECORATION_OF_MUSIC, INVALID_TIMER);
if (battle_config.debuff_on_logout&1) { //Remove negative buffs
status_change_end(&sd->bl, SC_ORCISH, INVALID_TIMER);
status_change_end(&sd->bl, SC_STRIPWEAPON, INVALID_TIMER);
status_change_end(&sd->bl, SC_STRIPARMOR, INVALID_TIMER);
status_change_end(&sd->bl, SC_STRIPSHIELD, INVALID_TIMER);
status_change_end(&sd->bl, SC_STRIPHELM, INVALID_TIMER);
status_change_end(&sd->bl, SC_EXTREMITYFIST, INVALID_TIMER);
status_change_end(&sd->bl, SC_EXPLOSIONSPIRITS, INVALID_TIMER);
if(sd->sc.data[SC_REGENERATION] && sd->sc.data[SC_REGENERATION]->val4)
status_change_end(&sd->bl, SC_REGENERATION, INVALID_TIMER);
//TO-DO Probably there are way more NPC_type negative status that are removed
status_change_end(&sd->bl, SC_CHANGEUNDEAD, INVALID_TIMER);
// Both these statuses are removed on logout. [L0ne_W0lf]
status_change_end(&sd->bl, SC_SLOWCAST, INVALID_TIMER);
status_change_end(&sd->bl, SC_CRITICALWOUND, INVALID_TIMER);
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);
status_change_end(&sd->bl, SC_MAXOVERTHRUST, INVALID_TIMER);
status_change_end(&sd->bl, SC_STEELBODY, INVALID_TIMER);
status_change_end(&sd->bl, SC_PRESERVE, INVALID_TIMER);
status_change_end(&sd->bl, SC_KAAHI, INVALID_TIMER);
status_change_end(&sd->bl, SC_SPIRIT, INVALID_TIMER);
status_change_end(&sd->bl, SC_HEAT_BARREL, INVALID_TIMER);
status_change_end(&sd->bl, SC_P_ALTER, INVALID_TIMER);
status_change_end(&sd->bl, SC_E_CHAIN, INVALID_TIMER);
status_change_end(&sd->bl, SC_SIGHTBLASTER, INVALID_TIMER);
status_change_end(&sd->bl, SC_BENEDICTIO, INVALID_TIMER);
status_change_end(&sd->bl, SC_GLASTHEIM_ATK, INVALID_TIMER);
status_change_end(&sd->bl, SC_GLASTHEIM_DEF, INVALID_TIMER);
status_change_end(&sd->bl, SC_GLASTHEIM_HEAL, INVALID_TIMER);
status_change_end(&sd->bl, SC_GLASTHEIM_HIDDEN, INVALID_TIMER);
status_change_end(&sd->bl, SC_GLASTHEIM_STATE, INVALID_TIMER);
status_change_end(&sd->bl, SC_GLASTHEIM_ITEMDEF, INVALID_TIMER);
status_change_end(&sd->bl, SC_GLASTHEIM_HPSP, INVALID_TIMER);
status_change_end(&sd->bl, SC_SOULGOLEM, INVALID_TIMER);
status_change_end(&sd->bl, SC_SOULSHADOW, INVALID_TIMER);
status_change_end(&sd->bl, SC_SOULFALCON, INVALID_TIMER);
status_change_end(&sd->bl, SC_SOULFAIRY, INVALID_TIMER);
for (const auto &it : status_db) {
std::bitset<SCF_MAX> &flag = it.second->flag;
//No need to save infinite status
if (flag[SCF_NOSAVEINFINITE] && sd->sc.data[it.first] && sd->sc.data[it.first]->val4 > 0) {
status_change_end(&sd->bl, static_cast<sc_type>(it.first), INVALID_TIMER);
continue;
}
//Status that are not saved
if (flag[SCF_NOSAVE]) {
status_change_end(&sd->bl, static_cast<sc_type>(it.first), INVALID_TIMER);
continue;
}
//Removes status by config
if (battle_config.debuff_on_logout&1 && flag[SCF_DEBUFF] || //Removes debuffs
(battle_config.debuff_on_logout&2 && !(flag[SCF_DEBUFF]))) //Removes buffs
{
status_change_end(&sd->bl, static_cast<sc_type>(it.first), INVALID_TIMER);
continue;
}
}
}

View File

@ -1698,8 +1698,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, t_tick tick)
return false;
// Abnormalities
if(( md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT && md->sc.opt1 != OPT1_BURNING )
|| md->sc.data[SC_BLADESTOP] || md->sc.data[SC__MANHOLE] || md->sc.data[SC_CURSEDCIRCLE_TARGET]) {//Should reset targets.
if(( md->sc.opt1 && md->sc.opt1 != OPT1_STONEWAIT && md->sc.opt1 != OPT1_BURNING ) || status_db.hasSCF(&md->sc, SCF_MOBLOSETARGET)) {//Should reset targets.
md->target_id = md->attacked_id = md->norm_attacked_id = 0;
return false;
}

View File

@ -2690,7 +2690,7 @@ static void pc_bonus_addeff(std::vector<s_addeffect> &effect, enum sc_type sc, s
flag |= ATF_WEAPON; //Default type: weapon.
if (!duration)
duration = (unsigned int)skill_get_time2(status_sc2skill(sc), 7);
duration = (unsigned int)skill_get_time2(status_db.getSkill(sc), 7);
for (auto &it : effect) {
if (it.sc == sc && it.flag == flag) {
@ -2732,7 +2732,7 @@ static void pc_bonus_addeff_onskill(std::vector<s_addeffectonskill> &effect, enu
}
if (!duration)
duration = (unsigned int)skill_get_time2(status_sc2skill(sc), 7);
duration = (unsigned int)skill_get_time2(status_db.getSkill(sc), 7);
for (auto &it : effect) {
if (it.sc == sc && it.skill_id == skill_id && it.target == target) {
@ -5697,7 +5697,7 @@ bool pc_isUseitem(struct map_session_data *sd,int n)
case ITEMID_M_BERSERK_POTION:
if( sd->md == NULL || sd->md->db == NULL )
return false;
if( sd->md->sc.data[SC_BERSERK] )
if( sd->md->sc.cant.consume )
return false;
if( nameid == ITEMID_M_AWAKENING_POTION && sd->md->db->lv < 40 )
return false;
@ -5738,24 +5738,7 @@ bool pc_isUseitem(struct map_session_data *sd,int n)
if (!pc_job_can_use_item(sd,item))
return false;
if (sd->sc.count && (
sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAYNIGHTFEVER] ||
(sd->sc.data[SC_GRAVITATION] && sd->sc.data[SC_GRAVITATION]->val3 == BCT_SELF) ||
sd->sc.data[SC_TRICKDEAD] ||
sd->sc.data[SC_HIDING] ||
sd->sc.data[SC__SHADOWFORM] ||
sd->sc.data[SC__INVISIBILITY] ||
sd->sc.data[SC__MANHOLE] ||
sd->sc.data[SC_DEEPSLEEP] ||
sd->sc.data[SC_CRYSTALIZE] ||
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_HANDICAPSTATE_FROSTBITE] ||
sd->sc.data[SC_HANDICAPSTATE_SWOONING] ||
sd->sc.data[SC_HANDICAPSTATE_LIGHTNINGSTRIKE] ||
sd->sc.data[SC_HANDICAPSTATE_CRYSTALLIZATION]))
if (sd->sc.cant.consume)
return false;
if (!pc_isItemClass(sd,item))
@ -6292,24 +6275,23 @@ enum e_setpos pc_setpos(struct map_session_data* sd, unsigned short mapindex, in
sd->state.pmap = sd->bl.m;
if (sc && sc->count) { // Cancel some map related stuff.
if (sc->data[SC_JAILED])
return SETPOS_MAPINDEX; //You may not get out!
status_change_end(&sd->bl, SC_BOSSMAPINFO, INVALID_TIMER);
status_change_end(&sd->bl, SC_WARM, INVALID_TIMER);
status_change_end(&sd->bl, SC_SUN_COMFORT, INVALID_TIMER);
status_change_end(&sd->bl, SC_MOON_COMFORT, INVALID_TIMER);
status_change_end(&sd->bl, SC_STAR_COMFORT, INVALID_TIMER);
status_change_end(&sd->bl, SC_MIRACLE, INVALID_TIMER);
if (sc->data[SC_KNOWLEDGE]) {
struct status_change_entry *sce = sc->data[SC_KNOWLEDGE];
if (sce->timer != INVALID_TIMER)
delete_timer(sce->timer, status_change_timer);
sce->timer = add_timer(gettick() + skill_get_time(SG_KNOWLEDGE, sce->val1), status_change_timer, sd->bl.id, SC_KNOWLEDGE);
if (sc->cant.warp)
return SETPOS_MAPINDEX; // You may not get out!
for (const auto &it : status_db) {
if (sc->data[it.first]) {
if (it.second->flag[SCF_REMOVEONMAPWARP])
status_change_end(&sd->bl, static_cast<sc_type>(it.first), INVALID_TIMER);
if (it.second->flag[SCF_RESTARTONMAPWARP] && it.second->skill_id > 0) {
status_change_entry *sce = sd->sc.data[it.first];
if (sce->timer != INVALID_TIMER)
delete_timer(sce->timer, status_change_timer);
sce->timer = add_timer(gettick() + skill_get_time(it.second->skill_id, sce->val1), status_change_timer, sd->bl.id, it.first);
}
}
}
status_change_end(&sd->bl, SC_PROPERTYWALK, INVALID_TIMER);
status_change_end(&sd->bl, SC_CLOAKING, INVALID_TIMER);
status_change_end(&sd->bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
status_change_end(&sd->bl, SC_SUHIDE, INVALID_TIMER);
}
for(int i = 0; i < EQI_MAX; i++ ) {
if( sd->equip_index[i] >= 0 )
@ -6685,47 +6667,26 @@ uint8 pc_checkskill_imperial_guard(struct map_session_data *sd, short flag)
*/
static void pc_checkallowskill(struct map_session_data *sd)
{
const enum sc_type scw_list[] = {
SC_TWOHANDQUICKEN,
SC_ONEHAND,
SC_AURABLADE,
SC_PARRYING,
SC_SPEARQUICKEN,
SC_ADRENALINE,
SC_ADRENALINE2,
SC_DANCING,
SC_GATLINGFEVER,
SC_DANCING_KNIFE,
};
uint8 i;
nullpo_retv(sd);
if(!sd->sc.count)
return;
for (i = 0; i < ARRAYLENGTH(scw_list); i++)
{ // Skills requiring specific weapon types
if( scw_list[i] == SC_DANCING && !battle_config.dancing_weaponswitch_fix )
continue;
if(sd->sc.data[scw_list[i]] &&
!pc_check_weapontype(sd,skill_get_weapontype(status_sc2skill(scw_list[i]))))
status_change_end(&sd->bl, scw_list[i], INVALID_TIMER);
}
for (const auto &it : status_db) {
sc_type status = it.second->type;
std::bitset<SCF_MAX> flag = it.second->flag;
if(sd->sc.data[SC_SPURT] && sd->status.weapon)
// Spurt requires bare hands (feet, in fact xD)
status_change_end(&sd->bl, SC_SPURT, INVALID_TIMER);
if (flag[SCF_REQUIREWEAPON]) { // Skills requiring specific weapon types
if (status == SC_DANCING && !battle_config.dancing_weaponswitch_fix)
continue;
if (sd->sc.data[status] && !pc_check_weapontype(sd, skill_get_weapontype(it.second->skill_id)))
status_change_end(&sd->bl, status, INVALID_TIMER);
}
if(sd->status.shield <= 0) { // Skills requiring a shield
const enum sc_type scs_list[] = {
SC_AUTOGUARD,
SC_DEFENDER,
SC_REFLECTSHIELD,
SC_REFLECTDAMAGE
};
for (i = 0; i < ARRAYLENGTH(scs_list); i++)
if(sd->sc.data[scs_list[i]])
status_change_end(&sd->bl, scs_list[i], INVALID_TIMER);
if (flag[SCF_REQUIRESHIELD]) { // Skills requiring a shield
if (sd->sc.data[status] && sd->status.shield <= 0)
status_change_end(&sd->bl, status, INVALID_TIMER);
}
}
}
@ -7539,16 +7500,17 @@ int pc_checkbaselevelup(struct map_session_data *sd) {
status_percent_heal(&sd->bl,100,100);
if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE) {
sc_start(&sd->bl,&sd->bl,status_skill2sc(PR_KYRIE),100,1,skill_get_time(PR_KYRIE,1));
sc_start(&sd->bl,&sd->bl,status_skill2sc(PR_IMPOSITIO),100,1,skill_get_time(PR_IMPOSITIO,1));
sc_start(&sd->bl,&sd->bl,status_skill2sc(PR_MAGNIFICAT),100,1,skill_get_time(PR_MAGNIFICAT,1));
sc_start(&sd->bl,&sd->bl,status_skill2sc(PR_GLORIA),100,1,skill_get_time(PR_GLORIA,1));
sc_start(&sd->bl,&sd->bl,status_skill2sc(PR_SUFFRAGIUM),100,1,skill_get_time(PR_SUFFRAGIUM,1));
for (const auto &status : status_db) {
if (status.second->flag[SCF_SUPERNOVICEANGEL])
sc_start(&sd->bl, &sd->bl, status.second->type, 100, 1, skill_get_time(status.second->skill_id, 1));
}
if (sd->state.snovice_dead_flag)
sd->state.snovice_dead_flag = 0; //Reenable steelbody resurrection on dead.
} else if( (sd->class_&MAPID_BASEMASK) == MAPID_TAEKWON ) {
sc_start(&sd->bl,&sd->bl,status_skill2sc(AL_INCAGI),100,10,600000);
sc_start(&sd->bl,&sd->bl,status_skill2sc(AL_BLESSING),100,10,600000);
for (const auto &status : status_db) {
if (status.second->flag[SCF_TAEKWONANGEL])
sc_start(&sd->bl, &sd->bl, status.second->type, 100, 10, 600000);
}
}
clif_misceffect(&sd->bl,0);
npc_script_event(sd, NPCE_BASELVUP); //LORDALFA - LVLUPEVENT
@ -9035,7 +8997,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
clif_resurrection(&sd->bl, 1);
if(battle_config.pc_invincible_time)
pc_setinvincibletimer(sd, battle_config.pc_invincible_time);
sc_start(&sd->bl,&sd->bl,status_skill2sc(MO_STEELBODY),100,5,skill_get_time(MO_STEELBODY,5));
sc_start(&sd->bl,&sd->bl,SC_STEELBODY,100,5,skill_get_time(MO_STEELBODY,5));
if(mapdata_flag_gvg2(mapdata))
pc_respawn_timer(INVALID_TIMER, gettick(), sd->bl.id, 0);
return 0;
@ -9243,7 +9205,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
// changed penalty options, added death by player if pk_mode [Valaris]
if(battle_config.death_penalty_type
&& (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE // only novices will receive no penalty
&& !sd->sc.data[SC_BABY] && !sd->sc.data[SC_LIFEINSURANCE]
&& !sd->sc.cant.deathpenalty
&& !mapdata->flag[MF_NOEXPPENALTY] && !mapdata_flag_gvg2(mapdata))
{
t_exp base_penalty = 0;
@ -10154,16 +10116,7 @@ bool pc_jobchange(struct map_session_data *sd,int job, char upper)
}
if ( (b_class&MAPID_UPPERMASK) != (sd->class_&MAPID_UPPERMASK) ) { //Things to remove when changing class tree.
std::shared_ptr<s_skill_tree> tree = skill_tree_db.find(sd->status.class_);
if (tree != nullptr && !tree->skills.empty()) {
for (const auto &skillsit : tree->skills) {
//Remove status specific to your current tree skills.
enum sc_type sc = status_skill2sc(skillsit.first);
if (sc > SC_COMMON_MAX && sd->sc.data[sc])
status_change_end(&sd->bl, sc, INVALID_TIMER);
}
}
status_db.changeSkillTree(sd);
}
if( (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && (b_class&MAPID_UPPERMASK) != MAPID_STAR_GLADIATOR) {
@ -10613,45 +10566,6 @@ bool pc_candrop(struct map_session_data *sd, struct item *item)
return (itemdb_isdropable(item, pc_get_group_level(sd)));
}
/**
* Determines whether a player can attack based on status changes
* Why not use status_check_skilluse?
* "src MAY be null to indicate we shouldn't check it, this is a ground-based skill attack."
* Even ground-based attacks should be blocked by these statuses
* Called from unit_attack and unit_attack_timer_sub
* @retval true Can attack
**/
bool pc_can_attack( struct map_session_data *sd, int target_id ) {
nullpo_retr(false, sd);
if( pc_is90overweight(sd) || pc_isridingwug(sd) )
return false;
if (sd->state.block_action & PCBLOCK_ATTACK)
return false;
if(
#ifdef RENEWAL
sd->sc.data[SC_BASILICA_CELL] ||
#else
sd->sc.data[SC_BASILICA] ||
#endif
sd->sc.data[SC__SHADOWFORM] ||
sd->sc.data[SC_CURSEDCIRCLE_ATKER] ||
sd->sc.data[SC_CURSEDCIRCLE_TARGET] ||
sd->sc.data[SC_CRYSTALIZE] ||
sd->sc.data[SC_ALL_RIDING] || // The client doesn't let you, this is to make cheat-safe
sd->sc.data[SC_TRICKDEAD] ||
(sd->sc.data[SC_VOICEOFSIREN] && sd->sc.data[SC_VOICEOFSIREN]->val2 == target_id) ||
sd->sc.data[SC_BLADESTOP] ||
sd->sc.data[SC_DEEPSLEEP] ||
(sd->sc.data[SC_GRAVITATION] && sd->sc.data[SC_GRAVITATION]->val3 == BCT_SELF) ||
sd->sc.data[SC_KINGS_GRACE] )
return false;
return true;
}
/*==========================================
* Read '@type' variables (temporary numeric char reg)
*------------------------------------------*/
@ -11355,8 +11269,7 @@ bool pc_equipitem(struct map_session_data *sd,short n,int req_pos,bool equipswit
}
return false;
}
if( sd->sc.count && (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAYNIGHTFEVER] ||
sd->sc.data[SC_KYOUGAKU] || (sd->sc.data[SC_PYROCLASTIC] && sd->inventory_data[n]->type == IT_WEAPON)) ) {
if( sd->sc.count && (sd->sc.cant.equip || (sd->sc.data[SC_PYROCLASTIC] && sd->inventory_data[n]->type == IT_WEAPON)) ) {
if( equipswitch ){
clif_equipswitch_add( sd, n, req_pos, ITEM_EQUIP_ACK_FAIL );
}else{
@ -11678,13 +11591,8 @@ bool pc_unequipitem(struct map_session_data *sd, int n, int flag) {
return false; //Nothing to unequip
}
// status change that makes player cannot unequip equipment
if (!(flag&2) && sd->sc.count &&
(sd->sc.data[SC_BERSERK] ||
sd->sc.data[SC_SATURDAYNIGHTFEVER] ||
sd->sc.data[SC__BLOODYLUST] ||
sd->sc.data[SC_KYOUGAKU] ||
(sd->sc.data[SC_PYROCLASTIC] &&
sd->inventory_data[n]->type == IT_WEAPON))) // can't switch weapon
if (!(flag&2) && sd->sc.count &&( sd->sc.cant.unequip ||
(sd->sc.data[SC_PYROCLASTIC] && sd->inventory_data[n]->type == IT_WEAPON))) // can't switch weapon
{
clif_unequipitemack(sd,n,0,0);
return false;
@ -14236,7 +14144,7 @@ void pc_bonus_script(struct map_session_data *sd) {
* @return New created entry pointer or NULL if failed or NULL if duplicate fail
* @author [Cydh]
**/
struct s_bonus_script_entry *pc_bonus_script_add(struct map_session_data *sd, const char *script_str, t_tick dur, enum efst_types icon, uint16 flag, uint8 type) {
struct s_bonus_script_entry *pc_bonus_script_add(struct map_session_data *sd, const char *script_str, t_tick dur, enum efst_type icon, uint16 flag, uint8 type) {
struct script_code *script = NULL;
struct linkdb_node *node = NULL;
struct s_bonus_script_entry *entry = NULL;
@ -14361,7 +14269,7 @@ TIMER_FUNC(pc_bonus_script_timer){
* @param flag: Reason to remove the bonus_script. e_bonus_script_flags or e_bonus_script_types
* @author [Cydh]
**/
void pc_bonus_script_clear(struct map_session_data *sd, uint16 flag) {
void pc_bonus_script_clear(struct map_session_data *sd, uint32 flag) {
struct linkdb_node *node = NULL;
uint16 count = 0;

View File

@ -291,7 +291,7 @@ struct s_bonus_script_entry {
StringBuf *script_buf; //Used for comparing and storing on table
t_tick tick;
uint16 flag;
enum efst_types icon;
enum efst_type icon;
uint8 type; //0 - Ignore; 1 - Buff; 2 - Debuff
int tid;
};
@ -1459,7 +1459,6 @@ void pc_regen (struct map_session_data *sd, t_tick diff_tick);
bool pc_setstand(struct map_session_data *sd, bool force);
bool pc_candrop(struct map_session_data *sd,struct item *item);
bool pc_can_attack(struct map_session_data *sd, int target_id);
uint64 pc_jobid2mapid(unsigned short b_class); // Skotlex
int pc_mapid2jobid(uint64 class_, int sex); // Skotlex
@ -1573,8 +1572,8 @@ void pc_show_version(struct map_session_data *sd);
TIMER_FUNC(pc_bonus_script_timer);
void pc_bonus_script(struct map_session_data *sd);
struct s_bonus_script_entry *pc_bonus_script_add(struct map_session_data *sd, const char *script_str, t_tick dur, enum efst_types icon, uint16 flag, uint8 type);
void pc_bonus_script_clear(struct map_session_data *sd, uint16 flag);
struct s_bonus_script_entry *pc_bonus_script_add(struct map_session_data *sd, const char *script_str, t_tick dur, enum efst_type icon, uint16 flag, uint8 type);
void pc_bonus_script_clear(struct map_session_data *sd, uint32 flag);
void pc_cell_basilica(struct map_session_data *sd);

View File

@ -11944,9 +11944,11 @@ BUILDIN_FUNC(sc_start)
else
bl = map_id2bl(st->rid);
if(tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status_sc2skill(type) != 0)
uint16 skill_id;
if(tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && (skill_id = status_db.getSkill(type)) > 0)
{// When there isn't a duration specified, try to get it from the skill_db
tick = skill_get_time(status_sc2skill(type), val1);
tick = skill_get_time(skill_id, val1);
}
if(potion_flag == 1 && potion_target) { //skill.cpp set the flags before running the script, this is a potion-pitched effect.
@ -11996,45 +11998,16 @@ BUILDIN_FUNC(sc_end)
if (!bl)
return SCRIPT_CMD_SUCCESS;
if (type >= 0 && type < SC_MAX) {
if (type >= SC_NONE && type < SC_MAX) {
struct status_change *sc = status_get_sc(bl);
struct status_change_entry *sce = sc ? sc->data[type] : NULL;
if (!sce)
if (!sc)
return SCRIPT_CMD_SUCCESS;
switch (type) {
case SC_WEIGHT50:
case SC_WEIGHT90:
case SC_NOCHAT:
case SC_PUSH_CART:
case SC_ALL_RIDING:
case SC_STYLE_CHANGE:
case SC_MONSTER_TRANSFORM:
case SC_ACTIVE_MONSTER_TRANSFORM:
case SC_MTF_ASPD:
case SC_MTF_RANGEATK:
case SC_MTF_MATK:
case SC_MTF_MLEATKED:
case SC_MTF_CRIDAMAGE:
case SC_MTF_ASPD2:
case SC_MTF_RANGEATK2:
case SC_MTF_MATK2:
case SC_MTF_MHP:
case SC_MTF_MSP:
case SC_MTF_PUMPKIN:
case SC_MTF_HITFLEE:
case SC_ATTHASTE_CASH:
case SC_REUSE_LIMIT_A: case SC_REUSE_LIMIT_B: case SC_REUSE_LIMIT_C:
case SC_REUSE_LIMIT_D: case SC_REUSE_LIMIT_E: case SC_REUSE_LIMIT_F:
case SC_REUSE_LIMIT_G: case SC_REUSE_LIMIT_H: case SC_REUSE_LIMIT_MTF:
case SC_REUSE_LIMIT_ASPD_POTION: case SC_REUSE_MILLENNIUMSHIELD: case SC_REUSE_CRUSHSTRIKE:
case SC_REUSE_STORMBLAST: case SC_ALL_RIDING_REUSE_LIMIT: case SC_REUSE_REFRESH:
case SC_REUSE_LIMIT_ECL: case SC_REUSE_LIMIT_RECALL:
return SCRIPT_CMD_SUCCESS;
default:
break;
}
if (status_db.hasSCF(sc, SCF_NOCLEARBUFF))
return SCRIPT_CMD_SUCCESS;
struct status_change_entry *sce = sc ? sc->data[type] : NULL;
//This should help status_change_end force disabling the SC in case it has no limit.
sce->val1 = sce->val2 = sce->val3 = sce->val4 = 0;
@ -12053,7 +12026,6 @@ BUILDIN_FUNC(sc_end)
BUILDIN_FUNC(sc_end_class)
{
struct map_session_data *sd;
uint16 skill_id;
int class_;
if (!script_charid2sd(2, sd))
@ -12069,17 +12041,7 @@ BUILDIN_FUNC(sc_end_class)
return SCRIPT_CMD_FAILURE;
}
std::shared_ptr<s_skill_tree> tree = skill_tree_db.find(class_);
if( tree != nullptr ){
for (const auto &it : tree->skills) {
skill_id = it.first;
enum sc_type sc = status_skill2sc(skill_id);
if (sc > SC_COMMON_MAX && sd->sc.data[sc])
status_change_end(&sd->bl, sc, INVALID_TIMER);
}
}
status_db.changeSkillTree(sd, class_);
return SCRIPT_CMD_SUCCESS;
}
@ -23021,7 +22983,7 @@ BUILDIN_FUNC(bonus_script) {
if (icon <= EFST_BLANK || icon >= EFST_MAX)
icon = EFST_BLANK;
if ((entry = pc_bonus_script_add(sd, script_str, dur, (enum efst_types)icon, flag, type))) {
if ((entry = pc_bonus_script_add(sd, script_str, dur, (enum efst_type)icon, flag, type))) {
linkdb_insert(&sd->bonus_script.head, (void *)((intptr_t)entry), entry);
status_calc_pc(sd,SCO_NONE);
}

View File

@ -1054,7 +1054,8 @@
export_constant(SC_ARMOR);
export_constant(SC_ARMOR_ELEMENT_WATER);
export_constant(SC_NOCHAT);
export_constant(SC_BABY);
export_constant(SC_PROTECTEXP);
export_deprecated_constant3("SC_BABY", SC_PROTECTEXP, "SC_PROTECTEXP");
export_constant(SC_AURABLADE);
export_constant(SC_PARRYING);
export_constant(SC_CONCENTRATION);
@ -1611,6 +1612,7 @@
export_constant(SC_GOLDENMACECLAN);
export_constant(SC_CROSSBOWCLAN);
export_constant(SC_JUMPINGCLAN);
export_constant(SC_TAROTCARD);
export_constant(SC_GEFFEN_MAGIC1);
export_constant(SC_GEFFEN_MAGIC2);
export_constant(SC_GEFFEN_MAGIC3);
@ -1647,6 +1649,7 @@
export_constant(SC_ANCILLA);
export_constant(SC_EARTHSHAKER);
export_constant(SC_WEAPONBLOCK_ON);
export_constant(SC_SPORE_EXPLOSION);
export_constant(SC_ENTRY_QUEUE_APPLY_DELAY);
export_constant(SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT);
export_constant(SC_ADAPTATION);
@ -1691,6 +1694,8 @@
export_constant(SC_LUXANIMA);
export_constant(SC_REUSE_LIMIT_LUXANIMA);
export_constant(SC_ENSEMBLEFATIGUE);
export_constant(SC_MISTY_FROST);
export_constant(SC_MAGIC_POISON);
export_constant(SC_EP16_2_BUFF_SS);
export_constant(SC_EP16_2_BUFF_SC);
export_constant(SC_EP16_2_BUFF_AC);
@ -8724,6 +8729,169 @@
export_constant(EL_SKILLMODE_ASSIST);
export_constant(EL_SKILLMODE_AGGRESSIVE);
/* status calc bl */
export_constant(SCB_NONE);
export_constant(SCB_BASE);
export_constant(SCB_MAXHP);
export_constant(SCB_MAXSP);
export_constant(SCB_STR);
export_constant(SCB_AGI);
export_constant(SCB_VIT);
export_constant(SCB_INT);
export_constant(SCB_DEX);
export_constant(SCB_LUK);
export_constant(SCB_BATK);
export_constant(SCB_WATK);
export_constant(SCB_MATK);
export_constant(SCB_HIT);
export_constant(SCB_FLEE);
export_constant(SCB_DEF);
export_constant(SCB_DEF2);
export_constant(SCB_MDEF);
export_constant(SCB_MDEF2);
export_constant(SCB_SPEED);
export_constant(SCB_ASPD);
export_constant(SCB_DSPD);
export_constant(SCB_CRI);
export_constant(SCB_FLEE2);
export_constant(SCB_ATK_ELE);
export_constant(SCB_DEF_ELE);
export_constant(SCB_MODE);
export_constant(SCB_SIZE);
export_constant(SCB_RACE);
export_constant(SCB_RANGE);
export_constant(SCB_REGEN);
export_constant(SCB_DYE);
export_constant(SCB_BATTLE);
export_constant(SCB_MAXAP);
export_constant(SCB_POW);
export_constant(SCB_STA);
export_constant(SCB_WIS);
export_constant(SCB_SPL);
export_constant(SCB_CON);
export_constant(SCB_CRT);
export_constant(SCB_PATK);
export_constant(SCB_SMATK);
export_constant(SCB_RES);
export_constant(SCB_MRES);
export_constant(SCB_HPLUS);
export_constant(SCB_CRATE);
export_constant(SCB_ALL);
/* status change states */
export_constant(SCS_NONE);
export_constant(SCS_NOMOVECOND);
export_constant(SCS_NOMOVE);
export_constant(SCS_NOPICKITEMCOND);
export_constant(SCS_NOPICKITEM);
export_constant(SCS_NODROPITEMCOND);
export_constant(SCS_NODROPITEM);
export_constant(SCS_NOCASTCOND);
export_constant(SCS_NOCAST);
export_constant(SCS_NOCHAT);
export_constant(SCS_NOCHATCOND);
export_constant(SCS_NOEQUIPITEM);
export_constant(SCS_NOEQUIPITEMCOND);
export_constant(SCS_NOUNEQUIPITEM);
export_constant(SCS_NOUNEQUIPITEMCOND);
export_constant(SCS_NOCONSUMEITEM);
export_constant(SCS_NOCONSUMEITEMCOND);
export_constant(SCS_NOATTACK);
export_constant(SCS_NOATTACKCOND);
export_constant(SCS_NOWARP);
export_constant(SCS_NOWARPCOND);
export_constant(SCS_NODEATHPENALTY);
export_constant(SCS_NODEATHPENALTYCOND);
export_constant(SCS_NOINTERACT);
export_constant(SCS_NOINTERACTCOND);
/* body states */
export_constant(OPT1_STONE);
export_constant(OPT1_FREEZE);
export_constant(OPT1_STUN);
export_constant(OPT1_SLEEP);
export_constant(OPT1_STONEWAIT);
export_constant(OPT1_BURNING);
export_constant(OPT1_IMPRISON);
/* health states */
export_constant(OPT2_POISON);
export_constant(OPT2_CURSE);
export_constant(OPT2_SILENCE);
export_constant(OPT2_SIGNUMCRUCIS);
export_constant(OPT2_BLIND);
export_constant(OPT2_ANGELUS);
export_constant(OPT2_BLEEDING);
export_constant(OPT2_DPOISON);
export_constant(OPT2_FEAR);
/* show effect states */
export_constant(OPT3_NORMAL);
export_constant(OPT3_QUICKEN);
export_constant(OPT3_OVERTHRUST);
export_constant(OPT3_ENERGYCOAT);
export_constant(OPT3_EXPLOSIONSPIRITS);
export_constant(OPT3_STEELBODY);
export_constant(OPT3_BLADESTOP);
export_constant(OPT3_AURABLADE);
export_constant(OPT3_BERSERK);
export_constant(OPT3_LIGHTBLADE);
export_constant(OPT3_MOONLIT);
export_constant(OPT3_MARIONETTE);
export_constant(OPT3_ASSUMPTIO);
export_constant(OPT3_WARM);
export_constant(OPT3_KAITE);
export_constant(OPT3_BUNSIN);
export_constant(OPT3_SOULLINK);
export_constant(OPT3_UNDEAD);
export_constant(OPT3_CONTRACT);
/* status change flags */
export_constant(SCF_BLEFFECT);
export_constant(SCF_DISPLAYPC);
export_constant(SCF_NOCLEARBUFF);
export_constant(SCF_NOREMOVEONDEAD);
export_constant(SCF_NODISPELL);
export_constant(SCF_NOCLEARANCE);
export_constant(SCF_NOBANISHINGBUSTER);
export_constant(SCF_NOSAVE);
export_constant(SCF_NOSAVEINFINITE);
export_constant(SCF_REMOVEONDAMAGED);
export_constant(SCF_REMOVEONREFRESH);
export_constant(SCF_REMOVEONLUXANIMA);
export_constant(SCF_STOPATTACKING);
export_constant(SCF_STOPCASTING);
export_constant(SCF_STOPWALKING);
export_constant(SCF_BOSSRESIST);
export_constant(SCF_MVPRESIST);
export_constant(SCF_SETSTAND);
export_constant(SCF_FAILEDMADO);
export_constant(SCF_DEBUFF);
export_constant(SCF_REMOVEONCHANGEMAP);
export_constant(SCF_REMOVEONMAPWARP);
export_constant(SCF_REMOVECHEMICALPROTECT);
export_constant(SCF_OVERLAPFAIL);
export_constant(SCF_OVERLAPIGNORELEVEL);
export_constant(SCF_SENDOPTION);
export_constant(SCF_ONTOUCH);
export_constant(SCF_UNITMOVE);
export_constant(SCF_NONPLAYER);
export_constant(SCF_SENDLOOK);
export_constant(SCF_DISPLAYNPC);
export_constant(SCF_REQUIREWEAPON);
export_constant(SCF_REQUIRESHIELD);
export_constant(SCF_MOBLOSETARGET);
export_constant(SCF_REMOVEELEMENTALOPTION);
export_constant(SCF_SUPERNOVICEANGEL);
export_constant(SCF_TAEKWONANGEL);
export_constant(SCF_MADOCANCEL);
export_constant(SCF_MADOENDCANCEL);
export_constant(SCF_RESTARTONMAPWARP);
export_constant(SCF_SPREADEFFECT);
export_constant(SCF_SENDVAL1);
export_constant(SCF_SENDVAL2);
export_constant(SCF_SENDVAL3);
#undef export_constant
#undef export_constant2
#undef export_parameter

View File

@ -218,6 +218,7 @@ int skill_get_ammo_qty( uint16 skill_id, uint16 skill_lv ) { skill_get_l
int skill_get_state( uint16 skill_id ) { skill_get(skill_id, skill_db.find(skill_id)->require.state); }
int skill_get_status_count( uint16 skill_id ) { skill_get(skill_id, skill_db.find(skill_id)->require.status.size()); }
int skill_get_spiritball( uint16 skill_id, uint16 skill_lv ) { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->require.spiritball); }
sc_type skill_get_sc(int16 skill_id) { if (!skill_check(skill_id)) return SC_NONE; return skill_db.find(skill_id)->sc; }
int skill_get_splash( uint16 skill_id , uint16 skill_lv ) {
int splash = skill_get_splash_(skill_id, skill_lv);
@ -1601,22 +1602,34 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
break;
case NPC_PETRIFYATTACK:
sc_start4(src,bl,status_skill2sc(skill_id),(20*skill_lv),
skill_lv,0,0,skill_get_time(skill_id,skill_lv),
skill_get_time2(skill_id,skill_lv));
sc_start4(src,bl,SC_STONE,50+10*skill_lv,skill_lv,0,0,skill_get_time(skill_id,skill_lv),skill_get_time2(skill_id,skill_lv));
break;
case NPC_CURSEATTACK:
sc_start(src,bl,SC_CURSE,(20*skill_lv),skill_lv,skill_get_time2(skill_id,skill_lv));
break;
case NPC_SLEEPATTACK:
sc_start(src,bl,SC_SLEEP,(20*skill_lv),skill_lv,skill_get_time2(skill_id,skill_lv));
break;
case NPC_BLINDATTACK:
sc_start(src,bl,SC_BLIND,(20*skill_lv),skill_lv,skill_get_time2(skill_id,skill_lv));
break;
case NPC_POISON:
sc_start(src,bl,SC_POISON,(20*skill_lv),skill_lv,skill_get_time2(skill_id,skill_lv));
break;
case NPC_SILENCEATTACK:
sc_start(src,bl,SC_SILENCE,(20*skill_lv),skill_lv,skill_get_time2(skill_id,skill_lv));
break;
case NPC_STUNATTACK:
sc_start(src,bl,SC_STUN,(20*skill_lv),skill_lv,skill_get_time2(skill_id,skill_lv));
break;
case NPC_BLEEDING:
sc_start(src,bl,status_skill2sc(skill_id),(20*skill_lv),skill_lv,skill_get_time2(skill_id,skill_lv));
sc_start(src,bl,SC_BLEEDING,(20*skill_lv),skill_lv,skill_get_time2(skill_id,skill_lv));
break;
case NPC_ACIDBREATH:
sc_start(src,bl,SC_POISON,70,skill_lv,skill_get_time2(skill_id,skill_lv));
break;
case NPC_ICEBREATH:
sc_start(src,bl,status_skill2sc(skill_id),70,skill_lv,skill_get_time2(skill_id,skill_lv));
sc_start(src,bl,SC_FREEZE,70,skill_lv,skill_get_time2(skill_id,skill_lv));
break;
case NPC_MENTALBREAKER:
{ //Based on observations by Tharis, Mental Breaker should do SP damage
@ -1772,7 +1785,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
sc_start(src,bl, SC_ADORAMUS, skill_lv * 4 + (sd ? sd->status.job_level : 50) / 2, skill_lv, skill_get_time2(skill_id, skill_lv));
break;
case WL_COMET:
sc_start(src, bl, status_skill2sc(skill_id), 100, skill_lv, 20000);
sc_start(src, bl, SC_BURNING, 100, skill_lv, 20000);
break;
case NPC_COMET:
sc_start4(src,bl,SC_BURNING,100,skill_lv,1000,src->id,0,skill_get_time(skill_id,skill_lv));
@ -1899,7 +1912,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
sc_start(src,bl, SC_POISON, 5 * skill_lv, skill_lv, skill_get_time(skill_id, skill_lv));
break;
case GN_SPORE_EXPLOSION:
sc_start(src, bl, status_skill2sc(skill_id), 100, skill_lv, skill_get_time(skill_id, skill_lv));
sc_start(src, bl, SC_SPORE_EXPLOSION, 100, skill_lv, skill_get_time(skill_id, skill_lv));
break;
case GN_SLINGITEM_RANGEMELEEATK:
if( sd ) {
@ -1935,8 +1948,10 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
sc_start(src,bl, SC_STUN, rate, skill_lv, skill_get_time(skill_id,skill_lv));
break;
case EL_ROCK_CRUSHER:
sc_start(src,bl, SC_ROCK_CRUSHER,50,skill_lv,skill_get_time(EL_ROCK_CRUSHER,skill_lv));
break;
case EL_ROCK_CRUSHER_ATK:
sc_start(src,bl,status_skill2sc(skill_id),50,skill_lv,skill_get_time(EL_ROCK_CRUSHER,skill_lv));
sc_start(src,bl,SC_ROCK_CRUSHER_ATK,50,skill_lv,skill_get_time(EL_ROCK_CRUSHER,skill_lv));
break;
case EL_TYPOON_MIS:
sc_start(src,bl,SC_SILENCE,10*skill_lv,skill_lv,skill_get_time(skill_id,skill_lv));
@ -1993,8 +2008,6 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
sc_start(src,bl,SC_STUN,100,skill_lv,skill_get_time2(skill_id,skill_lv));
break;
case RL_BANISHING_BUSTER: {
uint16 i, n = skill_lv;
if (!tsc || !tsc->count)
break;
@ -2007,99 +2020,24 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
break;
}
for (i = 0; n > 0 && i < SC_MAX; i++) {
if (!tsc->data[i])
uint16 n = skill_lv;
for (const auto &it : status_db) {
sc_type status = static_cast<sc_type>(it.first);
if (n <= 0)
break;
if (!tsc->data[status])
continue;
switch (i) {
case SC_WEIGHT50: case SC_WEIGHT90: case SC_HALLUCINATION:
case SC_STRIPWEAPON: case SC_STRIPSHIELD: case SC_STRIPARMOR:
case SC_STRIPHELM: case SC_CP_WEAPON: case SC_CP_SHIELD:
case SC_CP_ARMOR: case SC_CP_HELM: case SC_COMBO:
case SC_STRFOOD: case SC_AGIFOOD: case SC_VITFOOD:
case SC_INTFOOD: case SC_DEXFOOD: case SC_LUKFOOD:
case SC_HITFOOD: case SC_FLEEFOOD: case SC_BATKFOOD:
case SC_WATKFOOD: case SC_MATKFOOD: case SC_CRIFOOD:
case SC_DANCING: case SC_SPIRIT: case SC_AUTOBERSERK:
case SC_CARTBOOST: case SC_MELTDOWN: case SC_SAFETYWALL:
case SC_SMA: case SC_SPEEDUP0: case SC_NOCHAT:
case SC_ANKLE: case SC_SPIDERWEB: case SC_JAILED:
case SC_ITEMBOOST: case SC_EXPBOOST: case SC_LIFEINSURANCE:
case SC_BOSSMAPINFO: case SC_PNEUMA: case SC_AUTOSPELL:
case SC_INCHITRATE: case SC_INCATKRATE: case SC_NEN:
case SC_READYSTORM: case SC_READYDOWN: case SC_READYTURN:
case SC_READYCOUNTER: case SC_DODGE: case SC_WARM:
/*case SC_SPEEDUP1:*/ case SC_AUTOTRADE: case SC_CRITICALWOUND:
case SC_JEXPBOOST: case SC_INVINCIBLE: case SC_INVINCIBLEOFF:
case SC_HELLPOWER: case SC_MANU_ATK: case SC_MANU_DEF:
case SC_SPL_ATK: case SC_SPL_DEF: case SC_MANU_MATK:
case SC_SPL_MATK: case SC_RICHMANKIM: case SC_ETERNALCHAOS:
case SC_DRUMBATTLE: case SC_NIBELUNGEN: case SC_ROKISWEIL:
case SC_INTOABYSS: case SC_SIEGFRIED: case SC_FOOD_STR_CASH:
case SC_FOOD_AGI_CASH: case SC_FOOD_VIT_CASH: case SC_FOOD_DEX_CASH:
case SC_FOOD_INT_CASH: case SC_FOOD_LUK_CASH: case SC_ELECTRICSHOCKER:
case SC__STRIPACCESSORY: case SC__ENERVATION: case SC__GROOMY:
case SC__IGNORANCE: case SC__LAZINESS: case SC__UNLUCKY:
case SC__WEAKNESS: case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD:
case SC_MAGNETICFIELD: case SC_MINOR_BBQ: case SC_SIROMA_ICE_TEA:
case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES: case SC_NEUTRALBARRIER_MASTER:
case SC_NEUTRALBARRIER: case SC_STEALTHFIELD_MASTER: case SC_STEALTHFIELD:
case SC_LEADERSHIP: case SC_GLORYWOUNDS: case SC_SOULCOLD:
case SC_HAWKEYES: case SC_REGENERATION: case SC_SEVENWIND:
case SC_MIRACLE: case SC_S_LIFEPOTION: case SC_L_LIFEPOTION:
case SC_INCHEALRATE: case SC_PUSH_CART: case SC_PARTYFLEE:
case SC_RAISINGDRAGON: case SC_GT_REVITALIZE: case SC_GT_ENERGYGAIN:
case SC_GT_CHANGE: case SC_ANGEL_PROTECT: case SC_MONSTER_TRANSFORM:
case SC_FULL_THROTTLE: case SC_REBOUND: case SC_TELEKINESIS_INTENSE:
case SC_MOONSTAR: case SC_SUPER_STAR: case SC_ALL_RIDING:
case SC_MTF_ASPD: case SC_MTF_RANGEATK: case SC_MTF_MATK:
case SC_MTF_MLEATKED: case SC_MTF_CRIDAMAGE: case SC_HEAT_BARREL:
case SC_P_ALTER: case SC_E_CHAIN:
case SC_C_MARKER: case SC_B_TRAP: case SC_H_MINE:
case SC_STRANGELIGHTS: case SC_DECORATION_OF_MUSIC: case SC_GN_CARTBOOST:
case SC_RECOGNIZEDSPELL: case SC_CHASEWALK2: case SC_BITE:
case SC_ACTIVE_MONSTER_TRANSFORM: case SC_DORAM_BUF_01: case SC_DORAM_BUF_02:
case SC_SPORE_EXPLOSION:
case SC_NEWMOON: case SC_FLASHKICK: case SC_NOVAEXPLOSING:
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
case SC_HIDING: case SC_CLOAKING: case SC_CHASEWALK:
case SC_CLOAKINGEXCEED: case SC__INVISIBILITY: case SC_UTSUSEMI:
case SC_MTF_ASPD2: case SC_MTF_RANGEATK2: case SC_MTF_MATK2:
case SC_2011RWC_SCROLL: case SC_JP_EVENT04: case SC_MTF_MHP:
case SC_MTF_MSP: case SC_MTF_PUMPKIN: case SC_MTF_HITFLEE:
case SC_ATTHASTE_CASH: case SC_REUSE_REFRESH:
case SC_REUSE_LIMIT_A: case SC_REUSE_LIMIT_B: case SC_REUSE_LIMIT_C:
case SC_REUSE_LIMIT_D: case SC_REUSE_LIMIT_E: case SC_REUSE_LIMIT_F:
case SC_REUSE_LIMIT_G: case SC_REUSE_LIMIT_H: case SC_REUSE_LIMIT_MTF:
case SC_REUSE_LIMIT_ASPD_POTION: case SC_REUSE_MILLENNIUMSHIELD: case SC_REUSE_CRUSHSTRIKE:
case SC_REUSE_STORMBLAST: case SC_ALL_RIDING_REUSE_LIMIT:
case SC_SPRITEMABLE: case SC_BITESCAR:
case SC_CLAN_INFO: case SC_SWORDCLAN: case SC_ARCWANDCLAN:
case SC_GOLDENMACECLAN: case SC_CROSSBOWCLAN:
case SC_DAILYSENDMAILCNT:
case SC_WEDDING: case SC_XMAS: case SC_SUMMER:
case SC_DRESSUP: case SC_HANBOK: case SC_OKTOBERFEST:
case SC_LHZ_DUN_N1: case SC_LHZ_DUN_N2: case SC_LHZ_DUN_N3: case SC_LHZ_DUN_N4:
case SC_ENTRY_QUEUE_APPLY_DELAY: case SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT:
case SC_REUSE_LIMIT_LUXANIMA: case SC_LUXANIMA: case SC_SOULENERGY:
case SC_EP16_2_BUFF_SS: case SC_EP16_2_BUFF_SC: case SC_EP16_2_BUFF_AC:
case SC_EMERGENCY_MOVE: case SC_MADOGEAR: case SC_HOMUN_TIME:
case SC_PACKING_ENVELOPE1: case SC_PACKING_ENVELOPE2: case SC_PACKING_ENVELOPE3:
case SC_PACKING_ENVELOPE4: case SC_PACKING_ENVELOPE5: case SC_PACKING_ENVELOPE6:
case SC_PACKING_ENVELOPE7: case SC_PACKING_ENVELOPE8: case SC_PACKING_ENVELOPE9: case SC_PACKING_ENVELOPE10:
continue;
if (it.second->flag[SCF_NOBANISHINGBUSTER])
continue;
switch (status) {
case SC_WHISTLE: case SC_ASSNCROS: case SC_POEMBRAGI:
case SC_APPLEIDUN: case SC_HUMMING: case SC_DONTFORGETME:
case SC_FORTUNE: case SC_SERVICE4U:
if (!battle_config.dispel_song || tsc->data[i]->val4 == 0)
if (!battle_config.dispel_song || tsc->data[status]->val4 == 0)
continue; //If in song area don't end it, even if config enabled
break;
case SC_ASSUMPTIO:
@ -2107,9 +2045,9 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
continue;
break;
}
if( i == SC_BERSERK || i == SC_SATURDAYNIGHTFEVER )
tsc->data[i]->val2 = 0;
status_change_end(bl,(sc_type)i,INVALID_TIMER);
if( status == SC_BERSERK || status == SC_SATURDAYNIGHTFEVER )
tsc->data[status]->val2 = 0;
status_change_end(bl,status,INVALID_TIMER);
n--;
}
//Remove bonus_script by Banishing Buster
@ -2802,7 +2740,7 @@ int skill_break_equip(struct block_list *src, struct block_list *bl, unsigned sh
else if (rnd()%10000 >= rate)
where&=~where_list[i];
else if (!sd) //Cause Strip effect.
sc_start(src,bl,scatk[i],100,0,skill_get_time(status_sc2skill(scatk[i]),1));
sc_start(src,bl,scatk[i],100,0,skill_get_time(status_db.getSkill(scatk[i]),1));
}
}
if (!where) //Nothing to break.
@ -4490,14 +4428,19 @@ static TIMER_FUNC(skill_timerskill){
case PR_LEXDIVINA:
if (src->type == BL_MOB) {
// Monsters use the default duration when casting Lex Divina
sc_start(src, target, status_skill2sc(skl->skill_id), skl->type, skl->skill_lv, skill_get_time2(status_sc2skill(status_skill2sc(skl->skill_id)), 1));
sc_start(src, target, SC_SILENCE, skl->type, skl->skill_lv, skill_get_time2(status_db.getSkill(SC_SILENCE), 1));
break;
}
// Fall through
sc_start(src, target, SC_SILENCE, skl->type, skl->skill_lv, skill_get_time2(skl->skill_id, skl->skill_lv));
break;
case PR_STRECOVERY:
sc_start(src, target, SC_BLIND, skl->type, skl->skill_lv, skill_get_time2(skl->skill_id, skl->skill_lv));
break;
case BS_HAMMERFALL:
sc_start(src, target, SC_STUN, skl->type, skl->skill_lv, skill_get_time2(skl->skill_id, skl->skill_lv));
break;
case MER_LEXDIVINA:
sc_start(src, target, status_skill2sc(skl->skill_id), skl->type, skl->skill_lv, skill_get_time2(skl->skill_id, skl->skill_lv));
sc_start(src, target, SC_SILENCE, skl->type, skl->skill_lv, skill_get_time2(skl->skill_id, skl->skill_lv));
break;
case WZ_WATERBALL:
{
@ -4884,15 +4827,15 @@ static int skill_tarotcard(struct block_list* src, struct block_list *target, ui
{
enum sc_type sc[] = { SC_STOP, SC_FREEZE, SC_STONE };
uint8 rand_eff = rnd() % 3;
int time = ((rand_eff == 0) ? skill_get_time2(skill_id, skill_lv) : skill_get_time2(status_sc2skill(sc[rand_eff]), 1));
int time = ((rand_eff == 0) ? skill_get_time2(skill_id, skill_lv) : skill_get_time2(status_db.getSkill(sc[rand_eff]), 1));
sc_start(src, target, sc[rand_eff], 100, skill_lv, time);
break;
}
case 9: // DEATH - curse, coma and poison
{
status_change_start(src, target, SC_COMA, 10000, skill_lv, 0, src->id, 0, 0, SCSTART_NONE);
sc_start(src, target, SC_CURSE, 100, skill_lv, skill_get_time2(status_sc2skill(SC_CURSE), 1));
sc_start2(src, target, SC_POISON, 100, skill_lv, src->id, skill_get_time2(status_sc2skill(SC_POISON), 1));
sc_start(src, target, SC_CURSE, 100, skill_lv, skill_get_time2(status_db.getSkill(SC_CURSE), 1));
sc_start2(src, target, SC_POISON, 100, skill_lv, src->id, skill_get_time2(status_db.getSkill(SC_POISON), 1));
break;
}
case 10: // TEMPERANCE - confusion
@ -4906,7 +4849,7 @@ static int skill_tarotcard(struct block_list* src, struct block_list *target, ui
clif_damage(src, target, tick, 0, 0, 6666, 0, DMG_NORMAL, 0, false);
sc_start(src, target, SC_INCATKRATE, 100, -50, skill_get_time2(skill_id, skill_lv));
sc_start(src, target, SC_INCMATKRATE, 100, -50, skill_get_time2(skill_id, skill_lv));
sc_start(src, target, SC_CURSE, skill_lv, 100, skill_get_time2(status_sc2skill(SC_CURSE), 1));
sc_start(src, target, SC_CURSE, skill_lv, 100, skill_get_time2(status_db.getSkill(SC_CURSE), 1));
break;
}
case 12: // THE TOWER - 4444 damage
@ -4917,7 +4860,7 @@ static int skill_tarotcard(struct block_list* src, struct block_list *target, ui
}
case 13: // THE STAR - stun
{
sc_start(src, target, SC_STUN, 100, skill_lv, skill_get_time2(status_sc2skill(SC_STUN), 1));
sc_start(src, target, SC_STUN, 100, skill_lv, skill_get_time2(status_db.getSkill(SC_STUN), 1));
break;
}
default: // THE SUN - atk, matk, hit, flee and def reduced, immune to more tarot card effects
@ -4966,7 +4909,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
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);
sc_type sct = skill_get_sc(skill_id);
if(sct != SC_NONE)
status_change_end(bl, sct, INVALID_TIMER);
clif_skill_damage(src, bl, tick, status_get_amotion(src), status_get_dmotion(bl), 0, 1, skill_id, skill_lv, skill_get_hit(skill_id));
@ -5957,7 +5900,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
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));
sc_start(src,src,SC_MAGICALATTACK,100,skill_lv,skill_get_time(skill_id,skill_lv));
break;
case HVAN_CAPRICE: //[blackhole89]
@ -6209,7 +6152,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
case GC_DARKCROW:
skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
sc_start(src, bl, status_skill2sc(skill_id), 100, skill_lv, skill_get_time(skill_id, skill_lv)); // Should be applied even on miss
sc_start(src, bl, SC_DARKCROW, 100, skill_lv, skill_get_time(skill_id, skill_lv)); // Should be applied even on miss
break;
case WL_DRAINLIFE:
@ -6376,7 +6319,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
break;
case WL_FROSTMISTY:
// Causes Freezing status through walls.
sc_start(src, bl, status_skill2sc(skill_id), 25 + 5 * skill_lv, skill_lv, skill_get_time(skill_id, skill_lv));
sc_start(src, bl, SC_FREEZING, 25 + 5 * skill_lv, skill_lv, skill_get_time(skill_id, skill_lv));
sc_start(src, bl, SC_MISTY_FROST, 100, skill_lv, skill_get_time2(skill_id, skill_lv));
// Doesn't deal damage through non-shootable walls.
if( !battle_config.skill_wall_check || (battle_config.skill_wall_check && path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKWALL)) )
@ -6632,14 +6575,13 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
if( src->type == BL_ELEM ) {
s_elemental_data *ele = BL_CAST(BL_ELEM,src);
struct status_change *tsc_ele = status_get_sc(&ele->bl);
sc_type type = status_skill2sc(skill_id), type2;
type2 = static_cast<sc_type>(type - 1);
sc_type type = SC_TIDAL_WEAPON_OPTION, type2 = SC_TIDAL_WEAPON;
clif_skill_nodamage(src,battle_get_master(src),skill_id,skill_lv,1);
clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, DMG_SINGLE);
if( (tsc_ele && tsc_ele->data[type2]) || (tsc && tsc->data[type]) ) {
elemental_clean_single_effect(ele, skill_id);
status_change_end(battle_get_master(src),type,INVALID_TIMER);
status_change_end(src,type2,INVALID_TIMER);
}
if( rnd()%100 < 50 )
skill_attack(skill_get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag);
@ -6676,13 +6618,21 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
{
TBL_HOM *hd = BL_CAST(BL_HOM,src);
int duration = max(skill_lv, (status_get_str(src) / 7 - status_get_str(bl) / 10)) * 1000; //Yommy formula
sc_type type;
if (skill_id == MH_TINDER_BREAKER && unit_movepos(src, bl->x, bl->y, 1, 1)) {
clif_blown(src);
clif_skill_poseffect(src,skill_id,skill_lv,bl->x,bl->y,tick);
if( skill_id == MH_TINDER_BREAKER ){
type = SC_TINDER_BREAKER2;
if( unit_movepos(src, bl->x, bl->y, 1, 1) ){
clif_blown(src);
clif_skill_poseffect(src,skill_id,skill_lv,bl->x,bl->y,tick);
}
}else if( skill_id == MH_CBC ){
type = SC_CBC;
}else if( skill_id == MH_EQC ){
type = SC_EQC;
}
clif_skill_nodamage(src,bl,skill_id,skill_lv,
sc_start4(src,bl,status_skill2sc(skill_id),100,skill_lv,src->id,0,0,duration));
clif_skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(src,bl,type,100,skill_lv,src->id,0,0,duration));
skill_attack(skill_get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag);
}
break;
@ -6742,13 +6692,12 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
break;
case SU_SCAROFTAROU:
sc_start(src, bl, SC_BITESCAR, 10, skill_lv, skill_get_time(skill_id, skill_lv)); //! TODO: What's the activation chance for the Bite effect?
skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
break;
case SU_SV_STEMSPEAR:
if (skill_id == SU_SCAROFTAROU)
sc_start(src, bl, status_skill2sc(skill_id), 10, skill_lv, skill_get_time(skill_id, skill_lv)); //! TODO: What's the activation chance for the Bite effect?
else {
if (sd && pc_checkskill(sd, SU_SPIRITOFLAND))
sc_start(src, src, SC_DORAM_WALKSPEED, 100, 50, skill_get_time(SU_SPIRITOFLAND, 1));
}
if (sd && pc_checkskill(sd, SU_SPIRITOFLAND))
sc_start(src, src, SC_DORAM_WALKSPEED, 100, 50, skill_get_time(SU_SPIRITOFLAND, 1));
skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
break;
@ -6903,7 +6852,7 @@ static int skill_apply_songs(struct block_list* target, va_list ap)
default: // Buff/Debuff type songs
if (skill_id == CG_HERMODE && src->id != target->id)
status_change_clear_buffs(target, SCCB_BUFFS); // Should dispell only allies.
return sc_start(src, target, status_skill2sc(skill_id), 100, skill_lv, skill_get_time(skill_id, skill_lv));
return sc_start(src, target, skill_get_sc(skill_id), 100, skill_lv, skill_get_time(skill_id, skill_lv));
}
}
@ -7061,12 +7010,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
return skill_castend_pos2(src,bl->x,bl->y,skill_id,skill_lv,tick,0);
}
type = status_skill2sc(skill_id);
status_change *sc = status_get_sc(src);
type = skill_get_sc(skill_id);
tsc = status_get_sc(bl);
tsce = (tsc && type != -1)?tsc->data[type]:NULL;
tsce = (tsc && type != SC_NONE)?tsc->data[type]:NULL;
if (src!=bl && type > -1 &&
if (src!=bl && type > SC_NONE &&
CHK_ELEMENT((i = skill_get_ele(skill_id, skill_lv))) && i > ELE_NEUTRAL &&
skill_get_inf(skill_id) != INF_SUPPORT_SKILL &&
battle_attr_fix(NULL, NULL, 100, i, tstatus->def_ele, tstatus->ele_lv) <= 0)
@ -7703,6 +7651,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
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);
status_change *sc = status_get_sc(src);
if (sc && sc->data[SC_CLIMAX])
climax_lv = sc->data[SC_CLIMAX]->val1;
@ -7885,23 +7834,16 @@ 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 AS_ENCHANTPOISON: // Prevent spamming [Valaris]
if (sd && dstsd && dstsd->sc.count) {
if (dstsd->sc.data[SC_FIREWEAPON] ||
dstsd->sc.data[SC_WATERWEAPON] ||
dstsd->sc.data[SC_WINDWEAPON] ||
dstsd->sc.data[SC_EARTHWEAPON] ||
dstsd->sc.data[SC_SHADOWWEAPON] ||
dstsd->sc.data[SC_GHOSTWEAPON]
// dstsd->sc.data[SC_ENCPOISON] //People say you should be able to recast to lengthen the timer. [Skotlex]
) {
clif_skill_nodamage(src,bl,skill_id,skill_lv,0);
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
break;
case AS_ENCHANTPOISON:
if( sc_start( src, bl, type, 100, skill_lv, skill_get_time( skill_id, skill_lv ) ) ){
clif_skill_nodamage( src, bl, skill_id, skill_lv, 1 );
}else{
clif_skill_nodamage( src, bl, skill_id, skill_lv, 0 );
if( sd != nullptr ){
clif_skill_fail( sd, skill_id, USESKILL_FAIL_LEVEL, 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 LK_TENSIONRELAX:
@ -8544,7 +8486,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
}
if( skill_id == SP_SOULCOLLECT ){
clif_skill_nodamage(src, bl, skill_id, skill_lv, sc_start2(src, bl, type, 100, skill_lv, pc_checkskill(sd, SP_SOULENERGY), max(1000, skill_get_time(skill_id, skill_lv))));
clif_skill_nodamage(src, bl, skill_id, skill_lv, sc_start2(src, bl, type, 100, skill_lv, pc_checkskill(sd, SP_SOULENERGY), skill_get_time(skill_id, skill_lv)));
}else{
clif_skill_nodamage(src, bl, skill_id, skill_lv, sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)));
}
@ -9237,116 +9179,21 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
if(!tsc || !tsc->count)
break;
for(i=0;i<SC_MAX;i++) {
if (!tsc->data[i])
//Statuses that can't be Dispelled
for (const auto &it : status_db) {
sc_type status = static_cast<sc_type>(it.first);
if (!tsc->data[status])
continue;
switch (i) {
case SC_WEIGHT50: case SC_WEIGHT90: case SC_HALLUCINATION:
case SC_STRIPWEAPON: case SC_STRIPSHIELD: case SC_STRIPARMOR:
case SC_STRIPHELM: case SC_CP_WEAPON: case SC_CP_SHIELD:
case SC_CP_ARMOR: case SC_CP_HELM: case SC_COMBO:
case SC_STRFOOD: case SC_AGIFOOD: case SC_VITFOOD:
case SC_INTFOOD: case SC_DEXFOOD: case SC_LUKFOOD:
case SC_HITFOOD: case SC_FLEEFOOD: case SC_BATKFOOD:
case SC_WATKFOOD: case SC_MATKFOOD: case SC_CRIFOOD:
case SC_DANCING: case SC_EDP: case SC_AUTOBERSERK:
case SC_CARTBOOST: case SC_MELTDOWN: case SC_SAFETYWALL:
case SC_SMA: case SC_SPEEDUP0: case SC_NOCHAT:
case SC_ANKLE: case SC_SPIDERWEB: case SC_JAILED:
case SC_ITEMBOOST: case SC_EXPBOOST: case SC_LIFEINSURANCE:
case SC_BOSSMAPINFO: case SC_PNEUMA: case SC_AUTOSPELL:
case SC_INCHITRATE: case SC_INCATKRATE: case SC_NEN:
case SC_READYSTORM: case SC_READYDOWN: case SC_READYTURN:
case SC_READYCOUNTER: case SC_DODGE: case SC_WARM:
/*case SC_SPEEDUP1:*/ case SC_AUTOTRADE: case SC_CRITICALWOUND:
case SC_JEXPBOOST: case SC_INVINCIBLE: case SC_INVINCIBLEOFF:
case SC_HELLPOWER: case SC_MANU_ATK: case SC_MANU_DEF:
case SC_SPL_ATK: case SC_SPL_DEF: case SC_MANU_MATK:
case SC_SPL_MATK: case SC_RICHMANKIM: case SC_ETERNALCHAOS:
case SC_DRUMBATTLE: case SC_NIBELUNGEN: case SC_ROKISWEIL:
case SC_INTOABYSS: case SC_SIEGFRIED: case SC_FOOD_STR_CASH:
case SC_FOOD_AGI_CASH: case SC_FOOD_VIT_CASH: case SC_FOOD_DEX_CASH:
case SC_FOOD_INT_CASH: case SC_FOOD_LUK_CASH: case SC_SEVENWIND:
case SC_MIRACLE: case SC_S_LIFEPOTION: case SC_L_LIFEPOTION:
case SC_INCHEALRATE: case SC_ELECTRICSHOCKER: case SC__STRIPACCESSORY:
case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD: case SC_MINOR_BBQ:
case SC_SIROMA_ICE_TEA: case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES:
case SC_NEUTRALBARRIER_MASTER: case SC_NEUTRALBARRIER: case SC_STEALTHFIELD_MASTER:
case SC_STEALTHFIELD: case SC_GIANTGROWTH: case SC_MILLENNIUMSHIELD:
case SC_REFRESH: case SC_STONEHARDSKIN: case SC_VITALITYACTIVATION:
case SC_FIGHTINGSPIRIT: case SC_ABUNDANCE: case SC__SHADOWFORM:
case SC_RECOGNIZEDSPELL:case SC_LEADERSHIP: case SC_GLORYWOUNDS:
case SC_SOULCOLD: case SC_HAWKEYES: case SC_REGENERATION:
case SC_PUSH_CART: case SC_RAISINGDRAGON: case SC_GT_ENERGYGAIN:
case SC_GT_CHANGE: case SC_GT_REVITALIZE: case SC_REFLECTDAMAGE:
case SC_INSPIRATION: case SC_EXEEDBREAK: case SC_FORCEOFVANGUARD:
case SC_BANDING: case SC_DUPLELIGHT: case SC_EXPIATIO:
case SC_LAUDAAGNUS: case SC_LAUDARAMUS: case SC_GATLINGFEVER:
case SC_INCREASING: case SC_ADJUSTMENT: case SC_MADNESSCANCEL:
case SC_ANGEL_PROTECT: case SC_MONSTER_TRANSFORM: case SC_FULL_THROTTLE:
case SC_REBOUND: case SC_TELEKINESIS_INTENSE: case SC_MOONSTAR:
case SC_SUPER_STAR: case SC_ALL_RIDING: case SC_MTF_ASPD:
case SC_MTF_RANGEATK: case SC_MTF_MATK: case SC_MTF_MLEATKED:
case SC_MTF_CRIDAMAGE: case SC_HEAT_BARREL:
case SC_P_ALTER: case SC_E_CHAIN: case SC_C_MARKER:
case SC_B_TRAP: case SC_H_MINE: case SC_STRANGELIGHTS:
case SC_DECORATION_OF_MUSIC: case SC_GN_CARTBOOST: case SC_CHASEWALK2:
case SC_ACTIVE_MONSTER_TRANSFORM: case SC_DORAM_BUF_01: case SC_DORAM_BUF_02:
case SC_SPORE_EXPLOSION:
case SC_NEWMOON: case SC_FLASHKICK: case SC_NOVAEXPLOSING:
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
case SC_HIDING: case SC_CLOAKING: case SC_CHASEWALK:
case SC_CLOAKINGEXCEED: case SC__INVISIBILITY: case SC_UTSUSEMI:
case SC_MTF_ASPD2: case SC_MTF_RANGEATK2: case SC_MTF_MATK2:
case SC_2011RWC_SCROLL: case SC_JP_EVENT04: case SC_MTF_MHP:
case SC_MTF_MSP: case SC_MTF_PUMPKIN: case SC_MTF_HITFLEE:
case SC_ATTHASTE_CASH: case SC_ARMOR_ELEMENT_WATER: case SC_REUSE_REFRESH:
case SC_REUSE_LIMIT_A: case SC_REUSE_LIMIT_B: case SC_REUSE_LIMIT_C:
case SC_REUSE_LIMIT_D: case SC_REUSE_LIMIT_E: case SC_REUSE_LIMIT_F:
case SC_REUSE_LIMIT_G: case SC_REUSE_LIMIT_H: case SC_REUSE_LIMIT_MTF:
case SC_REUSE_LIMIT_ASPD_POTION: case SC_REUSE_MILLENNIUMSHIELD: case SC_REUSE_CRUSHSTRIKE:
case SC_REUSE_STORMBLAST: case SC_ALL_RIDING_REUSE_LIMIT:
case SC_SPRITEMABLE: case SC_BITESCAR: case SC_CRUSHSTRIKE:
case SC_QUEST_BUFF1: case SC_QUEST_BUFF2: case SC_QUEST_BUFF3:
case SC_ARMOR_ELEMENT_EARTH: case SC_ARMOR_ELEMENT_FIRE: case SC_ARMOR_ELEMENT_WIND:
case SC_ENTRY_QUEUE_APPLY_DELAY: case SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT:
case SC_MADOGEAR:
// Clans
case SC_CLAN_INFO:
case SC_SWORDCLAN:
case SC_ARCWANDCLAN:
case SC_GOLDENMACECLAN:
case SC_CROSSBOWCLAN:
case SC_JUMPINGCLAN:
case SC_DAILYSENDMAILCNT:
case SC_WEDDING: case SC_XMAS: case SC_SUMMER:
case SC_DRESSUP: case SC_HANBOK: case SC_OKTOBERFEST:
case SC_LHZ_DUN_N1: case SC_LHZ_DUN_N2: case SC_LHZ_DUN_N3: case SC_LHZ_DUN_N4:
case SC_REUSE_LIMIT_LUXANIMA: case SC_LUXANIMA: case SC_SOULENERGY:
case SC_EP16_2_BUFF_SS: case SC_EP16_2_BUFF_SC: case SC_EP16_2_BUFF_AC:
case SC_EMERGENCY_MOVE: case SC_HOMUN_TIME:
case SC_PACKING_ENVELOPE1: case SC_PACKING_ENVELOPE2: case SC_PACKING_ENVELOPE3:
case SC_PACKING_ENVELOPE4: case SC_PACKING_ENVELOPE5: case SC_PACKING_ENVELOPE6:
case SC_PACKING_ENVELOPE7: case SC_PACKING_ENVELOPE8: case SC_PACKING_ENVELOPE9: case SC_PACKING_ENVELOPE10:
continue;
case SC_WHISTLE:
case SC_ASSNCROS:
case SC_POEMBRAGI:
case SC_APPLEIDUN:
case SC_HUMMING:
case SC_DONTFORGETME:
case SC_FORTUNE:
case SC_SERVICE4U:
if (!battle_config.dispel_song || tsc->data[i]->val4 == 0)
if (it.second->flag[SCF_NODISPELL])
continue;
switch (status) {
// bugreport:4888 these songs may only be dispelled if you're not in their song area anymore
case SC_WHISTLE: case SC_ASSNCROS: case SC_POEMBRAGI:
case SC_APPLEIDUN: case SC_HUMMING: case SC_DONTFORGETME:
case SC_FORTUNE: case SC_SERVICE4U:
if (!battle_config.dispel_song || tsc->data[status]->val4 == 0)
continue; //If in song area don't end it, even if config enabled
break;
case SC_ASSUMPTIO:
@ -9354,8 +9201,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
continue;
break;
}
if(i == SC_BERSERK) tsc->data[i]->val2=0; //Mark a dispelled berserk to avoid setting hp to 100 by setting hp penalty to 0.
status_change_end(bl, (sc_type)i, INVALID_TIMER);
if (i == SC_BERSERK || i == SC_SATURDAYNIGHTFEVER)
tsc->data[status]->val2 = 0; //Mark a dispelled berserk to avoid setting hp to 100 by setting hp penalty to 0.
status_change_end(bl, status, INVALID_TIMER);
}
break;
}
@ -10161,7 +10009,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
break;
}
if (tsc) {
if (tsc->data[status_skill2sc(skill_id)]) { // Allow refreshing an already active soul link.
if (tsc->data[skill_get_sc(skill_id)]) { // Allow refreshing an already active soul link.
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;
} else if (tsc->data[SC_SPIRIT] || tsc->data[SC_SOULGOLEM] || tsc->data[SC_SOULSHADOW] || tsc->data[SC_SOULFALCON] || tsc->data[SC_SOULFAIRY]) { // Soul links from Soul Linker and Soul Reaper skills don't stack.
@ -10190,7 +10038,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
if (tsce) {
if(sd)
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
status_change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,10000,8);
status_change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,10000,SCSTART_NORATEDEF);
status_change_end(bl, SC_SWOO, INVALID_TIMER);
break;
}
@ -10825,106 +10673,32 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
if(!tsc || !tsc->count)
break;
for( i = 0; i < SC_MAX; i++ ) {
if (!tsc->data[i])
//Statuses change that can't be removed by Cleareance
for (const auto &it : status_db) {
sc_type status = static_cast<sc_type>(it.first);
if (!tsc->data[status])
continue;
switch (i) {
case SC_WEIGHT50: case SC_WEIGHT90: case SC_HALLUCINATION:
case SC_STRIPWEAPON: case SC_STRIPSHIELD: case SC_STRIPARMOR:
case SC_STRIPHELM: case SC_CP_WEAPON: case SC_CP_SHIELD:
case SC_CP_ARMOR: case SC_CP_HELM: case SC_COMBO:
case SC_STRFOOD: case SC_AGIFOOD: case SC_VITFOOD:
case SC_INTFOOD: case SC_DEXFOOD: case SC_LUKFOOD:
case SC_HITFOOD: case SC_FLEEFOOD: case SC_BATKFOOD:
case SC_WATKFOOD: case SC_MATKFOOD: case SC_CRIFOOD:
case SC_DANCING: case SC_SPIRIT: case SC_AUTOBERSERK:
case SC_CARTBOOST: case SC_MELTDOWN: case SC_SAFETYWALL:
case SC_SMA: case SC_SPEEDUP0: case SC_NOCHAT:
case SC_ANKLE: case SC_SPIDERWEB: case SC_JAILED:
case SC_ITEMBOOST: case SC_EXPBOOST: case SC_LIFEINSURANCE:
case SC_BOSSMAPINFO: case SC_PNEUMA: case SC_AUTOSPELL:
case SC_INCHITRATE: case SC_INCATKRATE: case SC_NEN:
case SC_READYSTORM: case SC_READYDOWN: case SC_READYTURN:
case SC_READYCOUNTER: case SC_DODGE: case SC_WARM:
/*case SC_SPEEDUP1:*/ case SC_AUTOTRADE: case SC_CRITICALWOUND:
case SC_JEXPBOOST: case SC_INVINCIBLE: case SC_INVINCIBLEOFF:
case SC_HELLPOWER: case SC_MANU_ATK: case SC_MANU_DEF:
case SC_SPL_ATK: case SC_SPL_DEF: case SC_MANU_MATK:
case SC_SPL_MATK: case SC_RICHMANKIM: case SC_ETERNALCHAOS:
case SC_DRUMBATTLE: case SC_NIBELUNGEN: case SC_ROKISWEIL:
case SC_INTOABYSS: case SC_SIEGFRIED: case SC_WHISTLE:
case SC_ASSNCROS: case SC_POEMBRAGI: case SC_APPLEIDUN:
case SC_HUMMING: case SC_DONTFORGETME: case SC_FORTUNE:
case SC_SERVICE4U: case SC_FOOD_STR_CASH: case SC_FOOD_AGI_CASH:
case SC_FOOD_VIT_CASH: case SC_FOOD_DEX_CASH: case SC_FOOD_INT_CASH:
case SC_FOOD_LUK_CASH: case SC_ELECTRICSHOCKER: case SC_BITE:
case SC__STRIPACCESSORY: case SC__ENERVATION: case SC__GROOMY:
case SC__IGNORANCE: case SC__LAZINESS: case SC__UNLUCKY:
case SC__WEAKNESS: case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD:
case SC_MAGNETICFIELD: case SC_MINOR_BBQ: case SC_SIROMA_ICE_TEA:
case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES: case SC_NEUTRALBARRIER_MASTER:
case SC_NEUTRALBARRIER: case SC_STEALTHFIELD_MASTER: case SC_STEALTHFIELD:
case SC_LEADERSHIP: case SC_GLORYWOUNDS: case SC_SOULCOLD:
case SC_HAWKEYES: case SC_REGENERATION: case SC_SEVENWIND:
case SC_MIRACLE: case SC_S_LIFEPOTION: case SC_L_LIFEPOTION:
case SC_INCHEALRATE: case SC_PUSH_CART: case SC_PARTYFLEE:
case SC_RAISINGDRAGON: case SC_GT_REVITALIZE: case SC_GT_ENERGYGAIN:
case SC_GT_CHANGE: case SC_ANGEL_PROTECT: case SC_MONSTER_TRANSFORM:
case SC_FULL_THROTTLE: case SC_REBOUND: case SC_TELEKINESIS_INTENSE:
case SC_MOONSTAR: case SC_SUPER_STAR: case SC_ALL_RIDING:
case SC_MTF_ASPD: case SC_MTF_RANGEATK: case SC_MTF_MATK:
case SC_MTF_MLEATKED: case SC_MTF_CRIDAMAGE: case SC_HEAT_BARREL:
case SC_P_ALTER: case SC_E_CHAIN:
case SC_C_MARKER: case SC_B_TRAP: case SC_H_MINE:
case SC_NEWMOON: case SC_FLASHKICK: case SC_DIMENSION:
case SC_NOVAEXPLOSING:
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:
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
case SC_HIDING: case SC_CLOAKING: case SC_CHASEWALK:
case SC_CLOAKINGEXCEED: case SC__INVISIBILITY: case SC_UTSUSEMI:
case SC_MTF_ASPD2: case SC_MTF_RANGEATK2: case SC_MTF_MATK2:
case SC_2011RWC_SCROLL: case SC_JP_EVENT04: case SC_MTF_MHP:
case SC_MTF_MSP: case SC_MTF_PUMPKIN: case SC_MTF_HITFLEE:
case SC_ATTHASTE_CASH: case SC_REUSE_REFRESH:
case SC_REUSE_LIMIT_A: case SC_REUSE_LIMIT_B: case SC_REUSE_LIMIT_C:
case SC_REUSE_LIMIT_D: case SC_REUSE_LIMIT_E: case SC_REUSE_LIMIT_F:
case SC_REUSE_LIMIT_G: case SC_REUSE_LIMIT_H: case SC_REUSE_LIMIT_MTF:
case SC_REUSE_LIMIT_ASPD_POTION: case SC_REUSE_MILLENNIUMSHIELD: case SC_REUSE_CRUSHSTRIKE:
case SC_REUSE_STORMBLAST: case SC_ALL_RIDING_REUSE_LIMIT:
case SC_SPRITEMABLE: case SC_DORAM_BUF_01: case SC_DORAM_BUF_02:
case SC_QUEST_BUFF1: case SC_QUEST_BUFF2: case SC_QUEST_BUFF3:
case SC_CLAN_INFO: case SC_SWORDCLAN: case SC_ARCWANDCLAN:
case SC_GOLDENMACECLAN: case SC_CROSSBOWCLAN:
case SC_DAILYSENDMAILCNT:
case SC_WEDDING: case SC_XMAS: case SC_SUMMER:
case SC_DRESSUP: case SC_HANBOK: case SC_OKTOBERFEST:
case SC_LHZ_DUN_N1: case SC_LHZ_DUN_N2: case SC_LHZ_DUN_N3: case SC_LHZ_DUN_N4:
case SC_ENTRY_QUEUE_APPLY_DELAY: case SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT:
case SC_REUSE_LIMIT_LUXANIMA: case SC_LUXANIMA: case SC_SOULENERGY:
case SC_EP16_2_BUFF_SS: case SC_EP16_2_BUFF_SC: case SC_EP16_2_BUFF_AC:
case SC_EMERGENCY_MOVE: case SC_MADOGEAR: case SC_HOMUN_TIME:
case SC_PACKING_ENVELOPE1: case SC_PACKING_ENVELOPE2: case SC_PACKING_ENVELOPE3:
case SC_PACKING_ENVELOPE4: case SC_PACKING_ENVELOPE5: case SC_PACKING_ENVELOPE6:
case SC_PACKING_ENVELOPE7: case SC_PACKING_ENVELOPE8: case SC_PACKING_ENVELOPE9: case SC_PACKING_ENVELOPE10:
if (it.second->flag[SCF_NOCLEARANCE])
continue;
case SC_ASSUMPTIO:
if( bl->type == BL_MOB )
continue;
break;
switch (status) {
case SC_WHISTLE: case SC_ASSNCROS: case SC_POEMBRAGI:
case SC_APPLEIDUN: case SC_HUMMING: case SC_DONTFORGETME:
case SC_FORTUNE: case SC_SERVICE4U:
if (!battle_config.dispel_song || tsc->data[status]->val4 == 0)
continue; //If in song area don't end it, even if config enabled
break;
case SC_ASSUMPTIO:
if (bl->type == BL_MOB)
continue;
break;
}
if(i == SC_BERSERK) tsc->data[i]->val2=0; //Mark a dispelled berserk to avoid setting hp to 100 by setting hp penalty to 0.
status_change_end(bl,(sc_type)i,INVALID_TIMER);
if (i == SC_BERSERK || i == SC_SATURDAYNIGHTFEVER)
tsc->data[status]->val2 = 0; //Mark a dispelled berserk to avoid setting hp to 100 by setting hp penalty to 0.
status_change_end(bl,status,INVALID_TIMER);
}
break;
}
@ -11929,7 +11703,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
struct status_change *sc = status_get_sc(&ele->bl);
if( (sc && sc->data[type2]) || (tsc && tsc->data[type]) ) {
elemental_clean_single_effect(ele, skill_id);
status_change_end(src,type,INVALID_TIMER);
status_change_end(bl,type2,INVALID_TIMER);
} else {
clif_skill_nodamage(src,src,skill_id,skill_lv,1);
if (!(skill_id >= EM_EL_FLAMETECHNIC && skill_id <= EM_EL_DEADLY_POISON))
@ -11957,7 +11732,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
clif_skill_nodamage(src,src,skill_id,skill_lv,1);
if( (sc && sc->data[type2]) || (tsc && tsc->data[type]) ) {
elemental_clean_single_effect(ele, skill_id);
status_change_end(bl,type,INVALID_TIMER);
status_change_end(src,type2,INVALID_TIMER);
} else {
// This not heals at the end.
clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, DMG_SINGLE);
@ -13354,9 +13130,8 @@ 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;
type = skill_get_sc(skill_id);
sce = (sc && type != SC_NONE)?sc->data[type]:NULL;
switch (skill_id) { //Skill effect.
case WZ_METEOR:
@ -13746,7 +13521,9 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
// Final heal increased by HPlus.
// Is this the right place for this??? [Rytech]
// Can HPlus also affect SP recovery???
if (sd && sstatus->hplus > 0) {
status_data *sstatus = status_get_status_data(src);
if (sstatus && sstatus->hplus > 0) {
potion_hp += potion_hp * sstatus->hplus / 100;
potion_sp += potion_sp * sstatus->hplus / 100;
}
@ -14283,7 +14060,7 @@ int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char
return 0;
}
if( ( sd->sc.opt1 && sd->sc.opt1 != OPT1_BURNING ) || sd->sc.option&OPTION_HIDE ) {
if( sd->sc.cant.cast ) {
skill_failed(sd);
return 0;
}
@ -15134,7 +14911,7 @@ static int skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, t_
if (sc && sc->data[SC_HOVERING] && skill->inf2[INF2_IGNOREHOVERING])
return 0; // Under Hovering characters are immune to select trap and ground target skills.
type = status_skill2sc(sg->skill_id);
type = skill_get_sc(sg->skill_id);
sce = (sc && type != SC_NONE) ? sc->data[type] : NULL;
skill_id = sg->skill_id; //In case the group is deleted, we need to return the correct skill id, still.
switch (sg->unit_id) {
@ -15463,7 +15240,7 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, t_t
tsc = status_get_sc(bl);
sc = status_get_sc(ss);
tstatus = status_get_status_data(bl);
type = status_skill2sc(sg->skill_id);
type = skill_get_sc(sg->skill_id);
skill_id = sg->skill_id;
std::bitset<INF2_MAX> inf2 = skill_db.find(skill_id)->inf2;
@ -16234,8 +16011,8 @@ int skill_unit_onout(struct skill_unit *src, struct block_list *bl, t_tick tick)
return 0;
sc = status_get_sc(bl);
type = status_skill2sc(sg->skill_id);
sce = (sc && type != -1)?sc->data[type]:NULL;
type = skill_get_sc(sg->skill_id);
sce = (sc && type != SC_NONE)?sc->data[type]:NULL;
if (bl->prev == NULL || (status_isdead(bl) && sg->unit_id != UNT_ANKLESNARE)) //Need to delete the trap if the source died.
return 0;
@ -16265,8 +16042,8 @@ int skill_unit_onout(struct skill_unit *src, struct block_list *bl, t_tick tick)
{
for(uint16 i = BA_WHISTLE; i <= DC_SERVICEFORYOU; i++) {
if(skill_get_inf2(i, INF2_ISSONG)) {
type = status_skill2sc(i);
sce = (sc && type != -1)?sc->data[type]:NULL;
type = skill_get_sc(i);
sce = (sc && type != SC_NONE)?sc->data[type]:NULL;
if(sce)
return i;
}
@ -16302,8 +16079,8 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, t_tick tick)
if (sc && !sc->count)
sc = NULL;
type = status_skill2sc(skill_id);
sce = (sc && type != -1)?sc->data[type]:NULL;
type = skill_get_sc(skill_id);
sce = (sc && type != SC_NONE)?sc->data[type]:NULL;
switch (skill_id)
{
@ -16368,8 +16145,8 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, t_tick tick)
{
for(uint16 i = BA_WHISTLE; i <= DC_SERVICEFORYOU; i++){
if(skill_get_inf2(i, INF2_ISSONG)){
type = status_skill2sc(i);
sce = (sc && type != -1)?sc->data[type]:NULL;
type = skill_get_sc(i);
sce = (sc && type != SC_NONE)?sc->data[type]:NULL;
if(sce && !sce->val4){ //We don't want dissonance updating this anymore
delete_timer(sce->timer, status_change_timer);
sce->val4 = 1; //Store the fact that this is a "reduced" duration effect.
@ -16560,7 +16337,7 @@ int skill_check_condition_char_sub (struct block_list *bl, va_list ap)
if(pc_isdead(tsd))
return 0;
if (tsd->sc.data[SC_SILENCE] || ( tsd->sc.opt1 && tsd->sc.opt1 != OPT1_BURNING ))
if (tsd->sc.cant.cast)
return 0;
if( is_chorus ) {
@ -20299,10 +20076,9 @@ int skill_delunit(struct skill_unit* unit)
case SC_ESCAPE:
{
struct block_list* target = map_id2bl(group->val2);
enum sc_type type = status_skill2sc(group->skill_id);
if( target )
status_change_end(target, type, INVALID_TIMER);
status_change_end(target, SC_ANKLE, INVALID_TIMER);
}
break;
case WZ_ICEWALL:
@ -20529,15 +20305,21 @@ int skill_delunitgroup_(std::shared_ptr<s_skill_unit_group> group, const char* f
break;
case SG_SUN_WARM:
case SG_MOON_WARM:
case SG_STAR_WARM:
case LG_BANDING:
{
case SG_STAR_WARM: {
status_change *sc = status_get_sc(src);
sc_type type = status_skill2sc(group->skill_id);
if (sc && sc->data[type]) {
sc->data[type]->val4 = 0;
status_change_end(src, type, INVALID_TIMER);
if (sc && sc->data[SC_WARM]) {
sc->data[SC_WARM]->val4 = 0;
status_change_end(src, SC_WARM, INVALID_TIMER);
}
}
break;
case LG_BANDING: {
status_change *sc = status_get_sc(src);
if (sc && sc->data[SC_BANDING]) {
sc->data[SC_BANDING]->val4 = 0;
status_change_end(src, SC_BANDING, INVALID_TIMER);
}
}
break;
@ -22118,12 +21900,11 @@ void skill_toggle_magicpower(struct block_list *bl, uint16 skill_id)
status_change_end(bl, SC_MAGICPOWER, INVALID_TIMER);
} else {
sc->data[SC_MAGICPOWER]->val4 = 1;
status_calc_bl(bl, status_sc2scb_flag(SC_MAGICPOWER));
status_calc_bl(bl, status_db.getCalcFlag(SC_MAGICPOWER));
if(bl->type == BL_PC){// update current display.
clif_updatestatus(((TBL_PC *)bl),SP_MATK1);
clif_updatestatus(((TBL_PC *)bl),SP_MATK2);
}
}
}
}
@ -23138,6 +22919,10 @@ int skill_block_check(struct block_list *bl, sc_type type , uint16 skill_id) {
*/
int skill_disable_check(struct status_change *sc, uint16 skill_id)
{
enum sc_type type = skill_get_sc(skill_id);
if (type <= SC_NONE || type >= SC_MAX)
return 0;
switch( skill_id ) { //HP & SP Consumption Check
case BS_MAXIMIZE:
case NV_TRICKDEAD:
@ -23168,11 +22953,11 @@ int skill_disable_check(struct status_change *sc, uint16 skill_id)
case SP_SOULCOLLECT:
case IG_GUARD_STANCE:
case IG_ATTACK_STANCE:
if( sc->data[status_skill2sc(skill_id)] )
if( sc->data[type] )
return 1;
break;
// These 2 skills contain a master and are not correctly pulled using skill2sc
// These 2 skills contain a master and are not correctly pulled using skill_get_sc
case NC_NEUTRALBARRIER:
if( sc->data[SC_NEUTRALBARRIER_MASTER] )
return 1;
@ -24226,6 +24011,31 @@ uint64 SkillDatabase::parseBodyNode(const YAML::Node &node) {
}
}
if (this->nodeExists(node, "Status")) {
std::string status;
if (!this->asString(node, "Status", status))
return 0;
std::string status_constant = "SC_" + status;
int64 constant;
if (!script_get_constant(status_constant.c_str(), &constant)) {
this->invalidWarning(node["Status"], "Status %s is invalid.\n", status.c_str());
return 0;
}
if (constant < SC_NONE || constant >= SC_MAX) {
this->invalidWarning(node["Status"], "Status %s is unknown. Defaulting to SC_NONE.\n", status.c_str());
constant = SC_NONE;
}
skill->sc = static_cast<sc_type>(constant);
} else {
if (!exists)
skill->sc = SC_NONE;
}
if (!exists) {
this->put(skill_id, skill);
this->skilldb_id2idx[skill_id] = this->skill_num;
@ -24722,15 +24532,8 @@ static bool skill_parse_row_skilldamage(char* split[], int columns, int current)
return true;
}
/*===============================
* DB reading.
* skill_db.yml
* skill_nocast_db.txt
* produce_db.txt
* create_arrow_db.txt
*------------------------------*/
static void skill_readdb(void)
{
/** Reads skill database files */
static void skill_readdb(void) {
int i;
const char* dbsubpath[] = {
"",
@ -24757,6 +24560,7 @@ static void skill_readdb(void)
safesnprintf(dbsubpath1,n1,"%s%s",db_path,dbsubpath[i]);
safesnprintf(dbsubpath2,n1,"%s%s",db_path,dbsubpath[i]);
}
sv_readdb(dbsubpath2, "skill_nocast_db.txt" , ',', 2, 2, -1, skill_parse_row_nocastdb, i > 0);
sv_readdb(dbsubpath2, "produce_db.txt" , ',', 5, 5+2*MAX_PRODUCE_RESOURCE, MAX_SKILL_PRODUCE_DB, skill_parse_row_producedb, i > 0);
@ -24784,7 +24588,6 @@ void skill_reload (void) {
skill_arrow_db.clear();
skill_readdb();
initChangeTables(); // Re-init Status Change tables
/* lets update all players skill tree : so that if any skill modes were changed they're properly updated */
s_mapiterator *iter = mapit_getallusers();

View File

@ -306,6 +306,7 @@ struct s_skill_db {
int32 abra_probability[MAX_SKILL_LEVEL];
s_skill_spellbook reading_spellbook;
uint16 improvisedsong_rate;
sc_type sc; ///< Default SC for skill
};
class SkillDatabase : public TypesafeCachedYamlDatabase <uint16, s_skill_db> {
@ -2634,6 +2635,7 @@ int skill_is_combo(uint16 skill_id);
void skill_combo_toggle_inf(struct block_list* bl, uint16 skill_id, int inf);
void skill_combo(struct block_list* src,struct block_list *dsrc, struct block_list *bl, uint16 skill_id, uint16 skill_lv, t_tick tick);
enum sc_type skill_get_sc(int16 skill_id);
void skill_reveal_trap_inarea(struct block_list *src, int range, int x, int y);
int skill_get_time3(struct map_data *mapdata, uint16 skill_id, uint16 skill_lv);

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,10 @@
#ifndef STATUS_HPP
#define STATUS_HPP
#include <algorithm>
#include <bitset>
#include <memory>
#include <unordered_map>
#include <vector>
#include "../common/database.hpp"
@ -11,6 +15,7 @@
#include "../common/timer.hpp"
#include "map.hpp"
#include "script.hpp"
enum e_race2 : uint8;
struct block_list;
@ -246,7 +251,7 @@ enum sc_type : int16 {
SC_ARMOR,
SC_ARMOR_ELEMENT_WATER,
SC_NOCHAT,
SC_BABY,
SC_PROTECTEXP,
SC_AURABLADE,
SC_PARRYING,
SC_CONCENTRATION, //110
@ -1175,7 +1180,7 @@ enum sc_type : int16 {
};
/// Official status change ids, used to display status icons on the client.
enum efst_types : short{
enum efst_type : short{
/// Do not modify code below this, until the end of the API hook, since it will be automatically generated again
/// @APIHOOK_START(EFST_ENUM)
EFST_BLANK = -1,
@ -2552,7 +2557,8 @@ extern short current_equip_opt_index;
//who were not on your field of sight when it happened)
///opt1: (BODYSTATE_*) Non stackable status changes.
enum sc_opt1 {
enum e_sc_opt1 : uint16 {
OPT1_NONE = 0,
OPT1_STONE = 1, //Petrified
OPT1_FREEZE,
OPT1_STUN,
@ -2561,10 +2567,12 @@ enum sc_opt1 {
OPT1_STONEWAIT = 6, //Petrifying
OPT1_BURNING,
OPT1_IMPRISON,
OPT1_MAX
};
///opt2: (HEALTHSTATE_*) Stackable status changes.
enum sc_opt2 {
enum e_sc_opt2 : uint16 {
OPT2_NONE = 0x0,
OPT2_POISON = 0x0001,
OPT2_CURSE = 0x0002,
OPT2_SILENCE = 0x0004,
@ -2574,11 +2582,12 @@ enum sc_opt2 {
OPT2_BLEEDING = 0x0040,
OPT2_DPOISON = 0x0080,
OPT2_FEAR = 0x0100,
OPT2_MAX
};
///opt3: (SHOW_EFST_*)
enum sc_opt3 {
OPT3_NORMAL = 0x00000000,
enum e_sc_opt3 : uint32 {
OPT3_NORMAL = 0x0,
OPT3_QUICKEN = 0x00000001,
OPT3_OVERTHRUST = 0x00000002,
OPT3_ENERGYCOAT = 0x00000004,
@ -2597,11 +2606,12 @@ enum sc_opt3 {
OPT3_SOULLINK = 0x00008000,
OPT3_UNDEAD = 0x00010000,
OPT3_CONTRACT = 0x00020000,
OPT3_MAX
};
///Option (EFFECTSTATE_*)
enum e_option {
OPTION_NOTHING = 0x00000000,
enum e_option : uint32 {
OPTION_NOTHING = 0x0,
OPTION_SIGHT = 0x00000001,
OPTION_HIDE = 0x00000002,
OPTION_CLOAK = 0x00000004,
@ -2632,6 +2642,7 @@ enum e_option {
OPTION_HANBOK = 0x08000000,
OPTION_OKTOBERFEST = 0x10000000,
OPTION_SUMMER2 = 0x20000000,
OPTION_MAX,
// compound constant for older carts
OPTION_CART = OPTION_CART1|OPTION_CART2|OPTION_CART3|OPTION_CART4|OPTION_CART5,
@ -2641,15 +2652,6 @@ enum e_option {
OPTION_COSTUME = OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK|OPTION_OKTOBERFEST|OPTION_SUMMER2,
};
enum e_option_change_flag : uint16 {
OCF_NONE = 0x0,
OCF_SEND_OPTION = 0x1,
OCF_ONTOUCH = 0x2,
OCF_UNIT_MOVE = 0x4,
OCF_NON_PLAYER = 0x8,
OCF_SEND_LOOK = 0x10,
};
///Defines for the manner system [Skotlex]
enum manner_flags
{
@ -2661,23 +2663,38 @@ enum manner_flags
};
/// Status Change State Flags
enum scs_flag {
SCS_NOMOVECOND = 0x00000001, ///< cond flag for nomove
SCS_NOMOVE = 0x00000002, ///< unit unable to move
SCS_NOPICKITEMCOND = 0x00000004, ///< cond flag for nopickitem
SCS_NOPICKITEM = 0x00000008, ///< player unable to pick up items
SCS_NODROPITEMCOND = 0x00000010, ///< cond flag for nodropitem
SCS_NODROPITEM = 0x00000020, ///< player unable to drop items
SCS_NOCASTCOND = 0x00000040, ///< cond flag for nocast
SCS_NOCAST = 0x00000080, ///< unit unable to cast skills
SCS_NOCHAT = 0x00000100, ///< unit can't talk
SCS_NOCHATCOND = 0x00000200, ///< cond flag for notalk
enum e_scs_flag : uint8 {
SCS_NONE = 0,
SCS_NOMOVECOND, ///< cond flag for SCS_NOMOVE
SCS_NOMOVE, ///< unit unable to move
SCS_NOPICKITEMCOND, ///< cond flag for SCS_NOPICKITEM
SCS_NOPICKITEM, ///< player unable to pick up items
SCS_NODROPITEMCOND, ///< cond flag for SCS_NODROPITEM
SCS_NODROPITEM, ///< player unable to drop items
SCS_NOCASTCOND, ///< cond flag for SCS_NOCAST
SCS_NOCAST, ///< unit unable to cast skills
SCS_NOCHAT, ///< unit can't talk
SCS_NOCHATCOND, ///< cond flag for SCS_NOCHAT
SCS_NOEQUIPITEM, ///< player can't puts on equip
SCS_NOEQUIPITEMCOND, ///< cond flag for SCS_NOEQUIPITEM
SCS_NOUNEQUIPITEM, ///< player can't puts off equip
SCS_NOUNEQUIPITEMCOND, ///< cond flag for SCS_NOUNEQUIPITEM
SCS_NOCONSUMEITEM, ///< player can't consumes equip
SCS_NOCONSUMEITEMCOND, ///< cond flag for SCS_NOCONSUMEITEM
SCS_NOATTACK, ///< unit can't attack
SCS_NOATTACKCOND, ///< cond flag for SCS_NOATTACK
SCS_NOWARP, ///< unit can't warp
SCS_NOWARPCOND, ///< cond flag for SCS_NOWARP
SCS_NODEATHPENALTY, ///< player doesn't experience EXP loss
SCS_NODEATHPENALTYCOND, ///< cond flag for SCS_NODEATHPENALTYCOND
SCS_NOINTERACT, ///< player can't sit/stand/talk to NPC
SCS_NOINTERACTCOND, ///< cond flag for SCS_NOINTERACT
SCS_MAX
};
///Define flags for the status_calc_bl function. [Skotlex]
enum scb_flag : uint64
{ // Main Flags
SCB_NONE = 0x00000000,
enum e_scb_flag : uint64 {
SCB_NONE = 0x0,
SCB_BASE = 0x00000001,
SCB_MAXHP = 0x00000002,
SCB_MAXSP = 0x00000004,
@ -2729,19 +2746,20 @@ enum scb_flag : uint64
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.
SCB_BATTLE = 0x07FFFFFFFFFE, // All except BASE and extra flags.
SCB_ALL = 0x07FFFFFFFFFF, // All except extra flags.
SCB_MAX = 0x0FFFFFFFFFFF,
};
enum e_status_calc_opt {
enum e_status_calc_opt : uint8 {
SCO_NONE = 0x0,
SCO_FIRST = 0x1, ///< Trigger the calculations that should take place only onspawn/once, process base status initialization code
SCO_FORCE = 0x2, ///< Only relevant to BL_PC types, ensures call bypasses the queue caused by delayed damage
};
/// Flags for status_change_start and status_get_sc_def
enum e_status_change_start_flags {
SCSTART_NONE = 0x00,
enum e_status_change_start_flags : int64 {
SCSTART_NONE = 0x0,
SCSTART_NOAVOID = 0x01, /// Cannot be avoided (it has to start)
SCSTART_NOTICKDEF = 0x02, /// Tick should not be reduced (by statuses or bonuses)
SCSTART_LOADED = 0x04, /// When sc_data loaded (fetched from table), no values (val1 ~ val4) have to be altered/recalculate
@ -2750,7 +2768,7 @@ enum e_status_change_start_flags {
};
/// Enum for status_change_clear_buffs
enum e_status_change_clear_buffs_flags {
enum e_status_change_clear_buffs_flags : int64 {
SCCB_BUFFS = 0x01,
SCCB_DEBUFFS = 0x02,
SCCB_REFRESH = 0x04,
@ -2759,7 +2777,7 @@ enum e_status_change_clear_buffs_flags {
};
///Enum for bonus_script's flag [Cydh]
enum e_bonus_script_flags {
enum e_bonus_script_flags : uint32 {
BSF_REM_ON_DEAD = 0x001, ///< Removed when dead
BSF_REM_ON_DISPELL = 0x002, ///< Removed by Dispell
BSF_REM_ON_CLEARANCE = 0x004, ///< Removed by Clearance
@ -2787,6 +2805,102 @@ enum e_status_bonus {
STATUS_BONUS_RATE = 1,
};
///Enum of Status Change Flags [Cydh]
enum e_status_change_flag : uint16 {
SCF_NONE = 0,
SCF_BLEFFECT,
SCF_DISPLAYPC,
SCF_NOCLEARBUFF,
SCF_NOREMOVEONDEAD,
SCF_NODISPELL,
SCF_NOCLEARANCE,
SCF_NOBANISHINGBUSTER,
SCF_NOSAVE,
SCF_NOSAVEINFINITE,
SCF_REMOVEONDAMAGED,
SCF_REMOVEONREFRESH,
SCF_REMOVEONLUXANIMA,
SCF_STOPATTACKING,
SCF_STOPCASTING,
SCF_STOPWALKING,
SCF_BOSSRESIST,
SCF_MVPRESIST,
SCF_SETSTAND,
SCF_FAILEDMADO,
SCF_DEBUFF,
SCF_REMOVEONCHANGEMAP,
SCF_REMOVEONMAPWARP,
SCF_REMOVECHEMICALPROTECT,
SCF_OVERLAPFAIL,
SCF_OVERLAPIGNORELEVEL,
SCF_SENDOPTION,
SCF_ONTOUCH,
SCF_UNITMOVE,
SCF_NONPLAYER,
SCF_SENDLOOK,
SCF_DISPLAYNPC,
SCF_REQUIREWEAPON,
SCF_REQUIRESHIELD,
SCF_MOBLOSETARGET,
SCF_REMOVEELEMENTALOPTION,
SCF_SUPERNOVICEANGEL,
SCF_TAEKWONANGEL,
SCF_MADOCANCEL,
SCF_MADOENDCANCEL,
SCF_RESTARTONMAPWARP,
SCF_SPREADEFFECT,
SCF_SENDVAL1,
SCF_SENDVAL2,
SCF_SENDVAL3,
SCF_MAX
};
/// Struct of SC configs [Cydh]
struct s_status_change_db {
sc_type type; ///< SC_
efst_type icon; ///< EFST_
std::bitset<SCS_MAX> state; ///< SCS_
uint64 calc_flag; ///< SCB_ flags
uint16 opt1; ///< OPT1_
uint16 opt2; ///< OPT2_
uint32 opt3; ///< OPT3_
uint32 look; ///, OPTION_ Changelook
std::bitset<SCF_MAX> flag; ///< SCF_ Flags, enum e_status_change_flag
bool display; ///< Display status effect/icon (for certain state)
uint16 skill_id; ///< Associated skill for (addeff) duration lookups
std::vector<sc_type> end; ///< List of SC that will be ended when this SC is activated
std::vector<sc_type> fail; ///< List of SC that causing this SC cannot be activated
bool end_return; ///< After SC ends the SC from end list, it does nothing
t_tick min_duration; ///< Minimum duration effect (after all status reduction)
uint16 min_rate; ///< Minimum rate to be applied (after all status reduction)
};
class StatusDatabase : public TypesafeCachedYamlDatabase<uint16, s_status_change_db> {
public:
StatusDatabase() : TypesafeCachedYamlDatabase("STATUS_DB", 1) {
}
const std::string getDefaultLocation() override;
uint64 parseBodyNode(const YAML::Node &node) override;
void loadingFinished() override;
// Determine who will receive a clif_status_change packet for effects that require one to display correctly
uint16 StatusRelevantBLTypes[EFST_MAX];
// Extras
efst_type getIcon(sc_type type);
uint64 getCalcFlag(sc_type type);
std::vector<sc_type> getEnd(sc_type type);
uint16 getSkill(sc_type type);
bool hasSCF(status_change *sc, e_status_change_flag flag);
void removeByStatusFlag(block_list *bl, std::vector<e_status_change_flag> flag);
void changeSkillTree(map_session_data *sd, int32 class_ = 0);
bool validateStatus(sc_type type);
};
extern StatusDatabase status_db;
/// Enum for status_calc_weight and status_calc_cart_weight
enum e_status_calc_weight_opt {
CALCWT_NONE = 0x0,
@ -2824,14 +2938,6 @@ struct weapon_atk {
#endif
};
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 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
extern unsigned int StatusDisplayType[SC_MAX];
///For holding basic status (which can be modified by status changes)
struct status_data {
unsigned int
@ -2938,11 +3044,18 @@ struct status_change {
unsigned char count;
//! TODO: See if it is possible to implement the following SC's without requiring extra parameters while the SC is inactive.
struct {
unsigned char move;
unsigned char pickup;
unsigned char drop;
unsigned char cast;
unsigned char chat;
uint8 move;
uint8 pickup;
uint8 drop;
uint8 cast;
uint8 chat;
uint8 equip;
uint8 unequip;
uint8 consume;
uint8 attack;
uint8 warp;
uint8 deathpenalty;
uint8 interact;
} cant;/* status change state flags */
//int sg_id; //ID of the previous Storm gust that hit you
short comet_x, comet_y; // Point where src casted Comet - required to calculate damage from this point
@ -2955,25 +3068,6 @@ struct status_change {
struct status_change_entry *data[SC_MAX];
};
/// Statuses that are cancelled/disabled while on Madogear
static const std::vector<sc_type> mado_statuses = {
SC_LOUD,
SC_CARTBOOST,
SC_MELTDOWN,
SC_ADRENALINE,
SC_ADRENALINE2,
SC_WEAPONPERFECTION,
SC_MAXIMIZEPOWER,
SC_OVERTHRUST,
SC_MAXOVERTHRUST
};
// for looking up associated data
sc_type status_skill2sc(int skill);
int status_sc2skill(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, 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 );
@ -3123,7 +3217,7 @@ int status_change_clear(struct block_list* bl, int type);
void status_change_clear_buffs(struct block_list* bl, uint8 type);
void status_change_clear_onChangeMap(struct block_list *bl, struct status_change *sc);
#define status_calc_bl(bl, flag) status_calc_bl_(bl, (enum scb_flag)(flag), SCO_NONE)
#define status_calc_bl(bl, flag) status_calc_bl_(bl, flag, SCO_NONE)
#define status_calc_mob(md, opt) status_calc_bl_(&(md)->bl, SCB_ALL, opt)
#define status_calc_pet(pd, opt) status_calc_bl_(&(pd)->bl, SCB_ALL, opt)
#define status_calc_pc(sd, opt) status_calc_bl_(&(sd)->bl, SCB_ALL, opt)
@ -3134,25 +3228,26 @@ void status_change_clear_onChangeMap(struct block_list *bl, struct status_change
bool status_calc_weight(struct map_session_data *sd, enum e_status_calc_weight_opt flag);
bool status_calc_cart_weight(struct map_session_data *sd, enum e_status_calc_weight_opt flag);
void status_calc_bl_(struct block_list *bl, enum scb_flag flag, enum e_status_calc_opt opt);
int status_calc_mob_(struct mob_data* md, enum e_status_calc_opt opt);
void status_calc_pet_(struct pet_data* pd, enum e_status_calc_opt opt);
int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt);
int status_calc_homunculus_(struct homun_data *hd, enum e_status_calc_opt opt);
int status_calc_mercenary_(s_mercenary_data *md, e_status_calc_opt opt);
int status_calc_elemental_(s_elemental_data *ed, e_status_calc_opt opt);
int status_calc_npc_(struct npc_data *nd, enum e_status_calc_opt opt);
void status_calc_bl_(struct block_list *bl, uint64 flag, uint8 opt);
int status_calc_mob_(struct mob_data* md, uint8 opt);
void status_calc_pet_(struct pet_data* pd, uint8 opt);
int status_calc_pc_(struct map_session_data* sd, uint8 opt);
int status_calc_homunculus_(struct homun_data *hd, uint8 opt);
int status_calc_mercenary_(s_mercenary_data *md, uint8 opt);
int status_calc_elemental_(s_elemental_data *ed, uint8 opt);
int status_calc_npc_(struct npc_data *nd, uint8 opt);
void status_calc_misc(struct block_list *bl, struct status_data *status, int level);
void status_calc_regen(struct block_list *bl, struct status_data *status, struct regen_data *regen);
void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, struct status_change *sc);
void status_calc_state(struct block_list *bl, struct status_change *sc, std::bitset<SCS_MAX> flag, bool start);
void status_calc_slave_mode(struct mob_data *md, struct mob_data *mmd);
bool status_check_skilluse(struct block_list *src, struct block_list *target, uint16 skill_id, int flag);
int status_check_visibility(struct block_list *src, struct block_list *target);
int status_change_spread(struct block_list *src, struct block_list *bl, bool type);
int status_change_spread(block_list *src, block_list *bl);
#ifndef RENEWAL
unsigned short status_base_matk_min(const struct status_data* status);
@ -3167,9 +3262,11 @@ unsigned short status_base_matk_max(struct block_list *bl, const struct status_d
unsigned short status_base_atk(const struct block_list *bl, const struct status_data *status, int level);
void initChangeTables(void);
int status_readdb( bool reload = false );
int do_init_status(void);
// Status changes accessors for StatusChange database
uint16 status_efst_get_bl_type(enum efst_type efst);
void status_readdb( bool reload = false );
void do_init_status(void);
void do_final_status(void);
#endif /* STATUS_HPP */

View File

@ -1449,9 +1449,9 @@ int unit_is_walking(struct block_list *bl)
* Some statuses are still checked here due too specific variables
* @author [Skotlex]
* @param bl: Object to check
* @return Can move(1); Can't move(0)
* @return True - can move; False - can't move
*/
int unit_can_move(struct block_list *bl) {
bool unit_can_move(struct block_list *bl) {
struct map_session_data *sd;
struct unit_data *ud;
struct status_change *sc;
@ -1463,37 +1463,20 @@ int unit_can_move(struct block_list *bl) {
sd = BL_CAST(BL_PC, bl);
if (!ud)
return 0;
return false;
if (ud->skilltimer != INVALID_TIMER && ud->skill_id != LG_EXEEDBREAK && (!sd || !pc_checkskill(sd, SA_FREECAST) || skill_get_inf2(ud->skill_id, INF2_ISGUILD)))
return 0; // Prevent moving while casting
return false; // Prevent moving while casting
if (DIFF_TICK(ud->canmove_tick, gettick()) > 0)
return 0;
return false;
if ((sd && (pc_issit(sd) || sd->state.vending || sd->state.buyingstore || (sd->state.block_action & PCBLOCK_MOVE) || sd->state.mail_writing)) || ud->state.blockedmove)
return 0; // Can't move
return false; // Can't move
// Status changes that block movement
if (sc) {
if( sc->cant.move // status placed here are ones that cannot be cached by sc->cant.move for they depend on other conditions other than their availability
|| sc->data[SC_SPIDERWEB]
|| (sc->data[SC_DANCING] && sc->data[SC_DANCING]->val4 && (
#ifndef RENEWAL
!sc->data[SC_LONGING] ||
#endif
(sc->data[SC_DANCING]->val1&0xFFFF) == CG_MOONLIT ||
(sc->data[SC_DANCING]->val1&0xFFFF) == CG_HERMODE
) )
)
return 0;
if (sc->opt1 > 0 && sc->opt1 != OPT1_STONEWAIT && sc->opt1 != OPT1_BURNING)
return 0;
if ((sc->option & OPTION_HIDE) && (!sd || pc_checkskill(sd, RG_TUNNELDRIVE) <= 0))
return 0;
}
if (sc && sc->cant.move)
return false;
// Icewall walk block special trapped monster mode
if(bl->type == BL_MOB) {
@ -1501,11 +1484,11 @@ int unit_can_move(struct block_list *bl) {
if(md && ((status_has_mode(&md->status,MD_STATUSIMMUNE) && battle_config.boss_icewall_walk_block == 1 && map_getcell(bl->m,bl->x,bl->y,CELL_CHKICEWALL))
|| (!status_has_mode(&md->status,MD_STATUSIMMUNE) && battle_config.mob_icewall_walk_block == 1 && map_getcell(bl->m,bl->x,bl->y,CELL_CHKICEWALL)))) {
md->walktoxy_fail_count = 1; //Make sure rudeattacked skills are invoked
return 0;
return false;
}
}
return 1;
return true;
}
/**
@ -1520,11 +1503,9 @@ TIMER_FUNC(unit_resume_running){
TBL_PC *sd = map_id2sd(id);
if (sd && pc_isridingwug(sd))
clif_skill_nodamage(ud->bl,ud->bl,RA_WUGDASH,ud->skill_lv,
sc_start4(ud->bl,ud->bl,status_skill2sc(RA_WUGDASH),100,ud->skill_lv,unit_getdir(ud->bl),0,0,0));
clif_skill_nodamage(ud->bl,ud->bl,RA_WUGDASH,ud->skill_lv,sc_start4(ud->bl,ud->bl,SC_WUGDASH,100,ud->skill_lv,unit_getdir(ud->bl),0,0,0));
else
clif_skill_nodamage(ud->bl,ud->bl,TK_RUN,ud->skill_lv,
sc_start4(ud->bl,ud->bl,status_skill2sc(TK_RUN),100,ud->skill_lv,unit_getdir(ud->bl),0,0,0));
clif_skill_nodamage(ud->bl,ud->bl,TK_RUN,ud->skill_lv,sc_start4(ud->bl,ud->bl,SC_RUN,100,ud->skill_lv,unit_getdir(ud->bl),0,0,0));
if (sd)
clif_walkok(sd);
@ -2404,23 +2385,6 @@ int unit_unattackable(struct block_list *bl)
return 0;
}
/**
* Checks if the unit can attack, returns yes if so.
*/
bool unit_can_attack(struct block_list *src, int target_id)
{
struct status_change *sc = status_get_sc(src);
if( sc != NULL ) {
if( sc->data[SC__MANHOLE] )
return false;
}
if( src->type == BL_PC )
return pc_can_attack(BL_CAST(BL_PC, src), target_id);
return true;
}
/**
* Requests a unit to attack a target
* @param src: Object initiating attack
@ -2723,7 +2687,7 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, t_tick tick)
#ifdef OFFICIAL_WALKPATH
|| !path_search_long(NULL, src->m, src->x, src->y, target->x, target->y, CELL_CHKWALL)
#endif
|| (sd && !pc_can_attack(sd, target->id)) )
|| !unit_can_attack(src, target->id) )
return 0; // Can't attack under these conditions
if( src->m != target->m ) {
@ -2870,6 +2834,35 @@ static TIMER_FUNC(unit_attack_timer){
return 0;
}
/**
* Determines whether a player can attack based on status changes
* Why not use status_check_skilluse?
* "src MAY be null to indicate we shouldn't check it, this is a ground-based skill attack."
* Even ground-based attacks should be blocked by these statuses
* Called from unit_attack and unit_attack_timer_sub
* @retval true Can attack
**/
bool unit_can_attack(struct block_list *bl, int target_id) {
nullpo_retr(false, bl);
if (bl->type == BL_PC) {
map_session_data *sd = ((TBL_PC *)bl);
if (sd && (sd->state.block_action & PCBLOCK_ATTACK))
return false;
}
struct status_change *sc;
if (!(sc = status_get_sc(bl)))
return true;
if (sc->cant.attack || (sc->data[SC_VOICEOFSIREN] && sc->data[SC_VOICEOFSIREN]->val2 == target_id))
return false;
return true;
}
/**
* Cancels a skill's cast
* @param bl: Object to cancel cast
@ -3059,50 +3052,20 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file,
ud->attackabletime = ud->canmove_tick /*= ud->canact_tick*/ = gettick();
if(sc && sc->count ) { // map-change/warp dispells.
status_change_end(bl, SC_BLADESTOP, INVALID_TIMER);
#ifdef RENEWAL
status_change_end(bl, SC_BASILICA_CELL, INVALID_TIMER);
#else
status_change_end(bl, SC_BASILICA, INVALID_TIMER);
#endif
status_change_end(bl, SC_ANKLE, INVALID_TIMER);
status_change_end(bl, SC_TRICKDEAD, INVALID_TIMER);
status_change_end(bl, SC_BLADESTOP_WAIT, INVALID_TIMER);
status_change_end(bl, SC_RUN, INVALID_TIMER);
status_change_end(bl, SC_DANCING, INVALID_TIMER);
status_change_end(bl, SC_WARM, INVALID_TIMER);
status_change_end(bl, SC_DEVOTION, INVALID_TIMER);
status_change_end(bl, SC_MARIONETTE, INVALID_TIMER);
status_change_end(bl, SC_MARIONETTE2, INVALID_TIMER);
status_change_end(bl, SC_CLOSECONFINE, INVALID_TIMER);
status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER);
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);
if (sc->cant.warp)
return 0;
status_db.removeByStatusFlag(bl, { SCF_REMOVEONCHANGEMAP });
// Ensure the bl is a PC; if so, we'll handle the removal of cloaking and cloaking exceed later
if ( bl->type != BL_PC ) {
status_change_end(bl, SC_CLOAKING, INVALID_TIMER);
status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
}
status_change_end(bl, SC_CHASEWALK, INVALID_TIMER);
if (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF)
status_change_end(bl, SC_GOSPEL, INVALID_TIMER);
if (sc->data[SC_PROVOKE] && sc->data[SC_PROVOKE]->timer == INVALID_TIMER)
if (sc->data[SC_PROVOKE] && sc->data[SC_PROVOKE]->val4 == 1)
status_change_end(bl, SC_PROVOKE, INVALID_TIMER); //End infinite provoke to prevent exploit
status_change_end(bl, SC_CHANGE, INVALID_TIMER);
status_change_end(bl, SC_STOP, INVALID_TIMER);
status_change_end(bl, SC_WUGDASH, INVALID_TIMER);
status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER);
status_change_end(bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER);
status_change_end(bl, SC_STEALTHFIELD_MASTER, INVALID_TIMER);
status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER);
status_change_end(bl, SC__MANHOLE, INVALID_TIMER);
status_change_end(bl, SC_VACUUM_EXTREME, INVALID_TIMER);
status_change_end(bl, SC_NEWMOON, INVALID_TIMER);
status_change_end(bl, SC_CURSEDCIRCLE_ATKER, INVALID_TIMER); // callme before warp
status_change_end(bl, SC_SUHIDE, INVALID_TIMER);
}
switch( bl->type ) {
@ -3583,7 +3546,7 @@ int unit_free(struct block_list *bl, clr_type clrtype)
sd->status.hom_id = 0;
#ifdef RENEWAL
status_change_end(&sd->bl, status_skill2sc(AM_CALLHOMUN), INVALID_TIMER);
status_change_end(&sd->bl, SC_HOMUN_TIME, INVALID_TIMER);
#endif
}

View File

@ -115,7 +115,7 @@ TIMER_FUNC(unit_delay_walktobl_timer);
// Causes the target object to stop moving.
int unit_stop_walking(struct block_list *bl,int type);
int unit_can_move(struct block_list *bl);
bool unit_can_move(struct block_list *bl);
int unit_is_walking(struct block_list *bl);
int unit_set_walkdelay(struct block_list *bl, t_tick tick, t_tick delay, int type);
@ -138,6 +138,7 @@ int unit_stopattack(struct block_list *bl, va_list ap);
void unit_stop_attack(struct block_list *bl);
int unit_attack(struct block_list *src,int target_id,int continuous);
int unit_cancel_combo(struct block_list *bl);
bool unit_can_attack(struct block_list *bl, int target_id);
// Cast on a unit
int unit_skilluse_id(struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv);