mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-15 08:21:28 +00:00
[Spells] Allow item click effects to have cast time and recast time modified by focus effects. (#1695)
* prelim * Spell Focus implemented * AA implemented * Update spdat.h * Update spdat.h * working * Update spells.cpp * prelim excludes * enum limit expansion * overhaul * v2 testing * updates * working * Fin * Update spell_effects.cpp * Update spell_effects.cpp * update * Update spells.cpp * fix * fix * Update spell_effects.cpp * remove debugs * Update spells.cpp
This commit is contained in:
parent
990729fe21
commit
d9c8e80bca
@ -4539,13 +4539,21 @@ int32 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id)
|
|||||||
int spell_level = 0;
|
int spell_level = 0;
|
||||||
int lvldiff = 0;
|
int lvldiff = 0;
|
||||||
uint32 effect = 0;
|
uint32 effect = 0;
|
||||||
int32 base_value = 0;
|
int32 base_value = 0;
|
||||||
int32 limit_value = 0;
|
int32 limit_value = 0;
|
||||||
uint32 slot = 0;
|
uint32 slot = 0;
|
||||||
|
|
||||||
int index_id = -1;
|
int index_id = -1;
|
||||||
uint32 focus_reuse_time = 0;
|
uint32 focus_reuse_time = 0;
|
||||||
|
|
||||||
|
bool is_from_item_click = false;
|
||||||
|
bool try_apply_to_item_click = false;
|
||||||
|
bool has_item_limit_check = false;
|
||||||
|
|
||||||
|
if (casting_spell_inventory_slot && casting_spell_inventory_slot != -1) {
|
||||||
|
is_from_item_click = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool LimitFailure = false;
|
bool LimitFailure = false;
|
||||||
bool LimitInclude[MaxLimitInclude] = {false};
|
bool LimitInclude[MaxLimitInclude] = {false};
|
||||||
/* Certain limits require only one of several Include conditions to be true. Ie. Add damage to fire OR ice
|
/* Certain limits require only one of several Include conditions to be true. Ie. Add damage to fire OR ice
|
||||||
@ -4903,6 +4911,7 @@ int32 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SE_FFItemClass:
|
case SE_FFItemClass:
|
||||||
|
has_item_limit_check = true;
|
||||||
if (casting_spell_inventory_slot && casting_spell_inventory_slot != -1) {
|
if (casting_spell_inventory_slot && casting_spell_inventory_slot != -1) {
|
||||||
if (IsClient() && casting_spell_slot == EQ::spells::CastingSlot::Item && casting_spell_inventory_slot != 0xFFFFFFFF) {
|
if (IsClient() && casting_spell_slot == EQ::spells::CastingSlot::Item && casting_spell_inventory_slot != 0xFFFFFFFF) {
|
||||||
auto item = CastToClient()->GetInv().GetItem(casting_spell_inventory_slot);
|
auto item = CastToClient()->GetInv().GetItem(casting_spell_inventory_slot);
|
||||||
@ -4995,18 +5004,21 @@ int32 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id)
|
|||||||
case SE_IncreaseSpellHaste:
|
case SE_IncreaseSpellHaste:
|
||||||
if (type == focusSpellHaste && base_value > value) {
|
if (type == focusSpellHaste && base_value > value) {
|
||||||
value = base_value;
|
value = base_value;
|
||||||
|
try_apply_to_item_click = is_from_item_click ? true : false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SE_Fc_CastTimeMod2:
|
case SE_Fc_CastTimeMod2:
|
||||||
if (type == focusFcCastTimeMod2 && base_value > value) {
|
if (type == focusFcCastTimeMod2 && base_value > value) {
|
||||||
value = base_value;
|
value = base_value;
|
||||||
|
try_apply_to_item_click = is_from_item_click ? true : false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SE_Fc_CastTimeAmt:
|
case SE_Fc_CastTimeAmt:
|
||||||
if (type == focusFcCastTimeAmt && base_value > value) {
|
if (type == focusFcCastTimeAmt && base_value > value) {
|
||||||
value = base_value;
|
value = base_value;
|
||||||
|
try_apply_to_item_click = is_from_item_click ? true : false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -5081,6 +5093,7 @@ int32 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id)
|
|||||||
case SE_ReduceReuseTimer:
|
case SE_ReduceReuseTimer:
|
||||||
if (type == focusReduceRecastTime) {
|
if (type == focusReduceRecastTime) {
|
||||||
value = base_value / 1000;
|
value = base_value / 1000;
|
||||||
|
try_apply_to_item_click = is_from_item_click ? true : false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -5247,6 +5260,10 @@ int32 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (try_apply_to_item_click && !has_item_limit_check) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (LimitFailure) {
|
if (LimitFailure) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5290,6 +5307,14 @@ int32 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
|||||||
uint32 Caston_spell_id = 0;
|
uint32 Caston_spell_id = 0;
|
||||||
int index_id = -1;
|
int index_id = -1;
|
||||||
uint32 focus_reuse_time = 0; //If this is set and all limits pass, start timer at end of script.
|
uint32 focus_reuse_time = 0; //If this is set and all limits pass, start timer at end of script.
|
||||||
|
|
||||||
|
bool is_from_item_click = false;
|
||||||
|
bool try_apply_to_item_click = false;
|
||||||
|
bool has_item_limit_check = false;
|
||||||
|
|
||||||
|
if (casting_spell_inventory_slot && casting_spell_inventory_slot != -1) {
|
||||||
|
is_from_item_click = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool LimitInclude[MaxLimitInclude] = {false};
|
bool LimitInclude[MaxLimitInclude] = {false};
|
||||||
/* Certain limits require only one of several Include conditions to be true. Determined by limits being negative or positive
|
/* Certain limits require only one of several Include conditions to be true. Determined by limits being negative or positive
|
||||||
@ -5638,14 +5663,14 @@ int32 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
|||||||
Limits focuses to check if cast from item clicks. Can be used to INCLUDE or EXCLUDE items by ItemType and/or SubType and/or Slots
|
Limits focuses to check if cast from item clicks. Can be used to INCLUDE or EXCLUDE items by ItemType and/or SubType and/or Slots
|
||||||
Not used on live, going on information we have plus implemented as broadly as possible to allow all possible options.
|
Not used on live, going on information we have plus implemented as broadly as possible to allow all possible options.
|
||||||
base = item table field 'ItemType' Limit = item table field 'SubType' Max = item table field 'Slots' (this is slot bitmask)
|
base = item table field 'ItemType' Limit = item table field 'SubType' Max = item table field 'Slots' (this is slot bitmask)
|
||||||
|
|
||||||
When including: Setting base, limit, max respectively to -1 will cause it to ignore that check, letting any type or slot ect be used.
|
When including: Setting base, limit, max respectively to -1 will cause it to ignore that check, letting any type or slot ect be used.
|
||||||
|
|
||||||
Special rules for excluding. base value needs to be negative < -1, if excluding all ItemTypes set to -1000.
|
Special rules for excluding. base value needs to be negative < -1, if excluding all ItemTypes set to -1000.
|
||||||
For SubType and Slots set using same rules above as for includes. Ie. -1 for all, positive for specifics
|
For SubType and Slots set using same rules above as for includes. Ie. -1 for all, positive for specifics
|
||||||
To exclude a specific ItemType we have to do some math. The exclude value will be the negative value of (ItemType + 100).
|
To exclude a specific ItemType we have to do some math. The exclude value will be the negative value of (ItemType + 100).
|
||||||
If ItemType = 10, then SET ItemType= -110 to exclude. If its ItemType 0, then SET ItemType= -100 to exclude ect. Not ideal but it works.
|
If ItemType = 10, then SET ItemType= -110 to exclude. If its ItemType 0, then SET ItemType= -100 to exclude ect. Not ideal but it works.
|
||||||
|
|
||||||
Usage example: [INCLUDE] Only focus spell if from click cast and is a 'defense armor' item type=10 [base= 10, limit= -1, max= -1]
|
Usage example: [INCLUDE] Only focus spell if from click cast and is a 'defense armor' item type=10 [base= 10, limit= -1, max= -1]
|
||||||
Usage example: [INCLUDE] Only focus spell if from click cast and is from helmet slot' slots= 4 [base= -1, limit= -1, max= 4]
|
Usage example: [INCLUDE] Only focus spell if from click cast and is from helmet slot' slots= 4 [base= -1, limit= -1, max= 4]
|
||||||
Usage example: [EXCLUDE] Do not focus spell if it is from an item click. [base= -1000, limit= -1, max= -1]
|
Usage example: [EXCLUDE] Do not focus spell if it is from an item click. [base= -1000, limit= -1, max= -1]
|
||||||
@ -5653,9 +5678,9 @@ int32 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
|||||||
Usage example: [EXCLUDE] Do not focus spell if it is from an item click and is a 'defense armor' item type=10. [base= -110, limit= -1, max= -1]
|
Usage example: [EXCLUDE] Do not focus spell if it is from an item click and is a 'defense armor' item type=10. [base= -110, limit= -1, max= -1]
|
||||||
|
|
||||||
Note: You can apply multiple includes or excludes to a single focus spell, using multiple SPA 415 limits in the spell. Ie. Check for clicks from ItemType 10 or 11.
|
Note: You can apply multiple includes or excludes to a single focus spell, using multiple SPA 415 limits in the spell. Ie. Check for clicks from ItemType 10 or 11.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
has_item_limit_check = true;
|
||||||
if (casting_spell_inventory_slot && casting_spell_inventory_slot != -1) {
|
if (casting_spell_inventory_slot && casting_spell_inventory_slot != -1) {
|
||||||
if (IsClient() && casting_spell_slot == EQ::spells::CastingSlot::Item && casting_spell_inventory_slot != 0xFFFFFFFF) {
|
if (IsClient() && casting_spell_slot == EQ::spells::CastingSlot::Item && casting_spell_inventory_slot != 0xFFFFFFFF) {
|
||||||
auto item = CastToClient()->GetInv().GetItem(casting_spell_inventory_slot);
|
auto item = CastToClient()->GetInv().GetItem(casting_spell_inventory_slot);
|
||||||
@ -5756,18 +5781,21 @@ int32 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
|||||||
case SE_IncreaseSpellHaste:
|
case SE_IncreaseSpellHaste:
|
||||||
if (type == focusSpellHaste && focus_spell.base_value[i] > value) {
|
if (type == focusSpellHaste && focus_spell.base_value[i] > value) {
|
||||||
value = focus_spell.base_value[i];
|
value = focus_spell.base_value[i];
|
||||||
|
try_apply_to_item_click = is_from_item_click ? true : false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SE_Fc_CastTimeMod2:
|
case SE_Fc_CastTimeMod2:
|
||||||
if (type == focusFcCastTimeMod2 && focus_spell.base_value[i] > value) {
|
if (type == focusFcCastTimeMod2 && focus_spell.base_value[i] > value) {
|
||||||
value = focus_spell.base_value[i];
|
value = focus_spell.base_value[i];
|
||||||
|
try_apply_to_item_click = is_from_item_click ? true : false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SE_Fc_CastTimeAmt:
|
case SE_Fc_CastTimeAmt:
|
||||||
if (type == focusFcCastTimeAmt && focus_spell.base_value[i] > value) {
|
if (type == focusFcCastTimeAmt && focus_spell.base_value[i] > value) {
|
||||||
value = focus_spell.base_value[i];
|
value = focus_spell.base_value[i];
|
||||||
|
try_apply_to_item_click = is_from_item_click ? true : false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -5828,6 +5856,7 @@ int32 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
|||||||
case SE_ReduceReuseTimer:
|
case SE_ReduceReuseTimer:
|
||||||
if (type == focusReduceRecastTime) {
|
if (type == focusReduceRecastTime) {
|
||||||
value = focus_spell.base_value[i] / 1000;
|
value = focus_spell.base_value[i] / 1000;
|
||||||
|
try_apply_to_item_click = is_from_item_click ? true : false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -6011,6 +6040,15 @@ int32 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
For item click cast/recast focus modifiers. Only use if SPA 415 exists.
|
||||||
|
This is an item click but does not have SPA 415 limiter. Fail here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (try_apply_to_item_click && !has_item_limit_check) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (Caston_spell_id) {
|
if (Caston_spell_id) {
|
||||||
if (IsValidSpell(Caston_spell_id) && (Caston_spell_id != spell_id)) {
|
if (IsValidSpell(Caston_spell_id) && (Caston_spell_id != spell_id)) {
|
||||||
|
|||||||
@ -417,14 +417,21 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
|||||||
target_id = GetID();
|
target_id = GetID();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cast_time <= -1) {
|
if (cast_time <= -1) {
|
||||||
// save the non-reduced cast time to use in the packet
|
// save the non-reduced cast time to use in the packet
|
||||||
cast_time = orgcasttime = spell.cast_time;
|
cast_time = orgcasttime = spell.cast_time;
|
||||||
// if there's a cast time, check if they have a modifier for it
|
// if there's a cast time, check if they have a modifier for it
|
||||||
if(cast_time) {
|
if (cast_time) {
|
||||||
cast_time = GetActSpellCasttime(spell_id, cast_time);
|
cast_time = GetActSpellCasttime(spell_id, cast_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//must use SPA 415 with focus (SPA 127/500/501) to reduce item recast
|
||||||
|
else if (cast_time && IsClient() && slot == CastingSlot::Item && item_slot != 0xFFFFFFFF) {
|
||||||
|
orgcasttime = cast_time;
|
||||||
|
if (cast_time) {
|
||||||
|
cast_time = GetActSpellCasttime(spell_id, cast_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
orgcasttime = cast_time;
|
orgcasttime = cast_time;
|
||||||
|
|
||||||
@ -2543,6 +2550,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, ui
|
|||||||
recast -= GetAA(aaTouchoftheWicked) * 420;
|
recast -= GetAA(aaTouchoftheWicked) * 420;
|
||||||
}
|
}
|
||||||
int reduction = CastToClient()->GetFocusEffect(focusReduceRecastTime, spell_id);//Client only
|
int reduction = CastToClient()->GetFocusEffect(focusReduceRecastTime, spell_id);//Client only
|
||||||
|
|
||||||
if(reduction)
|
if(reduction)
|
||||||
recast -= reduction;
|
recast -= reduction;
|
||||||
|
|
||||||
@ -2556,20 +2564,32 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, ui
|
|||||||
EQ::ItemInstance *itm = CastToClient()->GetInv().GetItem(inventory_slot);
|
EQ::ItemInstance *itm = CastToClient()->GetInv().GetItem(inventory_slot);
|
||||||
if(itm && itm->GetItem()->RecastDelay > 0){
|
if(itm && itm->GetItem()->RecastDelay > 0){
|
||||||
auto recast_type = itm->GetItem()->RecastType;
|
auto recast_type = itm->GetItem()->RecastType;
|
||||||
CastToClient()->GetPTimers().Start((pTimerItemStart + recast_type), itm->GetItem()->RecastDelay);
|
int recast_delay = itm->GetItem()->RecastDelay;
|
||||||
if (recast_type != -1) {
|
//must use SPA 415 with focus (SPA 310) to reduce item recast
|
||||||
database.UpdateItemRecastTimestamps(
|
int reduction = CastToClient()->GetFocusEffect(focusReduceRecastTime, spell_id);
|
||||||
CastToClient()->CharacterID(),
|
if (reduction) {
|
||||||
recast_type,
|
recast_delay -= reduction;
|
||||||
CastToClient()->GetPTimers().Get(pTimerItemStart + recast_type)->GetReadyTimestamp()
|
}
|
||||||
);
|
recast_delay = std::max(recast_delay, 0);
|
||||||
|
|
||||||
|
if (recast_delay > 0) {
|
||||||
|
|
||||||
|
CastToClient()->GetPTimers().Start((pTimerItemStart + recast_type), recast_delay);
|
||||||
|
if (recast_type != -1) {
|
||||||
|
database.UpdateItemRecastTimestamps(
|
||||||
|
CastToClient()->CharacterID(),
|
||||||
|
recast_type,
|
||||||
|
CastToClient()->GetPTimers().Get(pTimerItemStart + recast_type)->GetReadyTimestamp()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto outapp = new EQApplicationPacket(OP_ItemRecastDelay, sizeof(ItemRecastDelay_Struct));
|
||||||
|
ItemRecastDelay_Struct *ird = (ItemRecastDelay_Struct *)outapp->pBuffer;
|
||||||
|
ird->recast_delay = static_cast<uint32>(recast_delay);
|
||||||
|
ird->recast_type = recast_type;
|
||||||
|
CastToClient()->QueuePacket(outapp);
|
||||||
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
auto outapp = new EQApplicationPacket(OP_ItemRecastDelay, sizeof(ItemRecastDelay_Struct));
|
|
||||||
ItemRecastDelay_Struct *ird = (ItemRecastDelay_Struct *)outapp->pBuffer;
|
|
||||||
ird->recast_delay = itm->GetItem()->RecastDelay;
|
|
||||||
ird->recast_type = recast_type;
|
|
||||||
CastToClient()->QueuePacket(outapp);
|
|
||||||
safe_delete(outapp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user