diff --git a/common/ruletypes.h b/common/ruletypes.h index cb4b41405..b3c19ddbc 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -492,6 +492,7 @@ RULE_BOOL(Combat, ClassicMasterWu, false, "classic master wu uses a random speci RULE_INT(Combat, LevelToStopDamageCaps, 0, "1 will effectively disable them, 20 should give basically same results as old incorrect system") RULE_BOOL(Combat, ClassicNPCBackstab, false, "true disables npc facestab - npcs get normal attack if not behind") RULE_BOOL(Combat, UseNPCDamageClassLevelMods, true, "Uses GetClassLevelDamageMod calc in npc_scale_manager") +RULE_BOOL(Combat, UseExtendedPoisonProcs, false, "Allow old school poisons to last until characrer zones, at a lower proc rate") RULE_CATEGORY_END() RULE_CATEGORY(NPC) diff --git a/zone/attack.cpp b/zone/attack.cpp index 17c23971a..7c58f5059 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -4069,11 +4069,16 @@ void Mob::TrySpellProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *w if (!weapon && hand == EQEmu::invslot::slotRange && GetSpecialAbility(SPECATK_RANGED_ATK)) rangedattk = true; + int16 poison_slot=-1; + for (uint32 i = 0; i < MAX_PROCS; i++) { if (IsPet() && hand != EQEmu::invslot::slotPrimary) //Pets can only proc spell procs from their primay hand (ie; beastlord pets) continue; // If pets ever can proc from off hand, this will need to change - // Not ranged + if (!weapon || (SpellProcs[i].base_spellID == POISON_PROC && weapon->ItemType != EQEmu::item::ItemType1HPiercing)) + continue; // Old school poison will only proc with 1HP equipped. + + // Not ranged if (!rangedattk) { // Perma procs (AAs) if (PermaProcs[i].spellID != SPELL_UNKNOWN) { @@ -4088,6 +4093,11 @@ void Mob::TrySpellProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *w // Spell procs (buffs) if (SpellProcs[i].spellID != SPELL_UNKNOWN) { + if (SpellProcs[i].base_spellID == POISON_PROC) { + poison_slot=i; + continue; // Process the poison proc last per @mackal + } + float chance = ProcChance * (static_cast(SpellProcs[i].chance) / 100.0f); if (zone->random.Roll(chance)) { LogCombat("Spell proc [{}] procing spell [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance); @@ -4118,6 +4128,21 @@ void Mob::TrySpellProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *w } } + if (poison_slot > -1) { + bool one_shot = !RuleB(Combat, UseExtendedPoisonProcs); + float chance = (one_shot) ? 100.0f : ProcChance * (static_cast(SpellProcs[poison_slot].chance) / 100.0f); + uint16 spell_id = SpellProcs[poison_slot].spellID; + + if (zone->random.Roll(chance)) { + LogCombat("Poison proc [{}] procing spell [{}] ([{}] percent chance)", poison_slot, spell_id, chance); + SendBeginCast(spell_id, 0); + ExecWeaponProc(nullptr, spell_id, on, SpellProcs[poison_slot].level_override); + if (one_shot) { + RemoveProcFromWeapon(spell_id); + } + } + } + if (HasSkillProcs() && hand != EQEmu::invslot::slotRange) { //We check ranged skill procs within the attack functions. uint16 skillinuse = 28; if (weapon) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index c27a23065..a7460b5d7 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -2809,12 +2809,8 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app) uint32 ApplyPoisonSuccessResult = 0; - const EQEmu::ItemInstance* PrimaryWeapon = GetInv().GetItem(EQEmu::invslot::slotPrimary); - const EQEmu::ItemInstance* SecondaryWeapon = GetInv().GetItem(EQEmu::invslot::slotSecondary); const EQEmu::ItemInstance* PoisonItemInstance = GetInv().GetItem(ApplyPoisonData->inventorySlot); - const EQEmu::ItemData* primary = (PrimaryWeapon ? PrimaryWeapon->GetItem() : nullptr); - const EQEmu::ItemData* secondary = (SecondaryWeapon ? SecondaryWeapon->GetItem() : nullptr); const EQEmu::ItemData* poison = (PoisonItemInstance ? PoisonItemInstance->GetItem() : nullptr); bool IsPoison = (poison && poison->ItemType == EQEmu::item::ItemTypePoison); @@ -2828,10 +2824,7 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app) // Poison is too high to apply. MessageString(Chat::LightBlue, POISON_TOO_HIGH); } - else if ((primary && - primary->ItemType == EQEmu::item::ItemType1HPiercing) || - (secondary && - secondary->ItemType == EQEmu::item::ItemType1HPiercing)) { + else { double ChanceRoll = zone->random.Real(0, 1); @@ -2851,9 +2844,6 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app) AddProcToWeapon(poison->Proc.Effect, false, (GetDEX() / 100) + 103, POISON_PROC); } } - else { - Message(Chat::Red, "A piercing weapon must be wielded to apply poison."); - } // Live always deletes the item, success or failure. Even if too high. DeleteItemInInventory(ApplyPoisonData->inventorySlot, 1, true);