diff --git a/Changelog.txt b/Changelog.txt index 7b6e1a228..13bf32317 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3429,7 +3429,7 @@ Additionally, the problem of zig-zag issue following in the South direction has 02-11-2023, Jhobean - Modified: @Mount added argument ARGN1 - ARGN1 (rw) = The itemID of the item containing the animation use when moounting. (Anim # is in tiledata of this item) + ARGN1 (rw) = The itemID of the item containing the animation use when moounting. (Anim # is in tiledata of this item) NOTE: When mounting a pet you'll read a non sense random value but you can replace it by an ITEMID to force anim Example: 03ea6 for Llama anim or 03e9f for gray horse anim. Yes 03ea6 is a ship part but in tiledata it link to anim 828 @@ -3442,5 +3442,13 @@ Additionally, the problem of zig-zag issue following in the South direction has 13-12-2023, Nolok - Fixed: Rare crash occurring when a NPC is selecting an attackable target, but there's only one target (not attackable) in sight. + + + + 12-02-2024, Drk84 -- Updated SphereCrypt.ini. \ No newline at end of file +- Updated SphereCrypt.ini. + +13-03-2024, Jhobean +- Added: Item properties functionnality:HITAREAPHYSICAL,HITAREAFIRE,HITAREACOLD,HITAREAPOISON,HITAREAENERGY,HITFIREBALL,HITHARM,HITLIGHTNING,HITMAGICARROW,REFLECTPHYSICALDAM + diff --git a/src/game/chars/CChar.h b/src/game/chars/CChar.h index 0b8fc7029..b1f125c7b 100644 --- a/src/game/chars/CChar.h +++ b/src/game/chars/CChar.h @@ -1300,6 +1300,7 @@ public: void StatFlag_Mod(uint64 uiStatFlag, bool fMod) noexcept; // Outside events that occur to us. int OnTakeDamage( int iDmg, CChar * pSrc, DAMAGE_TYPE uType, int iDmgPhysical = 0, int iDmgFire = 0, int iDmgCold = 0, int iDmgPoison = 0, int iDmgEnergy = 0, SPELL_TYPE spell = SPELL_NONE ); + void OnTakeDamageInflictArea(int iDmg, CChar* pSrc, DAMAGE_TYPE uType, int iDmgPhysical = 0, int iDmgFire = 0, int iDmgCold = 0, int iDmgPoison = 0, int iDmgEnergy = 0, HUE_TYPE effectHue = HUE_DEFAULT, SOUND_TYPE effectSound = SOUND_NONE); void OnHarmedBy( CChar * pCharSrc ); bool OnAttackedBy( CChar * pCharSrc, bool fPetsCommand = false, bool fShouldReveal = true ); diff --git a/src/game/chars/CCharAct.cpp b/src/game/chars/CCharAct.cpp index bb9d6e6f1..4a90c9469 100644 --- a/src/game/chars/CCharAct.cpp +++ b/src/game/chars/CCharAct.cpp @@ -2214,6 +2214,7 @@ bool CChar::ItemEquip( CItem * pItem, CChar * pCharMsg, bool fFromDClick ) if (pItem->IsTypeWeapon()) { + //Necromancy Curse weapon CItem * pCursedMemory = LayerFind(LAYER_SPELL_Curse_Weapon); // Remove the cursed state from SPELL_Curse_Weapon. if (pCursedMemory) pItem->ModPropNum(pItemCCPItemEquippable, PROPIEQUIP_HITLEECHLIFE, + pCursedMemory->m_itSpell.m_spelllevel, pItemBaseCCPItemEquippable); diff --git a/src/game/chars/CCharFight.cpp b/src/game/chars/CCharFight.cpp index 2e3e967fa..90fd013d4 100644 --- a/src/game/chars/CCharFight.cpp +++ b/src/game/chars/CCharFight.cpp @@ -939,8 +939,21 @@ int CChar::OnTakeDamage( int iDmg, CChar * pSrc, DAMAGE_TYPE uType, int iDmgPhys pSrc->Sound(0x1F1); pSrc->Effect(EFFECT_OBJ, ITEMID_FX_CURSE_EFFECT, this, 10, 16); } - } - } + } + } + // Check if REFLECTPHYSICALDAM will reflect some damage back. + // Preventing recurrent reflection with DAMAGE_REACTIVE. + if (!(uType & DAMAGE_REACTIVE)) + { + int iReflectPhysical = (ushort)std::min(GetPropNum(pCCPChar, PROPCH_REFLECTPHYSICALDAM, pBaseCCPChar),250); //Capped to 250 + + if (iReflectPhysical) + { + int iReflectPhysicalDam = (iDmg * iReflectPhysical) / 100; + pSrc->OnTakeDamage(iReflectPhysicalDam, this, (DAMAGE_TYPE)(DAMAGE_FIXED | DAMAGE_REACTIVE), iDmgPhysical, iDmgFire, iDmgCold, iDmgPoison, iDmgEnergy); + } + } + } } @@ -983,6 +996,48 @@ int CChar::OnTakeDamage( int iDmg, CChar * pSrc, DAMAGE_TYPE uType, int iDmgPhys return iDmg; } +void CChar::OnTakeDamageInflictArea(int iDmg, CChar* pSrc, DAMAGE_TYPE uType, int iDmgPhysical, int iDmgFire, int iDmgCold, int iDmgPoison, int iDmgEnergy, HUE_TYPE effectHue, SOUND_TYPE effectSound) +{ + ADDTOCALLSTACK("CChar::OnTakeDamageInflictArea"); + + bool fMakeSound = false; + + int iDistance = 5; + if (IsAosFlagEnabled(FEATURE_AOS_DAMAGE)) + iDistance=10; // 5 for ML and 10 for aos + + CWorldSearch AreaChars(GetTopPoint(), iDistance); + for (;;) + //pSrc = Char make the attack + //pChar = Char scanned on the loop iteration + //this = Char get the initial hit + { + CChar* pChar = AreaChars.GetChar(); + if (!pChar) + break; + if ((pChar == this) || (pChar == pSrc)) //This char already receive the base hit. Damage already done + continue; + if (pChar->Fight_CanHit(pSrc,true) == WAR_SWING_INVALID) //Check if target can be hit (I am invul, stone etc. Target is Disconnected,safe zone etc) + continue; + if (!pChar->m_pClient && pChar->NPC_IsOwnedBy(pSrc,false)) // it's my pet? + continue; + if (pChar->Noto_CalcFlag(pSrc) == NOTO_GOOD) //Avoid to hit someone we can't legally attack (same guild, same party, Vendor etc) + continue; + if (!pChar->CanSeeLOS(pSrc)) //Avoid hit someone in nearby house + continue; + + /* On servUo they modify the damage depending of the distance with this formula + There no info about this on UO Wiki + damage *= ( 11 - from.GetDistanceToSqrt( m ) ) / 10; */ + + pChar->OnTakeDamage(iDmg, pSrc, uType, iDmgPhysical, iDmgFire, iDmgCold, iDmgPoison, iDmgEnergy); + pChar->Effect(EFFECT_OBJ, ITEMID_FX_SPARKLE_2, this, 1, 15, false, effectHue); + fMakeSound = true; + } + if (fMakeSound && (effectSound != SOUND_NONE)) + Sound(effectSound); +} + //******************************************************************************* // Fight specific memories. @@ -2167,6 +2222,46 @@ WAR_SWING_TYPE CChar::Fight_Hit( CChar * pCharTarg ) if ( fMakeLeechSound ) Sound(0x44d); + if (pWeapon) + { + + if (GetPropNum(pCCPChar, PROPCH_HITAREAPHYSICAL, pBaseCCPChar) > Calc_GetRandLLVal(100)) + pCharTarg->OnTakeDamageInflictArea(iDmg / 2, this, DAMAGE_HIT_BLUNT, 100, 0, 0, 0, 0, static_cast(0x32), static_cast(0x10E)); + + bool fElemental = IsSetCombatFlags(COMBAT_ELEMENTAL_ENGINE); + if (fElemental) + { + + if (GetPropNum(pCCPChar, PROPCH_HITAREAFIRE, pBaseCCPChar) > Calc_GetRandLLVal(100)) + pCharTarg->OnTakeDamageInflictArea(iDmg / 2, this, DAMAGE_FIRE, 0, 100, 0, 0, 0, static_cast(0x488), static_cast(0x11D)); + + if (GetPropNum(pCCPChar, PROPCH_HITAREACOLD, pBaseCCPChar) > Calc_GetRandLLVal(100)) + pCharTarg->OnTakeDamageInflictArea(iDmg / 2, this, DAMAGE_COLD, 0, 0, 100, 0, 0, static_cast(0x834), static_cast(0xFC)); + + if (GetPropNum(pCCPChar, PROPCH_HITAREAPOISON, pBaseCCPChar) > Calc_GetRandLLVal(100)) + pCharTarg->OnTakeDamageInflictArea(iDmg / 2, this, DAMAGE_POISON, 0, 0, 0, 100, 0, static_cast(0x48E), static_cast(0x205)); + + if (GetPropNum(pCCPChar, PROPCH_HITAREAENERGY, pBaseCCPChar) > Calc_GetRandLLVal(100)) + pCharTarg->OnTakeDamageInflictArea(iDmg / 2, this, DAMAGE_ENERGY, 0, 0, 0, 0, 100, static_cast(0x78), static_cast(0x1F1)); + + } + + if (GetPropNum(pCCPChar, PROPCH_HITDISPEL, pBaseCCPChar) > Calc_GetRandLLVal(100)) + pCharTarg->OnSpellEffect(SPELL_Dispel, this, Skill_GetAdjusted(SKILL_MAGERY), pWeapon); + + if (GetPropNum(pCCPChar, PROPCH_HITFIREBALL, pBaseCCPChar) > Calc_GetRandLLVal(100)) + pCharTarg->OnSpellEffect(SPELL_Fireball, this, Skill_GetAdjusted(SKILL_MAGERY), pWeapon); + + if (GetPropNum(pCCPChar, PROPCH_HITHARM, pBaseCCPChar) > Calc_GetRandLLVal(100)) + pCharTarg->OnSpellEffect(SPELL_Harm, this, Skill_GetAdjusted(SKILL_MAGERY), pWeapon); + + if (GetPropNum(pCCPChar, PROPCH_HITLIGHTNING, pBaseCCPChar) > Calc_GetRandLLVal(100)) + pCharTarg->OnSpellEffect(SPELL_Lightning, this, Skill_GetAdjusted(SKILL_MAGERY), pWeapon); + + if (GetPropNum(pCCPChar, PROPCH_HITMAGICARROW, pBaseCCPChar) > Calc_GetRandLLVal(100)) + pCharTarg->OnSpellEffect(SPELL_Magic_Arrow, this, Skill_GetAdjusted(SKILL_MAGERY), pWeapon); + } + // Make blood effects if ( pCharTarg->_wBloodHue != (HUE_TYPE)(-1) ) { diff --git a/src/game/components/CCPropsItemEquippable.cpp b/src/game/components/CCPropsItemEquippable.cpp index fa3f597e8..37dba2b27 100644 --- a/src/game/components/CCPropsItemEquippable.cpp +++ b/src/game/components/CCPropsItemEquippable.cpp @@ -331,39 +331,39 @@ void CCPropsItemEquippable::AddPropsTooltipData(CObjBase* pLinkedObj) case PROPIEQUIP_FASTERCASTRECOVERY: // unimplemented ADDTNUM(1060412); // faster cast recovery ~1_val~ break; - case PROPIEQUIP_HITAREACOLD: // unimplemented + case PROPIEQUIP_HITAREACOLD: if (IsSetCombatFlags(COMBAT_ELEMENTAL_ENGINE)) ADDTNUM(1060416); // hit cold area ~1_val~% break; - case PROPIEQUIP_HITAREAENERGY: // unimplemented + case PROPIEQUIP_HITAREAENERGY: if (IsSetCombatFlags(COMBAT_ELEMENTAL_ENGINE)) ADDTNUM(1060418); // hit energy area ~1_val~% break; - case PROPIEQUIP_HITAREAFIRE: // unimplemented + case PROPIEQUIP_HITAREAFIRE: if (IsSetCombatFlags(COMBAT_ELEMENTAL_ENGINE)) ADDTNUM(1060419); // hit fire area ~1_val~% break; - case PROPIEQUIP_HITAREAPHYSICAL: // unimplemented + case PROPIEQUIP_HITAREAPHYSICAL: if (IsSetCombatFlags(COMBAT_ELEMENTAL_ENGINE)) ADDTNUM(1060428); // hit physical area ~1_val~% break; - case PROPIEQUIP_HITAREAPOISON: // unimplemented + case PROPIEQUIP_HITAREAPOISON: if (IsSetCombatFlags(COMBAT_ELEMENTAL_ENGINE)) ADDTNUM(1060429); // hit poison area ~1_val~% break; case PROPIEQUIP_HITCURSE: // unimplemented ADDTNUM(1113712); // Hit Curse ~1_val~% break; - case PROPIEQUIP_HITDISPEL: // unimplemented + case PROPIEQUIP_HITDISPEL: ADDTNUM(1060417); // hit dispel ~1_val~% break; case PROPIEQUIP_HITFATIGUE: // unimplemented ADDTNUM(1113700); // // Hit Fatigue ~1_val~% break; - case PROPIEQUIP_HITFIREBALL: // unimplemented + case PROPIEQUIP_HITFIREBALL: ADDTNUM(1060420); // hit fireball ~1_val~% break; - case PROPIEQUIP_HITHARM: // unimplemented + case PROPIEQUIP_HITHARM: ADDTNUM(1060421); // hit harm ~1_val~% break; case PROPIEQUIP_HITLEECHLIFE: @@ -375,7 +375,7 @@ void CCPropsItemEquippable::AddPropsTooltipData(CObjBase* pLinkedObj) case PROPIEQUIP_HITLEECHSTAM: ADDTNUM(1060430); // hit stamina leech ~1_val~% break; - case PROPIEQUIP_HITLIGHTNING: // unimplemented + case PROPIEQUIP_HITLIGHTNING: ADDTNUM(1060422); // hit lightning ~1_val~% break; case PROPIEQUIP_HITLOWERATK: // unimplemented @@ -384,10 +384,10 @@ void CCPropsItemEquippable::AddPropsTooltipData(CObjBase* pLinkedObj) case PROPIEQUIP_HITLOWERDEF: // unimplemented ADDTNUM(1060425); // hit lower defense ~1_val~% break; - case PROPIEQUIP_HITMAGICARROW: // unimplemented + case PROPIEQUIP_HITMAGICARROW: ADDTNUM(1060426); // hit magic arrow ~1_val~% break; - case PROPIEQUIP_HITMANADRAIN: // unimplemented + case PROPIEQUIP_HITMANADRAIN: ADDTNUM(1113699); // Hit Mana Drain ~1_val~% break; case PROPIEQUIP_HITSPARKS: // unimplemented @@ -459,7 +459,7 @@ void CCPropsItemEquippable::AddPropsTooltipData(CObjBase* pLinkedObj) case PROPIEQUIP_REACTIVEPARALYZE: // Unimplemented ADDT(1112364); // reactive paralyze break; - case PROPIEQUIP_REFLECTPHYSICALDAM: // Unimplemented + case PROPIEQUIP_REFLECTPHYSICALDAM: ADDTNUM(1060442); // reflect physical damage ~1_val~% break; case PROPIEQUIP_REGENFOOD: // unimplemented