mirror of
https://github.com/EQEmu/Server.git
synced 2026-03-22 18:02:25 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
8048239a81
@ -1,5 +1,34 @@
|
|||||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
== 08/14/2016 ==
|
||||||
|
mackal: Implement Linked Spell Reuse Timers
|
||||||
|
- For whatever reason this is a bit unfriendly, but that's how it is on live.
|
||||||
|
- Titanium is especially unfriendly with large differences in reuse times (ex higher canni and the first 4)
|
||||||
|
- Unsure when this went live for spells, but canni was at least linked at OoW launch
|
||||||
|
|
||||||
|
== 08/13/2016 ==
|
||||||
|
Kinglykrab: Implemented optional avoidance cap rules.
|
||||||
|
- Serves to eliminate God-like characters on custom servers with high item stats
|
||||||
|
- Rule Names:
|
||||||
|
- Character:EnableAvoidanceCap (default is false)
|
||||||
|
- Character:AvoidanceCap (default is 750, beyond 1,000 seems to make characters dodge all attacks)
|
||||||
|
|
||||||
|
== 08/02/2016 ==
|
||||||
|
Uleat: Changed 'SendZoneSpawnsBulk' behavior to use near/far criteria (live-like) when sending packets.
|
||||||
|
- Zone-to-Zone client loading will see a small decrease in time (less than 10~15%)
|
||||||
|
- World-to-Zone client loading appears to greatly benefit from this (tested 'devastation' - pre-change: ~22 seconds, post-change: 12~15 seconds)
|
||||||
|
- This change does not affect the final spawning of mobs in the client
|
||||||
|
|
||||||
|
== 07/31/2016 ==
|
||||||
|
mackal: Implement more spell gems!
|
||||||
|
- There are a few things still left to due like make dealing with losing gems nice (reset AAs, going to an older client etc)
|
||||||
|
- Sadly SoF disc release doesn't support gem 10 like one might expect :(
|
||||||
|
- So changed clients:
|
||||||
|
- SoD = 10
|
||||||
|
- UF = 12
|
||||||
|
- RoF/RoF2 = 12. I know the UI supports 16, but the client does not and can cause client crashes
|
||||||
|
- The quest APIs assume you pass a valid spell gem ...
|
||||||
|
|
||||||
== 07/28/2016 ==
|
== 07/28/2016 ==
|
||||||
Uleat: Implemented zone memory-mapped file usage
|
Uleat: Implemented zone memory-mapped file usage
|
||||||
- Zone map files are converted to pre-loaded binary files, bypassing the (sometimes) time-consuming raw data transform process
|
- Zone map files are converted to pre-loaded binary files, bypassing the (sometimes) time-consuming raw data transform process
|
||||||
|
|||||||
@ -44,6 +44,26 @@ namespace EQEmu
|
|||||||
const size_t SayLinkBodySize = RoF2::constants::SayLinkBodySize;
|
const size_t SayLinkBodySize = RoF2::constants::SayLinkBodySize;
|
||||||
|
|
||||||
} /*constants*/
|
} /*constants*/
|
||||||
|
enum class CastingSlot : uint32 {
|
||||||
|
Gem1 = 0,
|
||||||
|
Gem2 = 1,
|
||||||
|
Gem3 = 2,
|
||||||
|
Gem4 = 3,
|
||||||
|
Gem5 = 4,
|
||||||
|
Gem6 = 5,
|
||||||
|
Gem7 = 6,
|
||||||
|
Gem8 = 7,
|
||||||
|
Gem9 = 8,
|
||||||
|
Gem10 = 9,
|
||||||
|
Gem11 = 10,
|
||||||
|
Gem12 = 11,
|
||||||
|
MaxGems = 12,
|
||||||
|
Ability = 20, // HT/LoH for Tit
|
||||||
|
PotionBelt = 21, // Tit uses a different slot for PB
|
||||||
|
Item = 22,
|
||||||
|
Discipline = 23,
|
||||||
|
AltAbility = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
} /*EQEmu*/
|
} /*EQEmu*/
|
||||||
|
|
||||||
|
|||||||
@ -289,6 +289,7 @@ N(OP_LFGuild),
|
|||||||
N(OP_LFPCommand),
|
N(OP_LFPCommand),
|
||||||
N(OP_LFPGetMatchesRequest),
|
N(OP_LFPGetMatchesRequest),
|
||||||
N(OP_LFPGetMatchesResponse),
|
N(OP_LFPGetMatchesResponse),
|
||||||
|
N(OP_LinkedReuse),
|
||||||
N(OP_LoadSpellSet),
|
N(OP_LoadSpellSet),
|
||||||
N(OP_LocInfo),
|
N(OP_LocInfo),
|
||||||
N(OP_LockoutTimerInfo),
|
N(OP_LockoutTimerInfo),
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
|
|
||||||
static const uint32 BUFF_COUNT = 25;
|
static const uint32 BUFF_COUNT = 25;
|
||||||
|
static const uint32 PET_BUFF_COUNT = 30;
|
||||||
static const uint32 MAX_MERC = 100;
|
static const uint32 MAX_MERC = 100;
|
||||||
static const uint32 MAX_MERC_GRADES = 10;
|
static const uint32 MAX_MERC_GRADES = 10;
|
||||||
static const uint32 MAX_MERC_STANCES = 10;
|
static const uint32 MAX_MERC_STANCES = 10;
|
||||||
@ -386,7 +387,19 @@ struct MemorizeSpell_Struct {
|
|||||||
uint32 slot; // Spot in the spell book/memorized slot
|
uint32 slot; // Spot in the spell book/memorized slot
|
||||||
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
||||||
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
||||||
uint32 unknown12;
|
uint32 reduction; // lower reuse
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Linked Spell Reuse Timer
|
||||||
|
** Length: 12
|
||||||
|
** Comes before the OP_Memorize
|
||||||
|
** Live (maybe TDS steam) has an extra DWORD after timer_id
|
||||||
|
*/
|
||||||
|
struct LinkedSpellReuseTimer_Struct {
|
||||||
|
uint32 timer_id; // Timer ID of the spell
|
||||||
|
uint32 end_time; // timestamp of when it will be ready
|
||||||
|
uint32 start_time; // timestamp of when it started
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -419,10 +432,11 @@ struct DeleteSpell_Struct
|
|||||||
|
|
||||||
struct ManaChange_Struct
|
struct ManaChange_Struct
|
||||||
{
|
{
|
||||||
uint32 new_mana; // New Mana AMount
|
/*00*/ uint32 new_mana; // New Mana AMount
|
||||||
uint32 stamina;
|
/*04*/ uint32 stamina;
|
||||||
uint32 spell_id;
|
/*08*/ uint32 spell_id;
|
||||||
uint32 unknown12;
|
/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting?
|
||||||
|
/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwapSpell_Struct
|
struct SwapSpell_Struct
|
||||||
@ -522,8 +536,8 @@ struct BuffRemoveRequest_Struct
|
|||||||
|
|
||||||
struct PetBuff_Struct {
|
struct PetBuff_Struct {
|
||||||
/*000*/ uint32 petid;
|
/*000*/ uint32 petid;
|
||||||
/*004*/ uint32 spellid[BUFF_COUNT+5];
|
/*004*/ uint32 spellid[PET_BUFF_COUNT];
|
||||||
/*124*/ int32 ticsremaining[BUFF_COUNT+5];
|
/*124*/ int32 ticsremaining[PET_BUFF_COUNT];
|
||||||
/*244*/ uint32 buffcount;
|
/*244*/ uint32 buffcount;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -834,7 +848,7 @@ struct SuspendedMinion_Struct
|
|||||||
*/
|
*/
|
||||||
static const uint32 MAX_PP_LANGUAGE = 28;
|
static const uint32 MAX_PP_LANGUAGE = 28;
|
||||||
static const uint32 MAX_PP_SPELLBOOK = 480; // Set for all functions
|
static const uint32 MAX_PP_SPELLBOOK = 480; // Set for all functions
|
||||||
static const uint32 MAX_PP_MEMSPELL = 9; // Set to latest client so functions can work right
|
static const uint32 MAX_PP_MEMSPELL = static_cast<uint32>(EQEmu::CastingSlot::MaxGems); // Set to latest client so functions can work right -- 12
|
||||||
static const uint32 MAX_PP_REF_SPELLBOOK = 480; // Set for Player Profile size retain
|
static const uint32 MAX_PP_REF_SPELLBOOK = 480; // Set for Player Profile size retain
|
||||||
static const uint32 MAX_PP_REF_MEMSPELL = 9; // Set for Player Profile size retain
|
static const uint32 MAX_PP_REF_MEMSPELL = 9; // Set for Player Profile size retain
|
||||||
|
|
||||||
@ -915,7 +929,7 @@ struct PlayerProfile_Struct
|
|||||||
/*0245*/ uint8 guildbanker;
|
/*0245*/ uint8 guildbanker;
|
||||||
/*0246*/ uint8 unknown0246[6]; //
|
/*0246*/ uint8 unknown0246[6]; //
|
||||||
/*0252*/ uint32 intoxication;
|
/*0252*/ uint32 intoxication;
|
||||||
/*0256*/ uint32 spellSlotRefresh[MAX_PP_REF_MEMSPELL]; //in ms
|
/*0256*/ uint32 spellSlotRefresh[MAX_PP_MEMSPELL]; //in ms
|
||||||
/*0292*/ uint32 abilitySlotRefresh;
|
/*0292*/ uint32 abilitySlotRefresh;
|
||||||
/*0296*/ uint8 haircolor; // Player hair color
|
/*0296*/ uint8 haircolor; // Player hair color
|
||||||
/*0297*/ uint8 beardcolor; // Player beard color
|
/*0297*/ uint8 beardcolor; // Player beard color
|
||||||
@ -956,7 +970,7 @@ struct PlayerProfile_Struct
|
|||||||
/*2580*/ uint8 unknown2616[4];
|
/*2580*/ uint8 unknown2616[4];
|
||||||
/*2584*/ uint32 spell_book[MAX_PP_REF_SPELLBOOK];
|
/*2584*/ uint32 spell_book[MAX_PP_REF_SPELLBOOK];
|
||||||
/*4504*/ uint8 unknown4540[128]; // Was [428] all 0xff
|
/*4504*/ uint8 unknown4540[128]; // Was [428] all 0xff
|
||||||
/*4632*/ uint32 mem_spells[MAX_PP_REF_MEMSPELL];
|
/*4632*/ uint32 mem_spells[MAX_PP_MEMSPELL];
|
||||||
/*4668*/ uint8 unknown4704[32]; //
|
/*4668*/ uint8 unknown4704[32]; //
|
||||||
/*4700*/ float y; // Player y position
|
/*4700*/ float y; // Player y position
|
||||||
/*4704*/ float x; // Player x position
|
/*4704*/ float x; // Player x position
|
||||||
|
|||||||
@ -1863,6 +1863,9 @@ uint8 ItemInst::FirstOpenSlot() const
|
|||||||
|
|
||||||
uint8 ItemInst::GetTotalItemCount() const
|
uint8 ItemInst::GetTotalItemCount() const
|
||||||
{
|
{
|
||||||
|
if (!m_item)
|
||||||
|
return 0;
|
||||||
|
|
||||||
uint8 item_count = 1;
|
uint8 item_count = 1;
|
||||||
|
|
||||||
if (m_item && !m_item->IsClassBag()) { return item_count; }
|
if (m_item && !m_item->IsClassBag()) { return item_count; }
|
||||||
|
|||||||
@ -63,6 +63,9 @@ namespace RoF
|
|||||||
// client to server text link converter
|
// client to server text link converter
|
||||||
static inline void RoFToServerTextLink(std::string& serverTextLink, const std::string& rofTextLink);
|
static inline void RoFToServerTextLink(std::string& serverTextLink, const std::string& rofTextLink);
|
||||||
|
|
||||||
|
static inline CastingSlot ServerToRoFCastingSlot(EQEmu::CastingSlot slot);
|
||||||
|
static inline EQEmu::CastingSlot RoFToServerCastingSlot(CastingSlot slot);
|
||||||
|
|
||||||
void Register(EQStreamIdentifier &into)
|
void Register(EQStreamIdentifier &into)
|
||||||
{
|
{
|
||||||
//create our opcode manager if we havent already
|
//create our opcode manager if we havent already
|
||||||
@ -507,10 +510,7 @@ namespace RoF
|
|||||||
ENCODE_LENGTH_EXACT(CastSpell_Struct);
|
ENCODE_LENGTH_EXACT(CastSpell_Struct);
|
||||||
SETUP_DIRECT_ENCODE(CastSpell_Struct, structs::CastSpell_Struct);
|
SETUP_DIRECT_ENCODE(CastSpell_Struct, structs::CastSpell_Struct);
|
||||||
|
|
||||||
if (emu->slot == 10)
|
eq->slot = static_cast<uint32>(ServerToRoFCastingSlot(static_cast<EQEmu::CastingSlot>(emu->slot)));
|
||||||
eq->slot = 13;
|
|
||||||
else
|
|
||||||
OUT(slot);
|
|
||||||
|
|
||||||
OUT(spell_id);
|
OUT(spell_id);
|
||||||
eq->inventory_slot = ServerToRoFSlot(emu->inventoryslot);
|
eq->inventory_slot = ServerToRoFSlot(emu->inventoryslot);
|
||||||
@ -1623,7 +1623,8 @@ namespace RoF
|
|||||||
OUT(new_mana);
|
OUT(new_mana);
|
||||||
OUT(stamina);
|
OUT(stamina);
|
||||||
OUT(spell_id);
|
OUT(spell_id);
|
||||||
eq->unknown16 = -1; // Self Interrupt/Success = -1, Fizzle = 1, Other Interrupt = 2?
|
OUT(keepcasting);
|
||||||
|
eq->slot = -1; // this is spell gem slot. It's -1 in normal operation
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@ -2012,18 +2013,18 @@ namespace RoF
|
|||||||
__packet->WriteUInt8(1); // 1 indicates all buffs on the pet (0 to add or remove a single buff)
|
__packet->WriteUInt8(1); // 1 indicates all buffs on the pet (0 to add or remove a single buff)
|
||||||
__packet->WriteUInt16(emu->buffcount);
|
__packet->WriteUInt16(emu->buffcount);
|
||||||
|
|
||||||
for (uint16 i = 0; i < BUFF_COUNT; ++i)
|
for (uint16 i = 0; i < PET_BUFF_COUNT; ++i)
|
||||||
{
|
{
|
||||||
if (emu->spellid[i])
|
if (emu->spellid[i])
|
||||||
{
|
{
|
||||||
__packet->WriteUInt32(i);
|
__packet->WriteUInt32(i);
|
||||||
__packet->WriteUInt32(emu->spellid[i]);
|
__packet->WriteUInt32(emu->spellid[i]);
|
||||||
__packet->WriteUInt32(emu->ticsremaining[i]);
|
__packet->WriteUInt32(emu->ticsremaining[i]);
|
||||||
__packet->WriteUInt32(0); // Unknown
|
__packet->WriteUInt32(0); // numhits
|
||||||
__packet->WriteString("");
|
__packet->WriteString("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__packet->WriteUInt8(0); // Unknown
|
__packet->WriteUInt8(0); // some sort of type
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@ -2259,22 +2260,23 @@ namespace RoF
|
|||||||
|
|
||||||
outapp->WriteUInt32(structs::MAX_PP_MEMSPELL); // Memorised spell slots
|
outapp->WriteUInt32(structs::MAX_PP_MEMSPELL); // Memorised spell slots
|
||||||
|
|
||||||
for (uint32 r = 0; r < MAX_PP_MEMSPELL; r++)
|
for (uint32 r = 0; r < MAX_PP_MEMSPELL; r++) // first 12
|
||||||
{
|
{
|
||||||
outapp->WriteUInt32(emu->mem_spells[r]);
|
outapp->WriteUInt32(emu->mem_spells[r]);
|
||||||
}
|
}
|
||||||
// zeroes for the rest of the slots
|
// zeroes for the rest of the slots -- the other 4 which don't work at all!
|
||||||
for (uint32 r = 0; r < structs::MAX_PP_MEMSPELL - MAX_PP_MEMSPELL; r++)
|
for (uint32 r = 0; r < structs::MAX_PP_MEMSPELL - MAX_PP_MEMSPELL; r++)
|
||||||
{
|
{
|
||||||
outapp->WriteUInt32(0xFFFFFFFFU);
|
outapp->WriteUInt32(0xFFFFFFFFU);
|
||||||
}
|
}
|
||||||
|
|
||||||
outapp->WriteUInt32(13); // Unknown count
|
outapp->WriteUInt32(13); // gem refresh count
|
||||||
|
|
||||||
for (uint32 r = 0; r < 13; r++)
|
for (uint32 r = 0; r < MAX_PP_MEMSPELL; r++)
|
||||||
{
|
{
|
||||||
outapp->WriteUInt32(0); // Unknown
|
outapp->WriteUInt32(emu->spellSlotRefresh[r]); // spell gem refresh
|
||||||
}
|
}
|
||||||
|
outapp->WriteUInt32(0); // also refresh -- historically HT/LoH :P
|
||||||
|
|
||||||
outapp->WriteUInt8(0); // Unknown
|
outapp->WriteUInt8(0); // Unknown
|
||||||
|
|
||||||
@ -4334,10 +4336,7 @@ namespace RoF
|
|||||||
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
||||||
SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct);
|
SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct);
|
||||||
|
|
||||||
if (eq->slot == 13)
|
emu->slot = static_cast<uint32>(RoFToServerCastingSlot(static_cast<CastingSlot>(eq->slot)));
|
||||||
emu->slot = 10;
|
|
||||||
else
|
|
||||||
IN(slot);
|
|
||||||
|
|
||||||
IN(spell_id);
|
IN(spell_id);
|
||||||
emu->inventoryslot = RoFToServerSlot(eq->inventory_slot);
|
emu->inventoryslot = RoFToServerSlot(eq->inventory_slot);
|
||||||
@ -6009,4 +6008,80 @@ namespace RoF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline CastingSlot ServerToRoFCastingSlot(EQEmu::CastingSlot slot)
|
||||||
|
{
|
||||||
|
switch (slot) {
|
||||||
|
case EQEmu::CastingSlot::Gem1:
|
||||||
|
return CastingSlot::Gem1;
|
||||||
|
case EQEmu::CastingSlot::Gem2:
|
||||||
|
return CastingSlot::Gem2;
|
||||||
|
case EQEmu::CastingSlot::Gem3:
|
||||||
|
return CastingSlot::Gem3;
|
||||||
|
case EQEmu::CastingSlot::Gem4:
|
||||||
|
return CastingSlot::Gem4;
|
||||||
|
case EQEmu::CastingSlot::Gem5:
|
||||||
|
return CastingSlot::Gem5;
|
||||||
|
case EQEmu::CastingSlot::Gem6:
|
||||||
|
return CastingSlot::Gem6;
|
||||||
|
case EQEmu::CastingSlot::Gem7:
|
||||||
|
return CastingSlot::Gem7;
|
||||||
|
case EQEmu::CastingSlot::Gem8:
|
||||||
|
return CastingSlot::Gem8;
|
||||||
|
case EQEmu::CastingSlot::Gem9:
|
||||||
|
return CastingSlot::Gem9;
|
||||||
|
case EQEmu::CastingSlot::Gem10:
|
||||||
|
return CastingSlot::Gem10;
|
||||||
|
case EQEmu::CastingSlot::Gem11:
|
||||||
|
return CastingSlot::Gem11;
|
||||||
|
case EQEmu::CastingSlot::Gem12:
|
||||||
|
return CastingSlot::Gem12;
|
||||||
|
case EQEmu::CastingSlot::Item:
|
||||||
|
case EQEmu::CastingSlot::PotionBelt:
|
||||||
|
return CastingSlot::Item;
|
||||||
|
case EQEmu::CastingSlot::Discipline:
|
||||||
|
return CastingSlot::Discipline;
|
||||||
|
case EQEmu::CastingSlot::AltAbility:
|
||||||
|
return CastingSlot::AltAbility;
|
||||||
|
default: // we shouldn't have any issues with other slots ... just return something
|
||||||
|
return CastingSlot::Discipline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline EQEmu::CastingSlot RoFToServerCastingSlot(CastingSlot slot)
|
||||||
|
{
|
||||||
|
switch (slot) {
|
||||||
|
case CastingSlot::Gem1:
|
||||||
|
return EQEmu::CastingSlot::Gem1;
|
||||||
|
case CastingSlot::Gem2:
|
||||||
|
return EQEmu::CastingSlot::Gem2;
|
||||||
|
case CastingSlot::Gem3:
|
||||||
|
return EQEmu::CastingSlot::Gem3;
|
||||||
|
case CastingSlot::Gem4:
|
||||||
|
return EQEmu::CastingSlot::Gem4;
|
||||||
|
case CastingSlot::Gem5:
|
||||||
|
return EQEmu::CastingSlot::Gem5;
|
||||||
|
case CastingSlot::Gem6:
|
||||||
|
return EQEmu::CastingSlot::Gem6;
|
||||||
|
case CastingSlot::Gem7:
|
||||||
|
return EQEmu::CastingSlot::Gem7;
|
||||||
|
case CastingSlot::Gem8:
|
||||||
|
return EQEmu::CastingSlot::Gem8;
|
||||||
|
case CastingSlot::Gem9:
|
||||||
|
return EQEmu::CastingSlot::Gem9;
|
||||||
|
case CastingSlot::Gem10:
|
||||||
|
return EQEmu::CastingSlot::Gem10;
|
||||||
|
case CastingSlot::Gem11:
|
||||||
|
return EQEmu::CastingSlot::Gem11;
|
||||||
|
case CastingSlot::Gem12:
|
||||||
|
return EQEmu::CastingSlot::Gem12;
|
||||||
|
case CastingSlot::Discipline:
|
||||||
|
return EQEmu::CastingSlot::Discipline;
|
||||||
|
case CastingSlot::Item:
|
||||||
|
return EQEmu::CastingSlot::Item;
|
||||||
|
case CastingSlot::AltAbility:
|
||||||
|
return EQEmu::CastingSlot::AltAbility;
|
||||||
|
default: // we shouldn't have any issues with other slots ... just return something
|
||||||
|
return EQEmu::CastingSlot::Discipline;
|
||||||
|
}
|
||||||
|
}
|
||||||
} /*RoF*/
|
} /*RoF*/
|
||||||
|
|||||||
@ -50,6 +50,24 @@ namespace RoF
|
|||||||
#include "rof_ops.h"
|
#include "rof_ops.h"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CastingSlot : uint32 {
|
||||||
|
Gem1 = 0,
|
||||||
|
Gem2 = 1,
|
||||||
|
Gem3 = 2,
|
||||||
|
Gem4 = 3,
|
||||||
|
Gem5 = 4,
|
||||||
|
Gem6 = 5,
|
||||||
|
Gem7 = 6,
|
||||||
|
Gem8 = 7,
|
||||||
|
Gem9 = 8,
|
||||||
|
Gem10 = 9,
|
||||||
|
Gem11 = 10,
|
||||||
|
Gem12 = 11,
|
||||||
|
Item = 12,
|
||||||
|
Discipline = 13,
|
||||||
|
AltAbility = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
}; /*RoF*/
|
}; /*RoF*/
|
||||||
|
|
||||||
#endif /*COMMON_ROF_H*/
|
#endif /*COMMON_ROF_H*/
|
||||||
|
|||||||
@ -63,6 +63,9 @@ namespace RoF2
|
|||||||
// client to server text link converter
|
// client to server text link converter
|
||||||
static inline void RoF2ToServerTextLink(std::string& serverTextLink, const std::string& rof2TextLink);
|
static inline void RoF2ToServerTextLink(std::string& serverTextLink, const std::string& rof2TextLink);
|
||||||
|
|
||||||
|
static inline CastingSlot ServerToRoF2CastingSlot(EQEmu::CastingSlot slot);
|
||||||
|
static inline EQEmu::CastingSlot RoF2ToServerCastingSlot(CastingSlot slot);
|
||||||
|
|
||||||
void Register(EQStreamIdentifier &into)
|
void Register(EQStreamIdentifier &into)
|
||||||
{
|
{
|
||||||
//create our opcode manager if we havent already
|
//create our opcode manager if we havent already
|
||||||
@ -584,10 +587,7 @@ namespace RoF2
|
|||||||
ENCODE_LENGTH_EXACT(CastSpell_Struct);
|
ENCODE_LENGTH_EXACT(CastSpell_Struct);
|
||||||
SETUP_DIRECT_ENCODE(CastSpell_Struct, structs::CastSpell_Struct);
|
SETUP_DIRECT_ENCODE(CastSpell_Struct, structs::CastSpell_Struct);
|
||||||
|
|
||||||
if (emu->slot == 10)
|
eq->slot = static_cast<uint32>(ServerToRoF2CastingSlot(static_cast<EQEmu::CastingSlot>(emu->slot)));
|
||||||
eq->slot = 13;
|
|
||||||
else
|
|
||||||
OUT(slot);
|
|
||||||
|
|
||||||
OUT(spell_id);
|
OUT(spell_id);
|
||||||
eq->inventory_slot = ServerToRoF2Slot(emu->inventoryslot);
|
eq->inventory_slot = ServerToRoF2Slot(emu->inventoryslot);
|
||||||
@ -1701,7 +1701,8 @@ namespace RoF2
|
|||||||
OUT(new_mana);
|
OUT(new_mana);
|
||||||
OUT(stamina);
|
OUT(stamina);
|
||||||
OUT(spell_id);
|
OUT(spell_id);
|
||||||
eq->unknown16 = -1; // Self Interrupt/Success = -1, Fizzle = 1, Other Interrupt = 2?
|
OUT(keepcasting);
|
||||||
|
eq->slot = -1; // this is spell gem slot. It's -1 in normal operation
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@ -2099,18 +2100,18 @@ namespace RoF2
|
|||||||
__packet->WriteUInt8(1); // 1 indicates all buffs on the pet (0 to add or remove a single buff)
|
__packet->WriteUInt8(1); // 1 indicates all buffs on the pet (0 to add or remove a single buff)
|
||||||
__packet->WriteUInt16(emu->buffcount);
|
__packet->WriteUInt16(emu->buffcount);
|
||||||
|
|
||||||
for (uint16 i = 0; i < BUFF_COUNT; ++i)
|
for (uint16 i = 0; i < PET_BUFF_COUNT; ++i)
|
||||||
{
|
{
|
||||||
if (emu->spellid[i])
|
if (emu->spellid[i])
|
||||||
{
|
{
|
||||||
__packet->WriteUInt32(i);
|
__packet->WriteUInt32(i);
|
||||||
__packet->WriteUInt32(emu->spellid[i]);
|
__packet->WriteUInt32(emu->spellid[i]);
|
||||||
__packet->WriteUInt32(emu->ticsremaining[i]);
|
__packet->WriteUInt32(emu->ticsremaining[i]);
|
||||||
__packet->WriteUInt32(0); // Unknown
|
__packet->WriteUInt32(0); // num hits
|
||||||
__packet->WriteString("");
|
__packet->WriteString("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__packet->WriteUInt8(0); // Unknown
|
__packet->WriteUInt8(0); // some sort of type
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@ -2346,22 +2347,23 @@ namespace RoF2
|
|||||||
|
|
||||||
outapp->WriteUInt32(structs::MAX_PP_MEMSPELL); // Memorised spell slots
|
outapp->WriteUInt32(structs::MAX_PP_MEMSPELL); // Memorised spell slots
|
||||||
|
|
||||||
for (uint32 r = 0; r < MAX_PP_MEMSPELL; r++)
|
for (uint32 r = 0; r < MAX_PP_MEMSPELL; r++) // write first 12
|
||||||
{
|
{
|
||||||
outapp->WriteUInt32(emu->mem_spells[r]);
|
outapp->WriteUInt32(emu->mem_spells[r]);
|
||||||
}
|
}
|
||||||
// zeroes for the rest of the slots
|
// zeroes for the rest of the slots the other 4, which actually don't work on the client at all :D
|
||||||
for (uint32 r = 0; r < structs::MAX_PP_MEMSPELL - MAX_PP_MEMSPELL; r++)
|
for (uint32 r = 0; r < structs::MAX_PP_MEMSPELL - MAX_PP_MEMSPELL; r++)
|
||||||
{
|
{
|
||||||
outapp->WriteUInt32(0xFFFFFFFFU);
|
outapp->WriteUInt32(0xFFFFFFFFU);
|
||||||
}
|
}
|
||||||
|
|
||||||
outapp->WriteUInt32(13); // Unknown count
|
outapp->WriteUInt32(13); // gem refresh counts
|
||||||
|
|
||||||
for (uint32 r = 0; r < 13; r++)
|
for (uint32 r = 0; r < MAX_PP_MEMSPELL; r++)
|
||||||
{
|
{
|
||||||
outapp->WriteUInt32(0); // Unknown
|
outapp->WriteUInt32(emu->spellSlotRefresh[r]); // spell gem refresh
|
||||||
}
|
}
|
||||||
|
outapp->WriteUInt32(0); // also refresh -- historically HT/LoH :P
|
||||||
|
|
||||||
outapp->WriteUInt8(0); // Unknown
|
outapp->WriteUInt8(0); // Unknown
|
||||||
|
|
||||||
@ -4574,10 +4576,7 @@ namespace RoF2
|
|||||||
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
||||||
SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct);
|
SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct);
|
||||||
|
|
||||||
if (eq->slot == 13)
|
emu->slot = static_cast<uint32>(RoF2ToServerCastingSlot(static_cast<CastingSlot>(eq->slot)));
|
||||||
emu->slot = 10;
|
|
||||||
else
|
|
||||||
IN(slot);
|
|
||||||
|
|
||||||
IN(spell_id);
|
IN(spell_id);
|
||||||
emu->inventoryslot = RoF2ToServerSlot(eq->inventory_slot);
|
emu->inventoryslot = RoF2ToServerSlot(eq->inventory_slot);
|
||||||
@ -6314,4 +6313,80 @@ namespace RoF2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline CastingSlot ServerToRoF2CastingSlot(EQEmu::CastingSlot slot)
|
||||||
|
{
|
||||||
|
switch (slot) {
|
||||||
|
case EQEmu::CastingSlot::Gem1:
|
||||||
|
return CastingSlot::Gem1;
|
||||||
|
case EQEmu::CastingSlot::Gem2:
|
||||||
|
return CastingSlot::Gem2;
|
||||||
|
case EQEmu::CastingSlot::Gem3:
|
||||||
|
return CastingSlot::Gem3;
|
||||||
|
case EQEmu::CastingSlot::Gem4:
|
||||||
|
return CastingSlot::Gem4;
|
||||||
|
case EQEmu::CastingSlot::Gem5:
|
||||||
|
return CastingSlot::Gem5;
|
||||||
|
case EQEmu::CastingSlot::Gem6:
|
||||||
|
return CastingSlot::Gem6;
|
||||||
|
case EQEmu::CastingSlot::Gem7:
|
||||||
|
return CastingSlot::Gem7;
|
||||||
|
case EQEmu::CastingSlot::Gem8:
|
||||||
|
return CastingSlot::Gem8;
|
||||||
|
case EQEmu::CastingSlot::Gem9:
|
||||||
|
return CastingSlot::Gem9;
|
||||||
|
case EQEmu::CastingSlot::Gem10:
|
||||||
|
return CastingSlot::Gem10;
|
||||||
|
case EQEmu::CastingSlot::Gem11:
|
||||||
|
return CastingSlot::Gem11;
|
||||||
|
case EQEmu::CastingSlot::Gem12:
|
||||||
|
return CastingSlot::Gem12;
|
||||||
|
case EQEmu::CastingSlot::Item:
|
||||||
|
case EQEmu::CastingSlot::PotionBelt:
|
||||||
|
return CastingSlot::Item;
|
||||||
|
case EQEmu::CastingSlot::Discipline:
|
||||||
|
return CastingSlot::Discipline;
|
||||||
|
case EQEmu::CastingSlot::AltAbility:
|
||||||
|
return CastingSlot::AltAbility;
|
||||||
|
default: // we shouldn't have any issues with other slots ... just return something
|
||||||
|
return CastingSlot::Discipline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline EQEmu::CastingSlot RoF2ToServerCastingSlot(CastingSlot slot)
|
||||||
|
{
|
||||||
|
switch (slot) {
|
||||||
|
case CastingSlot::Gem1:
|
||||||
|
return EQEmu::CastingSlot::Gem1;
|
||||||
|
case CastingSlot::Gem2:
|
||||||
|
return EQEmu::CastingSlot::Gem2;
|
||||||
|
case CastingSlot::Gem3:
|
||||||
|
return EQEmu::CastingSlot::Gem3;
|
||||||
|
case CastingSlot::Gem4:
|
||||||
|
return EQEmu::CastingSlot::Gem4;
|
||||||
|
case CastingSlot::Gem5:
|
||||||
|
return EQEmu::CastingSlot::Gem5;
|
||||||
|
case CastingSlot::Gem6:
|
||||||
|
return EQEmu::CastingSlot::Gem6;
|
||||||
|
case CastingSlot::Gem7:
|
||||||
|
return EQEmu::CastingSlot::Gem7;
|
||||||
|
case CastingSlot::Gem8:
|
||||||
|
return EQEmu::CastingSlot::Gem8;
|
||||||
|
case CastingSlot::Gem9:
|
||||||
|
return EQEmu::CastingSlot::Gem9;
|
||||||
|
case CastingSlot::Gem10:
|
||||||
|
return EQEmu::CastingSlot::Gem10;
|
||||||
|
case CastingSlot::Gem11:
|
||||||
|
return EQEmu::CastingSlot::Gem11;
|
||||||
|
case CastingSlot::Gem12:
|
||||||
|
return EQEmu::CastingSlot::Gem12;
|
||||||
|
case CastingSlot::Discipline:
|
||||||
|
return EQEmu::CastingSlot::Discipline;
|
||||||
|
case CastingSlot::Item:
|
||||||
|
return EQEmu::CastingSlot::Item;
|
||||||
|
case CastingSlot::AltAbility:
|
||||||
|
return EQEmu::CastingSlot::AltAbility;
|
||||||
|
default: // we shouldn't have any issues with other slots ... just return something
|
||||||
|
return EQEmu::CastingSlot::Discipline;
|
||||||
|
}
|
||||||
|
}
|
||||||
} /*RoF2*/
|
} /*RoF2*/
|
||||||
|
|||||||
@ -50,6 +50,24 @@ namespace RoF2
|
|||||||
#include "rof2_ops.h"
|
#include "rof2_ops.h"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CastingSlot : uint32 {
|
||||||
|
Gem1 = 0,
|
||||||
|
Gem2 = 1,
|
||||||
|
Gem3 = 2,
|
||||||
|
Gem4 = 3,
|
||||||
|
Gem5 = 4,
|
||||||
|
Gem6 = 5,
|
||||||
|
Gem7 = 6,
|
||||||
|
Gem8 = 7,
|
||||||
|
Gem9 = 8,
|
||||||
|
Gem10 = 9,
|
||||||
|
Gem11 = 10,
|
||||||
|
Gem12 = 11,
|
||||||
|
Item = 12,
|
||||||
|
Discipline = 13,
|
||||||
|
AltAbility = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
}; /*RoF2*/
|
}; /*RoF2*/
|
||||||
|
|
||||||
#endif /*COMMON_ROF2_H*/
|
#endif /*COMMON_ROF2_H*/
|
||||||
|
|||||||
@ -635,7 +635,7 @@ struct MemorizeSpell_Struct {
|
|||||||
uint32 slot; // Spot in the spell book/memorized slot
|
uint32 slot; // Spot in the spell book/memorized slot
|
||||||
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
||||||
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
||||||
uint32 unknown12;
|
uint32 reduction; // lowers reuse
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -668,11 +668,12 @@ struct DeleteSpell_Struct
|
|||||||
|
|
||||||
struct ManaChange_Struct
|
struct ManaChange_Struct
|
||||||
{
|
{
|
||||||
uint32 new_mana; // New Mana AMount
|
/*00*/ uint32 new_mana; // New Mana AMount
|
||||||
uint32 stamina;
|
/*04*/ uint32 stamina;
|
||||||
uint32 spell_id;
|
/*08*/ uint32 spell_id;
|
||||||
uint32 unknown12;
|
/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting?
|
||||||
uint32 unknown16;
|
/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like
|
||||||
|
/*16*/ int32 slot; // -1 for normal usage slot for when we want silent interrupt? I think it does timer stuff or something. Linked Spell Reuse interrupt uses it
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwapSpell_Struct
|
struct SwapSpell_Struct
|
||||||
|
|||||||
@ -624,7 +624,7 @@ struct MemorizeSpell_Struct {
|
|||||||
uint32 slot; // Spot in the spell book/memorized slot
|
uint32 slot; // Spot in the spell book/memorized slot
|
||||||
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
||||||
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
||||||
uint32 unknown12;
|
uint32 reduction; // lowers reuse
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -657,11 +657,12 @@ struct DeleteSpell_Struct
|
|||||||
|
|
||||||
struct ManaChange_Struct
|
struct ManaChange_Struct
|
||||||
{
|
{
|
||||||
uint32 new_mana; // New Mana AMount
|
/*00*/ uint32 new_mana; // New Mana AMount
|
||||||
uint32 stamina;
|
/*04*/ uint32 stamina;
|
||||||
uint32 spell_id;
|
/*08*/ uint32 spell_id;
|
||||||
uint32 unknown12;
|
/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting?
|
||||||
uint32 unknown16;
|
/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like
|
||||||
|
/*16*/ int32 slot; // -1 for normal usage slot for when we want silent interrupt? I think it does timer stuff or something. Linked Spell Reuse interrupt uses it
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwapSpell_Struct
|
struct SwapSpell_Struct
|
||||||
|
|||||||
@ -59,6 +59,9 @@ namespace SoD
|
|||||||
// client to server text link converter
|
// client to server text link converter
|
||||||
static inline void SoDToServerTextLink(std::string& serverTextLink, const std::string& sodTextLink);
|
static inline void SoDToServerTextLink(std::string& serverTextLink, const std::string& sodTextLink);
|
||||||
|
|
||||||
|
static inline CastingSlot ServerToSoDCastingSlot(EQEmu::CastingSlot slot);
|
||||||
|
static inline EQEmu::CastingSlot SoDToServerCastingSlot(CastingSlot slot);
|
||||||
|
|
||||||
void Register(EQStreamIdentifier &into)
|
void Register(EQStreamIdentifier &into)
|
||||||
{
|
{
|
||||||
//create our opcode manager if we havent already
|
//create our opcode manager if we havent already
|
||||||
@ -1136,7 +1139,8 @@ namespace SoD
|
|||||||
OUT(new_mana);
|
OUT(new_mana);
|
||||||
OUT(stamina);
|
OUT(stamina);
|
||||||
OUT(spell_id);
|
OUT(spell_id);
|
||||||
eq->unknown16 = -1; // Self Interrupt/Success = -1, Fizzle = 1, Other Interrupt = 2?
|
OUT(keepcasting);
|
||||||
|
eq->slot = -1; // this is spell gem slot. It's -1 in normal operation
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@ -1499,7 +1503,7 @@ namespace SoD
|
|||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petid);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petid);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, emu->buffcount);
|
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, emu->buffcount);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < BUFF_COUNT; ++i)
|
for (unsigned int i = 0; i < PET_BUFF_COUNT; ++i)
|
||||||
{
|
{
|
||||||
if (emu->spellid[i])
|
if (emu->spellid[i])
|
||||||
{
|
{
|
||||||
@ -1510,7 +1514,7 @@ namespace SoD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->buffcount);
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->buffcount); // I think this is actually some sort of type
|
||||||
|
|
||||||
delete[] __emu_buffer;
|
delete[] __emu_buffer;
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
@ -2948,6 +2952,7 @@ namespace SoD
|
|||||||
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
||||||
SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct);
|
SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct);
|
||||||
|
|
||||||
|
emu->slot = static_cast<uint32>(SoDToServerCastingSlot(static_cast<CastingSlot>(eq->slot)));
|
||||||
IN(slot);
|
IN(slot);
|
||||||
IN(spell_id);
|
IN(spell_id);
|
||||||
emu->inventoryslot = SoDToServerSlot(eq->inventoryslot);
|
emu->inventoryslot = SoDToServerSlot(eq->inventoryslot);
|
||||||
@ -4013,4 +4018,72 @@ namespace SoD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline CastingSlot ServerToSoDCastingSlot(EQEmu::CastingSlot slot)
|
||||||
|
{
|
||||||
|
switch (slot) {
|
||||||
|
case EQEmu::CastingSlot::Gem1:
|
||||||
|
return CastingSlot::Gem1;
|
||||||
|
case EQEmu::CastingSlot::Gem2:
|
||||||
|
return CastingSlot::Gem2;
|
||||||
|
case EQEmu::CastingSlot::Gem3:
|
||||||
|
return CastingSlot::Gem3;
|
||||||
|
case EQEmu::CastingSlot::Gem4:
|
||||||
|
return CastingSlot::Gem4;
|
||||||
|
case EQEmu::CastingSlot::Gem5:
|
||||||
|
return CastingSlot::Gem5;
|
||||||
|
case EQEmu::CastingSlot::Gem6:
|
||||||
|
return CastingSlot::Gem6;
|
||||||
|
case EQEmu::CastingSlot::Gem7:
|
||||||
|
return CastingSlot::Gem7;
|
||||||
|
case EQEmu::CastingSlot::Gem8:
|
||||||
|
return CastingSlot::Gem8;
|
||||||
|
case EQEmu::CastingSlot::Gem9:
|
||||||
|
return CastingSlot::Gem9;
|
||||||
|
case EQEmu::CastingSlot::Gem10:
|
||||||
|
return CastingSlot::Gem10;
|
||||||
|
case EQEmu::CastingSlot::Item:
|
||||||
|
case EQEmu::CastingSlot::PotionBelt:
|
||||||
|
return CastingSlot::Item;
|
||||||
|
case EQEmu::CastingSlot::Discipline:
|
||||||
|
return CastingSlot::Discipline;
|
||||||
|
case EQEmu::CastingSlot::AltAbility:
|
||||||
|
return CastingSlot::AltAbility;
|
||||||
|
default: // we shouldn't have any issues with other slots ... just return something
|
||||||
|
return CastingSlot::Discipline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline EQEmu::CastingSlot SoDToServerCastingSlot(CastingSlot slot)
|
||||||
|
{
|
||||||
|
switch (slot) {
|
||||||
|
case CastingSlot::Gem1:
|
||||||
|
return EQEmu::CastingSlot::Gem1;
|
||||||
|
case CastingSlot::Gem2:
|
||||||
|
return EQEmu::CastingSlot::Gem2;
|
||||||
|
case CastingSlot::Gem3:
|
||||||
|
return EQEmu::CastingSlot::Gem3;
|
||||||
|
case CastingSlot::Gem4:
|
||||||
|
return EQEmu::CastingSlot::Gem4;
|
||||||
|
case CastingSlot::Gem5:
|
||||||
|
return EQEmu::CastingSlot::Gem5;
|
||||||
|
case CastingSlot::Gem6:
|
||||||
|
return EQEmu::CastingSlot::Gem6;
|
||||||
|
case CastingSlot::Gem7:
|
||||||
|
return EQEmu::CastingSlot::Gem7;
|
||||||
|
case CastingSlot::Gem8:
|
||||||
|
return EQEmu::CastingSlot::Gem8;
|
||||||
|
case CastingSlot::Gem9:
|
||||||
|
return EQEmu::CastingSlot::Gem9;
|
||||||
|
case CastingSlot::Gem10:
|
||||||
|
return EQEmu::CastingSlot::Gem10;
|
||||||
|
case CastingSlot::Discipline:
|
||||||
|
return EQEmu::CastingSlot::Discipline;
|
||||||
|
case CastingSlot::Item:
|
||||||
|
return EQEmu::CastingSlot::Item;
|
||||||
|
case CastingSlot::AltAbility:
|
||||||
|
return EQEmu::CastingSlot::AltAbility;
|
||||||
|
default: // we shouldn't have any issues with other slots ... just return something
|
||||||
|
return EQEmu::CastingSlot::Discipline;
|
||||||
|
}
|
||||||
|
}
|
||||||
} /*SoD*/
|
} /*SoD*/
|
||||||
|
|||||||
@ -50,6 +50,22 @@ namespace SoD
|
|||||||
#include "sod_ops.h"
|
#include "sod_ops.h"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CastingSlot : uint32 {
|
||||||
|
Gem1 = 0,
|
||||||
|
Gem2 = 1,
|
||||||
|
Gem3 = 2,
|
||||||
|
Gem4 = 3,
|
||||||
|
Gem5 = 4,
|
||||||
|
Gem6 = 5,
|
||||||
|
Gem7 = 6,
|
||||||
|
Gem8 = 7,
|
||||||
|
Gem9 = 8,
|
||||||
|
Gem10 = 9,
|
||||||
|
Item = 10,
|
||||||
|
Discipline = 11,
|
||||||
|
AltAbility = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
}; /*SoD*/
|
}; /*SoD*/
|
||||||
|
|
||||||
#endif /*COMMON_SOD_H*/
|
#endif /*COMMON_SOD_H*/
|
||||||
|
|||||||
@ -479,7 +479,7 @@ struct MemorizeSpell_Struct {
|
|||||||
uint32 slot; // Spot in the spell book/memorized slot
|
uint32 slot; // Spot in the spell book/memorized slot
|
||||||
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
||||||
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
||||||
//uint32 unknown12;
|
uint32 reduction; // lowers reuse
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -512,11 +512,12 @@ struct DeleteSpell_Struct
|
|||||||
|
|
||||||
struct ManaChange_Struct
|
struct ManaChange_Struct
|
||||||
{
|
{
|
||||||
uint32 new_mana; // New Mana AMount
|
/*00*/ uint32 new_mana; // New Mana AMount
|
||||||
uint32 stamina;
|
/*04*/ uint32 stamina;
|
||||||
uint32 spell_id;
|
/*08*/ uint32 spell_id;
|
||||||
uint32 unknown12;
|
/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting?
|
||||||
uint32 unknown16;
|
/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like
|
||||||
|
/*16*/ int32 slot; // -1 for normal usage slot for when we want silent interrupt? I think it does timer stuff or something. Linked Spell Reuse interrupt uses it
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwapSpell_Struct
|
struct SwapSpell_Struct
|
||||||
|
|||||||
@ -59,6 +59,9 @@ namespace SoF
|
|||||||
// client to server text link converter
|
// client to server text link converter
|
||||||
static inline void SoFToServerTextLink(std::string& serverTextLink, const std::string& sofTextLink);
|
static inline void SoFToServerTextLink(std::string& serverTextLink, const std::string& sofTextLink);
|
||||||
|
|
||||||
|
static inline CastingSlot ServerToSoFCastingSlot(EQEmu::CastingSlot slot);
|
||||||
|
static inline EQEmu::CastingSlot SoFToServerCastingSlot(CastingSlot slot, uint32 itemlocation);
|
||||||
|
|
||||||
void Register(EQStreamIdentifier &into)
|
void Register(EQStreamIdentifier &into)
|
||||||
{
|
{
|
||||||
//create our opcode manager if we havent already
|
//create our opcode manager if we havent already
|
||||||
@ -933,7 +936,24 @@ namespace SoF
|
|||||||
OUT(new_mana);
|
OUT(new_mana);
|
||||||
OUT(stamina);
|
OUT(stamina);
|
||||||
OUT(spell_id);
|
OUT(spell_id);
|
||||||
eq->unknown16 = -1; // Self Interrupt/Success = -1, Fizzle = 1, Other Interrupt = 2?
|
OUT(keepcasting);
|
||||||
|
eq->slot = -1; // this is spell gem slot. It's -1 in normal operation
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
}
|
||||||
|
|
||||||
|
ENCODE(OP_MemorizeSpell)
|
||||||
|
{
|
||||||
|
ENCODE_LENGTH_EXACT(MemorizeSpell_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(MemorizeSpell_Struct, structs::MemorizeSpell_Struct);
|
||||||
|
|
||||||
|
// Since HT/LoH are translated up, we need to translate down only for memSpellSpellbar case
|
||||||
|
if (emu->scribing == 3)
|
||||||
|
eq->slot = static_cast<uint32>(ServerToSoFCastingSlot(static_cast<EQEmu::CastingSlot>(emu->slot)));
|
||||||
|
else
|
||||||
|
OUT(slot);
|
||||||
|
OUT(spell_id);
|
||||||
|
OUT(scribing);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@ -1158,9 +1178,9 @@ namespace SoF
|
|||||||
OUT(petid);
|
OUT(petid);
|
||||||
OUT(buffcount);
|
OUT(buffcount);
|
||||||
|
|
||||||
int EQBuffSlot = 0;
|
int EQBuffSlot = 0; // do we really want to shuffle them around like this?
|
||||||
|
|
||||||
for (uint32 EmuBuffSlot = 0; EmuBuffSlot < BUFF_COUNT; ++EmuBuffSlot)
|
for (uint32 EmuBuffSlot = 0; EmuBuffSlot < PET_BUFF_COUNT; ++EmuBuffSlot)
|
||||||
{
|
{
|
||||||
if (emu->spellid[EmuBuffSlot])
|
if (emu->spellid[EmuBuffSlot])
|
||||||
{
|
{
|
||||||
@ -2366,7 +2386,7 @@ namespace SoF
|
|||||||
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
||||||
SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct);
|
SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct);
|
||||||
|
|
||||||
IN(slot);
|
emu->slot = static_cast<uint32>(SoFToServerCastingSlot(static_cast<CastingSlot>(eq->slot), eq->inventoryslot));
|
||||||
IN(spell_id);
|
IN(spell_id);
|
||||||
emu->inventoryslot = SoFToServerSlot(eq->inventoryslot);
|
emu->inventoryslot = SoFToServerSlot(eq->inventoryslot);
|
||||||
IN(target_id);
|
IN(target_id);
|
||||||
@ -3355,4 +3375,75 @@ namespace SoF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline CastingSlot ServerToSoFCastingSlot(EQEmu::CastingSlot slot)
|
||||||
|
{
|
||||||
|
switch (slot) {
|
||||||
|
case EQEmu::CastingSlot::Gem1:
|
||||||
|
return CastingSlot::Gem1;
|
||||||
|
case EQEmu::CastingSlot::Gem2:
|
||||||
|
return CastingSlot::Gem2;
|
||||||
|
case EQEmu::CastingSlot::Gem3:
|
||||||
|
return CastingSlot::Gem3;
|
||||||
|
case EQEmu::CastingSlot::Gem4:
|
||||||
|
return CastingSlot::Gem4;
|
||||||
|
case EQEmu::CastingSlot::Gem5:
|
||||||
|
return CastingSlot::Gem5;
|
||||||
|
case EQEmu::CastingSlot::Gem6:
|
||||||
|
return CastingSlot::Gem6;
|
||||||
|
case EQEmu::CastingSlot::Gem7:
|
||||||
|
return CastingSlot::Gem7;
|
||||||
|
case EQEmu::CastingSlot::Gem8:
|
||||||
|
return CastingSlot::Gem8;
|
||||||
|
case EQEmu::CastingSlot::Gem9:
|
||||||
|
return CastingSlot::Gem9;
|
||||||
|
case EQEmu::CastingSlot::Item:
|
||||||
|
return CastingSlot::Item;
|
||||||
|
case EQEmu::CastingSlot::PotionBelt:
|
||||||
|
return CastingSlot::PotionBelt;
|
||||||
|
case EQEmu::CastingSlot::Discipline:
|
||||||
|
return CastingSlot::Discipline;
|
||||||
|
case EQEmu::CastingSlot::AltAbility:
|
||||||
|
return CastingSlot::AltAbility;
|
||||||
|
default: // we shouldn't have any issues with other slots ... just return something
|
||||||
|
return CastingSlot::Discipline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline EQEmu::CastingSlot SoFToServerCastingSlot(CastingSlot slot, uint32 itemlocation)
|
||||||
|
{
|
||||||
|
switch (slot) {
|
||||||
|
case CastingSlot::Gem1:
|
||||||
|
return EQEmu::CastingSlot::Gem1;
|
||||||
|
case CastingSlot::Gem2:
|
||||||
|
return EQEmu::CastingSlot::Gem2;
|
||||||
|
case CastingSlot::Gem3:
|
||||||
|
return EQEmu::CastingSlot::Gem3;
|
||||||
|
case CastingSlot::Gem4:
|
||||||
|
return EQEmu::CastingSlot::Gem4;
|
||||||
|
case CastingSlot::Gem5:
|
||||||
|
return EQEmu::CastingSlot::Gem5;
|
||||||
|
case CastingSlot::Gem6:
|
||||||
|
return EQEmu::CastingSlot::Gem6;
|
||||||
|
case CastingSlot::Gem7:
|
||||||
|
return EQEmu::CastingSlot::Gem7;
|
||||||
|
case CastingSlot::Gem8:
|
||||||
|
return EQEmu::CastingSlot::Gem8;
|
||||||
|
case CastingSlot::Gem9:
|
||||||
|
return EQEmu::CastingSlot::Gem9;
|
||||||
|
case CastingSlot::Ability:
|
||||||
|
return EQEmu::CastingSlot::Ability;
|
||||||
|
// Tit uses 10 for item and discipline casting, but items have a valid location
|
||||||
|
case CastingSlot::Item:
|
||||||
|
if (itemlocation == INVALID_INDEX)
|
||||||
|
return EQEmu::CastingSlot::Discipline;
|
||||||
|
else
|
||||||
|
return EQEmu::CastingSlot::Item;
|
||||||
|
case CastingSlot::PotionBelt:
|
||||||
|
return EQEmu::CastingSlot::PotionBelt;
|
||||||
|
case CastingSlot::AltAbility:
|
||||||
|
return EQEmu::CastingSlot::AltAbility;
|
||||||
|
default: // we shouldn't have any issues with other slots ... just return something
|
||||||
|
return EQEmu::CastingSlot::Discipline;
|
||||||
|
}
|
||||||
|
}
|
||||||
} /*SoF*/
|
} /*SoF*/
|
||||||
|
|||||||
@ -50,6 +50,23 @@ namespace SoF
|
|||||||
#include "sof_ops.h"
|
#include "sof_ops.h"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CastingSlot : uint32 {
|
||||||
|
Gem1 = 0,
|
||||||
|
Gem2 = 1,
|
||||||
|
Gem3 = 2,
|
||||||
|
Gem4 = 3,
|
||||||
|
Gem5 = 4,
|
||||||
|
Gem6 = 5,
|
||||||
|
Gem7 = 6,
|
||||||
|
Gem8 = 7,
|
||||||
|
Gem9 = 8,
|
||||||
|
Ability = 9,
|
||||||
|
Item = 10,
|
||||||
|
Discipline = 10,
|
||||||
|
PotionBelt = 11,
|
||||||
|
AltAbility = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
}; /*SoF*/
|
}; /*SoF*/
|
||||||
|
|
||||||
#endif /*COMMON_SOF_H*/
|
#endif /*COMMON_SOF_H*/
|
||||||
|
|||||||
@ -57,6 +57,7 @@ E(OP_LeadershipExpUpdate)
|
|||||||
E(OP_LogServer)
|
E(OP_LogServer)
|
||||||
E(OP_LootItem)
|
E(OP_LootItem)
|
||||||
E(OP_ManaChange)
|
E(OP_ManaChange)
|
||||||
|
E(OP_MemorizeSpell)
|
||||||
E(OP_MoveItem)
|
E(OP_MoveItem)
|
||||||
E(OP_NewSpawn)
|
E(OP_NewSpawn)
|
||||||
E(OP_NewZone)
|
E(OP_NewZone)
|
||||||
|
|||||||
@ -458,7 +458,7 @@ struct MemorizeSpell_Struct {
|
|||||||
uint32 slot; // Spot in the spell book/memorized slot
|
uint32 slot; // Spot in the spell book/memorized slot
|
||||||
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
||||||
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
||||||
//uint32 unknown12;
|
uint32 reduction; // lowers reuse
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -491,11 +491,12 @@ struct DeleteSpell_Struct
|
|||||||
|
|
||||||
struct ManaChange_Struct
|
struct ManaChange_Struct
|
||||||
{
|
{
|
||||||
uint32 new_mana; // New Mana AMount
|
/*00*/ uint32 new_mana; // New Mana AMount
|
||||||
uint32 stamina;
|
/*04*/ uint32 stamina;
|
||||||
uint32 spell_id;
|
/*08*/ uint32 spell_id;
|
||||||
uint32 unknown12;
|
/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting?
|
||||||
uint32 unknown16;
|
/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like
|
||||||
|
/*16*/ int32 slot; // -1 for normal usage slot for when we want silent interrupt? I think it does timer stuff or something. Linked Spell Reuse interrupt uses it
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwapSpell_Struct
|
struct SwapSpell_Struct
|
||||||
|
|||||||
@ -58,6 +58,9 @@ namespace Titanium
|
|||||||
// client to server text link converter
|
// client to server text link converter
|
||||||
static inline void TitaniumToServerTextLink(std::string& serverTextLink, const std::string& titaniumTextLink);
|
static inline void TitaniumToServerTextLink(std::string& serverTextLink, const std::string& titaniumTextLink);
|
||||||
|
|
||||||
|
static inline CastingSlot ServerToTitaniumCastingSlot(EQEmu::CastingSlot slot);
|
||||||
|
static inline EQEmu::CastingSlot TitaniumToServerCastingSlot(CastingSlot slot, uint32 itemlocation);
|
||||||
|
|
||||||
void Register(EQStreamIdentifier &into)
|
void Register(EQStreamIdentifier &into)
|
||||||
{
|
{
|
||||||
auto Config = EQEmuConfig::get();
|
auto Config = EQEmuConfig::get();
|
||||||
@ -833,6 +836,22 @@ namespace Titanium
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ENCODE(OP_MemorizeSpell)
|
||||||
|
{
|
||||||
|
ENCODE_LENGTH_EXACT(MemorizeSpell_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(MemorizeSpell_Struct, structs::MemorizeSpell_Struct);
|
||||||
|
|
||||||
|
// Since HT/LoH are translated up, we need to translate down only for memSpellSpellbar case
|
||||||
|
if (emu->scribing == 3)
|
||||||
|
eq->slot = static_cast<uint32>(ServerToTitaniumCastingSlot(static_cast<EQEmu::CastingSlot>(emu->slot)));
|
||||||
|
else
|
||||||
|
OUT(slot);
|
||||||
|
OUT(spell_id);
|
||||||
|
OUT(scribing);
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
}
|
||||||
|
|
||||||
ENCODE(OP_MoveItem)
|
ENCODE(OP_MoveItem)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(MoveItem_Struct);
|
ENCODE_LENGTH_EXACT(MoveItem_Struct);
|
||||||
@ -872,9 +891,9 @@ namespace Titanium
|
|||||||
OUT(petid);
|
OUT(petid);
|
||||||
OUT(buffcount);
|
OUT(buffcount);
|
||||||
|
|
||||||
int EQBuffSlot = 0;
|
int EQBuffSlot = 0; // do we really want to shuffle them around like this?
|
||||||
|
|
||||||
for (uint32 EmuBuffSlot = 0; EmuBuffSlot < BUFF_COUNT; ++EmuBuffSlot)
|
for (uint32 EmuBuffSlot = 0; EmuBuffSlot < PET_BUFF_COUNT; ++EmuBuffSlot)
|
||||||
{
|
{
|
||||||
if (emu->spellid[EmuBuffSlot])
|
if (emu->spellid[EmuBuffSlot])
|
||||||
{
|
{
|
||||||
@ -1731,7 +1750,7 @@ namespace Titanium
|
|||||||
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
||||||
SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct);
|
SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct);
|
||||||
|
|
||||||
IN(slot);
|
emu->slot = static_cast<uint32>(TitaniumToServerCastingSlot(static_cast<CastingSlot>(eq->slot), eq->inventoryslot));
|
||||||
IN(spell_id);
|
IN(spell_id);
|
||||||
emu->inventoryslot = TitaniumToServerSlot(eq->inventoryslot);
|
emu->inventoryslot = TitaniumToServerSlot(eq->inventoryslot);
|
||||||
IN(target_id);
|
IN(target_id);
|
||||||
@ -2487,4 +2506,75 @@ namespace Titanium
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline CastingSlot ServerToTitaniumCastingSlot(EQEmu::CastingSlot slot)
|
||||||
|
{
|
||||||
|
switch (slot) {
|
||||||
|
case EQEmu::CastingSlot::Gem1:
|
||||||
|
return CastingSlot::Gem1;
|
||||||
|
case EQEmu::CastingSlot::Gem2:
|
||||||
|
return CastingSlot::Gem2;
|
||||||
|
case EQEmu::CastingSlot::Gem3:
|
||||||
|
return CastingSlot::Gem3;
|
||||||
|
case EQEmu::CastingSlot::Gem4:
|
||||||
|
return CastingSlot::Gem4;
|
||||||
|
case EQEmu::CastingSlot::Gem5:
|
||||||
|
return CastingSlot::Gem5;
|
||||||
|
case EQEmu::CastingSlot::Gem6:
|
||||||
|
return CastingSlot::Gem6;
|
||||||
|
case EQEmu::CastingSlot::Gem7:
|
||||||
|
return CastingSlot::Gem7;
|
||||||
|
case EQEmu::CastingSlot::Gem8:
|
||||||
|
return CastingSlot::Gem8;
|
||||||
|
case EQEmu::CastingSlot::Gem9:
|
||||||
|
return CastingSlot::Gem9;
|
||||||
|
case EQEmu::CastingSlot::Item:
|
||||||
|
return CastingSlot::Item;
|
||||||
|
case EQEmu::CastingSlot::PotionBelt:
|
||||||
|
return CastingSlot::PotionBelt;
|
||||||
|
case EQEmu::CastingSlot::Discipline:
|
||||||
|
return CastingSlot::Discipline;
|
||||||
|
case EQEmu::CastingSlot::AltAbility:
|
||||||
|
return CastingSlot::AltAbility;
|
||||||
|
default: // we shouldn't have any issues with other slots ... just return something
|
||||||
|
return CastingSlot::Discipline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline EQEmu::CastingSlot TitaniumToServerCastingSlot(CastingSlot slot, uint32 itemlocation)
|
||||||
|
{
|
||||||
|
switch (slot) {
|
||||||
|
case CastingSlot::Gem1:
|
||||||
|
return EQEmu::CastingSlot::Gem1;
|
||||||
|
case CastingSlot::Gem2:
|
||||||
|
return EQEmu::CastingSlot::Gem2;
|
||||||
|
case CastingSlot::Gem3:
|
||||||
|
return EQEmu::CastingSlot::Gem3;
|
||||||
|
case CastingSlot::Gem4:
|
||||||
|
return EQEmu::CastingSlot::Gem4;
|
||||||
|
case CastingSlot::Gem5:
|
||||||
|
return EQEmu::CastingSlot::Gem5;
|
||||||
|
case CastingSlot::Gem6:
|
||||||
|
return EQEmu::CastingSlot::Gem6;
|
||||||
|
case CastingSlot::Gem7:
|
||||||
|
return EQEmu::CastingSlot::Gem7;
|
||||||
|
case CastingSlot::Gem8:
|
||||||
|
return EQEmu::CastingSlot::Gem8;
|
||||||
|
case CastingSlot::Gem9:
|
||||||
|
return EQEmu::CastingSlot::Gem9;
|
||||||
|
case CastingSlot::Ability:
|
||||||
|
return EQEmu::CastingSlot::Ability;
|
||||||
|
// Tit uses 10 for item and discipline casting, but items have a valid location
|
||||||
|
case CastingSlot::Item:
|
||||||
|
if (itemlocation == INVALID_INDEX)
|
||||||
|
return EQEmu::CastingSlot::Discipline;
|
||||||
|
else
|
||||||
|
return EQEmu::CastingSlot::Item;
|
||||||
|
case CastingSlot::PotionBelt:
|
||||||
|
return EQEmu::CastingSlot::PotionBelt;
|
||||||
|
case CastingSlot::AltAbility:
|
||||||
|
return EQEmu::CastingSlot::AltAbility;
|
||||||
|
default: // we shouldn't have any issues with other slots ... just return something
|
||||||
|
return EQEmu::CastingSlot::Discipline;
|
||||||
|
}
|
||||||
|
}
|
||||||
} /*Titanium*/
|
} /*Titanium*/
|
||||||
|
|||||||
@ -50,6 +50,23 @@ namespace Titanium
|
|||||||
#include "titanium_ops.h"
|
#include "titanium_ops.h"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CastingSlot : uint32 {
|
||||||
|
Gem1 = 0,
|
||||||
|
Gem2 = 1,
|
||||||
|
Gem3 = 2,
|
||||||
|
Gem4 = 3,
|
||||||
|
Gem5 = 4,
|
||||||
|
Gem6 = 5,
|
||||||
|
Gem7 = 6,
|
||||||
|
Gem8 = 7,
|
||||||
|
Gem9 = 8,
|
||||||
|
Ability = 9,
|
||||||
|
Item = 10,
|
||||||
|
Discipline = 10,
|
||||||
|
PotionBelt = 11,
|
||||||
|
AltAbility = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
}; /*Titanium*/
|
}; /*Titanium*/
|
||||||
|
|
||||||
#endif /*COMMON_TITANIUM_H*/
|
#endif /*COMMON_TITANIUM_H*/
|
||||||
|
|||||||
@ -50,6 +50,7 @@ E(OP_ItemPacket)
|
|||||||
E(OP_LeadershipExpUpdate)
|
E(OP_LeadershipExpUpdate)
|
||||||
E(OP_LFGuild)
|
E(OP_LFGuild)
|
||||||
E(OP_LootItem)
|
E(OP_LootItem)
|
||||||
|
E(OP_MemorizeSpell)
|
||||||
E(OP_MoveItem)
|
E(OP_MoveItem)
|
||||||
E(OP_OnLevelMessage)
|
E(OP_OnLevelMessage)
|
||||||
E(OP_PetBuffWindow)
|
E(OP_PetBuffWindow)
|
||||||
|
|||||||
@ -390,7 +390,7 @@ struct MemorizeSpell_Struct {
|
|||||||
uint32 slot; // Spot in the spell book/memorized slot
|
uint32 slot; // Spot in the spell book/memorized slot
|
||||||
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
||||||
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
||||||
uint32 unknown12;
|
uint32 reduction; // lowers reuse
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -420,13 +420,13 @@ struct DeleteSpell_Struct
|
|||||||
/*005*/uint8 unknowndss006[3];
|
/*005*/uint8 unknowndss006[3];
|
||||||
/*008*/
|
/*008*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ManaChange_Struct
|
struct ManaChange_Struct
|
||||||
{
|
{
|
||||||
uint32 new_mana; // New Mana AMount
|
/*00*/ uint32 new_mana; // New Mana AMount
|
||||||
uint32 stamina;
|
/*04*/ uint32 stamina;
|
||||||
uint32 spell_id;
|
/*08*/ uint32 spell_id;
|
||||||
uint32 unknown12;
|
/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting?
|
||||||
|
/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwapSpell_Struct
|
struct SwapSpell_Struct
|
||||||
|
|||||||
@ -59,6 +59,9 @@ namespace UF
|
|||||||
// client to server text link converter
|
// client to server text link converter
|
||||||
static inline void UFToServerTextLink(std::string& serverTextLink, const std::string& ufTextLink);
|
static inline void UFToServerTextLink(std::string& serverTextLink, const std::string& ufTextLink);
|
||||||
|
|
||||||
|
static inline CastingSlot ServerToUFCastingSlot(EQEmu::CastingSlot slot);
|
||||||
|
static inline EQEmu::CastingSlot UFToServerCastingSlot(CastingSlot slot);
|
||||||
|
|
||||||
void Register(EQStreamIdentifier &into)
|
void Register(EQStreamIdentifier &into)
|
||||||
{
|
{
|
||||||
//create our opcode manager if we havent already
|
//create our opcode manager if we havent already
|
||||||
@ -1383,7 +1386,8 @@ namespace UF
|
|||||||
OUT(new_mana);
|
OUT(new_mana);
|
||||||
OUT(stamina);
|
OUT(stamina);
|
||||||
OUT(spell_id);
|
OUT(spell_id);
|
||||||
eq->unknown16 = -1; // Self Interrupt/Success = -1, Fizzle = 1, Other Interrupt = 2?
|
OUT(keepcasting);
|
||||||
|
eq->slot = -1; // this is spell gem slot. It's -1 in normal operation
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@ -1761,18 +1765,18 @@ namespace UF
|
|||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 1);
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 1);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, emu->buffcount);
|
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, emu->buffcount);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < BUFF_COUNT; ++i)
|
for (unsigned int i = 0; i < PET_BUFF_COUNT; ++i)
|
||||||
{
|
{
|
||||||
if (emu->spellid[i])
|
if (emu->spellid[i])
|
||||||
{
|
{
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, i);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, i);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->spellid[i]);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->spellid[i]);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->ticsremaining[i]);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->ticsremaining[i]);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // numhits
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // This is a string. Name of the caster of the buff.
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // This is a string. Name of the caster of the buff.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->buffcount);
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->buffcount); /// I think this is actually some sort of type
|
||||||
|
|
||||||
delete[] __emu_buffer;
|
delete[] __emu_buffer;
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
@ -1867,7 +1871,7 @@ namespace UF
|
|||||||
OUT(thirst_level);
|
OUT(thirst_level);
|
||||||
OUT(hunger_level);
|
OUT(hunger_level);
|
||||||
//PS this needs to be figured out more; but it was 'good enough'
|
//PS this needs to be figured out more; but it was 'good enough'
|
||||||
for (r = 0; r < structs::BUFF_COUNT; r++)
|
for (r = 0; r < BUFF_COUNT; r++)
|
||||||
{
|
{
|
||||||
if (emu->buffs[r].spellid != 0xFFFF && emu->buffs[r].spellid != 0)
|
if (emu->buffs[r].spellid != 0xFFFF && emu->buffs[r].spellid != 0)
|
||||||
{
|
{
|
||||||
@ -3259,10 +3263,7 @@ namespace UF
|
|||||||
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
||||||
SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct);
|
SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct);
|
||||||
|
|
||||||
if (eq->slot == 13)
|
emu->slot = static_cast<uint32>(UFToServerCastingSlot(static_cast<CastingSlot>(eq->slot)));
|
||||||
emu->slot = 10;
|
|
||||||
else
|
|
||||||
IN(slot);
|
|
||||||
|
|
||||||
IN(spell_id);
|
IN(spell_id);
|
||||||
emu->inventoryslot = UFToServerSlot(eq->inventoryslot);
|
emu->inventoryslot = UFToServerSlot(eq->inventoryslot);
|
||||||
@ -4378,4 +4379,80 @@ namespace UF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline CastingSlot ServerToUFCastingSlot(EQEmu::CastingSlot slot)
|
||||||
|
{
|
||||||
|
switch (slot) {
|
||||||
|
case EQEmu::CastingSlot::Gem1:
|
||||||
|
return CastingSlot::Gem1;
|
||||||
|
case EQEmu::CastingSlot::Gem2:
|
||||||
|
return CastingSlot::Gem2;
|
||||||
|
case EQEmu::CastingSlot::Gem3:
|
||||||
|
return CastingSlot::Gem3;
|
||||||
|
case EQEmu::CastingSlot::Gem4:
|
||||||
|
return CastingSlot::Gem4;
|
||||||
|
case EQEmu::CastingSlot::Gem5:
|
||||||
|
return CastingSlot::Gem5;
|
||||||
|
case EQEmu::CastingSlot::Gem6:
|
||||||
|
return CastingSlot::Gem6;
|
||||||
|
case EQEmu::CastingSlot::Gem7:
|
||||||
|
return CastingSlot::Gem7;
|
||||||
|
case EQEmu::CastingSlot::Gem8:
|
||||||
|
return CastingSlot::Gem8;
|
||||||
|
case EQEmu::CastingSlot::Gem9:
|
||||||
|
return CastingSlot::Gem9;
|
||||||
|
case EQEmu::CastingSlot::Gem10:
|
||||||
|
return CastingSlot::Gem10;
|
||||||
|
case EQEmu::CastingSlot::Gem11:
|
||||||
|
return CastingSlot::Gem11;
|
||||||
|
case EQEmu::CastingSlot::Gem12:
|
||||||
|
return CastingSlot::Gem12;
|
||||||
|
case EQEmu::CastingSlot::Item:
|
||||||
|
case EQEmu::CastingSlot::PotionBelt:
|
||||||
|
return CastingSlot::Item;
|
||||||
|
case EQEmu::CastingSlot::Discipline:
|
||||||
|
return CastingSlot::Discipline;
|
||||||
|
case EQEmu::CastingSlot::AltAbility:
|
||||||
|
return CastingSlot::AltAbility;
|
||||||
|
default: // we shouldn't have any issues with other slots ... just return something
|
||||||
|
return CastingSlot::Discipline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline EQEmu::CastingSlot UFToServerCastingSlot(CastingSlot slot)
|
||||||
|
{
|
||||||
|
switch (slot) {
|
||||||
|
case CastingSlot::Gem1:
|
||||||
|
return EQEmu::CastingSlot::Gem1;
|
||||||
|
case CastingSlot::Gem2:
|
||||||
|
return EQEmu::CastingSlot::Gem2;
|
||||||
|
case CastingSlot::Gem3:
|
||||||
|
return EQEmu::CastingSlot::Gem3;
|
||||||
|
case CastingSlot::Gem4:
|
||||||
|
return EQEmu::CastingSlot::Gem4;
|
||||||
|
case CastingSlot::Gem5:
|
||||||
|
return EQEmu::CastingSlot::Gem5;
|
||||||
|
case CastingSlot::Gem6:
|
||||||
|
return EQEmu::CastingSlot::Gem6;
|
||||||
|
case CastingSlot::Gem7:
|
||||||
|
return EQEmu::CastingSlot::Gem7;
|
||||||
|
case CastingSlot::Gem8:
|
||||||
|
return EQEmu::CastingSlot::Gem8;
|
||||||
|
case CastingSlot::Gem9:
|
||||||
|
return EQEmu::CastingSlot::Gem9;
|
||||||
|
case CastingSlot::Gem10:
|
||||||
|
return EQEmu::CastingSlot::Gem10;
|
||||||
|
case CastingSlot::Gem11:
|
||||||
|
return EQEmu::CastingSlot::Gem11;
|
||||||
|
case CastingSlot::Gem12:
|
||||||
|
return EQEmu::CastingSlot::Gem12;
|
||||||
|
case CastingSlot::Discipline:
|
||||||
|
return EQEmu::CastingSlot::Discipline;
|
||||||
|
case CastingSlot::Item:
|
||||||
|
return EQEmu::CastingSlot::Item;
|
||||||
|
case CastingSlot::AltAbility:
|
||||||
|
return EQEmu::CastingSlot::AltAbility;
|
||||||
|
default: // we shouldn't have any issues with other slots ... just return something
|
||||||
|
return EQEmu::CastingSlot::Discipline;
|
||||||
|
}
|
||||||
|
}
|
||||||
} /*UF*/
|
} /*UF*/
|
||||||
|
|||||||
@ -50,6 +50,24 @@ namespace UF
|
|||||||
#include "uf_ops.h"
|
#include "uf_ops.h"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CastingSlot : uint32 {
|
||||||
|
Gem1 = 0,
|
||||||
|
Gem2 = 1,
|
||||||
|
Gem3 = 2,
|
||||||
|
Gem4 = 3,
|
||||||
|
Gem5 = 4,
|
||||||
|
Gem6 = 5,
|
||||||
|
Gem7 = 6,
|
||||||
|
Gem8 = 7,
|
||||||
|
Gem9 = 8,
|
||||||
|
Gem10 = 9,
|
||||||
|
Gem11 = 10,
|
||||||
|
Gem12 = 11,
|
||||||
|
Item = 12,
|
||||||
|
Discipline = 13,
|
||||||
|
AltAbility = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
}; /*UF*/
|
}; /*UF*/
|
||||||
|
|
||||||
#endif /*COMMON_UF_H*/
|
#endif /*COMMON_UF_H*/
|
||||||
|
|||||||
@ -26,7 +26,7 @@ namespace UF
|
|||||||
namespace structs {
|
namespace structs {
|
||||||
|
|
||||||
|
|
||||||
static const uint32 BUFF_COUNT = 25;
|
static const uint32 BUFF_COUNT = 30;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Compiler override to ensure
|
** Compiler override to ensure
|
||||||
@ -479,7 +479,7 @@ struct MemorizeSpell_Struct {
|
|||||||
uint32 slot; // Spot in the spell book/memorized slot
|
uint32 slot; // Spot in the spell book/memorized slot
|
||||||
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
uint32 spell_id; // Spell id (200 or c8 is minor healing, etc)
|
||||||
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming
|
||||||
//uint32 unknown12;
|
uint32 reduction; // lowers reuse
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -512,11 +512,12 @@ struct DeleteSpell_Struct
|
|||||||
|
|
||||||
struct ManaChange_Struct
|
struct ManaChange_Struct
|
||||||
{
|
{
|
||||||
uint32 new_mana; // New Mana AMount
|
/*00*/ uint32 new_mana; // New Mana AMount
|
||||||
uint32 stamina;
|
/*04*/ uint32 stamina;
|
||||||
uint32 spell_id;
|
/*08*/ uint32 spell_id;
|
||||||
uint32 unknown12;
|
/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting?
|
||||||
uint32 unknown16;
|
/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like
|
||||||
|
/*16*/ int32 slot; // -1 for normal usage slot for when we want silent interrupt? I think it does timer stuff or something. Linked Spell Reuse interrupt uses it
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwapSpell_Struct
|
struct SwapSpell_Struct
|
||||||
@ -958,8 +959,7 @@ struct PlayerProfile_Struct
|
|||||||
/*07880*/ uint32 toxicity; // Potion Toxicity (15=too toxic, each potion adds 3)
|
/*07880*/ uint32 toxicity; // Potion Toxicity (15=too toxic, each potion adds 3)
|
||||||
/*07884*/ uint32 thirst_level; // Drink (ticks till next drink)
|
/*07884*/ uint32 thirst_level; // Drink (ticks till next drink)
|
||||||
/*07888*/ uint32 hunger_level; // Food (ticks till next eat)
|
/*07888*/ uint32 hunger_level; // Food (ticks till next eat)
|
||||||
/*07892*/ SpellBuff_Struct buffs[BUFF_COUNT]; // [1900] Buffs currently on the player (30 Max) - (Each Size 76)
|
/*07892*/ SpellBuff_Struct buffs[BUFF_COUNT]; // [2280] Buffs currently on the player (30 Max) - (Each Size 76)
|
||||||
/*09792*/ uint8 unknown09792[380]; // BUFF_COUNT has been left at 25. These are the extra 5 buffs in Underfoot
|
|
||||||
/*10172*/ Disciplines_Struct disciplines; // [400] Known disciplines
|
/*10172*/ Disciplines_Struct disciplines; // [400] Known disciplines
|
||||||
/*10972*/ uint32 recastTimers[MAX_RECAST_TYPES]; // Timers (UNIX Time of last use)
|
/*10972*/ uint32 recastTimers[MAX_RECAST_TYPES]; // Timers (UNIX Time of last use)
|
||||||
/*11052*/ uint8 unknown11052[160]; // Some type of Timers
|
/*11052*/ uint8 unknown11052[160]; // Some type of Timers
|
||||||
@ -2167,9 +2167,7 @@ struct GroupFollow_Struct { // Underfoot Follow Struct
|
|||||||
|
|
||||||
struct InspectBuffs_Struct {
|
struct InspectBuffs_Struct {
|
||||||
/*000*/ uint32 spell_id[BUFF_COUNT];
|
/*000*/ uint32 spell_id[BUFF_COUNT];
|
||||||
/*100*/ uint32 filler100[5]; // BUFF_COUNT is really 30...
|
|
||||||
/*120*/ int32 tics_remaining[BUFF_COUNT];
|
/*120*/ int32 tics_remaining[BUFF_COUNT];
|
||||||
/*220*/ uint32 filler220[5]; // BUFF_COUNT is really 30...
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -37,10 +37,12 @@ enum { //values for pTimerType
|
|||||||
pTimerSenseTraps = 12,
|
pTimerSenseTraps = 12,
|
||||||
pTimerDisarmTraps = 13,
|
pTimerDisarmTraps = 13,
|
||||||
pTimerDisciplineReuseStart = 14,
|
pTimerDisciplineReuseStart = 14,
|
||||||
pTimerDisciplineReuseEnd = 24,
|
pTimerDisciplineReuseEnd = 24, // client actually has 20 ids, but still no disc go that high even on live
|
||||||
pTimerCombatAbility = 25,
|
pTimerCombatAbility = 25,
|
||||||
pTimerCombatAbility2 = 26, // RoF2+ Tiger Claw is unlinked from other monk skills, generic in case other classes ever need it
|
pTimerCombatAbility2 = 26, // RoF2+ Tiger Claw is unlinked from other monk skills, generic in case other classes ever need it
|
||||||
pTimerBeggingPickPocket = 27,
|
pTimerBeggingPickPocket = 27,
|
||||||
|
pTimerLinkedSpellReuseStart = 28,
|
||||||
|
pTimerLinkedSpellReuseEnd = 48,
|
||||||
|
|
||||||
pTimerLayHands = 87, //these IDs are used by client too
|
pTimerLayHands = 87, //these IDs are used by client too
|
||||||
pTimerHarmTouch = 89, //so dont change them
|
pTimerHarmTouch = 89, //so dont change them
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
#define TIGER 63
|
#define TIGER 63
|
||||||
#define ELEMENTAL 75
|
#define ELEMENTAL 75
|
||||||
#define ALLIGATOR 91
|
#define ALLIGATOR 91
|
||||||
|
#define OGGOK_CITIZEN 93
|
||||||
#define EYE_OF_ZOMM 108
|
#define EYE_OF_ZOMM 108
|
||||||
#define WOLF_ELEMENTAL 120
|
#define WOLF_ELEMENTAL 120
|
||||||
#define INVISIBLE_MAN 127
|
#define INVISIBLE_MAN 127
|
||||||
|
|||||||
@ -142,6 +142,8 @@ RULE_INT(Character, InvSnapshotMinRetryM, 30) // Time (in minutes) to re-attempt
|
|||||||
RULE_INT(Character, InvSnapshotHistoryD, 30) // Time (in days) to keep snapshot entries
|
RULE_INT(Character, InvSnapshotHistoryD, 30) // Time (in days) to keep snapshot entries
|
||||||
RULE_BOOL(Character, RestrictSpellScribing, false) // Restricts spell scribing to allowable races/classes of spell scroll, if true
|
RULE_BOOL(Character, RestrictSpellScribing, false) // Restricts spell scribing to allowable races/classes of spell scroll, if true
|
||||||
RULE_BOOL(Character, UseStackablePickPocketing, true) // Allows stackable pickpocketed items to stack instead of only being allowed in empty inventory slots
|
RULE_BOOL(Character, UseStackablePickPocketing, true) // Allows stackable pickpocketed items to stack instead of only being allowed in empty inventory slots
|
||||||
|
RULE_BOOL(Character, EnableAvoidanceCap, false)
|
||||||
|
RULE_INT(Character, AvoidanceCap, 750) // 750 Is a pretty good value, seen people dodge all attacks beyond 1,000 Avoidance
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Mercs)
|
RULE_CATEGORY(Mercs)
|
||||||
@ -329,7 +331,7 @@ RULE_INT(Spells, MaxBuffSlotsNPC, 25)
|
|||||||
RULE_INT(Spells, MaxSongSlotsNPC, 10)
|
RULE_INT(Spells, MaxSongSlotsNPC, 10)
|
||||||
RULE_INT(Spells, MaxDiscSlotsNPC, 1)
|
RULE_INT(Spells, MaxDiscSlotsNPC, 1)
|
||||||
RULE_INT(Spells, MaxTotalSlotsNPC, 36)
|
RULE_INT(Spells, MaxTotalSlotsNPC, 36)
|
||||||
RULE_INT(Spells, MaxTotalSlotsPET, 25) // do not set this higher than 25 until the player profile is removed from the blob
|
RULE_INT(Spells, MaxTotalSlotsPET, 30) // do not set this higher than 25 until the player profile is removed from the blob
|
||||||
RULE_BOOL (Spells, EnableBlockedBuffs, true)
|
RULE_BOOL (Spells, EnableBlockedBuffs, true)
|
||||||
RULE_INT(Spells, ReflectType, 1) //0 = disabled, 1 = single target player spells only, 2 = all player spells, 3 = all single target spells, 4 = all spells
|
RULE_INT(Spells, ReflectType, 1) //0 = disabled, 1 = single target player spells only, 2 = all player spells, 3 = all single target spells, 4 = all spells
|
||||||
RULE_INT(Spells, VirusSpreadDistance, 30) // The distance a viral spell will jump to its next victim
|
RULE_INT(Spells, VirusSpreadDistance, 30) // The distance a viral spell will jump to its next victim
|
||||||
@ -379,6 +381,7 @@ RULE_BOOL(Spells, UseAdditiveFocusFromWornSlot, false) // Allows an additive foc
|
|||||||
RULE_BOOL(Spells, AlwaysSendTargetsBuffs, false) // ignore LAA level if true
|
RULE_BOOL(Spells, AlwaysSendTargetsBuffs, false) // ignore LAA level if true
|
||||||
RULE_BOOL(Spells, FlatItemExtraSpellAmt, false) // allow SpellDmg stat to affect all spells, regardless of cast time/cooldown/etc
|
RULE_BOOL(Spells, FlatItemExtraSpellAmt, false) // allow SpellDmg stat to affect all spells, regardless of cast time/cooldown/etc
|
||||||
RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false) // ignore the 5 level spread on applying SpellDmg
|
RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false) // ignore the 5 level spread on applying SpellDmg
|
||||||
|
RULE_BOOL(Spells, AllowItemTGB, false) // TGB doesn't work with items on live, custom servers want it though
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Combat)
|
RULE_CATEGORY(Combat)
|
||||||
@ -503,6 +506,7 @@ RULE_BOOL(NPC, EnableMeritBasedFaction, false) // If set to true, faction will g
|
|||||||
RULE_INT(NPC, NPCToNPCAggroTimerMin, 500)
|
RULE_INT(NPC, NPCToNPCAggroTimerMin, 500)
|
||||||
RULE_INT(NPC, NPCToNPCAggroTimerMax, 6000)
|
RULE_INT(NPC, NPCToNPCAggroTimerMax, 6000)
|
||||||
RULE_BOOL(NPC, UseClassAsLastName, true) // Uses class archetype as LastName for npcs with none
|
RULE_BOOL(NPC, UseClassAsLastName, true) // Uses class archetype as LastName for npcs with none
|
||||||
|
RULE_BOOL(NPC, NewLevelScaling, true) // Better level scaling, use old if new formulas would break your server
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Aggro)
|
RULE_CATEGORY(Aggro)
|
||||||
@ -518,6 +522,7 @@ RULE_REAL(Aggro, TunnelVisionAggroMod, 0.75) //people not currently the top hate
|
|||||||
RULE_INT(Aggro, MaxScalingProcAggro, 400) // Set to -1 for no limit. Maxmimum amount of aggro that HP scaling SPA effect in a proc will add.
|
RULE_INT(Aggro, MaxScalingProcAggro, 400) // Set to -1 for no limit. Maxmimum amount of aggro that HP scaling SPA effect in a proc will add.
|
||||||
RULE_INT(Aggro, IntAggroThreshold, 75) // Int <= this will aggro regardless of level difference.
|
RULE_INT(Aggro, IntAggroThreshold, 75) // Int <= this will aggro regardless of level difference.
|
||||||
RULE_BOOL(Aggro, AllowTickPulling, false) // tick pulling is an exploit in an NPC's call for help fixed sometime in 2006 on live
|
RULE_BOOL(Aggro, AllowTickPulling, false) // tick pulling is an exploit in an NPC's call for help fixed sometime in 2006 on live
|
||||||
|
RULE_BOOL(Aggro, UseLevelAggro, true) // Level 18+ and Undead will aggro regardless of level difference. (this will disabled Rule:IntAggroThreshold if set to true)
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(TaskSystem)
|
RULE_CATEGORY(TaskSystem)
|
||||||
|
|||||||
@ -455,7 +455,7 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory *inv, bool is_charid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row[9]) {
|
if (inst && row[9]) {
|
||||||
std::string data_str(row[9]);
|
std::string data_str(row[9]);
|
||||||
std::string idAsString;
|
std::string idAsString;
|
||||||
std::string value;
|
std::string value;
|
||||||
@ -480,6 +480,7 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory *inv, bool is_charid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// theoretically inst can be nullptr ... this would be very bad ...
|
||||||
put_slot_id = inv->PutItem(slot_id, *inst);
|
put_slot_id = inv->PutItem(slot_id, *inst);
|
||||||
safe_delete(inst);
|
safe_delete(inst);
|
||||||
|
|
||||||
|
|||||||
@ -110,6 +110,20 @@ bool EQEmu::skills::IsBardInstrumentSkill(SkillType skill)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EQEmu::skills::IsCastingSkill(SkillType skill)
|
||||||
|
{
|
||||||
|
switch (skill) {
|
||||||
|
case SkillAbjuration:
|
||||||
|
case SkillAlteration:
|
||||||
|
case SkillConjuration:
|
||||||
|
case SkillDivination:
|
||||||
|
case SkillEvocation:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const std::map<EQEmu::skills::SkillType, std::string>& EQEmu::skills::GetSkillTypeMap()
|
const std::map<EQEmu::skills::SkillType, std::string>& EQEmu::skills::GetSkillTypeMap()
|
||||||
{
|
{
|
||||||
/* VS2013 code
|
/* VS2013 code
|
||||||
|
|||||||
@ -161,10 +161,11 @@ namespace EQEmu
|
|||||||
// server profile does not reflect this yet..so, prefixed with 'PACKET_'
|
// server profile does not reflect this yet..so, prefixed with 'PACKET_'
|
||||||
#define PACKET_SKILL_ARRAY_SIZE 100
|
#define PACKET_SKILL_ARRAY_SIZE 100
|
||||||
|
|
||||||
extern bool IsTradeskill(SkillType skill);
|
bool IsTradeskill(SkillType skill);
|
||||||
extern bool IsSpecializedSkill(SkillType skill);
|
bool IsSpecializedSkill(SkillType skill);
|
||||||
extern float GetSkillMeleePushForce(SkillType skill);
|
float GetSkillMeleePushForce(SkillType skill);
|
||||||
extern bool IsBardInstrumentSkill(SkillType skill);
|
bool IsBardInstrumentSkill(SkillType skill);
|
||||||
|
bool IsCastingSkill(SkillType skill);
|
||||||
|
|
||||||
extern const std::map<SkillType, std::string>& GetSkillTypeMap();
|
extern const std::map<SkillType, std::string>& GetSkillTypeMap();
|
||||||
|
|
||||||
|
|||||||
@ -235,8 +235,11 @@ bool IsBeneficialSpell(uint16 spell_id)
|
|||||||
// If the resisttype is magic and SpellAffectIndex is Calm/memblur/dispell sight
|
// If the resisttype is magic and SpellAffectIndex is Calm/memblur/dispell sight
|
||||||
// it's not beneficial
|
// it's not beneficial
|
||||||
if (spells[spell_id].resisttype == RESIST_MAGIC) {
|
if (spells[spell_id].resisttype == RESIST_MAGIC) {
|
||||||
if (sai == SAI_Calm || sai == SAI_Dispell_Sight ||
|
// checking these SAI cause issues with the rng defensive proc line
|
||||||
sai == SAI_Memory_Blur || sai == SAI_Calm_Song)
|
// So I guess instead of fixing it for real, just a quick hack :P
|
||||||
|
if (spells[spell_id].effectid[0] != SE_DefensiveProc &&
|
||||||
|
(sai == SAI_Calm || sai == SAI_Dispell_Sight || sai == SAI_Memory_Blur ||
|
||||||
|
sai == SAI_Calm_Song))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// If the resisttype is not magic and spell is Bind Sight or Cast Sight
|
// If the resisttype is not magic and spell is Bind Sight or Cast Sight
|
||||||
@ -669,9 +672,7 @@ bool IsDisciplineBuff(uint16 spell_id)
|
|||||||
if (!IsValidSpell(spell_id))
|
if (!IsValidSpell(spell_id))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (spells[spell_id].mana == 0 && spells[spell_id].short_buff_box == 0 &&
|
if (spells[spell_id].IsDisciplineBuff && spells[spell_id].targettype == ST_Self)
|
||||||
(spells[spell_id].EndurCost || spells[spell_id].EndurUpkeep) &&
|
|
||||||
spells[spell_id].targettype == ST_Self)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -446,7 +446,7 @@ typedef enum {
|
|||||||
#define SE_IncreaseRunSpeedCap 290 // implemented[AA] - increases run speed over the hard cap
|
#define SE_IncreaseRunSpeedCap 290 // implemented[AA] - increases run speed over the hard cap
|
||||||
#define SE_Purify 291 // implemented - Removes determental effects
|
#define SE_Purify 291 // implemented - Removes determental effects
|
||||||
#define SE_StrikeThrough2 292 // implemented[AA] - increasing chance of bypassing an opponent's special defenses, such as dodge, block, parry, and riposte.
|
#define SE_StrikeThrough2 292 // implemented[AA] - increasing chance of bypassing an opponent's special defenses, such as dodge, block, parry, and riposte.
|
||||||
#define SE_FrontalStunResist 293 // implemented[AA] - Reduce chance to be stunned from front.
|
#define SE_FrontalStunResist 293 // implemented[AA] - Reduce chance to be stunned from front. -- live descriptions sounds like this isn't limited to frontal anymore
|
||||||
#define SE_CriticalSpellChance 294 // implemented - increase chance to critical hit and critical damage modifier.
|
#define SE_CriticalSpellChance 294 // implemented - increase chance to critical hit and critical damage modifier.
|
||||||
//#define SE_ReduceTimerSpecial 295 // not used
|
//#define SE_ReduceTimerSpecial 295 // not used
|
||||||
#define SE_FcSpellVulnerability 296 // implemented - increase in incoming spell damage
|
#define SE_FcSpellVulnerability 296 // implemented - increase in incoming spell damage
|
||||||
|
|||||||
@ -1985,7 +1985,7 @@ void Client::ChannelGrantVoice(std::string CommandString) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(RequiredChannel->IsOwner(RequiredClient->GetName()) || RequiredChannel->IsModerator(RequiredClient->GetName())) {
|
if(RequiredClient && (RequiredChannel->IsOwner(RequiredClient->GetName()) || RequiredChannel->IsModerator(RequiredClient->GetName()))) {
|
||||||
|
|
||||||
GeneralChannelMessage("The channel owner and moderators automatically have voice.");
|
GeneralChannelMessage("The channel owner and moderators automatically have voice.");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -172,6 +172,7 @@ OP_BeginCast=0x17ff
|
|||||||
OP_ColoredText=0x41cb
|
OP_ColoredText=0x41cb
|
||||||
OP_ConsentResponse=0x183d
|
OP_ConsentResponse=0x183d
|
||||||
OP_MemorizeSpell=0x2fac
|
OP_MemorizeSpell=0x2fac
|
||||||
|
OP_LinkedReuse=0x3ac0
|
||||||
OP_SwapSpell=0x4736
|
OP_SwapSpell=0x4736
|
||||||
OP_CastSpell=0x1cb5
|
OP_CastSpell=0x1cb5
|
||||||
OP_Consider=0x4d8d
|
OP_Consider=0x4d8d
|
||||||
|
|||||||
@ -171,6 +171,7 @@ OP_BeginCast=0x318f
|
|||||||
OP_ColoredText=0x43af
|
OP_ColoredText=0x43af
|
||||||
OP_ConsentResponse=0x384a
|
OP_ConsentResponse=0x384a
|
||||||
OP_MemorizeSpell=0x217c
|
OP_MemorizeSpell=0x217c
|
||||||
|
OP_LinkedReuse=0x1619
|
||||||
OP_SwapSpell=0x0efa
|
OP_SwapSpell=0x0efa
|
||||||
OP_CastSpell=0x1287
|
OP_CastSpell=0x1287
|
||||||
OP_Consider=0x742b
|
OP_Consider=0x742b
|
||||||
|
|||||||
@ -171,6 +171,7 @@ OP_BeginCast=0x0d5a # C
|
|||||||
OP_ColoredText=0x569a # C
|
OP_ColoredText=0x569a # C
|
||||||
OP_ConsentResponse=0x6e47 # C
|
OP_ConsentResponse=0x6e47 # C
|
||||||
OP_MemorizeSpell=0x8543 # C
|
OP_MemorizeSpell=0x8543 # C
|
||||||
|
OP_LinkedReuse=0x6ef9
|
||||||
OP_SwapSpell=0x3fd2 # C
|
OP_SwapSpell=0x3fd2 # C
|
||||||
OP_CastSpell=0x3582 # C
|
OP_CastSpell=0x3582 # C
|
||||||
OP_Consider=0x6024 # C
|
OP_Consider=0x6024 # C
|
||||||
|
|||||||
@ -169,6 +169,7 @@ OP_BeginCast=0x5A50 #SEQ 12/04/08
|
|||||||
OP_ColoredText=0x3BC7 #SEQ 12/04/08
|
OP_ColoredText=0x3BC7 #SEQ 12/04/08
|
||||||
OP_ConsentResponse=0x4D30 #SEQ 12/04/08
|
OP_ConsentResponse=0x4D30 #SEQ 12/04/08
|
||||||
OP_MemorizeSpell=0x6A93 #SEQ 12/04/08
|
OP_MemorizeSpell=0x6A93 #SEQ 12/04/08
|
||||||
|
OP_LinkedReuse=0x2c26
|
||||||
OP_SwapSpell=0x1418 #SEQ 12/04/08
|
OP_SwapSpell=0x1418 #SEQ 12/04/08
|
||||||
OP_CastSpell=0x7F5D #SEQ 12/04/08
|
OP_CastSpell=0x7F5D #SEQ 12/04/08
|
||||||
OP_Consider=0x32E1 #SEQ 12/04/08
|
OP_Consider=0x32E1 #SEQ 12/04/08
|
||||||
|
|||||||
@ -170,6 +170,7 @@ OP_Save=0x736b # ShowEQ 10/27/05
|
|||||||
OP_Camp=0x78c1 # ShowEQ 10/27/05
|
OP_Camp=0x78c1 # ShowEQ 10/27/05
|
||||||
OP_EndLootRequest=0x2316 # ShowEQ 10/27/05
|
OP_EndLootRequest=0x2316 # ShowEQ 10/27/05
|
||||||
OP_MemorizeSpell=0x308e # ShowEQ 10/27/05
|
OP_MemorizeSpell=0x308e # ShowEQ 10/27/05
|
||||||
|
OP_LinkedReuse=0x6a00
|
||||||
OP_SwapSpell=0x2126 # ShowEQ 10/27/05
|
OP_SwapSpell=0x2126 # ShowEQ 10/27/05
|
||||||
OP_CastSpell=0x304b # ShowEQ 10/27/05
|
OP_CastSpell=0x304b # ShowEQ 10/27/05
|
||||||
OP_DeleteSpell=0x4f37
|
OP_DeleteSpell=0x4f37
|
||||||
|
|||||||
@ -173,6 +173,7 @@ OP_BeginCast=0x0d5a # C
|
|||||||
OP_ColoredText=0x71bf # C
|
OP_ColoredText=0x71bf # C
|
||||||
OP_ConsentResponse=0x0e87 # C
|
OP_ConsentResponse=0x0e87 # C
|
||||||
OP_MemorizeSpell=0x3887 # C
|
OP_MemorizeSpell=0x3887 # C
|
||||||
|
OP_LinkedReuse=0x1b26
|
||||||
OP_SwapSpell=0x5805 # C
|
OP_SwapSpell=0x5805 # C
|
||||||
OP_CastSpell=0x50c2 # C
|
OP_CastSpell=0x50c2 # C
|
||||||
OP_Consider=0x3c2d # C
|
OP_Consider=0x3c2d # C
|
||||||
|
|||||||
@ -33,6 +33,7 @@ if(!$ARGV[0]){
|
|||||||
print " tables=\"table1,table2,table3\" - Manually specify tables, default is to dump all tables from database\n";
|
print " tables=\"table1,table2,table3\" - Manually specify tables, default is to dump all tables from database\n";
|
||||||
print " compress - Compress Database with 7-ZIP, will fallback to WinRAR depending on what is installed (Must be installed to default program dir)...\n";
|
print " compress - Compress Database with 7-ZIP, will fallback to WinRAR depending on what is installed (Must be installed to default program dir)...\n";
|
||||||
print " nolock - Does not lock tables, meant for backuping while the server is running..\n";
|
print " nolock - Does not lock tables, meant for backuping while the server is running..\n";
|
||||||
|
print " backup_name=\"name\" - Sets database backup prefix name\n";
|
||||||
print ' Example: perl DB_Dumper.pl Loc="E:\Backups"' . "\n\n";
|
print ' Example: perl DB_Dumper.pl Loc="E:\Backups"' . "\n\n";
|
||||||
print "######################################################\n";
|
print "######################################################\n";
|
||||||
exit;
|
exit;
|
||||||
@ -72,6 +73,11 @@ while($ARGV[$n]){
|
|||||||
print "Database is " . $DB_NAME[1] . "\n";
|
print "Database is " . $DB_NAME[1] . "\n";
|
||||||
$db = $DB_NAME[1];
|
$db = $DB_NAME[1];
|
||||||
}
|
}
|
||||||
|
if($ARGV[$n]=~/backup_name=/i){
|
||||||
|
@data = split('=', $ARGV[$n]);
|
||||||
|
print "Backup Name is " . $data[1] . "\n";
|
||||||
|
$backup_name = $data[1];
|
||||||
|
}
|
||||||
if($ARGV[$n]=~/loc=/i){
|
if($ARGV[$n]=~/loc=/i){
|
||||||
@B_LOC = split('=', $ARGV[$n]);
|
@B_LOC = split('=', $ARGV[$n]);
|
||||||
print "Backup Directory: " . $B_LOC[1] . "\n";
|
print "Backup Directory: " . $B_LOC[1] . "\n";
|
||||||
@ -108,8 +114,14 @@ else {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($t_tables ne ""){
|
if($t_tables ne ""){
|
||||||
$tables_f_l = substr($t_tables_l, 0, 20) . '...';
|
$tables_f_l = substr($t_tables_l, 0, 20) . '-';
|
||||||
|
if($backup_name){
|
||||||
|
$target_file = $backup_name . '_' . $date . '';
|
||||||
|
}
|
||||||
|
else {
|
||||||
$target_file = '' . $tables_f_l . '_' . $date . '';
|
$target_file = '' . $tables_f_l . '_' . $date . '';
|
||||||
|
}
|
||||||
|
|
||||||
print "Performing table based backup...\n";
|
print "Performing table based backup...\n";
|
||||||
#::: Backup Database...
|
#::: Backup Database...
|
||||||
print "Backing up Database " . $db . "... \n\n";
|
print "Backing up Database " . $db . "... \n\n";
|
||||||
@ -121,7 +133,14 @@ if($t_tables ne ""){
|
|||||||
system($cmd);
|
system($cmd);
|
||||||
}
|
}
|
||||||
else{ #::: Entire DB Backup
|
else{ #::: Entire DB Backup
|
||||||
|
|
||||||
|
if($backup_name){
|
||||||
|
$target_file = $backup_name . '_' . $db . '_' . $date . '';
|
||||||
|
}
|
||||||
|
else {
|
||||||
$target_file = '' . $db . '_' . $date . '';
|
$target_file = '' . $db . '_' . $date . '';
|
||||||
|
}
|
||||||
|
|
||||||
#::: Backup Database...
|
#::: Backup Database...
|
||||||
print "Backing up Database " . $db . "... \n\n";
|
print "Backing up Database " . $db . "... \n\n";
|
||||||
if($no_lock == 1){
|
if($no_lock == 1){
|
||||||
@ -195,6 +214,9 @@ if($Compress == 1){
|
|||||||
$final_file = $target_file . ".tar.gz";
|
$final_file = $target_file . ".tar.gz";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$final_file = $target_file . ".sql";
|
||||||
|
}
|
||||||
|
|
||||||
#::: Get Final File Location for display
|
#::: Get Final File Location for display
|
||||||
if($B_LOC[1] ne ""){ $final_loc = $B_LOC[1] . '' . $file_app . ""; }
|
if($B_LOC[1] ne ""){ $final_loc = $B_LOC[1] . '' . $file_app . ""; }
|
||||||
|
|||||||
1552
utils/scripts/eqemu_server.pl
Normal file
1552
utils/scripts/eqemu_server.pl
Normal file
File diff suppressed because it is too large
Load Diff
@ -298,6 +298,7 @@ sub show_menu_prompt {
|
|||||||
18 => \&fetch_latest_windows_binaries_bots,
|
18 => \&fetch_latest_windows_binaries_bots,
|
||||||
19 => \&do_bots_db_schema_drop,
|
19 => \&do_bots_db_schema_drop,
|
||||||
20 => \&do_update_self,
|
20 => \&do_update_self,
|
||||||
|
21 => \&database_dump_player_tables,
|
||||||
0 => \&script_exit,
|
0 => \&script_exit,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -378,6 +379,7 @@ return <<EO_MENU;
|
|||||||
18) [Windows Server Build Bots] :: Download Latest and Stable Server Build with Bots
|
18) [Windows Server Build Bots] :: Download Latest and Stable Server Build with Bots
|
||||||
19) [EQEmu DB Drop Bots Schema] :: Remove Bots schema and return database to normal state
|
19) [EQEmu DB Drop Bots Schema] :: Remove Bots schema and return database to normal state
|
||||||
20) [Update the updater] Force update this script (Redownload)
|
20) [Update the updater] Force update this script (Redownload)
|
||||||
|
21) [DB :: Backup Player Tables] :: Backs up player tables
|
||||||
0) Exit
|
0) Exit
|
||||||
|
|
||||||
Enter numbered option and press enter...
|
Enter numbered option and press enter...
|
||||||
@ -404,6 +406,30 @@ sub database_dump {
|
|||||||
print "Performing database backup....\n";
|
print "Performing database backup....\n";
|
||||||
print `perl db_dumper.pl database="$db" loc="backups"`;
|
print `perl db_dumper.pl database="$db" loc="backups"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub database_dump_player_tables {
|
||||||
|
check_for_database_dump_script();
|
||||||
|
print "Performing database backup of player tables....\n";
|
||||||
|
get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/character_table_list.txt", "backups/character_table_list.txt");
|
||||||
|
|
||||||
|
$tables = "";
|
||||||
|
open (FILE, "backups/character_table_list.txt");
|
||||||
|
$i = 0;
|
||||||
|
while (<FILE>){
|
||||||
|
chomp;
|
||||||
|
$o = $_;
|
||||||
|
$tables .= $o . ",";
|
||||||
|
}
|
||||||
|
$tables = substr($tables, 0, -1);
|
||||||
|
|
||||||
|
print `perl db_dumper.pl database="$db" loc="backups" tables="$tables" backup_name="player_tables_export" nolock`;
|
||||||
|
|
||||||
|
print "\nPress any key to continue...\n";
|
||||||
|
|
||||||
|
<>; #Read from STDIN
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
sub database_dump_compress {
|
sub database_dump_compress {
|
||||||
check_for_database_dump_script();
|
check_for_database_dump_script();
|
||||||
print "Performing database backup....\n";
|
print "Performing database backup....\n";
|
||||||
|
|||||||
33
utils/sql/character_table_list.txt
Normal file
33
utils/sql/character_table_list.txt
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
adventure_stats
|
||||||
|
char_recipe_list
|
||||||
|
character_activities
|
||||||
|
character_alt_currency
|
||||||
|
character_alternate_abilities
|
||||||
|
character_bandolier
|
||||||
|
character_bind
|
||||||
|
character_currency
|
||||||
|
character_data
|
||||||
|
character_disciplines
|
||||||
|
character_enabledtasks
|
||||||
|
character_inspect_messages
|
||||||
|
character_languages
|
||||||
|
character_leadership_abilities
|
||||||
|
character_material
|
||||||
|
character_memmed_spells
|
||||||
|
character_potionbelt
|
||||||
|
character_skills
|
||||||
|
character_spells
|
||||||
|
character_tribute
|
||||||
|
completed_tasks
|
||||||
|
faction_values
|
||||||
|
friends
|
||||||
|
guild_members
|
||||||
|
instance_list_player
|
||||||
|
inventory
|
||||||
|
keyring
|
||||||
|
mail
|
||||||
|
player_titlesets
|
||||||
|
quest_globals
|
||||||
|
timers
|
||||||
|
titles
|
||||||
|
zone_flags
|
||||||
@ -142,7 +142,7 @@ void Client::SendLogServer()
|
|||||||
if(RuleB(World, IsGMPetitionWindowEnabled))
|
if(RuleB(World, IsGMPetitionWindowEnabled))
|
||||||
l->enable_petition_wnd = 1;
|
l->enable_petition_wnd = 1;
|
||||||
|
|
||||||
if(RuleI(World, FVNoDropFlag) == 1 || RuleI(World, FVNoDropFlag) == 2 && GetAdmin() > RuleI(Character, MinStatusForNoDropExemptions))
|
if((RuleI(World, FVNoDropFlag) == 1 || RuleI(World, FVNoDropFlag) == 2) && GetAdmin() > RuleI(Character, MinStatusForNoDropExemptions))
|
||||||
l->enable_FV = 1;
|
l->enable_FV = 1;
|
||||||
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
@ -1483,7 +1483,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
|||||||
for (i = 0; i < MAX_PP_REF_SPELLBOOK; i++)
|
for (i = 0; i < MAX_PP_REF_SPELLBOOK; i++)
|
||||||
pp.spell_book[i] = 0xFFFFFFFF;
|
pp.spell_book[i] = 0xFFFFFFFF;
|
||||||
|
|
||||||
for(i = 0; i < MAX_PP_REF_MEMSPELL; i++)
|
for(i = 0; i < MAX_PP_MEMSPELL; i++)
|
||||||
pp.mem_spells[i] = 0xFFFFFFFF;
|
pp.mem_spells[i] = 0xFFFFFFFF;
|
||||||
|
|
||||||
for(i = 0; i < BUFF_COUNT; i++)
|
for(i = 0; i < BUFF_COUNT; i++)
|
||||||
|
|||||||
@ -88,7 +88,7 @@ void ZSList::Process() {
|
|||||||
Process();
|
Process();
|
||||||
CatchSignal(2);
|
CatchSignal(2);
|
||||||
}
|
}
|
||||||
if(reminder && reminder->Check()){
|
if(reminder && reminder->Check() && shutdowntimer){
|
||||||
SendEmoteMessage(0,0,0,15,"<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World coming down, everyone log out now. World will shut down in %i minutes...", ((shutdowntimer->GetRemainingTime()/1000) / 60));
|
SendEmoteMessage(0,0,0,15,"<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World coming down, everyone log out now. World will shut down in %i minutes...", ((shutdowntimer->GetRemainingTime()/1000) / 60));
|
||||||
}
|
}
|
||||||
LinkedListIterator<ZoneServer*> iterator(list);
|
LinkedListIterator<ZoneServer*> iterator(list);
|
||||||
|
|||||||
10
zone/aa.cpp
10
zone/aa.cpp
@ -867,7 +867,7 @@ void Client::SendAlternateAdvancementRank(int aa_id, int level) {
|
|||||||
aai->max_level = ability->GetMaxLevel(this);
|
aai->max_level = ability->GetMaxLevel(this);
|
||||||
aai->prev_id = rank->prev_id;
|
aai->prev_id = rank->prev_id;
|
||||||
|
|
||||||
if(rank->next && !CanUseAlternateAdvancementRank(rank->next) || ability->charges > 0) {
|
if((rank->next && !CanUseAlternateAdvancementRank(rank->next)) || ability->charges > 0) {
|
||||||
aai->next_id = -1;
|
aai->next_id = -1;
|
||||||
} else {
|
} else {
|
||||||
aai->next_id = rank->next_id;
|
aai->next_id = rank->next_id;
|
||||||
@ -1183,12 +1183,12 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
|
|||||||
CommonBreakInvisible();
|
CommonBreakInvisible();
|
||||||
// Bards can cast instant cast AAs while they are casting another song
|
// Bards can cast instant cast AAs while they are casting another song
|
||||||
if(spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) {
|
if(spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) {
|
||||||
if(!SpellFinished(rank->spell, entity_list.GetMob(target_id), ALTERNATE_ABILITY_SPELL_SLOT, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) {
|
if(!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQEmu::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ExpendAlternateAdvancementCharge(ability->id);
|
ExpendAlternateAdvancementCharge(ability->id);
|
||||||
} else {
|
} else {
|
||||||
if(!CastSpell(rank->spell, target_id, ALTERNATE_ABILITY_SPELL_SLOT, -1, -1, 0, -1, rank->spell_type + pTimerAAStart, cooldown, nullptr, rank->id)) {
|
if(!CastSpell(rank->spell, target_id, EQEmu::CastingSlot::AltAbility, -1, -1, 0, -1, rank->spell_type + pTimerAAStart, cooldown, nullptr, rank->id)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1240,6 +1240,10 @@ void Mob::ExpendAlternateAdvancementCharge(uint32 aa_id) {
|
|||||||
CastToClient()->GetEPP().expended_aa += r->cost;
|
CastToClient()->GetEPP().expended_aa += r->cost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (IsClient()) {
|
||||||
|
auto c = CastToClient();
|
||||||
|
c->RemoveExpendedAA(ability->first_rank_id);
|
||||||
|
}
|
||||||
aa_ranks.erase(iter.first);
|
aa_ranks.erase(iter.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -156,11 +156,22 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RuleB(Aggro, UseLevelAggro))
|
||||||
|
{
|
||||||
|
if (GetLevel() < 18 && mob->GetLevelCon(GetLevel()) == CON_GREEN && GetBodyType() != 3)
|
||||||
|
{
|
||||||
|
towho->Message(0, "...%s is red to me (basically)", mob->GetName(), dist2, iAggroRange2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GREEN ) {
|
if(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GREEN ) {
|
||||||
towho->Message(0, "...%s is red to me (basically)", mob->GetName(),
|
towho->Message(0, "...%s is red to me (basically)", mob->GetName(),
|
||||||
dist2, iAggroRange2);
|
dist2, iAggroRange2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(verbose) {
|
if(verbose) {
|
||||||
int my_primary = GetPrimaryFaction();
|
int my_primary = GetPrimaryFaction();
|
||||||
@ -321,6 +332,40 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
|||||||
int heroicCHA_mod = mob->itembonuses.HeroicCHA/25; // 800 Heroic CHA cap
|
int heroicCHA_mod = mob->itembonuses.HeroicCHA/25; // 800 Heroic CHA cap
|
||||||
if(heroicCHA_mod > THREATENLY_ARRGO_CHANCE)
|
if(heroicCHA_mod > THREATENLY_ARRGO_CHANCE)
|
||||||
heroicCHA_mod = THREATENLY_ARRGO_CHANCE;
|
heroicCHA_mod = THREATENLY_ARRGO_CHANCE;
|
||||||
|
if (RuleB(Aggro, UseLevelAggro) &&
|
||||||
|
(
|
||||||
|
//old InZone check taken care of above by !mob->CastToClient()->Connected()
|
||||||
|
(
|
||||||
|
( GetLevel() >= 18 )
|
||||||
|
||(GetBodyType() == 3)
|
||||||
|
||( mob->IsClient() && mob->CastToClient()->IsSitting() )
|
||||||
|
||( mob->GetLevelCon(GetLevel()) != CON_GREEN )
|
||||||
|
|
||||||
|
)
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
(
|
||||||
|
fv == FACTION_SCOWLS
|
||||||
|
||
|
||||||
|
(mob->GetPrimaryFaction() != GetPrimaryFaction() && mob->GetPrimaryFaction() == -4 && GetOwner() == nullptr)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
fv == FACTION_THREATENLY
|
||||||
|
&& zone->random.Roll(THREATENLY_ARRGO_CHANCE - heroicCHA_mod)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//FatherNiwtit: make sure we can see them. last since it is very expensive
|
||||||
|
if(CheckLosFN(mob)) {
|
||||||
|
Log.Out(Logs::Detail, Logs::Aggro, "Check aggro for %s target %s.", GetName(), mob->GetName());
|
||||||
|
return( mod_will_aggro(mob, this) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if
|
if
|
||||||
(
|
(
|
||||||
//old InZone check taken care of above by !mob->CastToClient()->Connected()
|
//old InZone check taken care of above by !mob->CastToClient()->Connected()
|
||||||
@ -351,6 +396,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
|||||||
return( mod_will_aggro(mob, this) );
|
return( mod_will_aggro(mob, this) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log.Out(Logs::Detail, Logs::Aggro, "Is In zone?:%d\n", mob->InZone());
|
Log.Out(Logs::Detail, Logs::Aggro, "Is In zone?:%d\n", mob->InZone());
|
||||||
Log.Out(Logs::Detail, Logs::Aggro, "Dist^2: %f\n", dist2);
|
Log.Out(Logs::Detail, Logs::Aggro, "Dist^2: %f\n", dist2);
|
||||||
@ -462,7 +508,7 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) {
|
|||||||
{
|
{
|
||||||
//if they are in range, make sure we are not green...
|
//if they are in range, make sure we are not green...
|
||||||
//then jump in if they are our friend
|
//then jump in if they are our friend
|
||||||
if(attacker->GetLevelCon(mob->GetLevel()) != CON_GREEN)
|
if(mob->GetLevel() >= 50 || attacker->GetLevelCon(mob->GetLevel()) != CON_GREEN)
|
||||||
{
|
{
|
||||||
bool useprimfaction = false;
|
bool useprimfaction = false;
|
||||||
if(mob->GetPrimaryFaction() == sender->CastToNPC()->GetPrimaryFaction())
|
if(mob->GetPrimaryFaction() == sender->CastToNPC()->GetPrimaryFaction())
|
||||||
|
|||||||
127
zone/attack.cpp
127
zone/attack.cpp
@ -23,6 +23,7 @@
|
|||||||
#include "../common/skills.h"
|
#include "../common/skills.h"
|
||||||
#include "../common/spdat.h"
|
#include "../common/spdat.h"
|
||||||
#include "../common/string_util.h"
|
#include "../common/string_util.h"
|
||||||
|
#include "../common/data_verification.h"
|
||||||
#include "queryserv.h"
|
#include "queryserv.h"
|
||||||
#include "quest_parser_collection.h"
|
#include "quest_parser_collection.h"
|
||||||
#include "string_ids.h"
|
#include "string_ids.h"
|
||||||
@ -369,18 +370,15 @@ bool Mob::AvoidDamage(Mob *other, int32 &damage, int hand)
|
|||||||
counter_dodge = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 4);
|
counter_dodge = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////
|
|
||||||
// make enrage same as riposte
|
|
||||||
/////////////////////////////////////////////////////////
|
|
||||||
if (IsEnraged() && InFront) {
|
|
||||||
damage = -3;
|
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// riposte -- it may seem crazy, but if the attacker has SPA 173 on them, they are immune to Ripo
|
// riposte -- it may seem crazy, but if the attacker has SPA 173 on them, they are immune to Ripo
|
||||||
bool ImmuneRipo = attacker->aabonuses.RiposteChance || attacker->spellbonuses.RiposteChance || attacker->itembonuses.RiposteChance;
|
bool ImmuneRipo = attacker->aabonuses.RiposteChance || attacker->spellbonuses.RiposteChance || attacker->itembonuses.RiposteChance;
|
||||||
// Need to check if we have something in MainHand to actually attack with (or fists)
|
// Need to check if we have something in MainHand to actually attack with (or fists)
|
||||||
if (hand != EQEmu::legacy::SlotRange && CanThisClassRiposte() && InFront && !ImmuneRipo) {
|
if (hand != EQEmu::legacy::SlotRange && CanThisClassRiposte() && InFront && !ImmuneRipo) {
|
||||||
|
if (IsEnraged()) {
|
||||||
|
damage = -3;
|
||||||
|
Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (IsClient())
|
if (IsClient())
|
||||||
CastToClient()->CheckIncreaseSkill(EQEmu::skills::SkillRiposte, other, -10);
|
CastToClient()->CheckIncreaseSkill(EQEmu::skills::SkillRiposte, other, -10);
|
||||||
// check auto discs ... I guess aa/items too :P
|
// check auto discs ... I guess aa/items too :P
|
||||||
@ -1205,7 +1203,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
|||||||
IsValidSpell(aabonuses.SkillAttackProc[2])) {
|
IsValidSpell(aabonuses.SkillAttackProc[2])) {
|
||||||
float chance = aabonuses.SkillAttackProc[0] / 1000.0f;
|
float chance = aabonuses.SkillAttackProc[0] / 1000.0f;
|
||||||
if (zone->random.Roll(chance))
|
if (zone->random.Roll(chance))
|
||||||
SpellFinished(aabonuses.SkillAttackProc[2], other, 10, 0, -1,
|
SpellFinished(aabonuses.SkillAttackProc[2], other, EQEmu::CastingSlot::Item, 0, -1,
|
||||||
spells[aabonuses.SkillAttackProc[2]].ResistDiff);
|
spells[aabonuses.SkillAttackProc[2]].ResistDiff);
|
||||||
}
|
}
|
||||||
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse, true, -1, false, special);
|
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse, true, -1, false, special);
|
||||||
@ -1802,7 +1800,7 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, EQEmu::skills::Skill
|
|||||||
//handle EVENT_ATTACK. Resets after we have not been attacked for 12 seconds
|
//handle EVENT_ATTACK. Resets after we have not been attacked for 12 seconds
|
||||||
if(attacked_timer.Check())
|
if(attacked_timer.Check())
|
||||||
{
|
{
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Triggering EVENT_ATTACK due to attack by %s", other->GetName());
|
Log.Out(Logs::Detail, Logs::Combat, "Triggering EVENT_ATTACK due to attack by %s", other ? other->GetName() : "nullptr");
|
||||||
parse->EventNPC(EVENT_ATTACK, this, other, "", 0);
|
parse->EventNPC(EVENT_ATTACK, this, other, "", 0);
|
||||||
}
|
}
|
||||||
attacked_timer.Start(CombatEventTimer_expire);
|
attacked_timer.Start(CombatEventTimer_expire);
|
||||||
@ -1821,7 +1819,7 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, EQEmu::skills::Skill
|
|||||||
if(IsLDoNTrapped())
|
if(IsLDoNTrapped())
|
||||||
{
|
{
|
||||||
Message_StringID(13, LDON_ACCIDENT_SETOFF2);
|
Message_StringID(13, LDON_ACCIDENT_SETOFF2);
|
||||||
SpellFinished(GetLDoNTrapSpellID(), other, 10, 0, -1, spells[GetLDoNTrapSpellID()].ResistDiff, false);
|
SpellFinished(GetLDoNTrapSpellID(), other, EQEmu::CastingSlot::Item, 0, -1, spells[GetLDoNTrapSpellID()].ResistDiff, false);
|
||||||
SetLDoNTrapSpellID(0);
|
SetLDoNTrapSpellID(0);
|
||||||
SetLDoNTrapped(false);
|
SetLDoNTrapped(false);
|
||||||
SetLDoNTrapDetected(false);
|
SetLDoNTrapDetected(false);
|
||||||
@ -3169,68 +3167,63 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
|||||||
BuffFadeByEffect(SE_Mez);
|
BuffFadeByEffect(SE_Mez);
|
||||||
}
|
}
|
||||||
|
|
||||||
//check stun chances if bashing
|
// broken up for readability
|
||||||
if (damage > 0 && ((skill_used == EQEmu::skills::SkillBash || skill_used == EQEmu::skills::SkillKick) && attacker)) {
|
// This is based on what the client is doing
|
||||||
// NPCs can stun with their bash/kick as soon as they receive it.
|
// We had a bunch of stuff like BaseImmunityLevel checks, which I think is suppose to just be for spells
|
||||||
// Clients can stun mobs under level 56 with their kick when they get level 55 or greater.
|
// This is missing some merc checks, but those mostly just skipped the spell bonuses I think ...
|
||||||
// Clients have a chance to stun if the mob is 56+
|
bool can_stun = false;
|
||||||
|
int stunbash_chance = 0; // bonus
|
||||||
// Calculate the chance to stun
|
if (attacker) {
|
||||||
int stun_chance = 0;
|
if (skill_used == EQEmu::skills::SkillBash) {
|
||||||
if (!GetSpecialAbility(UNSTUNABLE)) {
|
can_stun = true;
|
||||||
if (attacker->IsNPC()) {
|
if (attacker->IsClient())
|
||||||
stun_chance = RuleI(Combat, NPCBashKickStunChance);
|
stunbash_chance = attacker->spellbonuses.StunBashChance +
|
||||||
} else if (attacker->IsClient()) {
|
|
||||||
// Less than base immunity
|
|
||||||
// Client vs. Client always uses the chance
|
|
||||||
if (!IsClient() && GetLevel() <= RuleI(Spells, BaseImmunityLevel)) {
|
|
||||||
if (skill_used == EQEmu::skills::SkillBash) // Bash always will
|
|
||||||
stun_chance = 100;
|
|
||||||
else if (attacker->GetLevel() >= RuleI(Combat, ClientStunLevel))
|
|
||||||
stun_chance = 100; // only if you're over level 55 and using kick
|
|
||||||
} else { // higher than base immunity or Client vs. Client
|
|
||||||
// not sure on this number, use same as NPC for now
|
|
||||||
if (skill_used == EQEmu::skills::SkillKick && attacker->GetLevel() < RuleI(Combat, ClientStunLevel))
|
|
||||||
stun_chance = RuleI(Combat, NPCBashKickStunChance);
|
|
||||||
else if (skill_used == EQEmu::skills::SkillBash)
|
|
||||||
stun_chance = RuleI(Combat, NPCBashKickStunChance) +
|
|
||||||
attacker->spellbonuses.StunBashChance +
|
|
||||||
attacker->itembonuses.StunBashChance +
|
attacker->itembonuses.StunBashChance +
|
||||||
attacker->aabonuses.StunBashChance;
|
attacker->aabonuses.StunBashChance;
|
||||||
}
|
} else if (skill_used == EQEmu::skills::SkillKick &&
|
||||||
}
|
(attacker->GetLevel() > 55 || attacker->IsNPC()) && GetClass() == WARRIOR) {
|
||||||
|
can_stun = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stun_chance && zone->random.Roll(stun_chance)) {
|
if ((GetBaseRace() == OGRE || GetBaseRace() == OGGOK_CITIZEN) &&
|
||||||
// Passed stun, try to resist now
|
!attacker->BehindMob(this, attacker->GetX(), attacker->GetY()))
|
||||||
int stun_resist = itembonuses.StunResist + spellbonuses.StunResist;
|
can_stun = false;
|
||||||
int frontal_stun_resist = itembonuses.FrontalStunResist + spellbonuses.FrontalStunResist;
|
if (GetSpecialAbility(UNSTUNABLE))
|
||||||
|
can_stun = false;
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Stun passed, checking resists. Was %d chance.", stun_chance);
|
|
||||||
if (IsClient()) {
|
|
||||||
stun_resist += aabonuses.StunResist;
|
|
||||||
frontal_stun_resist += aabonuses.FrontalStunResist;
|
|
||||||
}
|
}
|
||||||
|
if (can_stun) {
|
||||||
// frontal stun check for ogres/bonuses
|
int bashsave_roll = zone->random.Int(0, 100);
|
||||||
if (((GetBaseRace() == OGRE && IsClient()) ||
|
if (bashsave_roll > 98 || bashsave_roll > (55 - stunbash_chance)) {
|
||||||
(frontal_stun_resist && zone->random.Roll(frontal_stun_resist))) &&
|
// did stun -- roll other resists
|
||||||
!attacker->BehindMob(this, attacker->GetX(), attacker->GetY())) {
|
// SE_FrontalStunResist description says any angle now a days
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Frontal stun resisted. %d chance.", frontal_stun_resist);
|
int stun_resist2 = spellbonuses.FrontalStunResist + itembonuses.FrontalStunResist +
|
||||||
|
aabonuses.FrontalStunResist;
|
||||||
|
if (zone->random.Int(1, 100) > stun_resist2) {
|
||||||
|
// stun resist 2 failed
|
||||||
|
// time to check SE_StunResist and mod2 stun resist
|
||||||
|
int stun_resist =
|
||||||
|
spellbonuses.StunResist + itembonuses.StunResist + aabonuses.StunResist;
|
||||||
|
if (zone->random.Int(0, 100) >= stun_resist) {
|
||||||
|
// did stun
|
||||||
|
// nothing else to check!
|
||||||
|
Stun(2000); // straight 2 seconds every time
|
||||||
} else {
|
} else {
|
||||||
// Normal stun resist check.
|
// stun resist passed!
|
||||||
if (stun_resist && zone->random.Roll(stun_resist)) {
|
|
||||||
if (IsClient())
|
if (IsClient())
|
||||||
Message_StringID(MT_Stun, SHAKE_OFF_STUN);
|
Message_StringID(MT_Stun, SHAKE_OFF_STUN);
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Stun Resisted. %d chance.", stun_resist);
|
|
||||||
} else {
|
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Stunned. %d resist chance.", stun_resist);
|
|
||||||
Stun(zone->random.Int(0, 2) * 1000); // 0-2 seconds
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Stun failed. %d chance.", stun_chance);
|
// stun resist 2 passed!
|
||||||
|
if (IsClient())
|
||||||
|
Message_StringID(MT_Stun, AVOID_STUNNING_BLOW);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// main stun failed -- extra interrupt roll
|
||||||
|
if (IsCasting() &&
|
||||||
|
!EQEmu::ValueWithin(casting_spell_id, 859, 1023)) // these spells are excluded
|
||||||
|
// 90% chance >< -- stun immune won't reach this branch though :(
|
||||||
|
if (zone->random.Int(0, 9) > 1)
|
||||||
|
InterruptSpell();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3268,7 +3261,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
|||||||
a->damage = damage;
|
a->damage = damage;
|
||||||
a->spellid = spell_id;
|
a->spellid = spell_id;
|
||||||
a->special = special;
|
a->special = special;
|
||||||
a->meleepush_xy = attacker->GetHeading() * 2.0f;
|
a->meleepush_xy = attacker ? attacker->GetHeading() * 2.0f : 0.0f;
|
||||||
if (RuleB(Combat, MeleePush) && damage > 0 && !IsRooted() &&
|
if (RuleB(Combat, MeleePush) && damage > 0 && !IsRooted() &&
|
||||||
(IsClient() || zone->random.Roll(RuleI(Combat, MeleePushChance)))) {
|
(IsClient() || zone->random.Roll(RuleI(Combat, MeleePushChance)))) {
|
||||||
a->force = EQEmu::skills::GetSkillMeleePushForce(skill_used);
|
a->force = EQEmu::skills::GetSkillMeleePushForce(skill_used);
|
||||||
@ -3805,7 +3798,7 @@ void Mob::TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage)
|
|||||||
|
|
||||||
void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttackOptions *opts)
|
void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttackOptions *opts)
|
||||||
{
|
{
|
||||||
if(damage < 1)
|
if(damage < 1 || !defender)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// decided to branch this into it's own function since it's going to be duplicating a lot of the
|
// decided to branch this into it's own function since it's going to be duplicating a lot of the
|
||||||
@ -3826,8 +3819,8 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack
|
|||||||
bool IsBerskerSPA = false;
|
bool IsBerskerSPA = false;
|
||||||
|
|
||||||
//1: Try Slay Undead
|
//1: Try Slay Undead
|
||||||
if (defender && (defender->GetBodyType() == BT_Undead ||
|
if (defender->GetBodyType() == BT_Undead ||
|
||||||
defender->GetBodyType() == BT_SummonedUndead || defender->GetBodyType() == BT_Vampire)) {
|
defender->GetBodyType() == BT_SummonedUndead || defender->GetBodyType() == BT_Vampire) {
|
||||||
int32 SlayRateBonus = aabonuses.SlayUndead[0] + itembonuses.SlayUndead[0] + spellbonuses.SlayUndead[0];
|
int32 SlayRateBonus = aabonuses.SlayUndead[0] + itembonuses.SlayUndead[0] + spellbonuses.SlayUndead[0];
|
||||||
if (SlayRateBonus) {
|
if (SlayRateBonus) {
|
||||||
float slayChance = static_cast<float>(SlayRateBonus) / 10000.0f;
|
float slayChance = static_cast<float>(SlayRateBonus) / 10000.0f;
|
||||||
|
|||||||
54
zone/bot.cpp
54
zone/bot.cpp
@ -1709,8 +1709,8 @@ bool Bot::LoadPet()
|
|||||||
|
|
||||||
NPC *pet_inst = GetPet()->CastToNPC();
|
NPC *pet_inst = GetPet()->CastToNPC();
|
||||||
|
|
||||||
SpellBuff_Struct pet_buffs[BUFF_COUNT];
|
SpellBuff_Struct pet_buffs[PET_BUFF_COUNT];
|
||||||
memset(pet_buffs, 0, (sizeof(SpellBuff_Struct) * BUFF_COUNT));
|
memset(pet_buffs, 0, (sizeof(SpellBuff_Struct) * PET_BUFF_COUNT));
|
||||||
if (!botdb.LoadPetBuffs(GetBotID(), pet_buffs))
|
if (!botdb.LoadPetBuffs(GetBotID(), pet_buffs))
|
||||||
bot_owner->Message(13, "%s for %s's pet", BotDatabase::fail::LoadPetBuffs(), GetCleanName());
|
bot_owner->Message(13, "%s for %s's pet", BotDatabase::fail::LoadPetBuffs(), GetCleanName());
|
||||||
|
|
||||||
@ -1741,11 +1741,11 @@ bool Bot::SavePet()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
char* pet_name = new char[64];
|
char* pet_name = new char[64];
|
||||||
SpellBuff_Struct pet_buffs[BUFF_COUNT];
|
SpellBuff_Struct pet_buffs[PET_BUFF_COUNT];
|
||||||
uint32 pet_items[EQEmu::legacy::EQUIPMENT_SIZE];
|
uint32 pet_items[EQEmu::legacy::EQUIPMENT_SIZE];
|
||||||
|
|
||||||
memset(pet_name, 0, 64);
|
memset(pet_name, 0, 64);
|
||||||
memset(pet_buffs, 0, (sizeof(SpellBuff_Struct) * BUFF_COUNT));
|
memset(pet_buffs, 0, (sizeof(SpellBuff_Struct) * PET_BUFF_COUNT));
|
||||||
memset(pet_items, 0, (sizeof(uint32) * EQEmu::legacy::EQUIPMENT_SIZE));
|
memset(pet_items, 0, (sizeof(uint32) * EQEmu::legacy::EQUIPMENT_SIZE));
|
||||||
|
|
||||||
pet_inst->GetPetState(pet_buffs, pet_items, pet_name);
|
pet_inst->GetPetState(pet_buffs, pet_items, pet_name);
|
||||||
@ -2085,7 +2085,7 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, EQEmu::skills:
|
|||||||
CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
|
CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
|
||||||
|
|
||||||
if ((skillinuse == EQEmu::skills::SkillDragonPunch) && GetAA(aaDragonPunch) && zone->random.Int(0, 99) < 25){
|
if ((skillinuse == EQEmu::skills::SkillDragonPunch) && GetAA(aaDragonPunch) && zone->random.Int(0, 99) < 25){
|
||||||
SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff);
|
SpellFinished(904, other, EQEmu::CastingSlot::Item, 0, -1, spells[904].ResistDiff);
|
||||||
other->Stun(100);
|
other->Stun(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5900,7 +5900,7 @@ void Bot::DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster) {
|
|||||||
Mob::DoBuffTic(buff, slot, caster);
|
Mob::DoBuffTic(buff, slot, caster);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_time, int32 mana_cost,
|
bool Bot::CastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot, int32 cast_time, int32 mana_cost,
|
||||||
uint32* oSpellWillFinish, uint32 item_slot, int16 *resist_adjust, uint32 aa_id) {
|
uint32* oSpellWillFinish, uint32 item_slot, int16 *resist_adjust, uint32 aa_id) {
|
||||||
bool Result = false;
|
bool Result = false;
|
||||||
if(zone && !zone->IsSpellBlocked(spell_id, glm::vec3(GetPosition()))) {
|
if(zone && !zone->IsSpellBlocked(spell_id, glm::vec3(GetPosition()))) {
|
||||||
@ -5920,7 +5920,7 @@ bool Bot::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_t
|
|||||||
Message_StringID(13, MELEE_SILENCE);
|
Message_StringID(13, MELEE_SILENCE);
|
||||||
|
|
||||||
if(casting_spell_id)
|
if(casting_spell_id)
|
||||||
AI_Event_SpellCastFinished(false, casting_spell_slot);
|
AI_Event_SpellCastFinished(false, static_cast<uint16>(casting_spell_slot));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -5929,7 +5929,7 @@ bool Bot::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_t
|
|||||||
if(IsDetrimentalSpell(spell_id) && !zone->CanDoCombat()){
|
if(IsDetrimentalSpell(spell_id) && !zone->CanDoCombat()){
|
||||||
Message_StringID(13, SPELL_WOULDNT_HOLD);
|
Message_StringID(13, SPELL_WOULDNT_HOLD);
|
||||||
if(casting_spell_id)
|
if(casting_spell_id)
|
||||||
AI_Event_SpellCastFinished(false, casting_spell_slot);
|
AI_Event_SpellCastFinished(false, static_cast<uint16>(casting_spell_slot));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -5940,7 +5940,7 @@ bool Bot::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_t
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(slot < MAX_PP_MEMSPELL && !CheckFizzle(spell_id)) {
|
if(slot < EQEmu::CastingSlot::MaxGems && !CheckFizzle(spell_id)) {
|
||||||
int fizzle_msg = IsBardSong(spell_id) ? MISS_NOTE : SPELL_FIZZLE;
|
int fizzle_msg = IsBardSong(spell_id) ? MISS_NOTE : SPELL_FIZZLE;
|
||||||
InterruptSpell(fizzle_msg, 0x121, spell_id);
|
InterruptSpell(fizzle_msg, 0x121, spell_id);
|
||||||
|
|
||||||
@ -5954,7 +5954,7 @@ bool Bot::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_t
|
|||||||
Log.Out(Logs::Detail, Logs::Spells, "Casting a new spell/song while singing a song. Killing old song %d.", bardsong);
|
Log.Out(Logs::Detail, Logs::Spells, "Casting a new spell/song while singing a song. Killing old song %d.", bardsong);
|
||||||
bardsong = 0;
|
bardsong = 0;
|
||||||
bardsong_target_id = 0;
|
bardsong_target_id = 0;
|
||||||
bardsong_slot = 0;
|
bardsong_slot = EQEmu::CastingSlot::Gem1;
|
||||||
bardsong_timer.Disable();
|
bardsong_timer.Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6084,7 +6084,7 @@ bool Bot::IsImmuneToSpell(uint16 spell_id, Mob *caster) {
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, uint16 slot) {
|
bool Bot::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, EQEmu::CastingSlot slot) {
|
||||||
bool Result = false;
|
bool Result = false;
|
||||||
SpellTargetType targetType = spells[spell_id].targettype;
|
SpellTargetType targetType = spells[spell_id].targettype;
|
||||||
if(targetType == ST_GroupClientAndPet) {
|
if(targetType == ST_GroupClientAndPet) {
|
||||||
@ -6097,7 +6097,7 @@ bool Bot::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot, uint32 aa_id) {
|
bool Bot::DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot, uint32 aa_id) {
|
||||||
bool Result = false;
|
bool Result = false;
|
||||||
if(GetClass() == BARD)
|
if(GetClass() == BARD)
|
||||||
cast_time = 0;
|
cast_time = 0;
|
||||||
@ -6201,7 +6201,7 @@ void Bot::GenerateSpecialAttacks() {
|
|||||||
SetSpecialAbility(SPECATK_TRIPLE, 1);
|
SetSpecialAbility(SPECATK_TRIPLE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool& stopLogic) {
|
bool Bot::DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool& stopLogic) {
|
||||||
if(GetClass() == BARD) {
|
if(GetClass() == BARD) {
|
||||||
if(!ApplyNextBardPulse(bardsong, this, bardsong_slot))
|
if(!ApplyNextBardPulse(bardsong, this, bardsong_slot))
|
||||||
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
||||||
@ -6211,7 +6211,7 @@ bool Bot::DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, uint16 slot
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool& stopLogic) {
|
bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool& stopLogic) {
|
||||||
if(spellTarget) {
|
if(spellTarget) {
|
||||||
if(IsGrouped() && (spellTarget->IsBot() || spellTarget->IsClient()) && RuleB(Bots, GroupBuffing)) {
|
if(IsGrouped() && (spellTarget->IsBot() || spellTarget->IsClient()) && RuleB(Bots, GroupBuffing)) {
|
||||||
bool noGroupSpell = false;
|
bool noGroupSpell = false;
|
||||||
@ -6223,7 +6223,7 @@ bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, uint16
|
|||||||
bool spelltypeequal = ((spelltype == 2) || (spelltype == 16) || (spelltype == 32));
|
bool spelltypeequal = ((spelltype == 2) || (spelltype == 16) || (spelltype == 32));
|
||||||
bool spelltypetargetequal = ((spelltype == 8) && (spells[thespell].targettype == ST_Self));
|
bool spelltypetargetequal = ((spelltype == 8) && (spells[thespell].targettype == ST_Self));
|
||||||
bool spelltypeclassequal = ((spelltype == 1024) && (GetClass() == SHAMAN));
|
bool spelltypeclassequal = ((spelltype == 1024) && (GetClass() == SHAMAN));
|
||||||
bool slotequal = (slot == USE_ITEM_SPELL_SLOT);
|
bool slotequal = (slot == EQEmu::CastingSlot::Item);
|
||||||
if(spellequal || slotequal) {
|
if(spellequal || slotequal) {
|
||||||
if((spelltypeequal || spelltypetargetequal) || spelltypeclassequal || slotequal) {
|
if((spelltypeequal || spelltypetargetequal) || spelltypeclassequal || slotequal) {
|
||||||
if(((spells[thespell].effectid[0] == 0) && (spells[thespell].base[0] < 0)) &&
|
if(((spells[thespell].effectid[0] == 0) && (spells[thespell].base[0] < 0)) &&
|
||||||
@ -6262,7 +6262,7 @@ bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, uint16
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool& stopLogic) {
|
bool Bot::DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool& stopLogic) {
|
||||||
bool isMainGroupMGB = false;
|
bool isMainGroupMGB = false;
|
||||||
if(isMainGroupMGB && (GetClass() != BARD)) {
|
if(isMainGroupMGB && (GetClass() != BARD)) {
|
||||||
BotGroupSay(this, "MGB %s", spells[spell_id].name);
|
BotGroupSay(this, "MGB %s", spells[spell_id].name);
|
||||||
@ -8159,7 +8159,25 @@ bool Bot::GetNeedsCured(Mob *tar) {
|
|||||||
int buffsWithCounters = 0;
|
int buffsWithCounters = 0;
|
||||||
needCured = true;
|
needCured = true;
|
||||||
for (unsigned int j = 0; j < buff_count; j++) {
|
for (unsigned int j = 0; j < buff_count; j++) {
|
||||||
if(tar->GetBuffs()[j].spellid != SPELL_UNKNOWN) {
|
// this should prevent crashes until the cause can be found
|
||||||
|
if (!tar->GetBuffs()) {
|
||||||
|
std::string mob_type = "Unknown";
|
||||||
|
if (tar->IsClient())
|
||||||
|
mob_type = "Client";
|
||||||
|
else if (tar->IsBot())
|
||||||
|
mob_type = "Bot";
|
||||||
|
else if (tar->IsMerc())
|
||||||
|
mob_type = "Merc";
|
||||||
|
else if (tar->IsPet())
|
||||||
|
mob_type = "Pet";
|
||||||
|
else if (tar->IsNPC())
|
||||||
|
mob_type = "NPC";
|
||||||
|
|
||||||
|
Log.Out(Logs::General, Logs::Error, "Bot::GetNeedsCured() processed mob type '%s' with a null buffs pointer (mob: '%s')", mob_type.c_str(), tar->GetName());
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(tar->GetBuffs()[j].spellid != SPELL_UNKNOWN) {
|
||||||
if(CalculateCounters(tar->GetBuffs()[j].spellid) > 0) {
|
if(CalculateCounters(tar->GetBuffs()[j].spellid) > 0) {
|
||||||
buffsWithCounters++;
|
buffsWithCounters++;
|
||||||
if(buffsWithCounters == 1 && (tar->GetBuffs()[j].ticsremaining < 2 || (int32)((tar->GetBuffs()[j].ticsremaining * 6) / tar->GetBuffs()[j].counters) < 2)) {
|
if(buffsWithCounters == 1 && (tar->GetBuffs()[j].ticsremaining < 2 || (int32)((tar->GetBuffs()[j].ticsremaining * 6) / tar->GetBuffs()[j].counters) < 2)) {
|
||||||
@ -8251,7 +8269,7 @@ bool Bot::UseDiscipline(uint32 spell_id, uint32 target) {
|
|||||||
if(IsCasting())
|
if(IsCasting())
|
||||||
InterruptSpell();
|
InterruptSpell();
|
||||||
|
|
||||||
CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT);
|
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
zone/bot.h
12
zone/bot.h
@ -274,9 +274,9 @@ public:
|
|||||||
virtual void SetAttackTimer();
|
virtual void SetAttackTimer();
|
||||||
uint32 GetClassHPFactor();
|
uint32 GetClassHPFactor();
|
||||||
virtual int32 CalcMaxHP();
|
virtual int32 CalcMaxHP();
|
||||||
bool DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool &stopLogic);
|
bool DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic);
|
||||||
bool DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool &stopLogic);
|
bool DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic);
|
||||||
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool &stopLogic);
|
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic);
|
||||||
void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color);
|
void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color);
|
||||||
void Camp(bool databaseSave = true);
|
void Camp(bool databaseSave = true);
|
||||||
virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false);
|
virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false);
|
||||||
@ -374,12 +374,12 @@ public:
|
|||||||
virtual float GetAOERange(uint16 spell_id);
|
virtual float GetAOERange(uint16 spell_id);
|
||||||
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100);
|
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100);
|
||||||
virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr);
|
virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr);
|
||||||
virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0,
|
virtual bool CastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0,
|
||||||
uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr, uint32 aa_id = 0);
|
uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr, uint32 aa_id = 0);
|
||||||
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar);
|
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar);
|
||||||
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
|
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
|
||||||
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, uint16 slot);
|
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, EQEmu::CastingSlot slot);
|
||||||
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, uint32 aa_id = 0);
|
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, uint32 aa_id = 0);
|
||||||
|
|
||||||
// Bot Equipment & Inventory Class Methods
|
// Bot Equipment & Inventory Class Methods
|
||||||
void BotTradeSwapItem(Client* client, int16 lootSlot, const ItemInst* inst, const ItemInst* inst_swap, uint32 equipableSlots, std::string* errorMessage, bool swap = true);
|
void BotTradeSwapItem(Client* client, int16 lootSlot, const ItemInst* inst, const ItemInst* inst_swap, uint32 equipableSlots, std::string* errorMessage, bool swap = true);
|
||||||
|
|||||||
@ -7613,7 +7613,7 @@ bool helper_cast_standard_spell(Bot* casting_bot, Mob* target_mob, int spell_id,
|
|||||||
if (annouce_cast)
|
if (annouce_cast)
|
||||||
Bot::BotGroupSay(casting_bot, "Attempting to cast '%s' on %s", spells[spell_id].name, target_mob->GetCleanName());
|
Bot::BotGroupSay(casting_bot, "Attempting to cast '%s' on %s", spells[spell_id].name, target_mob->GetCleanName());
|
||||||
|
|
||||||
return casting_bot->CastSpell(spell_id, target_mob->GetID(), 1, -1, -1, dont_root_before);
|
return casting_bot->CastSpell(spell_id, target_mob->GetID(), EQEmu::CastingSlot::Gem2, -1, -1, dont_root_before);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool helper_command_alias_fail(Client *bot_owner, const char* command_handler, const char *alias, const char *command)
|
bool helper_command_alias_fail(Client *bot_owner, const char* command_handler, const char *alias, const char *command)
|
||||||
|
|||||||
@ -1472,7 +1472,7 @@ bool BotDatabase::LoadPetBuffs(const uint32 bot_id, SpellBuff_Struct* pet_buffs)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
int buff_index = 0;
|
int buff_index = 0;
|
||||||
for (auto row = results.begin(); row != results.end() && buff_index < BUFF_COUNT; ++row) {
|
for (auto row = results.begin(); row != results.end() && buff_index < PET_BUFF_COUNT; ++row) {
|
||||||
pet_buffs[buff_index].spellid = atoi(row[0]);
|
pet_buffs[buff_index].spellid = atoi(row[0]);
|
||||||
pet_buffs[buff_index].level = atoi(row[1]);
|
pet_buffs[buff_index].level = atoi(row[1]);
|
||||||
pet_buffs[buff_index].duration = atoi(row[2]);
|
pet_buffs[buff_index].duration = atoi(row[2]);
|
||||||
@ -1509,7 +1509,7 @@ bool BotDatabase::SavePetBuffs(const uint32 bot_id, const SpellBuff_Struct* pet_
|
|||||||
if (!saved_pet_index)
|
if (!saved_pet_index)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
for (int buff_index = 0; buff_index < BUFF_COUNT; ++buff_index) {
|
for (int buff_index = 0; buff_index < PET_BUFF_COUNT; ++buff_index) {
|
||||||
if (!pet_buffs[buff_index].spellid || pet_buffs[buff_index].spellid == SPELL_UNKNOWN)
|
if (!pet_buffs[buff_index].spellid || pet_buffs[buff_index].spellid == SPELL_UNKNOWN)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
@ -44,6 +44,7 @@ extern volatile bool RunLoops;
|
|||||||
#include "zonedb.h"
|
#include "zonedb.h"
|
||||||
#include "petitions.h"
|
#include "petitions.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
#include "water_map.h"
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
#include "bot_command.h"
|
#include "bot_command.h"
|
||||||
#endif
|
#endif
|
||||||
@ -155,7 +156,8 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
m_Proximity(FLT_MAX, FLT_MAX, FLT_MAX), //arbitrary large number
|
m_Proximity(FLT_MAX, FLT_MAX, FLT_MAX), //arbitrary large number
|
||||||
m_ZoneSummonLocation(-2.0f,-2.0f,-2.0f),
|
m_ZoneSummonLocation(-2.0f,-2.0f,-2.0f),
|
||||||
m_AutoAttackPosition(0.0f, 0.0f, 0.0f, 0.0f),
|
m_AutoAttackPosition(0.0f, 0.0f, 0.0f, 0.0f),
|
||||||
m_AutoAttackTargetLocation(0.0f, 0.0f, 0.0f)
|
m_AutoAttackTargetLocation(0.0f, 0.0f, 0.0f),
|
||||||
|
last_region_type(RegionTypeUnsupported)
|
||||||
{
|
{
|
||||||
for(int cf=0; cf < _FilterCount; cf++)
|
for(int cf=0; cf < _FilterCount; cf++)
|
||||||
ClientFilters[cf] = FilterShow;
|
ClientFilters[cf] = FilterShow;
|
||||||
@ -565,6 +567,11 @@ bool Client::SaveAA() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::RemoveExpendedAA(int aa_id)
|
||||||
|
{
|
||||||
|
database.QueryDatabase(StringFormat("DELETE from `character_alternate_abilities` WHERE `id` = %d and `aa_id` = %d", character_id, aa_id));
|
||||||
|
}
|
||||||
|
|
||||||
bool Client::Save(uint8 iCommitNow) {
|
bool Client::Save(uint8 iCommitNow) {
|
||||||
if(!ClientDataLoaded())
|
if(!ClientDataLoaded())
|
||||||
return false;
|
return false;
|
||||||
@ -1787,7 +1794,7 @@ const int32& Client::SetMana(int32 amount) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Client::SendManaUpdatePacket() {
|
void Client::SendManaUpdatePacket() {
|
||||||
if (!Connected() || IsCasting())
|
if (!Connected())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
||||||
@ -1801,7 +1808,8 @@ void Client::SendManaUpdatePacket() {
|
|||||||
ManaChange_Struct* manachange = (ManaChange_Struct*)outapp->pBuffer;
|
ManaChange_Struct* manachange = (ManaChange_Struct*)outapp->pBuffer;
|
||||||
manachange->new_mana = cur_mana;
|
manachange->new_mana = cur_mana;
|
||||||
manachange->stamina = cur_end;
|
manachange->stamina = cur_end;
|
||||||
manachange->spell_id = casting_spell_id; //always going to be 0... since we check IsCasting()
|
manachange->spell_id = casting_spell_id;
|
||||||
|
manachange->keepcasting = 1;
|
||||||
outapp->priority = 6;
|
outapp->priority = 6;
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
@ -2476,13 +2484,15 @@ uint16 Client::GetMaxSkillAfterSpecializationRules(EQEmu::skills::SkillType skil
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::SetPVP(bool toggle) {
|
void Client::SetPVP(bool toggle, bool message) {
|
||||||
m_pp.pvp = toggle ? 1 : 0;
|
m_pp.pvp = toggle ? 1 : 0;
|
||||||
|
|
||||||
|
if (message) {
|
||||||
if(GetPVP())
|
if(GetPVP())
|
||||||
this->Message_StringID(MT_Shout,PVP_ON);
|
this->Message_StringID(MT_Shout,PVP_ON);
|
||||||
else
|
else
|
||||||
Message(13, "You no longer follow the ways of discord.");
|
Message(13, "You no longer follow the ways of discord.");
|
||||||
|
}
|
||||||
|
|
||||||
SendAppearancePacket(AT_PVP, GetPVP());
|
SendAppearancePacket(AT_PVP, GetPVP());
|
||||||
Save();
|
Save();
|
||||||
@ -3674,15 +3684,15 @@ void Client::SacrificeConfirm(Client *caster)
|
|||||||
//Essentially a special case death function
|
//Essentially a special case death function
|
||||||
void Client::Sacrifice(Client *caster)
|
void Client::Sacrifice(Client *caster)
|
||||||
{
|
{
|
||||||
if(GetLevel() >= RuleI(Spells, SacrificeMinLevel) && GetLevel() <= RuleI(Spells, SacrificeMaxLevel)){
|
if (GetLevel() >= RuleI(Spells, SacrificeMinLevel) && GetLevel() <= RuleI(Spells, SacrificeMaxLevel)) {
|
||||||
int exploss = (int)(GetLevel() * (GetLevel() / 18.0) * 12000);
|
int exploss = (int)(GetLevel() * (GetLevel() / 18.0) * 12000);
|
||||||
if(exploss < GetEXP()){
|
if (exploss < GetEXP()) {
|
||||||
SetEXP(GetEXP()-exploss, GetAAXP());
|
SetEXP(GetEXP() - exploss, GetAAXP());
|
||||||
SendLogoutPackets();
|
SendLogoutPackets();
|
||||||
|
|
||||||
//make our become corpse packet, and queue to ourself before OP_Death.
|
// make our become corpse packet, and queue to ourself before OP_Death.
|
||||||
EQApplicationPacket app2(OP_BecomeCorpse, sizeof(BecomeCorpse_Struct));
|
EQApplicationPacket app2(OP_BecomeCorpse, sizeof(BecomeCorpse_Struct));
|
||||||
BecomeCorpse_Struct* bc = (BecomeCorpse_Struct*)app2.pBuffer;
|
BecomeCorpse_Struct *bc = (BecomeCorpse_Struct *)app2.pBuffer;
|
||||||
bc->spawn_id = GetID();
|
bc->spawn_id = GetID();
|
||||||
bc->x = GetX();
|
bc->x = GetX();
|
||||||
bc->y = GetY();
|
bc->y = GetY();
|
||||||
@ -3691,7 +3701,7 @@ void Client::Sacrifice(Client *caster)
|
|||||||
|
|
||||||
// make death packet
|
// make death packet
|
||||||
EQApplicationPacket app(OP_Death, sizeof(Death_Struct));
|
EQApplicationPacket app(OP_Death, sizeof(Death_Struct));
|
||||||
Death_Struct* d = (Death_Struct*)app.pBuffer;
|
Death_Struct *d = (Death_Struct *)app.pBuffer;
|
||||||
d->spawn_id = GetID();
|
d->spawn_id = GetID();
|
||||||
d->killer_id = caster ? caster->GetID() : 0;
|
d->killer_id = caster ? caster->GetID() : 0;
|
||||||
d->bindzoneid = GetPP().binds[0].zoneId;
|
d->bindzoneid = GetPP().binds[0].zoneId;
|
||||||
@ -3704,15 +3714,15 @@ void Client::Sacrifice(Client *caster)
|
|||||||
BuffFadeAll();
|
BuffFadeAll();
|
||||||
UnmemSpellAll();
|
UnmemSpellAll();
|
||||||
Group *g = GetGroup();
|
Group *g = GetGroup();
|
||||||
if(g){
|
if (g) {
|
||||||
g->MemberZoned(this);
|
g->MemberZoned(this);
|
||||||
}
|
}
|
||||||
Raid *r = entity_list.GetRaidByClient(this);
|
Raid *r = entity_list.GetRaidByClient(this);
|
||||||
if(r){
|
if (r) {
|
||||||
r->MemberZoned(this);
|
r->MemberZoned(this);
|
||||||
}
|
}
|
||||||
ClearAllProximities();
|
ClearAllProximities();
|
||||||
if(RuleB(Character, LeaveCorpses)){
|
if (RuleB(Character, LeaveCorpses)) {
|
||||||
auto new_corpse = new Corpse(this, 0);
|
auto new_corpse = new Corpse(this, 0);
|
||||||
entity_list.AddCorpse(new_corpse, GetID());
|
entity_list.AddCorpse(new_corpse, GetID());
|
||||||
SetID(0);
|
SetID(0);
|
||||||
@ -3720,11 +3730,11 @@ void Client::Sacrifice(Client *caster)
|
|||||||
}
|
}
|
||||||
Save();
|
Save();
|
||||||
GoToDeath();
|
GoToDeath();
|
||||||
|
if (caster) // I guess it's possible?
|
||||||
caster->SummonItem(RuleI(Spells, SacrificeItemID));
|
caster->SummonItem(RuleI(Spells, SacrificeItemID));
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else{
|
caster->Message_StringID(13, SAC_TOO_LOW); // This being is not a worthy sacrifice.
|
||||||
caster->Message_StringID(13, SAC_TOO_LOW); //This being is not a worthy sacrifice.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4604,7 +4614,7 @@ void Client::HandleLDoNOpen(NPC *target)
|
|||||||
if(target->GetLDoNTrapSpellID() != 0)
|
if(target->GetLDoNTrapSpellID() != 0)
|
||||||
{
|
{
|
||||||
Message_StringID(13, LDON_ACCIDENT_SETOFF2);
|
Message_StringID(13, LDON_ACCIDENT_SETOFF2);
|
||||||
target->SpellFinished(target->GetLDoNTrapSpellID(), this, 10, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff);
|
target->SpellFinished(target->GetLDoNTrapSpellID(), this, EQEmu::CastingSlot::Item, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff);
|
||||||
target->SetLDoNTrapSpellID(0);
|
target->SetLDoNTrapSpellID(0);
|
||||||
target->SetLDoNTrapped(false);
|
target->SetLDoNTrapped(false);
|
||||||
target->SetLDoNTrapDetected(false);
|
target->SetLDoNTrapDetected(false);
|
||||||
@ -4726,7 +4736,7 @@ void Client::HandleLDoNDisarm(NPC *target, uint16 skill, uint8 type)
|
|||||||
break;
|
break;
|
||||||
case -1:
|
case -1:
|
||||||
Message_StringID(13, LDON_ACCIDENT_SETOFF2);
|
Message_StringID(13, LDON_ACCIDENT_SETOFF2);
|
||||||
target->SpellFinished(target->GetLDoNTrapSpellID(), this, 10, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff);
|
target->SpellFinished(target->GetLDoNTrapSpellID(), this, EQEmu::CastingSlot::Item, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff);
|
||||||
target->SetLDoNTrapSpellID(0);
|
target->SetLDoNTrapSpellID(0);
|
||||||
target->SetLDoNTrapped(false);
|
target->SetLDoNTrapped(false);
|
||||||
target->SetLDoNTrapDetected(false);
|
target->SetLDoNTrapDetected(false);
|
||||||
@ -4745,7 +4755,7 @@ void Client::HandleLDoNPickLock(NPC *target, uint16 skill, uint8 type)
|
|||||||
if(target->IsLDoNTrapped())
|
if(target->IsLDoNTrapped())
|
||||||
{
|
{
|
||||||
Message_StringID(13, LDON_ACCIDENT_SETOFF2);
|
Message_StringID(13, LDON_ACCIDENT_SETOFF2);
|
||||||
target->SpellFinished(target->GetLDoNTrapSpellID(), this, 10, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff);
|
target->SpellFinished(target->GetLDoNTrapSpellID(), this, EQEmu::CastingSlot::Item, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff);
|
||||||
target->SetLDoNTrapSpellID(0);
|
target->SetLDoNTrapSpellID(0);
|
||||||
target->SetLDoNTrapped(false);
|
target->SetLDoNTrapped(false);
|
||||||
target->SetLDoNTrapDetected(false);
|
target->SetLDoNTrapDetected(false);
|
||||||
@ -8396,7 +8406,7 @@ void Client::SendColoredText(uint32 color, std::string message)
|
|||||||
void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction) {
|
void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction) {
|
||||||
|
|
||||||
auto outapp = new EQApplicationPacket(OP_Sound, sizeof(QuestReward_Struct));
|
auto outapp = new EQApplicationPacket(OP_Sound, sizeof(QuestReward_Struct));
|
||||||
memset(outapp->pBuffer, 0, sizeof(outapp->pBuffer));
|
memset(outapp->pBuffer, 0, sizeof(QuestReward_Struct));
|
||||||
QuestReward_Struct* qr = (QuestReward_Struct*)outapp->pBuffer;
|
QuestReward_Struct* qr = (QuestReward_Struct*)outapp->pBuffer;
|
||||||
|
|
||||||
qr->mob_id = target->GetID(); // Entity ID for the from mob name
|
qr->mob_id = target->GetID(); // Entity ID for the from mob name
|
||||||
@ -8527,3 +8537,27 @@ uint32 Client::GetMoney(uint8 type, uint8 subtype) {
|
|||||||
int Client::GetAccountAge() {
|
int Client::GetAccountAge() {
|
||||||
return (time(nullptr) - GetAccountCreation());
|
return (time(nullptr) - GetAccountCreation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::CheckRegionTypeChanges()
|
||||||
|
{
|
||||||
|
if (!zone->HasWaterMap())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto new_region = zone->watermap->ReturnRegionType(glm::vec3(m_Position));
|
||||||
|
|
||||||
|
// still same region, do nothing
|
||||||
|
if (last_region_type == new_region)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// region type changed
|
||||||
|
last_region_type = new_region;
|
||||||
|
|
||||||
|
// PVP is the only state we need to keep track of, so we can just return now for PVP servers
|
||||||
|
if (RuleI(World, PVPSettings) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (last_region_type == RegionTypePVP)
|
||||||
|
SetPVP(true, false);
|
||||||
|
else if (GetPVP())
|
||||||
|
SetPVP(false, false);
|
||||||
|
}
|
||||||
|
|||||||
@ -27,6 +27,7 @@ class Object;
|
|||||||
class Raid;
|
class Raid;
|
||||||
class Seperator;
|
class Seperator;
|
||||||
class ServerPacket;
|
class ServerPacket;
|
||||||
|
enum WaterRegionType : int;
|
||||||
|
|
||||||
namespace EQEmu
|
namespace EQEmu
|
||||||
{
|
{
|
||||||
@ -105,6 +106,7 @@ enum { //Type arguments to the Message* routines.
|
|||||||
|
|
||||||
#define SPELLBAR_UNLOCK 0x2bc
|
#define SPELLBAR_UNLOCK 0x2bc
|
||||||
enum { //scribing argument to MemorizeSpell
|
enum { //scribing argument to MemorizeSpell
|
||||||
|
memSpellUnknown = -1, // this modifies some state data
|
||||||
memSpellScribing = 0,
|
memSpellScribing = 0,
|
||||||
memSpellMemorize = 1,
|
memSpellMemorize = 1,
|
||||||
memSpellForget = 2,
|
memSpellForget = 2,
|
||||||
@ -326,6 +328,7 @@ public:
|
|||||||
/* New PP Save Functions */
|
/* New PP Save Functions */
|
||||||
bool SaveCurrency(){ return database.SaveCharacterCurrency(this->CharacterID(), &m_pp); }
|
bool SaveCurrency(){ return database.SaveCharacterCurrency(this->CharacterID(), &m_pp); }
|
||||||
bool SaveAA();
|
bool SaveAA();
|
||||||
|
void RemoveExpendedAA(int aa_id);
|
||||||
|
|
||||||
inline bool ClientDataLoaded() const { return client_data_loaded; }
|
inline bool ClientDataLoaded() const { return client_data_loaded; }
|
||||||
inline bool Connected() const { return (client_state == CLIENT_CONNECTED); }
|
inline bool Connected() const { return (client_state == CLIENT_CONNECTED); }
|
||||||
@ -359,9 +362,9 @@ public:
|
|||||||
int32 LevelRegen();
|
int32 LevelRegen();
|
||||||
void HPTick();
|
void HPTick();
|
||||||
void SetGM(bool toggle);
|
void SetGM(bool toggle);
|
||||||
void SetPVP(bool toggle);
|
void SetPVP(bool toggle, bool message = true);
|
||||||
|
|
||||||
inline bool GetPVP() const { return zone->GetZoneID() == 77 ? true : (m_pp.pvp != 0); }
|
inline bool GetPVP() const { return m_pp.pvp != 0; }
|
||||||
inline bool GetGM() const { return m_pp.gm != 0; }
|
inline bool GetGM() const { return m_pp.gm != 0; }
|
||||||
|
|
||||||
inline void SetBaseClass(uint32 i) { m_pp.class_=i; }
|
inline void SetBaseClass(uint32 i) { m_pp.class_=i; }
|
||||||
@ -510,6 +513,8 @@ public:
|
|||||||
virtual int GetMaxSongSlots() const { return 12; }
|
virtual int GetMaxSongSlots() const { return 12; }
|
||||||
virtual int GetMaxDiscSlots() const { return 1; }
|
virtual int GetMaxDiscSlots() const { return 1; }
|
||||||
virtual int GetMaxTotalSlots() const { return 38; }
|
virtual int GetMaxTotalSlots() const { return 38; }
|
||||||
|
virtual uint32 GetFirstBuffSlot(bool disc, bool song);
|
||||||
|
virtual uint32 GetLastBuffSlot(bool disc, bool song);
|
||||||
virtual void InitializeBuffSlots();
|
virtual void InitializeBuffSlots();
|
||||||
virtual void UninitializeBuffSlots();
|
virtual void UninitializeBuffSlots();
|
||||||
|
|
||||||
@ -889,6 +894,9 @@ public:
|
|||||||
void SendDisciplineTimer(uint32 timer_id, uint32 duration);
|
void SendDisciplineTimer(uint32 timer_id, uint32 duration);
|
||||||
bool UseDiscipline(uint32 spell_id, uint32 target);
|
bool UseDiscipline(uint32 spell_id, uint32 target);
|
||||||
|
|
||||||
|
void SetLinkedSpellReuseTimer(uint32 timer_id, uint32 duration);
|
||||||
|
bool IsLinkedSpellReuseTimerReady(uint32 timer_id);
|
||||||
|
|
||||||
bool CheckTitle(int titleset);
|
bool CheckTitle(int titleset);
|
||||||
void EnableTitle(int titleset);
|
void EnableTitle(int titleset);
|
||||||
void RemoveTitle(int titleset);
|
void RemoveTitle(int titleset);
|
||||||
@ -1230,6 +1238,8 @@ public:
|
|||||||
|
|
||||||
void SendHPUpdateMarquee();
|
void SendHPUpdateMarquee();
|
||||||
|
|
||||||
|
void CheckRegionTypeChanges();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Mob;
|
friend class Mob;
|
||||||
void CalcItemBonuses(StatBonuses* newbon);
|
void CalcItemBonuses(StatBonuses* newbon);
|
||||||
@ -1414,6 +1424,7 @@ private:
|
|||||||
uint8 zonesummon_ignorerestrictions;
|
uint8 zonesummon_ignorerestrictions;
|
||||||
ZoneMode zone_mode;
|
ZoneMode zone_mode;
|
||||||
|
|
||||||
|
WaterRegionType last_region_type;
|
||||||
|
|
||||||
Timer position_timer;
|
Timer position_timer;
|
||||||
uint8 position_timer_counter;
|
uint8 position_timer_counter;
|
||||||
|
|||||||
@ -1036,6 +1036,13 @@ int32 Client::CalcAC()
|
|||||||
if (avoidance < 0) {
|
if (avoidance < 0) {
|
||||||
avoidance = 0;
|
avoidance = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RuleB(Character, EnableAvoidanceCap)) {
|
||||||
|
if (avoidance > RuleI(Character, AvoidanceCap)) {
|
||||||
|
avoidance = RuleI(Character, AvoidanceCap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int mitigation = 0;
|
int mitigation = 0;
|
||||||
if (m_pp.class_ == WIZARD || m_pp.class_ == MAGICIAN || m_pp.class_ == NECROMANCER || m_pp.class_ == ENCHANTER) {
|
if (m_pp.class_ == WIZARD || m_pp.class_ == MAGICIAN || m_pp.class_ == NECROMANCER || m_pp.class_ == ENCHANTER) {
|
||||||
//something is wrong with this, naked casters have the wrong natural AC
|
//something is wrong with this, naked casters have the wrong natural AC
|
||||||
@ -1113,6 +1120,13 @@ int32 Client::GetACAvoid()
|
|||||||
if (avoidance < 0) {
|
if (avoidance < 0) {
|
||||||
avoidance = 0;
|
avoidance = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RuleB(Character, EnableAvoidanceCap)) {
|
||||||
|
if ((avoidance * 1000 / 847) > RuleI(Character, AvoidanceCap)) {
|
||||||
|
return RuleI(Character, AvoidanceCap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (avoidance * 1000 / 847);
|
return (avoidance * 1000 / 847);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -502,6 +502,27 @@ void Client::CompleteConnect()
|
|||||||
SetDuelTarget(0);
|
SetDuelTarget(0);
|
||||||
SetDueling(false);
|
SetDueling(false);
|
||||||
|
|
||||||
|
database.LoadPetInfo(this);
|
||||||
|
/*
|
||||||
|
This was moved before the spawn packets are sent
|
||||||
|
in hopes that it adds more consistency...
|
||||||
|
Remake pet
|
||||||
|
*/
|
||||||
|
if (m_petinfo.SpellID > 1 && !GetPet() && m_petinfo.SpellID <= SPDAT_RECORDS) {
|
||||||
|
MakePoweredPet(m_petinfo.SpellID, spells[m_petinfo.SpellID].teleport_zone, m_petinfo.petpower, m_petinfo.Name, m_petinfo.size);
|
||||||
|
if (GetPet() && GetPet()->IsNPC()) {
|
||||||
|
NPC *pet = GetPet()->CastToNPC();
|
||||||
|
pet->SetPetState(m_petinfo.Buffs, m_petinfo.Items);
|
||||||
|
pet->CalcBonuses();
|
||||||
|
pet->SetHP(m_petinfo.HP);
|
||||||
|
pet->SetMana(m_petinfo.Mana);
|
||||||
|
}
|
||||||
|
m_petinfo.SpellID = 0;
|
||||||
|
}
|
||||||
|
/* Moved here so it's after where we load the pet data. */
|
||||||
|
if (!GetAA(aaPersistentMinion))
|
||||||
|
memset(&m_suspendedminion, 0, sizeof(PetInfo));
|
||||||
|
|
||||||
EnteringMessages(this);
|
EnteringMessages(this);
|
||||||
LoadZoneFlags();
|
LoadZoneFlags();
|
||||||
|
|
||||||
@ -1628,27 +1649,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
|||||||
if (m_pp.RestTimer)
|
if (m_pp.RestTimer)
|
||||||
rest_timer.Start(m_pp.RestTimer * 1000);
|
rest_timer.Start(m_pp.RestTimer * 1000);
|
||||||
|
|
||||||
database.LoadPetInfo(this);
|
|
||||||
/*
|
|
||||||
This was moved before the spawn packets are sent
|
|
||||||
in hopes that it adds more consistency...
|
|
||||||
Remake pet
|
|
||||||
*/
|
|
||||||
if (m_petinfo.SpellID > 1 && !GetPet() && m_petinfo.SpellID <= SPDAT_RECORDS) {
|
|
||||||
MakePoweredPet(m_petinfo.SpellID, spells[m_petinfo.SpellID].teleport_zone, m_petinfo.petpower, m_petinfo.Name, m_petinfo.size);
|
|
||||||
if (GetPet() && GetPet()->IsNPC()) {
|
|
||||||
NPC *pet = GetPet()->CastToNPC();
|
|
||||||
pet->SetPetState(m_petinfo.Buffs, m_petinfo.Items);
|
|
||||||
pet->CalcBonuses();
|
|
||||||
pet->SetHP(m_petinfo.HP);
|
|
||||||
pet->SetMana(m_petinfo.Mana);
|
|
||||||
}
|
|
||||||
m_petinfo.SpellID = 0;
|
|
||||||
}
|
|
||||||
/* Moved here so it's after where we load the pet data. */
|
|
||||||
if (!GetAA(aaPersistentMinion))
|
|
||||||
memset(&m_suspendedminion, 0, sizeof(PetInfo));
|
|
||||||
|
|
||||||
/* Server Zone Entry Packet */
|
/* Server Zone Entry Packet */
|
||||||
outapp = new EQApplicationPacket(OP_ZoneEntry, sizeof(ServerZoneEntry_Struct));
|
outapp = new EQApplicationPacket(OP_ZoneEntry, sizeof(ServerZoneEntry_Struct));
|
||||||
ServerZoneEntry_Struct* sze = (ServerZoneEntry_Struct*)outapp->pBuffer;
|
ServerZoneEntry_Struct* sze = (ServerZoneEntry_Struct*)outapp->pBuffer;
|
||||||
@ -3966,6 +3966,7 @@ void Client::Handle_OP_CancelTrade(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
|
using EQEmu::CastingSlot;
|
||||||
if (app->size != sizeof(CastSpell_Struct)) {
|
if (app->size != sizeof(CastSpell_Struct)) {
|
||||||
std::cout << "Wrong size: OP_CastSpell, size=" << app->size << ", expected " << sizeof(CastSpell_Struct) << std::endl;
|
std::cout << "Wrong size: OP_CastSpell, size=" << app->size << ", expected " << sizeof(CastSpell_Struct) << std::endl;
|
||||||
return;
|
return;
|
||||||
@ -3981,10 +3982,10 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
|||||||
m_TargetRing = glm::vec3(castspell->x_pos, castspell->y_pos, castspell->z_pos);
|
m_TargetRing = glm::vec3(castspell->x_pos, castspell->y_pos, castspell->z_pos);
|
||||||
|
|
||||||
Log.Out(Logs::General, Logs::Spells, "OP CastSpell: slot=%d, spell=%d, target=%d, inv=%lx", castspell->slot, castspell->spell_id, castspell->target_id, (unsigned long)castspell->inventoryslot);
|
Log.Out(Logs::General, Logs::Spells, "OP CastSpell: slot=%d, spell=%d, target=%d, inv=%lx", castspell->slot, castspell->spell_id, castspell->target_id, (unsigned long)castspell->inventoryslot);
|
||||||
|
CastingSlot slot = static_cast<CastingSlot>(castspell->slot);
|
||||||
|
|
||||||
/* Memorized Spell */
|
/* Memorized Spell */
|
||||||
if (m_pp.mem_spells[castspell->slot] && m_pp.mem_spells[castspell->slot] == castspell->spell_id){
|
if (m_pp.mem_spells[castspell->slot] && m_pp.mem_spells[castspell->slot] == castspell->spell_id) {
|
||||||
|
|
||||||
uint16 spell_to_cast = 0;
|
uint16 spell_to_cast = 0;
|
||||||
if (castspell->slot < MAX_PP_MEMSPELL) {
|
if (castspell->slot < MAX_PP_MEMSPELL) {
|
||||||
spell_to_cast = m_pp.mem_spells[castspell->slot];
|
spell_to_cast = m_pp.mem_spells[castspell->slot];
|
||||||
@ -3998,20 +3999,12 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CastSpell(spell_to_cast, castspell->target_id, castspell->slot);
|
CastSpell(spell_to_cast, castspell->target_id, slot);
|
||||||
}
|
}
|
||||||
/* Spell Slot or Potion Belt Slot */
|
/* Spell Slot or Potion Belt Slot */
|
||||||
else if ((castspell->slot == USE_ITEM_SPELL_SLOT) || (castspell->slot == POTION_BELT_SPELL_SLOT)|| (castspell->slot == TARGET_RING_SPELL_SLOT)) // ITEM or POTION cast
|
else if (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt) // ITEM or POTION cast
|
||||||
{
|
{
|
||||||
//discipline, using the item spell slot
|
if (m_inv.SupportsClickCasting(castspell->inventoryslot) || slot == CastingSlot::PotionBelt) // sanity check
|
||||||
if (castspell->inventoryslot == INVALID_INDEX) {
|
|
||||||
if (!UseDiscipline(castspell->spell_id, castspell->target_id)) {
|
|
||||||
Log.Out(Logs::General, Logs::Spells, "Unknown ability being used by %s, spell being cast is: %i\n", GetName(), castspell->spell_id);
|
|
||||||
InterruptSpell(castspell->spell_id);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (m_inv.SupportsClickCasting(castspell->inventoryslot) || (castspell->slot == POTION_BELT_SPELL_SLOT) || (castspell->slot == TARGET_RING_SPELL_SLOT)) // sanity check
|
|
||||||
{
|
{
|
||||||
// packet field types will be reviewed as packet transistions occur
|
// packet field types will be reviewed as packet transistions occur
|
||||||
const ItemInst* inst = m_inv[castspell->inventoryslot]; //slot values are int16, need to check packet on this field
|
const ItemInst* inst = m_inv[castspell->inventoryslot]; //slot values are int16, need to check packet on this field
|
||||||
@ -4036,7 +4029,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
|||||||
int i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", castspell->inventoryslot);
|
int i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", castspell->inventoryslot);
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
CastSpell(item->Click.Effect, castspell->target_id, castspell->slot, item->CastTime, 0, 0, castspell->inventoryslot);
|
CastSpell(item->Click.Effect, castspell->target_id, slot, item->CastTime, 0, 0, castspell->inventoryslot);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
InterruptSpell(castspell->spell_id);
|
InterruptSpell(castspell->spell_id);
|
||||||
@ -4056,7 +4049,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
|||||||
int i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", castspell->inventoryslot);
|
int i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", castspell->inventoryslot);
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
CastSpell(item->Click.Effect, castspell->target_id, castspell->slot, item->CastTime, 0, 0, castspell->inventoryslot);
|
CastSpell(item->Click.Effect, castspell->target_id, slot, item->CastTime, 0, 0, castspell->inventoryslot);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
InterruptSpell(castspell->spell_id);
|
InterruptSpell(castspell->spell_id);
|
||||||
@ -4081,8 +4074,8 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
|||||||
InterruptSpell(castspell->spell_id);
|
InterruptSpell(castspell->spell_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Discipline */
|
/* Discipline -- older clients use the same slot as items, but we translate to it's own */
|
||||||
else if (castspell->slot == DISCIPLINE_SPELL_SLOT) {
|
else if (slot == CastingSlot::Discipline) {
|
||||||
if (!UseDiscipline(castspell->spell_id, castspell->target_id)) {
|
if (!UseDiscipline(castspell->spell_id, castspell->target_id)) {
|
||||||
Log.Out(Logs::General, Logs::Spells, "Unknown ability being used by %s, spell being cast is: %i\n", GetName(), castspell->spell_id);
|
Log.Out(Logs::General, Logs::Spells, "Unknown ability being used by %s, spell being cast is: %i\n", GetName(), castspell->spell_id);
|
||||||
InterruptSpell(castspell->spell_id);
|
InterruptSpell(castspell->spell_id);
|
||||||
@ -4090,7 +4083,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* ABILITY cast (LoH and Harm Touch) */
|
/* ABILITY cast (LoH and Harm Touch) */
|
||||||
else if (castspell->slot == ABILITY_SPELL_SLOT) {
|
else if (slot == CastingSlot::Ability) {
|
||||||
uint16 spell_to_cast = 0;
|
uint16 spell_to_cast = 0;
|
||||||
|
|
||||||
if (castspell->spell_id == SPELL_LAY_ON_HANDS && GetClass() == PALADIN) {
|
if (castspell->spell_id == SPELL_LAY_ON_HANDS && GetClass() == PALADIN) {
|
||||||
@ -4120,7 +4113,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (spell_to_cast > 0) // if we've matched LoH or HT, cast now
|
if (spell_to_cast > 0) // if we've matched LoH or HT, cast now
|
||||||
CastSpell(spell_to_cast, castspell->target_id, castspell->slot);
|
CastSpell(spell_to_cast, castspell->target_id, slot);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -4583,8 +4576,11 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
|
|||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(zone->watermap && zone->watermap->InLiquid(glm::vec3(m_Position)))
|
if (zone->watermap) {
|
||||||
|
if (zone->watermap->InLiquid(glm::vec3(m_Position)))
|
||||||
CheckIncreaseSkill(EQEmu::skills::SkillSwimming, nullptr, -17);
|
CheckIncreaseSkill(EQEmu::skills::SkillSwimming, nullptr, -17);
|
||||||
|
CheckRegionTypeChanges();
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -8410,6 +8406,7 @@ void Client::Handle_OP_ItemPreview(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
|
void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
|
using EQEmu::CastingSlot;
|
||||||
if (app->size != sizeof(ItemVerifyRequest_Struct))
|
if (app->size != sizeof(ItemVerifyRequest_Struct))
|
||||||
{
|
{
|
||||||
Log.Out(Logs::General, Logs::Error, "OP size error: OP_ItemVerifyRequest expected:%i got:%i", sizeof(ItemVerifyRequest_Struct), app->size);
|
Log.Out(Logs::General, Logs::Error, "OP size error: OP_ItemVerifyRequest expected:%i got:%i", sizeof(ItemVerifyRequest_Struct), app->size);
|
||||||
@ -8554,7 +8551,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
|
|||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
if (!IsCastWhileInvis(item->Click.Effect))
|
if (!IsCastWhileInvis(item->Click.Effect))
|
||||||
CommonBreakInvisible(); // client can't do this for us :(
|
CommonBreakInvisible(); // client can't do this for us :(
|
||||||
CastSpell(item->Click.Effect, target_id, USE_ITEM_SPELL_SLOT, item->CastTime, 0, 0, slot_id);
|
CastSpell(item->Click.Effect, target_id, CastingSlot::Item, item->CastTime, 0, 0, slot_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -8583,7 +8580,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
|
|||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
if (!IsCastWhileInvis(augitem->Click.Effect))
|
if (!IsCastWhileInvis(augitem->Click.Effect))
|
||||||
CommonBreakInvisible(); // client can't do this for us :(
|
CommonBreakInvisible(); // client can't do this for us :(
|
||||||
CastSpell(augitem->Click.Effect, target_id, USE_ITEM_SPELL_SLOT, augitem->CastTime, 0, 0, slot_id);
|
CastSpell(augitem->Click.Effect, target_id, CastingSlot::Item, augitem->CastTime, 0, 0, slot_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@ -624,7 +624,7 @@ bool Client::Process() {
|
|||||||
{
|
{
|
||||||
//client logged out or errored out
|
//client logged out or errored out
|
||||||
//ResetTrade();
|
//ResetTrade();
|
||||||
if (client_state != CLIENT_KICKED) {
|
if (client_state != CLIENT_KICKED && !zoning && !instalog) {
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2199,14 +2199,14 @@ void command_castspell(Client *c, const Seperator *sep)
|
|||||||
else
|
else
|
||||||
if (c->GetTarget() == 0)
|
if (c->GetTarget() == 0)
|
||||||
if(c->Admin() >= commandInstacast)
|
if(c->Admin() >= commandInstacast)
|
||||||
c->SpellFinished(spellid, 0, USE_ITEM_SPELL_SLOT, 0, -1, spells[spellid].ResistDiff);
|
c->SpellFinished(spellid, 0, EQEmu::CastingSlot::Item, 0, -1, spells[spellid].ResistDiff);
|
||||||
else
|
else
|
||||||
c->CastSpell(spellid, 0, USE_ITEM_SPELL_SLOT, 0);
|
c->CastSpell(spellid, 0, EQEmu::CastingSlot::Item, 0);
|
||||||
else
|
else
|
||||||
if(c->Admin() >= commandInstacast)
|
if(c->Admin() >= commandInstacast)
|
||||||
c->SpellFinished(spellid, c->GetTarget(), 10, 0, -1, spells[spellid].ResistDiff);
|
c->SpellFinished(spellid, c->GetTarget(), EQEmu::CastingSlot::Item, 0, -1, spells[spellid].ResistDiff);
|
||||||
else
|
else
|
||||||
c->CastSpell(spellid, c->GetTarget()->GetID(), USE_ITEM_SPELL_SLOT, 0);
|
c->CastSpell(spellid, c->GetTarget()->GetID(), EQEmu::CastingSlot::Item, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4339,11 +4339,15 @@ void command_goto(Client *c, const Seperator *sep)
|
|||||||
void command_iteminfo(Client *c, const Seperator *sep)
|
void command_iteminfo(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
auto inst = c->GetInv()[EQEmu::legacy::SlotCursor];
|
auto inst = c->GetInv()[EQEmu::legacy::SlotCursor];
|
||||||
if (!inst) { c->Message(13, "Error: You need an item on your cursor for this command"); }
|
if (!inst) {
|
||||||
|
c->Message(13, "Error: You need an item on your cursor for this command");
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto item = inst->GetItem();
|
auto item = inst->GetItem();
|
||||||
if (!item) {
|
if (!item) {
|
||||||
Log.Out(Logs::General, Logs::Inventory, "(%s) Command #iteminfo processed an item with no data pointer");
|
Log.Out(Logs::General, Logs::Inventory, "(%s) Command #iteminfo processed an item with no data pointer");
|
||||||
c->Message(13, "Error: This item has no data reference");
|
c->Message(13, "Error: This item has no data reference");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EQEmu::SayLinkEngine linker;
|
EQEmu::SayLinkEngine linker;
|
||||||
|
|||||||
@ -17,13 +17,6 @@
|
|||||||
#define _NPCPET(x) (x && x->IsNPC() && x->CastToMob()->GetOwner() && x->CastToMob()->GetOwner()->IsNPC())
|
#define _NPCPET(x) (x && x->IsNPC() && x->CastToMob()->GetOwner() && x->CastToMob()->GetOwner()->IsNPC())
|
||||||
#define _BECOMENPCPET(x) (x && x->CastToMob()->GetOwner() && x->CastToMob()->GetOwner()->IsClient() && x->CastToMob()->GetOwner()->CastToClient()->IsBecomeNPC())
|
#define _BECOMENPCPET(x) (x && x->CastToMob()->GetOwner() && x->CastToMob()->GetOwner()->IsClient() && x->CastToMob()->GetOwner()->CastToClient()->IsBecomeNPC())
|
||||||
|
|
||||||
#define USE_ITEM_SPELL_SLOT 10
|
|
||||||
#define POTION_BELT_SPELL_SLOT 11
|
|
||||||
#define TARGET_RING_SPELL_SLOT 12
|
|
||||||
#define DISCIPLINE_SPELL_SLOT 10
|
|
||||||
#define ABILITY_SPELL_SLOT 9
|
|
||||||
#define ALTERNATE_ABILITY_SPELL_SLOT 0xFF
|
|
||||||
|
|
||||||
//LOS Parameters:
|
//LOS Parameters:
|
||||||
#define HEAD_POSITION 0.9f //ratio of GetSize() where NPCs see from
|
#define HEAD_POSITION 0.9f //ratio of GetSize() where NPCs see from
|
||||||
#define SEE_POSITION 0.5f //ratio of GetSize() where NPCs try to see for LOS
|
#define SEE_POSITION 0.5f //ratio of GetSize() where NPCs try to see for LOS
|
||||||
|
|||||||
@ -1163,9 +1163,9 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char buf[88];
|
char buf[88];
|
||||||
char corpse_name[64];
|
char q_corpse_name[64];
|
||||||
strcpy(corpse_name, corpse_name);
|
strcpy(q_corpse_name, corpse_name);
|
||||||
snprintf(buf, 87, "%d %d %s", inst->GetItem()->ID, inst->GetCharges(), EntityList::RemoveNumbers(corpse_name));
|
snprintf(buf, 87, "%d %d %s", inst->GetItem()->ID, inst->GetCharges(), EntityList::RemoveNumbers(q_corpse_name));
|
||||||
buf[87] = '\0';
|
buf[87] = '\0';
|
||||||
std::vector<EQEmu::Any> args;
|
std::vector<EQEmu::Any> args;
|
||||||
args.push_back(inst);
|
args.push_back(inst);
|
||||||
|
|||||||
@ -684,9 +684,9 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (reduced_recast > 0)
|
if (reduced_recast > 0)
|
||||||
CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
|
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
|
||||||
else{
|
else{
|
||||||
CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT);
|
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,7 +694,7 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT);
|
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline);
|
||||||
}
|
}
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -927,12 +927,18 @@ bool EntityList::MakeDoorSpawnPacket(EQApplicationPacket *app, Client *client)
|
|||||||
|
|
||||||
Entity *EntityList::GetEntityMob(uint16 id)
|
Entity *EntityList::GetEntityMob(uint16 id)
|
||||||
{
|
{
|
||||||
return mob_list.count(id) ? mob_list.at(id) : nullptr;
|
auto it = mob_list.find(id);
|
||||||
|
if (it != mob_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *EntityList::GetEntityMerc(uint16 id)
|
Entity *EntityList::GetEntityMerc(uint16 id)
|
||||||
{
|
{
|
||||||
return merc_list.count(id) ? merc_list.at(id) : nullptr;
|
auto it = merc_list.find(id);
|
||||||
|
if (it != merc_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *EntityList::GetEntityMob(const char *name)
|
Entity *EntityList::GetEntityMob(const char *name)
|
||||||
@ -952,12 +958,18 @@ Entity *EntityList::GetEntityMob(const char *name)
|
|||||||
|
|
||||||
Entity *EntityList::GetEntityDoor(uint16 id)
|
Entity *EntityList::GetEntityDoor(uint16 id)
|
||||||
{
|
{
|
||||||
return door_list.count(id) ? door_list.at(id) : nullptr;
|
auto it = door_list.find(id);
|
||||||
|
if (it != door_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *EntityList::GetEntityCorpse(uint16 id)
|
Entity *EntityList::GetEntityCorpse(uint16 id)
|
||||||
{
|
{
|
||||||
return corpse_list.count(id) ? corpse_list.at(id) : nullptr;
|
auto it = corpse_list.find(id);
|
||||||
|
if (it != corpse_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *EntityList::GetEntityCorpse(const char *name)
|
Entity *EntityList::GetEntityCorpse(const char *name)
|
||||||
@ -977,22 +989,34 @@ Entity *EntityList::GetEntityCorpse(const char *name)
|
|||||||
|
|
||||||
Entity *EntityList::GetEntityTrap(uint16 id)
|
Entity *EntityList::GetEntityTrap(uint16 id)
|
||||||
{
|
{
|
||||||
return trap_list.count(id) ? trap_list.at(id) : nullptr;
|
auto it = trap_list.find(id);
|
||||||
|
if (it != trap_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *EntityList::GetEntityObject(uint16 id)
|
Entity *EntityList::GetEntityObject(uint16 id)
|
||||||
{
|
{
|
||||||
return object_list.count(id) ? object_list.at(id) : nullptr;
|
auto it = object_list.find(id);
|
||||||
|
if (it != object_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *EntityList::GetEntityBeacon(uint16 id)
|
Entity *EntityList::GetEntityBeacon(uint16 id)
|
||||||
{
|
{
|
||||||
return beacon_list.count(id) ? beacon_list.at(id) : nullptr;
|
auto it = beacon_list.find(id);
|
||||||
|
if (it != beacon_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *EntityList::GetEntityEncounter(uint16 id)
|
Entity *EntityList::GetEntityEncounter(uint16 id)
|
||||||
{
|
{
|
||||||
return encounter_list.count(id) ? encounter_list.at(id) : nullptr;
|
auto it = encounter_list.find(id);
|
||||||
|
if (it != encounter_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *EntityList::GetID(uint16 get_id)
|
Entity *EntityList::GetID(uint16 get_id)
|
||||||
@ -1188,6 +1212,8 @@ void EntityList::ChannelMessage(Mob *from, uint8 chan_num, uint8 language,
|
|||||||
|
|
||||||
void EntityList::ChannelMessageSend(Mob *to, uint8 chan_num, uint8 language, const char *message, ...)
|
void EntityList::ChannelMessageSend(Mob *to, uint8 chan_num, uint8 language, const char *message, ...)
|
||||||
{
|
{
|
||||||
|
if (!to->IsClient())
|
||||||
|
return;
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
|
|
||||||
@ -1195,8 +1221,7 @@ void EntityList::ChannelMessageSend(Mob *to, uint8 chan_num, uint8 language, con
|
|||||||
vsnprintf(buffer, 4096, message, argptr);
|
vsnprintf(buffer, 4096, message, argptr);
|
||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
|
|
||||||
if (client_list.count(to->GetID()))
|
to->CastToClient()->ChannelMessageSend(0, 0, chan_num, language, buffer);
|
||||||
client_list.at(to->GetID())->ChannelMessageSend(0, 0, chan_num, language, buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityList::SendZoneSpawns(Client *client)
|
void EntityList::SendZoneSpawns(Client *client)
|
||||||
@ -1232,7 +1257,9 @@ void EntityList::SendZoneSpawnsBulk(Client *client)
|
|||||||
maxspawns = mob_list.size();
|
maxspawns = mob_list.size();
|
||||||
auto bzsp = new BulkZoneSpawnPacket(client, maxspawns);
|
auto bzsp = new BulkZoneSpawnPacket(client, maxspawns);
|
||||||
|
|
||||||
int32 race=-1;
|
bool delaypkt = false;
|
||||||
|
const glm::vec4& cpos = client->GetPosition();
|
||||||
|
const float dmax = 600.0 * 600.0;
|
||||||
for (auto it = mob_list.begin(); it != mob_list.end(); ++it) {
|
for (auto it = mob_list.begin(); it != mob_list.end(); ++it) {
|
||||||
spawn = it->second;
|
spawn = it->second;
|
||||||
if (spawn && spawn->GetID() > 0 && spawn->Spawned()) {
|
if (spawn && spawn->GetID() > 0 && spawn->Spawned()) {
|
||||||
@ -1240,7 +1267,29 @@ void EntityList::SendZoneSpawnsBulk(Client *client)
|
|||||||
spawn->CastToClient()->IsHoveringForRespawn()))
|
spawn->CastToClient()->IsHoveringForRespawn()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
race = spawn->GetRace();
|
#if 1
|
||||||
|
const glm::vec4& spos = spawn->GetPosition();
|
||||||
|
|
||||||
|
delaypkt = false;
|
||||||
|
if (DistanceSquared(cpos, spos) > dmax || (spawn->IsClient() && (spawn->GetRace() == MINOR_ILL_OBJ || spawn->GetRace() == TREE)))
|
||||||
|
delaypkt = true;
|
||||||
|
|
||||||
|
if (delaypkt) {
|
||||||
|
app = new EQApplicationPacket;
|
||||||
|
spawn->CreateSpawnPacket(app);
|
||||||
|
client->QueuePacket(app, true, Client::CLIENT_CONNECTED);
|
||||||
|
safe_delete(app);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memset(&ns, 0, sizeof(NewSpawn_Struct));
|
||||||
|
spawn->FillSpawnStruct(&ns, client);
|
||||||
|
bzsp->AddSpawn(&ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
spawn->SendArmorAppearance(client);
|
||||||
|
#else
|
||||||
|
/* original code kept for spawn packet research */
|
||||||
|
int32 race = spawn->GetRace();
|
||||||
|
|
||||||
// Illusion races on PCs don't work as a mass spawn
|
// Illusion races on PCs don't work as a mass spawn
|
||||||
// But they will work as an add_spawn AFTER CLIENT_CONNECTED.
|
// But they will work as an add_spawn AFTER CLIENT_CONNECTED.
|
||||||
@ -1259,6 +1308,7 @@ void EntityList::SendZoneSpawnsBulk(Client *client)
|
|||||||
// Despite being sent in the OP_ZoneSpawns packet, the client
|
// Despite being sent in the OP_ZoneSpawns packet, the client
|
||||||
// does not display worn armor correctly so display it.
|
// does not display worn armor correctly so display it.
|
||||||
spawn->SendArmorAppearance(client);
|
spawn->SendArmorAppearance(client);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
safe_delete(bzsp);
|
safe_delete(bzsp);
|
||||||
|
|||||||
@ -148,14 +148,29 @@ public:
|
|||||||
bool IsMobSpawnedByNpcTypeID(uint32 get_id);
|
bool IsMobSpawnedByNpcTypeID(uint32 get_id);
|
||||||
Mob *GetTargetForVirus(Mob* spreader, int range);
|
Mob *GetTargetForVirus(Mob* spreader, int range);
|
||||||
inline NPC *GetNPCByID(uint16 id)
|
inline NPC *GetNPCByID(uint16 id)
|
||||||
{ return npc_list.count(id) ? npc_list.at(id) : nullptr; }
|
{
|
||||||
|
auto it = npc_list.find(id);
|
||||||
|
if (it != npc_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
NPC *GetNPCByNPCTypeID(uint32 npc_id);
|
NPC *GetNPCByNPCTypeID(uint32 npc_id);
|
||||||
inline Merc *GetMercByID(uint16 id)
|
inline Merc *GetMercByID(uint16 id)
|
||||||
{ return merc_list.count(id) ? merc_list.at(id) : nullptr; }
|
{
|
||||||
|
auto it = merc_list.find(id);
|
||||||
|
if (it != merc_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
Client *GetClientByName(const char *name);
|
Client *GetClientByName(const char *name);
|
||||||
Client *GetClientByAccID(uint32 accid);
|
Client *GetClientByAccID(uint32 accid);
|
||||||
inline Client *GetClientByID(uint16 id)
|
inline Client *GetClientByID(uint16 id)
|
||||||
{ return client_list.count(id) ? client_list.at(id) : nullptr; }
|
{
|
||||||
|
auto it = client_list.find(id);
|
||||||
|
if (it != client_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
Client *GetClientByCharID(uint32 iCharID);
|
Client *GetClientByCharID(uint32 iCharID);
|
||||||
Client *GetClientByWID(uint32 iWID);
|
Client *GetClientByWID(uint32 iWID);
|
||||||
Client *GetClient(uint32 ip, uint16 port);
|
Client *GetClient(uint32 ip, uint16 port);
|
||||||
@ -172,7 +187,12 @@ public:
|
|||||||
Corpse *GetCorpseByOwner(Client* client);
|
Corpse *GetCorpseByOwner(Client* client);
|
||||||
Corpse *GetCorpseByOwnerWithinRange(Client* client, Mob* center, int range);
|
Corpse *GetCorpseByOwnerWithinRange(Client* client, Mob* center, int range);
|
||||||
inline Corpse *GetCorpseByID(uint16 id)
|
inline Corpse *GetCorpseByID(uint16 id)
|
||||||
{ return corpse_list.count(id) ? corpse_list.at(id) : nullptr; }
|
{
|
||||||
|
auto it = corpse_list.find(id);
|
||||||
|
if (it != corpse_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
Corpse *GetCorpseByDBID(uint32 dbid);
|
Corpse *GetCorpseByDBID(uint32 dbid);
|
||||||
Corpse *GetCorpseByName(const char* name);
|
Corpse *GetCorpseByName(const char* name);
|
||||||
|
|
||||||
@ -181,10 +201,20 @@ public:
|
|||||||
Client* FindCorpseDragger(uint16 CorpseID);
|
Client* FindCorpseDragger(uint16 CorpseID);
|
||||||
|
|
||||||
inline Object *GetObjectByID(uint16 id)
|
inline Object *GetObjectByID(uint16 id)
|
||||||
{ return object_list.count(id) ? object_list.at(id) : nullptr; }
|
{
|
||||||
|
auto it = object_list.find(id);
|
||||||
|
if (it != object_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
Object *GetObjectByDBID(uint32 id);
|
Object *GetObjectByDBID(uint32 id);
|
||||||
inline Doors *GetDoorsByID(uint16 id)
|
inline Doors *GetDoorsByID(uint16 id)
|
||||||
{ return door_list.count(id) ? door_list.at(id) : nullptr; }
|
{
|
||||||
|
auto it = door_list.find(id);
|
||||||
|
if (it != door_list.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
Doors *GetDoorsByDoorID(uint32 id);
|
Doors *GetDoorsByDoorID(uint32 id);
|
||||||
Doors *GetDoorsByDBID(uint32 id);
|
Doors *GetDoorsByDBID(uint32 id);
|
||||||
void RemoveAllCorpsesByCharID(uint32 charid);
|
void RemoveAllCorpsesByCharID(uint32 charid);
|
||||||
|
|||||||
@ -759,28 +759,28 @@ bool Lua_Mob::CastSpell(int spell_id, int target_id) {
|
|||||||
|
|
||||||
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot) {
|
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot) {
|
||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
return self->CastSpell(spell_id, target_id, slot);
|
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time) {
|
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time) {
|
||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
return self->CastSpell(spell_id, target_id, slot, cast_time);
|
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost) {
|
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost) {
|
||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
return self->CastSpell(spell_id, target_id, slot, cast_time, mana_cost);
|
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time, mana_cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot) {
|
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot) {
|
||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
return self->CastSpell(spell_id, target_id, slot, cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot));
|
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer,
|
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer,
|
||||||
int timer_duration) {
|
int timer_duration) {
|
||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
return self->CastSpell(spell_id, target_id, slot, cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot),
|
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot),
|
||||||
static_cast<uint32>(timer), static_cast<uint32>(timer_duration));
|
static_cast<uint32>(timer), static_cast<uint32>(timer_duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -789,7 +789,7 @@ bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, in
|
|||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
int16 res = resist_adjust;
|
int16 res = resist_adjust;
|
||||||
|
|
||||||
return self->CastSpell(spell_id, target_id, slot, cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot),
|
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot),
|
||||||
static_cast<uint32>(timer), static_cast<uint32>(timer_duration), &res);
|
static_cast<uint32>(timer), static_cast<uint32>(timer_duration), &res);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -800,27 +800,27 @@ bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target) {
|
|||||||
|
|
||||||
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot) {
|
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot) {
|
||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
return self->SpellFinished(spell_id, target, slot);
|
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used) {
|
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used) {
|
||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
return self->SpellFinished(spell_id, target, slot, mana_used);
|
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot), mana_used);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot) {
|
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot) {
|
||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
return self->SpellFinished(spell_id, target, slot, mana_used, inventory_slot);
|
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot), mana_used, inventory_slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot, int resist_adjust) {
|
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot, int resist_adjust) {
|
||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
return self->SpellFinished(spell_id, target, slot, mana_used, inventory_slot, resist_adjust);
|
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot), mana_used, inventory_slot, resist_adjust);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot, int resist_adjust, bool proc) {
|
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot, int resist_adjust, bool proc) {
|
||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
return self->SpellFinished(spell_id, target, slot, mana_used, inventory_slot, resist_adjust, proc);
|
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot), mana_used, inventory_slot, resist_adjust, proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Lua_Mob::SpellEffect(Lua_Mob caster, int spell_id, double partial) {
|
void Lua_Mob::SpellEffect(Lua_Mob caster, int spell_id, double partial) {
|
||||||
|
|||||||
@ -163,7 +163,7 @@ float Map::FindClosestZ(glm::vec3 &start, glm::vec3 *result) const {
|
|||||||
to.z = -BEST_Z_INVALID;
|
to.z = -BEST_Z_INVALID;
|
||||||
hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance);
|
hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance);
|
||||||
if (hit) {
|
if (hit) {
|
||||||
if (abs(from.z - result->z) < abs(ClosestZ - from.z))
|
if (std::abs(from.z - result->z) < std::abs(ClosestZ - from.z))
|
||||||
return result->z;
|
return result->z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1963,7 +1963,7 @@ bool Merc::AIDoSpellCast(uint16 spellid, Mob* tar, int32 mana_cost, uint32* oDon
|
|||||||
SendPosition();
|
SendPosition();
|
||||||
SetMoving(false);
|
SetMoving(false);
|
||||||
|
|
||||||
result = CastSpell(spellid, tar->GetID(), 1, -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0);
|
result = CastSpell(spellid, tar->GetID(), EQEmu::CastingSlot::Gem2, -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0);
|
||||||
|
|
||||||
if(IsCasting() && IsSitting())
|
if(IsCasting() && IsSitting())
|
||||||
Stand();
|
Stand();
|
||||||
@ -4015,7 +4015,7 @@ bool Merc::UseDiscipline(int32 spell_id, int32 target) {
|
|||||||
if(IsCasting())
|
if(IsCasting())
|
||||||
InterruptSpell();
|
InterruptSpell();
|
||||||
|
|
||||||
CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT);
|
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline);
|
||||||
|
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|||||||
54
zone/mob.cpp
54
zone/mob.cpp
@ -2357,7 +2357,6 @@ void Mob::SetZone(uint32 zone_id, uint32 instance_id)
|
|||||||
{
|
{
|
||||||
CastToClient()->GetPP().zone_id = zone_id;
|
CastToClient()->GetPP().zone_id = zone_id;
|
||||||
CastToClient()->GetPP().zoneInstance = instance_id;
|
CastToClient()->GetPP().zoneInstance = instance_id;
|
||||||
CastToClient()->Save();
|
|
||||||
}
|
}
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
@ -3224,13 +3223,13 @@ void Mob::ExecWeaponProc(const ItemInst *inst, uint16 spell_id, Mob *on, int lev
|
|||||||
if(twinproc_chance && zone->random.Roll(twinproc_chance))
|
if(twinproc_chance && zone->random.Roll(twinproc_chance))
|
||||||
twinproc = true;
|
twinproc = true;
|
||||||
|
|
||||||
if (IsBeneficialSpell(spell_id)) {
|
if (IsBeneficialSpell(spell_id) && (!IsNPC() || (IsNPC() && CastToNPC()->GetInnateProcSpellID() != spell_id))) { // NPC innate procs don't take this path ever
|
||||||
SpellFinished(spell_id, this, 10, 0, -1, spells[spell_id].ResistDiff, true, level_override);
|
SpellFinished(spell_id, this, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff, true, level_override);
|
||||||
if(twinproc)
|
if(twinproc)
|
||||||
SpellOnTarget(spell_id, this, false, false, 0, true, level_override);
|
SpellOnTarget(spell_id, this, false, false, 0, true, level_override);
|
||||||
}
|
}
|
||||||
else if(!(on->IsClient() && on->CastToClient()->dead)) { //dont proc on dead clients
|
else if(!(on->IsClient() && on->CastToClient()->dead)) { //dont proc on dead clients
|
||||||
SpellFinished(spell_id, on, 10, 0, -1, spells[spell_id].ResistDiff, true, level_override);
|
SpellFinished(spell_id, on, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff, true, level_override);
|
||||||
if(twinproc)
|
if(twinproc)
|
||||||
SpellOnTarget(spell_id, on, false, false, 0, true, level_override);
|
SpellOnTarget(spell_id, on, false, false, 0, true, level_override);
|
||||||
}
|
}
|
||||||
@ -3518,10 +3517,9 @@ void Mob::TryTriggerOnCast(uint32 spell_id, bool aa_trigger)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Mob::TriggerOnCast(uint32 focus_spell, uint32 spell_id, bool aa_trigger)
|
void Mob::TriggerOnCast(uint32 focus_spell, uint32 spell_id, bool aa_trigger)
|
||||||
{
|
{
|
||||||
if(!IsValidSpell(focus_spell) || !IsValidSpell(spell_id))
|
if (!IsValidSpell(focus_spell) || !IsValidSpell(spell_id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32 trigger_spell_id = 0;
|
uint32 trigger_spell_id = 0;
|
||||||
@ -3532,15 +3530,17 @@ void Mob::TriggerOnCast(uint32 focus_spell, uint32 spell_id, bool aa_trigger)
|
|||||||
if (rank)
|
if (rank)
|
||||||
trigger_spell_id = CastToClient()->CalcAAFocus(focusTriggerOnCast, *rank, spell_id);
|
trigger_spell_id = CastToClient()->CalcAAFocus(focusTriggerOnCast, *rank, spell_id);
|
||||||
|
|
||||||
if(IsValidSpell(trigger_spell_id) && GetTarget())
|
if (IsValidSpell(trigger_spell_id) && GetTarget())
|
||||||
SpellFinished(trigger_spell_id, GetTarget(), 10, 0, -1, spells[trigger_spell_id].ResistDiff);
|
SpellFinished(trigger_spell_id, GetTarget(), EQEmu::CastingSlot::Item, 0, -1,
|
||||||
|
spells[trigger_spell_id].ResistDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
else{
|
else {
|
||||||
trigger_spell_id = CalcFocusEffect(focusTriggerOnCast, focus_spell, spell_id);
|
trigger_spell_id = CalcFocusEffect(focusTriggerOnCast, focus_spell, spell_id);
|
||||||
|
|
||||||
if(IsValidSpell(trigger_spell_id) && GetTarget()){
|
if (IsValidSpell(trigger_spell_id) && GetTarget()) {
|
||||||
SpellFinished(trigger_spell_id, GetTarget(),10, 0, -1, spells[trigger_spell_id].ResistDiff);
|
SpellFinished(trigger_spell_id, GetTarget(), EQEmu::CastingSlot::Item, 0, -1,
|
||||||
|
spells[trigger_spell_id].ResistDiff);
|
||||||
CheckNumHitsRemaining(NumHit::MatchingSpells, -1, focus_spell);
|
CheckNumHitsRemaining(NumHit::MatchingSpells, -1, focus_spell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3570,7 +3570,7 @@ bool Mob::TrySpellTrigger(Mob *target, uint32 spell_id, int effect)
|
|||||||
{
|
{
|
||||||
// If we trigger an effect then its over.
|
// If we trigger an effect then its over.
|
||||||
if (IsValidSpell(spells[spell_id].base2[i])){
|
if (IsValidSpell(spells[spell_id].base2[i])){
|
||||||
SpellFinished(spells[spell_id].base2[i], target, 10, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff);
|
SpellFinished(spells[spell_id].base2[i], target, EQEmu::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3589,7 +3589,7 @@ bool Mob::TrySpellTrigger(Mob *target, uint32 spell_id, int effect)
|
|||||||
if(zone->random.Int(0, 100) <= spells[spell_id].base[effect])
|
if(zone->random.Int(0, 100) <= spells[spell_id].base[effect])
|
||||||
{
|
{
|
||||||
if (IsValidSpell(spells[spell_id].base2[effect])){
|
if (IsValidSpell(spells[spell_id].base2[effect])){
|
||||||
SpellFinished(spells[spell_id].base2[effect], target, 10, 0, -1, spells[spells[spell_id].base2[effect]].ResistDiff);
|
SpellFinished(spells[spell_id].base2[effect], target, EQEmu::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[effect]].ResistDiff);
|
||||||
return true; //Only trigger once of these per spell effect.
|
return true; //Only trigger once of these per spell effect.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3666,7 +3666,7 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (use_spell){
|
if (use_spell){
|
||||||
SpellFinished(spells[spell_id].base[i], this, 10, 0, -1, spells[spell_id].ResistDiff);
|
SpellFinished(spells[spell_id].base[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
|
||||||
|
|
||||||
if(!TryFadeEffect(e))
|
if(!TryFadeEffect(e))
|
||||||
BuffFadeBySlot(e);
|
BuffFadeBySlot(e);
|
||||||
@ -3694,7 +3694,7 @@ void Mob::TryTwincast(Mob *caster, Mob *target, uint32 spell_id)
|
|||||||
if(zone->random.Roll(focus))
|
if(zone->random.Roll(focus))
|
||||||
{
|
{
|
||||||
Message(MT_Spells,"You twincast %s!",spells[spell_id].name);
|
Message(MT_Spells,"You twincast %s!",spells[spell_id].name);
|
||||||
SpellFinished(spell_id, target, 10, 0, -1, spells[spell_id].ResistDiff);
|
SpellFinished(spell_id, target, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3712,7 +3712,7 @@ void Mob::TryTwincast(Mob *caster, Mob *target, uint32 spell_id)
|
|||||||
{
|
{
|
||||||
if(zone->random.Roll(focus))
|
if(zone->random.Roll(focus))
|
||||||
{
|
{
|
||||||
SpellFinished(spell_id, target, 10, 0, -1, spells[spell_id].ResistDiff);
|
SpellFinished(spell_id, target, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3831,10 +3831,10 @@ bool Mob::TryFadeEffect(int slot)
|
|||||||
if(IsValidSpell(spell_id))
|
if(IsValidSpell(spell_id))
|
||||||
{
|
{
|
||||||
if (IsBeneficialSpell(spell_id)) {
|
if (IsBeneficialSpell(spell_id)) {
|
||||||
SpellFinished(spell_id, this, 10, 0, -1, spells[spell_id].ResistDiff);
|
SpellFinished(spell_id, this, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
|
||||||
}
|
}
|
||||||
else if(!(IsClient() && CastToClient()->dead)) {
|
else if(!(IsClient() && CastToClient()->dead)) {
|
||||||
SpellFinished(spell_id, this, 10, 0, -1, spells[spell_id].ResistDiff);
|
SpellFinished(spell_id, this, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -3868,7 +3868,7 @@ void Mob::TrySympatheticProc(Mob *target, uint32 spell_id)
|
|||||||
SpellFinished(focus_trigger, target);
|
SpellFinished(focus_trigger, target);
|
||||||
|
|
||||||
else
|
else
|
||||||
SpellFinished(focus_trigger, this, 10, 0, -1, spells[focus_trigger].ResistDiff);
|
SpellFinished(focus_trigger, this, EQEmu::CastingSlot::Item, 0, -1, spells[focus_trigger].ResistDiff);
|
||||||
}
|
}
|
||||||
// For detrimental spells, if the triggered spell is beneficial, then it will land on the caster
|
// For detrimental spells, if the triggered spell is beneficial, then it will land on the caster
|
||||||
// if the triggered spell is also detrimental, then it will land on the target
|
// if the triggered spell is also detrimental, then it will land on the target
|
||||||
@ -3878,7 +3878,7 @@ void Mob::TrySympatheticProc(Mob *target, uint32 spell_id)
|
|||||||
SpellFinished(focus_trigger, this);
|
SpellFinished(focus_trigger, this);
|
||||||
|
|
||||||
else
|
else
|
||||||
SpellFinished(focus_trigger, target, 10, 0, -1, spells[focus_trigger].ResistDiff);
|
SpellFinished(focus_trigger, target, EQEmu::CastingSlot::Item, 0, -1, spells[focus_trigger].ResistDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckNumHitsRemaining(NumHit::MatchingSpells, -1, focus_spell);
|
CheckNumHitsRemaining(NumHit::MatchingSpells, -1, focus_spell);
|
||||||
@ -4529,7 +4529,7 @@ void Mob::TrySpellOnKill(uint8 level, uint16 spell_id)
|
|||||||
if (IsValidSpell(spells[spell_id].base2[i]) && spells[spell_id].max[i] <= level)
|
if (IsValidSpell(spells[spell_id].base2[i]) && spells[spell_id].max[i] <= level)
|
||||||
{
|
{
|
||||||
if(zone->random.Roll(spells[spell_id].base[i]))
|
if(zone->random.Roll(spells[spell_id].base[i]))
|
||||||
SpellFinished(spells[spell_id].base2[i], this, 10, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff);
|
SpellFinished(spells[spell_id].base2[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4544,17 +4544,17 @@ void Mob::TrySpellOnKill(uint8 level, uint16 spell_id)
|
|||||||
|
|
||||||
if(aabonuses.SpellOnKill[i] && IsValidSpell(aabonuses.SpellOnKill[i]) && (level >= aabonuses.SpellOnKill[i + 2])) {
|
if(aabonuses.SpellOnKill[i] && IsValidSpell(aabonuses.SpellOnKill[i]) && (level >= aabonuses.SpellOnKill[i + 2])) {
|
||||||
if(zone->random.Roll(static_cast<int>(aabonuses.SpellOnKill[i + 1])))
|
if(zone->random.Roll(static_cast<int>(aabonuses.SpellOnKill[i + 1])))
|
||||||
SpellFinished(aabonuses.SpellOnKill[i], this, 10, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff);
|
SpellFinished(aabonuses.SpellOnKill[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(itembonuses.SpellOnKill[i] && IsValidSpell(itembonuses.SpellOnKill[i]) && (level >= itembonuses.SpellOnKill[i + 2])){
|
if(itembonuses.SpellOnKill[i] && IsValidSpell(itembonuses.SpellOnKill[i]) && (level >= itembonuses.SpellOnKill[i + 2])){
|
||||||
if(zone->random.Roll(static_cast<int>(itembonuses.SpellOnKill[i + 1])))
|
if(zone->random.Roll(static_cast<int>(itembonuses.SpellOnKill[i + 1])))
|
||||||
SpellFinished(itembonuses.SpellOnKill[i], this, 10, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff);
|
SpellFinished(itembonuses.SpellOnKill[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(spellbonuses.SpellOnKill[i] && IsValidSpell(spellbonuses.SpellOnKill[i]) && (level >= spellbonuses.SpellOnKill[i + 2])) {
|
if(spellbonuses.SpellOnKill[i] && IsValidSpell(spellbonuses.SpellOnKill[i]) && (level >= spellbonuses.SpellOnKill[i + 2])) {
|
||||||
if(zone->random.Roll(static_cast<int>(spellbonuses.SpellOnKill[i + 1])))
|
if(zone->random.Roll(static_cast<int>(spellbonuses.SpellOnKill[i + 1])))
|
||||||
SpellFinished(spellbonuses.SpellOnKill[i], this, 10, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff);
|
SpellFinished(spellbonuses.SpellOnKill[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -4571,19 +4571,19 @@ bool Mob::TrySpellOnDeath()
|
|||||||
for(int i = 0; i < MAX_SPELL_TRIGGER*2; i+=2) {
|
for(int i = 0; i < MAX_SPELL_TRIGGER*2; i+=2) {
|
||||||
if(IsClient() && aabonuses.SpellOnDeath[i] && IsValidSpell(aabonuses.SpellOnDeath[i])) {
|
if(IsClient() && aabonuses.SpellOnDeath[i] && IsValidSpell(aabonuses.SpellOnDeath[i])) {
|
||||||
if(zone->random.Roll(static_cast<int>(aabonuses.SpellOnDeath[i + 1]))) {
|
if(zone->random.Roll(static_cast<int>(aabonuses.SpellOnDeath[i + 1]))) {
|
||||||
SpellFinished(aabonuses.SpellOnDeath[i], this, 10, 0, -1, spells[aabonuses.SpellOnDeath[i]].ResistDiff);
|
SpellFinished(aabonuses.SpellOnDeath[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[aabonuses.SpellOnDeath[i]].ResistDiff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(itembonuses.SpellOnDeath[i] && IsValidSpell(itembonuses.SpellOnDeath[i])) {
|
if(itembonuses.SpellOnDeath[i] && IsValidSpell(itembonuses.SpellOnDeath[i])) {
|
||||||
if(zone->random.Roll(static_cast<int>(itembonuses.SpellOnDeath[i + 1]))) {
|
if(zone->random.Roll(static_cast<int>(itembonuses.SpellOnDeath[i + 1]))) {
|
||||||
SpellFinished(itembonuses.SpellOnDeath[i], this, 10, 0, -1, spells[itembonuses.SpellOnDeath[i]].ResistDiff);
|
SpellFinished(itembonuses.SpellOnDeath[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[itembonuses.SpellOnDeath[i]].ResistDiff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(spellbonuses.SpellOnDeath[i] && IsValidSpell(spellbonuses.SpellOnDeath[i])) {
|
if(spellbonuses.SpellOnDeath[i] && IsValidSpell(spellbonuses.SpellOnDeath[i])) {
|
||||||
if(zone->random.Roll(static_cast<int>(spellbonuses.SpellOnDeath[i + 1]))) {
|
if(zone->random.Roll(static_cast<int>(spellbonuses.SpellOnDeath[i + 1]))) {
|
||||||
SpellFinished(spellbonuses.SpellOnDeath[i], this, 10, 0, -1, spells[spellbonuses.SpellOnDeath[i]].ResistDiff);
|
SpellFinished(spellbonuses.SpellOnDeath[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[spellbonuses.SpellOnDeath[i]].ResistDiff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
zone/mob.h
20
zone/mob.h
@ -26,6 +26,7 @@
|
|||||||
#include "aa_ability.h"
|
#include "aa_ability.h"
|
||||||
#include "aa.h"
|
#include "aa.h"
|
||||||
#include "../common/light_source.h"
|
#include "../common/light_source.h"
|
||||||
|
#include "../common/emu_constants.h"
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -218,7 +219,7 @@ public:
|
|||||||
|
|
||||||
//Song
|
//Song
|
||||||
bool UseBardSpellLogic(uint16 spell_id = 0xffff, int slot = -1);
|
bool UseBardSpellLogic(uint16 spell_id = 0xffff, int slot = -1);
|
||||||
bool ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, uint16 slot);
|
bool ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, EQEmu::CastingSlot slot);
|
||||||
void BardPulse(uint16 spell_id, Mob *caster);
|
void BardPulse(uint16 spell_id, Mob *caster);
|
||||||
|
|
||||||
//Spell
|
//Spell
|
||||||
@ -248,29 +249,30 @@ public:
|
|||||||
void SendSpellBarEnable(uint16 spellid);
|
void SendSpellBarEnable(uint16 spellid);
|
||||||
void ZeroCastingVars();
|
void ZeroCastingVars();
|
||||||
virtual void SpellProcess();
|
virtual void SpellProcess();
|
||||||
virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1,
|
virtual bool CastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1,
|
||||||
int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF,
|
int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF,
|
||||||
uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, int16 *resist_adjust = nullptr,
|
uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, int16 *resist_adjust = nullptr,
|
||||||
uint32 aa_id = 0);
|
uint32 aa_id = 0);
|
||||||
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1,
|
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1,
|
||||||
int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF,
|
int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF,
|
||||||
uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, int16 resist_adjust = 0,
|
uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, int16 resist_adjust = 0,
|
||||||
uint32 aa_id = 0);
|
uint32 aa_id = 0);
|
||||||
void CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, uint16 mana_used,
|
void CastedSpellFinished(uint16 spell_id, uint32 target_id, EQEmu::CastingSlot slot, uint16 mana_used,
|
||||||
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0);
|
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0);
|
||||||
bool SpellFinished(uint16 spell_id, Mob *target, uint16 slot = 10, uint16 mana_used = 0,
|
bool SpellFinished(uint16 spell_id, Mob *target, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, uint16 mana_used = 0,
|
||||||
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1);
|
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1);
|
||||||
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect = false,
|
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect = false,
|
||||||
bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1);
|
bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1);
|
||||||
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1);
|
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1);
|
||||||
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center,
|
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center,
|
||||||
CastAction_type &CastAction, uint16 slot);
|
CastAction_type &CastAction, EQEmu::CastingSlot slot, bool isproc = false);
|
||||||
virtual bool CheckFizzle(uint16 spell_id);
|
virtual bool CheckFizzle(uint16 spell_id);
|
||||||
virtual bool CheckSpellLevelRestriction(uint16 spell_id);
|
virtual bool CheckSpellLevelRestriction(uint16 spell_id);
|
||||||
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
|
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
|
||||||
virtual float GetAOERange(uint16 spell_id);
|
virtual float GetAOERange(uint16 spell_id);
|
||||||
void InterruptSpell(uint16 spellid = SPELL_UNKNOWN);
|
void InterruptSpell(uint16 spellid = SPELL_UNKNOWN);
|
||||||
void InterruptSpell(uint16, uint16, uint16 spellid = SPELL_UNKNOWN);
|
void InterruptSpell(uint16, uint16, uint16 spellid = SPELL_UNKNOWN);
|
||||||
|
void StopCasting();
|
||||||
inline bool IsCasting() const { return((casting_spell_id != 0)); }
|
inline bool IsCasting() const { return((casting_spell_id != 0)); }
|
||||||
uint16 CastingSpellID() const { return casting_spell_id; }
|
uint16 CastingSpellID() const { return casting_spell_id; }
|
||||||
bool DoCastingChecks();
|
bool DoCastingChecks();
|
||||||
@ -306,6 +308,8 @@ public:
|
|||||||
virtual int GetMaxSongSlots() const { return 0; }
|
virtual int GetMaxSongSlots() const { return 0; }
|
||||||
virtual int GetMaxDiscSlots() const { return 0; }
|
virtual int GetMaxDiscSlots() const { return 0; }
|
||||||
virtual int GetMaxTotalSlots() const { return 0; }
|
virtual int GetMaxTotalSlots() const { return 0; }
|
||||||
|
virtual uint32 GetFirstBuffSlot(bool disc, bool song);
|
||||||
|
virtual uint32 GetLastBuffSlot(bool disc, bool song);
|
||||||
virtual void InitializeBuffSlots() { buffs = nullptr; current_buff_count = 0; }
|
virtual void InitializeBuffSlots() { buffs = nullptr; current_buff_count = 0; }
|
||||||
virtual void UninitializeBuffSlots() { }
|
virtual void UninitializeBuffSlots() { }
|
||||||
EQApplicationPacket *MakeBuffsPacket(bool for_target = true);
|
EQApplicationPacket *MakeBuffsPacket(bool for_target = true);
|
||||||
@ -1216,7 +1220,7 @@ protected:
|
|||||||
int attacked_count;
|
int attacked_count;
|
||||||
bool delaytimer;
|
bool delaytimer;
|
||||||
uint16 casting_spell_targetid;
|
uint16 casting_spell_targetid;
|
||||||
uint16 casting_spell_slot;
|
EQEmu::CastingSlot casting_spell_slot;
|
||||||
uint16 casting_spell_mana;
|
uint16 casting_spell_mana;
|
||||||
uint32 casting_spell_inventory_slot;
|
uint32 casting_spell_inventory_slot;
|
||||||
uint32 casting_spell_timer;
|
uint32 casting_spell_timer;
|
||||||
@ -1226,7 +1230,7 @@ protected:
|
|||||||
uint32 casting_spell_aa_id;
|
uint32 casting_spell_aa_id;
|
||||||
bool casting_spell_checks;
|
bool casting_spell_checks;
|
||||||
uint16 bardsong;
|
uint16 bardsong;
|
||||||
uint8 bardsong_slot;
|
EQEmu::CastingSlot bardsong_slot;
|
||||||
uint32 bardsong_target_id;
|
uint32 bardsong_target_id;
|
||||||
|
|
||||||
bool ActiveProjectileATK;
|
bool ActiveProjectileATK;
|
||||||
|
|||||||
@ -341,7 +341,7 @@ bool NPC::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
|
|||||||
SetCurrentSpeed(0);
|
SetCurrentSpeed(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CastSpell(AIspells[i].spellid, tar->GetID(), 1, AIspells[i].manacost == -2 ? 0 : -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, &(AIspells[i].resist_adjust));
|
return CastSpell(AIspells[i].spellid, tar->GetID(), EQEmu::CastingSlot::Gem2, AIspells[i].manacost == -2 ? 0 : -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, &(AIspells[i].resist_adjust));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityList::AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float iRange, uint16 iSpellTypes) {
|
bool EntityList::AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float iRange, uint16 iSpellTypes) {
|
||||||
@ -673,11 +673,11 @@ void Client::AI_SpellCast()
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32 spell_to_cast = 0xFFFFFFFF;
|
uint32 spell_to_cast = 0xFFFFFFFF;
|
||||||
uint32 slot_to_use = 10;
|
EQEmu::CastingSlot slot_to_use = EQEmu::CastingSlot::Item;
|
||||||
if(valid_spells.size() == 1)
|
if(valid_spells.size() == 1)
|
||||||
{
|
{
|
||||||
spell_to_cast = valid_spells[0];
|
spell_to_cast = valid_spells[0];
|
||||||
slot_to_use = slots[0];
|
slot_to_use = static_cast<EQEmu::CastingSlot>(slots[0]);
|
||||||
}
|
}
|
||||||
else if(valid_spells.empty())
|
else if(valid_spells.empty())
|
||||||
{
|
{
|
||||||
@ -687,7 +687,7 @@ void Client::AI_SpellCast()
|
|||||||
{
|
{
|
||||||
uint32 idx = zone->random.Int(0, (valid_spells.size()-1));
|
uint32 idx = zone->random.Int(0, (valid_spells.size()-1));
|
||||||
spell_to_cast = valid_spells[idx];
|
spell_to_cast = valid_spells[idx];
|
||||||
slot_to_use = slots[idx];
|
slot_to_use = static_cast<EQEmu::CastingSlot>(slots[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IsMezSpell(spell_to_cast) || IsFearSpell(spell_to_cast))
|
if(IsMezSpell(spell_to_cast) || IsFearSpell(spell_to_cast))
|
||||||
@ -2362,8 +2362,10 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) {
|
|||||||
return a.priority > b.priority;
|
return a.priority > b.priority;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (IsValidSpell(attack_proc_spell))
|
if (IsValidSpell(attack_proc_spell)) {
|
||||||
AddProcToWeapon(attack_proc_spell, true, proc_chance);
|
AddProcToWeapon(attack_proc_spell, true, proc_chance);
|
||||||
|
innate_proc_spell_id = attack_proc_spell;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsValidSpell(range_proc_spell))
|
if (IsValidSpell(range_proc_spell))
|
||||||
AddRangedProc(range_proc_spell, (rproc_chance + 100));
|
AddRangedProc(range_proc_spell, (rproc_chance + 100));
|
||||||
|
|||||||
47
zone/npc.cpp
47
zone/npc.cpp
@ -233,6 +233,7 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
|
|||||||
npc_spells_id = 0;
|
npc_spells_id = 0;
|
||||||
HasAISpell = false;
|
HasAISpell = false;
|
||||||
HasAISpellEffects = false;
|
HasAISpellEffects = false;
|
||||||
|
innate_proc_spell_id = 0;
|
||||||
|
|
||||||
if(GetClass() == MERCERNARY_MASTER && RuleB(Mercs, AllowMercs))
|
if(GetClass() == MERCERNARY_MASTER && RuleB(Mercs, AllowMercs))
|
||||||
{
|
{
|
||||||
@ -2006,6 +2007,51 @@ void NPC::LevelScale() {
|
|||||||
|
|
||||||
float scaling = (((random_level / (float)level) - 1) * (scalerate / 100.0f));
|
float scaling = (((random_level / (float)level) - 1) * (scalerate / 100.0f));
|
||||||
|
|
||||||
|
if (RuleB(NPC, NewLevelScaling)) {
|
||||||
|
if (scalerate == 0 || maxlevel <= 25) {
|
||||||
|
// pre-pop seems to scale by 20 HP increments while newer by 100
|
||||||
|
// We also don't want 100 increments on newer noobie zones, check level
|
||||||
|
if (zone->GetZoneID() < 200 || level < 48) {
|
||||||
|
max_hp += (random_level - level) * 20;
|
||||||
|
base_hp += (random_level - level) * 20;
|
||||||
|
} else {
|
||||||
|
max_hp += (random_level - level) * 100;
|
||||||
|
base_hp += (random_level - level) * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_hp = max_hp;
|
||||||
|
max_dmg += (random_level - level) * 2;
|
||||||
|
} else {
|
||||||
|
uint8 scale_adjust = 1;
|
||||||
|
|
||||||
|
base_hp += (int)(base_hp * scaling);
|
||||||
|
max_hp += (int)(max_hp * scaling);
|
||||||
|
cur_hp = max_hp;
|
||||||
|
|
||||||
|
if (max_dmg) {
|
||||||
|
max_dmg += (int)(max_dmg * scaling / scale_adjust);
|
||||||
|
min_dmg += (int)(min_dmg * scaling / scale_adjust);
|
||||||
|
}
|
||||||
|
|
||||||
|
STR += (int)(STR * scaling / scale_adjust);
|
||||||
|
STA += (int)(STA * scaling / scale_adjust);
|
||||||
|
AGI += (int)(AGI * scaling / scale_adjust);
|
||||||
|
DEX += (int)(DEX * scaling / scale_adjust);
|
||||||
|
INT += (int)(INT * scaling / scale_adjust);
|
||||||
|
WIS += (int)(WIS * scaling / scale_adjust);
|
||||||
|
CHA += (int)(CHA * scaling / scale_adjust);
|
||||||
|
if (MR)
|
||||||
|
MR += (int)(MR * scaling / scale_adjust);
|
||||||
|
if (CR)
|
||||||
|
CR += (int)(CR * scaling / scale_adjust);
|
||||||
|
if (DR)
|
||||||
|
DR += (int)(DR * scaling / scale_adjust);
|
||||||
|
if (FR)
|
||||||
|
FR += (int)(FR * scaling / scale_adjust);
|
||||||
|
if (PR)
|
||||||
|
PR += (int)(PR * scaling / scale_adjust);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// Compensate for scale rates at low levels so they don't add too much
|
// Compensate for scale rates at low levels so they don't add too much
|
||||||
uint8 scale_adjust = 1;
|
uint8 scale_adjust = 1;
|
||||||
if(level > 0 && level <= 5)
|
if(level > 0 && level <= 5)
|
||||||
@ -2044,6 +2090,7 @@ void NPC::LevelScale() {
|
|||||||
min_dmg += (int)(min_dmg * scaling / scale_adjust);
|
min_dmg += (int)(min_dmg * scaling / scale_adjust);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
level = random_level;
|
level = random_level;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -407,6 +407,7 @@ public:
|
|||||||
void mod_npc_killed_merit(Mob* c);
|
void mod_npc_killed_merit(Mob* c);
|
||||||
void mod_npc_killed(Mob* oos);
|
void mod_npc_killed(Mob* oos);
|
||||||
void AISpellsList(Client *c);
|
void AISpellsList(Client *c);
|
||||||
|
uint16 GetInnateProcSpellID() const { return innate_proc_spell_id; }
|
||||||
|
|
||||||
uint32 GetHeroForgeModel() const { return herosforgemodel; }
|
uint32 GetHeroForgeModel() const { return herosforgemodel; }
|
||||||
void SetHeroForgeModel(uint32 model) { herosforgemodel = model; }
|
void SetHeroForgeModel(uint32 model) { herosforgemodel = model; }
|
||||||
@ -454,6 +455,7 @@ protected:
|
|||||||
virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);
|
virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);
|
||||||
AISpellsVar_Struct AISpellVar;
|
AISpellsVar_Struct AISpellVar;
|
||||||
int16 GetFocusEffect(focusType type, uint16 spell_id);
|
int16 GetFocusEffect(focusType type, uint16 spell_id);
|
||||||
|
uint16 innate_proc_spell_id;
|
||||||
|
|
||||||
uint32 npc_spells_effects_id;
|
uint32 npc_spells_effects_id;
|
||||||
std::vector<AISpellsEffects_Struct> AIspellsEffects;
|
std::vector<AISpellsEffects_Struct> AIspellsEffects;
|
||||||
|
|||||||
@ -3982,12 +3982,12 @@ XS(XS_Mob_CastSpell)
|
|||||||
{
|
{
|
||||||
dXSARGS;
|
dXSARGS;
|
||||||
if (items < 3 || items > 7)
|
if (items < 3 || items > 7)
|
||||||
Perl_croak(aTHX_ "Usage: Mob::CastSpell(THIS, spell_id, target_id, slot= 10, casttime= -1, mana_cost= -1, resist_adjust = 0)");
|
Perl_croak(aTHX_ "Usage: Mob::CastSpell(THIS, spell_id, target_id, slot= 22, casttime= -1, mana_cost= -1, resist_adjust = 0)");
|
||||||
{
|
{
|
||||||
Mob * THIS;
|
Mob * THIS;
|
||||||
uint16 spell_id = (uint16)SvUV(ST(1));
|
uint16 spell_id = (uint16)SvUV(ST(1));
|
||||||
uint16 target_id = (uint16)SvUV(ST(2));
|
uint16 target_id = (uint16)SvUV(ST(2));
|
||||||
uint16 slot;
|
EQEmu::CastingSlot slot;
|
||||||
int32 casttime;
|
int32 casttime;
|
||||||
int32 mana_cost;
|
int32 mana_cost;
|
||||||
int16 resist_adjust;
|
int16 resist_adjust;
|
||||||
@ -4002,9 +4002,9 @@ XS(XS_Mob_CastSpell)
|
|||||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||||
|
|
||||||
if (items < 4)
|
if (items < 4)
|
||||||
slot = 10;
|
slot = EQEmu::CastingSlot::Item;
|
||||||
else {
|
else {
|
||||||
slot = (uint16)SvUV(ST(3));
|
slot = static_cast<EQEmu::CastingSlot>(SvUV(ST(3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (items < 5)
|
if (items < 5)
|
||||||
@ -4085,7 +4085,7 @@ XS(XS_Mob_SpellFinished)
|
|||||||
resist_diff = spells[spell_id].ResistDiff;
|
resist_diff = spells[spell_id].ResistDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
THIS->SpellFinished(spell_id, spell_target, 10, mana_cost, -1, resist_diff);
|
THIS->SpellFinished(spell_id, spell_target, EQEmu::CastingSlot::Item, mana_cost, -1, resist_diff);
|
||||||
}
|
}
|
||||||
XSRETURN_EMPTY;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -365,14 +365,14 @@ void QuestManager::castspell(int spell_id, int target_id) {
|
|||||||
if (owner) {
|
if (owner) {
|
||||||
Mob *tgt = entity_list.GetMob(target_id);
|
Mob *tgt = entity_list.GetMob(target_id);
|
||||||
if(tgt != nullptr)
|
if(tgt != nullptr)
|
||||||
owner->SpellFinished(spell_id, tgt, 10, 0, -1, spells[spell_id].ResistDiff);
|
owner->SpellFinished(spell_id, tgt, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuestManager::selfcast(int spell_id) {
|
void QuestManager::selfcast(int spell_id) {
|
||||||
QuestManagerCurrentQuestVars();
|
QuestManagerCurrentQuestVars();
|
||||||
if (initiator)
|
if (initiator)
|
||||||
initiator->SpellFinished(spell_id, initiator, 10, 0, -1, spells[spell_id].ResistDiff);
|
initiator->SpellFinished(spell_id, initiator, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuestManager::addloot(int item_id, int charges, bool equipitem) {
|
void QuestManager::addloot(int item_id, int charges, bool equipitem) {
|
||||||
|
|||||||
@ -149,7 +149,7 @@ void Mob::DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int32
|
|||||||
IsValidSpell(aabonuses.SkillAttackProc[2])) {
|
IsValidSpell(aabonuses.SkillAttackProc[2])) {
|
||||||
float chance = aabonuses.SkillAttackProc[0] / 1000.0f;
|
float chance = aabonuses.SkillAttackProc[0] / 1000.0f;
|
||||||
if (zone->random.Roll(chance))
|
if (zone->random.Roll(chance))
|
||||||
SpellFinished(aabonuses.SkillAttackProc[2], who, 10, 0, -1,
|
SpellFinished(aabonuses.SkillAttackProc[2], who, EQEmu::CastingSlot::Item, 0, -1,
|
||||||
spells[aabonuses.SkillAttackProc[2]].ResistDiff);
|
spells[aabonuses.SkillAttackProc[2]].ResistDiff);
|
||||||
}
|
}
|
||||||
who->Damage(this, max_damage, SPELL_UNKNOWN, skill, false);
|
who->Damage(this, max_damage, SPELL_UNKNOWN, skill, false);
|
||||||
@ -786,7 +786,7 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
|
|||||||
//EndlessQuiver AA base1 = 100% Chance to avoid consumption arrow.
|
//EndlessQuiver AA base1 = 100% Chance to avoid consumption arrow.
|
||||||
int ChanceAvoidConsume = aabonuses.ConsumeProjectile + itembonuses.ConsumeProjectile + spellbonuses.ConsumeProjectile;
|
int ChanceAvoidConsume = aabonuses.ConsumeProjectile + itembonuses.ConsumeProjectile + spellbonuses.ConsumeProjectile;
|
||||||
|
|
||||||
if (!ChanceAvoidConsume || (ChanceAvoidConsume < 100 && zone->random.Int(0,99) > ChanceAvoidConsume)){
|
if (RangeItem->ExpendableArrow || !ChanceAvoidConsume || (ChanceAvoidConsume < 100 && zone->random.Int(0,99) > ChanceAvoidConsume)){
|
||||||
DeleteItemInInventory(ammo_slot, 1, true);
|
DeleteItemInInventory(ammo_slot, 1, true);
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Consumed one arrow from slot %d", ammo_slot);
|
Log.Out(Logs::Detail, Logs::Combat, "Consumed one arrow from slot %d", ammo_slot);
|
||||||
} else {
|
} else {
|
||||||
@ -2429,7 +2429,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, EQEmu::skills:
|
|||||||
IsValidSpell(aabonuses.SkillAttackProc[2])) {
|
IsValidSpell(aabonuses.SkillAttackProc[2])) {
|
||||||
float chance = aabonuses.SkillAttackProc[0] / 1000.0f;
|
float chance = aabonuses.SkillAttackProc[0] / 1000.0f;
|
||||||
if (zone->random.Roll(chance))
|
if (zone->random.Roll(chance))
|
||||||
SpellFinished(aabonuses.SkillAttackProc[2], other, 10, 0, -1,
|
SpellFinished(aabonuses.SkillAttackProc[2], other, EQEmu::CastingSlot::Item, 0, -1,
|
||||||
spells[aabonuses.SkillAttackProc[2]].ResistDiff);
|
spells[aabonuses.SkillAttackProc[2]].ResistDiff);
|
||||||
}
|
}
|
||||||
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse);
|
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse);
|
||||||
|
|||||||
@ -194,6 +194,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
|
|
||||||
bool SE_SpellTrigger_HasCast = false;
|
bool SE_SpellTrigger_HasCast = false;
|
||||||
|
|
||||||
|
// if buff slot, use instrument mod there, otherwise calc it
|
||||||
|
uint32 instrument_mod = buffslot > -1 ? buffs[buffslot].instrument_mod : caster ? caster->GetInstrumentMod(spell_id) : 10;
|
||||||
// iterate through the effects in the spell
|
// iterate through the effects in the spell
|
||||||
for (i = 0; i < EFFECT_COUNT; i++)
|
for (i = 0; i < EFFECT_COUNT; i++)
|
||||||
{
|
{
|
||||||
@ -201,7 +203,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
effect = spell.effectid[i];
|
effect = spell.effectid[i];
|
||||||
effect_value = CalcSpellEffectValue(spell_id, i, caster_level, buffslot > -1 ? buffs[buffslot].instrument_mod : 10, caster ? caster : this);
|
effect_value = CalcSpellEffectValue(spell_id, i, caster_level, instrument_mod, caster ? caster : this);
|
||||||
|
|
||||||
if(spell_id == SPELL_LAY_ON_HANDS && caster && caster->GetAA(aaImprovedLayOnHands))
|
if(spell_id == SPELL_LAY_ON_HANDS && caster && caster->GetAA(aaImprovedLayOnHands))
|
||||||
effect_value = GetMaxHP();
|
effect_value = GetMaxHP();
|
||||||
@ -355,7 +357,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
int32 val = 0;
|
int32 val = 0;
|
||||||
val = 7500*effect_value;
|
val = 7500 * effect_value;
|
||||||
|
if (caster)
|
||||||
val = caster->GetActSpellHealing(spell_id, val, this);
|
val = caster->GetActSpellHealing(spell_id, val, this);
|
||||||
|
|
||||||
if (val > 0)
|
if (val > 0)
|
||||||
@ -375,11 +378,13 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
snprintf(effect_desc, _EDLEN, "Current Mana: %+i", effect_value);
|
snprintf(effect_desc, _EDLEN, "Current Mana: %+i", effect_value);
|
||||||
#endif
|
#endif
|
||||||
SetMana(GetMana() + effect_value);
|
SetMana(GetMana() + effect_value);
|
||||||
|
if (caster)
|
||||||
caster->SetMana(caster->GetMana() + std::abs(effect_value));
|
caster->SetMana(caster->GetMana() + std::abs(effect_value));
|
||||||
|
|
||||||
if (effect_value < 0)
|
if (effect_value < 0)
|
||||||
TryTriggerOnValueAmount(false, true);
|
TryTriggerOnValueAmount(false, true);
|
||||||
#ifdef SPELL_EFFECT_SPAM
|
#ifdef SPELL_EFFECT_SPAM
|
||||||
|
if (caster)
|
||||||
caster->Message(0, "You have gained %+i mana!", effect_value);
|
caster->Message(0, "You have gained %+i mana!", effect_value);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -532,7 +537,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effect == SE_GateCastersBindpoint && caster->IsClient())
|
if (effect == SE_GateCastersBindpoint && caster && caster->IsClient())
|
||||||
{ // Teleport Bind uses caster's bind point
|
{ // Teleport Bind uses caster's bind point
|
||||||
int index = spells[spell_id].base[i] - 1;
|
int index = spells[spell_id].base[i] - 1;
|
||||||
if (index < 0 || index > 4)
|
if (index < 0 || index > 4)
|
||||||
@ -648,7 +653,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
//Added client messages to give some indication this effect is active.
|
//Added client messages to give some indication this effect is active.
|
||||||
// Is there a message generated? Too disgusted by raids.
|
// Is there a message generated? Too disgusted by raids.
|
||||||
uint32 time = spell.base[i] * 10 * 1000;
|
uint32 time = spell.base[i] * 10 * 1000;
|
||||||
if (caster->IsClient()) {
|
if (caster && caster->IsClient()) {
|
||||||
if (caster->IsGrouped()) {
|
if (caster->IsGrouped()) {
|
||||||
auto group = caster->GetGroup();
|
auto group = caster->GetGroup();
|
||||||
for (int i = 0; i < 6; ++i)
|
for (int i = 0; i < 6; ++i)
|
||||||
@ -695,6 +700,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
((GetLevel() > max_level) && caster && (!caster->IsNPC() ||
|
((GetLevel() > max_level) && caster && (!caster->IsNPC() ||
|
||||||
(caster->IsNPC() && !RuleB(Spells, NPCIgnoreBaseImmunity))))))
|
(caster->IsNPC() && !RuleB(Spells, NPCIgnoreBaseImmunity))))))
|
||||||
{
|
{
|
||||||
|
if (caster)
|
||||||
caster->Message_StringID(MT_SpellFailure, IMMUNE_STUN);
|
caster->Message_StringID(MT_SpellFailure, IMMUNE_STUN);
|
||||||
} else {
|
} else {
|
||||||
int stun_resist = itembonuses.StunResist+spellbonuses.StunResist;
|
int stun_resist = itembonuses.StunResist+spellbonuses.StunResist;
|
||||||
@ -704,7 +710,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
if (stun_resist <= 0 || zone->random.Int(0,99) >= stun_resist) {
|
if (stun_resist <= 0 || zone->random.Int(0,99) >= stun_resist) {
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Stunned. We had %d percent resist chance.", stun_resist);
|
Log.Out(Logs::Detail, Logs::Combat, "Stunned. We had %d percent resist chance.", stun_resist);
|
||||||
|
|
||||||
if (caster->IsClient())
|
if (caster && caster->IsClient())
|
||||||
effect_value += effect_value*caster->GetFocusEffect(focusFcStunTimeMod, spell_id)/100;
|
effect_value += effect_value*caster->GetFocusEffect(focusFcStunTimeMod, spell_id)/100;
|
||||||
|
|
||||||
Stun(effect_value);
|
Stun(effect_value);
|
||||||
@ -916,11 +922,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
cd->meleepush_xy = action->sequence;
|
cd->meleepush_xy = action->sequence;
|
||||||
|
|
||||||
CastToClient()->QueuePacket(action_packet);
|
CastToClient()->QueuePacket(action_packet);
|
||||||
if(caster->IsClient() && caster != this)
|
if(caster && caster->IsClient() && caster != this)
|
||||||
caster->CastToClient()->QueuePacket(action_packet);
|
caster->CastToClient()->QueuePacket(action_packet);
|
||||||
|
|
||||||
CastToClient()->QueuePacket(message_packet);
|
CastToClient()->QueuePacket(message_packet);
|
||||||
if(caster->IsClient() && caster != this)
|
if(caster && caster->IsClient() && caster != this)
|
||||||
caster->CastToClient()->QueuePacket(message_packet);
|
caster->CastToClient()->QueuePacket(message_packet);
|
||||||
|
|
||||||
CastToClient()->SetBindPoint(spells[spell_id].base[i] - 1);
|
CastToClient()->SetBindPoint(spells[spell_id].base[i] - 1);
|
||||||
@ -1031,7 +1037,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
|
|
||||||
if(zone->random.Roll(effect_value))
|
if(zone->random.Roll(effect_value))
|
||||||
Gate(spells[spell_id].base2[i] - 1);
|
Gate(spells[spell_id].base2[i] - 1);
|
||||||
else
|
else if (caster)
|
||||||
caster->Message_StringID(MT_SpellFailure,GATE_FAIL);
|
caster->Message_StringID(MT_SpellFailure,GATE_FAIL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1043,6 +1049,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
snprintf(effect_desc, _EDLEN, "Cancel Magic: %d", effect_value);
|
snprintf(effect_desc, _EDLEN, "Cancel Magic: %d", effect_value);
|
||||||
#endif
|
#endif
|
||||||
if(GetSpecialAbility(UNDISPELLABLE)){
|
if(GetSpecialAbility(UNDISPELLABLE)){
|
||||||
|
if (caster)
|
||||||
caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name);
|
caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1053,7 +1060,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
spells[buffs[slot].spellid].dispel_flag == 0 &&
|
spells[buffs[slot].spellid].dispel_flag == 0 &&
|
||||||
!IsDiscipline(buffs[slot].spellid))
|
!IsDiscipline(buffs[slot].spellid))
|
||||||
{
|
{
|
||||||
if (TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){
|
if (caster && TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){
|
||||||
BuffFadeBySlot(slot);
|
BuffFadeBySlot(slot);
|
||||||
slot = buff_count;
|
slot = buff_count;
|
||||||
}
|
}
|
||||||
@ -1068,6 +1075,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
snprintf(effect_desc, _EDLEN, "Dispel Detrimental: %d", effect_value);
|
snprintf(effect_desc, _EDLEN, "Dispel Detrimental: %d", effect_value);
|
||||||
#endif
|
#endif
|
||||||
if(GetSpecialAbility(UNDISPELLABLE)){
|
if(GetSpecialAbility(UNDISPELLABLE)){
|
||||||
|
if (caster)
|
||||||
caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name);
|
caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1078,7 +1086,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
IsDetrimentalSpell(buffs[slot].spellid) &&
|
IsDetrimentalSpell(buffs[slot].spellid) &&
|
||||||
spells[buffs[slot].spellid].dispel_flag == 0)
|
spells[buffs[slot].spellid].dispel_flag == 0)
|
||||||
{
|
{
|
||||||
if (TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){
|
if (caster && TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){
|
||||||
BuffFadeBySlot(slot);
|
BuffFadeBySlot(slot);
|
||||||
slot = buff_count;
|
slot = buff_count;
|
||||||
}
|
}
|
||||||
@ -1093,6 +1101,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
snprintf(effect_desc, _EDLEN, "Dispel Beneficial: %d", effect_value);
|
snprintf(effect_desc, _EDLEN, "Dispel Beneficial: %d", effect_value);
|
||||||
#endif
|
#endif
|
||||||
if(GetSpecialAbility(UNDISPELLABLE)){
|
if(GetSpecialAbility(UNDISPELLABLE)){
|
||||||
|
if (caster)
|
||||||
caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name);
|
caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1103,7 +1112,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
IsBeneficialSpell(buffs[slot].spellid) &&
|
IsBeneficialSpell(buffs[slot].spellid) &&
|
||||||
spells[buffs[slot].spellid].dispel_flag == 0)
|
spells[buffs[slot].spellid].dispel_flag == 0)
|
||||||
{
|
{
|
||||||
if (TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){
|
if (caster && TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){
|
||||||
BuffFadeBySlot(slot);
|
BuffFadeBySlot(slot);
|
||||||
slot = buff_count;
|
slot = buff_count;
|
||||||
}
|
}
|
||||||
@ -1120,7 +1129,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
if (buffs[slot].spellid != SPELL_UNKNOWN &&
|
if (buffs[slot].spellid != SPELL_UNKNOWN &&
|
||||||
IsDetrimentalSpell(buffs[slot].spellid))
|
IsDetrimentalSpell(buffs[slot].spellid))
|
||||||
{
|
{
|
||||||
if (TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){
|
if (caster && TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){
|
||||||
BuffFadeBySlot(slot);
|
BuffFadeBySlot(slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1509,6 +1518,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
((GetLevel() > max_level)
|
((GetLevel() > max_level)
|
||||||
&& caster && (!caster->IsNPC() || (caster->IsNPC() && !RuleB(Spells, NPCIgnoreBaseImmunity)))))
|
&& caster && (!caster->IsNPC() || (caster->IsNPC() && !RuleB(Spells, NPCIgnoreBaseImmunity)))))
|
||||||
{
|
{
|
||||||
|
if (caster)
|
||||||
caster->Message_StringID(MT_Shout, IMMUNE_STUN);
|
caster->Message_StringID(MT_Shout, IMMUNE_STUN);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1726,7 +1736,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else if (caster) {
|
||||||
Raid *r = entity_list.GetRaidByClient(caster->CastToClient());
|
Raid *r = entity_list.GetRaidByClient(caster->CastToClient());
|
||||||
if(r)
|
if(r)
|
||||||
{
|
{
|
||||||
@ -1766,7 +1776,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
Message_StringID(4, CORPSE_CANT_SENSE);
|
Message_StringID(4, CORPSE_CANT_SENSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (caster)
|
||||||
caster->Message_StringID(MT_SpellFailure, SPELL_LEVEL_REQ);
|
caster->Message_StringID(MT_SpellFailure, SPELL_LEVEL_REQ);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -2113,7 +2123,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
#ifdef SPELL_EFFECT_SPAM
|
#ifdef SPELL_EFFECT_SPAM
|
||||||
snprintf(effect_desc, _EDLEN, "Sacrifice");
|
snprintf(effect_desc, _EDLEN, "Sacrifice");
|
||||||
#endif
|
#endif
|
||||||
if(!IsClient() || !caster->IsClient()){
|
if(!caster || !IsClient() || !caster->IsClient()){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
CastToClient()->SacrificeConfirm(caster->CastToClient());
|
CastToClient()->SacrificeConfirm(caster->CastToClient());
|
||||||
@ -2122,12 +2132,15 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
|
|
||||||
case SE_SummonPC:
|
case SE_SummonPC:
|
||||||
{
|
{
|
||||||
if(IsClient()){
|
if (!caster)
|
||||||
CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), caster->GetX(), caster->GetY(), caster->GetZ(), caster->GetHeading(), 2, SummonPC);
|
break;
|
||||||
|
if (IsClient()) {
|
||||||
|
CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), caster->GetX(),
|
||||||
|
caster->GetY(), caster->GetZ(), caster->GetHeading(), 2,
|
||||||
|
SummonPC);
|
||||||
Message(15, "You have been summoned!");
|
Message(15, "You have been summoned!");
|
||||||
entity_list.ClearAggro(this);
|
entity_list.ClearAggro(this);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
caster->Message(13, "This spell can only be cast on players.");
|
caster->Message(13, "This spell can only be cast on players.");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -2174,6 +2187,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
|
|
||||||
case SE_TemporaryPets: //Dook- swarms and wards:
|
case SE_TemporaryPets: //Dook- swarms and wards:
|
||||||
{
|
{
|
||||||
|
if (!caster)
|
||||||
|
break;
|
||||||
// this makes necro epic 1.5/2.0 proc work properly
|
// this makes necro epic 1.5/2.0 proc work properly
|
||||||
if((spell_id != 6882) && (spell_id != 6884)) // Chaotic Jester/Steadfast Servant
|
if((spell_id != 6882) && (spell_id != 6884)) // Chaotic Jester/Steadfast Servant
|
||||||
{
|
{
|
||||||
@ -2269,6 +2284,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
*/
|
*/
|
||||||
int16 focus = 0;
|
int16 focus = 0;
|
||||||
int ReuseTime = spells[spell_id].recast_time + spells[spell_id].recovery_time;
|
int ReuseTime = spells[spell_id].recast_time + spells[spell_id].recovery_time;
|
||||||
|
if (!caster)
|
||||||
|
break;
|
||||||
|
|
||||||
focus = caster->GetFocusEffect(focusFcBaseEffects, spell_id);
|
focus = caster->GetFocusEffect(focusFcBaseEffects, spell_id);
|
||||||
|
|
||||||
@ -2292,7 +2309,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
snprintf(effect_desc, _EDLEN, "Wake The Dead");
|
snprintf(effect_desc, _EDLEN, "Wake The Dead");
|
||||||
#endif
|
#endif
|
||||||
//meh dupe issue with npc casting this
|
//meh dupe issue with npc casting this
|
||||||
if(caster->IsClient()){
|
if(caster && caster->IsClient()){
|
||||||
int dur = spells[spell_id].max[i];
|
int dur = spells[spell_id].max[i];
|
||||||
if (!dur)
|
if (!dur)
|
||||||
dur = 60;
|
dur = 60;
|
||||||
@ -2657,7 +2674,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
|
|
||||||
case SE_Taunt:
|
case SE_Taunt:
|
||||||
{
|
{
|
||||||
if (IsNPC()){
|
if (caster && IsNPC()){
|
||||||
caster->Taunt(this->CastToNPC(), false, static_cast<float>(spell.base[i]), true, spell.base2[i]);
|
caster->Taunt(this->CastToNPC(), false, static_cast<float>(spell.base[i]), true, spell.base2[i]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2745,7 +2762,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
|
|
||||||
if (caster && IsValidSpell(spells[spell_id].base2[i])){
|
if (caster && IsValidSpell(spells[spell_id].base2[i])){
|
||||||
if(zone->random.Roll(spells[spell_id].base[i]))
|
if(zone->random.Roll(spells[spell_id].base[i]))
|
||||||
caster->SpellFinished(spells[spell_id].base2[i], this, 10, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff);
|
caster->SpellFinished(spells[spell_id].base2[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3668,10 +3685,11 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// These effects always trigger when they fade.
|
// These effects always trigger when they fade.
|
||||||
|
// Should we have this triggered from else where?
|
||||||
case SE_CastOnFadeEffect:
|
case SE_CastOnFadeEffect:
|
||||||
case SE_CastOnFadeEffectNPC:
|
case SE_CastOnFadeEffectNPC:
|
||||||
case SE_CastOnFadeEffectAlways: {
|
case SE_CastOnFadeEffectAlways: {
|
||||||
if (buff.ticsremaining == 1) {
|
if (buff.ticsremaining == 0) {
|
||||||
SpellOnTarget(spells[buff.spellid].base[i], this);
|
SpellOnTarget(spells[buff.spellid].base[i], this);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -5135,7 +5153,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
|||||||
|
|
||||||
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))
|
||||||
SpellFinished(Caston_spell_id, this, 10, 0, -1, spells[Caston_spell_id].ResistDiff);
|
SpellFinished(Caston_spell_id, this, EQEmu::CastingSlot::Item, 0, -1, spells[Caston_spell_id].ResistDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (value * lvlModifier / 100);
|
return (value * lvlModifier / 100);
|
||||||
@ -6226,7 +6244,7 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama
|
|||||||
{
|
{
|
||||||
/*If return TRUE spell met all restrictions and can continue (this = target).
|
/*If return TRUE spell met all restrictions and can continue (this = target).
|
||||||
This check is used when the spell_new field CastRestriction is defined OR spell effect '0'(DD/Heal) has a defined limit
|
This check is used when the spell_new field CastRestriction is defined OR spell effect '0'(DD/Heal) has a defined limit
|
||||||
Range 1 : UNKNOWN
|
Range 1 : UNKNOWN -- the spells with this seem to not have a restiction, true for now
|
||||||
Range 100 : *Animal OR Humanoid
|
Range 100 : *Animal OR Humanoid
|
||||||
Range 101 : *Dragon
|
Range 101 : *Dragon
|
||||||
Range 102 : *Animal OR Insect
|
Range 102 : *Animal OR Insect
|
||||||
@ -6253,7 +6271,10 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama
|
|||||||
Range 124 : *Undead HP < 10%
|
Range 124 : *Undead HP < 10%
|
||||||
Range 125 : *Clockwork HP < 10%
|
Range 125 : *Clockwork HP < 10%
|
||||||
Range 126 : *Wisp HP < 10%
|
Range 126 : *Wisp HP < 10%
|
||||||
Range 127-130 : UNKNOWN
|
Range 127 : UNKNOWN
|
||||||
|
Range 128 : pure melee -- guess
|
||||||
|
Range 129 : pure caster -- guess
|
||||||
|
Range 130 : hybrid -- guess
|
||||||
Range 150 : UNKNOWN
|
Range 150 : UNKNOWN
|
||||||
Range 190 : No Raid boss flag *not implemented
|
Range 190 : No Raid boss flag *not implemented
|
||||||
Range 191 : This spell will deal less damage to 'exceptionally strong targets' - Raid boss flag *not implemented
|
Range 191 : This spell will deal less damage to 'exceptionally strong targets' - Raid boss flag *not implemented
|
||||||
@ -6265,12 +6286,17 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama
|
|||||||
Range 300 - 303 : UNKOWN *not implemented
|
Range 300 - 303 : UNKOWN *not implemented
|
||||||
Range 304 : Chain + Plate class (buffs)
|
Range 304 : Chain + Plate class (buffs)
|
||||||
Range 399 - 409 : Heal if HP within a specified range (400 = 0-25% 401 = 25 - 35% 402 = 35-45% ect)
|
Range 399 - 409 : Heal if HP within a specified range (400 = 0-25% 401 = 25 - 35% 402 = 35-45% ect)
|
||||||
Range 410 - 411 : UNKOWN
|
Range 410 - 411 : UNKOWN -- examples are auras that cast on NPCs maybe in combat/out of combat?
|
||||||
Range 500 - 599 : Heal if HP less than a specified value
|
Range 500 - 599 : Heal if HP less than a specified value
|
||||||
Range 600 - 699 : Limit to Body Type [base2 - 600 = Body]
|
Range 600 - 699 : Limit to Body Type [base2 - 600 = Body]
|
||||||
Range 700 : NPC only -- from patch notes "Wizard - Arcane Fusion no longer deals damage to non-NPC targets. This should ensure that wizards who fail their Bucolic Gambit are slightly less likely to annihilate themselves."
|
Range 700 : NPC only -- from patch notes "Wizard - Arcane Fusion no longer deals damage to non-NPC targets. This should ensure that wizards who fail their Bucolic Gambit are slightly less likely to annihilate themselves."
|
||||||
Range 701 : NOT PET
|
Range 701 : NOT PET
|
||||||
Range 800 : UKNOWN
|
Range 800 : UKNOWN -- Target's Target Test (16598)
|
||||||
|
Range 812 : UNKNOWN -- triggered by Thaumatize Owner
|
||||||
|
Range 814 : UNKNOWN -- Vegetentacles
|
||||||
|
Range 815 : UNKNOWN -- Pumpkin Pulp Splash
|
||||||
|
Range 816 : UNKNOWN -- Rotten Fruit Splash
|
||||||
|
Range 817 : UNKNOWN -- Tainted Bixie Pollen Splash
|
||||||
Range 818 - 819 : If Undead/If Not Undead
|
Range 818 - 819 : If Undead/If Not Undead
|
||||||
Range 820 - 822 : UKNOWN
|
Range 820 - 822 : UKNOWN
|
||||||
Range 835 : Unknown *not implemented
|
Range 835 : Unknown *not implemented
|
||||||
@ -6290,6 +6316,9 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama
|
|||||||
|
|
||||||
switch(value)
|
switch(value)
|
||||||
{
|
{
|
||||||
|
case 1:
|
||||||
|
return true;
|
||||||
|
|
||||||
case 100:
|
case 100:
|
||||||
if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Humanoid))
|
if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Humanoid))
|
||||||
return true;
|
return true;
|
||||||
@ -6683,10 +6712,10 @@ void Mob::TryTriggerThreshHold(int32 damage, int effect_id, Mob* attacker){
|
|||||||
if (IsValidSpell(spell_id)) {
|
if (IsValidSpell(spell_id)) {
|
||||||
|
|
||||||
if (IsBeneficialSpell(spell_id))
|
if (IsBeneficialSpell(spell_id))
|
||||||
SpellFinished(spell_id, this, 10, 0, -1, spells[spell_id].ResistDiff);
|
SpellFinished(spell_id, this, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
|
||||||
|
|
||||||
else if(attacker)
|
else if(attacker)
|
||||||
SpellFinished(spell_id, attacker, 10, 0, -1, spells[spell_id].ResistDiff);
|
SpellFinished(spell_id, attacker, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
244
zone/spells.cpp
244
zone/spells.cpp
@ -104,6 +104,8 @@ extern Zone* zone;
|
|||||||
extern volatile bool is_zone_loaded;
|
extern volatile bool is_zone_loaded;
|
||||||
extern WorldServer worldserver;
|
extern WorldServer worldserver;
|
||||||
|
|
||||||
|
using EQEmu::CastingSlot;
|
||||||
|
|
||||||
// this is run constantly for every mob
|
// this is run constantly for every mob
|
||||||
void Mob::SpellProcess()
|
void Mob::SpellProcess()
|
||||||
{
|
{
|
||||||
@ -145,13 +147,13 @@ void NPC::SpellProcess()
|
|||||||
// the rule is you can cast one triggered (usually timed) spell at a time
|
// the rule is you can cast one triggered (usually timed) spell at a time
|
||||||
// but things like SpellFinished() can run concurrent with a triggered cast
|
// but things like SpellFinished() can run concurrent with a triggered cast
|
||||||
// to allow procs to work
|
// to allow procs to work
|
||||||
bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||||
int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot,
|
int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot,
|
||||||
uint32 timer, uint32 timer_duration, int16 *resist_adjust,
|
uint32 timer, uint32 timer_duration, int16 *resist_adjust,
|
||||||
uint32 aa_id)
|
uint32 aa_id)
|
||||||
{
|
{
|
||||||
Log.Out(Logs::Detail, Logs::Spells, "CastSpell called for spell %s (%d) on entity %d, slot %d, time %d, mana %d, from item slot %d",
|
Log.Out(Logs::Detail, Logs::Spells, "CastSpell called for spell %s (%d) on entity %d, slot %d, time %d, mana %d, from item slot %d",
|
||||||
(IsValidSpell(spell_id))?spells[spell_id].name:"UNKNOWN SPELL", spell_id, target_id, slot, cast_time, mana_cost, (item_slot==0xFFFFFFFF)?999:item_slot);
|
(IsValidSpell(spell_id))?spells[spell_id].name:"UNKNOWN SPELL", spell_id, target_id, static_cast<int>(slot), cast_time, mana_cost, (item_slot==0xFFFFFFFF)?999:item_slot);
|
||||||
|
|
||||||
if(casting_spell_id == spell_id)
|
if(casting_spell_id == spell_id)
|
||||||
ZeroCastingVars();
|
ZeroCastingVars();
|
||||||
@ -178,7 +180,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
|||||||
if(IsClient())
|
if(IsClient())
|
||||||
CastToClient()->SendSpellBarEnable(spell_id);
|
CastToClient()->SendSpellBarEnable(spell_id);
|
||||||
if(casting_spell_id && IsNPC())
|
if(casting_spell_id && IsNPC())
|
||||||
CastToNPC()->AI_Event_SpellCastFinished(false, casting_spell_slot);
|
CastToNPC()->AI_Event_SpellCastFinished(false, static_cast<uint16>(casting_spell_slot));
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
//It appears that the Sanctuary effect is removed by a check on the client side (keep this however for redundancy)
|
//It appears that the Sanctuary effect is removed by a check on the client side (keep this however for redundancy)
|
||||||
@ -201,7 +203,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
|||||||
if(IsClient())
|
if(IsClient())
|
||||||
CastToClient()->SendSpellBarEnable(spell_id);
|
CastToClient()->SendSpellBarEnable(spell_id);
|
||||||
if(casting_spell_id && IsNPC())
|
if(casting_spell_id && IsNPC())
|
||||||
CastToNPC()->AI_Event_SpellCastFinished(false, casting_spell_slot);
|
CastToNPC()->AI_Event_SpellCastFinished(false, static_cast<uint16>(casting_spell_slot));
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +233,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
|||||||
// check for fizzle
|
// check for fizzle
|
||||||
// note that CheckFizzle itself doesn't let NPCs fizzle,
|
// note that CheckFizzle itself doesn't let NPCs fizzle,
|
||||||
// but this code allows for it.
|
// but this code allows for it.
|
||||||
if(slot < MAX_PP_MEMSPELL && !CheckFizzle(spell_id))
|
if(slot < CastingSlot::MaxGems && !CheckFizzle(spell_id))
|
||||||
{
|
{
|
||||||
int fizzle_msg = IsBardSong(spell_id) ? MISS_NOTE : SPELL_FIZZLE;
|
int fizzle_msg = IsBardSong(spell_id) ? MISS_NOTE : SPELL_FIZZLE;
|
||||||
InterruptSpell(fizzle_msg, 0x121, spell_id);
|
InterruptSpell(fizzle_msg, 0x121, spell_id);
|
||||||
@ -252,7 +254,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Added to prevent MQ2 exploitation of equipping normally-unequippable/clickable items with effects and clicking them for benefits.
|
//Added to prevent MQ2 exploitation of equipping normally-unequippable/clickable items with effects and clicking them for benefits.
|
||||||
if(item_slot && IsClient() && ((slot == USE_ITEM_SPELL_SLOT) || (slot == POTION_BELT_SPELL_SLOT) || (slot == TARGET_RING_SPELL_SLOT)))
|
if(item_slot && IsClient() && (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt))
|
||||||
{
|
{
|
||||||
ItemInst *itm = CastToClient()->GetInv().GetItem(item_slot);
|
ItemInst *itm = CastToClient()->GetInv().GetItem(item_slot);
|
||||||
int bitmask = 1;
|
int bitmask = 1;
|
||||||
@ -336,14 +338,13 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
|||||||
// this is the 2nd phase of CastSpell, broken up like this to make it easier
|
// this is the 2nd phase of CastSpell, broken up like this to make it easier
|
||||||
// to repeat a spell for bard songs
|
// to repeat a spell for bard songs
|
||||||
//
|
//
|
||||||
bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||||
int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish,
|
int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish,
|
||||||
uint32 item_slot, uint32 timer, uint32 timer_duration,
|
uint32 item_slot, uint32 timer, uint32 timer_duration,
|
||||||
int16 resist_adjust, uint32 aa_id)
|
int16 resist_adjust, uint32 aa_id)
|
||||||
{
|
{
|
||||||
Mob* pMob = nullptr;
|
Mob* pMob = nullptr;
|
||||||
int32 orgcasttime;
|
int32 orgcasttime;
|
||||||
EQApplicationPacket *outapp = nullptr;
|
|
||||||
|
|
||||||
if(!IsValidSpell(spell_id)) {
|
if(!IsValidSpell(spell_id)) {
|
||||||
InterruptSpell();
|
InterruptSpell();
|
||||||
@ -353,7 +354,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
|||||||
const SPDat_Spell_Struct &spell = spells[spell_id];
|
const SPDat_Spell_Struct &spell = spells[spell_id];
|
||||||
|
|
||||||
Log.Out(Logs::Detail, Logs::Spells, "DoCastSpell called for spell %s (%d) on entity %d, slot %d, time %d, mana %d, from item %d",
|
Log.Out(Logs::Detail, Logs::Spells, "DoCastSpell called for spell %s (%d) on entity %d, slot %d, time %d, mana %d, from item %d",
|
||||||
spell.name, spell_id, target_id, slot, cast_time, mana_cost, item_slot==0xFFFFFFFF?999:item_slot);
|
spell.name, spell_id, target_id, static_cast<int>(slot), cast_time, mana_cost, item_slot==0xFFFFFFFF?999:item_slot);
|
||||||
|
|
||||||
casting_spell_id = spell_id;
|
casting_spell_id = spell_id;
|
||||||
casting_spell_slot = slot;
|
casting_spell_slot = slot;
|
||||||
@ -418,7 +419,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
|||||||
// If you're at full mana, let it cast even if you dont have enough mana
|
// If you're at full mana, let it cast even if you dont have enough mana
|
||||||
|
|
||||||
// we calculated this above, now enforce it
|
// we calculated this above, now enforce it
|
||||||
if(mana_cost > 0 && slot != USE_ITEM_SPELL_SLOT)
|
if(mana_cost > 0 && slot != CastingSlot::Item)
|
||||||
{
|
{
|
||||||
int my_curmana = GetMana();
|
int my_curmana = GetMana();
|
||||||
int my_maxmana = GetMaxMana();
|
int my_maxmana = GetMaxMana();
|
||||||
@ -453,8 +454,26 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
|||||||
Log.Out(Logs::Detail, Logs::Spells, "Spell %d: Casting time %d (orig %d), mana cost %d",
|
Log.Out(Logs::Detail, Logs::Spells, "Spell %d: Casting time %d (orig %d), mana cost %d",
|
||||||
spell_id, cast_time, orgcasttime, mana_cost);
|
spell_id, cast_time, orgcasttime, mana_cost);
|
||||||
|
|
||||||
|
// now tell the people in the area -- we ALWAYS want to send this, even instant cast spells.
|
||||||
|
// The only time this is skipped is for NPC innate procs and weapon procs. Procs from buffs
|
||||||
|
// oddly still send this. Since those cases don't reach here, we don't need to check them
|
||||||
|
if (slot != CastingSlot::Discipline) {
|
||||||
|
auto outapp = new EQApplicationPacket(OP_BeginCast,sizeof(BeginCast_Struct));
|
||||||
|
BeginCast_Struct* begincast = (BeginCast_Struct*)outapp->pBuffer;
|
||||||
|
begincast->caster_id = GetID();
|
||||||
|
begincast->spell_id = spell_id;
|
||||||
|
begincast->cast_time = orgcasttime; // client calculates reduced time by itself
|
||||||
|
outapp->priority = 3;
|
||||||
|
entity_list.QueueCloseClients(this, outapp, false, 200, 0, true); //IsClient() ? FILTER_PCSPELLS : FILTER_NPCSPELLS);
|
||||||
|
safe_delete(outapp);
|
||||||
|
}
|
||||||
|
|
||||||
// cast time is 0, just finish it right now and be done with it
|
// cast time is 0, just finish it right now and be done with it
|
||||||
if(cast_time == 0) {
|
if(cast_time == 0) {
|
||||||
|
if (!DoCastingChecks()) {
|
||||||
|
StopCasting();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
CastedSpellFinished(spell_id, target_id, slot, mana_cost, item_slot, resist_adjust);
|
CastedSpellFinished(spell_id, target_id, slot, mana_cost, item_slot, resist_adjust);
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
@ -476,25 +495,14 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
|||||||
if (oSpellWillFinish)
|
if (oSpellWillFinish)
|
||||||
*oSpellWillFinish = Timer::GetCurrentTime() + cast_time + 100;
|
*oSpellWillFinish = Timer::GetCurrentTime() + cast_time + 100;
|
||||||
|
|
||||||
// now tell the people in the area
|
if (IsClient() && slot == CastingSlot::Item && item_slot != 0xFFFFFFFF) {
|
||||||
outapp = new EQApplicationPacket(OP_BeginCast,sizeof(BeginCast_Struct));
|
|
||||||
BeginCast_Struct* begincast = (BeginCast_Struct*)outapp->pBuffer;
|
|
||||||
begincast->caster_id = GetID();
|
|
||||||
begincast->spell_id = spell_id;
|
|
||||||
begincast->cast_time = orgcasttime; // client calculates reduced time by itself
|
|
||||||
outapp->priority = 3;
|
|
||||||
entity_list.QueueCloseClients(this, outapp, false, 200, 0, true); //IsClient() ? FILTER_PCSPELLS : FILTER_NPCSPELLS);
|
|
||||||
safe_delete(outapp);
|
|
||||||
outapp = nullptr;
|
|
||||||
|
|
||||||
if (IsClient() && slot == USE_ITEM_SPELL_SLOT &&item_slot != 0xFFFFFFFF) {
|
|
||||||
auto item = CastToClient()->GetInv().GetItem(item_slot);
|
auto item = CastToClient()->GetInv().GetItem(item_slot);
|
||||||
if (item && item->GetItem())
|
if (item && item->GetItem())
|
||||||
Message_StringID(MT_Spells, BEGINS_TO_GLOW, item->GetItem()->Name);
|
Message_StringID(MT_Spells, BEGINS_TO_GLOW, item->GetItem()->Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DoCastingChecks()) {
|
if (!DoCastingChecks()) {
|
||||||
InterruptSpell();
|
StopCasting();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,6 +558,10 @@ bool Mob::DoCastingChecks()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsClient() && spells[spell_id].EndurTimerIndex > 0 && casting_spell_slot < CastingSlot::MaxGems)
|
||||||
|
if (!CastToClient()->IsLinkedSpellReuseTimerReady(spells[spell_id].EndurTimerIndex))
|
||||||
|
return false;
|
||||||
|
|
||||||
casting_spell_checks = true;
|
casting_spell_checks = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -767,7 +779,7 @@ void Mob::ZeroCastingVars()
|
|||||||
spellend_timer.Disable();
|
spellend_timer.Disable();
|
||||||
casting_spell_id = 0;
|
casting_spell_id = 0;
|
||||||
casting_spell_targetid = 0;
|
casting_spell_targetid = 0;
|
||||||
casting_spell_slot = 0;
|
casting_spell_slot = CastingSlot::Gem1;
|
||||||
casting_spell_mana = 0;
|
casting_spell_mana = 0;
|
||||||
casting_spell_inventory_slot = 0;
|
casting_spell_inventory_slot = 0;
|
||||||
casting_spell_timer = 0;
|
casting_spell_timer = 0;
|
||||||
@ -802,7 +814,7 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(casting_spell_id && IsNPC()) {
|
if(casting_spell_id && IsNPC()) {
|
||||||
CastToNPC()->AI_Event_SpellCastFinished(false, casting_spell_slot);
|
CastToNPC()->AI_Event_SpellCastFinished(false, static_cast<uint16>(casting_spell_slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(casting_spell_aa_id && IsClient()) { //Rest AA Timer on failed cast
|
if(casting_spell_aa_id && IsClient()) { //Rest AA Timer on failed cast
|
||||||
@ -874,18 +886,44 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is like interrupt, just it doesn't spam interrupt packets to everyone
|
||||||
|
// There are a few cases where this is what live does :P
|
||||||
|
void Mob::StopCasting()
|
||||||
|
{
|
||||||
|
if (casting_spell_id && IsNPC()) {
|
||||||
|
CastToNPC()->AI_Event_SpellCastFinished(false, static_cast<uint16>(casting_spell_slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsClient()) {
|
||||||
|
auto c = CastToClient();
|
||||||
|
if (casting_spell_aa_id) { //Rest AA Timer on failed cast
|
||||||
|
c->Message_StringID(MT_SpellFailure, ABILITY_FAILED);
|
||||||
|
c->ResetAlternateAdvancementTimer(casting_spell_aa_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto outapp = new EQApplicationPacket(OP_ManaChange, sizeof(ManaChange_Struct));
|
||||||
|
auto mc = (ManaChange_Struct *)outapp->pBuffer;
|
||||||
|
mc->new_mana = GetMana();
|
||||||
|
mc->stamina = GetEndurance();
|
||||||
|
mc->spell_id = casting_spell_id;
|
||||||
|
mc->keepcasting = 0;
|
||||||
|
c->FastQueuePacket(&outapp);
|
||||||
|
}
|
||||||
|
ZeroCastingVars();
|
||||||
|
}
|
||||||
|
|
||||||
// this is called after the timer is up and the spell is finished
|
// this is called after the timer is up and the spell is finished
|
||||||
// casting. everything goes through here, including items with zero cast time
|
// casting. everything goes through here, including items with zero cast time
|
||||||
// only to be used from SpellProcess
|
// only to be used from SpellProcess
|
||||||
// NOTE: do not put range checking, etc into this function. this should
|
// NOTE: do not put range checking, etc into this function. this should
|
||||||
// just check timed spell specific things before passing off to SpellFinished
|
// just check timed spell specific things before passing off to SpellFinished
|
||||||
// which figures out proper targets etc
|
// which figures out proper targets etc
|
||||||
void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
|
void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slot,
|
||||||
uint16 mana_used, uint32 inventory_slot, int16 resist_adjust)
|
uint16 mana_used, uint32 inventory_slot, int16 resist_adjust)
|
||||||
{
|
{
|
||||||
bool IsFromItem = false;
|
bool IsFromItem = false;
|
||||||
|
|
||||||
if(IsClient() && slot != USE_ITEM_SPELL_SLOT && slot != POTION_BELT_SPELL_SLOT && slot != TARGET_RING_SPELL_SLOT && spells[spell_id].recast_time > 1000) { // 10 is item
|
if(IsClient() && slot != CastingSlot::Item && slot != CastingSlot::PotionBelt && spells[spell_id].recast_time > 1000) { // 10 is item
|
||||||
if(!CastToClient()->GetPTimers().Expired(&database, pTimerSpellStart + spell_id, false)) {
|
if(!CastToClient()->GetPTimers().Expired(&database, pTimerSpellStart + spell_id, false)) {
|
||||||
//should we issue a message or send them a spell gem packet?
|
//should we issue a message or send them a spell gem packet?
|
||||||
Message_StringID(13, SPELL_RECAST);
|
Message_StringID(13, SPELL_RECAST);
|
||||||
@ -895,7 +933,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IsClient() && ((slot == USE_ITEM_SPELL_SLOT) || (slot == POTION_BELT_SPELL_SLOT) || (slot == TARGET_RING_SPELL_SLOT)))
|
if(IsClient() && (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt))
|
||||||
{
|
{
|
||||||
IsFromItem = true;
|
IsFromItem = true;
|
||||||
ItemInst *itm = CastToClient()->GetInv().GetItem(inventory_slot);
|
ItemInst *itm = CastToClient()->GetInv().GetItem(inventory_slot);
|
||||||
@ -1193,7 +1231,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
|
|||||||
|
|
||||||
int16 DeleteChargeFromSlot = -1;
|
int16 DeleteChargeFromSlot = -1;
|
||||||
|
|
||||||
if(IsClient() && ((slot == USE_ITEM_SPELL_SLOT) || (slot == POTION_BELT_SPELL_SLOT) || (slot == TARGET_RING_SPELL_SLOT))
|
if(IsClient() && (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt)
|
||||||
&& inventory_slot != 0xFFFFFFFF) // 10 is an item
|
&& inventory_slot != 0xFFFFFFFF) // 10 is an item
|
||||||
{
|
{
|
||||||
bool fromaug = false;
|
bool fromaug = false;
|
||||||
@ -1306,8 +1344,11 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
|
|||||||
{
|
{
|
||||||
if(IsClient())
|
if(IsClient())
|
||||||
{
|
{
|
||||||
this->CastToClient()->CheckSongSkillIncrease(spell_id);
|
Client *c = CastToClient();
|
||||||
this->CastToClient()->MemorizeSpell(slot, spell_id, memSpellSpellbar);
|
c->CheckSongSkillIncrease(spell_id);
|
||||||
|
if (spells[spell_id].EndurTimerIndex > 0 && slot < CastingSlot::MaxGems)
|
||||||
|
c->SetLinkedSpellReuseTimer(spells[spell_id].EndurTimerIndex, spells[spell_id].recast_time / 1000);
|
||||||
|
c->MemorizeSpell(static_cast<uint32>(slot), spell_id, memSpellSpellbar);
|
||||||
}
|
}
|
||||||
Log.Out(Logs::Detail, Logs::Spells, "Bard song %d should be started", spell_id);
|
Log.Out(Logs::Detail, Logs::Spells, "Bard song %d should be started", spell_id);
|
||||||
}
|
}
|
||||||
@ -1319,14 +1360,15 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
|
|||||||
SendSpellBarEnable(spell_id);
|
SendSpellBarEnable(spell_id);
|
||||||
|
|
||||||
// this causes the delayed refresh of the spell bar gems
|
// this causes the delayed refresh of the spell bar gems
|
||||||
c->MemorizeSpell(slot, spell_id, memSpellSpellbar);
|
if (spells[spell_id].EndurTimerIndex > 0 && slot < CastingSlot::MaxGems)
|
||||||
|
c->SetLinkedSpellReuseTimer(spells[spell_id].EndurTimerIndex, spells[spell_id].recast_time / 1000);
|
||||||
|
c->MemorizeSpell(static_cast<uint32>(slot), spell_id, memSpellSpellbar);
|
||||||
|
|
||||||
// this tells the client that casting may happen again
|
// this tells the client that casting may happen again
|
||||||
SetMana(GetMana());
|
SetMana(GetMana());
|
||||||
|
|
||||||
// skills
|
// skills
|
||||||
if(slot < MAX_PP_MEMSPELL)
|
if (EQEmu::skills::IsCastingSkill(spells[spell_id].skill)) {
|
||||||
{
|
|
||||||
c->CheckIncreaseSkill(spells[spell_id].skill, nullptr);
|
c->CheckIncreaseSkill(spells[spell_id].skill, nullptr);
|
||||||
|
|
||||||
// increased chance of gaining channel skill if you regained concentration
|
// increased chance of gaining channel skill if you regained concentration
|
||||||
@ -1348,8 +1390,8 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, uint16 slot) {
|
bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, CastingSlot slot, bool isproc)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
The basic types of spells:
|
The basic types of spells:
|
||||||
|
|
||||||
@ -1395,6 +1437,11 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
|||||||
targetType = ST_GroupClientAndPet;
|
targetType = ST_GroupClientAndPet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NPC innate procs override the target type to single target.
|
||||||
|
// Yes. This code will cause issues if they have the proc as innate AND on a weapon. Oh well.
|
||||||
|
if (isproc && IsNPC() && CastToNPC()->GetInnateProcSpellID() == spell_id)
|
||||||
|
targetType = ST_Target;
|
||||||
|
|
||||||
if (spell_target && !spell_target->PassCastRestriction(true, spells[spell_id].CastRestriction)){
|
if (spell_target && !spell_target->PassCastRestriction(true, spells[spell_id].CastRestriction)){
|
||||||
Message_StringID(13,SPELL_NEED_TAR);
|
Message_StringID(13,SPELL_NEED_TAR);
|
||||||
return false;
|
return false;
|
||||||
@ -1682,7 +1729,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
|||||||
case ST_Group:
|
case ST_Group:
|
||||||
case ST_GroupNoPets:
|
case ST_GroupNoPets:
|
||||||
{
|
{
|
||||||
if(IsClient() && CastToClient()->TGB() && IsTGBCompatibleSpell(spell_id) && slot != USE_ITEM_SPELL_SLOT) {
|
if(IsClient() && CastToClient()->TGB() && IsTGBCompatibleSpell(spell_id) && (slot != CastingSlot::Item || RuleB(Spells, AllowItemTGB))) {
|
||||||
if( (!target) ||
|
if( (!target) ||
|
||||||
(target->IsNPC() && !(target->GetOwner() && target->GetOwner()->IsClient())) ||
|
(target->IsNPC() && !(target->GetOwner() && target->GetOwner()->IsClient())) ||
|
||||||
(target->IsCorpse()) )
|
(target->IsCorpse()) )
|
||||||
@ -1728,7 +1775,9 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
|||||||
{
|
{
|
||||||
if(IsGrouped())
|
if(IsGrouped())
|
||||||
{
|
{
|
||||||
group_id_caster = GetGroup()->GetID();
|
if (Group* group = GetGroup()) {
|
||||||
|
group_id_caster = group->GetID();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(IsRaidGrouped())
|
else if(IsRaidGrouped())
|
||||||
{
|
{
|
||||||
@ -1743,7 +1792,9 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
|||||||
Mob *owner = GetOwner();
|
Mob *owner = GetOwner();
|
||||||
if(owner->IsGrouped())
|
if(owner->IsGrouped())
|
||||||
{
|
{
|
||||||
group_id_caster = owner->GetGroup()->GetID();
|
if (Group* group = owner->GetGroup()) {
|
||||||
|
group_id_caster = group->GetID();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(owner->IsRaidGrouped())
|
else if(owner->IsRaidGrouped())
|
||||||
{
|
{
|
||||||
@ -1772,7 +1823,9 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
|||||||
{
|
{
|
||||||
if(spell_target->IsGrouped())
|
if(spell_target->IsGrouped())
|
||||||
{
|
{
|
||||||
group_id_target = spell_target->GetGroup()->GetID();
|
if (Group* group = spell_target->GetGroup()) {
|
||||||
|
group_id_target = group->GetID();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(spell_target->IsRaidGrouped())
|
else if(spell_target->IsRaidGrouped())
|
||||||
{
|
{
|
||||||
@ -1787,7 +1840,9 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
|||||||
Mob *owner = spell_target->GetOwner();
|
Mob *owner = spell_target->GetOwner();
|
||||||
if(owner->IsGrouped())
|
if(owner->IsGrouped())
|
||||||
{
|
{
|
||||||
group_id_target = owner->GetGroup()->GetID();
|
if (Group* group = owner->GetGroup()) {
|
||||||
|
group_id_target = group->GetID();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(owner->IsRaidGrouped())
|
else if(owner->IsRaidGrouped())
|
||||||
{
|
{
|
||||||
@ -1904,7 +1959,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
|||||||
// only used from CastedSpellFinished, and procs
|
// only used from CastedSpellFinished, and procs
|
||||||
// we can't interrupt in this, or anything called from this!
|
// we can't interrupt in this, or anything called from this!
|
||||||
// if you need to abort the casting, return false
|
// if you need to abort the casting, return false
|
||||||
bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 mana_used,
|
bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, uint16 mana_used,
|
||||||
uint32 inventory_slot, int16 resist_adjust, bool isproc, int level_override)
|
uint32 inventory_slot, int16 resist_adjust, bool isproc, int level_override)
|
||||||
{
|
{
|
||||||
//EQApplicationPacket *outapp = nullptr;
|
//EQApplicationPacket *outapp = nullptr;
|
||||||
@ -1974,7 +2029,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
|||||||
|
|
||||||
//determine the type of spell target we have
|
//determine the type of spell target we have
|
||||||
CastAction_type CastAction;
|
CastAction_type CastAction;
|
||||||
if(!DetermineSpellTargets(spell_id, spell_target, ae_center, CastAction, slot))
|
if(!DetermineSpellTargets(spell_id, spell_target, ae_center, CastAction, slot, isproc))
|
||||||
return(false);
|
return(false);
|
||||||
|
|
||||||
Log.Out(Logs::Detail, Logs::Spells, "Spell %d: target type %d, target %s, AE center %s", spell_id, CastAction, spell_target?spell_target->GetName():"NONE", ae_center?ae_center->GetName():"NONE");
|
Log.Out(Logs::Detail, Logs::Spells, "Spell %d: target type %d, target %s, AE center %s", spell_id, CastAction, spell_target?spell_target->GetName():"NONE", ae_center?ae_center->GetName():"NONE");
|
||||||
@ -2263,7 +2318,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
|||||||
|
|
||||||
bool mgb = HasMGB() && spells[spell_id].can_mgb;
|
bool mgb = HasMGB() && spells[spell_id].can_mgb;
|
||||||
// if this was a spell slot or an ability use up the mana for it
|
// if this was a spell slot or an ability use up the mana for it
|
||||||
if(slot != USE_ITEM_SPELL_SLOT && slot != POTION_BELT_SPELL_SLOT && slot != TARGET_RING_SPELL_SLOT && mana_used > 0)
|
if(slot != CastingSlot::Item && slot != CastingSlot::PotionBelt && mana_used > 0)
|
||||||
{
|
{
|
||||||
mana_used = GetActSpellCost(spell_id, mana_used);
|
mana_used = GetActSpellCost(spell_id, mana_used);
|
||||||
if (mgb) {
|
if (mgb) {
|
||||||
@ -2326,7 +2381,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IsClient() && ((slot == USE_ITEM_SPELL_SLOT) || (slot == POTION_BELT_SPELL_SLOT) || (slot == TARGET_RING_SPELL_SLOT)))
|
if(IsClient() && (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt))
|
||||||
{
|
{
|
||||||
ItemInst *itm = CastToClient()->GetInv().GetItem(inventory_slot);
|
ItemInst *itm = CastToClient()->GetInv().GetItem(inventory_slot);
|
||||||
if(itm && itm->GetItem()->RecastDelay > 0){
|
if(itm && itm->GetItem()->RecastDelay > 0){
|
||||||
@ -2345,7 +2400,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(IsNPC())
|
if(IsNPC())
|
||||||
CastToNPC()->AI_Event_SpellCastFinished(true, slot);
|
CastToNPC()->AI_Event_SpellCastFinished(true, static_cast<uint16>(slot));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2360,8 +2415,8 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
|||||||
*
|
*
|
||||||
* return false to stop the song
|
* return false to stop the song
|
||||||
*/
|
*/
|
||||||
bool Mob::ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, uint16 slot) {
|
bool Mob::ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, CastingSlot slot) {
|
||||||
if(slot == USE_ITEM_SPELL_SLOT) {
|
if(slot == CastingSlot::Item) {
|
||||||
//bard songs should never come from items...
|
//bard songs should never come from items...
|
||||||
Log.Out(Logs::Detail, Logs::Spells, "Bard Song Pulse %d: Supposidly cast from an item. Killing song.", spell_id);
|
Log.Out(Logs::Detail, Logs::Spells, "Bard Song Pulse %d: Supposidly cast from an item. Killing song.", spell_id);
|
||||||
return(false);
|
return(false);
|
||||||
@ -2972,8 +3027,7 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
|||||||
if
|
if
|
||||||
(
|
(
|
||||||
effect1 == SE_AttackSpeed ||
|
effect1 == SE_AttackSpeed ||
|
||||||
effect1 == SE_AttackSpeed2 ||
|
effect1 == SE_AttackSpeed2
|
||||||
effect1 == SE_AttackSpeed3
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
sp1_value -= 100;
|
sp1_value -= 100;
|
||||||
@ -3047,6 +3101,34 @@ bool Client::CheckSpellLevelRestriction(uint16 spell_id)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 Mob::GetFirstBuffSlot(bool disc, bool song)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Mob::GetLastBuffSlot(bool disc, bool song)
|
||||||
|
{
|
||||||
|
return GetCurrentBuffSlots();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Client::GetFirstBuffSlot(bool disc, bool song)
|
||||||
|
{
|
||||||
|
if (song)
|
||||||
|
return GetMaxBuffSlots();
|
||||||
|
if (disc)
|
||||||
|
return GetMaxBuffSlots() + GetMaxSongSlots();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Client::GetLastBuffSlot(bool disc, bool song)
|
||||||
|
{
|
||||||
|
if (song)
|
||||||
|
return GetMaxBuffSlots() + GetCurrentSongSlots();
|
||||||
|
if (disc)
|
||||||
|
return GetMaxBuffSlots() + GetMaxSongSlots() + GetCurrentDiscSlots();
|
||||||
|
return GetCurrentBuffSlots();
|
||||||
|
}
|
||||||
|
|
||||||
// returns the slot the buff was added to, -1 if it wasn't added due to
|
// returns the slot the buff was added to, -1 if it wasn't added due to
|
||||||
// stacking problems, and -2 if this is not a buff
|
// stacking problems, and -2 if this is not a buff
|
||||||
// if caster is null, the buff will be added with the caster level being
|
// if caster is null, the buff will be added with the caster level being
|
||||||
@ -3084,18 +3166,8 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
|||||||
// we also check if overwriting will occur. this is so after this loop
|
// we also check if overwriting will occur. this is so after this loop
|
||||||
// we can determine if there will be room for this buff
|
// we can determine if there will be room for this buff
|
||||||
int buff_count = GetMaxTotalSlots();
|
int buff_count = GetMaxTotalSlots();
|
||||||
uint32 start_slot = 0;
|
uint32 start_slot = GetFirstBuffSlot(IsDisciplineBuff(spell_id), spells[spell_id].short_buff_box);
|
||||||
uint32 end_slot = 0;
|
uint32 end_slot = GetLastBuffSlot(IsDisciplineBuff(spell_id), spells[spell_id].short_buff_box);
|
||||||
if (IsDisciplineBuff(spell_id)) {
|
|
||||||
start_slot = GetMaxBuffSlots() + GetMaxSongSlots();
|
|
||||||
end_slot = start_slot + GetCurrentDiscSlots();
|
|
||||||
} else if(spells[spell_id].short_buff_box) {
|
|
||||||
start_slot = GetMaxBuffSlots();
|
|
||||||
end_slot = start_slot + GetCurrentSongSlots();
|
|
||||||
} else {
|
|
||||||
start_slot = 0;
|
|
||||||
end_slot = GetCurrentBuffSlots();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (buffslot = 0; buffslot < buff_count; buffslot++) {
|
for (buffslot = 0; buffslot < buff_count; buffslot++) {
|
||||||
const Buffs_Struct &curbuf = buffs[buffslot];
|
const Buffs_Struct &curbuf = buffs[buffslot];
|
||||||
@ -3107,7 +3179,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
|||||||
if (ret == -1) { // stop the spell
|
if (ret == -1) { // stop the spell
|
||||||
Log.Out(Logs::Detail, Logs::Spells, "Adding buff %d failed: stacking prevented by spell %d in slot %d with caster level %d",
|
Log.Out(Logs::Detail, Logs::Spells, "Adding buff %d failed: stacking prevented by spell %d in slot %d with caster level %d",
|
||||||
spell_id, curbuf.spellid, buffslot, curbuf.casterlevel);
|
spell_id, curbuf.spellid, buffslot, curbuf.casterlevel);
|
||||||
if (caster->IsClient() && RuleB(Client, UseLiveBlockedMessage)) {
|
if (caster && caster->IsClient() && RuleB(Client, UseLiveBlockedMessage)) {
|
||||||
caster->Message(13, "Your %s did not take hold on %s. (Blocked by %s.)", spells[spell_id].name, this->GetName(), spells[curbuf.spellid].name);
|
caster->Message(13, "Your %s did not take hold on %s. (Blocked by %s.)", spells[spell_id].name, this->GetName(), spells[curbuf.spellid].name);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
@ -3769,7 +3841,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (IsValidSpell(spells[spell_id].RecourseLink) && spells[spell_id].RecourseLink != spell_id)
|
if (IsValidSpell(spells[spell_id].RecourseLink) && spells[spell_id].RecourseLink != spell_id)
|
||||||
SpellFinished(spells[spell_id].RecourseLink, this, 10, 0, -1, spells[spells[spell_id].RecourseLink].ResistDiff);
|
SpellFinished(spells[spell_id].RecourseLink, this, CastingSlot::Item, 0, -1, spells[spells[spell_id].RecourseLink].ResistDiff);
|
||||||
|
|
||||||
if (IsDetrimentalSpell(spell_id)) {
|
if (IsDetrimentalSpell(spell_id)) {
|
||||||
|
|
||||||
@ -4713,6 +4785,7 @@ void Mob::SendSpellBarEnable(uint16 spell_id)
|
|||||||
manachange->new_mana = GetMana();
|
manachange->new_mana = GetMana();
|
||||||
manachange->spell_id = spell_id;
|
manachange->spell_id = spell_id;
|
||||||
manachange->stamina = CastToClient()->GetEndurance();
|
manachange->stamina = CastToClient()->GetEndurance();
|
||||||
|
manachange->keepcasting = 0;
|
||||||
outapp->priority = 6;
|
outapp->priority = 6;
|
||||||
CastToClient()->QueuePacket(outapp);
|
CastToClient()->QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
@ -5245,7 +5318,7 @@ bool Mob::UseBardSpellLogic(uint16 spell_id, int slot)
|
|||||||
spell_id = casting_spell_id;
|
spell_id = casting_spell_id;
|
||||||
|
|
||||||
if(slot == -1)
|
if(slot == -1)
|
||||||
slot = casting_spell_slot;
|
slot = static_cast<int>(casting_spell_slot);
|
||||||
|
|
||||||
// should we treat this as a bard singing?
|
// should we treat this as a bard singing?
|
||||||
return
|
return
|
||||||
@ -5273,7 +5346,7 @@ void Mob::_StopSong()
|
|||||||
{
|
{
|
||||||
bardsong = 0;
|
bardsong = 0;
|
||||||
bardsong_target_id = 0;
|
bardsong_target_id = 0;
|
||||||
bardsong_slot = 0;
|
bardsong_slot = CastingSlot::Gem1;
|
||||||
bardsong_timer.Disable();
|
bardsong_timer.Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5351,8 +5424,8 @@ void Mob::SendPetBuffsToClient()
|
|||||||
|
|
||||||
int MaxSlots = GetMaxTotalSlots();
|
int MaxSlots = GetMaxTotalSlots();
|
||||||
|
|
||||||
if(MaxSlots > BUFF_COUNT)
|
if(MaxSlots > PET_BUFF_COUNT)
|
||||||
MaxSlots = BUFF_COUNT;
|
MaxSlots = PET_BUFF_COUNT;
|
||||||
|
|
||||||
for(int buffslot = 0; buffslot < MaxSlots; buffslot++)
|
for(int buffslot = 0; buffslot < MaxSlots; buffslot++)
|
||||||
{
|
{
|
||||||
@ -5449,10 +5522,14 @@ void Mob::BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration)
|
|||||||
|
|
||||||
int Client::GetCurrentBuffSlots() const
|
int Client::GetCurrentBuffSlots() const
|
||||||
{
|
{
|
||||||
if(15 + aabonuses.BuffSlotIncrease > 25)
|
int numbuffs = 15;
|
||||||
return 25;
|
// client does check spells and items
|
||||||
else
|
numbuffs += aabonuses.BuffSlotIncrease + spellbonuses.BuffSlotIncrease + itembonuses.BuffSlotIncrease;
|
||||||
return 15 + aabonuses.BuffSlotIncrease;
|
if (GetLevel() > 70)
|
||||||
|
numbuffs++;
|
||||||
|
if (GetLevel() > 74)
|
||||||
|
numbuffs++;
|
||||||
|
return EQEmu::ClampUpper(numbuffs, GetMaxBuffSlots());
|
||||||
}
|
}
|
||||||
|
|
||||||
int Client::GetCurrentSongSlots() const
|
int Client::GetCurrentSongSlots() const
|
||||||
@ -5644,3 +5721,26 @@ void Mob::ConeDirectional(uint16 spell_id, int16 resist_adjust)
|
|||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// duration in seconds
|
||||||
|
void Client::SetLinkedSpellReuseTimer(uint32 timer_id, uint32 duration)
|
||||||
|
{
|
||||||
|
if (timer_id > 19)
|
||||||
|
return;
|
||||||
|
Log.Out(Logs::Detail, Logs::Spells, "Setting Linked Spell Reuse %d for %d", timer_id, duration);
|
||||||
|
GetPTimers().Start(pTimerLinkedSpellReuseStart + timer_id, duration);
|
||||||
|
auto outapp = new EQApplicationPacket(OP_LinkedReuse, sizeof(LinkedSpellReuseTimer_Struct));
|
||||||
|
auto lr = (LinkedSpellReuseTimer_Struct *)outapp->pBuffer;
|
||||||
|
lr->timer_id = timer_id;
|
||||||
|
lr->start_time = Timer::GetCurrentTime() / 1000;
|
||||||
|
lr->end_time = lr->start_time + duration;
|
||||||
|
FastQueuePacket(&outapp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Client::IsLinkedSpellReuseTimerReady(uint32 timer_id)
|
||||||
|
{
|
||||||
|
if (timer_id > 19)
|
||||||
|
return true;
|
||||||
|
return GetPTimers().Expired(&database, pTimerLinkedSpellReuseStart + timer_id, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -297,6 +297,7 @@
|
|||||||
#define ADVENTURE_COMPLETE 5147 //You received %1 points for successfully completing the adventure.
|
#define ADVENTURE_COMPLETE 5147 //You received %1 points for successfully completing the adventure.
|
||||||
#define SUCCOR_FAIL 5169 //The portal collapes before you can escape!
|
#define SUCCOR_FAIL 5169 //The portal collapes before you can escape!
|
||||||
#define PET_ATTACKING 5501 //%1 tells you, 'Attacking %2 Master.'
|
#define PET_ATTACKING 5501 //%1 tells you, 'Attacking %2 Master.'
|
||||||
|
#define AVOID_STUNNING_BLOW 5753 //You avoid the stunning blow.
|
||||||
#define FATAL_BOW_SHOT 5745 //%1 performs a FATAL BOW SHOT!!
|
#define FATAL_BOW_SHOT 5745 //%1 performs a FATAL BOW SHOT!!
|
||||||
#define MELEE_SILENCE 5806 //You *CANNOT* use this melee ability, you are suffering from amnesia!
|
#define MELEE_SILENCE 5806 //You *CANNOT* use this melee ability, you are suffering from amnesia!
|
||||||
#define DISCIPLINE_REUSE_MSG 5807 //You can use the ability %1 again in %2 hour(s) %3 minute(s) %4 seconds.
|
#define DISCIPLINE_REUSE_MSG 5807 //You can use the ability %1 again in %2 hour(s) %3 minute(s) %4 seconds.
|
||||||
@ -354,7 +355,7 @@
|
|||||||
#define HIT_NON_MELEE 9073 //%1 hit %2 for %3 points of non-melee damage.
|
#define HIT_NON_MELEE 9073 //%1 hit %2 for %3 points of non-melee damage.
|
||||||
#define GLOWS_BLUE 9074 //Your %1 glows blue.
|
#define GLOWS_BLUE 9074 //Your %1 glows blue.
|
||||||
#define GLOWS_RED 9075 //Your %1 glows red.
|
#define GLOWS_RED 9075 //Your %1 glows red.
|
||||||
#define SHAKE_OFF_STUN 9077
|
#define SHAKE_OFF_STUN 9077 //You shake off the stun effect!
|
||||||
#define STRIKETHROUGH_STRING 9078 //You strike through your opponent's defenses!
|
#define STRIKETHROUGH_STRING 9078 //You strike through your opponent's defenses!
|
||||||
#define SPELL_REFLECT 9082 //%1's spell has been reflected by %2.
|
#define SPELL_REFLECT 9082 //%1's spell has been reflected by %2.
|
||||||
#define NEW_SPELLS_AVAIL 9149 //You have new spells available to you. Check the merchants near your guild master.
|
#define NEW_SPELLS_AVAIL 9149 //You have new spells available to you. Check the merchants near your guild master.
|
||||||
|
|||||||
@ -115,7 +115,7 @@ void Trap::Trigger(Mob* trigger)
|
|||||||
entity_list.MessageClose(trigger,false,100,13,"%s",message.c_str());
|
entity_list.MessageClose(trigger,false,100,13,"%s",message.c_str());
|
||||||
}
|
}
|
||||||
if(hiddenTrigger){
|
if(hiddenTrigger){
|
||||||
hiddenTrigger->SpellFinished(effectvalue, trigger, 10, 0, -1, spells[effectvalue].ResistDiff);
|
hiddenTrigger->SpellFinished(effectvalue, trigger, EQEmu::CastingSlot::Item, 0, -1, spells[effectvalue].ResistDiff);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case trapTypeAlarm:
|
case trapTypeAlarm:
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
extern const ZoneConfig *Config;
|
extern const ZoneConfig *Config;
|
||||||
|
|
||||||
enum WaterRegionType {
|
enum WaterRegionType : int {
|
||||||
RegionTypeUnsupported = -2,
|
RegionTypeUnsupported = -2,
|
||||||
RegionTypeUntagged = -1,
|
RegionTypeUntagged = -1,
|
||||||
RegionTypeNormal = 0,
|
RegionTypeNormal = 0,
|
||||||
@ -33,6 +33,8 @@ public:
|
|||||||
virtual bool InVWater(const glm::vec3& location) const = 0;
|
virtual bool InVWater(const glm::vec3& location) const = 0;
|
||||||
virtual bool InLava(const glm::vec3& location) const = 0;
|
virtual bool InLava(const glm::vec3& location) const = 0;
|
||||||
virtual bool InLiquid(const glm::vec3& location) const = 0;
|
virtual bool InLiquid(const glm::vec3& location) const = 0;
|
||||||
|
virtual bool InPvP(const glm::vec3& location) const = 0;
|
||||||
|
virtual bool InZoneLine(const glm::vec3& location) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool Load(FILE *fp) { return false; }
|
virtual bool Load(FILE *fp) { return false; }
|
||||||
|
|||||||
@ -30,6 +30,14 @@ bool WaterMapV1::InLiquid(const glm::vec3& location) const {
|
|||||||
return InWater(location) || InLava(location);
|
return InWater(location) || InLava(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WaterMapV1::InPvP(const glm::vec3& location) const {
|
||||||
|
return ReturnRegionType(location) == RegionTypePVP;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WaterMapV1::InZoneLine(const glm::vec3& location) const {
|
||||||
|
return ReturnRegionType(location) == RegionTypeZoneLine;
|
||||||
|
}
|
||||||
|
|
||||||
bool WaterMapV1::Load(FILE *fp) {
|
bool WaterMapV1::Load(FILE *fp) {
|
||||||
uint32 bsp_tree_size;
|
uint32 bsp_tree_size;
|
||||||
if (fread(&bsp_tree_size, sizeof(bsp_tree_size), 1, fp) != 1) {
|
if (fread(&bsp_tree_size, sizeof(bsp_tree_size), 1, fp) != 1) {
|
||||||
|
|||||||
@ -24,6 +24,8 @@ public:
|
|||||||
virtual bool InVWater(const glm::vec3& location) const;
|
virtual bool InVWater(const glm::vec3& location) const;
|
||||||
virtual bool InLava(const glm::vec3& location) const;
|
virtual bool InLava(const glm::vec3& location) const;
|
||||||
virtual bool InLiquid(const glm::vec3& location) const;
|
virtual bool InLiquid(const glm::vec3& location) const;
|
||||||
|
virtual bool InPvP(const glm::vec3& location) const;
|
||||||
|
virtual bool InZoneLine(const glm::vec3& location) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool Load(FILE *fp);
|
virtual bool Load(FILE *fp);
|
||||||
|
|||||||
@ -33,6 +33,14 @@ bool WaterMapV2::InLiquid(const glm::vec3& location) const {
|
|||||||
return InWater(location) || InLava(location);
|
return InWater(location) || InLava(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WaterMapV2::InPvP(const glm::vec3& location) const {
|
||||||
|
return ReturnRegionType(location) == RegionTypePVP;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WaterMapV2::InZoneLine(const glm::vec3& location) const {
|
||||||
|
return ReturnRegionType(location) == RegionTypeZoneLine;
|
||||||
|
}
|
||||||
|
|
||||||
bool WaterMapV2::Load(FILE *fp) {
|
bool WaterMapV2::Load(FILE *fp) {
|
||||||
uint32 region_count;
|
uint32 region_count;
|
||||||
if (fread(®ion_count, sizeof(region_count), 1, fp) != 1) {
|
if (fread(®ion_count, sizeof(region_count), 1, fp) != 1) {
|
||||||
|
|||||||
@ -17,6 +17,8 @@ public:
|
|||||||
virtual bool InVWater(const glm::vec3& location) const;
|
virtual bool InVWater(const glm::vec3& location) const;
|
||||||
virtual bool InLava(const glm::vec3& location) const;
|
virtual bool InLava(const glm::vec3& location) const;
|
||||||
virtual bool InLiquid(const glm::vec3& location) const;
|
virtual bool InLiquid(const glm::vec3& location) const;
|
||||||
|
virtual bool InPvP(const glm::vec3& location) const;
|
||||||
|
virtual bool InZoneLine(const glm::vec3& location) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool Load(FILE *fp);
|
virtual bool Load(FILE *fp);
|
||||||
|
|||||||
@ -765,7 +765,7 @@ void WorldServer::Process() {
|
|||||||
zone->SetZoneHasCurrentTime(true);
|
zone->SetZoneHasCurrentTime(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
if (zone->is_zone_time_localized){
|
if (zone && zone->is_zone_time_localized){
|
||||||
Log.Out(Logs::General, Logs::Zone_Server, "Received request to sync time from world, but our time is localized currently");
|
Log.Out(Logs::General, Logs::Zone_Server, "Received request to sync time from world, but our time is localized currently");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -1594,7 +1594,9 @@ ZonePoint* Zone::GetClosestZonePoint(const glm::vec3& location, uint32 to, Clien
|
|||||||
iterator.Advance();
|
iterator.Advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(closest_dist > 400.0f && closest_dist < max_distance2)
|
// if we have a water map and it says we're in a zoneline, lets assume it's just a really big zone line
|
||||||
|
// this shouldn't open up any exploits since those situations are detected later on
|
||||||
|
if ((zone->HasWaterMap() && !zone->watermap->InZoneLine(glm::vec3(client->GetPosition()))) || (!zone->HasWaterMap() && closest_dist > 400.0f && closest_dist < max_distance2))
|
||||||
{
|
{
|
||||||
if(client)
|
if(client)
|
||||||
client->CheatDetected(MQZoneUnknownDest, location.x, location.y, location.z); // Someone is trying to use /zone
|
client->CheatDetected(MQZoneUnknownDest, location.x, location.y, location.z); // Someone is trying to use /zone
|
||||||
|
|||||||
@ -3178,7 +3178,8 @@ void ZoneDatabase::SavePetInfo(Client *client)
|
|||||||
query.clear();
|
query.clear();
|
||||||
|
|
||||||
// pet buffs!
|
// pet buffs!
|
||||||
for (int index = 0; index < RuleI(Spells, MaxTotalSlotsPET); index++) {
|
int max_slots = RuleI(Spells, MaxTotalSlotsPET);
|
||||||
|
for (int index = 0; index < max_slots; index++) {
|
||||||
if (petinfo->Buffs[index].spellid == SPELL_UNKNOWN || petinfo->Buffs[index].spellid == 0)
|
if (petinfo->Buffs[index].spellid == SPELL_UNKNOWN || petinfo->Buffs[index].spellid == 0)
|
||||||
continue;
|
continue;
|
||||||
if (query.length() == 0)
|
if (query.length() == 0)
|
||||||
|
|||||||
@ -125,7 +125,7 @@ struct PetInfo {
|
|||||||
uint32 HP;
|
uint32 HP;
|
||||||
uint32 Mana;
|
uint32 Mana;
|
||||||
float size;
|
float size;
|
||||||
SpellBuff_Struct Buffs[BUFF_COUNT];
|
SpellBuff_Struct Buffs[PET_BUFF_COUNT];
|
||||||
uint32 Items[EQEmu::legacy::EQUIPMENT_SIZE];
|
uint32 Items[EQEmu::legacy::EQUIPMENT_SIZE];
|
||||||
char Name[64];
|
char Name[64];
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user