[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:
KayenEQ 2021-11-10 21:23:49 -05:00 committed by GitHub
parent 990729fe21
commit d9c8e80bca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 23 deletions

View File

@ -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)) {

View File

@ -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);
} }
} }