Move out faction changes to later db version as it is still pending.

This commit is contained in:
Noudess
2019-01-23 14:54:16 -05:00
1681 changed files with 221296 additions and 36385 deletions
+3 -2
View File
@@ -82,6 +82,8 @@ SET(zone_sources
merc.cpp
mob.cpp
mob_ai.cpp
mob_appearance.cpp
mob_movement_manager.cpp
mob_info.cpp
mod_functions.cpp
net.cpp
@@ -93,7 +95,6 @@ SET(zone_sources
pathfinder_interface.cpp
pathfinder_nav_mesh.cpp
pathfinder_null.cpp
pathfinder_waypoint.cpp
pathing.cpp
perl_client.cpp
perl_doors.cpp
@@ -205,6 +206,7 @@ SET(zone_headers
message.h
merc.h
mob.h
mob_movement_manager.h
net.h
npc.h
npc_ai.h
@@ -214,7 +216,6 @@ SET(zone_headers
pathfinder_interface.h
pathfinder_nav_mesh.h
pathfinder_null.h
pathfinder_waypoint.h
perlpacket.h
petitions.h
pets.h
+16 -16
View File
@@ -126,7 +126,7 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
(npc_dup != nullptr) ? npc_dup : npc_type, //make sure we give the NPC the correct data pointer
0,
GetPosition() + glm::vec4(swarmPetLocations[summon_count], 0.0f, 0.0f),
FlyMode3);
GravityBehavior::Water);
if (followme)
swarm_pet_npc->SetFollowID(GetID());
@@ -225,7 +225,7 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid
(npc_dup!=nullptr)?npc_dup:npc_type, //make sure we give the NPC the correct data pointer
0,
GetPosition() + glm::vec4(swarmPetLocations[summon_count], 0.0f, 0.0f),
FlyMode3);
GravityBehavior::Water);
if (followme)
swarm_pet_npc->SetFollowID(GetID());
@@ -286,7 +286,7 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
make_npc->min_dmg = 1;
//base stats
make_npc->cur_hp = (GetLevel() * 55);
make_npc->current_hp = (GetLevel() * 55);
make_npc->max_hp = (GetLevel() * 55);
make_npc->STR = 85 + (GetLevel() * 3);
make_npc->STA = 85 + (GetLevel() * 3);
@@ -356,51 +356,51 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
case PALADIN:
//SPECATK_TRIPLE
strcpy(make_npc->special_abilities, "6,1");
make_npc->cur_hp = make_npc->cur_hp * 150 / 100;
make_npc->current_hp = make_npc->current_hp * 150 / 100;
make_npc->max_hp = make_npc->max_hp * 150 / 100;
make_npc->npc_spells_id = 8;
break;
case SHADOWKNIGHT:
strcpy(make_npc->special_abilities, "6,1");
make_npc->cur_hp = make_npc->cur_hp * 150 / 100;
make_npc->current_hp = make_npc->current_hp * 150 / 100;
make_npc->max_hp = make_npc->max_hp * 150 / 100;
make_npc->npc_spells_id = 9;
break;
case RANGER:
strcpy(make_npc->special_abilities, "7,1");
make_npc->cur_hp = make_npc->cur_hp * 135 / 100;
make_npc->current_hp = make_npc->current_hp * 135 / 100;
make_npc->max_hp = make_npc->max_hp * 135 / 100;
make_npc->npc_spells_id = 10;
break;
case BARD:
strcpy(make_npc->special_abilities, "6,1");
make_npc->cur_hp = make_npc->cur_hp * 110 / 100;
make_npc->current_hp = make_npc->current_hp * 110 / 100;
make_npc->max_hp = make_npc->max_hp * 110 / 100;
make_npc->npc_spells_id = 11;
break;
case BEASTLORD:
strcpy(make_npc->special_abilities, "7,1");
make_npc->cur_hp = make_npc->cur_hp * 110 / 100;
make_npc->current_hp = make_npc->current_hp * 110 / 100;
make_npc->max_hp = make_npc->max_hp * 110 / 100;
make_npc->npc_spells_id = 12;
break;
case ROGUE:
strcpy(make_npc->special_abilities, "7,1");
make_npc->max_dmg = make_npc->max_dmg * 150 /100;
make_npc->cur_hp = make_npc->cur_hp * 110 / 100;
make_npc->current_hp = make_npc->current_hp * 110 / 100;
make_npc->max_hp = make_npc->max_hp * 110 / 100;
break;
case MONK:
strcpy(make_npc->special_abilities, "7,1");
make_npc->max_dmg = make_npc->max_dmg * 150 /100;
make_npc->cur_hp = make_npc->cur_hp * 135 / 100;
make_npc->current_hp = make_npc->current_hp * 135 / 100;
make_npc->max_hp = make_npc->max_hp * 135 / 100;
break;
case WARRIOR:
case BERSERKER:
strcpy(make_npc->special_abilities, "7,1");
make_npc->max_dmg = make_npc->max_dmg * 150 /100;
make_npc->cur_hp = make_npc->cur_hp * 175 / 100;
make_npc->current_hp = make_npc->current_hp * 175 / 100;
make_npc->max_hp = make_npc->max_hp * 175 / 100;
break;
default:
@@ -413,7 +413,7 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
make_npc->d_melee_texture1 = 0;
make_npc->d_melee_texture2 = 0;
auto npca = new NPC(make_npc, 0, GetPosition(), FlyMode3);
auto npca = new NPC(make_npc, 0, GetPosition(), GravityBehavior::Water);
if(!npca->GetSwarmInfo()){
auto nSI = new SwarmPet;
@@ -488,7 +488,7 @@ void Client::ResetAA() {
database.DeleteCharacterLeadershipAAs(CharacterID());
// undefined for these clients
if (ClientVersionBit() & EQEmu::versions::bit_TitaniumAndEarlier)
if (ClientVersionBit() & EQEmu::versions::maskTitaniumAndEarlier)
Kick();
}
@@ -1221,12 +1221,12 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
// 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(!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQEmu::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) {
if(!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQEmu::spells::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) {
return;
}
ExpendAlternateAdvancementCharge(ability->id);
} else {
if(!CastSpell(rank->spell, target_id, EQEmu::CastingSlot::AltAbility, -1, -1, 0, -1, rank->spell_type + pTimerAAStart, cooldown, nullptr, rank->id)) {
if(!CastSpell(rank->spell, target_id, EQEmu::spells::CastingSlot::AltAbility, -1, -1, 0, -1, rank->spell_type + pTimerAAStart, cooldown, nullptr, rank->id)) {
return;
}
}
@@ -1455,7 +1455,7 @@ bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank) {
//the one titanium hack i will allow
//just to make sure we dont crash the client with newer aas
//we'll exclude any expendable ones
if(IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::bit_TitaniumAndEarlier) {
if(IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::maskTitaniumAndEarlier) {
if(ability->charges > 0) {
return false;
}
+1 -1
View File
@@ -954,7 +954,7 @@ bool Mob::CombatRange(Mob* other)
if (_DistNoRoot <= size_mod)
{
//A hack to kill an exploit till we get something better.
if (flymode == 0 && _zDist > 500 && !CheckLastLosState()) {
if (flymode != GravityBehavior::Flying && _zDist > 500 && !CheckLastLosState()) {
return false;
}
+29 -24
View File
@@ -33,6 +33,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "zone.h"
#include "lua_parser.h"
#include "fastmath.h"
#include "mob.h"
#include <assert.h>
#include <stdio.h>
@@ -1524,7 +1526,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
IsValidSpell(aabonuses.SkillAttackProc[2])) {
float chance = aabonuses.SkillAttackProc[0] / 1000.0f;
if (zone->random.Roll(chance))
SpellFinished(aabonuses.SkillAttackProc[2], other, EQEmu::CastingSlot::Item, 0, -1,
SpellFinished(aabonuses.SkillAttackProc[2], other, EQEmu::spells::CastingSlot::Item, 0, -1,
spells[aabonuses.SkillAttackProc[2]].ResistDiff);
}
other->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, my_hit.skill, true, -1, false, m_specialattacks);
@@ -1792,7 +1794,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk
//this generates a lot of 'updates' to the client that the client does not need
BuffFadeNonPersistDeath();
if (RuleB(Character, UnmemSpellsOnDeath)) {
if ((ClientVersionBit() & EQEmu::versions::bit_SoFAndLater) && RuleB(Character, RespawnFromHover))
if ((ClientVersionBit() & EQEmu::versions::maskSoFAndLater) && RuleB(Character, RespawnFromHover))
UnmemSpellAll(true);
else
UnmemSpellAll(false);
@@ -1855,7 +1857,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk
from these and overwrite what we set in pp anyway
*/
if (LeftCorpse && (ClientVersionBit() & EQEmu::versions::bit_SoFAndLater) && RuleB(Character, RespawnFromHover))
if (LeftCorpse && (ClientVersionBit() & EQEmu::versions::maskSoFAndLater) && RuleB(Character, RespawnFromHover))
{
ClearDraggedCorpses();
RespawnFromHoverTimer.Start(RuleI(Character, RespawnFromHoverTimer) * 1000);
@@ -2128,7 +2130,7 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, EQEmu::skills::Skill
if (IsLDoNTrapped())
{
Message_StringID(13, LDON_ACCIDENT_SETOFF2);
SpellFinished(GetLDoNTrapSpellID(), other, EQEmu::CastingSlot::Item, 0, -1, spells[GetLDoNTrapSpellID()].ResistDiff, false);
SpellFinished(GetLDoNTrapSpellID(), other, EQEmu::spells::CastingSlot::Item, 0, -1, spells[GetLDoNTrapSpellID()].ResistDiff, false);
SetLDoNTrapSpellID(0);
SetLDoNTrapped(false);
SetLDoNTrapDetected(false);
@@ -2668,12 +2670,6 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
}
}
}
if (IsNPC() && CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if (!zone->watermap->InLiquid(glm::vec3(other->GetPosition()))) {
return;
}
}
// first add self
// The damage on the hate list is used to award XP to the killer. This check is to prevent Killstealing.
@@ -2695,16 +2691,24 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
#ifdef BOTS
// if other is a bot, add the bots client to the hate list
if (other->IsBot()) {
if (other->CastToBot()->GetBotOwner() && other->CastToBot()->GetBotOwner()->CastToClient()->GetFeigned()) {
AddFeignMemory(other->CastToBot()->GetBotOwner()->CastToClient());
while (other->IsBot()) {
auto other_ = other->CastToBot();
if (!other_ || !other_->GetBotOwner())
break;
auto owner_ = other_->GetBotOwner()->CastToClient();
if (!owner_ || owner_->IsDead() || !owner_->InZone()) // added isdead and inzone checks to avoid issues in AddAutoXTarget(...) below
break;
if (owner_->GetFeigned()) {
AddFeignMemory(owner_);
}
else {
if (!hate_list.IsEntOnHateList(other->CastToBot()->GetBotOwner())) {
hate_list.AddEntToHateList(other->CastToBot()->GetBotOwner(), 0, 0, false, true);
other->CastToBot()->GetBotOwner()->CastToClient()->AddAutoXTarget(this);
}
else if (!hate_list.IsEntOnHateList(owner_)) {
hate_list.AddEntToHateList(owner_, 0, 0, false, true);
owner_->AddAutoXTarget(this); // this was being called on dead/out-of-zone clients
}
break;
}
#endif //BOTS
@@ -2716,6 +2720,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
else {
if (!hate_list.IsEntOnHateList(other->CastToMerc()->GetMercOwner()))
hate_list.AddEntToHateList(other->CastToMerc()->GetMercOwner(), 0, 0, false, true);
// if mercs are reworked to include adding 'this' to owner's xtarget list, this should reflect bots code above
}
} //MERC
@@ -3786,7 +3791,7 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id)
if (IsBuffSpell(spell_id)) { // hots
// message to caster
if (caster->IsClient() && caster == this) {
if (caster->CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoFAndLater)
if (caster->CastToClient()->ClientVersionBit() & EQEmu::versions::maskSoFAndLater)
FilteredMessage_StringID(caster, MT_NonMelee, FilterHealOverTime,
HOT_HEAL_SELF, itoa(acthealed), spells[spell_id].name);
else
@@ -3794,7 +3799,7 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id)
YOU_HEALED, GetCleanName(), itoa(acthealed));
}
else if (caster->IsClient() && caster != this) {
if (caster->CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoFAndLater)
if (caster->CastToClient()->ClientVersionBit() & EQEmu::versions::maskSoFAndLater)
caster->FilteredMessage_StringID(caster, MT_NonMelee, FilterHealOverTime,
HOT_HEAL_OTHER, GetCleanName(), itoa(acthealed),
spells[spell_id].name);
@@ -3804,7 +3809,7 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id)
}
// message to target
if (IsClient() && caster != this) {
if (CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoFAndLater)
if (CastToClient()->ClientVersionBit() & EQEmu::versions::maskSoFAndLater)
FilteredMessage_StringID(this, MT_NonMelee, FilterHealOverTime,
HOT_HEALED_OTHER, caster->GetCleanName(),
itoa(acthealed), spells[spell_id].name);
@@ -5033,7 +5038,7 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
hit.damage_done = headshot;
}
else if (GetClass() == RANGER && GetLevel() > 50) { // no double dmg on headshot
if (defender->IsNPC() && !defender->IsMoving() && !defender->IsRooted()) {
if ((defender->IsNPC() && !defender->IsMoving() && !defender->IsRooted()) || !RuleB(Combat, ArcheryBonusRequiresStationary)) {
hit.damage_done *= 2;
Message_StringID(MT_CritMelee, BOW_DOUBLE_DAMAGE);
}
@@ -5441,7 +5446,7 @@ void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
// For now, SPECATK_QUAD means innate DW when Combat:UseLiveCombatRounds is true
if ((GetSpecialAbility(SPECATK_INNATE_DW) ||
(RuleB(Combat, UseLiveCombatRounds) && GetSpecialAbility(SPECATK_QUAD))) ||
GetEquipment(EQEmu::textures::weaponSecondary) != 0) {
GetEquippedItemFromTextureSlot(EQEmu::textures::weaponSecondary) != 0) {
if (CheckDualWield()) {
Attack(target, EQEmu::invslot::slotSecondary, false, false, false, opts);
if (CanThisClassDoubleAttack() && GetLevel() > 35 && CheckDoubleAttack()) {
@@ -5473,4 +5478,4 @@ int32 Mob::GetHPRegen() const
int32 Mob::GetManaRegen() const
{
return mana_regen;
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
#include "raids.h"
Aura::Aura(NPCType *type_data, Mob *owner, AuraRecord &record)
: NPC(type_data, 0, owner->GetPosition(), FlyMode3), spell_id(record.spell_id), distance(record.distance),
: NPC(type_data, 0, owner->GetPosition(), GravityBehavior::Flying), spell_id(record.spell_id), distance(record.distance),
remove_timer(record.duration), movement_timer(100), process_timer(100), aura_id(-1)
{
GiveNPCTypeData(type_data); // we will delete this later on
-4
View File
@@ -52,10 +52,6 @@ void Mob::CalcBonuses()
We set this here because NPC's can cast spells to change walkspeed/runspeed
*/
float get_walk_speed = static_cast<float>(0.025f * this->GetWalkspeed());
if (get_walk_speed >= 0.9 && this->fix_z_timer.GetDuration() != 100) {
this->fix_z_timer.SetTimer(100);
}
rooted = FindType(SE_Root);
}
+57 -81
View File
@@ -29,7 +29,7 @@
extern volatile bool is_zone_loaded;
// This constructor is used during the bot create command
Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm::vec4(), 0, false), rest_timer(1) {
Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm::vec4(), Ground, false), rest_timer(1) {
if(botOwner) {
this->SetBotOwner(botOwner);
this->_botOwnerCharacterID = botOwner->CharacterID();
@@ -39,6 +39,7 @@ Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm
}
m_inv.SetInventoryVersion(EQEmu::versions::MobVersion::Bot);
m_inv.SetGMInventory(false); // bot expansions are not currently implemented (defaults to static)
_guildRank = 0;
_guildId = 0;
@@ -89,7 +90,7 @@ Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm
GenerateAppearance();
GenerateBaseStats();
// Calculate HitPoints Last As It Uses Base Stats
cur_hp = GenerateBaseHitPoints();
current_hp = GenerateBaseHitPoints();
current_mana = GenerateBaseManaPoints();
cur_end = CalcBaseEndurance();
hp_regen = CalcHPRegen();
@@ -103,7 +104,8 @@ Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm
}
// This constructor is used when the bot is loaded out of the database
Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double totalPlayTime, uint32 lastZoneId, NPCType npcTypeData) : NPC(&npcTypeData, nullptr, glm::vec4(), 0, false), rest_timer(1)
Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double totalPlayTime, uint32 lastZoneId, NPCType npcTypeData)
: NPC(&npcTypeData, nullptr, glm::vec4(), Ground, false), rest_timer(1)
{
this->_botOwnerCharacterID = botOwnerCharacterID;
if(this->_botOwnerCharacterID > 0)
@@ -112,6 +114,7 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
auto bot_owner = GetBotOwner();
m_inv.SetInventoryVersion(EQEmu::versions::MobVersion::Bot);
m_inv.SetGMInventory(false); // bot expansions are not currently implemented (defaults to static)
_guildRank = 0;
_guildId = 0;
@@ -136,7 +139,7 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
_baseATK = npcTypeData.ATK;
_baseRace = npcTypeData.race;
_baseGender = npcTypeData.gender;
cur_hp = npcTypeData.cur_hp;
current_hp = npcTypeData.current_hp;
current_mana = npcTypeData.Mana;
RestRegenHP = 0;
RestRegenMana = 0;
@@ -208,10 +211,10 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
hp_regen = CalcHPRegen();
mana_regen = CalcManaRegen();
end_regen = CalcEnduranceRegen();
if(cur_hp > max_hp)
cur_hp = max_hp;
if(current_hp > max_hp)
current_hp = max_hp;
if(cur_hp <= 0) {
if(current_hp <= 0) {
SetHP(max_hp/5);
SetMana(0);
BuffFadeAll();
@@ -284,8 +287,7 @@ void Bot::ChangeBotArcherWeapons(bool isArcher) {
void Bot::Sit() {
if(IsMoving()) {
moved = false;
SetCurrentSpeed(0);
tar_ndx = 0;
StopNavigation();
}
SetAppearance(eaSitting);
@@ -336,7 +338,7 @@ NPCType Bot::FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::str
BotNPCType.drakkin_heritage = drakkinHeritage;
BotNPCType.drakkin_tattoo = drakkinTattoo;
BotNPCType.drakkin_details = drakkinDetails;
BotNPCType.cur_hp = hp;
BotNPCType.current_hp = hp;
BotNPCType.Mana = mana;
BotNPCType.MR = mr;
BotNPCType.CR = cr;
@@ -386,7 +388,7 @@ NPCType Bot::CreateDefaultNPCTypeStructForBot(std::string botName, std::string b
Result.maxlevel = botLevel;
Result.size = 6.0;
Result.npc_id = 0;
Result.cur_hp = 0;
Result.current_hp = 0;
Result.drakkin_details = 0;
Result.drakkin_heritage = 0;
Result.drakkin_tattoo = 0;
@@ -1827,7 +1829,6 @@ bool Bot::Process() {
if(tic_timer.Check()) {
//6 seconds, or whatever the rule is set to has passed, send this position to everyone to avoid ghosting
if(!IsMoving() && !IsEngaged()) {
SendPosition();
if(IsSitting()) {
if(!rest_timer.Enabled())
rest_timer.Start(RuleI(Character, RestRegenTimeToActivate) * 1000);
@@ -2526,7 +2527,7 @@ void Bot::AI_Process() {
if (GetArchetype() == ARCHETYPE_CASTER || GetClass() == ROGUE) {
if (tar_distance <= melee_distance_max) {
if (PlotPositionAroundTarget(this, Goal.x, Goal.y, Goal.z)) {
CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetBotWalkspeed(), true, false);
WalkTo(Goal.x, Goal.y, Goal.z);
return;
}
}
@@ -2538,7 +2539,7 @@ void Bot::AI_Process() {
if (caster_distance_min && tar_distance < caster_distance_min && !tar->IsFeared()) { // Caster back-off adjustment
if (PlotPositionAroundTarget(this, Goal.x, Goal.y, Goal.z)) {
if (DistanceSquared(Goal, tar->GetPosition()) <= caster_distance_max) {
CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetBotWalkspeed(), true, false);
WalkTo(Goal.x, Goal.y, Goal.z);
return;
}
}
@@ -2546,7 +2547,7 @@ void Bot::AI_Process() {
else if (tar_distance < melee_distance_min) { // Melee back-off adjustment
if (PlotPositionAroundTarget(this, Goal.x, Goal.y, Goal.z)) {
if (DistanceSquared(Goal, tar->GetPosition()) <= melee_distance_max) {
CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetBotWalkspeed(), true, false);
WalkTo(Goal.x, Goal.y, Goal.z);
return;
}
}
@@ -2554,7 +2555,7 @@ void Bot::AI_Process() {
else if (backstab_weapon && !behind_mob) { // Move the rogue to behind the mob
if (PlotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z)) {
if (DistanceSquared(Goal, tar->GetPosition()) <= melee_distance_max) {
CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetBotRunspeed(), true, false); // rogues are agile enough to run in melee range
RunTo(Goal.x, Goal.y, Goal.z);
return;
}
}
@@ -2565,7 +2566,7 @@ void Bot::AI_Process() {
PlotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z)) // If we're behind the mob, we can attack when it's enraged
{
if (DistanceSquared(Goal, tar->GetPosition()) <= melee_distance_max) {
CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetBotWalkspeed(), true, false);
WalkTo(Goal.x, Goal.y, Goal.z);
return;
}
}
@@ -2710,35 +2711,19 @@ void Bot::AI_Process() {
Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName());
Goal = GetTarget()->GetPosition();
if (RuleB(Bots, UsePathing) && zone->pathing) {
bool WaypointChanged, NodeReached;
Goal = UpdatePath(Goal.x, Goal.y, Goal.z,
GetBotRunspeed(), WaypointChanged, NodeReached);
if (WaypointChanged)
tar_ndx = 20;
}
CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetBotRunspeed());
RunTo(Goal.x, Goal.y, Goal.z);
return;
}
else {
if (IsMoving())
StopMoving();
else
SendPosition();
return;
}
}
// Fix Z when following during pull, not when engaged and stationary
if (IsMoving() && fix_z_timer_engaged.Check()) {
FixZ();
return;
}
if (GetTarget() && GetTarget()->IsFeared() && !spellend_timer.Enabled() && AI_think_timer->Check()) {
if (!IsFacingMob(GetTarget()))
@@ -2753,8 +2738,6 @@ void Bot::AI_Process() {
} // end not in combat range
if (!IsMoving() && !spellend_timer.Enabled()) { // This may actually need work...
SendPosition();
if (GetBotStance() == BotStancePassive)
return;
@@ -2789,10 +2772,10 @@ void Bot::AI_Process() {
if (IsMoving())
StopMoving();
Warp(glm::vec3(my_guard));
Teleport(my_guard);
if (HasPet())
GetPet()->Warp(glm::vec3(my_guard));
GetPet()->Teleport(my_guard);
return;
}
@@ -2802,10 +2785,10 @@ void Bot::AI_Process() {
if (IsMoving())
StopMoving();
Warp(glm::vec3(leash_owner->GetPosition()));
Teleport(leash_owner->GetPosition());
if (HasPet())
GetPet()->Warp(glm::vec3(leash_owner->GetPosition()));
GetPet()->Teleport(leash_owner->GetPosition());
return;
}
@@ -2833,23 +2816,18 @@ void Bot::AI_Process() {
if (rest_timer.Enabled())
rest_timer.Disable();
int speed = GetBotRunspeed();
bool running = true;
if (fm_dist < GetFollowDistance() + BOT_FOLLOW_DISTANCE_WALK)
speed = GetBotWalkspeed();
running = false;
Goal = follow_mob->GetPosition();
if (RuleB(Bots, UsePathing) && zone->pathing) {
bool WaypointChanged, NodeReached;
Goal = UpdatePath(Goal.x, Goal.y, Goal.z,
speed, WaypointChanged, NodeReached);
if (WaypointChanged)
tar_ndx = 20;
if (running) {
RunTo(Goal.x, Goal.y, Goal.z);
}
else {
WalkTo(Goal.x, Goal.y, Goal.z);
}
CalculateNewPosition(Goal.x, Goal.y, Goal.z, speed);
return;
}
}
@@ -2931,14 +2909,14 @@ void Bot::PetAIProcess() {
if(botPet->GetClass() == ROGUE && !petHasAggro && !botPet->BehindMob(botPet->GetTarget(), botPet->GetX(), botPet->GetY())) {
// Move the rogue to behind the mob
if(botPet->PlotPositionAroundTarget(botPet->GetTarget(), newX, newY, newZ)) {
botPet->CalculateNewPosition(newX, newY, newZ, botPet->GetRunspeed());
botPet->RunTo(newX, newY, newZ);
return;
}
}
else if(GetTarget() == botPet->GetTarget() && !petHasAggro && !botPet->BehindMob(botPet->GetTarget(), botPet->GetX(), botPet->GetY())) {
// If the bot owner and the bot are fighting the same mob, then move the pet to the rear arc of the mob
if(botPet->PlotPositionAroundTarget(botPet->GetTarget(), newX, newY, newZ)) {
botPet->CalculateNewPosition(newX, newY, newZ, botPet->GetRunspeed());
botPet->RunTo(newX, newY, newZ);
return;
}
}
@@ -2953,7 +2931,7 @@ void Bot::PetAIProcess() {
moveBehindMob = true;
if(botPet->PlotPositionAroundTarget(botPet->GetTarget(), newX, newY, newZ, moveBehindMob)) {
botPet->CalculateNewPosition(newX, newY, newZ, botPet->GetRunspeed());
botPet->RunTo(newX, newY, newZ);
return;
}
}
@@ -3036,15 +3014,14 @@ void Bot::PetAIProcess() {
botPet->SetRunAnimSpeed(0);
if(!botPet->IsRooted()) {
Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", botPet->GetTarget()->GetCleanName());
botPet->CalculateNewPosition(botPet->GetTarget()->GetX(), botPet->GetTarget()->GetY(), botPet->GetTarget()->GetZ(), botPet->GetOwner()->GetRunspeed());
botPet->RunTo(botPet->GetTarget()->GetX(), botPet->GetTarget()->GetY(), botPet->GetTarget()->GetZ());
return;
} else {
botPet->SetHeading(botPet->GetTarget()->GetHeading());
if(moved) {
moved = false;
SetCurrentSpeed(0);
botPet->SendPosition();
botPet->SetMoving(false);
StopNavigation();
botPet->StopNavigation();
}
}
}
@@ -3064,15 +3041,14 @@ void Bot::PetAIProcess() {
float dist = DistanceSquared(botPet->GetPosition(), botPet->GetTarget()->GetPosition());
botPet->SetRunAnimSpeed(0);
if(dist > 184) {
botPet->CalculateNewPosition(botPet->GetTarget()->GetX(), botPet->GetTarget()->GetY(), botPet->GetTarget()->GetZ(), botPet->GetTarget()->GetRunspeed());
botPet->RunTo(botPet->GetTarget()->GetX(), botPet->GetTarget()->GetY(), botPet->GetTarget()->GetZ());
return;
} else {
botPet->SetHeading(botPet->GetTarget()->GetHeading());
if(moved) {
moved = false;
SetCurrentSpeed(0);
botPet->SendPosition();
botPet->SetMoving(false);
StopNavigation();
botPet->StopNavigation();
}
}
break;
@@ -3134,7 +3110,7 @@ bool Bot::Spawn(Client* botCharacterOwner) {
entity_list.AddBot(this, true, true);
// Load pet
LoadPet();
this->SendPosition();
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
// there is something askew with spawn struct appearance fields...
// I re-enabled this until I can sort it out
uint32 itemID = 0;
@@ -5173,7 +5149,7 @@ int Bot::GetHandToHandDamage(void) {
// everyone uses this in the revamp!
int skill = GetSkill(EQEmu::skills::SkillHandtoHand);
int epic = 0;
if (CastToNPC()->GetEquipment(EQEmu::textures::armorHands) == 10652 && GetLevel() > 46)
if (CastToNPC()->GetEquippedItemFromTextureSlot(EQEmu::textures::armorHands) == 10652 && GetLevel() > 46)
epic = 280;
if (epic > skill)
skill = epic;
@@ -5195,7 +5171,7 @@ int Bot::GetHandToHandDamage(void) {
9, 9, 9, 9, 9, 10, 10, 10, 10, 10, // 31-40
10, 11, 11, 11, 11, 11, 11, 12, 12}; // 41-49
if (GetClass() == MONK) {
if (CastToNPC()->GetEquipment(EQEmu::textures::armorHands) == 10652 && GetLevel() > 50)
if (CastToNPC()->GetEquippedItemFromTextureSlot(EQEmu::textures::armorHands) == 10652 && GetLevel() > 50)
return 9;
if (level > 62)
return 15;
@@ -6287,7 +6263,7 @@ void Bot::DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster) {
Mob::DoBuffTic(buff, slot, caster);
}
bool Bot::CastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot, int32 cast_time, int32 mana_cost,
bool Bot::CastSpell(uint16 spell_id, uint16 target_id, EQEmu::spells::CastingSlot slot, int32 cast_time, int32 mana_cost,
uint32* oSpellWillFinish, uint32 item_slot, int16 *resist_adjust, uint32 aa_id) {
bool Result = false;
if(zone && !zone->IsSpellBlocked(spell_id, glm::vec3(GetPosition()))) {
@@ -6327,7 +6303,7 @@ bool Bot::CastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot,
return false;
}
if(slot < EQEmu::CastingSlot::MaxGems && !CheckFizzle(spell_id)) {
if(slot < EQEmu::spells::CastingSlot::MaxGems && !CheckFizzle(spell_id)) {
int fizzle_msg = IsBardSong(spell_id) ? MISS_NOTE : SPELL_FIZZLE;
InterruptSpell(fizzle_msg, 0x121, spell_id);
@@ -6341,7 +6317,7 @@ bool Bot::CastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot,
Log(Logs::Detail, Logs::Spells, "Casting a new spell/song while singing a song. Killing old song %d.", bardsong);
bardsong = 0;
bardsong_target_id = 0;
bardsong_slot = EQEmu::CastingSlot::Gem1;
bardsong_slot = EQEmu::spells::CastingSlot::Gem1;
bardsong_timer.Disable();
}
@@ -6471,7 +6447,7 @@ bool Bot::IsImmuneToSpell(uint16 spell_id, Mob *caster) {
return Result;
}
bool Bot::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, EQEmu::CastingSlot slot) {
bool Bot::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, EQEmu::spells::CastingSlot slot) {
bool Result = false;
SpellTargetType targetType = spells[spell_id].targettype;
if(targetType == ST_GroupClientAndPet) {
@@ -6484,7 +6460,7 @@ bool Bot::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
return Result;
}
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 Bot::DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::spells::CastingSlot slot, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot, uint32 aa_id) {
bool Result = false;
if(GetClass() == BARD)
cast_time = 0;
@@ -6588,7 +6564,7 @@ void Bot::GenerateSpecialAttacks() {
SetSpecialAbility(SPECATK_TRIPLE, 1);
}
bool Bot::DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool& stopLogic) {
bool Bot::DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQEmu::spells::CastingSlot slot, bool& stopLogic) {
if(GetClass() == BARD) {
if(!ApplyNextBardPulse(bardsong, this, bardsong_slot))
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
@@ -6598,7 +6574,7 @@ bool Bot::DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQEmu::Cast
return true;
}
bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool& stopLogic) {
bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQEmu::spells::CastingSlot slot, bool& stopLogic) {
if(spellTarget) {
if(IsGrouped() && (spellTarget->IsBot() || spellTarget->IsClient()) && RuleB(Bots, GroupBuffing)) {
bool noGroupSpell = false;
@@ -6610,7 +6586,7 @@ bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQEmu::
bool spelltypeequal = ((spelltype == 2) || (spelltype == 16) || (spelltype == 32));
bool spelltypetargetequal = ((spelltype == 8) && (spells[thespell].targettype == ST_Self));
bool spelltypeclassequal = ((spelltype == 1024) && (GetClass() == SHAMAN));
bool slotequal = (slot == EQEmu::CastingSlot::Item);
bool slotequal = (slot == EQEmu::spells::CastingSlot::Item);
if(spellequal || slotequal) {
if((spelltypeequal || spelltypetargetequal) || spelltypeclassequal || slotequal) {
if(((spells[thespell].effectid[0] == 0) && (spells[thespell].base[0] < 0)) &&
@@ -6649,7 +6625,7 @@ bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQEmu::
return true;
}
bool Bot::DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool& stopLogic) {
bool Bot::DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::spells::CastingSlot slot, bool& stopLogic) {
bool isMainGroupMGB = false;
if(isMainGroupMGB && (GetClass() != BARD)) {
BotGroupSay(this, "MGB %s", spells[spell_id].name);
@@ -7185,14 +7161,14 @@ int32 Bot::CalcMaxHP() {
bot_hp += GroupLeadershipAAHealthEnhancement();
bot_hp += (bot_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f));
max_hp = bot_hp;
if (cur_hp > max_hp)
cur_hp = max_hp;
if (current_hp > max_hp)
current_hp = max_hp;
int hp_perc_cap = spellbonuses.HPPercCap[0];
if(hp_perc_cap) {
int curHP_cap = ((max_hp * hp_perc_cap) / 100);
if (cur_hp > curHP_cap || (spellbonuses.HPPercCap[1] && cur_hp > spellbonuses.HPPercCap[1]))
cur_hp = curHP_cap;
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[1] && current_hp > spellbonuses.HPPercCap[1]))
current_hp = curHP_cap;
}
return max_hp;
}
@@ -8732,7 +8708,7 @@ bool Bot::UseDiscipline(uint32 spell_id, uint32 target) {
if(IsCasting())
InterruptSpell();
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline);
CastSpell(spell_id, target, EQEmu::spells::CastingSlot::Discipline);
return true;
}
+6 -6
View File
@@ -322,9 +322,9 @@ public:
virtual void SetAttackTimer();
uint32 GetClassHPFactor();
virtual int32 CalcMaxHP();
bool DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic);
bool DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic);
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic);
bool DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQEmu::spells::CastingSlot slot, bool &stopLogic);
bool DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQEmu::spells::CastingSlot slot, bool &stopLogic);
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::spells::CastingSlot slot, bool &stopLogic);
void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color);
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, bool pet_command = false);
@@ -425,12 +425,12 @@ public:
virtual float GetAOERange(uint16 spell_id);
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100);
virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr);
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,
virtual bool CastSpell(uint16 spell_id, uint16 target_id, EQEmu::spells::CastingSlot slot = EQEmu::spells::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0,
uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr, uint32 aa_id = 0);
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar);
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
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, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, uint32 aa_id = 0);
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, EQEmu::spells::CastingSlot slot);
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::spells::CastingSlot slot = EQEmu::spells::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
void BotTradeSwapItem(Client* client, int16 lootSlot, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* inst_swap, uint32 equipableSlots, std::string* errorMessage, bool swap = true);
+3 -3
View File
@@ -5273,7 +5273,7 @@ void bot_subcommand_bot_summon(Client *c, const Seperator *sep)
bot_iter->WipeHateList();
bot_iter->SetTarget(nullptr);
bot_iter->Warp(glm::vec3(c->GetPosition()));
bot_iter->Teleport(c->GetPosition());
bot_iter->DoAnim(0);
if (!bot_iter->HasPet())
@@ -5281,7 +5281,7 @@ void bot_subcommand_bot_summon(Client *c, const Seperator *sep)
bot_iter->GetPet()->WipeHateList();
bot_iter->GetPet()->SetTarget(nullptr);
bot_iter->GetPet()->Warp(glm::vec3(c->GetPosition()));
bot_iter->GetPet()->Teleport(c->GetPosition());
}
if (sbl.size() == 1)
@@ -7774,7 +7774,7 @@ bool helper_cast_standard_spell(Bot* casting_bot, Mob* target_mob, int spell_id,
if (annouce_cast)
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(), EQEmu::CastingSlot::Gem2, -1, -1, dont_root_before);
return casting_bot->CastSpell(spell_id, target_mob->GetID(), EQEmu::spells::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)
+127 -355
View File
@@ -54,6 +54,7 @@ extern volatile bool RunLoops;
#include "guild_mgr.h"
#include "quest_parser_collection.h"
#include "queryserv.h"
#include "mob_movement_manager.h"
extern QueryServ* QServ;
extern EntityList entity_list;
@@ -119,7 +120,6 @@ Client::Client(EQStreamInterface* ieqs)
0,
0
),
position_timer(250),
hpupdate_timer(2000),
camp_timer(29000),
process_timer(100),
@@ -167,6 +167,7 @@ Client::Client(EQStreamInterface* ieqs)
for (int client_filter = 0; client_filter < _FilterCount; client_filter++)
ClientFilters[client_filter] = FilterShow;
mMovementManager->AddClient(this);
character_id = 0;
conn_state = NoPacketsReceived;
client_data_loaded = false;
@@ -221,7 +222,6 @@ Client::Client(EQStreamInterface* ieqs)
npcflag = false;
npclevel = 0;
pQueuedSaveWorkID = 0;
position_timer_counter = 0;
position_update_same_count = 0;
fishing_timer.Disable();
shield_timer.Disable();
@@ -287,14 +287,6 @@ Client::Client(EQStreamInterface* ieqs)
XPRate = 100;
current_endurance = 0;
m_TimeSinceLastPositionCheck = 0;
m_DistanceSinceLastPositionCheck = 0.0f;
m_ShadowStepExemption = 0;
m_KnockBackExemption = 0;
m_PortExemption = 0;
m_SenseExemption = 0;
m_AssistExemption = 0;
m_CheatDetectMoved = false;
CanUseReport = true;
aa_los_them_mob = nullptr;
los_status = false;
@@ -359,6 +351,8 @@ Client::Client(EQStreamInterface* ieqs)
}
Client::~Client() {
mMovementManager->RemoveClient(this);
#ifdef BOTS
Bot::ProcessBotOwnerRefDelete(this);
#endif
@@ -1135,7 +1129,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
CheckLDoNHail(GetTarget());
CheckEmoteHail(GetTarget(), message);
if(DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= RuleI(Range, Say)) {
if(DistanceNoZ(m_Position, GetTarget()->GetPosition()) <= RuleI(Range, Say)) {
NPC *tar = GetTarget()->CastToNPC();
parse->EventNPC(EVENT_SAY, tar->CastToNPC(), this, message, language);
@@ -1905,9 +1899,9 @@ void Client::CheckManaEndUpdate() {
mana_update->cur_mana = GetMana();
mana_update->max_mana = GetMaxMana();
mana_update->spawn_id = GetID();
if ((ClientVersionBit() & EQEmu::versions::ClientVersionBit::bit_SoDAndLater) != 0)
if ((ClientVersionBit() & EQEmu::versions::ClientVersionBitmask::maskSoDAndLater) != 0)
QueuePacket(mana_packet); // do we need this with the OP_ManaChange packet above?
entity_list.QueueClientsByXTarget(this, mana_packet, false, EQEmu::versions::ClientVersionBit::bit_SoDAndLater);
entity_list.QueueClientsByXTarget(this, mana_packet, false, EQEmu::versions::ClientVersionBitmask::maskSoDAndLater);
safe_delete(mana_packet);
last_reported_mana_percent = this->GetManaPercent();
@@ -1930,9 +1924,9 @@ void Client::CheckManaEndUpdate() {
endurance_update->cur_end = GetEndurance();
endurance_update->max_end = GetMaxEndurance();
endurance_update->spawn_id = GetID();
if ((ClientVersionBit() & EQEmu::versions::ClientVersionBit::bit_SoDAndLater) != 0)
if ((ClientVersionBit() & EQEmu::versions::ClientVersionBitmask::maskSoDAndLater) != 0)
QueuePacket(endurance_packet); // do we need this with the OP_ManaChange packet above?
entity_list.QueueClientsByXTarget(this, endurance_packet, false, EQEmu::versions::ClientVersionBit::bit_SoDAndLater);
entity_list.QueueClientsByXTarget(this, endurance_packet, false, EQEmu::versions::ClientVersionBitmask::maskSoDAndLater);
safe_delete(endurance_packet);
last_reported_endurance_percent = this->GetEndurancePercent();
@@ -2083,6 +2077,7 @@ bool Client::ChangeFirstName(const char* in_firstname, const char* gmname)
void Client::SetGM(bool toggle) {
m_pp.gm = toggle ? 1 : 0;
m_inv.SetGMInventory((bool)m_pp.gm);
Message(13, "You are %s a GM.", m_pp.gm ? "now" : "no longer");
SendAppearancePacket(AT_GM, m_pp.gm);
Save();
@@ -2971,13 +2966,12 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
return true;
}
void Client::SetMaterial(int16 in_slot, uint32 item_id) {
const EQEmu::ItemData* item = database.GetItem(item_id);
if (item && item->IsClassCommon())
{
void Client::SetMaterial(int16 in_slot, uint32 item_id)
{
const EQEmu::ItemData *item = database.GetItem(item_id);
if (item && item->IsClassCommon()) {
uint8 matslot = EQEmu::InventoryProfile::CalcMaterialFromSlot(in_slot);
if (matslot != EQEmu::textures::materialInvalid)
{
if (matslot != EQEmu::textures::materialInvalid) {
m_pp.item_material.Slot[matslot].Material = GetEquipmentMaterial(matslot);
}
}
@@ -3061,7 +3055,7 @@ void Client::ServerFilter(SetServerFilter_Struct* filter){
Filter0(FilterMissedMe);
Filter1(FilterDamageShields);
if (ClientVersionBit() & EQEmu::versions::bit_SoDAndLater) {
if (ClientVersionBit() & EQEmu::versions::maskSoDAndLater) {
if (filter->filters[FilterDOT] == 0)
ClientFilters[FilterDOT] = FilterShow;
else if (filter->filters[FilterDOT] == 1)
@@ -3082,7 +3076,7 @@ void Client::ServerFilter(SetServerFilter_Struct* filter){
Filter1(FilterFocusEffects);
Filter1(FilterPetSpells);
if (ClientVersionBit() & EQEmu::versions::bit_SoDAndLater) {
if (ClientVersionBit() & EQEmu::versions::maskSoDAndLater) {
if (filter->filters[FilterHealOverTime] == 0)
ClientFilters[FilterHealOverTime] = FilterShow;
// This is called 'Show Mine Only' in the clients, but functions the same as show
@@ -4956,7 +4950,7 @@ void Client::HandleLDoNOpen(NPC *target)
if(target->GetLDoNTrapSpellID() != 0)
{
Message_StringID(13, LDON_ACCIDENT_SETOFF2);
target->SpellFinished(target->GetLDoNTrapSpellID(), this, EQEmu::CastingSlot::Item, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff);
target->SpellFinished(target->GetLDoNTrapSpellID(), this, EQEmu::spells::CastingSlot::Item, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff);
target->SetLDoNTrapSpellID(0);
target->SetLDoNTrapped(false);
target->SetLDoNTrapDetected(false);
@@ -5078,7 +5072,7 @@ void Client::HandleLDoNDisarm(NPC *target, uint16 skill, uint8 type)
break;
case -1:
Message_StringID(13, LDON_ACCIDENT_SETOFF2);
target->SpellFinished(target->GetLDoNTrapSpellID(), this, EQEmu::CastingSlot::Item, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff);
target->SpellFinished(target->GetLDoNTrapSpellID(), this, EQEmu::spells::CastingSlot::Item, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff);
target->SetLDoNTrapSpellID(0);
target->SetLDoNTrapped(false);
target->SetLDoNTrapDetected(false);
@@ -5097,7 +5091,7 @@ void Client::HandleLDoNPickLock(NPC *target, uint16 skill, uint8 type)
if(target->IsLDoNTrapped())
{
Message_StringID(13, LDON_ACCIDENT_SETOFF2);
target->SpellFinished(target->GetLDoNTrapSpellID(), this, EQEmu::CastingSlot::Item, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff);
target->SpellFinished(target->GetLDoNTrapSpellID(), this, EQEmu::spells::CastingSlot::Item, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff);
target->SetLDoNTrapSpellID(0);
target->SetLDoNTrapped(false);
target->SetLDoNTrapDetected(false);
@@ -5330,177 +5324,6 @@ void Client::ShowSkillsWindow()
this->SendPopupToClient(WindowTitle, WindowText.c_str());
}
void Client::SetShadowStepExemption(bool v)
{
if(v == true)
{
uint32 cur_time = Timer::GetCurrentTime();
if((cur_time - m_TimeSinceLastPositionCheck) > 1000)
{
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
int runs = GetRunspeed();
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
{
printf("%s %i moving too fast! moved: %.2f in %ims, speed %.2f\n", __FILE__, __LINE__,
m_DistanceSinceLastPositionCheck, (cur_time - m_TimeSinceLastPositionCheck), speed);
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
{
if(IsShadowStepExempted())
{
if(m_DistanceSinceLastPositionCheck > 800)
{
CheatDetected(MQWarpShadowStep, GetX(), GetY(), GetZ());
}
}
else if(IsKnockBackExempted())
{
//still potential to trigger this if you're knocked back off a
//HUGE fall that takes > 2.5 seconds
if(speed > 30.0f)
{
CheatDetected(MQWarpKnockBack, GetX(), GetY(), GetZ());
}
}
else if(!IsPortExempted())
{
if(!IsMQExemptedArea(zone->GetZoneID(), GetX(), GetY(), GetZ()))
{
if(speed > (runs * 2 * RuleR(Zone, MQWarpDetectionDistanceFactor)))
{
CheatDetected(MQWarp, GetX(), GetY(), GetZ());
m_TimeSinceLastPositionCheck = cur_time;
m_DistanceSinceLastPositionCheck = 0.0f;
//Death(this, 10000000, SPELL_UNKNOWN, _1H_BLUNT);
}
else
{
CheatDetected(MQWarpLight, GetX(), GetY(), GetZ());
}
}
}
}
}
}
m_TimeSinceLastPositionCheck = cur_time;
m_DistanceSinceLastPositionCheck = 0.0f;
}
m_ShadowStepExemption = v;
}
void Client::SetKnockBackExemption(bool v)
{
if(v == true)
{
uint32 cur_time = Timer::GetCurrentTime();
if((cur_time - m_TimeSinceLastPositionCheck) > 1000)
{
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
int runs = GetRunspeed();
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
{
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
{
printf("%s %i moving too fast! moved: %.2f in %ims, speed %.2f\n", __FILE__, __LINE__,
m_DistanceSinceLastPositionCheck, (cur_time - m_TimeSinceLastPositionCheck), speed);
if(IsShadowStepExempted())
{
if(m_DistanceSinceLastPositionCheck > 800)
{
CheatDetected(MQWarpShadowStep, GetX(), GetY(), GetZ());
}
}
else if(IsKnockBackExempted())
{
//still potential to trigger this if you're knocked back off a
//HUGE fall that takes > 2.5 seconds
if(speed > 30.0f)
{
CheatDetected(MQWarpKnockBack, GetX(), GetY(), GetZ());
}
}
else if(!IsPortExempted())
{
if(!IsMQExemptedArea(zone->GetZoneID(), GetX(), GetY(), GetZ()))
{
if(speed > (runs * 2 * RuleR(Zone, MQWarpDetectionDistanceFactor)))
{
m_TimeSinceLastPositionCheck = cur_time;
m_DistanceSinceLastPositionCheck = 0.0f;
CheatDetected(MQWarp, GetX(), GetY(), GetZ());
//Death(this, 10000000, SPELL_UNKNOWN, _1H_BLUNT);
}
else
{
CheatDetected(MQWarpLight, GetX(), GetY(), GetZ());
}
}
}
}
}
}
m_TimeSinceLastPositionCheck = cur_time;
m_DistanceSinceLastPositionCheck = 0.0f;
}
m_KnockBackExemption = v;
}
void Client::SetPortExemption(bool v)
{
if(v == true)
{
uint32 cur_time = Timer::GetCurrentTime();
if((cur_time - m_TimeSinceLastPositionCheck) > 1000)
{
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
int runs = GetRunspeed();
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
{
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
{
printf("%s %i moving too fast! moved: %.2f in %ims, speed %.2f\n", __FILE__, __LINE__,
m_DistanceSinceLastPositionCheck, (cur_time - m_TimeSinceLastPositionCheck), speed);
if(IsShadowStepExempted())
{
if(m_DistanceSinceLastPositionCheck > 800)
{
CheatDetected(MQWarpShadowStep, GetX(), GetY(), GetZ());
}
}
else if(IsKnockBackExempted())
{
//still potential to trigger this if you're knocked back off a
//HUGE fall that takes > 2.5 seconds
if(speed > 30.0f)
{
CheatDetected(MQWarpKnockBack, GetX(), GetY(), GetZ());
}
}
else if(!IsPortExempted())
{
if(!IsMQExemptedArea(zone->GetZoneID(), GetX(), GetY(), GetZ()))
{
if(speed > (runs * 2 * RuleR(Zone, MQWarpDetectionDistanceFactor)))
{
m_TimeSinceLastPositionCheck = cur_time;
m_DistanceSinceLastPositionCheck = 0.0f;
CheatDetected(MQWarp, GetX(), GetY(), GetZ());
//Death(this, 10000000, SPELL_UNKNOWN, _1H_BLUNT);
}
else
{
CheatDetected(MQWarpLight, GetX(), GetY(), GetZ());
}
}
}
}
}
}
m_TimeSinceLastPositionCheck = cur_time;
m_DistanceSinceLastPositionCheck = 0.0f;
}
m_PortExemption = v;
}
void Client::Signal(uint32 data)
{
char buf[32];
@@ -5509,158 +5332,6 @@ void Client::Signal(uint32 data)
parse->EventPlayer(EVENT_SIGNAL, this, buf, 0);
}
const bool Client::IsMQExemptedArea(uint32 zoneID, float x, float y, float z) const
{
float max_dist = 90000;
switch(zoneID)
{
case 2:
{
float delta = (x-(-713.6));
delta *= delta;
float distance = delta;
delta = (y-(-160.2));
delta *= delta;
distance += delta;
delta = (z-(-12.8));
delta *= delta;
distance += delta;
if(distance < max_dist)
return true;
delta = (x-(-153.8));
delta *= delta;
distance = delta;
delta = (y-(-30.3));
delta *= delta;
distance += delta;
delta = (z-(8.2));
delta *= delta;
distance += delta;
if(distance < max_dist)
return true;
break;
}
case 9:
{
float delta = (x-(-682.5));
delta *= delta;
float distance = delta;
delta = (y-(147.0));
delta *= delta;
distance += delta;
delta = (z-(-9.9));
delta *= delta;
distance += delta;
if(distance < max_dist)
return true;
delta = (x-(-655.4));
delta *= delta;
distance = delta;
delta = (y-(10.5));
delta *= delta;
distance += delta;
delta = (z-(-51.8));
delta *= delta;
distance += delta;
if(distance < max_dist)
return true;
break;
}
case 62:
case 75:
case 114:
case 209:
{
//The portals are so common in paineel/felwitheb that checking
//distances wouldn't be worth it cause unless you're porting to the
//start field you're going to be triggering this and that's a level of
//accuracy I'm willing to sacrifice
return true;
break;
}
case 24:
{
float delta = (x-(-183.0));
delta *= delta;
float distance = delta;
delta = (y-(-773.3));
delta *= delta;
distance += delta;
delta = (z-(54.1));
delta *= delta;
distance += delta;
if(distance < max_dist)
return true;
delta = (x-(-8.8));
delta *= delta;
distance = delta;
delta = (y-(-394.1));
delta *= delta;
distance += delta;
delta = (z-(41.1));
delta *= delta;
distance += delta;
if(distance < max_dist)
return true;
delta = (x-(-310.3));
delta *= delta;
distance = delta;
delta = (y-(-1411.6));
delta *= delta;
distance += delta;
delta = (z-(-42.8));
delta *= delta;
distance += delta;
if(distance < max_dist)
return true;
delta = (x-(-183.1));
delta *= delta;
distance = delta;
delta = (y-(-1409.8));
delta *= delta;
distance += delta;
delta = (z-(37.1));
delta *= delta;
distance += delta;
if(distance < max_dist)
return true;
break;
}
case 110:
case 34:
case 96:
case 93:
case 68:
case 84:
{
if(GetBoatID() != 0)
return true;
break;
}
default:
break;
}
return false;
}
void Client::SendRewards()
{
std::vector<ClientReward> rewards;
@@ -5952,7 +5623,7 @@ void Client::SuspendMinion()
memset(&m_suspendedminion, 0, sizeof(struct PetInfo));
// TODO: These pet command states need to be synced ...
// Will just fix them for now
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) {
if (m_ClientVersionBit & EQEmu::versions::maskUFAndLater) {
SetPetCommandState(PET_BUTTON_SIT, 0);
SetPetCommandState(PET_BUTTON_STOP, 0);
SetPetCommandState(PET_BUTTON_REGROUP, 0);
@@ -6493,7 +6164,7 @@ void Client::LocateCorpse()
SetHeading(CalculateHeadingToTarget(ClosestCorpse->GetX(), ClosestCorpse->GetY()));
SetTarget(ClosestCorpse);
SendTargetCommand(ClosestCorpse->GetID());
SendPositionUpdate(2);
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0, true);
}
else if(!GetTarget())
Message_StringID(clientMessageError, SENSE_CORPSE_NONE);
@@ -6658,7 +6329,7 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid
(npc_dup!=nullptr)?npc_dup:npc_type, //make sure we give the NPC the correct data pointer
0,
GetPosition() + glm::vec4(swarmPetLocations[summon_count], 0.0f, 0.0f),
FlyMode3);
GravityBehavior::Water);
if(!swarm_pet_npc->GetSwarmInfo()){
auto nSI = new SwarmPet;
@@ -7961,7 +7632,7 @@ void Client::SendClearMercInfo()
void Client::DuplicateLoreMessage(uint32 ItemID)
{
if (!(m_ClientVersionBit & EQEmu::versions::bit_RoFAndLater))
if (!(m_ClientVersionBit & EQEmu::versions::maskRoFAndLater))
{
Message_StringID(0, PICK_LORE);
return;
@@ -8856,11 +8527,11 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold,
}
void Client::SendHPUpdateMarquee(){
if (!this || !this->IsClient() || !this->cur_hp || !this->max_hp)
if (!this || !this->IsClient() || !this->current_hp || !this->max_hp)
return;
/* Health Update Marquee Display: Custom*/
uint8 health_percentage = (uint8)(this->cur_hp * 100 / this->max_hp);
uint8 health_percentage = (uint8)(this->current_hp * 100 / this->max_hp);
if (health_percentage >= 100)
return;
@@ -9351,7 +9022,108 @@ bool Client::IsDevToolsWindowEnabled() const
return dev_tools_window_enabled;
}
/**
* @param in_dev_tools_window_enabled
*/
void Client::SetDevToolsWindowEnabled(bool in_dev_tools_window_enabled)
{
Client::dev_tools_window_enabled = in_dev_tools_window_enabled;
}
/**
* @param model_id
*/
void Client::SetPrimaryWeaponOrnamentation(uint32 model_id)
{
auto primary_item = m_inv.GetItem(EQEmu::invslot::slotPrimary);
if (primary_item) {
database.QueryDatabase(
StringFormat(
"UPDATE `inventory` SET `ornamentidfile` = %i WHERE `charid` = %i AND `slotid` = %i",
model_id,
character_id,
EQEmu::invslot::slotPrimary
));
primary_item->SetOrnamentationIDFile(model_id);
SendItemPacket(EQEmu::invslot::slotPrimary, primary_item, ItemPacketTrade);
WearChange(EQEmu::textures::weaponPrimary, static_cast<uint16>(model_id), 0);
Message(15, "Your primary weapon appearance has been modified");
}
}
/**
* @param model_id
*/
void Client::SetSecondaryWeaponOrnamentation(uint32 model_id)
{
auto secondary_item = m_inv.GetItem(EQEmu::invslot::slotSecondary);
if (secondary_item) {
database.QueryDatabase(
StringFormat(
"UPDATE `inventory` SET `ornamentidfile` = %i WHERE `charid` = %i AND `slotid` = %i",
model_id,
character_id,
EQEmu::invslot::slotSecondary
));
secondary_item->SetOrnamentationIDFile(model_id);
SendItemPacket(EQEmu::invslot::slotSecondary, secondary_item, ItemPacketTrade);
WearChange(EQEmu::textures::weaponSecondary, static_cast<uint16>(model_id), 0);
Message(15, "Your secondary weapon appearance has been modified");
}
}
/**
* Used in #goto <player_name>
*
* @param player_name
*/
bool Client::GotoPlayer(std::string player_name)
{
std::string query = StringFormat(
"SELECT"
" character_data.zone_id,"
" character_data.zone_instance,"
" character_data.x,"
" character_data.y,"
" character_data.z,"
" character_data.heading "
"FROM"
" character_data "
"WHERE"
" TRUE"
" AND character_data.name = '%s'"
" AND character_data.last_login > (UNIX_TIMESTAMP() - 600) LIMIT 1", player_name.c_str());
auto results = database.QueryDatabase(query);
if (!results.Success()) {
return false;
}
for (auto row = results.begin(); row != results.end(); ++row) {
auto zone_id = static_cast<uint32>(atoi(row[0]));
auto instance_id = static_cast<uint16>(atoi(row[1]));
auto x = static_cast<float>(atof(row[2]));
auto y = static_cast<float>(atof(row[3]));
auto z = static_cast<float>(atof(row[4]));
auto heading = static_cast<float>(atof(row[5]));
if (instance_id > 0 && !database.CheckInstanceExists(instance_id)) {
this->Message(15, "Instance no longer exists...");
return false;
}
if (instance_id > 0) {
database.AddClientToInstance(instance_id, this->CharacterID());
}
this->MovePC(zone_id, instance_id, x, y, z, heading);
return true;
}
return false;
}
+13 -34
View File
@@ -252,6 +252,11 @@ public:
bool IsDevToolsWindowEnabled() const;
void SetDevToolsWindowEnabled(bool dev_tools_window_enabled);
void SetPrimaryWeaponOrnamentation(uint32 model_id);
void SetSecondaryWeaponOrnamentation(uint32 model_id);
bool GotoPlayer(std::string player_name);
//abstract virtual function implementations required by base abstract class
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill);
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
@@ -352,7 +357,7 @@ public:
void SetHideMe(bool hm);
inline uint16 GetPort() const { return port; }
bool IsDead() const { return(dead); }
bool IsUnconscious() const { return ((cur_hp <= 0) ? true : false); }
bool IsUnconscious() const { return ((current_hp <= 0) ? true : false); }
inline bool IsLFP() { return LFP; }
void UpdateLFP();
@@ -554,10 +559,10 @@ public:
virtual int GetCurrentBuffSlots() const;
virtual int GetCurrentSongSlots() const;
virtual int GetCurrentDiscSlots() const { return 1; }
virtual int GetMaxBuffSlots() const { return EQEmu::constants::LongBuffs; }
virtual int GetMaxSongSlots() const { return EQEmu::constants::ShortBuffs; }
virtual int GetMaxDiscSlots() const { return EQEmu::constants::DiscBuffs; }
virtual int GetMaxTotalSlots() const { return EQEmu::constants::TotalBuffs; }
virtual int GetMaxBuffSlots() const { return EQEmu::spells::LONG_BUFFS; }
virtual int GetMaxSongSlots() const { return EQEmu::spells::SHORT_BUFFS; }
virtual int GetMaxDiscSlots() const { return EQEmu::spells::DISC_BUFFS; }
virtual int GetMaxTotalSlots() const { return EQEmu::spells::TOTAL_BUFFS; }
virtual uint32 GetFirstBuffSlot(bool disc, bool song);
virtual uint32 GetLastBuffSlot(bool disc, bool song);
virtual void InitializeBuffSlots();
@@ -798,7 +803,7 @@ public:
#ifdef PACKET_PROFILER
void DumpPacketProfile() { if(eqs) eqs->DumpPacketProfile(); }
#endif
uint32 GetEquipment(uint8 material_slot) const; // returns item id
uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const; // returns item id
uint32 GetEquipmentColor(uint8 material_slot) const;
virtual void UpdateEquipmentLight() { m_Light.Type[EQEmu::lightsource::LightEquipment] = m_inv.FindBrightestLightType(); m_Light.Level[EQEmu::lightsource::LightEquipment] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightEquipment]); }
@@ -968,23 +973,7 @@ public:
void SendRules(Client* client);
std::list<std::string> consent_list;
//Anti-Cheat Stuff
uint32 m_TimeSinceLastPositionCheck;
float m_DistanceSinceLastPositionCheck;
bool m_CheatDetectMoved;
void SetShadowStepExemption(bool v);
void SetKnockBackExemption(bool v);
void SetPortExemption(bool v);
void SetSenseExemption(bool v) { m_SenseExemption = v; }
void SetAssistExemption(bool v) { m_AssistExemption = v; }
const bool IsShadowStepExempted() const { return m_ShadowStepExemption; }
const bool IsKnockBackExempted() const { return m_KnockBackExemption; }
const bool IsPortExempted() const { return m_PortExemption; }
const bool IsSenseExempted() const { return m_SenseExemption; }
const bool IsAssistExempted() const { return m_AssistExemption; }
const bool GetGMSpeed() const { return (gmspeed > 0); }
void CheatDetected(CheatTypes CheatType, float x, float y, float z);
const bool IsMQExemptedArea(uint32 zoneID, float x, float y, float z) const;
bool CanUseReport;
//This is used to later set the buff duration of the spell, in slot to duration.
@@ -1162,7 +1151,6 @@ public:
inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); }
void DragCorpses();
inline void ClearDraggedCorpses() { DraggedCorpses.clear(); }
inline void ResetPositionTimer() { position_timer_counter = 0; }
void SendAltCurrencies();
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0);
@@ -1174,7 +1162,7 @@ public:
void HandleLFGuildResponse(ServerPacket *pack);
void SendLFGuildStatus();
void SendGuildLFGuildStatus();
inline bool XTargettingAvailable() const { return ((m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) && RuleB(Character, EnableXTargetting)); }
inline bool XTargettingAvailable() const { return ((m_ClientVersionBit & EQEmu::versions::maskUFAndLater) && RuleB(Character, EnableXTargetting)); }
inline uint8 GetMaxXTargets() const { return MaxXTargets; }
void SetMaxXTargets(uint8 NewMax);
bool IsXTarget(const Mob *m) const;
@@ -1198,7 +1186,7 @@ public:
bool GroupFollow(Client* inviter);
inline bool GetRunMode() const { return runmode; }
inline bool AggroMeterAvailable() const { return ((m_ClientVersionBit & EQEmu::versions::bit_RoF2AndLater)) && RuleB(Character, EnableAggroMeter); } // RoF untested
inline bool AggroMeterAvailable() const { return ((m_ClientVersionBit & EQEmu::versions::maskRoF2AndLater)) && RuleB(Character, EnableAggroMeter); } // RoF untested
inline void SetAggroMeterLock(int in) { m_aggrometer.set_lock_id(in); }
void ProcessAggroMeter(); // builds packet and sends
@@ -1509,9 +1497,6 @@ private:
WaterRegionType last_region_type;
Timer position_timer;
uint8 position_timer_counter;
// this is used to try to cut back on position update reflections
int position_update_same_count;
@@ -1552,7 +1537,6 @@ private:
Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
glm::vec3 m_Proximity;
glm::vec4 last_major_update_position;
void BulkSendInventoryItems();
@@ -1596,11 +1580,6 @@ private:
int XPRate;
bool m_ShadowStepExemption;
bool m_KnockBackExemption;
bool m_PortExemption;
bool m_SenseExemption;
bool m_AssistExemption;
bool alternate_currency_loaded;
std::map<uint32, uint32> alternate_currency;
std::queue<std::pair<uint32, int32>> alternate_currency_queued_operations;
+5 -5
View File
@@ -325,15 +325,15 @@ int32 Client::CalcMaxHP()
max_hp += spellbonuses.HP + aabonuses.HP;
max_hp += GroupLeadershipAAHealthEnhancement();
max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f);
if (cur_hp > max_hp) {
cur_hp = max_hp;
if (current_hp > max_hp) {
current_hp = max_hp;
}
int hp_perc_cap = spellbonuses.HPPercCap[0];
if (hp_perc_cap) {
int curHP_cap = (max_hp * hp_perc_cap) / 100;
if (cur_hp > curHP_cap || (spellbonuses.HPPercCap[1] && cur_hp > spellbonuses.HPPercCap[1])) {
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[1] && current_hp > spellbonuses.HPPercCap[1])) {
cur_hp = curHP_cap;
current_hp = curHP_cap;
}
}
return max_hp;
@@ -838,7 +838,7 @@ uint32 Client::CalcCurrentWeight()
This is the ONLY instance I have seen where the client is hard coded to particular Item IDs to set a certain property for an item. It is very odd.
*/
// SoD+ client has no weight for coin
if (EQEmu::behavior::Lookup(EQEmu::versions::ConvertClientVersionToMobVersion(ClientVersion()))->CoinHasWeight) {
if (EQEmu::behavior::StaticLookup(EQEmu::versions::ConvertClientVersionToMobVersion(ClientVersion()))->CoinHasWeight) {
Total += (m_pp.platinum + m_pp.gold + m_pp.silver + m_pp.copper) / 4;
}
float Packrat = (float)spellbonuses.Packrat + (float)aabonuses.Packrat + (float)itembonuses.Packrat;
+118 -325
View File
@@ -506,7 +506,6 @@ void Client::CompleteConnect()
client_state = CLIENT_CONNECTED;
SendAllPackets();
hpupdate_timer.Start();
position_timer.Start();
autosave_timer.Start();
SetDuelTarget(0);
SetDueling(false);
@@ -531,7 +530,7 @@ void Client::CompleteConnect()
SendAppearancePacket(AT_GuildID, GuildID(), false);
SendAppearancePacket(AT_GuildRank, rank, false);
}
for (uint32 spellInt = 0; spellInt < MAX_PP_REF_SPELLBOOK; spellInt++) {
for (uint32 spellInt = 0; spellInt < EQEmu::spells::SPELLBOOK_SIZE; spellInt++) {
if (m_pp.spell_book[spellInt] < 3 || m_pp.spell_book[spellInt] > 50000)
m_pp.spell_book[spellInt] = 0xFFFFFFFF;
}
@@ -754,7 +753,7 @@ void Client::CompleteConnect()
entity_list.SendUntargetable(this);
int x;
for (x = 0; x < 8; x++) {
for (x = EQEmu::textures::textureBegin; x <= EQEmu::textures::LastTexture; x++) {
SendWearChange(x);
}
// added due to wear change above
@@ -763,7 +762,7 @@ void Client::CompleteConnect()
Mob *pet = GetPet();
if (pet != nullptr) {
for (x = 0; x < 8; x++) {
for (x = EQEmu::textures::textureBegin; x <= EQEmu::textures::LastTexture; x++) {
pet->SendWearChange(x);
}
// added due to wear change above
@@ -810,6 +809,16 @@ void Client::CompleteConnect()
std::string event_desc = StringFormat("Connect :: Logged into zoneid:%i instid:%i", this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Connect_State, this->CharacterID(), event_desc);
}
/**
* Update last login since this doesn't get updated until a late save later so we can update online status
*/
database.QueryDatabase(
StringFormat(
"UPDATE `character_data` SET `last_login` = UNIX_TIMESTAMP() WHERE id = %u",
this->CharacterID()
)
);
}
if (zone) {
@@ -869,14 +878,14 @@ void Client::CompleteConnect()
worldserver.SendPacket(pack);
delete pack;
if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::bit_UFAndLater) {
if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::maskUFAndLater) {
EQApplicationPacket *outapp = MakeBuffsPacket(false);
CastToClient()->FastQueuePacket(&outapp);
}
// TODO: load these states
// We at least will set them to the correct state for now
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater && GetPet()) {
if (m_ClientVersionBit & EQEmu::versions::maskUFAndLater && GetPet()) {
SetPetCommandState(PET_BUTTON_SIT, 0);
SetPetCommandState(PET_BUTTON_STOP, 0);
SetPetCommandState(PET_BUTTON_REGROUP, 0);
@@ -896,108 +905,6 @@ void Client::CompleteConnect()
worldserver.RequestTellQueue(GetName());
}
void Client::CheatDetected(CheatTypes CheatType, float x, float y, float z)
{
//ToDo: Break warp down for special zones. Some zones have special teleportation pads or bad .map files which can trigger the detector without a legit zone request.
switch (CheatType)
{
case MQWarp: //Some zones may still have issues. Database updates will eliminate most if not all problems.
if (RuleB(Zone, EnableMQWarpDetector)
&& ((this->Admin() < RuleI(Zone, MQWarpExemptStatus)
|| (RuleI(Zone, MQWarpExemptStatus)) == -1)))
{
Message(13, "Large warp detected.");
char hString[250];
sprintf(hString, "/MQWarp with location %.2f, %.2f, %.2f", GetX(), GetY(), GetZ());
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
}
break;
case MQWarpShadowStep:
if (RuleB(Zone, EnableMQWarpDetector)
&& ((this->Admin() < RuleI(Zone, MQWarpExemptStatus)
|| (RuleI(Zone, MQWarpExemptStatus)) == -1)))
{
char *hString = nullptr;
MakeAnyLenString(&hString, "/MQWarp(SS) with location %.2f, %.2f, %.2f, the target was shadow step exempt but we still found this suspicious.", GetX(), GetY(), GetZ());
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
safe_delete_array(hString);
}
break;
case MQWarpKnockBack:
if (RuleB(Zone, EnableMQWarpDetector)
&& ((this->Admin() < RuleI(Zone, MQWarpExemptStatus)
|| (RuleI(Zone, MQWarpExemptStatus)) == -1)))
{
char *hString = nullptr;
MakeAnyLenString(&hString, "/MQWarp(KB) with location %.2f, %.2f, %.2f, the target was Knock Back exempt but we still found this suspicious.", GetX(), GetY(), GetZ());
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
safe_delete_array(hString);
}
break;
case MQWarpLight:
if (RuleB(Zone, EnableMQWarpDetector)
&& ((this->Admin() < RuleI(Zone, MQWarpExemptStatus)
|| (RuleI(Zone, MQWarpExemptStatus)) == -1)))
{
if (RuleB(Zone, MarkMQWarpLT))
{
char *hString = nullptr;
MakeAnyLenString(&hString, "/MQWarp(LT) with location %.2f, %.2f, %.2f, running fast but not fast enough to get killed, possibly: small warp, speed hack, excessive lag, marked as suspicious.", GetX(), GetY(), GetZ());
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
safe_delete_array(hString);
}
}
break;
case MQZone:
if (RuleB(Zone, EnableMQZoneDetector) && ((this->Admin() < RuleI(Zone, MQZoneExemptStatus) || (RuleI(Zone, MQZoneExemptStatus)) == -1)))
{
char hString[250];
sprintf(hString, "/MQZone used at %.2f, %.2f, %.2f to %.2f %.2f %.2f", GetX(), GetY(), GetZ(), x, y, z);
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
}
break;
case MQZoneUnknownDest:
if (RuleB(Zone, EnableMQZoneDetector) && ((this->Admin() < RuleI(Zone, MQZoneExemptStatus) || (RuleI(Zone, MQZoneExemptStatus)) == -1)))
{
char hString[250];
sprintf(hString, "/MQZone used at %.2f, %.2f, %.2f", GetX(), GetY(), GetZ());
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
}
break;
case MQGate:
if (RuleB(Zone, EnableMQGateDetector) && ((this->Admin() < RuleI(Zone, MQGateExemptStatus) || (RuleI(Zone, MQGateExemptStatus)) == -1))) {
Message(13, "Illegal gate request.");
char hString[250];
sprintf(hString, "/MQGate used at %.2f, %.2f, %.2f", GetX(), GetY(), GetZ());
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
if (zone)
{
this->SetZone(this->GetZoneID(), zone->GetInstanceID()); //Prevent the player from zoning, place him back in the zone where he tried to originally /gate.
}
else
{
this->SetZone(this->GetZoneID(), 0); //Prevent the player from zoning, place him back in the zone where he tried to originally /gate.
}
}
break;
case MQGhost: //Not currently implemented, but the framework is in place - just needs detection scenarios identified
if (RuleB(Zone, EnableMQGhostDetector) && ((this->Admin() < RuleI(Zone, MQGhostExemptStatus) || (RuleI(Zone, MQGhostExemptStatus)) == -1))) {
database.SetMQDetectionFlag(this->account_name, this->name, "/MQGhost", zone->GetShortName());
}
break;
default:
char *hString = nullptr;
MakeAnyLenString(&hString, "Unhandled HackerDetection flag with location %.2f, %.2f, %.2f.", GetX(), GetY(), GetZ());
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
safe_delete_array(hString);
break;
}
}
// connecting opcode handlers
/*
void Client::Handle_Connect_0x3e33(const EQApplicationPacket *app)
@@ -1247,8 +1154,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
SetClientVersion(Connection()->ClientVersion());
m_ClientVersionBit = EQEmu::versions::ConvertClientVersionToClientVersionBit(Connection()->ClientVersion());
bool siv = m_inv.SetInventoryVersion(m_ClientVersion);
Log(Logs::General, Logs::None, "%s inventory version to %s(%i)", (siv ? "Succeeded in setting" : "Failed to set"), ClientVersionName(m_ClientVersion), m_ClientVersion);
m_inv.SetInventoryVersion(m_ClientVersion);
/* Antighost code
tmp var is so the search doesnt find this object
@@ -1288,7 +1194,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
uint32 cid = CharacterID();
character_id = cid; /* Global character_id reference */
/* Flush and reload factions */
/* Flush and reload factions */
database.RemoveTempFactions(this);
database.LoadCharacterFactionValues(cid, factionvalues);
@@ -1325,6 +1231,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
m_pp.platinum_shared = database.GetSharedPlatinum(this->AccountID());
database.ClearOldRecastTimestamps(cid); /* Clear out our old recast timestamps to keep the DB clean */
// set to full support in case they're a gm with items in disabled expansion slots..but, have their gm flag off...
// item loss will occur when they use the 'empty' slots, if this is not done
m_inv.SetGMInventory(true);
loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */
database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */
database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */
@@ -1341,7 +1250,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
database.LoadCharacterLeadershipAA(cid, &m_pp); /* Load Character Leadership AA's */
database.LoadCharacterTribute(cid, &m_pp); /* Load CharacterTribute */
/* Load AdventureStats */
/* Load AdventureStats */
AdventureStats_Struct as;
if (database.GetAdventureStats(cid, &as))
{
@@ -1500,8 +1409,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
if (m_pp.ldon_points_tak < 0 || m_pp.ldon_points_tak > 2000000000) { m_pp.ldon_points_tak = 0; }
if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000) { m_pp.ldon_points_available = 0; }
// need to rework .. not until full scope of change is accounted for, though
if (RuleB(World, UseClientBasedExpansionSettings)) {
m_pp.expansions = EQEmu::versions::ConvertClientVersionToExpansion(ClientVersion());
m_pp.expansions = EQEmu::expansions::ConvertClientVersionToExpansionMask(ClientVersion());
}
else {
m_pp.expansions = RuleI(World, ExpansionSettings);
@@ -1512,7 +1422,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
}
if (SPDAT_RECORDS > 0) {
for (uint32 z = 0; z<MAX_PP_MEMSPELL; z++) {
for (uint32 z = 0; z < EQEmu::spells::SPELL_GEM_COUNT; z++) {
if (m_pp.mem_spells[z] >= (uint32)SPDAT_RECORDS)
UnmemSpell(z, false);
}
@@ -1619,6 +1529,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
Bot::LoadAndSpawnAllZonedBots(this);
#endif
m_inv.SetGMInventory((bool)m_pp.gm); // set to current gm state for calc
CalcBonuses();
if (RuleB(Zone, EnableLoggedOffReplenishments) &&
time(nullptr) - m_pp.lastlogin >= RuleI(Zone, MinOfflineTimeToReplenishments)) {
@@ -1643,7 +1554,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
}
/* Load Spell Slot Refresh from Currently Memoried Spells */
for (unsigned int i = 0; i < MAX_PP_MEMSPELL; ++i)
for (unsigned int i = 0; i < EQEmu::spells::SPELL_GEM_COUNT; ++i)
if (IsValidSpell(m_pp.mem_spells[i]))
m_pp.spellSlotRefresh[i] = p_timers.GetRemainingTime(pTimerSpellStart + m_pp.mem_spells[i]) * 1000;
@@ -1742,6 +1653,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
this is not quite where live sends inventory, they do it after tribute
*/
if (loaditems) { /* Dont load if a length error occurs */
if (admin >= minStatusToBeGM)
m_inv.SetGMInventory(true); // set to true to allow expansion-restricted packets through
BulkSendInventoryItems();
/* Send stuff on the cursor which isnt sent in bulk */
for (auto iter = m_inv.cursor_cbegin(); iter != m_inv.cursor_cend(); ++iter) {
@@ -1751,6 +1665,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
const EQEmu::ItemInstance *inst = *iter;
SendItemPacket(EQEmu::invslot::slotCursor, inst, ItemPacketLimbo);
}
// this is kinda hackish atm..this process needs to be realigned to allow a contiguous flow
m_inv.SetGMInventory((bool)m_pp.gm); // reset back to current gm state
}
/* Task Packets */
@@ -1766,7 +1683,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
}
}
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) {
if (m_ClientVersionBit & EQEmu::versions::maskUFAndLater) {
outapp = new EQApplicationPacket(OP_XTargetResponse, 8);
outapp->WriteUInt32(GetMaxXTargets());
outapp->WriteUInt32(0);
@@ -2973,7 +2890,6 @@ void Client::Handle_OP_Assist(const EQApplicationPacket *app)
Mob *new_target = assistee->GetTarget();
if (new_target && (GetGM() ||
Distance(m_Position, assistee->GetPosition()) <= TARGETING_RANGE)) {
SetAssistExemption(true);
eid->entity_id = new_target->GetID();
} else {
eid->entity_id = 0;
@@ -3341,42 +3257,40 @@ void Client::Handle_OP_AutoAttack(const EQApplicationPacket *app)
return;
}
if (app->pBuffer[0] == 0)
{
if (app->pBuffer[0] == 0) {
auto_attack = false;
if (IsAIControlled())
if (IsAIControlled()) {
return;
}
attack_timer.Disable();
ranged_timer.Disable();
attack_dw_timer.Disable();
m_AutoAttackPosition = glm::vec4();
m_AutoAttackPosition = glm::vec4();
m_AutoAttackTargetLocation = glm::vec3();
aa_los_them_mob = nullptr;
aa_los_them_mob = nullptr;
}
else if (app->pBuffer[0] == 1)
{
else if (app->pBuffer[0] == 1) {
auto_attack = true;
auto_fire = false;
if (IsAIControlled())
auto_fire = false;
if (IsAIControlled()) {
return;
}
SetAttackTimer();
if (GetTarget())
{
aa_los_them_mob = GetTarget();
m_AutoAttackPosition = GetPosition();
if (GetTarget()) {
aa_los_them_mob = GetTarget();
m_AutoAttackPosition = GetPosition();
m_AutoAttackTargetLocation = glm::vec3(aa_los_them_mob->GetPosition());
los_status = CheckLosFN(aa_los_them_mob);
los_status_facing = IsFacingMob(aa_los_them_mob);
los_status = CheckLosFN(aa_los_them_mob);
los_status_facing = IsFacingMob(aa_los_them_mob);
}
else
{
m_AutoAttackPosition = GetPosition();
else {
m_AutoAttackPosition = GetPosition();
m_AutoAttackTargetLocation = glm::vec3();
aa_los_them_mob = nullptr;
los_status = false;
los_status_facing = false;
aa_los_them_mob = nullptr;
los_status = false;
los_status_facing = false;
}
}
}
@@ -3944,6 +3858,8 @@ void Client::Handle_OP_BoardBoat(const EQApplicationPacket *app)
return;
controlling_boat_id = boat->GetID(); // set the client's BoatID to show that it's on this boat
Message(0, "Board boat: %s", boatname);
return;
}
@@ -4100,7 +4016,7 @@ void Client::Handle_OP_CancelTrade(const EQApplicationPacket *app)
void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
{
using EQEmu::CastingSlot;
using EQEmu::spells::CastingSlot;
if (app->size != sizeof(CastSpell_Struct)) {
std::cout << "Wrong size: OP_CastSpell, size=" << app->size << ", expected " << sizeof(CastSpell_Struct) << std::endl;
return;
@@ -4121,14 +4037,14 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
/* Memorized Spell */
if (m_pp.mem_spells[castspell->slot] && m_pp.mem_spells[castspell->slot] == castspell->spell_id) {
uint16 spell_to_cast = 0;
if (castspell->slot < MAX_PP_MEMSPELL) {
if (castspell->slot < EQEmu::spells::SPELL_GEM_COUNT) {
spell_to_cast = m_pp.mem_spells[castspell->slot];
if (spell_to_cast != castspell->spell_id) {
InterruptSpell(castspell->spell_id); //CHEATER!!!
return;
}
}
else if (castspell->slot >= MAX_PP_MEMSPELL) {
else if (castspell->slot >= EQEmu::spells::SPELL_GEM_COUNT) {
InterruptSpell();
return;
}
@@ -4451,9 +4367,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
sizeof(PlayerPositionUpdateClient_Struct), app->size);
return;
}
PlayerPositionUpdateClient_Struct *ppu = (PlayerPositionUpdateClient_Struct *) app->pBuffer;
/* Boat handling */
if (ppu->spawn_id != GetID()) {
/* If player is controlling boat */
@@ -4463,163 +4379,67 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
controlling_boat_id = 0;
return;
}
auto boat_delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading));
boat->SetDelta(boat_delta);
auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
PlayerPositionUpdateServer_Struct *ppus = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer;
boat->MakeSpawnUpdate(ppus);
entity_list.QueueCloseClients(boat, outapp, true, 300, this, false);
safe_delete(outapp);
/* Update the boat's position on the server, without sending an update */
boat->GMMove(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading), false);
return;
} else return;
}
float dist = 0;
float tmp;
tmp = m_Position.x - ppu->x_pos;
dist += tmp * tmp;
tmp = m_Position.y - ppu->y_pos;
dist += tmp * tmp;
dist = sqrt(dist);
/* Hack checks */
if (dist == 0) {
if (m_DistanceSinceLastPositionCheck > 0.0) {
uint32 cur_time = Timer::GetCurrentTime();
if ((cur_time - m_TimeSinceLastPositionCheck) > 0) {
float speed =
(m_DistanceSinceLastPositionCheck * 100) / (float) (cur_time - m_TimeSinceLastPositionCheck);
int runs = GetRunspeed();
if (speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor))) {
if (!GetGMSpeed() && (runs >= GetBaseRunspeed() ||
(speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor))))) {
if (IsShadowStepExempted()) {
if (m_DistanceSinceLastPositionCheck > 800) {
CheatDetected(MQWarpShadowStep, ppu->x_pos, ppu->y_pos, ppu->z_pos);
}
} else if (IsKnockBackExempted()) {
if (speed > 30.0f) {
CheatDetected(MQWarpKnockBack, ppu->x_pos, ppu->y_pos, ppu->z_pos);
}
} else if (!IsPortExempted()) {
if (!IsMQExemptedArea(zone->GetZoneID(), ppu->x_pos, ppu->y_pos, ppu->z_pos)) {
if (speed > (runs * 2 * RuleR(Zone, MQWarpDetectionDistanceFactor))) {
m_TimeSinceLastPositionCheck = cur_time;
m_DistanceSinceLastPositionCheck = 0.0f;
CheatDetected(MQWarp, ppu->x_pos, ppu->y_pos, ppu->z_pos);
//Death(this, 10000000, SPELL_UNKNOWN, _1H_BLUNT);
} else {
CheatDetected(MQWarpLight, ppu->x_pos, ppu->y_pos, ppu->z_pos);
}
}
}
}
}
SetShadowStepExemption(false);
SetKnockBackExemption(false);
SetPortExemption(false);
m_TimeSinceLastPositionCheck = cur_time;
m_DistanceSinceLastPositionCheck = 0.0f;
m_CheatDetectMoved = false;
}
} else {
m_TimeSinceLastPositionCheck = Timer::GetCurrentTime();
m_CheatDetectMoved = false;
}
} else {
m_DistanceSinceLastPositionCheck += dist;
m_CheatDetectMoved = true;
if (m_TimeSinceLastPositionCheck == 0) {
m_TimeSinceLastPositionCheck = Timer::GetCurrentTime();
} else {
uint32 cur_time = Timer::GetCurrentTime();
if ((cur_time - m_TimeSinceLastPositionCheck) > 2500) {
float speed =
(m_DistanceSinceLastPositionCheck * 100) / (float) (cur_time - m_TimeSinceLastPositionCheck);
int runs = GetRunspeed();
if (speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor))) {
if (!GetGMSpeed() && (runs >= GetBaseRunspeed() ||
(speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor))))) {
if (IsShadowStepExempted()) {
if (m_DistanceSinceLastPositionCheck > 800) {
CheatDetected(MQWarpShadowStep, ppu->x_pos, ppu->y_pos, ppu->z_pos);
}
} else if (IsKnockBackExempted()) {
if (speed > 30.0f) {
CheatDetected(MQWarpKnockBack, ppu->x_pos, ppu->y_pos, ppu->z_pos);
}
} else if (!IsPortExempted()) {
if (!IsMQExemptedArea(zone->GetZoneID(), ppu->x_pos, ppu->y_pos, ppu->z_pos)) {
if (speed > (runs * 2 * RuleR(Zone, MQWarpDetectionDistanceFactor))) {
m_TimeSinceLastPositionCheck = cur_time;
m_DistanceSinceLastPositionCheck = 0.0f;
CheatDetected(MQWarp, ppu->x_pos, ppu->y_pos, ppu->z_pos);
} else {
CheatDetected(MQWarpLight, ppu->x_pos, ppu->y_pos, ppu->z_pos);
}
}
}
}
}
SetShadowStepExemption(false);
SetKnockBackExemption(false);
SetPortExemption(false);
m_TimeSinceLastPositionCheck = cur_time;
m_DistanceSinceLastPositionCheck = 0.0f;
}
}
if (IsDraggingCorpse())
DragCorpses();
}
if (IsDraggingCorpse())
DragCorpses();
/* Check to see if PPU should trigger an update to the rewind position. */
float rewind_x_diff = 0;
float rewind_y_diff = 0;
rewind_x_diff = ppu->x_pos - m_RewindLocation.x;
rewind_x_diff *= rewind_x_diff;
rewind_y_diff = ppu->y_pos - m_RewindLocation.y;
rewind_y_diff *= rewind_y_diff;
/*
We only need to store updated values if the player has moved.
If the player has moved more than units for x or y, then we'll store
his pre-PPU x and y for /rewind, in case he gets stuck.
*/
if ((rewind_x_diff > 750) || (rewind_y_diff > 750))
m_RewindLocation = glm::vec3(m_Position);
/*
If the PPU was a large jump, such as a cross zone gate or Call of Hero,
just update rewind coordinates to the new ppu coordinates. This will prevent exploitation.
*/
if ((rewind_x_diff > 5000) || (rewind_y_diff > 5000))
m_RewindLocation = glm::vec3(ppu->x_pos, ppu->y_pos, ppu->z_pos);
if (proximity_timer.Check()) {
entity_list.ProcessMove(this, glm::vec3(ppu->x_pos, ppu->y_pos, ppu->z_pos));
if (RuleB(TaskSystem, EnableTaskSystem) && RuleB(TaskSystem, EnableTaskProximity))
ProcessTaskProximities(ppu->x_pos, ppu->y_pos, ppu->z_pos);
m_Proximity = glm::vec3(ppu->x_pos, ppu->y_pos, ppu->z_pos);
}
/* Update internal state */
m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading));
if (IsTracking() && ((m_Position.x != ppu->x_pos) || (m_Position.y != ppu->y_pos))) {
if (zone->random.Real(0, 100) < 70)//should be good
CheckIncreaseSkill(EQEmu::skills::SkillTracking, nullptr, -20);
}
/* Break Hide if moving without sneaking and set rewind timer if moved */
if (ppu->y_pos != m_Position.y || ppu->x_pos != m_Position.x) {
if ((hidden || improved_hidden) && !sneaking) {
@@ -4638,43 +4458,35 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
}
rewind_timer.Start(30000, true);
}
/* Handle client aggro scanning timers NPCs */
is_client_moving = (ppu->y_pos == m_Position.y && ppu->x_pos == m_Position.x) ? false : true;
if (is_client_moving) {
Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is moving - scan timer is: %u",
client_scan_npc_aggro_timer.GetDuration());
if (client_scan_npc_aggro_timer.GetDuration() > 1000) {
npc_close_scan_timer.Disable();
npc_close_scan_timer.Start(500);
client_scan_npc_aggro_timer.Disable();
client_scan_npc_aggro_timer.Start(500);
}
} else {
Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is NOT moving - scan timer is: %u",
client_scan_npc_aggro_timer.GetDuration());
if (client_scan_npc_aggro_timer.GetDuration() < 1000) {
npc_close_scan_timer.Disable();
npc_close_scan_timer.Start(6000);
client_scan_npc_aggro_timer.Disable();
client_scan_npc_aggro_timer.Start(3000);
}
}
float new_heading = EQ12toFloat(ppu->heading);
int32 new_animation = ppu->animation;
/* Update internal server position from what the client has sent */
m_Position.x = ppu->x_pos;
m_Position.y = ppu->y_pos;
m_Position.z = ppu->z_pos;
/* Visual Debugging */
if (RuleB(Character, OPClientUpdateVisualDebug)) {
Log(Logs::General, Logs::Debug, "ClientUpdate: ppu x: %f y: %f z: %f h: %u", ppu->x_pos, ppu->y_pos, ppu->z_pos,
@@ -4682,43 +4494,43 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
this->SendAppearanceEffect(78, 0, 0, 0, 0);
this->SendAppearanceEffect(41, 0, 0, 0, 0);
}
/* Only feed real time updates when client is moving */
if (is_client_moving || new_heading != m_Position.w || new_animation != animation) {
animation = ppu->animation;
m_Position.w = EQ12toFloat(ppu->heading);
/* Broadcast update to other clients */
auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
PlayerPositionUpdateServer_Struct *position_update = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer;
MakeSpawnUpdate(position_update);
if (gm_hide_me) {
entity_list.QueueClientsStatus(this, outapp, true, Admin(), 250);
} else {
entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, ClientPositionUpdates), nullptr, true);
}
/* Always send position updates to group - send when beyond normal ClientPositionUpdate range */
Group *group = this->GetGroup();
Raid *raid = this->GetRaid();
if (raid) {
raid->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
} else if (group) {
group->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
}
safe_delete(outapp);
}
if (zone->watermap) {
if (zone->watermap->InLiquid(glm::vec3(m_Position))) {
CheckIncreaseSkill(EQEmu::skills::SkillSwimming, nullptr, -17);
// Dismount horses when entering water
if (GetHorseId() && RuleB(Character, DismountWater)) {
SetHorseId(0);
@@ -4727,7 +4539,6 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
}
CheckRegionTypeChanges();
}
return;
}
void Client::Handle_OP_CombatAbility(const EQApplicationPacket *app)
@@ -5452,7 +5263,7 @@ void Client::Handle_OP_DeleteSpell(const EQApplicationPacket *app)
EQApplicationPacket* outapp = app->Copy();
DeleteSpell_Struct* dss = (DeleteSpell_Struct*)outapp->pBuffer;
if (dss->spell_slot < 0 || dss->spell_slot > int(MAX_PP_SPELLBOOK))
if (dss->spell_slot < 0 || dss->spell_slot > int(EQEmu::spells::SPELLBOOK_SIZE))
return;
if (m_pp.spell_book[dss->spell_slot] != SPELLBOOK_UNKNOWN) {
@@ -8650,7 +8461,7 @@ void Client::Handle_OP_ItemPreview(const EQApplicationPacket *app)
void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
{
using EQEmu::CastingSlot;
using EQEmu::spells::CastingSlot;
if (app->size != sizeof(ItemVerifyRequest_Struct))
{
Log(Logs::General, Logs::Error, "OP size error: OP_ItemVerifyRequest expected:%i got:%i", sizeof(ItemVerifyRequest_Struct), app->size);
@@ -9376,7 +9187,7 @@ void Client::Handle_OP_LoadSpellSet(const EQApplicationPacket *app)
}
int i;
LoadSpellSet_Struct* ss = (LoadSpellSet_Struct*)app->pBuffer;
for (i = 0; i<MAX_PP_MEMSPELL; i++) {
for (i = 0; i < EQEmu::spells::SPELL_GEM_COUNT; i++) {
if (ss->spell[i] != 0xFFFFFFFF)
UnmemSpell(i, true);
}
@@ -10260,9 +10071,9 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
if (mypet->IsNPC()) {
mypet->SayTo_StringID(this, MT_PetResponse, PET_GUARDINGLIFE);
mypet->SetPetOrder(SPO_Guard);
mypet->CastToNPC()->SaveGuardSpot();
mypet->CastToNPC()->SaveGuardSpot(mypet->GetPosition());
if (!mypet->GetTarget()) // want them to not twitch if they're chasing something down
mypet->SetCurrentSpeed(0);
mypet->StopNavigation();
if (mypet->IsPetStop()) {
mypet->SetPetStop(false);
SetPetCommandState(PET_BUTTON_STOP, 0);
@@ -10377,16 +10188,16 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) {
if (mypet->IsHeld())
{
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskSoDAndLater)
Message_StringID(MT_PetResponse, PET_HOLD_SET_OFF);
mypet->SetHeld(false);
}
else
{
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskSoDAndLater)
Message_StringID(MT_PetResponse, PET_HOLD_SET_ON);
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskUFAndLater)
mypet->SayTo_StringID(this, MT_PetResponse, PET_NOW_HOLDING);
else
mypet->SayTo_StringID(this, MT_PetResponse, PET_ON_HOLD);
@@ -10400,10 +10211,10 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
}
case PET_HOLD_ON: {
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && !mypet->IsHeld()) {
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskSoDAndLater)
Message_StringID(MT_PetResponse, PET_HOLD_SET_ON);
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskUFAndLater)
mypet->SayTo_StringID(this, MT_PetResponse, PET_NOW_HOLDING);
else
mypet->SayTo_StringID(this, MT_PetResponse, PET_ON_HOLD);
@@ -10415,7 +10226,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
}
case PET_HOLD_OFF: {
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && mypet->IsHeld()) {
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskSoDAndLater)
Message_StringID(MT_PetResponse, PET_HOLD_SET_OFF);
mypet->SetHeld(false);
}
@@ -10425,13 +10236,13 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) {
if (mypet->IsGHeld())
{
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskUFAndLater)
Message_StringID(MT_PetResponse, PET_OFF_GHOLD);
mypet->SetGHeld(false);
}
else
{
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) {
if (m_ClientVersionBit & EQEmu::versions::maskUFAndLater) {
Message_StringID(MT_PetResponse, PET_ON_GHOLD);
mypet->SayTo_StringID(this, MT_PetResponse, PET_GHOLD_ON_MSG);
} else {
@@ -10446,7 +10257,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
}
case PET_GHOLD_ON: {
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) {
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) {
if (m_ClientVersionBit & EQEmu::versions::maskUFAndLater) {
Message_StringID(MT_PetResponse, PET_ON_GHOLD);
mypet->SayTo_StringID(this, MT_PetResponse, PET_GHOLD_ON_MSG);
} else {
@@ -10460,7 +10271,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
}
case PET_GHOLD_OFF: {
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && mypet->IsGHeld()) {
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskUFAndLater)
Message_StringID(MT_PetResponse, PET_OFF_GHOLD);
mypet->SetGHeld(false);
}
@@ -10472,13 +10283,13 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
break;
if (mypet->IsNoCast()) {
Message_StringID(MT_PetResponse, PET_CASTING);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskSoDAndLater)
Message_StringID(MT_PetResponse, PET_SPELLHOLD_SET_OFF);
mypet->SetNoCast(false);
}
else {
Message_StringID(MT_PetResponse, PET_NOT_CASTING);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskSoDAndLater)
Message_StringID(MT_PetResponse, PET_SPELLHOLD_SET_ON);
mypet->SetNoCast(true);
}
@@ -10491,7 +10302,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
break;
if (!mypet->IsNoCast()) {
Message_StringID(MT_PetResponse, PET_NOT_CASTING);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskSoDAndLater)
Message_StringID(MT_PetResponse, PET_SPELLHOLD_SET_ON);
mypet->SetNoCast(true);
}
@@ -10504,7 +10315,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
break;
if (mypet->IsNoCast()) {
Message_StringID(MT_PetResponse, PET_CASTING);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskSoDAndLater)
Message_StringID(MT_PetResponse, PET_SPELLHOLD_SET_OFF);
mypet->SetNoCast(false);
}
@@ -10517,13 +10328,13 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
break;
if (mypet->IsFocused()) {
Message_StringID(MT_PetResponse, PET_NOT_FOCUSING);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskSoDAndLater)
Message_StringID(MT_PetResponse, PET_FOCUS_SET_OFF);
mypet->SetFocused(false);
}
else {
Message_StringID(MT_PetResponse, PET_NOW_FOCUSING);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskSoDAndLater)
Message_StringID(MT_PetResponse, PET_FOCUS_SET_ON);
mypet->SetFocused(true);
}
@@ -10536,7 +10347,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
break;
if (!mypet->IsFocused()) {
Message_StringID(MT_PetResponse, PET_NOW_FOCUSING);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskSoDAndLater)
Message_StringID(MT_PetResponse, PET_FOCUS_SET_ON);
mypet->SetFocused(true);
}
@@ -10549,7 +10360,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
break;
if (mypet->IsFocused()) {
Message_StringID(MT_PetResponse, PET_NOT_FOCUSING);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
if (m_ClientVersionBit & EQEmu::versions::maskSoDAndLater)
Message_StringID(MT_PetResponse, PET_FOCUS_SET_OFF);
mypet->SetFocused(false);
}
@@ -10564,7 +10375,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
mypet->SetPetStop(false);
} else {
mypet->SetPetStop(true);
mypet->SetCurrentSpeed(0);
mypet->StopNavigation();
mypet->SetTarget(nullptr);
if (mypet->IsPetRegroup()) {
mypet->SetPetRegroup(false);
@@ -10580,7 +10391,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
mypet->SetPetStop(true);
mypet->SetCurrentSpeed(0);
mypet->StopNavigation();
mypet->SetTarget(nullptr);
mypet->SayTo_StringID(this, MT_PetResponse, PET_GETLOST_STRING);
if (mypet->IsPetRegroup()) {
@@ -13526,7 +13337,7 @@ void Client::Handle_OP_SwapSpell(const EQApplicationPacket *app)
const SwapSpell_Struct* swapspell = (const SwapSpell_Struct*)app->pBuffer;
int swapspelltemp;
if (swapspell->from_slot < 0 || swapspell->from_slot > MAX_PP_SPELLBOOK || swapspell->to_slot < 0 || swapspell->to_slot > MAX_PP_SPELLBOOK)
if (swapspell->from_slot < 0 || swapspell->from_slot > EQEmu::spells::SPELLBOOK_SIZE || swapspell->to_slot < 0 || swapspell->to_slot > EQEmu::spells::SPELLBOOK_SIZE)
return;
swapspelltemp = m_pp.spell_book[swapspell->from_slot];
@@ -13701,12 +13512,6 @@ void Client::Handle_OP_TargetCommand(const EQApplicationPacket *app)
GetTarget()->IsTargeted(1);
return;
}
else if (IsAssistExempted())
{
GetTarget()->IsTargeted(1);
SetAssistExemption(false);
return;
}
else if (GetTarget()->IsClient())
{
//make sure this client is in our raid/group
@@ -13724,17 +13529,6 @@ void Client::Handle_OP_TargetCommand(const EQApplicationPacket *app)
SetTarget((Mob*)nullptr);
return;
}
else if (IsPortExempted())
{
GetTarget()->IsTargeted(1);
return;
}
else if (IsSenseExempted())
{
GetTarget()->IsTargeted(1);
SetSenseExemption(false);
return;
}
else if (IsXTarget(GetTarget()))
{
GetTarget()->IsTargeted(1);
@@ -14676,7 +14470,6 @@ void Client::Handle_OP_WearChange(const EQApplicationPacket *app)
// we could maybe ignore this and just send our own from moveitem
entity_list.QueueClients(this, app, true);
return;
}
void Client::Handle_OP_WhoAllRequest(const EQApplicationPacket *app)
+23 -77
View File
@@ -122,7 +122,7 @@ bool Client::Process() {
/* I haven't naturally updated my position in 10 seconds, updating manually */
if (!is_client_moving && position_update_timer.Check()) {
SendPositionUpdate();
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
}
if (mana_timer.Check())
@@ -188,10 +188,6 @@ bool Client::Process() {
if (IsStunned() && stunned_timer.Check())
Mob::UnStun();
if (!m_CheatDetectMoved) {
m_TimeSinceLastPositionCheck = Timer::GetCurrentTime();
}
if (bardsong_timer.Check() && bardsong != 0) {
//NOTE: this is kinda a heavy-handed check to make sure the mob still exists before
//doing the next pulse on them...
@@ -258,20 +254,13 @@ bool Client::Process() {
/* Build a close range list of NPC's */
if (npc_close_scan_timer.Check()) {
close_mobs.clear();
/* Force spawn updates when traveled far */
//Force spawn updates when traveled far
bool force_spawn_updates = false;
float client_update_range = (RuleI(Range, ClientForceSpawnUpdateRange) * RuleI(Range, ClientForceSpawnUpdateRange));
if (DistanceSquared(last_major_update_position, m_Position) >= client_update_range) {
last_major_update_position = m_Position;
force_spawn_updates = true;
}
float scan_range = (RuleI(Range, ClientNPCScan) * RuleI(Range, ClientNPCScan));
auto &mob_list = entity_list.GetMobList();
for (auto itr = mob_list.begin(); itr != mob_list.end(); ++itr) {
Mob* mob = itr->second;
float distance = DistanceSquared(m_Position, mob->GetPosition());
if (mob->IsNPC()) {
if (distance <= scan_range) {
@@ -281,21 +270,9 @@ bool Client::Process() {
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
}
}
if (force_spawn_updates && mob != this) {
if (mob->is_distance_roamer) {
mob->SendPositionUpdateToClient(this);
continue;
}
if (distance <= client_update_range)
mob->SendPositionUpdateToClient(this);
}
}
}
bool may_use_attacks = false;
/*
Things which prevent us from attacking:
@@ -368,25 +345,22 @@ bool Client::Process() {
}
Mob *auto_attack_target = GetTarget();
if (auto_attack && auto_attack_target != nullptr && may_use_attacks && attack_timer.Check())
{
if (auto_attack && auto_attack_target != nullptr && may_use_attacks && attack_timer.Check()) {
//check if change
//only check on primary attack.. sorry offhand you gotta wait!
if (aa_los_them_mob)
{
if (aa_los_them_mob) {
if (auto_attack_target != aa_los_them_mob ||
m_AutoAttackPosition.x != GetX() ||
m_AutoAttackPosition.y != GetY() ||
m_AutoAttackPosition.z != GetZ() ||
m_AutoAttackTargetLocation.x != aa_los_them_mob->GetX() ||
m_AutoAttackTargetLocation.y != aa_los_them_mob->GetY() ||
m_AutoAttackTargetLocation.z != aa_los_them_mob->GetZ())
{
aa_los_them_mob = auto_attack_target;
m_AutoAttackPosition = GetPosition();
m_AutoAttackTargetLocation.z != aa_los_them_mob->GetZ()) {
aa_los_them_mob = auto_attack_target;
m_AutoAttackPosition = GetPosition();
m_AutoAttackTargetLocation = glm::vec3(aa_los_them_mob->GetPosition());
los_status = CheckLosFN(auto_attack_target);
los_status_facing = IsFacingMob(aa_los_them_mob);
los_status = CheckLosFN(auto_attack_target);
los_status_facing = IsFacingMob(aa_los_them_mob);
}
// If only our heading changes, we can skip the CheckLosFN call
// but above we still need to update los_status_facing
@@ -395,25 +369,21 @@ bool Client::Process() {
los_status_facing = IsFacingMob(aa_los_them_mob);
}
}
else
{
aa_los_them_mob = auto_attack_target;
m_AutoAttackPosition = GetPosition();
else {
aa_los_them_mob = auto_attack_target;
m_AutoAttackPosition = GetPosition();
m_AutoAttackTargetLocation = glm::vec3(aa_los_them_mob->GetPosition());
los_status = CheckLosFN(auto_attack_target);
los_status_facing = IsFacingMob(aa_los_them_mob);
los_status = CheckLosFN(auto_attack_target);
los_status_facing = IsFacingMob(aa_los_them_mob);
}
if (!CombatRange(auto_attack_target))
{
if (!CombatRange(auto_attack_target)) {
Message_StringID(MT_TooFarAway, TARGET_TOO_FAR);
}
else if (auto_attack_target == this)
{
else if (auto_attack_target == this) {
Message_StringID(MT_TooFarAway, TRY_ATTACKING_SOMEONE);
}
else if (!los_status || !los_status_facing)
{
else if (!los_status || !los_status_facing) {
//you can't see your target
}
else if (auto_attack_target->GetHP() > -10) // -10 so we can watch people bleed in PvP
@@ -423,8 +393,9 @@ bool Client::Process() {
TriggerDefensiveProcs(auto_attack_target, EQEmu::invslot::slotPrimary, false);
DoAttackRounds(auto_attack_target, EQEmu::invslot::slotPrimary);
if (CheckAATimer(aaTimerRampage))
if (CheckAATimer(aaTimerRampage)) {
entity_list.AEAttack(this, 30);
}
}
}
@@ -466,31 +437,6 @@ bool Client::Process() {
}
}
if (position_timer.Check()) {
if (IsAIControlled())
{
if (!IsMoving())
{
animation = 0;
m_Delta = glm::vec4(0.0f, 0.0f, 0.0f, m_Delta.w);
SendPositionUpdate(2);
}
}
// Send a position packet every 8 seconds - if not done, other clients
// see this char disappear after 10-12 seconds of inactivity
if (position_timer_counter >= 36) { // Approx. 4 ticks per second
entity_list.SendPositionUpdates(this, pLastUpdateWZ, RuleI(Range, MobPositionUpdates), GetTarget(), true);
pLastUpdate = Timer::GetCurrentTime();
pLastUpdateWZ = pLastUpdate;
position_timer_counter = 0;
}
else {
pLastUpdate = Timer::GetCurrentTime();
position_timer_counter++;
}
}
if (HasVirus()) {
if (viral_timer.Check()) {
viral_timer_counter++;
@@ -866,7 +812,7 @@ void Client::BulkSendInventoryItems()
void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
const EQEmu::ItemData* handyitem = nullptr;
uint32 numItemSlots = 80; //The max number of items passed in the transaction.
if (m_ClientVersionBit & EQEmu::versions::bit_RoFAndLater) { // RoF+ can send 200 items
if (m_ClientVersionBit & EQEmu::versions::maskRoFAndLater) { // RoF+ can send 200 items
numItemSlots = 200;
}
const EQEmu::ItemData *item = nullptr;
@@ -1186,7 +1132,7 @@ void Client::CancelSneakHide()
// The later clients send back a OP_Hide (this has a size but data is 0)
// as well as OP_SpawnAppearance with AT_Invis and one with AT_Sneak
// So we don't have to handle any of those flags
if (ClientVersionBit() & EQEmu::versions::bit_SoFAndEarlier)
if (ClientVersionBit() & EQEmu::versions::maskSoFAndEarlier)
sneaking = false;
}
}
@@ -2183,7 +2129,7 @@ void Client::ClearHover()
entity_list.QueueClients(this, outapp, false);
safe_delete(outapp);
if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::bit_UFAndLater)
if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::maskUFAndLater)
{
EQApplicationPacket *outapp = MakeBuffsPacket(false);
CastToClient()->FastQueuePacket(&outapp);
+561 -89
View File
@@ -67,6 +67,7 @@
#include "water_map.h"
#include "worldserver.h"
#include "fastmath.h"
#include "mob_movement_manager.h"
#include "npc_scale_manager.h"
extern QueryServ* QServ;
@@ -205,7 +206,7 @@ int command_init(void)
command_add("flag", "[status] [acctname] - Refresh your admin status, or set an account's admin status if arguments provided", 0, command_flag) ||
command_add("flagedit", "- Edit zone flags on your target", 100, command_flagedit) ||
command_add("flags", "- displays the flags of you or your target", 0, command_flags) ||
command_add("flymode", "[0/1/2] - Set your or your player target's flymode to off/on/levitate", 50, command_flymode) ||
command_add("flymode", "[0/1/2/3/4/5] - Set your or your player target's flymode to ground/flying/levitate/water/floating/levitate_running", 50, command_flymode) ||
command_add("fov", "- Check wether you're behind or in your target's field of view", 80, command_fov) ||
command_add("freeze", "- Freeze your target", 80, command_freeze) ||
command_add("gassign", "[id] - Assign targetted NPC to predefined wandering grid id", 100, command_gassign) ||
@@ -218,6 +219,7 @@ int command_init(void)
command_add("globalview", "Lists all qglobals in cache if you were to do a quest with this target.", 80, command_globalview) ||
command_add("gm", "- Turn player target's or your GM flag on or off", 80, command_gm) ||
command_add("gmspeed", "[on/off] - Turn GM speed hack on/off for you or your player target", 100, command_gmspeed) ||
command_add("gmzone", "[zone_short_name] [zone_version=0] [identifier=gmzone] - Zones to a private GM instance", 100, command_gmzone) ||
command_add("goto", "[x] [y] [z] - Teleport to the provided coordinates or to your target", 10, command_goto) ||
command_add("grid", "[add/delete] [grid_num] [wandertype] [pausetype] - Create/delete a wandering grid", 170, command_grid) ||
command_add("guild", "- Guild manipulation commands. Use argument help for more info.", 10, command_guild) ||
@@ -248,6 +250,7 @@ int command_init(void)
command_add("itemsearch", "[search criteria] - Search for an item", 10, command_itemsearch) ||
command_add("kick", "[charname] - Disconnect charname", 150, command_kick) ||
command_add("kill", "- Kill your target", 100, command_kill) ||
command_add("killallnpcs", " [npc_name] Kills all npcs by search name, leave blank for all attackable NPC's", 200, command_killallnpcs) ||
command_add("lastname", "[new lastname] - Set your or your player target's lastname", 50, command_lastname) ||
command_add("level", "[level] - Set your or your target's level", 10, command_level) ||
command_add("listnpcs", "[name/range] - Search NPCs", 20, command_listnpcs) ||
@@ -267,6 +270,7 @@ int command_init(void)
command_add("modifynpcstat", "- Modifys a NPC's stats", 150, command_modifynpcstat) ||
command_add("motd", "[new motd] - Set message of the day", 150, command_motd) ||
command_add("movechar", "[charname] [zonename] - Move charname to zonename", 50, command_movechar) ||
command_add("movement", "Various movement commands", 200, command_movement) ||
command_add("myskills", "- Show details about your current skill levels", 0, command_myskills) ||
command_add("mysqltest", "Akkadius MySQL Bench Test", 250, command_mysqltest) ||
command_add("mysql", "Mysql CLI, see 'help' for options.", 250, command_mysql) ||
@@ -310,6 +314,7 @@ int command_init(void)
#endif
command_add("push", "Lets you do spell push", 150, command_push) ||
command_add("proximity", "Shows NPC proximity", 150, command_proximity) ||
command_add("pvp", "[on/off] - Set your or your player target's PVP status", 100, command_pvp) ||
command_add("qglobal", "[on/off/view] - Toggles qglobal functionality on an NPC", 100, command_qglobal) ||
command_add("questerrors", "Shows quest errors.", 100, command_questerrors) ||
@@ -385,6 +390,7 @@ int command_init(void)
command_add("tattoo", "- Change the tattoo of your target (Drakkin Only)", 80, command_tattoo) ||
command_add("tempname", "[newname] - Temporarily renames your target. Leave name blank to restore the original name.", 100, command_tempname) ||
command_add("petname", "[newname] - Temporarily renames your pet. Leave name blank to restore the original name.", 100, command_petname) ||
command_add("test", "Test command", 200, command_test) ||
command_add("texture", "[texture] [helmtexture] - Change your or your target's appearance, use 255 to show equipment", 10, command_texture) ||
command_add("time", "[HH] [MM] - Set EQ time", 90, command_time) ||
command_add("timers", "- Display persistent timers for target", 200, command_timers) ||
@@ -408,6 +414,7 @@ int command_init(void)
command_add("viewpetition", "[petition number] - View a petition", 20, command_viewpetition) ||
command_add("wc", "[wear slot] [material] - Sends an OP_WearChange for your target", 200, command_wc) ||
command_add("weather", "[0/1/2/3] (Off/Rain/Snow/Manual) - Change the weather", 80, command_weather) ||
command_add("who", "[search]", 20, command_who) ||
command_add("worldshutdown", "- Shut down world and all zones", 200, command_worldshutdown) ||
command_add("wp", "[add/delete] [grid_num] [pause] [wp_num] [-h] - Add/delete a waypoint to/from a wandering grid", 170, command_wp) ||
command_add("wpadd", "[pause] [-h] - Add your current location as a waypoint to your NPC target's AI path", 170, command_wpadd) ||
@@ -745,21 +752,21 @@ void command_serversidename(Client *c, const Seperator *sep)
void command_wc(Client *c, const Seperator *sep)
{
if(sep->argnum < 2)
{
c->Message(0, "Usage: #wc [wear slot] [material] [ [hero_forge_model] [elite_material] [unknown06] [unknown18] ]");
if (sep->argnum < 2) {
c->Message(
0,
"Usage: #wc [wear slot] [material] [ [hero_forge_model] [elite_material] [unknown06] [unknown18] ]"
);
}
else if(c->GetTarget() == nullptr) {
else if (c->GetTarget() == nullptr) {
c->Message(13, "You must have a target to do a wear change.");
}
else
{
else {
uint32 hero_forge_model = 0;
uint32 wearslot = atoi(sep->arg[1]);
uint32 wearslot = atoi(sep->arg[1]);
// Hero Forge
if (sep->argnum > 2)
{
if (sep->argnum > 2) {
hero_forge_model = atoi(sep->arg[3]);
if (hero_forge_model != 0 && hero_forge_model < 1000) {
@@ -775,45 +782,43 @@ void command_wc(Client *c, const Seperator *sep)
else
Color = c->GetTarget()->GetArmorTint(atoi(sep->arg[1]));
*/
c->GetTarget()->SendTextureWC(wearslot, atoi(sep->arg[2]), hero_forge_model, atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6]));
c->GetTarget()->SendTextureWC(
wearslot,
atoi(sep->arg[2]),
hero_forge_model,
atoi(sep->arg[4]),
atoi(sep->arg[5]),
atoi(sep->arg[6]));
}
}
void command_heromodel(Client *c, const Seperator *sep)
{
if (sep->argnum < 1)
{
if (sep->argnum < 1) {
c->Message(0, "Usage: #heromodel [hero forge model] [ [slot] ] (example: #heromodel 63)");
}
else if (c->GetTarget() == nullptr)
{
else if (c->GetTarget() == nullptr) {
c->Message(13, "You must have a target to do a wear change for Hero's Forge Models.");
}
else
{
else {
uint32 hero_forge_model = atoi(sep->arg[1]);
if (sep->argnum > 1)
{
uint8 wearslot = (uint8)atoi(sep->arg[2]);
if (sep->argnum > 1) {
uint8 wearslot = (uint8) atoi(sep->arg[2]);
c->GetTarget()->SendTextureWC(wearslot, 0, hero_forge_model, 0, 0, 0);
}
else
{
if (hero_forge_model > 0)
{
else {
if (hero_forge_model > 0) {
// Conversion to simplify the command arguments
// Hero's Forge model is actually model * 1000 + texture * 100 + wearslot
// Hero's Forge Model slot 7 is actually for Robes, but it still needs to use wearslot 1 in the packet
hero_forge_model *= 100;
for (uint8 wearslot = 0; wearslot < 7; wearslot++)
{
for (uint8 wearslot = 0; wearslot < 7; wearslot++) {
c->GetTarget()->SendTextureWC(wearslot, 0, (hero_forge_model + wearslot), 0, 0, 0);
}
}
else
{
else {
c->Message(13, "Hero's Forge Model must be greater than 0.");
}
}
@@ -824,12 +829,14 @@ void command_setanim(Client *c, const Seperator *sep)
{
if (c->GetTarget() && sep->IsNumber(1)) {
int num = atoi(sep->arg[1]);
if(num < 0 || num >= _eaMaxAppearance) {
c->Message(0, "Invalid animation number, between 0 and %d", _eaMaxAppearance-1);
if (num < 0 || num >= _eaMaxAppearance) {
c->Message(0, "Invalid animation number, between 0 and %d", _eaMaxAppearance - 1);
}
c->GetTarget()->SetAppearance(EmuAppearance(num));
} else
}
else {
c->Message(0, "Usage: #setanim [animnum]");
}
}
void command_serverinfo(Client *c, const Seperator *sep)
@@ -1024,7 +1031,7 @@ void command_summon(Client *c, const Seperator *sep)
{ // npc target
c->Message(0, "Summoning NPC %s to %1.1f, %1.1f, %1.1f", t->GetName(), c->GetX(), c->GetY(), c->GetZ());
t->CastToNPC()->GMMove(c->GetX(), c->GetY(), c->GetZ(), c->GetHeading());
t->CastToNPC()->SaveGuardSpot(true);
t->CastToNPC()->SaveGuardSpot(glm::vec4(0.0f));
}
else if (t->IsCorpse())
{ // corpse target
@@ -1261,6 +1268,78 @@ void command_movechar(Client *c, const Seperator *sep)
}
}
void command_movement(Client *c, const Seperator *sep)
{
auto &mgr = MobMovementManager::Get();
if (sep->arg[1][0] == 0) {
c->Message(0, "Usage: #movement stats/clearstats/walkto/runto/rotateto/stop/packet");
return;
}
if (strcasecmp(sep->arg[1], "stats") == 0)
{
mgr.DumpStats(c);
}
else if (strcasecmp(sep->arg[1], "clearstats") == 0)
{
mgr.ClearStats();
}
else if (strcasecmp(sep->arg[1], "walkto") == 0)
{
auto target = c->GetTarget();
if (target == nullptr) {
c->Message(0, "No target found.");
return;
}
target->WalkTo(c->GetX(), c->GetY(), c->GetZ());
}
else if (strcasecmp(sep->arg[1], "runto") == 0)
{
auto target = c->GetTarget();
if (target == nullptr) {
c->Message(0, "No target found.");
return;
}
target->RunTo(c->GetX(), c->GetY(), c->GetZ());
}
else if (strcasecmp(sep->arg[1], "rotateto") == 0)
{
auto target = c->GetTarget();
if (target == nullptr) {
c->Message(0, "No target found.");
return;
}
target->RotateToWalking(target->CalculateHeadingToTarget(c->GetX(), c->GetY()));
}
else if (strcasecmp(sep->arg[1], "stop") == 0)
{
auto target = c->GetTarget();
if (target == nullptr) {
c->Message(0, "No target found.");
return;
}
target->StopNavigation();
}
else if (strcasecmp(sep->arg[1], "packet") == 0)
{
auto target = c->GetTarget();
if (target == nullptr) {
c->Message(0, "No target found.");
return;
}
mgr.SendCommandToClients(target, atof(sep->arg[2]), atof(sep->arg[3]), atof(sep->arg[4]), atof(sep->arg[5]), atoi(sep->arg[6]), ClientRangeAny);
}
else {
c->Message(0, "Usage: #movement stats/clearstats/walkto/runto/rotateto/stop/packet");
}
}
void command_viewpetition(Client *c, const Seperator *sep)
{
if (sep->arg[1][0] == 0) {
@@ -2072,7 +2151,7 @@ void command_ai(Client *c, const Seperator *sep)
}
else if (strcasecmp(sep->arg[1], "guard") == 0) {
if (target && target->IsNPC())
target->CastToNPC()->SaveGuardSpot();
target->CastToNPC()->SaveGuardSpot(target->GetPosition());
else
c->Message(0, "Usage: (targeted) #ai guard - sets npc to guard the current location (use #summon to move)");
}
@@ -2185,10 +2264,12 @@ void command_sendzonespawns(Client *c, const Seperator *sep)
void command_zsave(Client *c, const Seperator *sep)
{
if(zone->SaveZoneCFG())
if (zone->SaveZoneCFG()) {
c->Message(13, "Zone header saved successfully.");
else
}
else {
c->Message(13, "ERROR: Zone header data was NOT saved.");
}
}
void command_dbspawn2(Client *c, const Seperator *sep)
@@ -2321,7 +2402,7 @@ void command_grid(Client *c, const Seperator *sep)
static_cast<uint32>(atoi(row[4])),
static_cast<uint32>(atoi(row[5]))
);
npc->SetFlyMode(1);
npc->SetFlyMode(GravityBehavior::Flying);
npc->GMMove(node_position.x, node_position.y, node_position.z, node_position.w);
}
}
@@ -2421,20 +2502,37 @@ void command_mana(Client *c, const Seperator *sep)
void command_flymode(Client *c, const Seperator *sep)
{
Client *t=c;
Mob *t = c;
if (strlen(sep->arg[1]) == 1 && !(sep->arg[1][0] == '0' || sep->arg[1][0] == '1' || sep->arg[1][0] == '2'))
c->Message(0, "#flymode [0/1/2]");
if (strlen(sep->arg[1]) == 1 && !(sep->arg[1][0] == '0' || sep->arg[1][0] == '1' || sep->arg[1][0] == '2' || sep->arg[1][0] == '3' || sep->arg[1][0] == '4' || sep->arg[1][0] == '5'))
c->Message(0, "#flymode [0/1/2/3/4/5]");
else {
if(c->GetTarget() && c->GetTarget()->IsClient())
t=c->GetTarget()->CastToClient();
t->SendAppearancePacket(AT_Levitate, atoi(sep->arg[1]));
if (sep->arg[1][0] == '1')
c->Message(0, "Turning %s's Flymode ON", t->GetName());
else if (sep->arg[1][0] == '2')
c->Message(0, "Turning %s's Flymode LEV", t->GetName());
else
c->Message(0, "Turning %s's Flymode OFF", t->GetName());
if (c->GetTarget()) {
t = c->GetTarget();
}
int fm = atoi(sep->arg[1]);
t->SetFlyMode(static_cast<GravityBehavior>(fm));
t->SendAppearancePacket(AT_Levitate, fm);
if (sep->arg[1][0] == '0') {
c->Message(0, "Setting %s to Grounded", t->GetName());
}
else if (sep->arg[1][0] == '1') {
c->Message(0, "Setting %s to Flying", t->GetName());
}
else if (sep->arg[1][0] == '2') {
c->Message(0, "Setting %s to Levitating", t->GetName());
}
else if (sep->arg[1][0] == '3') {
c->Message(0, "Setting %s to In Water", t->GetName());
}
else if (sep->arg[1][0] == '4') {
c->Message(0, "Setting %s to Floating(Boat)", t->GetName());
}
else if (sep->arg[1][0] == '5') {
c->Message(0, "Setting %s to Levitating While Running", t->GetName());
}
}
}
@@ -2515,14 +2613,14 @@ void command_castspell(Client *c, const Seperator *sep)
else
if (c->GetTarget() == 0)
if(c->Admin() >= commandInstacast)
c->SpellFinished(spellid, 0, EQEmu::CastingSlot::Item, 0, -1, spells[spellid].ResistDiff);
c->SpellFinished(spellid, 0, EQEmu::spells::CastingSlot::Item, 0, -1, spells[spellid].ResistDiff);
else
c->CastSpell(spellid, 0, EQEmu::CastingSlot::Item, 0);
c->CastSpell(spellid, 0, EQEmu::spells::CastingSlot::Item, 0);
else
if(c->Admin() >= commandInstacast)
c->SpellFinished(spellid, c->GetTarget(), EQEmu::CastingSlot::Item, 0, -1, spells[spellid].ResistDiff);
c->SpellFinished(spellid, c->GetTarget(), EQEmu::spells::CastingSlot::Item, 0, -1, spells[spellid].ResistDiff);
else
c->CastSpell(spellid, c->GetTarget()->GetID(), EQEmu::CastingSlot::Item, 0);
c->CastSpell(spellid, c->GetTarget()->GetID(), EQEmu::spells::CastingSlot::Item, 0);
}
}
@@ -2636,18 +2734,21 @@ void command_setskillall(Client *c, const Seperator *sep)
void command_race(Client *c, const Seperator *sep)
{
Mob *t=c->CastToMob();
Mob *target = c->CastToMob();
if (sep->IsNumber(1)) {
auto race = atoi(sep->arg[1]);
if ((race >= 0 && race <= 732) || (race >= 2253 && race <= 2259)) {
if ((c->GetTarget()) && c->Admin() >= commandRaceOthers)
t = c->GetTarget();
t->SendIllusionPacket(race);
} else {
if ((c->GetTarget()) && c->Admin() >= commandRaceOthers) {
target = c->GetTarget();
}
target->SendIllusionPacket(race);
}
else {
c->Message(0, "Usage: #race [0-732, 2253-2259] (0 for back to normal)");
}
} else {
}
else {
c->Message(0, "Usage: #race [0-732, 2253-2259] (0 for back to normal)");
}
}
@@ -2725,6 +2826,18 @@ void command_spawn(Client *c, const Seperator *sep)
}
}
void command_test(Client *c, const Seperator *sep)
{
c->Message(15, "Triggering test command");
if (sep->arg[1]) {
c->SetPrimaryWeaponOrnamentation(atoi(sep->arg[1]));
}
if (sep->arg[2]) {
c->SetSecondaryWeaponOrnamentation(atoi(sep->arg[2]));
}
}
void command_texture(Client *c, const Seperator *sep)
{
@@ -2776,7 +2889,7 @@ void command_npctypespawn(Client *c, const Seperator *sep)
const NPCType* tmp = 0;
if ((tmp = database.LoadNPCTypesData(atoi(sep->arg[1])))) {
//tmp->fixedZ = 1;
auto npc = new NPC(tmp, 0, c->GetPosition(), FlyMode3);
auto npc = new NPC(tmp, 0, c->GetPosition(), GravityBehavior::Water);
if (npc && sep->IsNumber(2))
npc->SetNPCFactionID(atoi(sep->arg[2]));
@@ -4317,18 +4430,94 @@ void command_fixmob(Client *c, const Seperator *sep)
void command_gmspeed(Client *c, const Seperator *sep)
{
bool state=atobool(sep->arg[1]);
Client *t=c;
bool state = atobool(sep->arg[1]);
Client *t = c;
if(c->GetTarget() && c->GetTarget()->IsClient())
t=c->GetTarget()->CastToClient();
if(sep->arg[1][0] != 0) {
database.SetGMSpeed(t->AccountID(), state?1:0);
c->Message(0, "Turning GMSpeed %s for %s (zone to take effect)", state?"On":"Off", t->GetName());
if (c->GetTarget() && c->GetTarget()->IsClient()) {
t = c->GetTarget()->CastToClient();
}
else
if (sep->arg[1][0] != 0) {
database.SetGMSpeed(t->AccountID(), state ? 1 : 0);
c->Message(0, "Turning GMSpeed %s for %s (zone to take effect)", state ? "On" : "Off", t->GetName());
}
else {
c->Message(0, "Usage: #gmspeed [on/off]");
}
}
void command_gmzone(Client *c, const Seperator *sep)
{
if (!sep->arg[1]) {
c->Message(0, "Usage");
c->Message(0, "-------");
c->Message(0, "#gmzone [zone_short_name] [zone_version=0]");
return;
}
std::string zone_short_name_string = sep->arg[1];
const char *zone_short_name = sep->arg[1];
auto zone_version = static_cast<uint32>(sep->arg[2] ? atoi(sep->arg[2]) : 0);
std::string identifier = "gmzone";
uint32 zone_id = database.GetZoneID(zone_short_name);
uint32 duration = 100000000;
uint16 instance_id = 0;
if (zone_id == 0) {
c->Message(13, "Invalid zone specified");
return;
}
if (sep->arg[3] && sep->arg[3][0]) {
identifier = sep->arg[3];
}
std::string bucket_key = StringFormat("%s-%s-instance", zone_short_name, identifier.c_str());
std::string existing_zone_instance = DataBucket::GetData(bucket_key);
if (existing_zone_instance.length() > 0) {
instance_id = std::stoi(existing_zone_instance);
c->Message(15, "Found already created instance (%s) (%u)", zone_short_name, instance_id);
}
if (instance_id == 0) {
if (!database.GetUnusedInstanceID(instance_id)) {
c->Message(13, "Server was unable to find a free instance id.");
return;
}
if (!database.CreateInstance(instance_id, zone_id, zone_version, duration)) {
c->Message(13, "Server was unable to create a new instance.");
return;
}
c->Message(15, "New private GM instance %s was created with id %lu.", zone_short_name, (unsigned long) instance_id);
DataBucket::SetData(bucket_key, std::to_string(instance_id));
}
if (instance_id > 0) {
float target_x = -1, target_y = -1, target_z = -1;
int16 min_status = 0;
uint8 min_level = 0;
if (!database.GetSafePoints(
zone_short_name,
zone_version,
&target_x,
&target_y,
&target_z,
&min_status,
&min_level
)) {
c->Message(13, "Failed to find safe coordinates for specified zone");
}
c->Message(15, "Zoning to private GM instance (%s) (%u)", zone_short_name, instance_id);
c->AssignToInstance(instance_id);
c->MovePC(zone_id, instance_id, target_x, target_y, target_z, 0, 1);
}
}
void command_title(Client *c, const Seperator *sep)
@@ -4511,7 +4700,7 @@ void command_memspell(Client *c, const Seperator *sep)
{
slot = atoi(sep->arg[1]) - 1;
spell_id = atoi(sep->arg[2]);
if (slot > MAX_PP_MEMSPELL || spell_id >= SPDAT_RECORDS)
if (slot > EQEmu::spells::SPELL_GEM_COUNT || spell_id >= SPDAT_RECORDS)
{
c->Message(0, "Error: #MemSpell: Arguement out of range");
}
@@ -4839,6 +5028,78 @@ void command_push(Client *c, const Seperator *sep)
}
}
void command_proximity(Client *c, const Seperator *sep)
{
if (!c->GetTarget() && !c->GetTarget()->IsNPC()) {
c->Message(0, "You must target an NPC");
return;
}
for (auto &iter : entity_list.GetNPCList()) {
auto npc = iter.second;
std::string name = npc->GetName();
if (name.find("Proximity") != std::string::npos) {
npc->Depop();
}
}
NPC *npc = c->GetTarget()->CastToNPC();
std::vector<FindPerson_Point> points;
FindPerson_Point p{};
if (npc->IsProximitySet()) {
glm::vec4 position;
position.w = npc->GetHeading();
position.x = npc->GetProximityMinX();
position.y = npc->GetProximityMinY();
position.z = npc->GetZ();
position.x = npc->GetProximityMinX();
position.y = npc->GetProximityMinY();
NPC::SpawnNodeNPC("Proximity", "", position);
position.x = npc->GetProximityMinX();
position.y = npc->GetProximityMaxY();
NPC::SpawnNodeNPC("Proximity", "", position);
position.x = npc->GetProximityMaxX();
position.y = npc->GetProximityMinY();
NPC::SpawnNodeNPC("Proximity", "", position);
position.x = npc->GetProximityMaxX();
position.y = npc->GetProximityMaxY();
NPC::SpawnNodeNPC("Proximity", "", position);
p.x = npc->GetProximityMinX();
p.y = npc->GetProximityMinY();
p.z = npc->GetZ();
points.push_back(p);
p.x = npc->GetProximityMinX();
p.y = npc->GetProximityMaxY();
points.push_back(p);
p.x = npc->GetProximityMaxX();
p.y = npc->GetProximityMaxY();
points.push_back(p);
p.x = npc->GetProximityMaxX();
p.y = npc->GetProximityMinY();
points.push_back(p);
p.x = npc->GetProximityMinX();
p.y = npc->GetProximityMinY();
points.push_back(p);
}
if (c->ClientVersion() >= EQEmu::versions::ClientVersion::RoF) {
c->SendPathPacket(points);
}
}
void command_pvp(Client *c, const Seperator *sep)
{
bool state=atobool(sep->arg[1]);
@@ -4976,6 +5237,49 @@ void command_kill(Client *c, const Seperator *sep)
c->GetTarget()->Kill();
}
void command_killallnpcs(Client *c, const Seperator *sep)
{
std::string search_string;
if (sep->arg[1]) {
search_string = sep->arg[1];
}
int count = 0;
for (auto &itr : entity_list.GetMobList()) {
Mob *entity = itr.second;
if (!entity->IsNPC()) {
continue;
}
std::string entity_name = entity->GetName();
/**
* Filter by name
*/
if (search_string.length() > 0 && entity_name.find(search_string) == std::string::npos) {
continue;
}
bool is_not_attackable =
(
entity->IsInvisible() ||
!entity->IsAttackAllowed(c) ||
entity->GetRace() == 127 ||
entity->GetRace() == 240
);
if (is_not_attackable) {
continue;
}
entity->Damage(c, 1000000000, 0, EQEmu::skills::SkillDragonPunch);
count++;
}
c->Message(15, "Killed (%i) npc(s)", count);
}
void command_haste(Client *c, const Seperator *sep)
{
// #haste command to set client attack speed. Takes a percentage (100 = twice normal attack speed)
@@ -5133,13 +5437,65 @@ void command_loc(Client *c, const Seperator *sep)
void command_goto(Client *c, const Seperator *sep)
{
// goto function
if (sep->arg[1][0] == '\0' && c->GetTarget())
c->MovePC(zone->GetZoneID(), zone->GetInstanceID(), c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ(), c->GetTarget()->GetHeading());
else if (!(sep->IsNumber(1) && sep->IsNumber(2) && sep->IsNumber(3)))
/**
* Goto via target and no args
*/
if (sep->arg[1][0] == '\0' && c->GetTarget()) {
c->MovePC(
zone->GetZoneID(),
zone->GetInstanceID(),
c->GetTarget()->GetX(),
c->GetTarget()->GetY(),
c->GetTarget()->GetZ(),
c->GetTarget()->GetHeading());
}
/**
* Goto via player name
*/
else if (!sep->IsNumber(1) && sep->arg[1]) {
/**
* Find them in zone first
*/
const char *player_name = sep->arg[1];
std::string player_name_string = sep->arg[1];
Client *client = entity_list.GetClientByName(player_name);
if (client) {
c->MovePC(
zone->GetZoneID(),
zone->GetInstanceID(),
client->GetX(),
client->GetY(),
client->GetZ(),
client->GetHeading());
c->Message(15, "Goto player '%s' same zone", player_name_string.c_str());
}
else if (c->GotoPlayer(player_name_string)) {
c->Message(15, "Goto player '%s' different zone", player_name_string.c_str());
}
else {
c->Message(15, "Player '%s' not found", player_name_string.c_str());
}
}
/**
* Goto via x y z
*/
else if (sep->IsNumber(1) && sep->IsNumber(2) && sep->IsNumber(3)) {
c->MovePC(
zone->GetZoneID(),
zone->GetInstanceID(),
atof(sep->arg[1]),
atof(sep->arg[2]),
atof(sep->arg[3]),
c->GetHeading());
}
else {
c->Message(0, "Usage: #goto [x y z]");
else
c->MovePC(zone->GetZoneID(), zone->GetInstanceID(), atof(sep->arg[1]), atof(sep->arg[2]), atof(sep->arg[3]), c->GetHeading());
c->Message(0, "Usage: #goto [player_name]");
}
}
void command_iteminfo(Client *c, const Seperator *sep)
@@ -6085,7 +6441,7 @@ void command_scribespells(Client *c, const Seperator *sep)
c->Message(0, "Scribing spells for %s.", t->GetName());
Log(Logs::General, Logs::Normal, "Scribe spells request for %s from %s, levels: %u -> %u", t->GetName(), c->GetName(), min_level, max_level);
for(curspell = 0, book_slot = t->GetNextAvailableSpellBookSlot(), count = 0; curspell < SPDAT_RECORDS && book_slot < MAX_PP_SPELLBOOK; curspell++, book_slot = t->GetNextAvailableSpellBookSlot(book_slot))
for(curspell = 0, book_slot = t->GetNextAvailableSpellBookSlot(), count = 0; curspell < SPDAT_RECORDS && book_slot < EQEmu::spells::SPELLBOOK_SIZE; curspell++, book_slot = t->GetNextAvailableSpellBookSlot(book_slot))
{
if
(
@@ -7807,10 +8163,8 @@ void command_pf(Client *c, const Seperator *sep)
Mob *who = c->GetTarget();
c->Message(0, "POS: (%.2f, %.2f, %.2f)", who->GetX(), who->GetY(), who->GetZ());
c->Message(0, "WP: %s (%d/%d)", to_string(who->GetCurrentWayPoint()).c_str(), who->IsNPC()?who->CastToNPC()->GetMaxWp():-1);
c->Message(0, "TAR: (%.2f, %.2f, %.2f)", who->GetTarX(), who->GetTarY(), who->GetTarZ());
c->Message(0, "TARV: (%.2f, %.2f, %.2f)", who->GetTarVX(), who->GetTarVY(), who->GetTarVZ());
c->Message(0, "|TV|=%.2f index=%d", who->GetTarVector(), who->GetTarNDX());
c->Message(0, "pause=%d RAspeed=%d", who->GetCWPP(), who->GetRunAnimSpeed());
//who->DumpMovement(c);
} else {
c->Message(0, "ERROR: target required");
}
@@ -8131,7 +8485,7 @@ void command_rules(Client *c, const Seperator *sep) {
c->Message(0, "(%d) %s", cur->first, cur->second.c_str());
}
} else if(!strcasecmp(sep->arg[1], "reload")) {
RuleManager::Instance()->LoadRules(&database, RuleManager::Instance()->GetActiveRuleset());
RuleManager::Instance()->LoadRules(&database, RuleManager::Instance()->GetActiveRuleset(), true);
c->Message(0, "The active ruleset (%s (%d)) has been reloaded", RuleManager::Instance()->GetActiveRuleset(),
RuleManager::Instance()->GetActiveRulesetID());
} else if(!strcasecmp(sep->arg[1], "switch")) {
@@ -8147,7 +8501,7 @@ void command_rules(Client *c, const Seperator *sep) {
}
//TODO: we likely want to reload this ruleset everywhere...
RuleManager::Instance()->LoadRules(&database, sep->arg[2]);
RuleManager::Instance()->LoadRules(&database, sep->arg[2], true);
c->Message(0, "The selected ruleset has been changed to (%s (%d)) and reloaded locally", sep->arg[2], rsid);
} else if(!strcasecmp(sep->arg[1], "load")) {
@@ -8157,7 +8511,7 @@ void command_rules(Client *c, const Seperator *sep) {
c->Message(13, "Unknown rule set '%s'", sep->arg[2]);
return;
}
RuleManager::Instance()->LoadRules(&database, sep->arg[2]);
RuleManager::Instance()->LoadRules(&database, sep->arg[2], true);
c->Message(0, "Loaded ruleset '%s' (%d) locally", sep->arg[2], rsid);
} else if(!strcasecmp(sep->arg[1], "store")) {
if(sep->argnum == 1) {
@@ -8181,9 +8535,9 @@ void command_rules(Client *c, const Seperator *sep) {
return;
}
} else if(!strcasecmp(sep->arg[1], "reset")) {
RuleManager::Instance()->ResetRules();
RuleManager::Instance()->ResetRules(true);
c->Message(0, "The running ruleset has been set to defaults");
} else if(!strcasecmp(sep->arg[1], "get")) {
if(sep->argnum != 2) {
c->Message(13, "Invalid argument count, see help.");
@@ -8200,7 +8554,7 @@ void command_rules(Client *c, const Seperator *sep) {
c->Message(13, "Invalid argument count, see help.");
return;
}
if(!RuleManager::Instance()->SetRule(sep->arg[2], sep->arg[3])) {
if(!RuleManager::Instance()->SetRule(sep->arg[2], sep->arg[3], nullptr, false, true)) {
c->Message(13, "Failed to modify rule");
} else {
c->Message(0, "Rule modified locally.");
@@ -8210,7 +8564,7 @@ void command_rules(Client *c, const Seperator *sep) {
c->Message(13, "Invalid argument count, see help.");
return;
}
if(!RuleManager::Instance()->SetRule(sep->arg[2], sep->arg[3], &database, true)) {
if(!RuleManager::Instance()->SetRule(sep->arg[2], sep->arg[3], &database, true, true)) {
c->Message(13, "Failed to modify rule");
} else {
c->Message(0, "Rule modified locally and in the database.");
@@ -8733,9 +9087,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep)
}
c->Message(0, "Updating coordinates successful.");
target->CastToNPC()->GMMove(c->GetX(), c->GetY(), c->GetZ(), c->GetHeading());
target->CastToNPC()->SaveGuardSpot(true);
target->SendPosition();
target->GMMove(c->GetX(), c->GetY(), c->GetZ(), c->GetHeading());
return;
}
@@ -11573,6 +11925,126 @@ void command_scale(Client *c, const Seperator *sep)
}
}
void command_who(Client *c, const Seperator *sep)
{
std::string query =
"SELECT\n"
" character_data.account_id,\n"
" character_data.name,\n"
" character_data.zone_id,\n"
" COALESCE((select zone.short_name from zone where zoneidnumber = character_data.zone_id LIMIT 1), \"Not Found\") as zone_name,\n"
" character_data.zone_instance,\n"
" COALESCE((select guilds.name from guilds where id = ((select guild_id from guild_members where char_id = character_data.id))), \"\") as guild_name,\n"
" character_data.level,\n"
" character_data.race,\n"
" character_data.class,\n"
" COALESCE((select account.status from account where account.id = character_data.account_id LIMIT 1), 0) as account_status,\n"
" COALESCE((select account.name from account where account.id = character_data.account_id LIMIT 1), \"\") as account_name,\n"
" COALESCE((select account_ip.ip from account_ip where account_ip.accid = character_data.account_id ORDER BY account_ip.lastused DESC LIMIT 1), \"\") as account_ip\n"
"FROM\n"
" character_data\n"
"WHERE\n"
" last_login > (UNIX_TIMESTAMP() - 600)\n"
"ORDER BY character_data.name;";
auto results = database.QueryDatabase(query);
if (!results.Success())
return;
if (results.RowCount() == 0) {
c->Message(15, "No results found");
return;
}
std::string search_string;
if (sep->arg[1]) {
search_string = str_tolower(sep->arg[1]);
}
int found_count = 0;
c->Message(5, "Players in EverQuest");
c->Message(5, "--------------------");
for (auto row = results.begin(); row != results.end(); ++row) {
auto account_id = static_cast<uint32>(atoi(row[0]));
std::string player_name = row[1];
auto zone_id = static_cast<uint32>(atoi(row[2]));
std::string zone_short_name = row[3];
auto zone_instance = static_cast<uint32>(atoi(row[4]));
std::string guild_name = row[5];
auto player_level = static_cast<uint32>(atoi(row[6]));
auto player_race = static_cast<uint32>(atoi(row[7]));
auto player_class = static_cast<uint32>(atoi(row[8]));
auto account_status = static_cast<uint32>(atoi(row[9]));
std::string account_name = row[10];
std::string account_ip = row[11];
std::string base_class_name = GetClassIDName(static_cast<uint8>(player_class), 1);
std::string displayed_race_name = GetRaceIDName(static_cast<uint16>(player_race));
if (search_string.length() > 0) {
bool found_search_term =
(
str_tolower(player_name).find(search_string) != std::string::npos ||
str_tolower(zone_short_name).find(search_string) != std::string::npos ||
str_tolower(displayed_race_name).find(search_string) != std::string::npos ||
str_tolower(base_class_name).find(search_string) != std::string::npos ||
str_tolower(guild_name).find(search_string) != std::string::npos ||
str_tolower(account_name).find(search_string) != std::string::npos ||
str_tolower(account_ip).find(search_string) != std::string::npos
);
if (!found_search_term) {
continue;
}
}
std::string displayed_guild_name;
if (guild_name.length() > 0) {
displayed_guild_name = EQEmu::SayLinkEngine::GenerateQuestSaylink(
StringFormat(
"#who \"%s\"",
guild_name.c_str()),
false,
StringFormat("<%s>", guild_name.c_str())
);
}
std::string goto_saylink = EQEmu::SayLinkEngine::GenerateQuestSaylink(
StringFormat("#goto %s", player_name.c_str()), false, "Goto"
);
std::string display_class_name = GetClassIDName(static_cast<uint8>(player_class), static_cast<uint8>(player_level));
c->Message(
5, "%s[%u %s] %s (%s) %s ZONE: %s (%u) (%s) (%s) (%s)",
(account_status > 0 ? "* GM * " : ""),
player_level,
EQEmu::SayLinkEngine::GenerateQuestSaylink(StringFormat("#who %s", base_class_name.c_str()), false, display_class_name).c_str(),
player_name.c_str(),
EQEmu::SayLinkEngine::GenerateQuestSaylink(StringFormat("#who %s", displayed_race_name.c_str()), false, displayed_race_name).c_str(),
displayed_guild_name.c_str(),
EQEmu::SayLinkEngine::GenerateQuestSaylink(StringFormat("#who %s", zone_short_name.c_str()), false, zone_short_name).c_str(),
zone_instance,
goto_saylink.c_str(),
EQEmu::SayLinkEngine::GenerateQuestSaylink(StringFormat("#who %s", account_name.c_str()), false, account_name).c_str(),
EQEmu::SayLinkEngine::GenerateQuestSaylink(StringFormat("#who %s", account_ip.c_str()), false, account_ip).c_str()
);
found_count++;
}
std::string message = (
found_count > 0 ?
StringFormat("There is %i player(s) in EverQuest", found_count).c_str() :
"There are no players in EverQuest that match those who filters."
);
c->Message(5, message.c_str());
}
// All new code added to command.cpp should be BEFORE this comment line. Do no append code to this file below the BOTS code block.
#ifdef BOTS
#include "bot_command.h"
+6
View File
@@ -117,6 +117,7 @@ void command_givemoney(Client *c, const Seperator *sep);
void command_globalview(Client* c, const Seperator *sep);
void command_gm(Client *c, const Seperator *sep);
void command_gmspeed(Client *c, const Seperator *sep);
void command_gmzone(Client *c, const Seperator *sep);
void command_goto(Client *c, const Seperator *sep);
void command_grid(Client *c, const Seperator *sep);
void command_guild(Client *c, const Seperator *sep);
@@ -149,6 +150,7 @@ void command_iteminfo(Client *c, const Seperator *sep);
void command_itemsearch(Client *c, const Seperator *sep);
void command_itemtest(Client *c, const Seperator *sep);
void command_kick(Client *c, const Seperator *sep);
void command_killallnpcs(Client *c, const Seperator *sep);
void command_kill(Client *c, const Seperator *sep);
void command_lastname(Client *c, const Seperator *sep);
void command_level(Client *c, const Seperator *sep);
@@ -170,6 +172,7 @@ void command_merchantopenshop(Client *c, const Seperator *sep);
void command_modifynpcstat(Client *c, const Seperator *sep);
void command_motd(Client *c, const Seperator *sep);
void command_movechar(Client *c, const Seperator *sep);
void command_movement(Client *c, const Seperator *sep);
void command_myskills(Client *c, const Seperator *sep);
void command_mysql(Client *c, const Seperator *sep);
void command_mysqltest(Client *c, const Seperator *sep);
@@ -213,6 +216,7 @@ void command_profiledump(Client *c, const Seperator *sep);
void command_profilereset(Client *c, const Seperator *sep);
#endif
void command_proximity(Client *c, const Seperator *sep);
void command_push(Client *c, const Seperator *sep);
void command_pvp(Client *c, const Seperator *sep);
void command_qglobal(Client *c, const Seperator *sep);
@@ -295,6 +299,7 @@ void command_task(Client *c, const Seperator *sep);
void command_tattoo(Client *c, const Seperator *sep);
void command_tempname(Client *c, const Seperator *sep);
void command_petname(Client *c, const Seperator *sep);
void command_test(Client *c, const Seperator *sep);
void command_testspawn(Client *c, const Seperator *sep);
void command_testspawnkill(Client *c, const Seperator *sep);
void command_texture(Client *c, const Seperator *sep);
@@ -321,6 +326,7 @@ void command_viewnpctype(Client *c, const Seperator *sep);
void command_viewpetition(Client *c, const Seperator *sep);
void command_wc(Client *c, const Seperator *sep);
void command_weather(Client *c, const Seperator *sep);
void command_who(Client *c, const Seperator *sep);
void command_worldshutdown(Client *c, const Seperator *sep);
void command_wp(Client *c, const Seperator *sep);
void command_wpadd(Client *c, const Seperator *sep);
-2
View File
@@ -206,8 +206,6 @@ typedef enum { //fear states
fearStateStuck //I cannot move somehow...
} FearState;
enum { FlyMode0 = 0, FlyMode1 = 1, Flymode2 = 2, FlyMode3 = 3 };
// This is actually FlyMode, from MQ2
enum GravityBehavior {
Ground,
+3 -3
View File
@@ -1374,7 +1374,7 @@ void Corpse::QueryLoot(Client* to) {
cur = itemlist.begin();
end = itemlist.end();
int corpselootlimit = EQEmu::inventory::Lookup(EQEmu::versions::ConvertClientVersionToMobVersion(to->ClientVersion()))->InventoryTypeSize[EQEmu::invtype::typeCorpse];
int corpselootlimit = to->GetInv().GetLookup()->InventoryTypeSize.Corpse;
for(; cur != end; ++cur) {
ServerLootItem_Struct* sitem = *cur;
@@ -1479,7 +1479,7 @@ void Corpse::Spawn() {
safe_delete(app);
}
uint32 Corpse::GetEquipment(uint8 material_slot) const {
uint32 Corpse::GetEquippedItemFromTextureSlot(uint8 material_slot) const {
int16 invslot;
if (material_slot > EQEmu::textures::LastTexture) {
@@ -1500,7 +1500,7 @@ uint32 Corpse::GetEquipmentColor(uint8 material_slot) const {
return 0;
}
item = database.GetItem(GetEquipment(material_slot));
item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
if(item != 0) {
return (item_tint.Slot[material_slot].UseTint ? item_tint.Slot[material_slot].Color : item->Color);
}
+1 -1
View File
@@ -126,7 +126,7 @@ class Corpse : public Mob {
void Spawn();
char corpse_name[64];
uint32 GetEquipment(uint8 material_slot) const;
uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const;
uint32 GetEquipmentColor(uint8 material_slot) const;
inline int GetRezExp() { return rez_experience; }
+1 -1
View File
@@ -496,7 +496,7 @@ void Doors::HandleClick(Client* sender, uint8 trigger) {
}
}
void Doors::NPCOpen(NPC* sender, bool alt_mode)
void Doors::Open(Mob* sender, bool alt_mode)
{
if (sender) {
if (GetTriggerType() == 255 || GetTriggerDoorID() > 0 || GetLockpick() != 0 || GetKeyItem() != 0 || open_type == 59 || open_type == 58 || !sender->IsNPC()) { // this object isnt triggered or door is locked - NPCs should not open locked doors!
+1 -1
View File
@@ -49,7 +49,7 @@ public:
void ForceClose(Mob *sender, bool alt_mode = false);
void ForceOpen(Mob *sender, bool alt_mode = false);
void HandleClick(Client *sender, uint8 trigger);
void NPCOpen(NPC *sender, bool alt_mode = false);
void Open(Mob *sender, bool alt_mode = false);
void SetDisableTimer(bool flag);
void SetDoorName(const char *name);
void SetEntityID(uint32 entity) { entity_id = entity; }
+3 -3
View File
@@ -643,9 +643,9 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
}
if (reduced_recast > 0)
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
CastSpell(spell_id, target, EQEmu::spells::CastingSlot::Discipline, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
else{
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline);
CastSpell(spell_id, target, EQEmu::spells::CastingSlot::Discipline);
return true;
}
@@ -653,7 +653,7 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
}
else
{
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline);
CastSpell(spell_id, target, EQEmu::spells::CastingSlot::Discipline);
}
return(true);
}
+34 -2
View File
@@ -3203,9 +3203,9 @@ XS(XS__FlyMode);
XS(XS__FlyMode) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::FlyMode(uint8 mode [0-3])");
Perl_croak(aTHX_ "Usage: quest::FlyMode(uint8 mode [0-5])");
uint8 flymode = (int) SvUV(ST(0));
GravityBehavior flymode = (GravityBehavior) SvUV(ST(0));
quest_manager.FlyMode(flymode);
XSRETURN_EMPTY;
@@ -3622,6 +3622,36 @@ XS(XS__UpdateZoneHeader) {
XSRETURN_EMPTY;
}
XS(XS__set_rule);
XS(XS__set_rule) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: quest::set_rule(string rule_name, string rule_value)");
std::string rule_name = (std::string) SvPV_nolen(ST(0));
std::string rule_value = (std::string) SvPV_nolen(ST(1));
RuleManager::Instance()->SetRule(rule_name.c_str(), rule_value.c_str());
XSRETURN_EMPTY;
}
XS(XS__get_rule);
XS(XS__get_rule) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::get_rule(string rule_name)");
dXSTARG;
std::string rule_name = (std::string) SvPV_nolen(ST(0));
std::string rule_value;
RuleManager::Instance()->GetRule(rule_name.c_str(), rule_value);
sv_setpv(TARG, rule_value.c_str());
XSprePUSH;
PUSHTARG;
XSRETURN(1);
}
XS(XS__get_data);
XS(XS__get_data) {
dXSARGS;
@@ -3734,6 +3764,8 @@ EXTERN_C XS(boot_quest) {
newXS(strcpy(buf, "GetTimeSeconds"), XS__GetTimeSeconds, file);
newXS(strcpy(buf, "GetZoneID"), XS__GetZoneID, file);
newXS(strcpy(buf, "GetZoneLongName"), XS__GetZoneLongName, file);
newXS(strcpy(buf, "set_rule"), XS__set_rule, file);
newXS(strcpy(buf, "get_rule"), XS__get_rule, file);
newXS(strcpy(buf, "get_data"), XS__get_data, file);
newXS(strcpy(buf, "get_data_expires"), XS__get_data_expires, file);
newXS(strcpy(buf, "set_data"), XS__set_data, file);
+51 -96
View File
@@ -650,8 +650,6 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
npc->FixZ();
uint16 emoteid = npc->GetEmoteID();
if (emoteid != 0)
npc->DoNPCEmote(ONSPAWN, emoteid);
@@ -1274,32 +1272,35 @@ void EntityList::SendZoneSpawns(Client *client)
void EntityList::SendZoneSpawnsBulk(Client *client)
{
NewSpawn_Struct ns;
Mob *spawn;
uint32 maxspawns = 100;
NewSpawn_Struct ns{};
Mob *spawn;
EQApplicationPacket *app;
if (maxspawns > mob_list.size())
maxspawns = mob_list.size();
auto bzsp = new BulkZoneSpawnPacket(client, maxspawns);
uint32 max_spawns = 100;
if (max_spawns > mob_list.size()) {
max_spawns = static_cast<uint32>(mob_list.size());
}
auto bulk_zone_spawn_packet = new BulkZoneSpawnPacket(client, max_spawns);
const glm::vec4 &client_position = client->GetPosition();
const float distance_max = (600.0 * 600.0);
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) {
spawn = it->second;
if (spawn && spawn->GetID() > 0 && spawn->Spawned()) {
if (!spawn->ShouldISpawnFor(client))
if (!spawn->ShouldISpawnFor(client)) {
continue;
}
#if 1
const glm::vec4& spos = spawn->GetPosition();
const glm::vec4 &spawn_position = spawn->GetPosition();
delaypkt = false;
if (DistanceSquared(cpos, spos) > dmax || (spawn->IsClient() && (spawn->GetRace() == MINOR_ILL_OBJ || spawn->GetRace() == TREE)))
delaypkt = true;
bool is_delayed_packet = (
DistanceSquared(client_position, spawn_position) > distance_max ||
(spawn->IsClient() && (spawn->GetRace() == MINOR_ILL_OBJ || spawn->GetRace() == TREE))
);
if (delaypkt) {
if (is_delayed_packet) {
app = new EQApplicationPacket;
spawn->CreateSpawnPacket(app);
client->QueuePacket(app, true, Client::CLIENT_CONNECTED);
@@ -1308,35 +1309,38 @@ void EntityList::SendZoneSpawnsBulk(Client *client)
else {
memset(&ns, 0, sizeof(NewSpawn_Struct));
spawn->FillSpawnStruct(&ns, client);
bzsp->AddSpawn(&ns);
bulk_zone_spawn_packet->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
// But they will work as an add_spawn AFTER CLIENT_CONNECTED.
if (spawn->IsClient() && (race == MINOR_ILL_OBJ || race == TREE)) {
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);
}
// Despite being sent in the OP_ZoneSpawns packet, the client
// does not display worn armor correctly so display it.
spawn->SendArmorAppearance(client);
#endif
/**
* Original code kept for spawn packet research
*
* int32 race = spawn->GetRace();
*
* Illusion races on PCs don't work as a mass spawn
* But they will work as an add_spawn AFTER CLIENT_CONNECTED.
* if (spawn->IsClient() && (race == MINOR_ILL_OBJ || race == TREE)) {
* 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);
* }
*
* Despite being sent in the OP_ZoneSpawns packet, the client
* does not display worn armor correctly so display it.
* spawn->SendArmorAppearance(client);
*/
}
}
safe_delete(bzsp);
safe_delete(bulk_zone_spawn_packet);
}
//this is a hack to handle a broken spawn struct
@@ -1558,7 +1562,7 @@ void EntityList::QueueClientsByTarget(Mob *sender, const EQApplicationPacket *ap
}
}
void EntityList::QueueClientsByXTarget(Mob *sender, const EQApplicationPacket *app, bool iSendToSender, EQEmu::versions::ClientVersionBit client_version_bits)
void EntityList::QueueClientsByXTarget(Mob *sender, const EQApplicationPacket *app, bool iSendToSender, EQEmu::versions::ClientVersionBitmask client_version_bits)
{
auto it = client_list.begin();
while (it != client_list.end()) {
@@ -2652,56 +2656,6 @@ void EntityList::RemoveDebuffs(Mob *caster)
}
}
// Currently, a new packet is sent per entity.
// @todo: Come back and use FLAG_COMBINED to pack
// all updates into one packet.
void EntityList::SendPositionUpdates(Client *client, uint32 cLastUpdate, float update_range, Entity *always_send, bool iSendEvenIfNotChanged)
{
update_range = (update_range * update_range);
EQApplicationPacket *outapp = 0;
PlayerPositionUpdateServer_Struct *ppu = 0;
Mob *mob = 0;
auto it = mob_list.begin();
while (it != mob_list.end()) {
mob = it->second;
if (
mob && !mob->IsCorpse()
&& (it->second != client)
&& (mob->IsClient() || iSendEvenIfNotChanged || (mob->LastChange() >= cLastUpdate))
&& (it->second->ShouldISpawnFor(client))
) {
if (
update_range == 0
|| (it->second == always_send)
|| mob->IsClient()
|| (DistanceSquared(mob->GetPosition(), client->GetPosition()) <= update_range)
) {
if (mob && mob->IsClient() && mob->GetID() > 0) {
client->QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
if (outapp == 0) {
outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
ppu = (PlayerPositionUpdateServer_Struct*)outapp->pBuffer;
}
mob->MakeSpawnUpdate(ppu);
safe_delete(outapp);
outapp = 0;
}
}
}
++it;
}
safe_delete(outapp);
}
char *EntityList::MakeNameUnique(char *name)
{
bool used[300];
@@ -3213,7 +3167,7 @@ void EntityList::AddHealAggro(Mob *target, Mob *caster, uint16 hate)
}
}
void EntityList::OpenDoorsNear(NPC *who)
void EntityList::OpenDoorsNear(Mob *who)
{
for (auto it = door_list.begin();it != door_list.end(); ++it) {
@@ -3226,7 +3180,7 @@ void EntityList::OpenDoorsNear(NPC *who)
float curdist = diff.x * diff.x + diff.y * diff.y;
if (diff.z * diff.z < 10 && curdist <= 100)
cdoor->NPCOpen(who);
cdoor->Open(who);
}
}
@@ -4017,8 +3971,9 @@ Mob *EntityList::GetTargetForMez(Mob *caster)
void EntityList::SendZoneAppearance(Client *c)
{
if (!c)
if (!c) {
return;
}
auto it = mob_list.begin();
while (it != mob_list.end()) {
@@ -4033,7 +3988,7 @@ void EntityList::SendZoneAppearance(Client *c)
cur->SendAppearancePacket(AT_Anim, cur->GetAppearanceValue(cur->GetAppearance()), false, true, c);
}
if (cur->GetSize() != cur->GetBaseSize()) {
cur->SendAppearancePacket(AT_Size, (uint32)cur->GetSize(), false, true, c);
cur->SendAppearancePacket(AT_Size, (uint32) cur->GetSize(), false, true, c);
}
}
++it;
+2 -3
View File
@@ -353,7 +353,7 @@ public:
void QueueClientsByTarget(Mob* sender, const EQApplicationPacket* app, bool iSendToSender = true, Mob* SkipThisMob = 0, bool ackreq = true,
bool HoTT = true, uint32 ClientVersionBits = 0xFFFFFFFF, bool inspect_buffs = false);
void QueueClientsByXTarget(Mob* sender, const EQApplicationPacket* app, bool iSendToSender = true, EQEmu::versions::ClientVersionBit client_version_bits = EQEmu::versions::ClientVersionBit::bit_AllClients);
void QueueClientsByXTarget(Mob* sender, const EQApplicationPacket* app, bool iSendToSender = true, EQEmu::versions::ClientVersionBitmask client_version_bits = EQEmu::versions::ClientVersionBitmask::maskAllClients);
void QueueToGroupsForNPCHealthAA(Mob* sender, const EQApplicationPacket* app);
void QueueManaged(Mob* sender, const EQApplicationPacket* app, bool ignore_sender=false, bool ackreq = true);
@@ -370,9 +370,8 @@ public:
void AddHealAggro(Mob* target, Mob* caster, uint16 hate);
Mob* FindDefenseNPC(uint32 npcid);
void OpenDoorsNear(NPC* opener);
void OpenDoorsNear(Mob* opener);
void UpdateWho(bool iSendFullUpdate = false);
void SendPositionUpdates(Client* client, uint32 cLastUpdate = 0, float update_range = 0, Entity* always_send = 0, bool iSendEvenIfNotChanged = false);
char* MakeNameUnique(char* name);
static char* RemoveNumbers(char* name);
void SignalMobsByNPCID(uint32 npc_type, int signal_id);
+1 -1
View File
@@ -1133,7 +1133,7 @@ uint32 Client::GetCharMaxLevelFromQGlobal() {
uint32 Client::GetCharMaxLevelFromBucket() {
uint32 char_id = this->CharacterID();
std::string query = StringFormat("SELECT value FROM data_buckets WHERE key = '%i-CharMaxLevel'", char_id);
std::string query = StringFormat("SELECT value FROM data_buckets WHERE `key` = '%i-CharMaxLevel'", char_id);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
Log(Logs::General, Logs::Error, "Data bucket for CharMaxLevel for char ID %i failed.", char_id);
+2 -26
View File
@@ -157,10 +157,8 @@ void Mob::ProcessFlee()
void Mob::CalculateNewFearpoint() {
if (RuleB(Pathing, Fear) && zone->pathing) {
auto Node = zone->pathing->GetRandomLocation();
auto Node = zone->pathing->GetRandomLocation(glm::vec3(GetX(), GetY(), GetZ()));
if (Node.x != 0.0f || Node.y != 0.0f || Node.z != 0.0f) {
++Node.z;
m_FearWalkTarget = Node;
currently_fleeing = true;
@@ -169,29 +167,7 @@ void Mob::CalculateNewFearpoint() {
Log(Logs::Detail,
Logs::Pathing,
"No path found to selected node. Falling through to old fear point selection.");
"No path found to selected node during CalculateNewFearpoint.");
}
int loop = 0;
float ranx, rany, ranz;
currently_fleeing = true;
while (loop < 100) //Max 100 tries
{
int ran = 250 - (loop * 2);
loop++;
ranx = GetX() + zone->random.Int(0, ran - 1) - zone->random.Int(0, ran - 1);
rany = GetY() + zone->random.Int(0, ran - 1) - zone->random.Int(0, ran - 1);
ranz = FindGroundZ(ranx, rany);
if (ranz == BEST_Z_INVALID)
continue;
float fdist = ranz - GetZ();
if (fdist >= -12 && fdist <= 12 && CheckCoordLosNoZLeaps(GetX(), GetY(), GetZ(), ranx, rany, ranz)) {
break;
}
}
if (currently_fleeing)
m_FearWalkTarget = glm::vec3(ranx, rany, ranz);
}
+1 -1
View File
@@ -284,7 +284,7 @@ void Client::GoFish()
if (tmp != nullptr) {
auto positionNPC = GetPosition();
positionNPC.x = positionNPC.x + 3;
auto npc = new NPC(tmp, nullptr, positionNPC, FlyMode3);
auto npc = new NPC(tmp, nullptr, positionNPC, GravityBehavior::Water);
npc->AddLootTable();
if (npc->DropsGlobalLoot())
npc->CheckGlobalLootTables();
+1 -1
View File
@@ -691,7 +691,7 @@ void GuildBankManager::SendGuildBank(Client *c)
auto &guild_bank = *Iterator;
// RoF+ uses a bulk list packet -- This is also how the Action 0 of older clients basically works
if (c->ClientVersionBit() & EQEmu::versions::bit_RoFAndLater) {
if (c->ClientVersionBit() & EQEmu::versions::maskRoFAndLater) {
auto outapp = new EQApplicationPacket(OP_GuildBankItemList, sizeof(GuildBankItemListEntry_Struct) * 240);
for (int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) {
const EQEmu::ItemData *Item = database.GetItem(guild_bank->Items.DepositArea[i].ItemID);
-17
View File
@@ -335,15 +335,6 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center, Mob *skip)
continue;
}
auto hateEntryPosition = glm::vec3(cur->entity_on_hatelist->GetX(), cur->entity_on_hatelist->GetY(), cur->entity_on_hatelist->GetZ());
if (center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if (!zone->watermap->InLiquid(hateEntryPosition)) {
skipped_count++;
++iterator;
continue;
}
}
if (cur->entity_on_hatelist->Sanctuary()) {
if (hate == -1)
{
@@ -474,14 +465,6 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center, Mob *skip)
continue;
}
if (center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if(!zone->watermap->InLiquid(glm::vec3(cur->entity_on_hatelist->GetPosition()))) {
skipped_count++;
++iterator;
continue;
}
}
if (cur->entity_on_hatelist != nullptr && ((cur->stored_hate_amount > hate) || cur->is_entity_frenzy))
{
top_hate = cur->entity_on_hatelist;
+2 -2
View File
@@ -30,7 +30,7 @@ std::map<uint16, const NPCType *> Horse::horse_types;
LinkedList<NPCType *> horses_auto_delete;
Horse::Horse(Client *_owner, uint16 spell_id, const glm::vec4& position)
: NPC(GetHorseType(spell_id), nullptr, position, FlyMode3)
: NPC(GetHorseType(spell_id), nullptr, position, GravityBehavior::Water)
{
//give the horse its proper name.
strn0cpy(name, _owner->GetCleanName(), 55);
@@ -90,7 +90,7 @@ const NPCType *Horse::BuildHorseType(uint16 spell_id) {
strcpy(npc_type->name, "Unclaimed_Mount"); // this should never get used
strcpy(npc_type->special_abilities, "19,1^20,1^24,1");
npc_type->cur_hp = 1;
npc_type->current_hp = 1;
npc_type->max_hp = 1;
npc_type->race = atoi(row[0]);
npc_type->gender = atoi(row[1]); // Drogmor's are female horses. Yuck.
+25 -27
View File
@@ -113,7 +113,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) {
x++;
}
DeleteItemInInventory(i, 0, ((i - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank]));
DeleteItemInInventory(i, 0, ((i - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank));
}
}
@@ -126,7 +126,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) {
x++;
}
DeleteItemInInventory(i, 0, (((i - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank]));
DeleteItemInInventory(i, 0, (((i - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT) >= GetInv().GetLookup()->InventoryTypeSize.Bank));
}
}
}
@@ -781,12 +781,12 @@ int32 Client::GetItemIDAt(int16 slot_id) {
return INVALID_ID;
}
else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) {
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank)
return INVALID_ID;
}
else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) {
auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize.Bank)
return INVALID_ID;
}
@@ -811,12 +811,12 @@ int32 Client::GetAugmentIDAt(int16 slot_id, uint8 augslot) {
return INVALID_ID;
}
else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) {
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank)
return INVALID_ID;
}
else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) {
auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize.Bank)
return INVALID_ID;
}
@@ -1474,11 +1474,11 @@ bool Client::IsValidSlot(uint32 slot) {
return ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) != 0);
}
else if (slot <= EQEmu::invslot::BANK_END && slot >= EQEmu::invslot::BANK_BEGIN) {
return ((slot - EQEmu::invslot::BANK_BEGIN) < GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank]);
return ((slot - EQEmu::invslot::BANK_BEGIN) < GetInv().GetLookup()->InventoryTypeSize.Bank);
}
else if (slot <= EQEmu::invbag::BANK_BAGS_END && slot >= EQEmu::invbag::BANK_BAGS_BEGIN) {
auto temp_slot = (slot - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
return (temp_slot < GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank]);
return (temp_slot < GetInv().GetLookup()->InventoryTypeSize.Bank);
}
else if (
(slot == (uint32)INVALID_INDEX) ||
@@ -2500,7 +2500,7 @@ void Client::DisenchantSummonedBags(bool client_update)
}
for (auto slot_id = EQEmu::invslot::BANK_BEGIN; slot_id <= EQEmu::invslot::BANK_END; ++slot_id) {
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank)
continue;
auto inst = m_inv[slot_id];
@@ -2627,7 +2627,7 @@ void Client::RemoveNoRent(bool client_update)
}
for (auto slot_id = EQEmu::invslot::BANK_BEGIN; slot_id <= EQEmu::invslot::BANK_END; ++slot_id) {
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank)
continue;
auto inst = m_inv[slot_id];
@@ -2639,7 +2639,7 @@ void Client::RemoveNoRent(bool client_update)
for (auto slot_id = EQEmu::invbag::BANK_BAGS_BEGIN; slot_id <= EQEmu::invbag::BANK_BAGS_END; ++slot_id) {
auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize.Bank)
continue;
auto inst = m_inv[slot_id];
@@ -2745,7 +2745,7 @@ void Client::RemoveDuplicateLore(bool client_update)
}
for (auto slot_id = EQEmu::invslot::BANK_BEGIN; slot_id <= EQEmu::invslot::BANK_END; ++slot_id) {
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank)
continue;
auto inst = m_inv.PopItem(slot_id);
@@ -2762,7 +2762,7 @@ void Client::RemoveDuplicateLore(bool client_update)
for (auto slot_id = EQEmu::invbag::BANK_BAGS_BEGIN; slot_id <= EQEmu::invbag::BANK_BAGS_END; ++slot_id) {
auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize.Bank)
continue;
auto inst = m_inv.PopItem(slot_id);
@@ -2858,26 +2858,24 @@ void Client::MoveSlotNotAllowed(bool client_update)
}
// these functions operate with a material slot, which is from 0 to 8
uint32 Client::GetEquipment(uint8 material_slot) const
uint32 Client::GetEquippedItemFromTextureSlot(uint8 material_slot) const
{
int16 invslot;
int16 inventory_slot;
const EQEmu::ItemInstance *item;
if(material_slot > EQEmu::textures::LastTexture)
{
if (material_slot > EQEmu::textures::LastTexture) {
return 0;
}
invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
if (invslot == INVALID_INDEX)
{
inventory_slot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
if (inventory_slot == INVALID_INDEX) {
return 0;
}
item = m_inv.GetItem(invslot);
item = m_inv.GetItem(inventory_slot);
if(item && item->GetItem())
{
if (item && item->GetItem()) {
return item->GetItem()->ID;
}
@@ -2889,7 +2887,7 @@ int32 Client::GetEquipmentMaterial(uint8 material_slot)
{
const ItemData *item;
item = database.GetItem(GetEquipment(material_slot));
item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
if(item != 0)
{
return item->Material;
@@ -2904,7 +2902,7 @@ uint32 Client::GetEquipmentColor(uint8 material_slot) const
if (material_slot > EQEmu::textures::LastTexture)
return 0;
const EQEmu::ItemData *item = database.GetItem(GetEquipment(material_slot));
const EQEmu::ItemData *item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
if(item != nullptr)
return ((m_pp.item_tint.Slot[material_slot].UseTint) ? m_pp.item_tint.Slot[material_slot].Color : item->Color);
@@ -2927,12 +2925,12 @@ void Client::SendItemPacket(int16 slot_id, const EQEmu::ItemInstance* inst, Item
return;
}
else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) {
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank)
return;
}
else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) {
auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize.Bank)
return;
}
+12
View File
@@ -1486,6 +1486,16 @@ void Lua_Client::DisableAreaRegens()
self->DisableAreaRegens();
}
void Lua_Client::SetPrimaryWeaponOrnamentation(uint32 model_id) {
Lua_Safe_Call_Void();
self->SetPrimaryWeaponOrnamentation(model_id);
}
void Lua_Client::SetSecondaryWeaponOrnamentation(uint32 model_id) {
Lua_Safe_Call_Void();
self->SetSecondaryWeaponOrnamentation(model_id);
}
luabind::scope lua_register_client() {
return luabind::class_<Lua_Client, Lua_Mob>("Client")
.def(luabind::constructor<>())
@@ -1548,6 +1558,8 @@ luabind::scope lua_register_client() {
.def("GetBindHeading", (float(Lua_Client::*)(int))&Lua_Client::GetBindHeading)
.def("GetBindZoneID", (uint32(Lua_Client::*)(void))&Lua_Client::GetBindZoneID)
.def("GetBindZoneID", (uint32(Lua_Client::*)(int))&Lua_Client::GetBindZoneID)
.def("SetPrimaryWeaponOrnamentation", (void(Lua_Client::*)(uint32))&Lua_Client::SetPrimaryWeaponOrnamentation)
.def("SetSecondaryWeaponOrnamentation", (void(Lua_Client::*)(uint32))&Lua_Client::SetSecondaryWeaponOrnamentation)
.def("MovePC", (void(Lua_Client::*)(int,float,float,float,float))&Lua_Client::MovePC)
.def("MovePCInstance", (void(Lua_Client::*)(int,int,float,float,float,float))&Lua_Client::MovePCInstance)
.def("ChangeLastName", (void(Lua_Client::*)(const char *in))&Lua_Client::ChangeLastName)
+4
View File
@@ -309,6 +309,10 @@ public:
void DisableAreaEndRegen();
void EnableAreaRegens(int value);
void DisableAreaRegens();
void SetPrimaryWeaponOrnamentation(uint32 model_id);
void SetSecondaryWeaponOrnamentation(uint32 model_id);
};
#endif
+2 -2
View File
@@ -231,7 +231,7 @@ void Lua_EntityList::ReplaceWithTarget(Lua_Mob target, Lua_Mob new_target) {
self->ReplaceWithTarget(target, new_target);
}
void Lua_EntityList::OpenDoorsNear(Lua_NPC opener) {
void Lua_EntityList::OpenDoorsNear(Lua_Mob opener) {
Lua_Safe_Call_Void();
self->OpenDoorsNear(opener);
}
@@ -479,7 +479,7 @@ luabind::scope lua_register_entity_list() {
.def("RemoveFromTargets", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::RemoveFromTargets)
.def("RemoveFromTargets", (void(Lua_EntityList::*)(Lua_Mob, bool))&Lua_EntityList::RemoveFromTargets)
.def("ReplaceWithTarget", (void(Lua_EntityList::*)(Lua_Mob, Lua_Mob))&Lua_EntityList::ReplaceWithTarget)
.def("OpenDoorsNear", (void(Lua_EntityList::*)(Lua_NPC))&Lua_EntityList::OpenDoorsNear)
.def("OpenDoorsNear", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::OpenDoorsNear)
.def("MakeNameUnique", (std::string(Lua_EntityList::*)(const char*))&Lua_EntityList::MakeNameUnique)
.def("RemoveNumbers", (std::string(Lua_EntityList::*)(const char*))&Lua_EntityList::RemoveNumbers)
.def("SignalMobsByNPCID", (void(Lua_EntityList::*)(uint32, int))&Lua_EntityList::SignalMobsByNPCID)
+1 -1
View File
@@ -84,7 +84,7 @@ public:
void RemoveFromTargets(Lua_Mob mob);
void RemoveFromTargets(Lua_Mob mob, bool RemoveFromXTargets);
void ReplaceWithTarget(Lua_Mob target, Lua_Mob new_target);
void OpenDoorsNear(Lua_NPC opener);
void OpenDoorsNear(Lua_Mob opener);
std::string MakeNameUnique(const char *name);
std::string RemoveNumbers(const char *name);
void SignalMobsByNPCID(uint32 npc_id, int signal);
+15 -3
View File
@@ -814,6 +814,16 @@ std::string lua_say_link(const char *phrase) {
return quest_manager.saylink(text, false, text);
}
void lua_set_rule(std::string rule_name, std::string rule_value) {
RuleManager::Instance()->SetRule(rule_name.c_str(), rule_value.c_str());
}
std::string lua_get_rule(std::string rule_name) {
std::string rule_value;
RuleManager::Instance()->GetRule(rule_name.c_str(), rule_value);
return rule_value;
}
std::string lua_get_data(std::string bucket_key) {
return DataBucket::GetData(bucket_key);
}
@@ -903,7 +913,7 @@ void lua_flag_instance_by_raid_leader(uint32 zone, uint32 version) {
}
void lua_fly_mode(int flymode) {
quest_manager.FlyMode(flymode);
quest_manager.FlyMode(static_cast<GravityBehavior>(flymode));
}
int lua_faction_value() {
@@ -1413,7 +1423,7 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float
luabind::adl::index_proxy<luabind::adl::object> cur = table["name"];
LuaCreateNPCParseString(name, 64, "_");
LuaCreateNPCParseString(lastname, 64, "");
LuaCreateNPCParse(cur_hp, int32, 30);
LuaCreateNPCParse(current_hp, int32, 30);
LuaCreateNPCParse(max_hp, int32, 30);
LuaCreateNPCParse(size, float, 6.0f);
LuaCreateNPCParse(runspeed, float, 1.25f);
@@ -1511,7 +1521,7 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float
LuaCreateNPCParse(no_target_hotkey, bool, false);
LuaCreateNPCParse(raid_target, bool, false);
NPC* npc = new NPC(npc_type, nullptr, glm::vec4(x, y, z, heading), FlyMode3);
NPC* npc = new NPC(npc_type, nullptr, glm::vec4(x, y, z, heading), GravityBehavior::Water);
npc->GiveNPCTypeData(npc_type);
entity_list.AddNPC(npc);
}
@@ -1687,6 +1697,8 @@ luabind::scope lua_register_general() {
luabind::def("say_link", (std::string(*)(const char*,bool,const char*))&lua_say_link),
luabind::def("say_link", (std::string(*)(const char*,bool))&lua_say_link),
luabind::def("say_link", (std::string(*)(const char*))&lua_say_link),
luabind::def("set_rule", (void(*)(std::string, std::string))&lua_set_rule),
luabind::def("get_rule", (std::string(*)(std::string))&lua_get_rule),
luabind::def("get_data", (std::string(*)(std::string))&lua_get_data),
luabind::def("get_data_expires", (std::string(*)(std::string))&lua_get_data_expires),
luabind::def("set_data", (void(*)(std::string, std::string))&lua_set_data),
+32 -21
View File
@@ -770,28 +770,28 @@ bool Lua_Mob::CastSpell(int spell_id, int target_id) {
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot) {
Lua_Safe_Call_Bool();
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot));
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::spells::CastingSlot>(slot));
}
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time) {
Lua_Safe_Call_Bool();
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time);
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::spells::CastingSlot>(slot), cast_time);
}
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost) {
Lua_Safe_Call_Bool();
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time, mana_cost);
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::spells::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) {
Lua_Safe_Call_Bool();
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot));
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::spells::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,
int timer_duration) {
Lua_Safe_Call_Bool();
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot),
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::spells::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot),
static_cast<uint32>(timer), static_cast<uint32>(timer_duration));
}
@@ -800,7 +800,7 @@ bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, in
Lua_Safe_Call_Bool();
int16 res = resist_adjust;
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot),
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::spells::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot),
static_cast<uint32>(timer), static_cast<uint32>(timer_duration), &res);
}
@@ -811,27 +811,27 @@ bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target) {
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot) {
Lua_Safe_Call_Bool();
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot));
return self->SpellFinished(spell_id, target, static_cast<EQEmu::spells::CastingSlot>(slot));
}
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used) {
Lua_Safe_Call_Bool();
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot), mana_used);
return self->SpellFinished(spell_id, target, static_cast<EQEmu::spells::CastingSlot>(slot), mana_used);
}
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot) {
Lua_Safe_Call_Bool();
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot), mana_used, inventory_slot);
return self->SpellFinished(spell_id, target, static_cast<EQEmu::spells::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) {
Lua_Safe_Call_Bool();
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot), mana_used, inventory_slot, resist_adjust);
return self->SpellFinished(spell_id, target, static_cast<EQEmu::spells::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) {
Lua_Safe_Call_Bool();
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot), mana_used, inventory_slot, resist_adjust, proc);
return self->SpellFinished(spell_id, target, static_cast<EQEmu::spells::CastingSlot>(slot), mana_used, inventory_slot, resist_adjust, proc);
}
void Lua_Mob::SendBeginCast(int spell_id, int cast_time) {
@@ -1124,15 +1124,24 @@ double Lua_Mob::CalculateHeadingToTarget(double in_x, double in_y) {
return self->CalculateHeadingToTarget(static_cast<float>(in_x), static_cast<float>(in_y));
}
bool Lua_Mob::CalculateNewPosition(double x, double y, double z, double speed) {
Lua_Safe_Call_Bool();
return self->CalculateNewPosition(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(speed));
void Lua_Mob::RunTo(double x, double y, double z) {
Lua_Safe_Call_Void();
self->RunTo(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
}
bool Lua_Mob::CalculateNewPosition(double x, double y, double z, double speed, bool check_z) {
Lua_Safe_Call_Bool();
return self->CalculateNewPosition(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(speed),
check_z);
void Lua_Mob::WalkTo(double x, double y, double z) {
Lua_Safe_Call_Void();
self->WalkTo(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
}
void Lua_Mob::NavigateTo(double x, double y, double z) {
Lua_Safe_Call_Void();
self->NavigateTo(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
}
void Lua_Mob::StopNavigation() {
Lua_Safe_Call_Void();
self->StopNavigation();
}
float Lua_Mob::CalculateDistance(double x, double y, double z) {
@@ -1430,7 +1439,7 @@ void Lua_Mob::SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uin
void Lua_Mob::SetFlyMode(int in) {
Lua_Safe_Call_Void();
self->SetFlyMode(in);
self->SetFlyMode(static_cast<GravityBehavior>(in));
}
void Lua_Mob::SetTexture(int in) {
@@ -2361,8 +2370,10 @@ luabind::scope lua_register_mob() {
.def("FaceTarget", (void(Lua_Mob::*)(Lua_Mob))&Lua_Mob::FaceTarget)
.def("SetHeading", (void(Lua_Mob::*)(double))&Lua_Mob::SetHeading)
.def("CalculateHeadingToTarget", (double(Lua_Mob::*)(double,double))&Lua_Mob::CalculateHeadingToTarget)
.def("CalculateNewPosition", (bool(Lua_Mob::*)(double,double,double,double))&Lua_Mob::CalculateNewPosition)
.def("CalculateNewPosition", (bool(Lua_Mob::*)(double,double,double,double,bool))&Lua_Mob::CalculateNewPosition)
.def("RunTo", (void(Lua_Mob::*)(double, double, double))&Lua_Mob::RunTo)
.def("WalkTo", (void(Lua_Mob::*)(double, double, double))&Lua_Mob::WalkTo)
.def("NavigateTo", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::NavigateTo)
.def("StopNavigation", (void(Lua_Mob::*)(void))&Lua_Mob::StopNavigation)
.def("CalculateDistance", (float(Lua_Mob::*)(double,double,double))&Lua_Mob::CalculateDistance)
.def("SendTo", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::SendTo)
.def("SendToFixZ", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::SendToFixZ)
+4 -2
View File
@@ -240,8 +240,10 @@ public:
void FaceTarget(Lua_Mob target);
void SetHeading(double in);
double CalculateHeadingToTarget(double in_x, double in_y);
bool CalculateNewPosition(double x, double y, double z, double speed);
bool CalculateNewPosition(double x, double y, double z, double speed, bool check_z);
void RunTo(double x, double y, double z);
void WalkTo(double x, double y, double z);
void NavigateTo(double x, double y, double z);
void StopNavigation();
float CalculateDistance(double x, double y, double z);
void SendTo(double x, double y, double z);
void SendToFixZ(double x, double y, double z);
+3 -9
View File
@@ -308,14 +308,9 @@ void Lua_NPC::NextGuardPosition() {
self->NextGuardPosition();
}
void Lua_NPC::SaveGuardSpot() {
void Lua_NPC::SaveGuardSpot(float x, float y, float z, float heading) {
Lua_Safe_Call_Void();
self->SaveGuardSpot();
}
void Lua_NPC::SaveGuardSpot(bool clear) {
Lua_Safe_Call_Void();
self->SaveGuardSpot(clear);
self->SaveGuardSpot(glm::vec4(x, y, z, heading));
}
bool Lua_NPC::IsGuarding() {
@@ -597,8 +592,7 @@ luabind::scope lua_register_npc() {
.def("PauseWandering", (void(Lua_NPC::*)(int))&Lua_NPC::PauseWandering)
.def("MoveTo", (void(Lua_NPC::*)(float,float,float,float,bool))&Lua_NPC::MoveTo)
.def("NextGuardPosition", (void(Lua_NPC::*)(void))&Lua_NPC::NextGuardPosition)
.def("SaveGuardSpot", (void(Lua_NPC::*)(void))&Lua_NPC::SaveGuardSpot)
.def("SaveGuardSpot", (void(Lua_NPC::*)(bool))&Lua_NPC::SaveGuardSpot)
.def("SaveGuardSpot", (void(Lua_NPC::*)(float,float,float,float))&Lua_NPC::SaveGuardSpot)
.def("IsGuarding", (bool(Lua_NPC::*)(void))&Lua_NPC::IsGuarding)
.def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float))&Lua_NPC::AI_SetRoambox)
.def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float,uint32,uint32))&Lua_NPC::AI_SetRoambox)
+1 -2
View File
@@ -87,8 +87,7 @@ public:
void PauseWandering(int pause_time);
void MoveTo(float x, float y, float z, float h, bool save);
void NextGuardPosition();
void SaveGuardSpot();
void SaveGuardSpot(bool clear);
void SaveGuardSpot(float x, float y, float z, float heading);
bool IsGuarding();
void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y);
void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y, uint32 delay, uint32 mindelay);
+35 -65
View File
@@ -29,7 +29,7 @@ extern volatile bool is_zone_loaded;
#endif
Merc::Merc(const NPCType* d, float x, float y, float z, float heading)
: NPC(d, nullptr, glm::vec4(x, y, z, heading), 0, false), endupkeep_timer(1000), rest_timer(1), confidence_timer(6000), check_target_timer(2000)
: NPC(d, nullptr, glm::vec4(x, y, z, heading), GravityBehavior::Water, false), endupkeep_timer(1000), rest_timer(1), confidence_timer(6000), check_target_timer(2000)
{
base_hp = d->max_hp;
base_mana = d->Mana;
@@ -859,14 +859,14 @@ int32 Merc::CalcMaxHP() {
max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f);
if (cur_hp > max_hp)
cur_hp = max_hp;
if (current_hp > max_hp)
current_hp = max_hp;
int hp_perc_cap = spellbonuses.HPPercCap[0];
if(hp_perc_cap) {
int curHP_cap = (max_hp * hp_perc_cap) / 100;
if (cur_hp > curHP_cap || (spellbonuses.HPPercCap[1] && cur_hp > spellbonuses.HPPercCap[1]))
cur_hp = curHP_cap;
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[1] && current_hp > spellbonuses.HPPercCap[1]))
current_hp = curHP_cap;
}
return max_hp;
@@ -1271,7 +1271,7 @@ bool Merc::Process()
//6 seconds, or whatever the rule is set to has passed, send this position to everyone to avoid ghosting
if(!IsMoving() && !IsEngaged())
{
SendPosition();
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
if(IsSitting()) {
if(!rest_timer.Enabled()) {
rest_timer.Start(RuleI(Character, RestRegenTimeToActivate) * 1000);
@@ -1465,35 +1465,15 @@ void Merc::AI_Process() {
if(moved) {
moved = false;
SetCurrentSpeed(0);
StopNavigation();
}
}
return;
}
else if (!CheckLosFN(GetTarget())) {
if (RuleB(Mercs, MercsUsePathing) && zone->pathing) {
bool WaypointChanged, NodeReached;
glm::vec3 Goal = UpdatePath(
GetTarget()->GetX(),
GetTarget()->GetY(),
GetTarget()->GetZ(),
GetRunspeed(),
WaypointChanged,
NodeReached
);
if (WaypointChanged)
tar_ndx = 20;
CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetRunspeed());
}
else {
Mob* follow = entity_list.GetMob(GetFollowID());
if (follow)
CalculateNewPosition(follow->GetX(), follow->GetY(), follow->GetZ(), GetRunspeed());
}
auto Goal = GetTarget()->GetPosition();
RunTo(Goal.x, Goal.y, Goal.z);
return;
}
@@ -1527,7 +1507,7 @@ void Merc::AI_Process() {
SetRunAnimSpeed(0);
if(moved) {
SetCurrentSpeed(0);
StopNavigation();
}
}
@@ -1559,7 +1539,7 @@ void Merc::AI_Process() {
float newZ = 0;
FaceTarget(GetTarget());
if (PlotPositionAroundTarget(this, newX, newY, newZ)) {
CalculateNewPosition(newX, newY, newZ, GetRunspeed());
RunTo(newX, newY, newZ);
return;
}
}
@@ -1571,7 +1551,7 @@ void Merc::AI_Process() {
float newY = 0;
float newZ = 0;
if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ)) {
CalculateNewPosition(newX, newY, newZ, GetRunspeed());
RunTo(newX, newY, newZ);
return;
}
}
@@ -1582,16 +1562,16 @@ void Merc::AI_Process() {
float newY = 0;
float newZ = 0;
if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ, false) && GetArchetype() != ARCHETYPE_CASTER) {
CalculateNewPosition(newX, newY, newZ, GetRunspeed());
RunTo(newX, newY, newZ);
return;
}
}
}
if (IsMoving())
SendPositionUpdate();
else
SendPosition();
//if (IsMoving())
// SendPositionUpdate();
//else
// SendPosition();
}
if(!IsMercCaster() && GetTarget() && !IsStunned() && !IsMezzed() && (GetAppearance() != eaDead))
@@ -1709,14 +1689,14 @@ void Merc::AI_Process() {
{
if(!IsRooted()) {
Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName());
CalculateNewPosition(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed());
RunTo(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ());
return;
}
if(IsMoving())
SendPositionUpdate();
else
SendPosition();
//if(IsMoving())
// SendPositionUpdate();
//else
// SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
}
} // end not in combat range
@@ -1764,27 +1744,19 @@ void Merc::AI_Process() {
if (follow) {
float dist = DistanceSquared(m_Position, follow->GetPosition());
int speed = GetRunspeed();
bool running = true;
if (dist < GetFollowDistance() + 1000)
speed = GetWalkspeed();
running = false;
SetRunAnimSpeed(0);
if (dist > GetFollowDistance()) {
if (RuleB(Mercs, MercsUsePathing) && zone->pathing) {
bool WaypointChanged, NodeReached;
glm::vec3 Goal = UpdatePath(follow->GetX(), follow->GetY(), follow->GetZ(),
speed, WaypointChanged, NodeReached);
if (WaypointChanged)
tar_ndx = 20;
CalculateNewPosition(Goal.x, Goal.y, Goal.z, speed);
if (running) {
RunTo(follow->GetX(), follow->GetY(), follow->GetZ());
}
else {
CalculateNewPosition(follow->GetX(), follow->GetY(), follow->GetZ(), speed);
WalkTo(follow->GetX(), follow->GetY(), follow->GetZ());
}
if (rest_timer.Enabled())
@@ -1793,7 +1765,7 @@ void Merc::AI_Process() {
else {
if (moved) {
moved = false;
SetCurrentSpeed(0);
StopNavigation();
}
}
}
@@ -1819,8 +1791,7 @@ void Merc::AI_Start(int32 iMoveDelay) {
}
SendTo(GetX(), GetY(), GetZ());
SetChanged();
SaveGuardSpot();
SaveGuardSpot(GetPosition());
}
void Merc::AI_Stop() {
@@ -2019,10 +1990,10 @@ bool Merc::AIDoSpellCast(uint16 spellid, Mob* tar, int32 mana_cost, uint32* oDon
|| dist2 <= GetActSpellRange(spellid, spells[spellid].range)*GetActSpellRange(spellid, spells[spellid].range)) && (mana_cost <= GetMana() || GetMana() == GetMaxMana()))
{
SetRunAnimSpeed(0);
SendPosition();
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
SetMoving(false);
result = CastSpell(spellid, tar->GetID(), EQEmu::CastingSlot::Gem2, -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0);
result = CastSpell(spellid, tar->GetID(), EQEmu::spells::CastingSlot::Gem2, -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0);
if(IsCasting() && IsSitting())
Stand();
@@ -4074,7 +4045,7 @@ bool Merc::UseDiscipline(int32 spell_id, int32 target) {
if(IsCasting())
InterruptSpell();
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline);
CastSpell(spell_id, target, EQEmu::spells::CastingSlot::Discipline);
return(true);
}
@@ -4389,9 +4360,8 @@ void Merc::Sit() {
if(IsMoving()) {
moved = false;
// SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SendPosition();
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
SetMoving(false);
tar_ndx = 0;
}
SetAppearance(eaSitting);
@@ -4979,7 +4949,7 @@ void Merc::ScaleStats(int scalepercent, bool setmax) {
max_hp = (int)((float)base_hp * scalerate);
base_hp = max_hp;
if (setmax)
cur_hp = max_hp;
current_hp = max_hp;
}
if (base_mana)
@@ -5158,7 +5128,7 @@ bool Merc::Spawn(Client *owner) {
entity_list.AddMerc(this, true, true);
SendPosition();
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
Log(Logs::General, Logs::Mercenaries, "Spawn Mercenary %s.", GetName());
+311 -621
View File
File diff suppressed because it is too large Load Diff
+130 -145
View File
@@ -49,6 +49,7 @@ class Aura;
struct AuraRecord;
struct NewSpawn_Struct;
struct PlayerPositionUpdateServer_Struct;
class MobMovementManager;
const int COLLISION_BOX_SIZE = 8;
@@ -106,70 +107,67 @@ public:
AuraMgr() : count(0) { }
};
Mob(const char* in_name,
const char* in_lastname,
int32 in_cur_hp,
int32 in_max_hp,
uint8 in_gender,
uint16 in_race,
uint8 in_class,
bodyType in_bodytype,
uint8 in_deity,
uint8 in_level,
uint32 in_npctype_id,
float in_size,
float in_runspeed,
const glm::vec4& position,
uint8 in_light,
uint8 in_texture,
uint8 in_helmtexture,
uint16 in_ac,
uint16 in_atk,
uint16 in_str,
uint16 in_sta,
uint16 in_dex,
uint16 in_agi,
uint16 in_int,
uint16 in_wis,
uint16 in_cha,
uint8 in_haircolor,
uint8 in_beardcolor,
uint8 in_eyecolor1, // the eyecolors always seem to be the same, maybe left and right eye?
uint8 in_eyecolor2,
uint8 in_hairstyle,
uint8 in_luclinface,
uint8 in_beard,
uint32 in_drakkin_heritage,
uint32 in_drakkin_tattoo,
uint32 in_drakkin_details,
EQEmu::TintProfile in_armor_tint,
uint8 in_aa_title,
uint8 in_see_invis, // see through invis
uint8 in_see_invis_undead, // see through invis vs. undead
uint8 in_see_hide,
uint8 in_see_improved_hide,
int32 in_hp_regen,
int32 in_mana_regen,
uint8 in_qglobal,
uint8 in_maxlevel,
uint32 in_scalerate,
uint8 in_armtexture,
uint8 in_bracertexture,
uint8 in_handtexture,
uint8 in_legtexture,
uint8 in_feettexture
Mob(
const char *in_name,
const char *in_lastname,
int32 in_cur_hp,
int32 in_max_hp,
uint8 in_gender,
uint16 in_race,
uint8 in_class,
bodyType in_bodytype,
uint8 in_deity,
uint8 in_level,
uint32 in_npctype_id,
float in_size,
float in_runspeed,
const glm::vec4 &position,
uint8 in_light,
uint8 in_texture,
uint8 in_helmtexture,
uint16 in_ac,
uint16 in_atk,
uint16 in_str,
uint16 in_sta,
uint16 in_dex,
uint16 in_agi,
uint16 in_int,
uint16 in_wis,
uint16 in_cha,
uint8 in_haircolor,
uint8 in_beardcolor,
uint8 in_eyecolor1, // the eyecolors always seem to be the same, maybe left and right eye?
uint8 in_eyecolor2,
uint8 in_hairstyle,
uint8 in_luclinface,
uint8 in_beard,
uint32 in_drakkin_heritage,
uint32 in_drakkin_tattoo,
uint32 in_drakkin_details,
EQEmu::TintProfile in_armor_tint,
uint8 in_aa_title,
uint8 in_see_invis, // see through invis
uint8 in_see_invis_undead, // see through invis vs. undead
uint8 in_see_hide,
uint8 in_see_improved_hide,
int32 in_hp_regen,
int32 in_mana_regen,
uint8 in_qglobal,
uint8 in_maxlevel,
uint32 in_scalerate,
uint8 in_armtexture,
uint8 in_bracertexture,
uint8 in_handtexture,
uint8 in_legtexture,
uint8 in_feettexture
);
virtual ~Mob();
inline virtual bool IsMob() const { return true; }
inline virtual bool InZone() const { return true; }
bool is_distance_roamer;
void DisplayInfo(Mob *mob);
public:
//Somewhat sorted: needs documenting!
//Attack
@@ -240,34 +238,47 @@ public:
return;
}
//Appearance
void SendLevelAppearance();
void SendStunAppearance();
void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5,
Client *specific_target=nullptr);
void SendTargetable(bool on, Client *specific_target = nullptr);
virtual void SendArmorAppearance(Client *one_client = nullptr);
virtual void SendWearChange(uint8 material_slot, Client *one_client = nullptr);
virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0,
uint32 unknown06 = 0, uint32 unknown18 = 0);
virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint);
virtual void WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model = 0);
void DoAnim(const int animnum, int type=0, bool ackreq = true, eqFilterType filter = FilterNone);
void ProjectileAnimation(Mob* to, int item_id, bool IsArrow = false, float speed = 0,
float angle = 0, float tilt = 0, float arc = 0, const char *IDFile = nullptr, EQEmu::skills::SkillType skillInUse = EQEmu::skills::SkillArchery);
void ChangeSize(float in_size, bool bNoRestriction = false);
inline uint8 SeeInvisible() const { return see_invis; }
inline bool SeeInvisibleUndead() const { return see_invis_undead; }
/**
************************************************
* Appearance
************************************************
*/
EQEmu::InternalTextureProfile mob_texture_profile = {};
bool IsInvisible(Mob* other = 0) const;
EQEmu::skills::SkillType AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon, EQEmu::skills::SkillType skillinuse = EQEmu::skills::Skill1HBlunt);
inline bool GetSeeInvisible(uint8 see_invis);
inline bool SeeHide() const { return see_hide; }
inline bool SeeImprovedHide() const { return see_improved_hide; }
inline bool GetSeeInvisible(uint8 see_invis);
bool IsInvisible(Mob* other = 0) const;
inline bool SeeInvisibleUndead() const { return see_invis_undead; }
inline uint8 SeeInvisible() const { return see_invis; }
int32 GetTextureProfileMaterial(uint8 material_slot) const;
int32 GetTextureProfileColor(uint8 material_slot) const;
int32 GetTextureProfileHeroForgeModel(uint8 material_slot) const;
virtual void SendArmorAppearance(Client *one_client = nullptr);
virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0, uint32 unknown06 = 0, uint32 unknown18 = 0);
virtual void SendWearChange(uint8 material_slot, Client *one_client = nullptr);
virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint);
virtual void WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model = 0);
void ChangeSize(float in_size, bool bNoRestriction = false);
void DoAnim(const int animnum, int type=0, bool ackreq = true, eqFilterType filter = FilterNone);
void ProjectileAnimation(Mob* to, int item_id, bool IsArrow = false, float speed = 0, float angle = 0, float tilt = 0, float arc = 0, const char *IDFile = nullptr, EQEmu::skills::SkillType skillInUse = EQEmu::skills::SkillArchery);
void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5, Client *specific_target=nullptr);
void SendLevelAppearance();
void SendStunAppearance();
void SendTargetable(bool on, Client *specific_target = nullptr);
void SetInvisible(uint8 state);
EQEmu::skills::SkillType AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon, EQEmu::skills::SkillType skillinuse = EQEmu::skills::Skill1HBlunt);
void SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color = 0, uint32 hero_forge_model = 0);
//Song
bool UseBardSpellLogic(uint16 spell_id = 0xffff, int slot = -1);
bool ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, EQEmu::CastingSlot slot);
bool ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, EQEmu::spells::CastingSlot slot);
void BardPulse(uint16 spell_id, Mob *caster);
//Spell
@@ -298,24 +309,24 @@ public:
void SendSpellBarEnable(uint16 spellid);
void ZeroCastingVars();
virtual void SpellProcess();
virtual bool CastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1,
virtual bool CastSpell(uint16 spell_id, uint16 target_id, EQEmu::spells::CastingSlot slot = EQEmu::spells::CastingSlot::Item, int32 casttime = -1,
int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF,
uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, int16 *resist_adjust = nullptr,
uint32 aa_id = 0);
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1,
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::spells::CastingSlot slot = EQEmu::spells::CastingSlot::Item, int32 casttime = -1,
int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF,
uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, int16 resist_adjust = 0,
uint32 aa_id = 0);
void CastedSpellFinished(uint16 spell_id, uint32 target_id, EQEmu::CastingSlot slot, uint16 mana_used,
void CastedSpellFinished(uint16 spell_id, uint32 target_id, EQEmu::spells::CastingSlot slot, uint16 mana_used,
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0);
bool SpellFinished(uint16 spell_id, Mob *target, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, uint16 mana_used = 0,
bool SpellFinished(uint16 spell_id, Mob *target, EQEmu::spells::CastingSlot slot = EQEmu::spells::CastingSlot::Item, uint16 mana_used = 0,
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1);
void SendBeginCast(uint16 spell_id, uint32 casttime);
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);
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,
CastAction_type &CastAction, EQEmu::CastingSlot slot, bool isproc = false);
CastAction_type &CastAction, EQEmu::spells::CastingSlot slot, bool isproc = false);
virtual bool CheckFizzle(uint16 spell_id);
virtual bool CheckSpellLevelRestriction(uint16 spell_id);
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
@@ -413,7 +424,7 @@ public:
bool CanFacestab() { return can_facestab; }
void SetFacestab(bool val) { can_facestab = val; }
virtual uint16 GetSkill(EQEmu::skills::SkillType skill_num) const { return 0; }
virtual uint32 GetEquipment(uint8 material_slot) const { return(0); }
virtual uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const { return(0); }
virtual int32 GetEquipmentMaterial(uint8 material_slot) const;
virtual int32 GetHerosForgeModel(uint8 material_slot) const;
virtual uint32 GetEquipmentColor(uint8 material_slot) const;
@@ -423,12 +434,12 @@ public:
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) = 0;
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill,
bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) = 0;
inline virtual void SetHP(int32 hp) { if (hp >= max_hp) cur_hp = max_hp; else cur_hp = hp;}
inline virtual void SetHP(int32 hp) { if (hp >= max_hp) current_hp = max_hp; else current_hp = hp;}
bool ChangeHP(Mob* other, int32 amount, uint16 spell_id = 0, int8 buffslot = -1, bool iBuffTic = false);
inline void SetOOCRegen(int32 newoocregen) {ooc_regen = newoocregen;}
virtual void Heal();
virtual void HealDamage(uint32 ammount, Mob* caster = nullptr, uint16 spell_id = SPELL_UNKNOWN);
virtual void SetMaxHP() { cur_hp = max_hp; }
virtual void SetMaxHP() { current_hp = max_hp; }
virtual inline uint16 GetBaseRace() const { return base_race; }
virtual inline uint8 GetBaseGender() const { return base_gender; }
virtual inline uint16 GetDeity() const { return deity; }
@@ -474,8 +485,8 @@ public:
inline Mob* GetTarget() const { return target; }
virtual void SetTarget(Mob* mob);
inline bool HasTargetReflection() const { return (target && target != this && target->target == this); }
virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)cur_hp/max_hp*100); }
virtual inline int GetIntHPRatio() const { return max_hp == 0 ? 0 : static_cast<int>(cur_hp * 100 / max_hp); }
virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)current_hp/max_hp*100); }
virtual inline int GetIntHPRatio() const { return max_hp == 0 ? 0 : static_cast<int>(current_hp * 100 / max_hp); }
inline int32 GetAC() const { return AC; }
inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK; }
inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; }
@@ -524,7 +535,7 @@ public:
inline virtual int32 GetMaxCR() const { return 255; }
inline virtual int32 GetMaxFR() const { return 255; }
inline virtual int32 GetDelayDeath() const { return 0; }
inline int32 GetHP() const { return cur_hp; }
inline int32 GetHP() const { return current_hp; }
inline int32 GetMaxHP() const { return max_hp; }
virtual int32 CalcMaxHP();
inline int32 GetMaxMana() const { return max_mana; }
@@ -541,21 +552,14 @@ public:
uint32 GetNPCTypeID() const { return npctype_id; }
void SetNPCTypeID(uint32 npctypeid) { npctype_id = npctypeid; }
inline const glm::vec4& GetPosition() const { return m_Position; }
inline void SetPosition(const float x, const float y, const float z) { m_Position.x = x; m_Position.y = y; m_Position.z = z; }
inline const float GetX() const { return m_Position.x; }
inline const float GetY() const { return m_Position.y; }
inline const float GetZ() const { return m_Position.z; }
inline const float GetHeading() const { return m_Position.w; }
inline const float GetSize() const { return size; }
inline const float GetBaseSize() const { return base_size; }
inline const float GetTarX() const { return m_TargetLocation.x; }
inline const float GetTarY() const { return m_TargetLocation.y; }
inline const float GetTarZ() const { return m_TargetLocation.z; }
inline const float GetTarVX() const { return m_TargetV.x; }
inline const float GetTarVY() const { return m_TargetV.y; }
inline const float GetTarVZ() const { return m_TargetV.z; }
inline const float GetTarVector() const { return tar_vector; }
inline const uint8 GetTarNDX() const { return tar_ndx; }
inline const int8 GetFlyMode() const { return static_cast<const int8>(flymode); }
inline const GravityBehavior GetFlyMode() const { return flymode; }
bool IsBoat() const;
//Group
@@ -568,14 +572,12 @@ public:
virtual inline int32 GetPrimaryFaction() const { return 0; }
//Movement
void Warp(const glm::vec3& location);
inline bool IsMoving() const { return moving; }
virtual void SetMoving(bool move) { moving = move; m_Delta = glm::vec4(); }
virtual void GoToBind(uint8 bindnum = 0) { }
virtual void Gate(uint8 bindnum = 0);
int GetWalkspeed() const { return(_GetWalkSpeed()); }
int GetRunspeed() const { return(_GetRunSpeed()); }
void SetCurrentSpeed(int in);
int GetBaseRunspeed() const { return base_runspeed; }
int GetBaseWalkspeed() const { return base_walkspeed; }
int GetBaseFearSpeed() const { return base_fearspeed; }
@@ -584,26 +586,24 @@ public:
void SetRunning(bool val) { m_is_running = val; }
virtual void GMMove(float x, float y, float z, float heading = 0.01, bool SendUpdate = true);
void SetDelta(const glm::vec4& delta);
void SetTargetDestSteps(uint8 target_steps) { tar_ndx = target_steps; }
void SendPositionUpdateToClient(Client *client);
void SendPositionUpdate(uint8 iSendToSelf = 0);
void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu);
void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu);
void SendPosition();
void SentPositionPacket(float dx, float dy, float dz, float dh, int anim, bool send_to_self = false);
void StopMoving();
void StopMoving(float new_heading);
void SetSpawned() { spawned = true; };
bool Spawned() { return spawned; };
virtual bool ShouldISpawnFor(Client *c) { return true; }
void SetFlyMode(uint8 flymode);
inline void Teleport(glm::vec3 NewPosition) { m_Position.x = NewPosition.x; m_Position.y = NewPosition.y;
m_Position.z = NewPosition.z; };
void SetFlyMode(GravityBehavior flymode);
void Teleport(const glm::vec3 &pos);
void Teleport(const glm::vec4 &pos);
void TryMoveAlong(float distance, float angle, bool send = true);
void ProcessForcedMovement();
inline void IncDeltaX(float in) { m_Delta.x += in; }
inline void IncDeltaY(float in) { m_Delta.y += in; }
inline void IncDeltaZ(float in) { m_Delta.z += in; }
inline void SetForcedMovement(int in) { ForcedMovement = in; }
void SetHeading(float iHeading) { m_Position.w = iHeading; }
//AI
static uint32 GetLevelCon(uint8 mylevel, uint8 iOtherLevel);
@@ -630,8 +630,6 @@ public:
void SetAssistAggro(bool value) { AssistAggro = value; if (PrimaryAggro) AssistAggro = false; }
bool HateSummon();
void FaceTarget(Mob* mob_to_face = 0);
void SetHeading(float iHeading) { if(m_Position.w != iHeading) { pLastChange = Timer::GetCurrentTime();
m_Position.w = iHeading; } }
void WipeHateList();
void AddFeignMemory(Client* attacker);
void RemoveFromFeignMemory(Client* attacker);
@@ -642,8 +640,6 @@ public:
bool CheckLosFN(Mob* other);
bool CheckLosFN(float posX, float posY, float posZ, float mobSize);
static bool CheckLosFN(glm::vec3 posWatcher, float sizeWatcher, glm::vec3 posTarget, float sizeTarget);
inline void SetChanged() { pLastChange = Timer::GetCurrentTime(); }
inline const uint32 LastChange() const { return pLastChange; }
inline void SetLastLosState(bool value) { last_los_check = value; }
inline bool CheckLastLosState() const { return last_los_check; }
@@ -833,8 +829,10 @@ public:
void SendAppearancePacket(uint32 type, uint32 value, bool WholeZone = true, bool iIgnoreSelf = false, Client *specific_target=nullptr);
void SetAppearance(EmuAppearance app, bool iIgnoreSelf = true);
inline EmuAppearance GetAppearance() const { return _appearance; }
inline const int GetAnimation() const { return animation; }
inline void SetAnimation(int a) { animation = a; }
inline const uint8 GetRunAnimSpeed() const { return pRunAnimSpeed; }
inline void SetRunAnimSpeed(int8 in) { if (pRunAnimSpeed != in) { pRunAnimSpeed = in; pLastChange = Timer::GetCurrentTime(); } }
inline void SetRunAnimSpeed(int8 in) { pRunAnimSpeed = in; }
bool IsDestructibleObject() { return destructibleobject; }
void SetDestructibleObject(bool in) { destructibleobject = in; }
@@ -1000,7 +998,13 @@ public:
inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);}
float CalculateHeadingToTarget(float in_x, float in_y) { return HeadingAngleToMob(in_x, in_y); }
virtual bool CalculateNewPosition(float x, float y, float z, float speed, bool check_z = true, bool calculate_heading = true);
void WalkTo(float x, float y, float z);
void RunTo(float x, float y, float z);
void NavigateTo(float x, float y, float z);
void RotateTo(float new_heading);
void RotateToWalking(float new_heading);
void RotateToRunning(float new_heading);
void StopNavigation();
float CalculateDistance(float x, float y, float z);
float GetGroundZ(float new_x, float new_y, float z_offset=0.0);
void SendTo(float new_x, float new_y, float new_z);
@@ -1008,8 +1012,9 @@ public:
float GetZOffset() const;
float GetDefaultRaceSize() const;
void FixZ(int32 z_find_offset = 5, bool fix_client_z = false);
float GetFixedZ(glm::vec3 destination, int32 z_find_offset = 5);
float GetFixedZ(const glm::vec3 &destination, int32 z_find_offset = 5);
virtual int GetStuckBehavior() const { return 0; }
void NPCSpecialAttacks(const char* parse, int permtag, bool reset = true, bool remove = false);
inline uint32 DontHealMeBefore() const { return pDontHealMeBefore; }
inline uint32 DontBuffMeBefore() const { return pDontBuffMeBefore; }
@@ -1088,6 +1093,7 @@ public:
void SetCurrentWP(uint16 waypoint) { cur_wp = waypoint; }
virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther) { return FACTION_INDIFFERENT; }
virtual const bool IsUnderwaterOnly() const { return false; }
inline bool IsTrackable() const { return(trackable); }
Timer* GetAIThinkTimer() { return AI_think_timer.get(); }
Timer* GetAIMovementTimer() { return AI_movement_timer.get(); }
@@ -1189,7 +1195,6 @@ protected:
int _GetWalkSpeed() const;
int _GetRunSpeed() const;
int _GetFearSpeed() const;
virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, bool check_z = true, bool calculate_heading = true);
virtual bool AI_EngagedCastCheck() { return(false); }
virtual bool AI_PursueCastCheck() { return(false); }
@@ -1240,7 +1245,7 @@ protected:
int targeted;
bool findable;
bool trackable;
int32 cur_hp;
int32 current_hp;
int32 max_hp;
int32 base_hp;
int32 current_mana;
@@ -1283,10 +1288,8 @@ protected:
uint8 level;
uint8 orig_level;
uint32 npctype_id;
glm::vec4 m_Position;
/* Used to determine when an NPC has traversed so many units - to send a zone wide pos update */
glm::vec4 last_major_update_position;
glm::vec4 m_Position;
int animation; // this is really what MQ2 calls SpeedRun just packed like (int)(SpeedRun * 40.0f)
float base_size;
float size;
@@ -1299,7 +1302,6 @@ protected:
int current_speed;
eSpecialAttacks m_specialattacks;
uint32 pLastChange;
bool held;
bool gheld;
bool nocast;
@@ -1329,8 +1331,6 @@ protected:
void CalculateNewFearpoint();
float FindGroundZ(float new_x, float new_y, float z_offset=0.0);
float FindDestGroundZ(glm::vec3 dest, float z_offset=0.0);
glm::vec3 UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChange, bool &NodeReached);
glm::vec3 HandleStuckPath(const glm::vec3 &To, const glm::vec3 &From);
virtual float GetSympatheticProcChances(uint16 spell_id, int16 ProcRateMod, int32 ItemProcRate = 0);
int16 GetSympatheticSpellProcRate(uint16 spell_id);
@@ -1375,7 +1375,7 @@ protected:
int attacked_count;
bool delaytimer;
uint16 casting_spell_targetid;
EQEmu::CastingSlot casting_spell_slot;
EQEmu::spells::CastingSlot casting_spell_slot;
uint16 casting_spell_mana;
uint32 casting_spell_inventory_slot;
uint32 casting_spell_timer;
@@ -1385,7 +1385,7 @@ protected:
uint32 casting_spell_aa_id;
bool casting_spell_checks;
uint16 bardsong;
EQEmu::CastingSlot bardsong_slot;
EQEmu::spells::CastingSlot bardsong_slot;
uint32 bardsong_target_id;
bool ActiveProjectileATK;
@@ -1467,7 +1467,6 @@ protected:
std::unique_ptr<Timer> AI_think_timer;
std::unique_ptr<Timer> AI_movement_timer;
std::unique_ptr<Timer> AI_target_check_timer;
bool movetimercompleted;
int8 ForcedMovement; // push
bool permarooted;
std::unique_ptr<Timer> AI_scan_area_timer;
@@ -1491,8 +1490,6 @@ protected:
bool flee_mode;
Timer flee_timer;
Timer fix_z_timer;
Timer fix_z_timer_engaged;
Timer attack_anim_timer;
Timer position_update_melee_push_timer;
@@ -1518,15 +1515,8 @@ protected:
glm::vec3 m_FearWalkTarget;
bool currently_fleeing;
// Pathing
//
glm::vec3 PathingDestination;
IPathfinder::IPath Route;
std::unique_ptr<Timer> PathRecalcTimer;
bool pause_timer_complete;
bool DistractedFromGrid;
glm::vec3 PathingLastPosition;
int PathingLoopCount;
uint32 pDontHealMeBefore;
uint32 pDontBuffMeBefore;
uint32 pDontDotMeBefore;
@@ -1545,18 +1535,11 @@ protected:
bool pet_owner_client; //Flags regular and pets as belonging to a client
uint32 pet_targetlock_id;
EGNode *_egnode; //the EG node we are in
glm::vec3 m_TargetLocation;
uint8 tar_ndx;
float tar_vector;
glm::vec3 m_TargetV;
float test_vector;
glm::vec3 m_TargetRing;
// we might want to do this differently, we gotta do max NPC buffs ... which is 97
uint32 m_spellHitsLeft[EQEmu::constants::TotalBuffs]; // Used to track which spells will have their numhits incremented when spell finishes casting
int flymode;
uint32 m_spellHitsLeft[EQEmu::spells::TOTAL_BUFFS]; // Used to track which spells will have their numhits incremented when spell finishes casting
GravityBehavior flymode;
bool m_targetable;
int QGVarDuration(const char *fmt);
void InsertQuestGlobal(int charid, int npcid, int zoneid, const char *name, const char *value, int expdate);
@@ -1574,6 +1557,8 @@ protected:
AuraMgr aura_mgr;
AuraMgr trap_mgr;
MobMovementManager *mMovementManager;
private:
void _StopSong(); //this is not what you think it is
Mob* target;
+129 -346
View File
@@ -375,12 +375,7 @@ bool NPC::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
#endif
casting_spell_AIindex = i;
//stop moving if were casting a spell and were not a bard...
if(!IsBardSong(AIspells[i].spellid)) {
SetCurrentSpeed(0);
}
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));
return CastSpell(AIspells[i].spellid, tar->GetID(), EQEmu::spells::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, uint32 iSpellTypes) {
@@ -520,7 +515,6 @@ void Mob::AI_Start(uint32 iMoveDelay) {
m_Delta = glm::vec4();
pRunAnimSpeed = 0;
pLastChange = Timer::GetCurrentTime();
}
void Client::AI_Start(uint32 iMoveDelay) {
@@ -556,8 +550,7 @@ void NPC::AI_Start(uint32 iMoveDelay) {
}
SendTo(GetX(), GetY(), GetZ());
SetChanged();
SaveGuardSpot();
SaveGuardSpot(GetPosition());
}
void Mob::AI_Stop() {
@@ -695,11 +688,11 @@ void Client::AI_SpellCast()
}
uint32 spell_to_cast = 0xFFFFFFFF;
EQEmu::CastingSlot slot_to_use = EQEmu::CastingSlot::Item;
EQEmu::spells::CastingSlot slot_to_use = EQEmu::spells::CastingSlot::Item;
if(valid_spells.size() == 1)
{
spell_to_cast = valid_spells[0];
slot_to_use = static_cast<EQEmu::CastingSlot>(slots[0]);
slot_to_use = static_cast<EQEmu::spells::CastingSlot>(slots[0]);
}
else if(valid_spells.empty())
{
@@ -709,7 +702,7 @@ void Client::AI_SpellCast()
{
uint32 idx = zone->random.Int(0, (valid_spells.size()-1));
spell_to_cast = valid_spells[idx];
slot_to_use = static_cast<EQEmu::CastingSlot>(slots[idx]);
slot_to_use = static_cast<EQEmu::spells::CastingSlot>(slots[idx]);
}
if(IsMezSpell(spell_to_cast) || IsFearSpell(spell_to_cast))
@@ -722,7 +715,7 @@ void Client::AI_SpellCast()
{
if(!IsBardSong(spell_to_cast))
{
SetCurrentSpeed(0);
StopNavigation();
}
CastSpell(spell_to_cast, tar->GetID(), slot_to_use);
return;
@@ -736,7 +729,7 @@ void Client::AI_SpellCast()
{
if(!IsBardSong(spell_to_cast))
{
SetCurrentSpeed(0);
StopNavigation();
}
CastSpell(spell_to_cast, tar->GetID(), slot_to_use);
return;
@@ -788,50 +781,23 @@ void Client::AI_Process()
if (RuleB(Combat, EnableFearPathing)) {
if (currently_fleeing) {
if (fix_z_timer.Check())
this->FixZ(5, true);
if (IsRooted()) {
//make sure everybody knows were not moving, for appearance sake
if (IsMoving()) {
if (GetTarget())
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SetCurrentSpeed(0);
FaceTarget();
StopNavigation();
}
//continue on to attack code, ensuring that we execute the engaged code
engaged = true;
}
else {
if (AI_movement_timer->Check()) {
int speed = GetFearSpeed();
animation = speed;
speed *= 2;
SetCurrentSpeed(speed);
// Check if we have reached the last fear point
if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) &&
(std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) {
// Calculate a new point to run to
if(IsPositionEqualWithinCertainZ(glm::vec3(GetX(), GetY(), GetZ()), m_FearWalkTarget, 5.0f)) {
CalculateNewFearpoint();
}
if (!RuleB(Pathing, Fear) || !zone->pathing)
CalculateNewPosition(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, speed, true);
else {
bool waypoint_changed, node_reached;
glm::vec3 Goal = UpdatePath(
m_FearWalkTarget.x,
m_FearWalkTarget.y,
m_FearWalkTarget.z,
speed,
waypoint_changed,
node_reached
);
if (waypoint_changed)
tar_ndx = 20;
CalculateNewPosition(Goal.x, Goal.y, Goal.z, speed);
RunTo(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z);
}
}
return;
@@ -866,6 +832,10 @@ void Client::AI_Process()
bool is_combat_range = CombatRange(GetTarget());
if (is_combat_range) {
if (IsMoving()) {
StopNavigation();
}
if (charm_class_attacks_timer.Check()) {
DoClassAttacks(GetTarget());
}
@@ -873,10 +843,8 @@ void Client::AI_Process()
if (AI_movement_timer->Check()) {
if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) !=
m_Position.w) {
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SendPosition();
FaceTarget();
}
SetCurrentSpeed(0);
}
if (GetTarget() && !IsStunned() && !IsMezzed() && !GetFeigned()) {
if (attack_timer.Check()) {
@@ -898,29 +866,12 @@ void Client::AI_Process()
{
if(AI_movement_timer->Check())
{
int newspeed = GetRunspeed();
animation = newspeed;
newspeed *= 2;
SetCurrentSpeed(newspeed);
if(!RuleB(Pathing, Aggro) || !zone->pathing)
CalculateNewPosition(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), newspeed);
else
{
bool WaypointChanged, NodeReached;
glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(),
GetRunspeed(), WaypointChanged, NodeReached);
if(WaypointChanged)
tar_ndx = 20;
CalculateNewPosition(Goal.x, Goal.y, Goal.z, newspeed);
}
RunTo(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ());
}
}
else if(IsMoving())
{
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SetCurrentSpeed(0);
FaceTarget();
}
}
AI_SpellCast();
@@ -953,22 +904,18 @@ void Client::AI_Process()
float dist = DistanceSquared(m_Position, owner->GetPosition());
if (dist >= 202500) { // >= 450 distance
Teleport(static_cast<glm::vec3>(owner->GetPosition()));
SendPositionUpdate(); // this shouldn't happen a lot (and hard to make it) so lets not rate limit
Teleport(owner->GetPosition());
} else if (dist >= 400) { // >=20
if (AI_movement_timer->Check()) {
int nspeed = (dist >= 1225 ? GetRunspeed() : GetWalkspeed()); // >= 35
animation = nspeed;
nspeed *= 2;
SetCurrentSpeed(nspeed);
CalculateNewPosition(owner->GetX(), owner->GetY(), owner->GetZ(), nspeed);
if (dist >= 1225) {
RunTo(owner->GetX(), owner->GetY(), owner->GetZ());
}
else {
WalkTo(owner->GetX(), owner->GetY(), owner->GetZ());
}
}
} else {
if (moved) {
SetCurrentSpeed(0);
moved = false;
}
StopNavigation();
}
}
}
@@ -982,49 +929,49 @@ void Mob::ProcessForcedMovement()
if (AI_movement_timer->Check()) {
bool bPassed = true;
glm::vec3 normal;
// no zone map = fucked
if (zone->HasMap()) {
// in front
m_CollisionBox[0].x = m_Position.x + 3.0f * g_Math.FastSin(0.0f);
m_CollisionBox[0].y = m_Position.y + 3.0f * g_Math.FastCos(0.0f);
m_CollisionBox[0].z = m_Position.z;
// 45 right front
m_CollisionBox[1].x = m_Position.x + 3.0f * g_Math.FastSin(64.0f);
m_CollisionBox[1].y = m_Position.y + 3.0f * g_Math.FastCos(64.0f);
m_CollisionBox[1].z = m_Position.z;
// to right
m_CollisionBox[2].x = m_Position.x + 3.0f * g_Math.FastSin(128.0f);
m_CollisionBox[2].y = m_Position.y + 3.0f * g_Math.FastCos(128.0f);
m_CollisionBox[2].z = m_Position.z;
// 45 right back
m_CollisionBox[3].x = m_Position.x + 3.0f * g_Math.FastSin(192.0f);
m_CollisionBox[3].y = m_Position.y + 3.0f * g_Math.FastCos(192.0f);
m_CollisionBox[3].z = m_Position.z;
// behind
m_CollisionBox[4].x = m_Position.x + 3.0f * g_Math.FastSin(256.0f);
m_CollisionBox[4].y = m_Position.y + 3.0f * g_Math.FastCos(256.0f);
m_CollisionBox[4].z = m_Position.z;
// 45 left back
m_CollisionBox[5].x = m_Position.x + 3.0f * g_Math.FastSin(320.0f);
m_CollisionBox[5].y = m_Position.y + 3.0f * g_Math.FastCos(320.0f);
m_CollisionBox[5].z = m_Position.z;
// to left
m_CollisionBox[6].x = m_Position.x + 3.0f * g_Math.FastSin(384.0f);
m_CollisionBox[6].y = m_Position.y + 3.0f * g_Math.FastCos(384.0f);
m_CollisionBox[6].z = m_Position.z;
// 45 left front
m_CollisionBox[7].x = m_Position.x + 3.0f * g_Math.FastSin(448.0f);
m_CollisionBox[7].y = m_Position.y + 3.0f * g_Math.FastCos(448.0f);
m_CollisionBox[7].z = m_Position.z;
// collision happened, need to move along the wall
float distance = 0.0f, shortest = std::numeric_limits<float>::infinity();
glm::vec3 tmp_nrm;
@@ -1038,13 +985,12 @@ void Mob::ProcessForcedMovement()
}
}
}
if (bPassed) {
ForcedMovement = 0;
Teleport(m_Position + m_Delta);
m_Delta = glm::vec4();
SendPositionUpdate();
pLastChange = Timer::GetCurrentTime();
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0, true);
FixZ(); // so we teleport to the ground locally, we want the client to interpolate falling etc
} else if (--ForcedMovement) {
if (normal.z < -0.15f) // prevent too much wall climbing. ex. OMM's room in anguish
@@ -1119,9 +1065,8 @@ void Mob::AI_Process() {
!IsPetRegroup()) {
//make sure everybody knows were not moving, for appearance sake
if (IsMoving()) {
if (target)
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY()));
SetCurrentSpeed(0);
FaceTarget();
StopNavigation();
moved = false;
}
//continue on to attack code, ensuring that we execute the engaged code
@@ -1130,37 +1075,16 @@ void Mob::AI_Process() {
else {
if (AI_movement_timer->Check()) {
// Check if we have reached the last fear point
if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) &&
(std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) {
if (DistanceNoZ(glm::vec3(GetX(), GetY(), GetZ()), m_FearWalkTarget) <= 5.0f) {
// Calculate a new point to run to
StopNavigation();
CalculateNewFearpoint();
}
if (!RuleB(Pathing, Fear) || !zone->pathing) {
CalculateNewPosition(
m_FearWalkTarget.x,
m_FearWalkTarget.y,
m_FearWalkTarget.z,
GetFearSpeed(),
true
);
}
else {
bool WaypointChanged, NodeReached;
glm::vec3 Goal = UpdatePath(
m_FearWalkTarget.x,
m_FearWalkTarget.y,
m_FearWalkTarget.z,
GetFearSpeed(),
WaypointChanged,
NodeReached
);
if (WaypointChanged)
tar_ndx = 20;
CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetFearSpeed());
}
RunTo(
m_FearWalkTarget.x,
m_FearWalkTarget.y,
m_FearWalkTarget.z
);
}
return;
}
@@ -1173,26 +1097,6 @@ void Mob::AI_Process() {
}
if (engaged) {
/* Fix Z when following during pull, not when engaged and stationary */
if (moving && fix_z_timer_engaged.Check()) {
if (this->GetTarget()) {
/* If we are engaged, moving and following client, let's look for best Z more often */
float target_distance = DistanceNoZ(this->GetPosition(), this->GetTarget()->GetPosition());
this->FixZ();
if (target_distance <= 15 && !this->CheckLosFN(this->GetTarget())) {
Mob *target = this->GetTarget();
m_Position.x = target->GetX();
m_Position.y = target->GetY();
m_Position.z = target->GetZ();
m_Position.w = target->GetHeading();
SendPosition();
}
}
}
if (!(m_PlayerState & static_cast<uint32>(PlayerState::Aggressive)))
SendAddPlayerState(PlayerState::Aggressive);
@@ -1275,21 +1179,12 @@ void Mob::AI_Process() {
bool is_combat_range = CombatRange(target);
if (is_combat_range) {
if (AI_movement_timer->Check()) {
if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) {
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SendPosition();
}
SetCurrentSpeed(0);
}
if (IsMoving()) {
if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) {
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SendPosition();
}
SetCurrentSpeed(0);
StopNavigation();
}
FaceTarget();
//casting checked above...
if (target && !IsStunned() && !IsMezzed() && GetAppearance() != eaDead && !IsMeleeDisabled()) {
@@ -1444,26 +1339,6 @@ void Mob::AI_Process() {
} //end is within combat rangepet
else {
//we cannot reach our target...
//underwater stuff only works with water maps in the zone!
if (IsNPC() && CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
auto targetPosition = glm::vec3(target->GetX(), target->GetY(), target->GetZ());
if (!zone->watermap->InLiquid(targetPosition)) {
Mob *tar = hate_list.GetEntWithMostHateOnList(this);
if (tar == target) {
WipeHateList();
Heal();
BuffFadeAll();
AI_walking_timer->Start(100);
time_until_can_move = Timer::GetCurrentTime();
return;
}
else if (tar != nullptr) {
SetTarget(tar);
return;
}
}
}
// See if we can summon the mob to us
if (!HateSummon()) {
@@ -1474,32 +1349,19 @@ void Mob::AI_Process() {
// Now pursue
// TODO: Check here for another person on hate list with close hate value
if (AI_PursueCastCheck()) {
//we did something, so do not process movement.
if (IsCasting() && GetClass() != BARD) {
StopNavigation();
FaceTarget();
}
}
else if (AI_movement_timer->Check() && target) {
if (!IsRooted()) {
Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", target->GetName());
if (!RuleB(Pathing, Aggro) || !zone->pathing)
CalculateNewPosition(target->GetX(), target->GetY(), target->GetZ(), GetRunspeed());
else {
bool WaypointChanged, NodeReached;
glm::vec3 Goal = UpdatePath(
target->GetX(), target->GetY(), target->GetZ(),
GetRunspeed(), WaypointChanged, NodeReached
);
if (WaypointChanged)
tar_ndx = 20;
CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetRunspeed());
}
RunTo(target->GetX(), target->GetY(), target->GetZ());
}
else if (IsMoving()) {
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY()));
SetCurrentSpeed(0);
else {
FaceTarget();
}
}
}
@@ -1536,7 +1398,9 @@ void Mob::AI_Process() {
}
}
if (AI_IdleCastCheck()) {
//we processed a spell action, so do nothing else.
if (IsCasting() && GetClass() != BARD) {
StopNavigation();
}
}
else if (zone->CanDoCombat() && CastToNPC()->WillAggroNPCs() && AI_scan_area_timer->Check()) {
@@ -1572,44 +1436,38 @@ void Mob::AI_Process() {
if (distance_to_owner >= 400 || z_distance > 100) {
int pet_speed = GetWalkspeed();
bool running = false;
/**
* Distance: >= 35 (Run if far away)
*/
if (distance_to_owner >= 1225) {
pet_speed = GetRunspeed();
running = true;
}
/**
* Distance: >= 450 (Snap to owner)
*/
if (distance_to_owner >= 202500 || z_distance > 100) {
m_Position = pet_owner_position;
SendPositionUpdate();
moved = true;
if (running) {
RunTo(pet_owner_position.x, pet_owner_position.y, pet_owner_position.z);
}
else {
WalkTo(pet_owner_position.x, pet_owner_position.y, pet_owner_position.z);
}
}
else {
bool waypoint_changed, node_reached;
glm::vec3 Goal = UpdatePath(
owner->GetX(),
owner->GetY(),
owner->GetZ(),
pet_speed,
waypoint_changed,
node_reached
);
CalculateNewPosition(Goal.x, Goal.y, Goal.z, pet_speed, true);
if (running) {
RunTo(pet_owner_position.x, pet_owner_position.y, pet_owner_position.z);
}
else {
WalkTo(pet_owner_position.x, pet_owner_position.y, pet_owner_position.z);
}
}
}
else {
if (moved) {
this->FixZ();
SetCurrentSpeed(0);
moved = false;
}
StopNavigation();
}
break;
@@ -1647,29 +1505,24 @@ void Mob::AI_Process() {
* Default follow distance is 100
*/
if (distance >= follow_distance) {
int speed = GetWalkspeed();
bool running = false;
// maybe we want the NPC to only walk doing follow logic
if (GetFollowCanRun() && distance >= follow_distance + 150) {
speed = GetRunspeed();
running = true;
}
bool waypoint_changed, node_reached;
auto &Goal = follow->GetPosition();
glm::vec3 Goal = UpdatePath(
follow->GetX(),
follow->GetY(),
follow->GetZ(),
speed,
waypoint_changed,
node_reached
);
CalculateNewPosition(Goal.x, Goal.y, Goal.z, speed, true);
if (running) {
RunTo(Goal.x, Goal.y, Goal.z);
}
else {
WalkTo(Goal.x, Goal.y, Goal.z);
}
}
else {
moved = false;
SetCurrentSpeed(0);
StopNavigation();
}
}
}
@@ -1776,7 +1629,7 @@ void NPC::AI_DoMovement() {
destination.x = roambox_destination_x;
destination.y = roambox_destination_y;
destination.z = m_Position.z;
roambox_destination_z = GetFixedZ(destination) + this->GetZOffset();
roambox_destination_z = zone->zonemap ? zone->zonemap->FindClosestZ(destination, nullptr) + this->GetZOffset() : 0;
Log(Logs::Detail,
Logs::NPCRoamBox,
@@ -1791,45 +1644,29 @@ void NPC::AI_DoMovement() {
roambox_destination_y);
}
/**
bool waypoint_changed, node_reached;
glm::vec3 Goal = UpdatePath(
roambox_destination_x,
roambox_destination_y,
roambox_destination_z,
move_speed,
waypoint_changed,
node_reached
);
**/
CalculateNewPosition(roambox_destination_x, roambox_destination_y, roambox_destination_z, move_speed, true);
NavigateTo(roambox_destination_x, roambox_destination_y, roambox_destination_z);
if (m_Position.x == roambox_destination_x && m_Position.y == roambox_destination_y) {
time_until_can_move = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay);
SetMoving(false);
this->FixZ();
SendPosition();
}
return;
}
else if (roamer) {
if (AI_walking_timer->Check()) {
movetimercompleted = true;
pause_timer_complete = true;
AI_walking_timer->Disable();
}
int32 gridno = CastToNPC()->GetGrid();
if (gridno > 0 || cur_wp == -2) {
if (movetimercompleted == true) { // time to pause at wp is over
if (pause_timer_complete == true) { // time to pause at wp is over
AI_SetupNextWaypoint();
} // endif (movetimercompleted==true)
} // endif (pause_timer_complete==true)
else if (!(AI_walking_timer->Enabled())) { // currently moving
bool doMove = true;
if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY()) { // are we there yet? then stop
if(IsPositionEqual(glm::vec2(m_CurrentWayPoint.x, m_CurrentWayPoint.y), glm::vec2(GetX(), GetY()))) {
Log(Logs::Detail,
Logs::AI,
"We have reached waypoint %d (%.3f,%.3f,%.3f) on grid %d",
@@ -1838,17 +1675,13 @@ void NPC::AI_DoMovement() {
GetY(),
GetZ(),
GetGrid());
SetWaypointPause();
SetAppearance(eaStanding, false);
SetMoving(false);
if (m_CurrentWayPoint.w >= 0.0) {
SetHeading(m_CurrentWayPoint.w);
if (cur_wp_pause > 0) {
RotateTo(m_CurrentWayPoint.w);
}
this->FixZ();
SendPosition();
//kick off event_waypoint arrive
char temp[16];
sprintf(temp, "%d", cur_wp);
@@ -1862,91 +1695,46 @@ void NPC::AI_DoMovement() {
if (cur_wp == -2) {
AI_SetupNextWaypoint();
}
// wipe feign memory since we reached our first waypoint
if (cur_wp == 1)
ClearFeignMemory();
}
if (doMove) { // not at waypoint yet or at 0 pause WP, so keep moving
if (!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0))
CalculateNewPosition(
m_CurrentWayPoint.x,
m_CurrentWayPoint.y,
m_CurrentWayPoint.z,
move_speed,
true
);
else {
bool WaypointChanged;
bool NodeReached;
glm::vec3 Goal = UpdatePath(
m_CurrentWayPoint.x,
m_CurrentWayPoint.y,
m_CurrentWayPoint.z,
move_speed,
WaypointChanged,
NodeReached
);
if (WaypointChanged)
tar_ndx = 20;
if (NodeReached)
entity_list.OpenDoorsNear(CastToNPC());
CalculateNewPosition(Goal.x, Goal.y, Goal.z, move_speed, true);
if (cur_wp_pause == 0) {
pause_timer_complete = true;
AI_SetupNextWaypoint();
doMove = true;
}
}
if (doMove) { // not at waypoint yet or at 0 pause WP, so keep moving
NavigateTo(
m_CurrentWayPoint.x,
m_CurrentWayPoint.y,
m_CurrentWayPoint.z
);
}
}
} // endif (gridno > 0)
// handle new quest grid command processing
else if (gridno < 0) { // this mob is under quest control
if (movetimercompleted == true) { // time to pause has ended
if (pause_timer_complete == true) { // time to pause has ended
SetGrid(0 - GetGrid()); // revert to AI control
Log(Logs::Detail, Logs::Pathing, "Quest pathing is finished. Resuming on grid %d", GetGrid());
SetAppearance(eaStanding, false);
CalculateNewWaypoint();
}
}
}
else if (IsGuarding()) {
bool CP2Moved;
if (!RuleB(Pathing, Guard) || !zone->pathing) {
CP2Moved = CalculateNewPosition(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, move_speed);
}
else {
if (!((m_Position.x == m_GuardPoint.x) && (m_Position.y == m_GuardPoint.y) &&
(m_Position.z == m_GuardPoint.z))) {
else if (IsGuarding()) {
bool at_gp = IsPositionEqualWithinCertainZ(m_Position, m_GuardPoint, 15.0f);
bool WaypointChanged, NodeReached;
if (at_gp) {
glm::vec3 Goal = UpdatePath(
m_GuardPoint.x,
m_GuardPoint.y,
m_GuardPoint.z,
move_speed,
WaypointChanged,
NodeReached
);
if (WaypointChanged) {
tar_ndx = 20;
}
if (NodeReached) {
entity_list.OpenDoorsNear(CastToNPC());
}
CP2Moved = CalculateNewPosition(Goal.x, Goal.y, Goal.z, move_speed);
}
else {
CP2Moved = false;
}
}
if (!CP2Moved) {
if (moved) {
Log(Logs::Detail,
Logs::AI,
@@ -1958,15 +1746,17 @@ void NPC::AI_DoMovement() {
ClearFeignMemory();
moved = false;
if (GetTarget() == nullptr || DistanceSquared(m_Position, GetTarget()->GetPosition()) >= 5 * 5) {
SetHeading(m_GuardPoint.w);
RotateTo(m_GuardPoint.w);
}
else {
FaceTarget(GetTarget());
}
SetCurrentSpeed(0);
SetAppearance(GetGuardPointAnim());
}
}
else {
NavigateTo(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z);
}
}
}
@@ -1998,27 +1788,26 @@ void NPC::AI_SetupNextWaypoint() {
found_spawn->SetNPCPointerNull();
}
else {
movetimercompleted = false;
pause_timer_complete = false;
Log(Logs::Detail, Logs::Pathing, "We are departing waypoint %d.", cur_wp);
//if we were under quest control (with no grid), we are done now..
if (cur_wp == -2) {
Log(Logs::Detail, Logs::Pathing, "Non-grid quest mob has reached its quest ordered waypoint. Leaving pathing mode.");
roamer = false;
cur_wp = 0;
}
SetAppearance(eaStanding, false);
entity_list.OpenDoorsNear(CastToNPC());
entity_list.OpenDoorsNear(this);
if (!DistractedFromGrid) {
//kick off event_waypoint depart
char temp[16];
sprintf(temp, "%d", cur_wp);
parse->EventNPC(EVENT_WAYPOINT_DEPART, CastToNPC(), nullptr, temp, 0);
//setup our next waypoint, if we are still on our normal grid
//remember that the quest event above could have done anything it wanted with our grid
if (GetGrid() > 0) {
@@ -2083,20 +1872,14 @@ void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) {
void Mob::AI_Event_NoLongerEngaged() {
if (!IsAIControlled())
return;
this->AI_walking_timer->Start(RandomTimer(3000,20000));
AI_walking_timer->Start(RandomTimer(3000,20000));
time_until_can_move = Timer::GetCurrentTime();
if (minLastFightingDelayMoving == maxLastFightingDelayMoving)
time_until_can_move += minLastFightingDelayMoving;
else
time_until_can_move += zone->random.Int(minLastFightingDelayMoving, maxLastFightingDelayMoving);
// So mobs don't keep running as a ghost until AIwalking_timer fires
// if they were moving prior to losing all hate
// except if we're a pet, then we might run into some issues with pets backing off when they should immediately be moving
if(!IsPet())
{
SetRunAnimSpeed(0);
SendPosition();
}
StopNavigation();
ClearRampage();
if(IsNPC())
+548
View File
@@ -0,0 +1,548 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "../common/eqemu_logsys.h"
#include "../common/misc_functions.h"
#include "../common/spdat.h"
#include "../common/string_util.h"
#include "mob.h"
#include "quest_parser_collection.h"
#include "zonedb.h"
#ifdef BOTS
#include "bot.h"
#endif
/**
* Stores internal representation of mob texture by material slot
*
* @param material_slot
* @param texture
* @param color
* @param hero_forge_model
*/
void Mob::SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model)
{
Log(Logs::Detail, Logs::MobAppearance,
"Mob::SetMobTextureProfile [%s] material_slot: %u texture: %u color: %u hero_forge_model: %u",
this->GetCleanName(),
material_slot,
texture,
color,
hero_forge_model
);
switch (material_slot) {
case EQEmu::textures::armorHead:
mob_texture_profile.Head.Material = texture;
mob_texture_profile.Head.HerosForgeModel = hero_forge_model;
mob_texture_profile.Head.Color = color;
break;
case EQEmu::textures::armorChest:
mob_texture_profile.Chest.Material = texture;
mob_texture_profile.Chest.HerosForgeModel = hero_forge_model;
mob_texture_profile.Chest.Color = color;
break;
case EQEmu::textures::armorArms:
mob_texture_profile.Arms.Material = texture;
mob_texture_profile.Arms.HerosForgeModel = hero_forge_model;
mob_texture_profile.Arms.Color = color;
break;
case EQEmu::textures::armorWrist:
mob_texture_profile.Wrist.Material = texture;
mob_texture_profile.Wrist.HerosForgeModel = hero_forge_model;
mob_texture_profile.Wrist.Color = color;
break;
case EQEmu::textures::armorHands:
mob_texture_profile.Hands.Material = texture;
mob_texture_profile.Hands.HerosForgeModel = hero_forge_model;
mob_texture_profile.Hands.Color = color;
break;
case EQEmu::textures::armorLegs:
mob_texture_profile.Legs.Material = texture;
mob_texture_profile.Legs.HerosForgeModel = hero_forge_model;
mob_texture_profile.Legs.Color = color;
break;
case EQEmu::textures::armorFeet:
mob_texture_profile.Feet.Material = texture;
mob_texture_profile.Feet.HerosForgeModel = hero_forge_model;
mob_texture_profile.Feet.Color = color;
break;
case EQEmu::textures::weaponPrimary:
mob_texture_profile.Primary.Material = texture;
mob_texture_profile.Primary.HerosForgeModel = hero_forge_model;
mob_texture_profile.Primary.Color = color;
break;
case EQEmu::textures::weaponSecondary:
mob_texture_profile.Secondary.Material = texture;
mob_texture_profile.Secondary.HerosForgeModel = hero_forge_model;
mob_texture_profile.Secondary.Color = color;
break;
default:
return;
}
}
/**
* Returns internal representation of mob texture by material
*
* @param material_slot
* @return
*/
int32 Mob::GetTextureProfileMaterial(uint8 material_slot) const
{
switch (material_slot) {
case EQEmu::textures::armorHead:
return mob_texture_profile.Head.Material;
case EQEmu::textures::armorChest:
return mob_texture_profile.Chest.Material;
case EQEmu::textures::armorArms:
return mob_texture_profile.Arms.Material;
case EQEmu::textures::armorWrist:
return mob_texture_profile.Wrist.Material;
case EQEmu::textures::armorHands:
return mob_texture_profile.Hands.Material;
case EQEmu::textures::armorLegs:
return mob_texture_profile.Legs.Material;
case EQEmu::textures::armorFeet:
return mob_texture_profile.Feet.Material;
case EQEmu::textures::weaponPrimary:
return mob_texture_profile.Primary.Material;
case EQEmu::textures::weaponSecondary:
return mob_texture_profile.Secondary.Material;
default:
return 0;
}
}
/**
* Returns internal representation of mob texture by color
*
* @param material_slot
* @return
*/
int32 Mob::GetTextureProfileColor(uint8 material_slot) const
{
switch (material_slot) {
case EQEmu::textures::armorHead:
return mob_texture_profile.Head.Color;
case EQEmu::textures::armorChest:
return mob_texture_profile.Chest.Color;
case EQEmu::textures::armorArms:
return mob_texture_profile.Arms.Color;
case EQEmu::textures::armorWrist:
return mob_texture_profile.Wrist.Color;
case EQEmu::textures::armorHands:
return mob_texture_profile.Hands.Color;
case EQEmu::textures::armorLegs:
return mob_texture_profile.Legs.Color;
case EQEmu::textures::armorFeet:
return mob_texture_profile.Feet.Color;
case EQEmu::textures::weaponPrimary:
return mob_texture_profile.Primary.Color;
case EQEmu::textures::weaponSecondary:
return mob_texture_profile.Secondary.Color;
default:
return 0;
}
}
/**
* Returns internal representation of mob texture by HerosForgeModel
*
* @param material_slot
* @return
*/
int32 Mob::GetTextureProfileHeroForgeModel(uint8 material_slot) const
{
switch (material_slot) {
case EQEmu::textures::armorHead:
return mob_texture_profile.Head.HerosForgeModel;
case EQEmu::textures::armorChest:
return mob_texture_profile.Chest.HerosForgeModel;
case EQEmu::textures::armorArms:
return mob_texture_profile.Arms.HerosForgeModel;
case EQEmu::textures::armorWrist:
return mob_texture_profile.Wrist.HerosForgeModel;
case EQEmu::textures::armorHands:
return mob_texture_profile.Hands.HerosForgeModel;
case EQEmu::textures::armorLegs:
return mob_texture_profile.Legs.HerosForgeModel;
case EQEmu::textures::armorFeet:
return mob_texture_profile.Feet.HerosForgeModel;
case EQEmu::textures::weaponPrimary:
return mob_texture_profile.Primary.HerosForgeModel;
case EQEmu::textures::weaponSecondary:
return mob_texture_profile.Secondary.HerosForgeModel;
default:
return 0;
}
}
/**
* Gets the material or texture for a slot (leather / plate etc.)
*
* @param material_slot
* @return
*/
int32 Mob::GetEquipmentMaterial(uint8 material_slot) const
{
uint32 equipment_material = 0;
int32 ornamentation_augment_type = RuleI(Character, OrnamentationAugmentType);
int32 texture_profile_material = GetTextureProfileMaterial(material_slot);
Log(Logs::Detail, Logs::MobAppearance,
"Mob::GetEquipmentMaterial [%s] material_slot: %u texture_profile_material: %i",
this->clean_name,
material_slot,
texture_profile_material
);
if (texture_profile_material > 0) {
return texture_profile_material;
}
auto item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
if (item != nullptr) {
/**
* Handle primary / secondary texture
*/
bool is_primary_or_secondary_weapon =
material_slot == EQEmu::textures::weaponPrimary ||
material_slot == EQEmu::textures::weaponSecondary;
if (is_primary_or_secondary_weapon) {
if (this->IsClient()) {
int16 inventory_slot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
if (inventory_slot == INVALID_INDEX) {
return 0;
}
const EQEmu::ItemInstance *item_instance = CastToClient()->m_inv[inventory_slot];
if (item_instance) {
if (item_instance->GetOrnamentationAug(ornamentation_augment_type)) {
item = item_instance->GetOrnamentationAug(ornamentation_augment_type)->GetItem();
if (item && strlen(item->IDFile) > 2) {
equipment_material = atoi(&item->IDFile[2]);
}
}
else if (item_instance->GetOrnamentationIDFile()) {
equipment_material = item_instance->GetOrnamentationIDFile();
}
}
}
if (equipment_material == 0 && strlen(item->IDFile) > 2) {
equipment_material = atoi(&item->IDFile[2]);
}
}
else {
equipment_material = item->Material;
}
}
return equipment_material;
}
/**
* @param material_slot
* @return
*/
uint32 Mob::GetEquipmentColor(uint8 material_slot) const
{
const EQEmu::ItemData *item = nullptr;
if (armor_tint.Slot[material_slot].Color) {
return armor_tint.Slot[material_slot].Color;
}
item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
if (item != nullptr) {
return item->Color;
}
return 0;
}
/**
* @param material_slot
* @return
*/
int32 Mob::GetHerosForgeModel(uint8 material_slot) const
{
uint32 hero_model = 0;
if (material_slot >= 0 && material_slot < EQEmu::textures::weaponPrimary) {
uint32 ornamentation_aug_type = RuleI(Character, OrnamentationAugmentType);
const EQEmu::ItemData *item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
int16 invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
if (item != nullptr && invslot != INVALID_INDEX) {
if (IsClient()) {
const EQEmu::ItemInstance *inst = CastToClient()->m_inv[invslot];
if (inst) {
if (inst->GetOrnamentationAug(ornamentation_aug_type)) {
item = inst->GetOrnamentationAug(ornamentation_aug_type)->GetItem();
hero_model = item->HerosForgeModel;
}
else if (inst->GetOrnamentHeroModel()) {
hero_model = inst->GetOrnamentHeroModel();
}
}
}
if (hero_model == 0) {
hero_model = item->HerosForgeModel;
}
}
if (IsNPC()) {
hero_model = CastToNPC()->GetHeroForgeModel();
/**
* Robes require full model number, and should only be sent to chest, arms, wrists, and legs slots
*/
if (hero_model > 1000 && material_slot != 1 && material_slot != 2 && material_slot != 3 &&
material_slot != 5) {
hero_model = 0;
}
}
}
/**
* Auto-Convert Hero Model to match the slot
*
* Otherwise, use the exact Model if model is > 999
* Robes for example are 11607 to 12107 in RoF
*/
if (hero_model > 0 && hero_model < 1000) {
hero_model *= 100;
hero_model += material_slot;
}
return hero_model;
}
uint32 NPC::GetEquippedItemFromTextureSlot(uint8 material_slot) const
{
if (material_slot > 8) {
return 0;
}
int16 inventory_slot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
if (inventory_slot == INVALID_INDEX) {
return 0;
}
return equipment[inventory_slot];
}
/**
* NPCs typically use this function for sending appearance
* @param one_client
*/
void Mob::SendArmorAppearance(Client *one_client)
{
/**
* one_client of 0 means sent to all clients
*
* Despite the fact that OP_NewSpawn and OP_ZoneSpawns include the
* armor being worn and its mats, the client doesn't update the display
* on arrival of these packets reliably.
*
* Send Wear changes if mob is a PC race and item is an armor slot.
* The other packets work for primary/secondary.
*/
Log(Logs::Detail, Logs::MobAppearance, "Mob::SendArmorAppearance [%s]",
this->GetCleanName()
);
if (IsPlayerRace(race)) {
if (!IsClient()) {
for (uint8 i = 0; i <= EQEmu::textures::materialCount; ++i) {
const EQEmu::ItemData *item = database.GetItem(GetEquippedItemFromTextureSlot(i));
if (item != nullptr) {
SendWearChange(i, one_client);
}
}
}
}
for (uint8 i = 0; i <= EQEmu::textures::materialCount; ++i) {
if (GetTextureProfileMaterial(i)) {
SendWearChange(i, one_client);
}
}
}
/**
* @param material_slot
* @param one_client
*/
void Mob::SendWearChange(uint8 material_slot, Client *one_client)
{
auto packet = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
auto *wear_change = (WearChange_Struct *) packet->pBuffer;
Log(Logs::Detail, Logs::MobAppearance, "Mob::SendWearChange [%s]",
this->GetCleanName()
);
wear_change->spawn_id = GetID();
wear_change->material = static_cast<uint32>(GetEquipmentMaterial(material_slot));
wear_change->elite_material = IsEliteMaterialItem(material_slot);
wear_change->hero_forge_model = static_cast<uint32>(GetHerosForgeModel(material_slot));
#ifdef BOTS
if (IsBot()) {
auto item_inst = CastToBot()->GetBotItem(EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot));
if (item_inst)
wear_change->color.Color = item_inst->GetColor();
else
wear_change->color.Color = 0;
}
else {
wear_change->color.Color = GetEquipmentColor(material_slot);
}
#else
wear_change->color.Color = GetEquipmentColor(material_slot);
#endif
wear_change->wear_slot_id = material_slot;
if (!one_client) {
entity_list.QueueClients(this, packet);
}
else {
one_client->QueuePacket(packet, false, Client::CLIENT_CONNECTED);
}
safe_delete(packet);
}
/**
*
* @param slot
* @param texture
* @param hero_forge_model
* @param elite_material
* @param unknown06
* @param unknown18
*/
void Mob::SendTextureWC(
uint8 slot,
uint16 texture,
uint32 hero_forge_model,
uint32 elite_material,
uint32 unknown06,
uint32 unknown18
)
{
auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
auto *wear_change = (WearChange_Struct *) outapp->pBuffer;
if (this->IsClient()) {
wear_change->color.Color = GetEquipmentColor(slot);
}
else {
wear_change->color.Color = this->GetArmorTint(slot);
}
wear_change->spawn_id = this->GetID();
wear_change->material = texture;
wear_change->wear_slot_id = slot;
wear_change->unknown06 = unknown06;
wear_change->elite_material = elite_material;
wear_change->hero_forge_model = hero_forge_model;
wear_change->unknown18 = unknown18;
SetMobTextureProfile(slot, texture, wear_change->color.Color, hero_forge_model);
entity_list.QueueClients(this, outapp);
safe_delete(outapp);
}
/**
* @param material_slot
* @param red_tint
* @param green_tint
* @param blue_tint
*/
void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint)
{
uint32 color;
color = (red_tint & 0xFF) << 16;
color |= (green_tint & 0xFF) << 8;
color |= (blue_tint & 0xFF);
color |= (color) ? (0xFF << 24) : 0;
armor_tint.Slot[material_slot].Color = color;
auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
auto *wc = (WearChange_Struct *) outapp->pBuffer;
wc->spawn_id = this->GetID();
wc->material = GetEquipmentMaterial(material_slot);
wc->hero_forge_model = GetHerosForgeModel(material_slot);
wc->color.Color = color;
wc->wear_slot_id = material_slot;
SetMobTextureProfile(material_slot, texture, color);
entity_list.QueueClients(this, outapp);
safe_delete(outapp);
}
/**
* @param material_slot
* @param texture
* @param color
* @param hero_forge_model
*/
void Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model)
{
armor_tint.Slot[material_slot].Color = color;
/**
* Change internal values
*/
SetMobTextureProfile(material_slot, texture, color, hero_forge_model);
/**
* Packet update
*/
auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
auto *wear_change = (WearChange_Struct *) outapp->pBuffer;
wear_change->spawn_id = this->GetID();
wear_change->material = texture;
wear_change->hero_forge_model = hero_forge_model;
wear_change->color.Color = color;
wear_change->wear_slot_id = material_slot;
entity_list.QueueClients(this, outapp);
safe_delete(outapp);
}
+5 -1
View File
@@ -618,6 +618,10 @@ inline void NPCCommandsMenu(Client* client, NPC* npc)
menu_commands += "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#npcloot show", false, "Loot") + "] ";
}
if (npc->IsProximitySet()) {
menu_commands += "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#proximity show", false, "Proximity") + "] ";
}
if (menu_commands.length() > 0) {
std::string dev_menu = "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#devtools", false, "DevTools") + "] ";;
client->Message(0, "| %s [Show Commands] %s", dev_menu.c_str(), menu_commands.c_str());
@@ -813,7 +817,7 @@ void Mob::DisplayInfo(Mob *mob)
NPCCommandsMenu(client, npc);
}
std::cout << "Window Length: " << window_text.length() << std::endl;
// std::cout << "Window Length: " << window_text.length() << std::endl;
if (client->GetDisplayMobInfoWindow()) {
client->SendFullPopup(
File diff suppressed because it is too large Load Diff
+83
View File
@@ -0,0 +1,83 @@
#pragma once
#include <memory>
class Mob;
class Client;
struct RotateCommand;
struct MovementCommand;
struct MobMovementEntry;
struct PlayerPositionUpdateServer_Struct;
enum ClientRange : int
{
ClientRangeNone = 0,
ClientRangeClose = 1,
ClientRangeMedium = 2,
ClientRangeCloseMedium = 3,
ClientRangeLong = 4,
ClientRangeCloseLong = 5,
ClientRangeMediumLong = 6,
ClientRangeAny = 7
};
enum MobMovementMode : int
{
MovementWalking = 0,
MovementRunning = 1
};
enum MobStuckBehavior : int
{
RunToTarget,
WarpToTarget,
TakeNoAction,
EvadeCombat,
MaxStuckBehavior
};
class MobMovementManager
{
public:
~MobMovementManager();
void Process();
void AddMob(Mob *m);
void RemoveMob(Mob *m);
void AddClient(Client *c);
void RemoveClient(Client *c);
void RotateTo(Mob *who, float to, MobMovementMode mode = MovementRunning);
void Teleport(Mob *who, float x, float y, float z, float heading);
void NavigateTo(Mob *who, float x, float y, float z, MobMovementMode mode = MovementRunning);
void StopNavigation(Mob *who);
void SendCommandToClients(Mob *m, float dx, float dy, float dz, float dh, int anim, ClientRange range);
float FixHeading(float in);
void DumpStats(Client *to);
void ClearStats();
static MobMovementManager &Get() {
static MobMovementManager inst;
return inst;
}
private:
MobMovementManager();
MobMovementManager(const MobMovementManager&);
MobMovementManager& operator=(const MobMovementManager&);
void FillCommandStruct(PlayerPositionUpdateServer_Struct *spu, Mob *m, float dx, float dy, float dz, float dh, int anim);
void UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mode);
void UpdatePathGround(Mob *who, float x, float y, float z, MobMovementMode mode);
void UpdatePathUnderwater(Mob *who, float x, float y, float z, MobMovementMode mode);
void UpdatePathBoat(Mob *who, float x, float y, float z, MobMovementMode mode);
void PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading);
void PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode);
void PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode);
void PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mode);
void PushStopMoving(MobMovementEntry &ent);
void PushEvadeCombat(MobMovementEntry &ent);
void HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mode);
struct Implementation;
std::unique_ptr<Implementation> _impl;
};
+8 -5
View File
@@ -110,7 +110,7 @@ EQEmuLogSys LogSys;
const SPDat_Spell_Struct* spells;
int32 SPDAT_RECORDS = -1;
const ZoneConfig *Config;
uint64_t frame_time = 0;
double frame_time = 0.0;
void Shutdown();
extern void MapOpcodes();
@@ -362,18 +362,21 @@ int main(int argc, char** argv) {
std::string tmp;
if (database.GetVariable("RuleSet", tmp)) {
Log(Logs::General, Logs::Zone_Server, "Loading rule set '%s'", tmp.c_str());
if (!RuleManager::Instance()->LoadRules(&database, tmp.c_str())) {
if (!RuleManager::Instance()->LoadRules(&database, tmp.c_str(), false)) {
Log(Logs::General, Logs::Error, "Failed to load ruleset '%s', falling back to defaults.", tmp.c_str());
}
}
else {
if (!RuleManager::Instance()->LoadRules(&database, "default")) {
if (!RuleManager::Instance()->LoadRules(&database, "default", false)) {
Log(Logs::General, Logs::Zone_Server, "No rule set configured, using default rules");
}
else {
Log(Logs::General, Logs::Zone_Server, "Loaded default rule set 'default'", tmp.c_str());
}
}
EQEmu::InitializeDynamicLookups();
Log(Logs::General, Logs::Zone_Server, "Initialized dynamic dictionary entries");
}
#ifdef BOTS
@@ -453,7 +456,7 @@ int main(int argc, char** argv) {
//Calculate frame time
std::chrono::time_point<std::chrono::system_clock> frame_now = std::chrono::system_clock::now();
frame_time = std::chrono::duration_cast<std::chrono::milliseconds>(frame_now - frame_prev).count();
frame_time = std::chrono::duration_cast<std::chrono::duration<double>>(frame_now - frame_prev).count();
frame_prev = frame_now;
if (!eqsf_open && Config->ZonePort != 0) {
@@ -680,4 +683,4 @@ void UpdateWindowTitle(char* iNewTitle) {
}
SetConsoleTitle(tmp);
#endif
}
}
+135 -75
View File
@@ -39,6 +39,7 @@
#include "spawn2.h"
#include "zone.h"
#include "quest_parser_collection.h"
#include "water_map.h"
#include "npc_scale_manager.h"
#include <cctype>
@@ -58,7 +59,7 @@ extern Zone* zone;
extern volatile bool is_zone_loaded;
extern EntityList entity_list;
NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &position, int iflymode, bool IsCorpse)
NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &position, GravityBehavior iflymode, bool IsCorpse)
: Mob(
npc_type_data->name,
npc_type_data->lastname,
@@ -506,7 +507,7 @@ void NPC::SetTarget(Mob* mob) {
if (owner) {
auto client = owner->CastToClient();
if (client->ClientVersionBit() & EQEmu::versions::bit_UFAndLater) {
if (client->ClientVersionBit() & EQEmu::versions::maskUFAndLater) {
auto app = new EQApplicationPacket(OP_PetHoTT, sizeof(ClientTarget_Struct));
auto ct = (ClientTarget_Struct *)app->pBuffer;
ct->new_target = mob ? mob->GetID() : 0;
@@ -803,9 +804,8 @@ bool NPC::Process()
DoGravityEffect();
}
if(reface_timer->Check() && !IsEngaged() && (m_GuardPoint.x == GetX() && m_GuardPoint.y == GetY() && m_GuardPoint.z == GetZ())) {
SetHeading(m_GuardPoint.w);
SendPosition();
if(reface_timer->Check() && !IsEngaged() && IsPositionEqualWithinCertainZ(m_Position, m_GuardPoint, 5.0f)) {
RotateTo(m_GuardPoint.w);
reface_timer->Disable();
}
@@ -973,7 +973,7 @@ bool NPC::SpawnZoneController()
memset(npc_type, 0, sizeof(NPCType));
strncpy(npc_type->name, "zone_controller", 60);
npc_type->cur_hp = 2000000000;
npc_type->current_hp = 2000000000;
npc_type->max_hp = 2000000000;
npc_type->hp_regen = 100000000;
npc_type->race = 240;
@@ -1009,7 +1009,7 @@ bool NPC::SpawnZoneController()
point.y = 1000;
point.z = 500;
auto npc = new NPC(npc_type, nullptr, point, FlyMode3);
auto npc = new NPC(npc_type, nullptr, point, GravityBehavior::Flying);
npc->GiveNPCTypeData(npc_type);
entity_list.AddNPC(npc);
@@ -1024,7 +1024,7 @@ NPC * NPC::SpawnGridNodeNPC(std::string name, const glm::vec4 &position, uint32
sprintf(npc_type->name, "%u_%u", grid_id, grid_number);
sprintf(npc_type->lastname, "Number: %u Grid: %u Pause: %u", grid_number, grid_id, pause);
npc_type->cur_hp = 4000000;
npc_type->current_hp = 4000000;
npc_type->max_hp = 4000000;
npc_type->race = 2254;
npc_type->gender = 2;
@@ -1037,22 +1037,50 @@ NPC * NPC::SpawnGridNodeNPC(std::string name, const glm::vec4 &position, uint32
npc_type->light = 1;
npc_type->size = 1;
npc_type->runspeed = 0;
npc_type->merchanttype = 1;
npc_type->bodytype = 1;
npc_type->show_name = true;
npc_type->findable = true;
auto node_position = glm::vec4(position.x, position.y, position.z, position.w);
auto npc = new NPC(npc_type, nullptr, node_position, GravityBehavior::Flying);
npc->GiveNPCTypeData(npc_type);
entity_list.AddNPC(npc, true, true);
return npc;
}
NPC * NPC::SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4 &position) {
auto npc_type = new NPCType;
memset(npc_type, 0, sizeof(NPCType));
sprintf(npc_type->name, "%s", name.c_str());
sprintf(npc_type->lastname, "%s", last_name.c_str());
npc_type->current_hp = 4000000;
npc_type->max_hp = 4000000;
npc_type->race = 2254;
npc_type->gender = 2;
npc_type->class_ = 9;
npc_type->deity = 1;
npc_type->level = 200;
npc_type->npc_id = 0;
npc_type->loottable_id = 0;
npc_type->texture = 1;
npc_type->light = 1;
npc_type->size = 3;
npc_type->d_melee_texture1 = 1;
npc_type->d_melee_texture2 = 1;
npc_type->merchanttype = 1;
npc_type->bodytype = 1;
npc_type->show_name = true;
npc_type->STR = 150;
npc_type->STA = 150;
npc_type->DEX = 150;
npc_type->AGI = 150;
npc_type->INT = 150;
npc_type->WIS = 150;
npc_type->CHA = 150;
npc_type->findable = true;
npc_type->runspeed = 1.25;
auto node_position = glm::vec4(position.x, position.y, position.z, position.w);
auto npc = new NPC(npc_type, nullptr, node_position, FlyMode1);
auto npc = new NPC(npc_type, nullptr, node_position, GravityBehavior::Flying);
npc->GiveNPCTypeData(npc_type);
entity_list.AddNPC(npc, true, true);
@@ -1067,33 +1095,45 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client*
else {
Seperator sep(spawncommand);
//Lets see if someone didn't fill out the whole #spawn function properly
if (!sep.IsNumber(1))
sprintf(sep.arg[1],"1");
if (!sep.IsNumber(2))
sprintf(sep.arg[2],"1");
if (!sep.IsNumber(3))
sprintf(sep.arg[3],"0");
if (atoi(sep.arg[4]) > 2100000000 || atoi(sep.arg[4]) <= 0)
sprintf(sep.arg[4]," ");
if (!strcmp(sep.arg[5],"-"))
sprintf(sep.arg[5]," ");
if (!sep.IsNumber(5))
sprintf(sep.arg[5]," ");
if (!sep.IsNumber(6))
sprintf(sep.arg[6],"1");
if (!sep.IsNumber(8))
sprintf(sep.arg[8],"0");
if (!sep.IsNumber(9))
if (!sep.IsNumber(1)) {
sprintf(sep.arg[1], "1");
}
if (!sep.IsNumber(2)) {
sprintf(sep.arg[2], "1");
}
if (!sep.IsNumber(3)) {
sprintf(sep.arg[3], "0");
}
if (atoi(sep.arg[4]) > 2100000000 || atoi(sep.arg[4]) <= 0) {
sprintf(sep.arg[4], " ");
}
if (!strcmp(sep.arg[5], "-")) {
sprintf(sep.arg[5], " ");
}
if (!sep.IsNumber(5)) {
sprintf(sep.arg[5], " ");
}
if (!sep.IsNumber(6)) {
sprintf(sep.arg[6], "1");
}
if (!sep.IsNumber(8)) {
sprintf(sep.arg[8], "0");
}
if (!sep.IsNumber(9)) {
sprintf(sep.arg[9], "0");
if (!sep.IsNumber(7))
sprintf(sep.arg[7],"0");
if (!strcmp(sep.arg[4],"-"))
sprintf(sep.arg[4]," ");
if (!sep.IsNumber(10)) // bodytype
}
if (!sep.IsNumber(7)) {
sprintf(sep.arg[7], "0");
}
if (!strcmp(sep.arg[4], "-")) {
sprintf(sep.arg[4], " ");
}
if (!sep.IsNumber(10)) { // bodytype
sprintf(sep.arg[10], "0");
}
//Calc MaxHP if client neglected to enter it...
if (!sep.IsNumber(4)) {
sep.arg[4] = 0;
if (sep.arg[4] && !sep.IsNumber(4)) {
sprintf(sep.arg[4], "0");
}
// Autoselect NPC Gender
@@ -1106,7 +1146,7 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client*
memset(npc_type, 0, sizeof(NPCType));
strncpy(npc_type->name, sep.arg[0], 60);
npc_type->cur_hp = atoi(sep.arg[4]);
npc_type->current_hp = atoi(sep.arg[4]);
npc_type->max_hp = atoi(sep.arg[4]);
npc_type->race = atoi(sep.arg[1]);
npc_type->gender = atoi(sep.arg[5]);
@@ -1136,7 +1176,7 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client*
npc_type->prim_melee_type = 28;
npc_type->sec_melee_type = 28;
auto npc = new NPC(npc_type, nullptr, position, FlyMode3);
auto npc = new NPC(npc_type, nullptr, position, GravityBehavior::Water);
npc->GiveNPCTypeData(npc_type);
entity_list.AddNPC(npc);
@@ -1348,7 +1388,7 @@ uint32 ZoneDatabase::DeleteSpawnRemoveFromNPCTypeTable(const char *zone, uint32
uint32 spawngroupID = 0;
std::string query = StringFormat("SELECT id, spawngroupID FROM spawn2 WHERE zone = '%s' "
"AND version = %u AND spawngroupID = %i",
"AND (version = %u OR version = -1) AND spawngroupID = %i",
zone, zone_version, spawn->GetSp2());
auto results = QueryDatabase(query);
if (!results.Success())
@@ -1459,38 +1499,49 @@ uint32 ZoneDatabase::NPCSpawnDB(uint8 command, const char* zone, uint32 zone_ver
int32 NPC::GetEquipmentMaterial(uint8 material_slot) const
{
if (material_slot >= EQEmu::textures::materialCount)
int32 texture_profile_material = GetTextureProfileMaterial(material_slot);
Log(Logs::Detail, Logs::MobAppearance, "NPC::GetEquipmentMaterial [%s] material_slot: %u",
this->clean_name,
material_slot
);
if (texture_profile_material > 0) {
return texture_profile_material;
}
if (material_slot >= EQEmu::textures::materialCount) {
return 0;
}
int16 invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
if (invslot == INVALID_INDEX)
if (invslot == INVALID_INDEX) {
return 0;
}
if (equipment[invslot] == 0)
{
switch(material_slot)
{
case EQEmu::textures::armorHead:
return helmtexture;
case EQEmu::textures::armorChest:
return texture;
case EQEmu::textures::armorArms:
return armtexture;
case EQEmu::textures::armorWrist:
return bracertexture;
case EQEmu::textures::armorHands:
return handtexture;
case EQEmu::textures::armorLegs:
return legtexture;
case EQEmu::textures::armorFeet:
return feettexture;
case EQEmu::textures::weaponPrimary:
return d_melee_texture1;
case EQEmu::textures::weaponSecondary:
return d_melee_texture2;
default:
//they have nothing in the slot, and its not a special slot... they get nothing.
return(0);
if (equipment[invslot] == 0) {
switch (material_slot) {
case EQEmu::textures::armorHead:
return helmtexture;
case EQEmu::textures::armorChest:
return texture;
case EQEmu::textures::armorArms:
return armtexture;
case EQEmu::textures::armorWrist:
return bracertexture;
case EQEmu::textures::armorHands:
return handtexture;
case EQEmu::textures::armorLegs:
return legtexture;
case EQEmu::textures::armorFeet:
return feettexture;
case EQEmu::textures::weaponPrimary:
return d_melee_texture1;
case EQEmu::textures::weaponSecondary:
return d_melee_texture2;
default:
//they have nothing in the slot, and its not a special slot... they get nothing.
return (0);
}
}
@@ -2136,8 +2187,8 @@ void NPC::ModifyNPCStat(const char *identifier, const char *new_value)
base_hp = atoi(val.c_str());
CalcMaxHP();
if (cur_hp > max_hp) {
cur_hp = max_hp;
if (current_hp > max_hp) {
current_hp = max_hp;
}
return;
@@ -2318,14 +2369,14 @@ void NPC::LevelScale() {
base_hp += (random_level - level) * 100;
}
cur_hp = max_hp;
current_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;
current_hp = max_hp;
if (max_dmg) {
max_dmg += (int)(max_dmg * scaling / scale_adjust);
@@ -2366,7 +2417,7 @@ void NPC::LevelScale() {
ATK += (int)(ATK * scaling);
base_hp += (int)(base_hp * scaling);
max_hp += (int)(max_hp * scaling);
cur_hp = max_hp;
current_hp = max_hp;
STR += (int)(STR * scaling / scale_adjust);
STA += (int)(STA * scaling / scale_adjust);
AGI += (int)(AGI * scaling / scale_adjust);
@@ -2849,3 +2900,12 @@ float NPC::GetProximityMaxZ()
{
return proximity->max_z;
}
bool NPC::IsProximitySet()
{
if (proximity && proximity->proximity_set) {
return proximity->proximity_set;
}
return false;
}
+10 -7
View File
@@ -51,6 +51,7 @@ typedef struct {
float min_z;
float max_z;
bool say;
bool proximity_set;
} NPCProximity;
struct AISpells_Struct {
@@ -106,10 +107,11 @@ public:
static bool SpawnZoneController();
static int8 GetAILevel(bool iForceReRead = false);
NPC(const NPCType* npc_type_data, Spawn2* respawn, const glm::vec4& position, int iflymode, bool IsCorpse = false);
NPC(const NPCType* npc_type_data, Spawn2* respawn, const glm::vec4& position, GravityBehavior iflymode, bool IsCorpse = false);
virtual ~NPC();
static NPC *SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4 &position);
static NPC *SpawnGridNodeNPC(std::string name, const glm::vec4 &position, uint32 grid_id, uint32 grid_number, uint32 pause);
//abstract virtual function implementations requird by base abstract class
@@ -226,9 +228,6 @@ public:
EmuAppearance GetGuardPointAnim() const { return guard_anim; }
void SaveGuardPointAnim(EmuAppearance anim) { guard_anim = anim; }
void SetFlyMode(uint8 FlyMode){ flymode=FlyMode; }
uint32 GetFlyMode() const { return flymode; }
uint8 GetPrimSkill() const { return prim_melee_type; }
uint8 GetSecSkill() const { return sec_melee_type; }
uint8 GetRangedSkill() const { return ranged_type; }
@@ -312,11 +311,11 @@ public:
void MoveTo(const glm::vec4& position, bool saveguardspot);
void GetClosestWaypoint(std::list<wplist> &wp_list, int count, const glm::vec3& location);
uint32 GetEquipment(uint8 material_slot) const; // returns item id
uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const; // returns item id
int32 GetEquipmentMaterial(uint8 material_slot) const;
void NextGuardPosition();
void SaveGuardSpot(bool iClearGuardSpot = false);
void SaveGuardSpot(const glm::vec4 &pos);
inline bool IsGuarding() const { return(m_GuardPoint.w != 0); }
void SaveGuardSpotCharm();
@@ -358,6 +357,7 @@ public:
float GetProximityMaxY();
float GetProximityMinZ();
float GetProximityMaxZ();
bool IsProximitySet();
ItemList itemlist; //kathgar - why is this public? Doing other things or I would check the code
@@ -402,7 +402,7 @@ public:
/* Only allows players that killed corpse to loot */
const bool HasPrivateCorpse() const { return NPCTypedata->private_corpse; }
const bool IsUnderwaterOnly() const { return NPCTypedata->underwater; }
virtual const bool IsUnderwaterOnly() const { return NPCTypedata->underwater; }
const char* GetRawNPCTypeName() const { return NPCTypedata->name; }
void ChangeLastName(const char* in_lastname);
@@ -466,6 +466,9 @@ public:
std::unique_ptr<Timer> AIautocastspell_timer;
virtual int GetStuckBehavior() const { return NPCTypedata_ours ? NPCTypedata_ours->stuck_behavior : NPCTypedata->stuck_behavior; }
protected:
const NPCType* NPCTypedata;
+1 -1
View File
@@ -100,7 +100,7 @@ void NpcScaleManager::ScaleNPC(NPC * npc)
if (npc->GetPhR() == 0) {
npc->ModifyNPCStat("pr", std::to_string(scale_data.physical_resist).c_str());
}
if (npc->GetMinDMG() == 0) {
if (npc->GetMinDMG() == 0 && npc->GetMaxDMG() == 0) {
int min_dmg = scale_data.min_dmg;
if (RuleB(Combat, UseNPCDamageClassLevelMods)) {
int32 class_level_damage_mod = GetClassLevelDamageMod(npc->GetLevel(), npc->GetClass());
-5
View File
@@ -8,15 +8,10 @@
IPathfinder *IPathfinder::Load(const std::string &zone) {
struct stat statbuffer;
std::string waypoint_path = fmt::format("maps/path/{0}.path", zone);
std::string navmesh_path = fmt::format("maps/nav/{0}.nav", zone);
if (stat(navmesh_path.c_str(), &statbuffer) == 0) {
return new PathfinderNavmesh(navmesh_path);
}
if (stat(waypoint_path.c_str(), &statbuffer) == 0) {
return new PathfinderWaypoint(waypoint_path);
}
return new PathfinderNull();
}
+47 -2
View File
@@ -6,6 +6,50 @@
class Client;
class Seperator;
enum PathingPolyFlags
{
PathingNormal = 1,
PathingWater = 2,
PathingLava = 4,
PathingZoneLine = 8,
PathingPvP = 16,
PathingSlime = 32,
PathingIce = 64,
PathingVWater = 128,
PathingGeneralArea = 256,
PathingPortal = 512,
PathingPrefer = 1024,
PathingDisabled = 2048,
PathingAll = 65535,
PathingNotDisabled = PathingAll ^ PathingDisabled
};
struct PathfinderOptions
{
PathfinderOptions() {
flags = PathingNotDisabled;
smooth_path = true;
step_size = 10.0f;
flag_cost[0] = 1.0f;
flag_cost[1] = 3.0f;
flag_cost[2] = 5.0f;
flag_cost[3] = 1.0f;
flag_cost[4] = 2.0f;
flag_cost[5] = 2.0f;
flag_cost[6] = 4.0f;
flag_cost[7] = 1.0f;
flag_cost[8] = 0.1f;
flag_cost[9] = 0.1f;
offset = 3.25f;
}
int flags;
bool smooth_path;
float step_size;
float flag_cost[10];
float offset;
};
class IPathfinder
{
public:
@@ -29,8 +73,9 @@ public:
IPathfinder() { }
virtual ~IPathfinder() { }
virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck) = 0;
virtual glm::vec3 GetRandomLocation() = 0;
virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags = PathingNotDisabled) = 0;
virtual IPath FindPath(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, const PathfinderOptions& opts) = 0;
virtual glm::vec3 GetRandomLocation(const glm::vec3 &start) = 0;
virtual void DebugCommand(Client *c, const Seperator *sep) = 0;
static IPathfinder *Load(const std::string &zone);
+279 -25
View File
@@ -1,9 +1,9 @@
#include <memory>
#include <stdio.h>
#include <vector>
#include <DetourNavMesh.h>
#include <DetourNavMeshQuery.h>
#include "pathfinder_nav_mesh.h"
#include <DetourCommon.h>
#include <DetourNavMeshQuery.h>
#include "zone.h"
#include "water_map.h"
@@ -12,7 +12,7 @@
extern Zone *zone;
const int MaxNavmeshNodes = 4092;
const int MaxNavmeshNodes = 4096;
struct PathfinderNavmesh::Implementation
{
@@ -33,7 +33,7 @@ PathfinderNavmesh::~PathfinderNavmesh()
Clear();
}
IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck)
IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags)
{
partial = false;
@@ -43,14 +43,14 @@ IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const gl
if (!m_impl->query) {
m_impl->query = dtAllocNavMeshQuery();
m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes);
}
m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes);
glm::vec3 current_location(start.x, start.z, start.y);
glm::vec3 dest_location(end.x, end.z, end.y);
dtQueryFilter filter;
filter.setIncludeFlags(65535U ^ 2048);
filter.setIncludeFlags(flags);
filter.setAreaCost(0, 1.0f); //Normal
filter.setAreaCost(1, 3.0f); //Water
filter.setAreaCost(2, 5.0f); //Lava
@@ -131,10 +131,184 @@ IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const gl
return Route;
}
glm::vec3 PathfinderNavmesh::GetRandomLocation()
IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, const PathfinderOptions &opts)
{
partial = false;
if (!m_impl->nav_mesh) {
return glm::vec3();
return IPath();
}
if (!m_impl->query) {
m_impl->query = dtAllocNavMeshQuery();
}
m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes);
glm::vec3 current_location(start.x, start.z, start.y);
glm::vec3 dest_location(end.x, end.z, end.y);
dtQueryFilter filter;
filter.setIncludeFlags(opts.flags);
filter.setAreaCost(0, opts.flag_cost[0]); //Normal
filter.setAreaCost(1, opts.flag_cost[1]); //Water
filter.setAreaCost(2, opts.flag_cost[2]); //Lava
filter.setAreaCost(4, opts.flag_cost[3]); //PvP
filter.setAreaCost(5, opts.flag_cost[4]); //Slime
filter.setAreaCost(6, opts.flag_cost[5]); //Ice
filter.setAreaCost(7, opts.flag_cost[6]); //V Water (Frigid Water)
filter.setAreaCost(8, opts.flag_cost[7]); //General Area
filter.setAreaCost(9, opts.flag_cost[8]); //Portal
filter.setAreaCost(10, opts.flag_cost[9]); //Prefer
static const int max_polys = 256;
dtPolyRef start_ref;
dtPolyRef end_ref;
glm::vec3 ext(5.0f, 100.0f, 5.0f);
m_impl->query->findNearestPoly(&current_location[0], &ext[0], &filter, &start_ref, 0);
m_impl->query->findNearestPoly(&dest_location[0], &ext[0], &filter, &end_ref, 0);
if (!start_ref || !end_ref) {
return IPath();
}
int npoly = 0;
dtPolyRef path[max_polys] = { 0 };
m_impl->query->findPath(start_ref, end_ref, &current_location[0], &dest_location[0], &filter, path, &npoly, max_polys);
if (npoly) {
glm::vec3 epos = dest_location;
if (path[npoly - 1] != end_ref) {
m_impl->query->closestPointOnPoly(path[npoly - 1], &dest_location[0], &epos[0], 0);
partial = true;
auto dist = DistanceSquared(epos, current_location);
if (dist < 10000.0f) {
stuck = true;
}
}
int n_straight_polys;
glm::vec3 straight_path[max_polys];
unsigned char straight_path_flags[max_polys];
dtPolyRef straight_path_polys[max_polys];
auto status = m_impl->query->findStraightPath(&current_location[0], &epos[0], path, npoly,
(float*)&straight_path[0], straight_path_flags,
straight_path_polys, &n_straight_polys, 2048, DT_STRAIGHTPATH_AREA_CROSSINGS | DT_STRAIGHTPATH_ALL_CROSSINGS);
if (dtStatusFailed(status)) {
return IPath();
}
if (n_straight_polys) {
if (opts.smooth_path) {
IPath Route;
//Add the first point
{
auto &flag = straight_path_flags[0];
if (flag & DT_STRAIGHTPATH_OFFMESH_CONNECTION) {
auto &p = straight_path[0];
Route.push_back(glm::vec3(p.x, p.z, p.y));
}
else {
auto &p = straight_path[0];
float h = 0.0f;
if (dtStatusSucceed(GetPolyHeightOnPath(path, npoly, p, &h))) {
p.y = h + opts.offset;
}
Route.push_back(glm::vec3(p.x, p.z, p.y));
}
}
for (int i = 0; i < n_straight_polys - 1; ++i)
{
auto &flag = straight_path_flags[i];
if (flag & DT_STRAIGHTPATH_OFFMESH_CONNECTION) {
auto &poly = straight_path_polys[i];
auto &p2 = straight_path[i + 1];
glm::vec3 node(p2.x, p2.z, p2.y);
Route.push_back(node);
unsigned short pflag = 0;
if (dtStatusSucceed(m_impl->nav_mesh->getPolyFlags(straight_path_polys[i], &pflag))) {
if (pflag & 512) {
Route.push_back(true);
}
}
}
else {
auto &p1 = straight_path[i];
auto &p2 = straight_path[i + 1];
auto dist = glm::distance(p1, p2);
auto dir = glm::normalize(p2 - p1);
float total = 0.0f;
glm::vec3 previous_pt = p1;
while (total < dist) {
glm::vec3 current_pt;
float dist_to_move = opts.step_size;
float ff = opts.step_size / 2.0f;
if (total + dist_to_move + ff >= dist) {
current_pt = p2;
total = dist;
}
else {
total += dist_to_move;
current_pt = p1 + dir * total;
}
float h = 0.0f;
if (dtStatusSucceed(GetPolyHeightOnPath(path, npoly, current_pt, &h))) {
current_pt.y = h + opts.offset;
}
Route.push_back(glm::vec3(current_pt.x, current_pt.z, current_pt.y));
previous_pt = current_pt;
}
}
}
return Route;
}
else {
IPath Route;
for (int i = 0; i < n_straight_polys; ++i)
{
auto &current = straight_path[i];
glm::vec3 node(current.x, current.z, current.y);
Route.push_back(node);
unsigned short flag = 0;
if (dtStatusSucceed(m_impl->nav_mesh->getPolyFlags(straight_path_polys[i], &flag))) {
if (flag & 512) {
Route.push_back(true);
}
}
}
return Route;
}
}
}
return IPath();
}
glm::vec3 PathfinderNavmesh::GetRandomLocation(const glm::vec3 &start)
{
if (start.x == 0.0f && start.y == 0.0)
return glm::vec3(0.f);
if (!m_impl->nav_mesh) {
return glm::vec3(0.f);
}
if (!m_impl->query) {
@@ -143,19 +317,38 @@ glm::vec3 PathfinderNavmesh::GetRandomLocation()
}
dtQueryFilter filter;
filter.setIncludeFlags(65535U);
filter.setIncludeFlags(65535U ^ 2048);
filter.setAreaCost(0, 1.0f); //Normal
filter.setAreaCost(1, 3.0f); //Water
filter.setAreaCost(2, 5.0f); //Lava
filter.setAreaCost(4, 1.0f); //PvP
filter.setAreaCost(5, 2.0f); //Slime
filter.setAreaCost(6, 2.0f); //Ice
filter.setAreaCost(7, 4.0f); //V Water (Frigid Water)
filter.setAreaCost(8, 1.0f); //General Area
filter.setAreaCost(9, 0.1f); //Portal
filter.setAreaCost(10, 0.1f); //Prefer
dtPolyRef randomRef;
float point[3];
if (dtStatusSucceed(m_impl->query->findRandomPoint(&filter, []() {
return (float)zone->random.Real(0.0, 1.0);
}, &randomRef, point)))
dtPolyRef start_ref;
glm::vec3 current_location(start.x, start.z, start.y);
glm::vec3 ext(5.0f, 100.0f, 5.0f);
m_impl->query->findNearestPoly(&current_location[0], &ext[0], &filter, &start_ref, 0);
if (!start_ref)
{
return glm::vec3(0.f);
}
if (dtStatusSucceed(m_impl->query->findRandomPointAroundCircle(start_ref, &current_location[0], 100.f, &filter, []() { return (float)zone->random.Real(0.0, 1.0); }, &randomRef, point)))
{
return glm::vec3(point[0], point[2], point[1]);
}
return glm::vec3();
return glm::vec3(0.f);
}
void PathfinderNavmesh::DebugCommand(Client *c, const Seperator *sep)
@@ -288,24 +481,85 @@ void PathfinderNavmesh::Load(const std::string &path)
void PathfinderNavmesh::ShowPath(Client * c, const glm::vec3 &start, const glm::vec3 &end)
{
auto &list = entity_list.GetNPCList();
for (auto &iter : list) {
auto npc = iter.second;
auto name = npc->GetName();
if (strstr(name, "PathNode") != nullptr) {
npc->Depop();
}
}
PathfinderOptions opts;
opts.smooth_path = true;
opts.step_size = RuleR(Pathing, NavmeshStepSize);
bool partial = false;
bool stuck = false;
auto path = FindRoute(start, end, partial, stuck);
std::vector<FindPerson_Point> points;
auto path = FindPath(start, end, partial, stuck, opts);
if (!partial) {
FindPerson_Point p;
for (auto &node : path)
for (auto &node : path) {
if (!node.teleport) {
NPC::SpawnNPC("PathNode 2253 1 0 1 2 1", glm::vec4(node.pos, 1.0));
}
}
}
dtStatus PathfinderNavmesh::GetPolyHeightNoConnections(dtPolyRef ref, const float *pos, float *height) const
{
auto *m_nav = m_impl->nav_mesh;
if (!m_nav) {
return DT_FAILURE;
}
const dtMeshTile* tile = 0;
const dtPoly* poly = 0;
if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) {
return DT_FAILURE | DT_INVALID_PARAM;
}
if (poly->getType() != DT_POLYTYPE_OFFMESH_CONNECTION) {
const unsigned int ip = (unsigned int)(poly - tile->polys);
const dtPolyDetail* pd = &tile->detailMeshes[ip];
for (int j = 0; j < pd->triCount; ++j)
{
if (!node.teleport) {
p.x = node.pos.x;
p.y = node.pos.y;
p.z = node.pos.z;
points.push_back(p);
const unsigned char* t = &tile->detailTris[(pd->triBase + j) * 4];
const float* v[3];
for (int k = 0; k < 3; ++k)
{
if (t[k] < poly->vertCount)
v[k] = &tile->verts[poly->verts[t[k]] * 3];
else
v[k] = &tile->detailVerts[(pd->vertBase + (t[k] - poly->vertCount)) * 3];
}
float h;
if (dtClosestHeightPointTriangle(pos, v[0], v[1], v[2], h))
{
if (height)
*height = h;
return DT_SUCCESS;
}
}
}
c->SendPathPacket(points);
return DT_FAILURE | DT_INVALID_PARAM;
}
dtStatus PathfinderNavmesh::GetPolyHeightOnPath(const dtPolyRef *path, const int path_len, const glm::vec3 &pos, float *h) const
{
if (!path || !path_len) {
return DT_FAILURE;
}
for (int i = 0; i < path_len; ++i) {
dtPolyRef ref = path[i];
if (dtStatusSucceed(GetPolyHeightNoConnections(ref, &pos[0], h))) {
return DT_SUCCESS;
}
}
return DT_FAILURE;
}
+7 -3
View File
@@ -2,6 +2,7 @@
#include "pathfinder_interface.h"
#include <string>
#include <DetourNavMesh.h>
class PathfinderNavmesh : public IPathfinder
{
@@ -9,15 +10,18 @@ public:
PathfinderNavmesh(const std::string &path);
virtual ~PathfinderNavmesh();
virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck);
virtual glm::vec3 GetRandomLocation();
virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags = PathingNotDisabled);
virtual IPath FindPath(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, const PathfinderOptions& opts);
virtual glm::vec3 GetRandomLocation(const glm::vec3 &start);
virtual void DebugCommand(Client *c, const Seperator *sep);
private:
void Clear();
void Load(const std::string &path);
void ShowPath(Client *c, const glm::vec3 &start, const glm::vec3 &end);
dtStatus GetPolyHeightNoConnections(dtPolyRef ref, const float *pos, float *height) const;
dtStatus GetPolyHeightOnPath(const dtPolyRef *path, const int path_len, const glm::vec3 &pos, float *h) const;
struct Implementation;
std::unique_ptr<Implementation> m_impl;
};
};
+13 -3
View File
@@ -1,6 +1,6 @@
#include "pathfinder_null.h"
IPathfinder::IPath PathfinderNull::FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck)
IPathfinder::IPath PathfinderNull::FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags)
{
partial = false;
stuck = false;
@@ -10,7 +10,17 @@ IPathfinder::IPath PathfinderNull::FindRoute(const glm::vec3 &start, const glm::
return ret;
}
glm::vec3 PathfinderNull::GetRandomLocation()
IPathfinder::IPath PathfinderNull::FindPath(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, const PathfinderOptions &opts)
{
return glm::vec3();
partial = false;
stuck = false;
IPath ret;
ret.push_back(start);
ret.push_back(end);
return ret;
}
glm::vec3 PathfinderNull::GetRandomLocation(const glm::vec3 &start)
{
return glm::vec3(0.0f);
}
+4 -3
View File
@@ -8,7 +8,8 @@ public:
PathfinderNull() { }
virtual ~PathfinderNull() { }
virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck);
virtual glm::vec3 GetRandomLocation();
virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags = PathingNotDisabled);
virtual IPath FindPath(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, const PathfinderOptions& opts);
virtual glm::vec3 GetRandomLocation(const glm::vec3 &start);
virtual void DebugCommand(Client *c, const Seperator *sep) { }
};
};
+4 -4
View File
@@ -114,7 +114,7 @@ PathfinderWaypoint::~PathfinderWaypoint()
{
}
IPathfinder::IPath PathfinderWaypoint::FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck)
IPathfinder::IPath PathfinderWaypoint::FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags)
{
stuck = false;
partial = false;
@@ -184,7 +184,7 @@ IPathfinder::IPath PathfinderWaypoint::FindRoute(const glm::vec3 &start, const g
return IPath();
}
glm::vec3 PathfinderWaypoint::GetRandomLocation()
glm::vec3 PathfinderWaypoint::GetRandomLocation(const glm::vec3 &start)
{
if (m_impl->Nodes.size() > 0) {
auto idx = zone->random.Int(0, (int)m_impl->Nodes.size() - 1);
@@ -529,7 +529,7 @@ void PathfinderWaypoint::ShowNode(const Node &n) {
sprintf(npc_type->name, "%s", DigitToWord(n.id).c_str());
sprintf(npc_type->lastname, "%i", n.id);
npc_type->cur_hp = 4000000;
npc_type->current_hp = 4000000;
npc_type->max_hp = 4000000;
npc_type->race = 2254;
npc_type->gender = 2;
@@ -557,7 +557,7 @@ void PathfinderWaypoint::ShowNode(const Node &n) {
npc_type->findable = 1;
auto position = glm::vec4(n.v.x, n.v.y, n.v.z, 0.0f);
auto npc = new NPC(npc_type, nullptr, position, FlyMode1);
auto npc = new NPC(npc_type, nullptr, position, GravityBehavior::Flying);
npc->GiveNPCTypeData(npc_type);
entity_list.AddNPC(npc, true, true);
+3 -3
View File
@@ -11,8 +11,8 @@ public:
PathfinderWaypoint(const std::string &path);
virtual ~PathfinderWaypoint();
virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck);
virtual glm::vec3 GetRandomLocation();
virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags = PathingNotDisabled);
virtual glm::vec3 GetRandomLocation(const glm::vec3 &start);
virtual void DebugCommand(Client *c, const Seperator *sep);
private:
@@ -28,4 +28,4 @@ private:
struct Implementation;
std::unique_ptr<Implementation> m_impl;
};
};
-201
View File
@@ -7,207 +7,6 @@
extern Zone *zone;
void AdjustRoute(std::list<IPathfinder::IPathNode> &nodes, int flymode, float offset) {
if (!zone->HasMap() || !zone->HasWaterMap()) {
return;
}
for (auto &node : nodes) {
if (flymode == 0 || !zone->watermap->InLiquid(node.pos)) {
auto best_z = zone->zonemap->FindBestZ(node.pos, nullptr);
if (best_z != BEST_Z_INVALID) {
node.pos.z = best_z + offset;
}
}
}
}
glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChanged, bool &NodeReached)
{
glm::vec3 To(ToX, ToY, ToZ);
if (Speed <= 0) {
return To;
}
glm::vec3 From(GetX(), GetY(), GetZ());
if (DistanceSquared(To, From) < 1.0f) {
WaypointChanged = false;
NodeReached = true;
Route.clear();
return To;
}
if (Route.empty()) {
bool partial = false;
bool stuck = false;
Route = zone->pathing->FindRoute(From, To, partial, stuck);
AdjustRoute(Route, flymode, GetZOffset());
PathingDestination = To;
WaypointChanged = true;
NodeReached = false;
if (stuck) {
return HandleStuckPath(To, From);
}
if (Route.empty()) {
return To;
}
else {
return (*Route.begin()).pos;
}
}
else {
if (PathRecalcTimer->Check()) {
bool SameDestination = DistanceSquared(To, PathingDestination) < 100.0f;
if (!SameDestination) {
//We had a route but our target position moved too much
bool partial = false;
bool stuck = false;
Route = zone->pathing->FindRoute(From, To, partial, stuck);
AdjustRoute(Route, flymode, GetZOffset());
PathingDestination = To;
WaypointChanged = true;
NodeReached = false;
if (stuck) {
return HandleStuckPath(To, From);
}
if (Route.empty()) {
return To;
}
else {
return (*Route.begin()).pos;
}
}
}
if (!IsRooted()) {
bool AtPrevNode = DistanceSquared(From, PathingLastPosition) < 1.0f;
if (AtPrevNode) {
PathingLoopCount++;
auto front = (*Route.begin()).pos;
if (PathingLoopCount > 5) {
Teleport(front);
SendPosition();
Route.pop_front();
WaypointChanged = true;
NodeReached = true;
PathingLoopCount = 0;
}
return front;
}
else {
PathingLastPosition = From;
PathingLoopCount = 0;
}
}
else {
PathingLastPosition = From;
PathingLoopCount = 0;
}
bool AtNextNode = false;
if (flymode == 1) {
AtNextNode = DistanceSquared(From, (*Route.begin()).pos) < 4.0f;
}
else {
float z_dist = From.z - (*Route.begin()).pos.z;
z_dist *= z_dist;
AtNextNode = DistanceSquaredNoZ(From, (*Route.begin()).pos) < 4.0f && z_dist < 25.0f;
}
if (AtNextNode) {
WaypointChanged = false;
NodeReached = true;
Route.pop_front();
if (Route.empty()) {
bool partial = false;
bool stuck = false;
Route = zone->pathing->FindRoute(From, To, partial, stuck);
AdjustRoute(Route, flymode, GetZOffset());
PathingDestination = To;
WaypointChanged = true;
if (stuck) {
return HandleStuckPath(To, From);
}
if(Route.empty()) {
return To;
}
else {
return (*Route.begin()).pos;
}
}
else {
auto node = *Route.begin();
if (node.teleport) {
Route.pop_front();
if (Route.empty()) {
return To;
}
auto nextNode = *Route.begin();
Teleport(nextNode.pos);
Route.pop_front();
if (Route.empty()) {
return To;
}
return (*Route.begin()).pos;
}
return node.pos;
}
}
else {
WaypointChanged = false;
NodeReached = false;
return (*Route.begin()).pos;
}
}
return To;
}
glm::vec3 Mob::HandleStuckPath(const glm::vec3 &To, const glm::vec3 &From)
{
bool partial = false;
bool stuck = false;
auto r = zone->pathing->FindRoute(To, From, partial, stuck);
Route.clear();
if (r.size() < 1) {
Teleport(To);
return To;
}
auto iter = r.rbegin();
auto final_node = (*iter);
Teleport(final_node.pos);
if (r.size() < 2) {
return final_node.pos;
}
else {
iter++;
return (*iter).pos;
}
}
void CullPoints(std::vector<FindPerson_Point> &points) {
if (!zone->HasMap()) {
return;
+265 -211
View File
@@ -6126,6 +6126,59 @@ XS(XS_Client_Popup2) {
XSRETURN_EMPTY;
}
XS(XS_Client_SetPrimaryWeaponOrnamentation); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_SetPrimaryWeaponOrnamentation)
{
dXSARGS;
if (items != 2) {
Perl_croak(aTHX_ "Usage: Client::SetPrimaryWeaponOrnamentation(THIS, model_id)");
}
{
Client *THIS;
uint32 model_id = (uint32) SvUV(ST(1));
if (sv_derived_from(ST(0), "Client")) {
IV tmp = SvIV((SV *) SvRV(ST(0)));
THIS = INT2PTR(Client *, tmp);
}
else {
Perl_croak(aTHX_ "THIS is not of type Client");
}
if (THIS == nullptr) {
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
}
THIS->SetPrimaryWeaponOrnamentation(model_id);
}
XSRETURN_EMPTY;
}
XS(XS_Client_SetSecondaryWeaponOrnamentation); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_SetSecondaryWeaponOrnamentation)
{
dXSARGS;
if (items != 2) {
Perl_croak(aTHX_ "Usage: Client::SetSecondaryWeaponOrnamentation(THIS, model_id)");
}
{
Client *THIS;
uint32 model_id = (uint32) SvUV(ST(1));
if (sv_derived_from(ST(0), "Client")) {
IV tmp = SvIV((SV *) SvRV(ST(0)));
THIS = INT2PTR(Client *, tmp);
}
else {
Perl_croak(aTHX_ "THIS is not of type Client");
}
if (THIS == nullptr) {
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
}
THIS->SetSecondaryWeaponOrnamentation(model_id);
}
XSRETURN_EMPTY;
}
#ifdef __cplusplus
extern "C"
@@ -6147,240 +6200,241 @@ XS(boot_Client) {
XS_VERSION_BOOTCHECK;
newXSproto(strcpy(buf, "SendSound"), XS_Client_SendSound, file, "$");
newXSproto(strcpy(buf, "Save"), XS_Client_Save, file, "$$");
newXSproto(strcpy(buf, "SaveBackup"), XS_Client_SaveBackup, file, "$");
newXSproto(strcpy(buf, "AccountID"), XS_Client_AccountID, file, "$");
newXSproto(strcpy(buf, "AccountName"), XS_Client_AccountName, file, "$");
newXSproto(strcpy(buf, "AddAAPoints"), XS_Client_AddAAPoints, file, "$$");
newXSproto(strcpy(buf, "AddAlternateCurrencyValue"), XS_Client_AddAlternateCurrencyValue, file, "$$$");
newXSproto(strcpy(buf, "AddCrystals"), XS_Client_AddCrystals, file, "$$");
newXSproto(strcpy(buf, "AddEXP"), XS_Client_AddEXP, file, "$$;$$");
newXSproto(strcpy(buf, "AddLevelBasedExp"), XS_Client_AddLevelBasedExp, file, "$$;$");
newXSproto(strcpy(buf, "AddMoneyToPP"), XS_Client_AddMoneyToPP, file, "$$$$$$");
newXSproto(strcpy(buf, "AddPVPPoints"), XS_Client_AddPVPPoints, file, "$$");
newXSproto(strcpy(buf, "AddSkill"), XS_Client_AddSkill, file, "$$$");
newXSproto(strcpy(buf, "Admin"), XS_Client_Admin, file, "$");
newXSproto(strcpy(buf, "AssignTask"), XS_Client_AssignTask, file, "$$$;$");
newXSproto(strcpy(buf, "AssignToInstance"), XS_Client_AssignToInstance, file, "$$");
newXSproto(strcpy(buf, "AutoSplitEnabled"), XS_Client_AutoSplitEnabled, file, "$");
newXSproto(strcpy(buf, "BreakInvis"), XS_Client_BreakInvis, file, "$");
newXSproto(strcpy(buf, "CalcEXP"), XS_Client_CalcEXP, file, "$");
newXSproto(strcpy(buf, "CalcPriceMod"), XS_Client_CalcPriceMod, file, "$;$$");
newXSproto(strcpy(buf, "CanHaveSkill"), XS_Client_CanHaveSkill, file, "$$");
newXSproto(strcpy(buf, "ChangeLastName"), XS_Client_ChangeLastName, file, "$$");
newXSproto(strcpy(buf, "CharacterID"), XS_Client_CharacterID, file, "$");
newXSproto(strcpy(buf, "CheckIncreaseSkill"), XS_Client_CheckIncreaseSkill, file, "$$;$");
newXSproto(strcpy(buf, "CheckSpecializeIncrease"), XS_Client_CheckSpecializeIncrease, file, "$$");
newXSproto(strcpy(buf, "ClearCompassMark"), XS_Client_ClearCompassMark, file, "$");
newXSproto(strcpy(buf, "ClearZoneFlag"), XS_Client_ClearZoneFlag, file, "$$");
newXSproto(strcpy(buf, "Connected"), XS_Client_Connected, file, "$");
newXSproto(strcpy(buf, "InZone"), XS_Client_InZone, file, "$");
newXSproto(strcpy(buf, "Kick"), XS_Client_Kick, file, "$");
newXSproto(strcpy(buf, "DecreaseByID"), XS_Client_DecreaseByID, file, "$$$");
newXSproto(strcpy(buf, "DeleteItemInInventory"), XS_Client_DeleteItemInInventory, file, "$$;$$");
newXSproto(strcpy(buf, "Disconnect"), XS_Client_Disconnect, file, "$");
newXSproto(strcpy(buf, "IsLD"), XS_Client_IsLD, file, "$");
newXSproto(strcpy(buf, "WorldKick"), XS_Client_WorldKick, file, "$");
newXSproto(strcpy(buf, "GetAnon"), XS_Client_GetAnon, file, "$");
newXSproto(strcpy(buf, "DropItem"), XS_Client_DropItem, file, "$$");
newXSproto(strcpy(buf, "Duck"), XS_Client_Duck, file, "$");
newXSproto(strcpy(buf, "Stand"), XS_Client_Stand, file, "$");
newXSproto(strcpy(buf, "SetGM"), XS_Client_SetGM, file, "$$");
newXSproto(strcpy(buf, "SetPVP"), XS_Client_SetPVP, file, "$$");
newXSproto(strcpy(buf, "GetPVP"), XS_Client_GetPVP, file, "$");
newXSproto(strcpy(buf, "GetGM"), XS_Client_GetGM, file, "$");
newXSproto(strcpy(buf, "SetBaseClass"), XS_Client_SetBaseClass, file, "$$");
newXSproto(strcpy(buf, "SetBaseRace"), XS_Client_SetBaseRace, file, "$$");
newXSproto(strcpy(buf, "SetBaseGender"), XS_Client_SetBaseGender, file, "$$");
newXSproto(strcpy(buf, "GetBaseFace"), XS_Client_GetBaseFace, file, "$");
newXSproto(strcpy(buf, "GetLanguageSkill"), XS_Client_GetLanguageSkill, file, "$$");
newXSproto(strcpy(buf, "GetLastName"), XS_Client_GetLastName, file, "$");
newXSproto(strcpy(buf, "GetLDoNPointsTheme"), XS_Client_GetLDoNPointsTheme, file, "$");
newXSproto(strcpy(buf, "GetBaseSTR"), XS_Client_GetBaseSTR, file, "$");
newXSproto(strcpy(buf, "GetBaseSTA"), XS_Client_GetBaseSTA, file, "$");
newXSproto(strcpy(buf, "Escape"), XS_Client_Escape, file, "$");
newXSproto(strcpy(buf, "ExpeditionMessage"), XS_Client_ExpeditionMessage, file, "$$$");
newXSproto(strcpy(buf, "FailTask"), XS_Client_FailTask, file, "$$");
newXSproto(strcpy(buf, "ForageItem"), XS_Client_ForageItem, file, "$");
newXSproto(strcpy(buf, "Freeze"), XS_Client_Freeze, file, "$");
newXSproto(strcpy(buf, "GetAAExp"), XS_Client_GetAAExp, file, "$");
newXSproto(strcpy(buf, "GetAALevel"), XS_Client_GetAALevel, file, "$$");
newXSproto(strcpy(buf, "GetAAPercent"), XS_Client_GetAAPercent, file, "$");
newXSproto(strcpy(buf, "GetAAPoints"), XS_Client_GetAAPoints, file, "$$");
newXSproto(strcpy(buf, "GetAccountAge"), XS_Client_GetAccountAge, file, "$");
newXSproto(strcpy(buf, "GetAccountFlag"), XS_Client_GetAccountFlag, file, "$$");
newXSproto(strcpy(buf, "GetAggroCount"), XS_Client_GetAggroCount, file, "$");
newXSproto(strcpy(buf, "GetAllMoney"), XS_Client_GetAllMoney, file, "$");
newXSproto(strcpy(buf, "GetAnon"), XS_Client_GetAnon, file, "$");
newXSproto(strcpy(buf, "GetAugmentAt"), XS_Client_GetAugmentAt, file, "$$$");
newXSproto(strcpy(buf, "GetAugmentIDAt"), XS_Client_GetAugmentIDAt, file, "$$$");
newXSproto(strcpy(buf, "GetBaseAGI"), XS_Client_GetBaseAGI, file, "$");
newXSproto(strcpy(buf, "GetBaseCHA"), XS_Client_GetBaseCHA, file, "$");
newXSproto(strcpy(buf, "GetBaseDEX"), XS_Client_GetBaseDEX, file, "$");
newXSproto(strcpy(buf, "GetBaseFace"), XS_Client_GetBaseFace, file, "$");
newXSproto(strcpy(buf, "GetBaseINT"), XS_Client_GetBaseINT, file, "$");
newXSproto(strcpy(buf, "GetBaseAGI"), XS_Client_GetBaseAGI, file, "$");
newXSproto(strcpy(buf, "GetBaseSTA"), XS_Client_GetBaseSTA, file, "$");
newXSproto(strcpy(buf, "GetBaseSTR"), XS_Client_GetBaseSTR, file, "$");
newXSproto(strcpy(buf, "GetBaseWIS"), XS_Client_GetBaseWIS, file, "$");
newXSproto(strcpy(buf, "GetWeight"), XS_Client_GetWeight, file, "$");
newXSproto(strcpy(buf, "GetEXP"), XS_Client_GetEXP, file, "$");
newXSproto(strcpy(buf, "GetAAExp"), XS_Client_GetAAExp, file, "$");
newXSproto(strcpy(buf, "GetAAPercent"), XS_Client_GetAAPercent, file, "$");
newXSproto(strcpy(buf, "GetTotalSecondsPlayed"), XS_Client_GetTotalSecondsPlayed, file, "$");
newXSproto(strcpy(buf, "UpdateLDoNPoints"), XS_Client_UpdateLDoNPoints, file, "$$$");
newXSproto(strcpy(buf, "SetDeity"), XS_Client_SetDeity, file, "$$");
newXSproto(strcpy(buf, "AddEXP"), XS_Client_AddEXP, file, "$$;$$");
newXSproto(strcpy(buf, "SetEXP"), XS_Client_SetEXP, file, "$$$;$");
newXSproto(strcpy(buf, "SetBindPoint"), XS_Client_SetBindPoint, file, "$;$$$$$");
newXSproto(strcpy(buf, "GetBecomeNPCLevel"), XS_Client_GetBecomeNPCLevel, file, "$");
newXSproto(strcpy(buf, "GetBindHeading"), XS_Client_GetBindHeading, file, "$$");
newXSproto(strcpy(buf, "GetBindX"), XS_Client_GetBindX, file, "$$");
newXSproto(strcpy(buf, "GetBindY"), XS_Client_GetBindY, file, "$$");
newXSproto(strcpy(buf, "GetBindZ"), XS_Client_GetBindZ, file, "$$");
newXSproto(strcpy(buf, "GetBindHeading"), XS_Client_GetBindHeading, file, "$$");
newXSproto(strcpy(buf, "GetBindZoneID"), XS_Client_GetBindZoneID, file, "$$");
newXSproto(strcpy(buf, "MovePC"), XS_Client_MovePC, file, "$$$$$$");
newXSproto(strcpy(buf, "MovePCInstance"), XS_Client_MovePCInstance, file, "$$$$$$$");
newXSproto(strcpy(buf, "ChangeLastName"), XS_Client_ChangeLastName, file, "$$");
newXSproto(strcpy(buf, "GetFactionLevel"), XS_Client_GetFactionLevel, file, "$$$$$$$$");
newXSproto(strcpy(buf, "SetFactionLevel"), XS_Client_SetFactionLevel, file, "$$$$$$");
newXSproto(strcpy(buf, "SetFactionLevel2"), XS_Client_SetFactionLevel2, file, "$$$$$$$");
newXSproto(strcpy(buf, "GetRawItemAC"), XS_Client_GetRawItemAC, file, "$");
newXSproto(strcpy(buf, "AccountID"), XS_Client_AccountID, file, "$");
newXSproto(strcpy(buf, "AccountName"), XS_Client_AccountName, file, "$");
newXSproto(strcpy(buf, "Admin"), XS_Client_Admin, file, "$");
newXSproto(strcpy(buf, "CharacterID"), XS_Client_CharacterID, file, "$");
newXSproto(strcpy(buf, "UpdateAdmin"), XS_Client_UpdateAdmin, file, "$;$");
newXSproto(strcpy(buf, "UpdateWho"), XS_Client_UpdateWho, file, "$;$");
newXSproto(strcpy(buf, "GuildRank"), XS_Client_GuildRank, file, "$");
newXSproto(strcpy(buf, "GuildID"), XS_Client_GuildID, file, "$");
newXSproto(strcpy(buf, "GetFace"), XS_Client_GetFace, file, "$");
newXSproto(strcpy(buf, "TakeMoneyFromPP"), XS_Client_TakeMoneyFromPP, file, "$$;$");
newXSproto(strcpy(buf, "AddMoneyToPP"), XS_Client_AddMoneyToPP, file, "$$$$$$");
newXSproto(strcpy(buf, "TGB"), XS_Client_TGB, file, "$");
newXSproto(strcpy(buf, "GetSkillPoints"), XS_Client_GetSkillPoints, file, "$");
newXSproto(strcpy(buf, "SetSkillPoints"), XS_Client_SetSkillPoints, file, "$$");
newXSproto(strcpy(buf, "IncreaseSkill"), XS_Client_IncreaseSkill, file, "$$;$");
newXSproto(strcpy(buf, "IncreaseLanguageSkill"), XS_Client_IncreaseLanguageSkill, file, "$$;$");
newXSproto(strcpy(buf, "GetSkill"), XS_Client_GetSkill, file, "$$");
newXSproto(strcpy(buf, "GetRawSkill"), XS_Client_GetRawSkill, file, "$$");
newXSproto(strcpy(buf, "HasSkill"), XS_Client_HasSkill, file, "$$");
newXSproto(strcpy(buf, "CanHaveSkill"), XS_Client_CanHaveSkill, file, "$$");
newXSproto(strcpy(buf, "SetSkill"), XS_Client_SetSkill, file, "$$$");
newXSproto(strcpy(buf, "AddSkill"), XS_Client_AddSkill, file, "$$$");
newXSproto(strcpy(buf, "CheckSpecializeIncrease"), XS_Client_CheckSpecializeIncrease, file, "$$");
newXSproto(strcpy(buf, "CheckIncreaseSkill"), XS_Client_CheckIncreaseSkill, file, "$$;$");
newXSproto(strcpy(buf, "SetLanguageSkill"), XS_Client_SetLanguageSkill, file, "$$$");
newXSproto(strcpy(buf, "MaxSkill"), XS_Client_MaxSkill, file, "$$;$$");
newXSproto(strcpy(buf, "GMKill"), XS_Client_GMKill, file, "$");
newXSproto(strcpy(buf, "IsMedding"), XS_Client_IsMedding, file, "$");
newXSproto(strcpy(buf, "GetDuelTarget"), XS_Client_GetDuelTarget, file, "$");
newXSproto(strcpy(buf, "IsDueling"), XS_Client_IsDueling, file, "$");
newXSproto(strcpy(buf, "SetDuelTarget"), XS_Client_SetDuelTarget, file, "$$");
newXSproto(strcpy(buf, "SetDueling"), XS_Client_SetDueling, file, "$$");
newXSproto(strcpy(buf, "ResetAA"), XS_Client_ResetAA, file, "$");
newXSproto(strcpy(buf, "MemSpell"), XS_Client_MemSpell, file, "$$$;$");
newXSproto(strcpy(buf, "UnmemSpell"), XS_Client_UnmemSpell, file, "$$;$");
newXSproto(strcpy(buf, "UnmemSpellBySpellID"), XS_Client_UnmemSpellBySpellID, file, "$$");
newXSproto(strcpy(buf, "UnmemSpellAll"), XS_Client_UnmemSpellAll, file, "$;$");
newXSproto(strcpy(buf, "ScribeSpell"), XS_Client_ScribeSpell, file, "$$$;$");
newXSproto(strcpy(buf, "UnscribeSpell"), XS_Client_UnscribeSpell, file, "$$;$");
newXSproto(strcpy(buf, "UnscribeSpellAll"), XS_Client_UnscribeSpellAll, file, "$;$");
newXSproto(strcpy(buf, "TrainDiscBySpellID"), XS_Client_TrainDiscBySpellID, file, "$$");
newXSproto(strcpy(buf, "GetDiscSlotBySpellID"), XS_Client_GetDiscSlotBySpellID, file, "$$");
newXSproto(strcpy(buf, "UntrainDisc"), XS_Client_UntrainDisc, file, "$$;$");
newXSproto(strcpy(buf, "UntrainDiscAll"), XS_Client_UntrainDiscAll, file, "$;$");
newXSproto(strcpy(buf, "IsSitting"), XS_Client_IsSitting, file, "$");
newXSproto(strcpy(buf, "IsBecomeNPC"), XS_Client_IsBecomeNPC, file, "$");
newXSproto(strcpy(buf, "GetBecomeNPCLevel"), XS_Client_GetBecomeNPCLevel, file, "$");
newXSproto(strcpy(buf, "SetBecomeNPC"), XS_Client_SetBecomeNPC, file, "$$");
newXSproto(strcpy(buf, "SetBecomeNPCLevel"), XS_Client_SetBecomeNPCLevel, file, "$$");
newXSproto(strcpy(buf, "SetFeigned"), XS_Client_SetFeigned, file, "$$");
newXSproto(strcpy(buf, "GetFeigned"), XS_Client_GetFeigned, file, "$");
newXSproto(strcpy(buf, "AutoSplitEnabled"), XS_Client_AutoSplitEnabled, file, "$");
newXSproto(strcpy(buf, "SetHorseId"), XS_Client_SetHorseId, file, "$$");
newXSproto(strcpy(buf, "GetHorseId"), XS_Client_GetHorseId, file, "$");
newXSproto(strcpy(buf, "NukeItem"), XS_Client_NukeItem, file, "$$;$");
newXSproto(strcpy(buf, "SetTint"), XS_Client_SetTint, file, "$$$");
newXSproto(strcpy(buf, "SetMaterial"), XS_Client_SetMaterial, file, "$$$");
newXSproto(strcpy(buf, "Undye"), XS_Client_Undye, file, "$");
newXSproto(strcpy(buf, "GetItemIDAt"), XS_Client_GetItemIDAt, file, "$$");
newXSproto(strcpy(buf, "GetAugmentIDAt"), XS_Client_GetAugmentIDAt, file, "$$$");
newXSproto(strcpy(buf, "DeleteItemInInventory"), XS_Client_DeleteItemInInventory, file, "$$;$$");
newXSproto(strcpy(buf, "SummonItem"), XS_Client_SummonItem, file, "$$;$$$$$$$$");
newXSproto(strcpy(buf, "SetStats"), XS_Client_SetStats, file, "$$$");
newXSproto(strcpy(buf, "IncStats"), XS_Client_IncStats, file, "$$$");
newXSproto(strcpy(buf, "DropItem"), XS_Client_DropItem, file, "$$");
newXSproto(strcpy(buf, "BreakInvis"), XS_Client_BreakInvis, file, "$");
newXSproto(strcpy(buf, "GetGroup"), XS_Client_GetGroup, file, "$");
newXSproto(strcpy(buf, "LeaveGroup"), XS_Client_LeaveGroup, file, "$");
newXSproto(strcpy(buf, "GetRaid"), XS_Client_GetRaid, file, "$");
newXSproto(strcpy(buf, "IsGrouped"), XS_Client_IsGrouped, file, "$");
newXSproto(strcpy(buf, "IsRaidGrouped"), XS_Client_IsRaidGrouped, file, "$");
newXSproto(strcpy(buf, "Hungry"), XS_Client_Hungry, file, "$");
newXSproto(strcpy(buf, "Thirsty"), XS_Client_Thirsty, file, "$");
newXSproto(strcpy(buf, "GetInstrumentMod"), XS_Client_GetInstrumentMod, file, "$$");
newXSproto(strcpy(buf, "DecreaseByID"), XS_Client_DecreaseByID, file, "$$$");
newXSproto(strcpy(buf, "SlotConvert2"), XS_Client_SlotConvert2, file, "$$");
newXSproto(strcpy(buf, "Escape"), XS_Client_Escape, file, "$");
newXSproto(strcpy(buf, "RemoveNoRent"), XS_Client_RemoveNoRent, file, "$");
newXSproto(strcpy(buf, "GoFish"), XS_Client_GoFish, file, "$");
newXSproto(strcpy(buf, "ForageItem"), XS_Client_ForageItem, file, "$");
newXSproto(strcpy(buf, "CalcPriceMod"), XS_Client_CalcPriceMod, file, "$;$$");
newXSproto(strcpy(buf, "ResetTrade"), XS_Client_ResetTrade, file, "$");
newXSproto(strcpy(buf, "UseDiscipline"), XS_Client_UseDiscipline, file, "$$$");
newXSproto(strcpy(buf, "GetCarriedMoney"), XS_Client_GetCarriedMoney, file, "$");
newXSproto(strcpy(buf, "GetCharacterFactionLevel"), XS_Client_GetCharacterFactionLevel, file, "$$");
newXSproto(strcpy(buf, "SetZoneFlag"), XS_Client_SetZoneFlag, file, "$$");
newXSproto(strcpy(buf, "ClearZoneFlag"), XS_Client_ClearZoneFlag, file, "$$");
newXSproto(strcpy(buf, "HasZoneFlag"), XS_Client_HasZoneFlag, file, "$$");
newXSproto(strcpy(buf, "SendZoneFlagInfo"), XS_Client_SendZoneFlagInfo, file, "$$");
newXSproto(strcpy(buf, "LoadZoneFlags"), XS_Client_LoadZoneFlags, file, "$");
newXSproto(strcpy(buf, "SetAATitle"), XS_Client_SetAATitle, file, "$$;$");
newXSproto(strcpy(buf, "GetClientVersion"), XS_Client_GetClientVersion, file, "$");
newXSproto(strcpy(buf, "GetClientVersionBit"), XS_Client_GetClientVersionBit, file, "$");
newXSproto(strcpy(buf, "SetTitleSuffix"), XS_Client_SetTitleSuffix, file, "$$;$");
newXSproto(strcpy(buf, "SetAAPoints"), XS_Client_SetAAPoints, file, "$$");
newXSproto(strcpy(buf, "GetAAPoints"), XS_Client_GetAAPoints, file, "$$");
newXSproto(strcpy(buf, "GetSpentAA"), XS_Client_GetSpentAA, file, "$$");
newXSproto(strcpy(buf, "AddAAPoints"), XS_Client_AddAAPoints, file, "$$");
newXSproto(strcpy(buf, "RefundAA"), XS_Client_RefundAA, file, "$$");
newXSproto(strcpy(buf, "GetModCharacterFactionLevel"), XS_Client_GetModCharacterFactionLevel, file, "$$");
newXSproto(strcpy(buf, "GetLDoNWins"), XS_Client_GetLDoNWins, file, "$");
newXSproto(strcpy(buf, "GetLDoNLosses"), XS_Client_GetLDoNLosses, file, "$");
newXSproto(strcpy(buf, "GetLDoNWinsTheme"), XS_Client_GetLDoNWinsTheme, file, "$$");
newXSproto(strcpy(buf, "GetLDoNLossesTheme"), XS_Client_GetLDoNLossesTheme, file, "$$");
newXSproto(strcpy(buf, "GetItemAt"), XS_Client_GetItemAt, file, "$$");
newXSproto(strcpy(buf, "GetAugmentAt"), XS_Client_GetAugmentAt, file, "$$$");
newXSproto(strcpy(buf, "GetStartZone"), XS_Client_GetStartZone, file, "$");
newXSproto(strcpy(buf, "SetStartZone"), XS_Client_SetStartZone, file, "$$");
newXSproto(strcpy(buf, "KeyRingAdd"), XS_Client_KeyRingAdd, file, "$$");
newXSproto(strcpy(buf, "KeyRingCheck"), XS_Client_KeyRingCheck, file, "$$");
newXSproto(strcpy(buf, "AddPVPPoints"), XS_Client_AddPVPPoints, file, "$$");
newXSproto(strcpy(buf, "AddCrystals"), XS_Client_AddCrystals, file, "$$");
newXSproto(strcpy(buf, "GetPVPPoints"), XS_Client_GetPVPPoints, file, "$");
newXSproto(strcpy(buf, "GetRadiantCrystals"), XS_Client_GetRadiantCrystals, file, "$");
newXSproto(strcpy(buf, "GetEbonCrystals"), XS_Client_GetEbonCrystals, file, "$");
newXSproto(strcpy(buf, "ReadBook"), XS_Client_ReadBook, file, "$$$");
newXSproto(strcpy(buf, "UpdateGroupAAs"), XS_Client_UpdateGroupAAs, file, "$$$");
newXSproto(strcpy(buf, "GetGroupPoints"), XS_Client_GetGroupPoints, file, "$");
newXSproto(strcpy(buf, "GetRaidPoints"), XS_Client_GetRaidPoints, file, "$");
newXSproto(strcpy(buf, "LearnRecipe"), XS_Client_LearnRecipe, file, "$$");
newXSproto(strcpy(buf, "GetEndurance"), XS_Client_GetEndurance, file, "$");
newXSproto(strcpy(buf, "GetMaxEndurance"), XS_Client_GetMaxEndurance, file, "$");
newXSproto(strcpy(buf, "GetEnduranceRatio"), XS_Client_GetEnduranceRatio, file, "$");
newXSproto(strcpy(buf, "SetEndurance"), XS_Client_SetEndurance, file, "$$");
newXSproto(strcpy(buf, "SendOPTranslocateConfirm"), XS_Client_SendOPTranslocateConfirm, file, "$$$");
newXSproto(strcpy(buf, "NPCSpawn"), XS_Client_NPCSpawn, file, "$$$;$");
newXSproto(strcpy(buf, "GetIP"), XS_Client_GetIP, file, "$");
newXSproto(strcpy(buf, "AddLevelBasedExp"), XS_Client_AddLevelBasedExp, file, "$$;$");
newXSproto(strcpy(buf, "IncrementAA"), XS_Client_IncrementAA, file, "$$");
newXSproto(strcpy(buf, "GrantAlternateAdvancementAbility"), XS_Client_GrantAlternateAdvancementAbility, file,
"$$$;$");
newXSproto(strcpy(buf, "GetAALevel"), XS_Client_GetAALevel, file, "$$");
newXSproto(strcpy(buf, "MarkCompassLoc"), XS_Client_MarkCompassLoc, file, "$$$$");
newXSproto(strcpy(buf, "ClearCompassMark"), XS_Client_ClearCompassMark, file, "$");
newXSproto(strcpy(buf, "GetFreeSpellBookSlot"), XS_Client_GetFreeSpellBookSlot, file, "$;$");
newXSproto(strcpy(buf, "GetSpellBookSlotBySpellID"), XS_Client_GetSpellBookSlotBySpellID, file, "$$");
newXSproto(strcpy(buf, "UpdateTaskActivity"), XS_Client_UpdateTaskActivity, file, "$$$$;$");
newXSproto(strcpy(buf, "AssignTask"), XS_Client_AssignTask, file, "$$$;$");
newXSproto(strcpy(buf, "FailTask"), XS_Client_FailTask, file, "$$");
newXSproto(strcpy(buf, "IsTaskCompleted"), XS_Client_IsTaskCompleted, file, "$$");
newXSproto(strcpy(buf, "IsTaskActive"), XS_Client_IsTaskActive, file, "$$");
newXSproto(strcpy(buf, "IsTaskActivityActive"), XS_Client_IsTaskActivityActive, file, "$$$");
newXSproto(strcpy(buf, "GetTaskActivityDoneCount"), XS_Client_GetTaskActivityDoneCount, file, "$$$");
newXSproto(strcpy(buf, "GetCorpseCount"), XS_Client_GetCorpseCount, file, "$");
newXSproto(strcpy(buf, "GetCorpseID"), XS_Client_GetCorpseID, file, "$$");
newXSproto(strcpy(buf, "GetCorpseItemAt"), XS_Client_GetCorpseItemAt, file, "$$$");
newXSproto(strcpy(buf, "AssignToInstance"), XS_Client_AssignToInstance, file, "$$");
newXSproto(strcpy(buf, "Freeze"), XS_Client_Freeze, file, "$");
newXSproto(strcpy(buf, "UnFreeze"), XS_Client_UnFreeze, file, "$");
newXSproto(strcpy(buf, "GetAggroCount"), XS_Client_GetAggroCount, file, "$");
newXSproto(strcpy(buf, "GetCarriedMoney"), XS_Client_GetCarriedMoney, file, "$");
newXSproto(strcpy(buf, "GetAllMoney"), XS_Client_GetAllMoney, file, "$");
newXSproto(strcpy(buf, "GetItemInInventory"), XS_Client_GetItemInInventory, file, "$$");
newXSproto(strcpy(buf, "SetCustomItemData"), XS_Client_SetCustomItemData, file, "$$$$");
newXSproto(strcpy(buf, "GetCustomItemData"), XS_Client_GetCustomItemData, file, "$$$");
newXSproto(strcpy(buf, "OpenLFGuildWindow"), XS_Client_OpenLFGuildWindow, file, "$");
newXSproto(strcpy(buf, "SignalClient"), XS_Client_SignalClient, file, "$");
newXSproto(strcpy(buf, "AddAlternateCurrencyValue"), XS_Client_AddAlternateCurrencyValue, file, "$$$");
newXSproto(strcpy(buf, "SendWebLink"), XS_Client_SendWebLink, file, "$:$");
newXSproto(strcpy(buf, "GetInstanceID"), XS_Client_GetInstanceID, file, "$$");
newXSproto(strcpy(buf, "HasSpellScribed"), XS_Client_HasSkill, file, "$$");
newXSproto(strcpy(buf, "SetAccountFlag"), XS_Client_SetAccountFlag, file, "$$");
newXSproto(strcpy(buf, "GetAccountFlag"), XS_Client_GetAccountFlag, file, "$$");
newXSproto(strcpy(buf, "GetDiscSlotBySpellID"), XS_Client_GetDiscSlotBySpellID, file, "$$");
newXSproto(strcpy(buf, "GetDuelTarget"), XS_Client_GetDuelTarget, file, "$");
newXSproto(strcpy(buf, "GetEbonCrystals"), XS_Client_GetEbonCrystals, file, "$");
newXSproto(strcpy(buf, "GetEndurance"), XS_Client_GetEndurance, file, "$");
newXSproto(strcpy(buf, "GetEnduranceRatio"), XS_Client_GetEnduranceRatio, file, "$");
newXSproto(strcpy(buf, "GetEXP"), XS_Client_GetEXP, file, "$");
newXSproto(strcpy(buf, "GetFace"), XS_Client_GetFace, file, "$");
newXSproto(strcpy(buf, "GetFactionLevel"), XS_Client_GetFactionLevel, file, "$$$$$$$$");
newXSproto(strcpy(buf, "GetFeigned"), XS_Client_GetFeigned, file, "$");
newXSproto(strcpy(buf, "GetFreeSpellBookSlot"), XS_Client_GetFreeSpellBookSlot, file, "$;$");
newXSproto(strcpy(buf, "GetGM"), XS_Client_GetGM, file, "$");
newXSproto(strcpy(buf, "GetGroup"), XS_Client_GetGroup, file, "$");
newXSproto(strcpy(buf, "GetGroupPoints"), XS_Client_GetGroupPoints, file, "$");
newXSproto(strcpy(buf, "GetHorseId"), XS_Client_GetHorseId, file, "$");
newXSproto(strcpy(buf, "GetHunger"), XS_Client_GetHunger, file, "$$");
newXSproto(strcpy(buf, "GetThirst"), XS_Client_GetThirst, file, "$$");
newXSproto(strcpy(buf, "SetHunger"), XS_Client_SetHunger, file, "$$");
newXSproto(strcpy(buf, "SetThirst"), XS_Client_SetThirst, file, "$$");
newXSproto(strcpy(buf, "SetConsumption"), XS_Client_SetConsumption, file, "$$$");
newXSproto(strcpy(buf, "SilentMessage"), XS_Client_SilentMessage, file, "$$");
newXSproto(strcpy(buf, "PlayMP3"), XS_Client_PlayMP3, file, "$;$");
newXSproto(strcpy(buf, "SendTargetCommand"), XS_Client_SendTargetCommand, file, "$$");
newXSproto(strcpy(buf, "ExpeditionMessage"), XS_Client_ExpeditionMessage, file, "$$$");
newXSproto(strcpy(buf, "SendMarqueeMessage"), XS_Client_SendMarqueeMessage, file, "$$$$$$$");
newXSproto(strcpy(buf, "SendColoredText"), XS_Client_SendColoredText, file, "$$$");
newXSproto(strcpy(buf, "SendSpellAnim"), XS_Client_SendSpellAnim, file, "$$$");
newXSproto(strcpy(buf, "GetInstanceID"), XS_Client_GetInstanceID, file, "$$");
newXSproto(strcpy(buf, "GetInstrumentMod"), XS_Client_GetInstrumentMod, file, "$$");
newXSproto(strcpy(buf, "GetIP"), XS_Client_GetIP, file, "$");
newXSproto(strcpy(buf, "GetItemAt"), XS_Client_GetItemAt, file, "$$");
newXSproto(strcpy(buf, "GetItemIDAt"), XS_Client_GetItemIDAt, file, "$$");
newXSproto(strcpy(buf, "GetItemInInventory"), XS_Client_GetItemInInventory, file, "$$");
newXSproto(strcpy(buf, "GetLanguageSkill"), XS_Client_GetLanguageSkill, file, "$$");
newXSproto(strcpy(buf, "GetLastName"), XS_Client_GetLastName, file, "$");
newXSproto(strcpy(buf, "GetLDoNLosses"), XS_Client_GetLDoNLosses, file, "$");
newXSproto(strcpy(buf, "GetLDoNLossesTheme"), XS_Client_GetLDoNLossesTheme, file, "$$");
newXSproto(strcpy(buf, "GetLDoNPointsTheme"), XS_Client_GetLDoNPointsTheme, file, "$");
newXSproto(strcpy(buf, "GetLDoNWins"), XS_Client_GetLDoNWins, file, "$");
newXSproto(strcpy(buf, "GetLDoNWinsTheme"), XS_Client_GetLDoNWinsTheme, file, "$$");
newXSproto(strcpy(buf, "GetMaxEndurance"), XS_Client_GetMaxEndurance, file, "$");
newXSproto(strcpy(buf, "GetModCharacterFactionLevel"), XS_Client_GetModCharacterFactionLevel, file, "$$");
newXSproto(strcpy(buf, "GetMoney"), XS_Client_GetMoney, file, "$$$");
newXSproto(strcpy(buf, "GetPVP"), XS_Client_GetPVP, file, "$");
newXSproto(strcpy(buf, "GetPVPPoints"), XS_Client_GetPVPPoints, file, "$");
newXSproto(strcpy(buf, "GetRadiantCrystals"), XS_Client_GetRadiantCrystals, file, "$");
newXSproto(strcpy(buf, "GetRaid"), XS_Client_GetRaid, file, "$");
newXSproto(strcpy(buf, "GetRaidPoints"), XS_Client_GetRaidPoints, file, "$");
newXSproto(strcpy(buf, "GetRawItemAC"), XS_Client_GetRawItemAC, file, "$");
newXSproto(strcpy(buf, "GetRawSkill"), XS_Client_GetRawSkill, file, "$$");
newXSproto(strcpy(buf, "GetSkill"), XS_Client_GetSkill, file, "$$");
newXSproto(strcpy(buf, "GetSkillPoints"), XS_Client_GetSkillPoints, file, "$");
newXSproto(strcpy(buf, "GetSpellBookSlotBySpellID"), XS_Client_GetSpellBookSlotBySpellID, file, "$$");
newXSproto(strcpy(buf, "GetSpentAA"), XS_Client_GetSpentAA, file, "$$");
newXSproto(strcpy(buf, "GetStartZone"), XS_Client_GetStartZone, file, "$");
newXSproto(strcpy(buf, "GetTargetRingX"), XS_Client_GetTargetRingX, file, "$$");
newXSproto(strcpy(buf, "GetTargetRingY"), XS_Client_GetTargetRingY, file, "$$");
newXSproto(strcpy(buf, "GetTargetRingZ"), XS_Client_GetTargetRingZ, file, "$$");
newXSproto(strcpy(buf, "QuestReward"), XS_Client_QuestReward, file, "$$;$$$$$$$");
newXSproto(strcpy(buf, "CalcEXP"), XS_Client_CalcEXP, file, "$");
newXSproto(strcpy(buf, "GetMoney"), XS_Client_GetMoney, file, "$$$");
newXSproto(strcpy(buf, "GetAccountAge"), XS_Client_GetAccountAge, file, "$");
newXSproto(strcpy(buf, "GetTaskActivityDoneCount"), XS_Client_GetTaskActivityDoneCount, file, "$$$");
newXSproto(strcpy(buf, "GetThirst"), XS_Client_GetThirst, file, "$$");
newXSproto(strcpy(buf, "GetTotalSecondsPlayed"), XS_Client_GetTotalSecondsPlayed, file, "$");
newXSproto(strcpy(buf, "GetWeight"), XS_Client_GetWeight, file, "$");
newXSproto(strcpy(buf, "GMKill"), XS_Client_GMKill, file, "$");
newXSproto(strcpy(buf, "GoFish"), XS_Client_GoFish, file, "$");
newXSproto(strcpy(buf, "GrantAlternateAdvancementAbility"), XS_Client_GrantAlternateAdvancementAbility, file, "$$$;$");
newXSproto(strcpy(buf, "GuildID"), XS_Client_GuildID, file, "$");
newXSproto(strcpy(buf, "GuildRank"), XS_Client_GuildRank, file, "$");
newXSproto(strcpy(buf, "HasSkill"), XS_Client_HasSkill, file, "$$");
newXSproto(strcpy(buf, "HasSpellScribed"), XS_Client_HasSkill, file, "$$");
newXSproto(strcpy(buf, "HasZoneFlag"), XS_Client_HasZoneFlag, file, "$$");
newXSproto(strcpy(buf, "Hungry"), XS_Client_Hungry, file, "$");
newXSproto(strcpy(buf, "IncreaseLanguageSkill"), XS_Client_IncreaseLanguageSkill, file, "$$;$");
newXSproto(strcpy(buf, "IncreaseSkill"), XS_Client_IncreaseSkill, file, "$$;$");
newXSproto(strcpy(buf, "IncrementAA"), XS_Client_IncrementAA, file, "$$");
newXSproto(strcpy(buf, "IncStats"), XS_Client_IncStats, file, "$$$");
newXSproto(strcpy(buf, "InZone"), XS_Client_InZone, file, "$");
newXSproto(strcpy(buf, "IsBecomeNPC"), XS_Client_IsBecomeNPC, file, "$");
newXSproto(strcpy(buf, "IsDueling"), XS_Client_IsDueling, file, "$");
newXSproto(strcpy(buf, "IsGrouped"), XS_Client_IsGrouped, file, "$");
newXSproto(strcpy(buf, "IsLD"), XS_Client_IsLD, file, "$");
newXSproto(strcpy(buf, "IsMedding"), XS_Client_IsMedding, file, "$");
newXSproto(strcpy(buf, "IsRaidGrouped"), XS_Client_IsRaidGrouped, file, "$");
newXSproto(strcpy(buf, "IsSitting"), XS_Client_IsSitting, file, "$");
newXSproto(strcpy(buf, "IsTaskActive"), XS_Client_IsTaskActive, file, "$$");
newXSproto(strcpy(buf, "IsTaskActivityActive"), XS_Client_IsTaskActivityActive, file, "$$$");
newXSproto(strcpy(buf, "IsTaskCompleted"), XS_Client_IsTaskCompleted, file, "$$");
newXSproto(strcpy(buf, "KeyRingAdd"), XS_Client_KeyRingAdd, file, "$$");
newXSproto(strcpy(buf, "KeyRingCheck"), XS_Client_KeyRingCheck, file, "$$");
newXSproto(strcpy(buf, "Kick"), XS_Client_Kick, file, "$");
newXSproto(strcpy(buf, "LearnRecipe"), XS_Client_LearnRecipe, file, "$$");
newXSproto(strcpy(buf, "LeaveGroup"), XS_Client_LeaveGroup, file, "$");
newXSproto(strcpy(buf, "LoadZoneFlags"), XS_Client_LoadZoneFlags, file, "$");
newXSproto(strcpy(buf, "MarkCompassLoc"), XS_Client_MarkCompassLoc, file, "$$$$");
newXSproto(strcpy(buf, "MaxSkill"), XS_Client_MaxSkill, file, "$$;$$");
newXSproto(strcpy(buf, "MemSpell"), XS_Client_MemSpell, file, "$$$;$");
newXSproto(strcpy(buf, "MovePC"), XS_Client_MovePC, file, "$$$$$$");
newXSproto(strcpy(buf, "MovePCInstance"), XS_Client_MovePCInstance, file, "$$$$$$$");
newXSproto(strcpy(buf, "NPCSpawn"), XS_Client_NPCSpawn, file, "$$$;$");
newXSproto(strcpy(buf, "NukeItem"), XS_Client_NukeItem, file, "$$;$");
newXSproto(strcpy(buf, "OpenLFGuildWindow"), XS_Client_OpenLFGuildWindow, file, "$");
newXSproto(strcpy(buf, "PlayMP3"), XS_Client_PlayMP3, file, "$;$");
newXSproto(strcpy(buf, "Popup2"), XS_Client_Popup2, file, "$$$;$$$$$$$");
newXSproto(strcpy(buf, "QuestReward"), XS_Client_QuestReward, file, "$$;$$$$$$$");
newXSproto(strcpy(buf, "ReadBook"), XS_Client_ReadBook, file, "$$$");
newXSproto(strcpy(buf, "RefundAA"), XS_Client_RefundAA, file, "$$");
newXSproto(strcpy(buf, "RemoveNoRent"), XS_Client_RemoveNoRent, file, "$");
newXSproto(strcpy(buf, "ResetAA"), XS_Client_ResetAA, file, "$");
newXSproto(strcpy(buf, "ResetTrade"), XS_Client_ResetTrade, file, "$");
newXSproto(strcpy(buf, "Save"), XS_Client_Save, file, "$$");
newXSproto(strcpy(buf, "SaveBackup"), XS_Client_SaveBackup, file, "$");
newXSproto(strcpy(buf, "ScribeSpell"), XS_Client_ScribeSpell, file, "$$$;$");
newXSproto(strcpy(buf, "SendColoredText"), XS_Client_SendColoredText, file, "$$$");
newXSproto(strcpy(buf, "SendMarqueeMessage"), XS_Client_SendMarqueeMessage, file, "$$$$$$$");
newXSproto(strcpy(buf, "SendOPTranslocateConfirm"), XS_Client_SendOPTranslocateConfirm, file, "$$$");
newXSproto(strcpy(buf, "SendSound"), XS_Client_SendSound, file, "$");
newXSproto(strcpy(buf, "SendSpellAnim"), XS_Client_SendSpellAnim, file, "$$$");
newXSproto(strcpy(buf, "SendTargetCommand"), XS_Client_SendTargetCommand, file, "$$");
newXSproto(strcpy(buf, "SendWebLink"), XS_Client_SendWebLink, file, "$:$");
newXSproto(strcpy(buf, "SendZoneFlagInfo"), XS_Client_SendZoneFlagInfo, file, "$$");
newXSproto(strcpy(buf, "SetAAPoints"), XS_Client_SetAAPoints, file, "$$");
newXSproto(strcpy(buf, "SetAATitle"), XS_Client_SetAATitle, file, "$$;$");
newXSproto(strcpy(buf, "SetAccountFlag"), XS_Client_SetAccountFlag, file, "$$");
newXSproto(strcpy(buf, "SetBaseClass"), XS_Client_SetBaseClass, file, "$$");
newXSproto(strcpy(buf, "SetBaseGender"), XS_Client_SetBaseGender, file, "$$");
newXSproto(strcpy(buf, "SetBaseRace"), XS_Client_SetBaseRace, file, "$$");
newXSproto(strcpy(buf, "SetBecomeNPC"), XS_Client_SetBecomeNPC, file, "$$");
newXSproto(strcpy(buf, "SetBecomeNPCLevel"), XS_Client_SetBecomeNPCLevel, file, "$$");
newXSproto(strcpy(buf, "SetBindPoint"), XS_Client_SetBindPoint, file, "$;$$$$$");
newXSproto(strcpy(buf, "SetConsumption"), XS_Client_SetConsumption, file, "$$$");
newXSproto(strcpy(buf, "SetCustomItemData"), XS_Client_SetCustomItemData, file, "$$$$");
newXSproto(strcpy(buf, "SetDeity"), XS_Client_SetDeity, file, "$$");
newXSproto(strcpy(buf, "SetDueling"), XS_Client_SetDueling, file, "$$");
newXSproto(strcpy(buf, "SetDuelTarget"), XS_Client_SetDuelTarget, file, "$$");
newXSproto(strcpy(buf, "SetEndurance"), XS_Client_SetEndurance, file, "$$");
newXSproto(strcpy(buf, "SetEXP"), XS_Client_SetEXP, file, "$$$;$");
newXSproto(strcpy(buf, "SetFactionLevel"), XS_Client_SetFactionLevel, file, "$$$$$$");
newXSproto(strcpy(buf, "SetFactionLevel2"), XS_Client_SetFactionLevel2, file, "$$$$$$$");
newXSproto(strcpy(buf, "SetFeigned"), XS_Client_SetFeigned, file, "$$");
newXSproto(strcpy(buf, "SetGM"), XS_Client_SetGM, file, "$$");
newXSproto(strcpy(buf, "SetHorseId"), XS_Client_SetHorseId, file, "$$");
newXSproto(strcpy(buf, "SetHunger"), XS_Client_SetHunger, file, "$$");
newXSproto(strcpy(buf, "SetLanguageSkill"), XS_Client_SetLanguageSkill, file, "$$$");
newXSproto(strcpy(buf, "SetMaterial"), XS_Client_SetMaterial, file, "$$$");
newXSproto(strcpy(buf, "SetPrimaryWeaponOrnamentation"), XS_Client_SetPrimaryWeaponOrnamentation, file, "$$");
newXSproto(strcpy(buf, "SetPVP"), XS_Client_SetPVP, file, "$$");
newXSproto(strcpy(buf, "SetSecondaryWeaponOrnamentation"), XS_Client_SetSecondaryWeaponOrnamentation, file, "$$");
newXSproto(strcpy(buf, "SetSkill"), XS_Client_SetSkill, file, "$$$");
newXSproto(strcpy(buf, "SetSkillPoints"), XS_Client_SetSkillPoints, file, "$$");
newXSproto(strcpy(buf, "SetStartZone"), XS_Client_SetStartZone, file, "$$");
newXSproto(strcpy(buf, "SetStats"), XS_Client_SetStats, file, "$$$");
newXSproto(strcpy(buf, "SetThirst"), XS_Client_SetThirst, file, "$$");
newXSproto(strcpy(buf, "SetTint"), XS_Client_SetTint, file, "$$$");
newXSproto(strcpy(buf, "SetTitleSuffix"), XS_Client_SetTitleSuffix, file, "$$;$");
newXSproto(strcpy(buf, "SetZoneFlag"), XS_Client_SetZoneFlag, file, "$$");
newXSproto(strcpy(buf, "SignalClient"), XS_Client_SignalClient, file, "$");
newXSproto(strcpy(buf, "SilentMessage"), XS_Client_SilentMessage, file, "$$");
newXSproto(strcpy(buf, "SlotConvert2"), XS_Client_SlotConvert2, file, "$$");
newXSproto(strcpy(buf, "Stand"), XS_Client_Stand, file, "$");
newXSproto(strcpy(buf, "SummonItem"), XS_Client_SummonItem, file, "$$;$$$$$$$$");
newXSproto(strcpy(buf, "TakeMoneyFromPP"), XS_Client_TakeMoneyFromPP, file, "$$;$");
newXSproto(strcpy(buf, "TGB"), XS_Client_TGB, file, "$");
newXSproto(strcpy(buf, "Thirsty"), XS_Client_Thirsty, file, "$");
newXSproto(strcpy(buf, "TrainDiscBySpellID"), XS_Client_TrainDiscBySpellID, file, "$$");
newXSproto(strcpy(buf, "Undye"), XS_Client_Undye, file, "$");
newXSproto(strcpy(buf, "UnFreeze"), XS_Client_UnFreeze, file, "$");
newXSproto(strcpy(buf, "UnmemSpell"), XS_Client_UnmemSpell, file, "$$;$");
newXSproto(strcpy(buf, "UnmemSpellAll"), XS_Client_UnmemSpellAll, file, "$;$");
newXSproto(strcpy(buf, "UnmemSpellBySpellID"), XS_Client_UnmemSpellBySpellID, file, "$$");
newXSproto(strcpy(buf, "UnscribeSpell"), XS_Client_UnscribeSpell, file, "$$;$");
newXSproto(strcpy(buf, "UnscribeSpellAll"), XS_Client_UnscribeSpellAll, file, "$;$");
newXSproto(strcpy(buf, "UntrainDisc"), XS_Client_UntrainDisc, file, "$$;$");
newXSproto(strcpy(buf, "UntrainDiscAll"), XS_Client_UntrainDiscAll, file, "$;$");
newXSproto(strcpy(buf, "UpdateAdmin"), XS_Client_UpdateAdmin, file, "$;$");
newXSproto(strcpy(buf, "UpdateGroupAAs"), XS_Client_UpdateGroupAAs, file, "$$$");
newXSproto(strcpy(buf, "UpdateLDoNPoints"), XS_Client_UpdateLDoNPoints, file, "$$$");
newXSproto(strcpy(buf, "UpdateTaskActivity"), XS_Client_UpdateTaskActivity, file, "$$$$;$");
newXSproto(strcpy(buf, "UpdateWho"), XS_Client_UpdateWho, file, "$;$");
newXSproto(strcpy(buf, "UseDiscipline"), XS_Client_UseDiscipline, file, "$$$");
newXSproto(strcpy(buf, "WorldKick"), XS_Client_WorldKick, file, "$");
XSRETURN_YES;
}
+4 -4
View File
@@ -1355,7 +1355,7 @@ XS(XS_EntityList_OpenDoorsNear) {
Perl_croak(aTHX_ "Usage: EntityList::OpenDoorsNear(THIS, NPC* opener)");
{
EntityList *THIS;
NPC *opener;
Mob *opener;
if (sv_derived_from(ST(0), "EntityList")) {
IV tmp = SvIV((SV *) SvRV(ST(0)));
@@ -1365,11 +1365,11 @@ XS(XS_EntityList_OpenDoorsNear) {
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
if (sv_derived_from(ST(1), "NPC")) {
if (sv_derived_from(ST(1), "Mob")) {
IV tmp = SvIV((SV *) SvRV(ST(1)));
opener = INT2PTR(NPC *, tmp);
opener = INT2PTR(Mob *, tmp);
} else
Perl_croak(aTHX_ "opener is not of type NPC");
Perl_croak(aTHX_ "opener is not of type Mob");
if (opener == nullptr)
Perl_croak(aTHX_ "opener is nullptr, avoiding crash.");
+95 -98
View File
@@ -639,7 +639,7 @@ XS(XS_Mob_GetEquipment) {
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetEquipment(material_slot);
RETVAL = THIS->GetEquippedItemFromTextureSlot(material_slot);
XSprePUSH;
PUSHi((IV) RETVAL);
}
@@ -1166,55 +1166,6 @@ XS(XS_Mob_GMMove) {
XSRETURN_EMPTY;
}
XS(XS_Mob_SendPosUpdate); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_SendPosUpdate) {
dXSARGS;
if (items < 1 || items > 2)
Perl_croak(aTHX_ "Usage: Mob::SendPosUpdate(THIS, [uint8 send_to_self = 0])");
{
Mob *THIS;
uint8 iSendToSelf;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV *) SvRV(ST(0)));
THIS = INT2PTR(Mob *, tmp);
} else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
if (items < 2)
iSendToSelf = 0;
else {
iSendToSelf = (uint8) SvUV(ST(1));
}
THIS->SendPositionUpdate(iSendToSelf);
}
XSRETURN_EMPTY;
}
XS(XS_Mob_SendPosition); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_SendPosition) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::SendPosition(THIS)");
{
Mob *THIS;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV *) SvRV(ST(0)));
THIS = INT2PTR(Mob *, tmp);
} else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->SendPosition();
}
XSRETURN_EMPTY;
}
XS(XS_Mob_HasProcs); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_HasProcs) {
dXSARGS;
@@ -3786,7 +3737,7 @@ XS(XS_Mob_CastSpell) {
Mob *THIS;
uint16 spell_id = (uint16) SvUV(ST(1));
uint16 target_id = (uint16) SvUV(ST(2));
EQEmu::CastingSlot slot;
EQEmu::spells::CastingSlot slot;
int32 casttime;
int32 mana_cost;
int16 resist_adjust;
@@ -3800,9 +3751,9 @@ XS(XS_Mob_CastSpell) {
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
if (items < 4)
slot = EQEmu::CastingSlot::Item;
slot = EQEmu::spells::CastingSlot::Item;
else {
slot = static_cast<EQEmu::CastingSlot>(SvUV(ST(3)));
slot = static_cast<EQEmu::spells::CastingSlot>(SvUV(ST(3)));
}
if (items < 5)
@@ -3876,7 +3827,7 @@ XS(XS_Mob_SpellFinished) {
resist_diff = spells[spell_id].ResistDiff;
}
THIS->SpellFinished(spell_id, spell_target, EQEmu::CastingSlot::Item, mana_cost, -1, resist_diff);
THIS->SpellFinished(spell_id, spell_target, EQEmu::spells::CastingSlot::Item, mana_cost, -1, resist_diff);
}
XSRETURN_EMPTY;
}
@@ -5526,20 +5477,71 @@ XS(XS_Mob_CalculateHeadingToTarget) {
XSRETURN(1);
}
XS(XS_Mob_CalculateNewPosition); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_CalculateNewPosition) {
XS(XS_Mob_RunTo); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_RunTo) {
dXSARGS;
if (items < 5 || items > 6)
if (items < 4 || items > 5)
Perl_croak(aTHX_
"Usage: Mob::CalculateNewPosition(THIS, float x, float y, float z, float speed, [bool check_z = false])");
"Usage: Mob::RunTo(THIS, float x, float y, float z)");
{
Mob *THIS;
float x = (float)SvNV(ST(1));
float y = (float)SvNV(ST(2));
float z = (float)SvNV(ST(3));
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV *)SvRV(ST(0)));
THIS = INT2PTR(Mob *, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->RunTo(x, y, z);
}
XSRETURN_EMPTY;
}
XS(XS_Mob_WalkTo); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_WalkTo) {
dXSARGS;
if (items < 4 || items > 5)
Perl_croak(aTHX_
"Usage: Mob::WalkTo(THIS, float x, float y, float z)");
{
Mob *THIS;
float x = (float)SvNV(ST(1));
float y = (float)SvNV(ST(2));
float z = (float)SvNV(ST(3));
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV *)SvRV(ST(0)));
THIS = INT2PTR(Mob *, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->WalkTo(x, y, z);
}
XSRETURN_EMPTY;
}
XS(XS_Mob_NavigateTo); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_NavigateTo) {
dXSARGS;
if (items < 4 || items > 5)
Perl_croak(aTHX_
"Usage: Mob::NavigateTo(THIS, float x, float y, float z)");
{
Mob *THIS;
bool RETVAL;
float x = (float) SvNV(ST(1));
float y = (float) SvNV(ST(2));
float z = (float) SvNV(ST(3));
float speed = (float) SvNV(ST(4));
bool checkZ;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV *) SvRV(ST(0)));
@@ -5549,17 +5551,34 @@ XS(XS_Mob_CalculateNewPosition) {
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
if (items < 6)
checkZ = false;
else {
checkZ = (bool) SvTRUE(ST(5));
}
RETVAL = THIS->CalculateNewPosition(x, y, z, speed, checkZ);
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
THIS->NavigateTo(x, y, z);
}
XSRETURN(1);
XSRETURN_EMPTY;
}
XS(XS_Mob_StopNavigation); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_StopNavigation) {
dXSARGS;
if (items < 5 || items > 6)
Perl_croak(aTHX_
"Usage: Mob::StopNavigation(THIS)");
{
Mob *THIS;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV *)SvRV(ST(0)));
THIS = INT2PTR(Mob *, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->StopNavigation();
}
XSRETURN_EMPTY;
}
XS(XS_Mob_CalculateDistance); /* prototype to pass -Wmissing-prototypes */
@@ -6652,10 +6671,10 @@ XS(XS_Mob_SetFlyMode); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_SetFlyMode) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Mob::SetFlyMode(THIS, uint8 flymode[0|1|2|3])");
Perl_croak(aTHX_ "Usage: Mob::SetFlyMode(THIS, uint8 flymode[0|1|2|3|4|5])");
{
Mob *THIS;
uint8 flymode = (uint8) SvIV(ST(1));
GravityBehavior flymode = (GravityBehavior) SvIV(ST(1));
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV *) SvRV(ST(0)));
@@ -7275,28 +7294,6 @@ XS(XS_Mob_SetLD) {
XSRETURN_EMPTY;
}
XS(XS_Mob_SetTargetDestSteps); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_SetTargetDestSteps) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Mob::SetTargetDestSteps(THIS, uint8 target_steps)");
{
Mob *THIS;
uint8 target_steps = (uint8) SvIV(ST(1));
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV *) SvRV(ST(0)));
THIS = INT2PTR(Mob *, tmp);
} else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->SetTargetDestSteps(target_steps);
}
XSRETURN_EMPTY;
}
XS(XS_Mob_SetTargetable); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_SetTargetable) {
dXSARGS;
@@ -8556,8 +8553,6 @@ XS(boot_Mob) {
newXSproto(strcpy(buf, "DoAnim"), XS_Mob_DoAnim, file, "$$;$");
newXSproto(strcpy(buf, "ChangeSize"), XS_Mob_ChangeSize, file, "$$;$");
newXSproto(strcpy(buf, "GMMove"), XS_Mob_GMMove, file, "$$$$;$");
newXSproto(strcpy(buf, "SendPosUpdate"), XS_Mob_SendPosUpdate, file, "$;$");
newXSproto(strcpy(buf, "SendPosition"), XS_Mob_SendPosition, file, "$");
newXSproto(strcpy(buf, "HasProcs"), XS_Mob_HasProcs, file, "$");
newXSproto(strcpy(buf, "IsInvisible"), XS_Mob_IsInvisible, file, "$;$");
newXSproto(strcpy(buf, "SetInvisible"), XS_Mob_SetInvisible, file, "$$");
@@ -8718,7 +8713,10 @@ XS(boot_Mob) {
newXSproto(strcpy(buf, "WipeHateList"), XS_Mob_WipeHateList, file, "$");
newXSproto(strcpy(buf, "CheckAggro"), XS_Mob_CheckAggro, file, "$$");
newXSproto(strcpy(buf, "CalculateHeadingToTarget"), XS_Mob_CalculateHeadingToTarget, file, "$$$");
newXSproto(strcpy(buf, "CalculateNewPosition"), XS_Mob_CalculateNewPosition, file, "$$$$$;$");
newXSproto(strcpy(buf, "RunTo"), XS_Mob_RunTo, file, "$$$$");
newXSproto(strcpy(buf, "WalkTo"), XS_Mob_WalkTo, file, "$$$$");
newXSproto(strcpy(buf, "NavigateTo"), XS_Mob_NavigateTo, file, "$$$$");
newXSproto(strcpy(buf, "StopNavigation"), XS_Mob_StopNavigation, file, "$");
newXSproto(strcpy(buf, "CalculateDistance"), XS_Mob_CalculateDistance, file, "$$$$");
newXSproto(strcpy(buf, "SendTo"), XS_Mob_SendTo, file, "$$$$");
newXSproto(strcpy(buf, "SendToFixZ"), XS_Mob_SendToFixZ, file, "$$$$");
@@ -8781,7 +8779,6 @@ XS(boot_Mob) {
newXSproto(strcpy(buf, "SetBodyType"), XS_Mob_SetBodyType, file, "$$;$");
newXSproto(strcpy(buf, "SetDeltas"), XS_Mob_SetDeltas, file, "$$$$$");
newXSproto(strcpy(buf, "SetLD"), XS_Mob_SetLD, file, "$$");
newXSproto(strcpy(buf, "SetTargetDestSteps"), XS_Mob_SetTargetDestSteps, file, "$$");
newXSproto(strcpy(buf, "SetTargetable"), XS_Mob_SetTargetable, file, "$$");
newXSproto(strcpy(buf, "MakeTempPet"), XS_Mob_MakeTempPet, file, "$$;$$$$");
newXSproto(strcpy(buf, "ModSkillDmgTaken"), XS_Mob_ModSkillDmgTaken, file, "$$$");
+8 -11
View File
@@ -1341,11 +1341,14 @@ XS(XS_NPC_NextGuardPosition) {
XS(XS_NPC_SaveGuardSpot); /* prototype to pass -Wmissing-prototypes */
XS(XS_NPC_SaveGuardSpot) {
dXSARGS;
if (items < 1 || items > 2)
Perl_croak(aTHX_ "Usage: NPC::SaveGuardSpot(THIS, [bool clear_guard_spot = false])");
if (items != 5)
Perl_croak(aTHX_ "Usage: NPC::SaveGuardSpot(THIS, x, y, z, heading)");
{
NPC *THIS;
bool iClearGuardSpot;
float x = (float)SvNV(ST(1));
float y = (float)SvNV(ST(2));
float z = (float)SvNV(ST(3));
float heading = (float)SvNV(ST(4));
if (sv_derived_from(ST(0), "NPC")) {
IV tmp = SvIV((SV *) SvRV(ST(0)));
@@ -1355,13 +1358,7 @@ XS(XS_NPC_SaveGuardSpot) {
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
if (items < 2)
iClearGuardSpot = false;
else {
iClearGuardSpot = (bool) SvTRUE(ST(1));
}
THIS->SaveGuardSpot(iClearGuardSpot);
THIS->SaveGuardSpot(glm::vec4(x, y, z, heading));
}
XSRETURN_EMPTY;
}
@@ -2449,7 +2446,7 @@ XS(boot_NPC) {
newXSproto(strcpy(buf, "PauseWandering"), XS_NPC_PauseWandering, file, "$$");
newXSproto(strcpy(buf, "MoveTo"), XS_NPC_MoveTo, file, "$$$$");
newXSproto(strcpy(buf, "NextGuardPosition"), XS_NPC_NextGuardPosition, file, "$");
newXSproto(strcpy(buf, "SaveGuardSpot"), XS_NPC_SaveGuardSpot, file, "$;$");
newXSproto(strcpy(buf, "SaveGuardSpot"), XS_NPC_SaveGuardSpot, file, "$$$$$");
newXSproto(strcpy(buf, "IsGuarding"), XS_NPC_IsGuarding, file, "$");
newXSproto(strcpy(buf, "AI_SetRoambox"), XS_NPC_AI_SetRoambox, file, "$$$$$$;$$");
newXSproto(strcpy(buf, "GetNPCSpellsID"), XS_NPC_GetNPCSpellsID, file, "$");
+3 -3
View File
@@ -240,7 +240,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
if(scale_power > 0)
{
npc_type->max_hp *= (1 + scale_power);
npc_type->cur_hp = npc_type->max_hp;
npc_type->current_hp = npc_type->max_hp;
npc_type->AC *= (1 + scale_power);
npc_type->level += 1 + ((int)act_power / 25) > npc_type->level + RuleR(Pets, PetPowerLevelCap) ? RuleR(Pets, PetPowerLevelCap) : 1 + ((int)act_power / 25); // gains an additional level for every 25 pet power
npc_type->min_dmg = (npc_type->min_dmg * (1 + (scale_power / 2)));
@@ -255,7 +255,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
if (MaxHP){
npc_type->max_hp += (npc_type->max_hp*MaxHP)/100;
npc_type->cur_hp = npc_type->max_hp;
npc_type->current_hp = npc_type->max_hp;
}
//TODO: think about regen (engaged vs. not engaged)
@@ -425,7 +425,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
into walls or objects (+10), this sometimes creates the "ghost" effect. I changed to +2 (as close as I
could get while it still looked good). I also noticed this can happen if an NPC is spawned on the same spot of another or in a related bad spot.*/
Pet::Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 power)
: NPC(type_data, 0, owner->GetPosition() + glm::vec4(2.0f, 2.0f, 0.0f, 0.0f), FlyMode3)
: NPC(type_data, 0, owner->GetPosition() + glm::vec4(2.0f, 2.0f, 0.0f, 0.0f), GravityBehavior::Water)
{
GiveNPCTypeData(type_data);
typeofpet = type;
+93
View File
@@ -5,6 +5,8 @@
#include <cmath>
#include "../common/string_util.h"
static const float position_eps = 0.0001f;
std::string to_string(const glm::vec4 &position) {
return StringFormat("(%.3f, %.3f, %.3f, %.3f)", position.x,position.y,position.z,position.w);
}
@@ -160,3 +162,94 @@ float GetReciprocalHeading(const float heading)
return result;
}
bool IsHeadingEqual(const float h1, const float h2)
{
return std::abs(h2 - h1) < 0.01f;
}
bool IsPositionEqual(const glm::vec2 &p1, const glm::vec2 &p2)
{
return std::abs(p1.x - p2.x) < position_eps && std::abs(p1.y - p2.y) < position_eps;
}
bool IsPositionEqual(const glm::vec3 &p1, const glm::vec3 &p2)
{
return std::abs(p1.x - p2.x) < position_eps && std::abs(p1.y - p2.y) < position_eps && std::abs(p1.z - p2.z) < position_eps;
}
bool IsPositionEqual(const glm::vec4 &p1, const glm::vec4 &p2)
{
return std::abs(p1.x - p2.x) < position_eps && std::abs(p1.y - p2.y) < position_eps && std::abs(p1.z - p2.z) < position_eps;
}
bool IsPositionEqualWithinCertainZ(const glm::vec3 &p1, const glm::vec3 &p2, float z_eps) {
return std::abs(p1.x - p2.x) < position_eps && std::abs(p1.y - p2.y) < position_eps && std::abs(p1.z - p2.z) < z_eps;
}
bool IsPositionEqualWithinCertainZ(const glm::vec4 &p1, const glm::vec4 &p2, float z_eps) {
return std::abs(p1.x - p2.x) < position_eps && std::abs(p1.y - p2.y) < position_eps && std::abs(p1.z - p2.z) < z_eps;
}
bool IsPositionWithinSimpleCylinder(const glm::vec3 &p1, const glm::vec3 &cylinder_center, float cylinder_radius, float cylinder_height)
{
//If we're outside the height of cylinder then we're not in it (duh)
auto d = std::abs(p1.z - cylinder_center.z);
if (d > cylinder_height / 2.0) {
return false;
}
glm::vec2 p1d(p1.x, p1.y);
glm::vec2 ccd(cylinder_center.x, cylinder_center.y);
//If we're outside the radius of the cylinder then we're not in it (also duh)
d = Distance(p1d, ccd);
if (d > cylinder_radius) {
return false;
}
return true;
}
bool IsPositionWithinSimpleCylinder(const glm::vec4 &p1, const glm::vec4 &cylinder_center, float cylinder_radius, float cylinder_height)
{
//If we're outside the height of cylinder then we're not in it (duh)
auto d = std::abs(p1.z - cylinder_center.z);
if (d > cylinder_height / 2.0) {
return false;
}
glm::vec2 p1d(p1.x, p1.y);
glm::vec2 ccd(cylinder_center.x, cylinder_center.y);
//If we're outside the radius of the cylinder then we're not in it (also duh)
d = Distance(p1d, ccd);
if (d > cylinder_radius) {
return false;
}
return true;
}
float CalculateHeadingAngleBetweenPositions(float x1, float y1, float x2, float y2)
{
float y_diff = std::abs(y1 - y2);
float x_diff = std::abs(x1 - x2);
if (y_diff < 0.0000009999999974752427)
y_diff = 0.0000009999999974752427;
float angle = atan2(x_diff, y_diff) * 180.0f * 0.3183099014828645f; // angle, nice "pi"
// return the right thing based on relative quadrant
// I'm sure this could be improved for readability, but whatever
if (y1 >= y2) {
if (x2 >= x1)
return (90.0f - angle + 90.0f) * 511.5f * 0.0027777778f;
if (x2 <= x1)
return (angle + 180.0f) * 511.5f * 0.0027777778f;
}
if (y1 > y2 || x2 > x1)
return angle * 511.5f * 0.0027777778f;
else
return (90.0f - angle + 270.0f) * 511.5f * 0.0027777778f;
}
+13
View File
@@ -50,4 +50,17 @@ float DistanceSquaredNoZ(const glm::vec4& point1, const glm::vec4& point2);
float GetReciprocalHeading(const glm::vec4& point1);
float GetReciprocalHeading(const float heading);
bool IsHeadingEqual(const float h1, const float h2);
bool IsPositionEqual(const glm::vec2 &p1, const glm::vec2 &p2);
bool IsPositionEqual(const glm::vec3 &p1, const glm::vec3 &p2);
bool IsPositionEqual(const glm::vec4 &p1, const glm::vec4 &p2);
bool IsPositionEqualWithinCertainZ(const glm::vec3 &p1, const glm::vec3 &p2, float z_eps);
bool IsPositionEqualWithinCertainZ(const glm::vec4 &p1, const glm::vec4 &p2, float z_eps);
bool IsPositionWithinSimpleCylinder(const glm::vec3 &p1, const glm::vec3 &cylinder_center, float cylinder_radius, float cylinder_height);
bool IsPositionWithinSimpleCylinder(const glm::vec4 &p1, const glm::vec4 &cylinder_center, float cylinder_radius, float cylinder_height);
float CalculateHeadingAngleBetweenPositions(float x1, float y1, float x2, float y2);
#endif
+40 -43
View File
@@ -208,7 +208,7 @@ Mob* QuestManager::spawn2(int npc_type, int grid, int unused, const glm::vec4& p
const NPCType* tmp = 0;
if (tmp = database.LoadNPCTypesData(npc_type))
{
auto npc = new NPC(tmp, nullptr, position, FlyMode3);
auto npc = new NPC(tmp, nullptr, position, GravityBehavior::Water);
npc->AddLootTable();
if (npc->DropsGlobalLoot())
npc->CheckGlobalLootTables();
@@ -217,7 +217,7 @@ Mob* QuestManager::spawn2(int npc_type, int grid, int unused, const glm::vec4& p
{
npc->AssignWaypoints(grid);
}
npc->SendPositionUpdate();
return npc;
}
return nullptr;
@@ -232,7 +232,7 @@ Mob* QuestManager::unique_spawn(int npc_type, int grid, int unused, const glm::v
const NPCType* tmp = 0;
if (tmp = database.LoadNPCTypesData(npc_type))
{
auto npc = new NPC(tmp, nullptr, position, FlyMode3);
auto npc = new NPC(tmp, nullptr, position, GravityBehavior::Water);
npc->AddLootTable();
if (npc->DropsGlobalLoot())
npc->CheckGlobalLootTables();
@@ -241,7 +241,7 @@ Mob* QuestManager::unique_spawn(int npc_type, int grid, int unused, const glm::v
{
npc->AssignWaypoints(grid);
}
npc->SendPositionUpdate();
return npc;
}
return nullptr;
@@ -308,22 +308,22 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id)
found_spawn->SetCurrentNPCID(npcid);
auto position = glm::vec4(found_spawn->GetX(), found_spawn->GetY(), found_spawn->GetZ(), found_spawn->GetHeading());
auto npc = new NPC(tmp, found_spawn, position, FlyMode3);
auto npc = new NPC(tmp, found_spawn, position, GravityBehavior::Water);
found_spawn->SetNPCPointer(npc);
npc->AddLootTable();
if (npc->DropsGlobalLoot())
npc->CheckGlobalLootTables();
npc->SetSp2(found_spawn->SpawnGroupID());
entity_list.AddNPC(npc);
entity_list.LimitAddNPC(npc);
found_spawn->SetNPCPointer(npc);
npc->AddLootTable();
if (npc->DropsGlobalLoot())
npc->CheckGlobalLootTables();
npc->SetSp2(found_spawn->SpawnGroupID());
entity_list.AddNPC(npc);
entity_list.LimitAddNPC(npc);
if (sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay &&
sg->min_delay)
npc->AI_SetRoambox(sg->roamdist, sg->roambox[0], sg->roambox[1], sg->roambox[2], sg->roambox[3],
sg->delay, sg->min_delay);
if (zone->InstantGrids()) {
found_spawn->LoadGrid();
if (sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay &&
sg->min_delay)
npc->AI_SetRoambox(sg->roamdist, sg->roambox[0], sg->roambox[1], sg->roambox[2], sg->roambox[3],
sg->delay, sg->min_delay);
if (zone->InstantGrids()) {
found_spawn->LoadGrid();
}
return npc;
@@ -371,14 +371,14 @@ void QuestManager::castspell(int spell_id, int target_id) {
if (owner) {
Mob *tgt = entity_list.GetMob(target_id);
if(tgt != nullptr)
owner->SpellFinished(spell_id, tgt, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
owner->SpellFinished(spell_id, tgt, EQEmu::spells::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
}
}
void QuestManager::selfcast(int spell_id) {
QuestManagerCurrentQuestVars();
if (initiator)
initiator->SpellFinished(spell_id, initiator, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
initiator->SpellFinished(spell_id, initiator, EQEmu::spells::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
}
void QuestManager::addloot(int item_id, int charges, bool equipitem, int aug1, int aug2, int aug3, int aug4, int aug5, int aug6) {
@@ -985,7 +985,7 @@ uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) {
bool SpellBucketCheckResult = 0;
for(spell_id = 0, book_slot = initiator->GetNextAvailableSpellBookSlot(), count = 0; spell_id < SPDAT_RECORDS && book_slot < MAX_PP_SPELLBOOK; spell_id++, book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot))
for(spell_id = 0, book_slot = initiator->GetNextAvailableSpellBookSlot(), count = 0; spell_id < SPDAT_RECORDS && book_slot < EQEmu::spells::SPELLBOOK_SIZE; spell_id++, book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot))
{
if
(
@@ -1706,32 +1706,33 @@ void QuestManager::respawn(int npcTypeID, int grid) {
const NPCType* npcType = nullptr;
if ((npcType = database.LoadNPCTypesData(npcTypeID)))
{
owner = new NPC(npcType, nullptr, owner->GetPosition(), FlyMode3);
owner = new NPC(npcType, nullptr, owner->GetPosition(), GravityBehavior::Water);
owner->CastToNPC()->AddLootTable();
if (owner->CastToNPC()->DropsGlobalLoot())
owner->CastToNPC()->CheckGlobalLootTables();
entity_list.AddNPC(owner->CastToNPC(),true,true);
if(grid > 0)
owner->CastToNPC()->AssignWaypoints(grid);
owner->SendPositionUpdate();
}
}
void QuestManager::set_proximity(float minx, float maxx, float miny, float maxy, float minz, float maxz, bool bSay) {
void QuestManager::set_proximity(float minx, float maxx, float miny, float maxy, float minz, float maxz, bool bSay)
{
QuestManagerCurrentQuestVars();
if (!owner || !owner->IsNPC())
if (!owner || !owner->IsNPC()) {
return;
}
entity_list.AddProximity(owner->CastToNPC());
owner->CastToNPC()->proximity->min_x = minx;
owner->CastToNPC()->proximity->max_x = maxx;
owner->CastToNPC()->proximity->min_y = miny;
owner->CastToNPC()->proximity->max_y = maxy;
owner->CastToNPC()->proximity->min_z = minz;
owner->CastToNPC()->proximity->max_z = maxz;
owner->CastToNPC()->proximity->say = bSay;
owner->CastToNPC()->proximity->min_x = minx;
owner->CastToNPC()->proximity->max_x = maxx;
owner->CastToNPC()->proximity->min_y = miny;
owner->CastToNPC()->proximity->max_y = maxy;
owner->CastToNPC()->proximity->min_z = minz;
owner->CastToNPC()->proximity->max_z = maxz;
owner->CastToNPC()->proximity->say = bSay;
owner->CastToNPC()->proximity->proximity_set = true;
}
void QuestManager::clear_proximity() {
@@ -2823,22 +2824,18 @@ bool QuestManager::IsRunning()
return owner->IsRunning();
}
void QuestManager::FlyMode(uint8 flymode)
void QuestManager::FlyMode(GravityBehavior flymode)
{
QuestManagerCurrentQuestVars();
if(initiator)
{
if (flymode >= 0 && flymode < 3) {
initiator->SendAppearancePacket(AT_Levitate, flymode);
return;
}
initiator->SendAppearancePacket(AT_Levitate, static_cast<int>(flymode));
initiator->SetFlyMode(flymode);
}
if(owner)
else if(owner)
{
if (flymode >= 0 && flymode < 3) {
owner->SendAppearancePacket(AT_Levitate, flymode);
return;
}
owner->SendAppearancePacket(AT_Levitate, static_cast<int>(flymode));
owner->SetFlyMode(flymode);
}
}
+1 -1
View File
@@ -252,7 +252,7 @@ public:
const char* getguildnamebyid(int guild_id);
void SetRunning(bool val);
bool IsRunning();
void FlyMode(uint8 flymode);
void FlyMode(GravityBehavior flymode);
uint8 FactionValue();
void wearchange(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0);
void voicetell(const char *str, int macronum, int racenum, int gendernum);
+3 -3
View File
@@ -255,7 +255,7 @@ bool Spawn2::Process() {
}
currentnpcid = npcid;
NPC *npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), FlyMode3);
NPC *npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), GravityBehavior::Water);
npc->mod_prespawn(this);
@@ -488,7 +488,7 @@ bool ZoneDatabase::PopulateZoneSpawnListClose(uint32 zoneid, LinkedList<Spawn2*>
"animation "
"FROM "
"spawn2 "
"WHERE zone = '%s' AND version = %u",
"WHERE zone = '%s' AND (version = %u OR version = -1) ",
zone_name,
version
);
@@ -592,7 +592,7 @@ bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spa
"animation "
"FROM "
"spawn2 "
"WHERE zone = '%s' AND version = %u",
"WHERE zone = '%s' AND (version = %u OR version = -1)",
zone_name,
version
);
+4 -4
View File
@@ -27,7 +27,7 @@
#include <string.h>
extern uint64_t frame_time;
extern double frame_time;
int Mob::GetBaseSkillDamage(EQEmu::skills::SkillType skill, Mob *target)
{
@@ -197,7 +197,7 @@ void Mob::DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int32
IsValidSpell(aabonuses.SkillAttackProc[2])) {
float chance = aabonuses.SkillAttackProc[0] / 1000.0f;
if (zone->random.Roll(chance))
SpellFinished(aabonuses.SkillAttackProc[2], who, EQEmu::CastingSlot::Item, 0, -1,
SpellFinished(aabonuses.SkillAttackProc[2], who, EQEmu::spells::CastingSlot::Item, 0, -1,
spells[aabonuses.SkillAttackProc[2]].ResistDiff);
}
@@ -1033,7 +1033,7 @@ void Mob::ProjectileAttack()
ProjectileAtk[i].skill = 0;
ProjectileAtk[i].speed_mod = 0.0f;
} else {
ProjectileAtk[i].increment += frame_time;
ProjectileAtk[i].increment += 1000 * frame_time;
}
}
@@ -2156,7 +2156,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob *other, uint16 weapon_damage, EQEmu::skills:
IsValidSpell(aabonuses.SkillAttackProc[2])) {
float chance = aabonuses.SkillAttackProc[0] / 1000.0f;
if (zone->random.Roll(chance))
SpellFinished(aabonuses.SkillAttackProc[2], other, EQEmu::CastingSlot::Item, 0, -1,
SpellFinished(aabonuses.SkillAttackProc[2], other, EQEmu::spells::CastingSlot::Item, 0, -1,
spells[aabonuses.SkillAttackProc[2]].ResistDiff);
}
+16 -75
View File
@@ -149,7 +149,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
if (spells[spell_id].EndurUpkeep > 0)
SetEndurUpkeep(true);
if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::bit_UFAndLater)
if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::maskUFAndLater)
{
EQApplicationPacket *outapp = MakeBuffsPacket(false);
CastToClient()->FastQueuePacket(&outapp);
@@ -826,9 +826,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
#endif
if(IsClient())
{
CastToClient()->SetSenseExemption(true);
if (CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoDAndLater)
if (CastToClient()->ClientVersionBit() & EQEmu::versions::maskSoDAndLater)
{
bodyType bt = BT_Undead;
@@ -853,7 +851,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
SetHeading(CalculateHeadingToTarget(ClosestMob->GetX(), ClosestMob->GetY()));
SetTarget(ClosestMob);
CastToClient()->SendTargetCommand(ClosestMob->GetID());
SendPositionUpdate(2);
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0, true);
}
else
Message_StringID(clientMessageError, SENSE_NOTHING);
@@ -1246,7 +1244,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
// Will fix buttons for now
if (IsClient()) {
auto c = CastToClient();
if (c->ClientVersionBit() & EQEmu::versions::bit_UFAndLater) {
if (c->ClientVersionBit() & EQEmu::versions::maskUFAndLater) {
c->SetPetCommandState(PET_BUTTON_SIT, 0);
c->SetPetCommandState(PET_BUTTON_STOP, 0);
c->SetPetCommandState(PET_BUTTON_REGROUP, 0);
@@ -1665,7 +1663,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
#endif
// This is handled by the client prior to SoD.
//
if (IsClient() && (CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoDAndLater))
if (IsClient() && (CastToClient()->ClientVersionBit() & EQEmu::versions::maskSoDAndLater))
CastToClient()->LocateCorpse();
break;
@@ -2472,7 +2470,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
case SE_FcTimerRefresh:
{
if(IsClient()) {
for(unsigned int i =0 ; i < MAX_PP_MEMSPELL; ++i) {
for (unsigned int i = 0; i < EQEmu::spells::SPELL_GEM_COUNT; ++i) {
if(IsValidSpell(CastToClient()->m_pp.mem_spells[i])) {
if (CalcFocusEffect(focusFcTimerRefresh, spell_id, CastToClient()->m_pp.mem_spells[i])){
CastToClient()->m_pp.spellSlotRefresh[i] = 1;
@@ -2741,7 +2739,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
if (caster && IsValidSpell(spells[spell_id].base2[i])){
if(zone->random.Roll(spells[spell_id].base[i]))
caster->SpellFinished(spells[spell_id].base2[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff);
caster->SpellFinished(spells[spell_id].base2[i], this, EQEmu::spells::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff);
}
break;
}
@@ -3404,7 +3402,7 @@ void Mob::BuffProcess()
Log(Logs::Detail, Logs::Spells, "Buff %d in slot %d has %d tics remaining.", buffs[buffs_i].spellid, buffs_i, buffs[buffs_i].ticsremaining);
}
}
else if (IsClient() && !(CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoFAndLater))
else if (IsClient() && !(CastToClient()->ClientVersionBit() & EQEmu::versions::maskSoFAndLater))
{
buffs[buffs_i].UpdateClient = true;
}
@@ -3664,14 +3662,14 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster)
case SE_CastOnFadeEffectNPC:
case SE_CastOnFadeEffectAlways: {
if (buff.ticsremaining == 0) {
SpellFinished(spells[buff.spellid].base[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[spells[buff.spellid].base[i]].ResistDiff);
SpellFinished(spells[buff.spellid].base[i], this, EQEmu::spells::CastingSlot::Item, 0, -1, spells[spells[buff.spellid].base[i]].ResistDiff);
}
break;
}
case SE_LocateCorpse: {
// This is handled by the client prior to SoD.
if (IsClient() && (CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoDAndLater))
if (IsClient() && (CastToClient()->ClientVersionBit() & EQEmu::versions::maskSoDAndLater))
CastToClient()->LocateCorpse();
}
@@ -4038,63 +4036,6 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
SetLevel(GetOrigLevel());
break;
}
case SE_MovementSpeed:
{
if(IsClient())
{
Client *my_c = CastToClient();
uint32 cur_time = Timer::GetCurrentTime();
if((cur_time - my_c->m_TimeSinceLastPositionCheck) > 1000)
{
float speed = (my_c->m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - my_c->m_TimeSinceLastPositionCheck);
float runs = my_c->GetRunspeed();
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
{
if(!my_c->GetGMSpeed() && (runs >= my_c->GetBaseRunspeed() || (speed > (my_c->GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
{
printf("%s %i moving too fast! moved: %.2f in %ims, speed %.2f\n", __FILE__, __LINE__,
my_c->m_DistanceSinceLastPositionCheck, (cur_time - my_c->m_TimeSinceLastPositionCheck), speed);
if(my_c->IsShadowStepExempted())
{
if(my_c->m_DistanceSinceLastPositionCheck > 800)
{
my_c->CheatDetected(MQWarpShadowStep, my_c->GetX(), my_c->GetY(), my_c->GetZ());
}
}
else if(my_c->IsKnockBackExempted())
{
//still potential to trigger this if you're knocked back off a
//HUGE fall that takes > 2.5 seconds
if(speed > 30.0f)
{
my_c->CheatDetected(MQWarpKnockBack, my_c->GetX(), my_c->GetY(), my_c->GetZ());
}
}
else if(!my_c->IsPortExempted())
{
if(!my_c->IsMQExemptedArea(zone->GetZoneID(), my_c->GetX(), my_c->GetY(), my_c->GetZ()))
{
if(speed > (runs * 2 * RuleR(Zone, MQWarpDetectionDistanceFactor)))
{
my_c->m_TimeSinceLastPositionCheck = cur_time;
my_c->m_DistanceSinceLastPositionCheck = 0.0f;
my_c->CheatDetected(MQWarp, my_c->GetX(), my_c->GetY(), my_c->GetZ());
//my_c->Death(my_c, 10000000, SPELL_UNKNOWN, _1H_BLUNT);
}
else
{
my_c->CheatDetected(MQWarpLight, my_c->GetX(), my_c->GetY(), my_c->GetZ());
}
}
}
}
}
}
my_c->m_TimeSinceLastPositionCheck = cur_time;
my_c->m_DistanceSinceLastPositionCheck = 0.0f;
}
}
}
}
@@ -4144,7 +4085,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
{
EQApplicationPacket *outapp = MakeBuffsPacket();
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQEmu::versions::bit_SoDAndLater);
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQEmu::versions::maskSoDAndLater);
if(IsClient() && GetTarget() == this) {
CastToClient()->QueuePacket(outapp);
}
@@ -4154,11 +4095,11 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
if (IsNPC()) {
EQApplicationPacket *outapp = MakeBuffsPacket();
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQEmu::versions::bit_SoDAndLater, true);
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQEmu::versions::maskSoDAndLater, true);
safe_delete(outapp);
}
if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::bit_UFAndLater)
if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::maskUFAndLater)
{
EQApplicationPacket *outapp = MakeBuffsPacket(false);
CastToClient()->FastQueuePacket(&outapp);
@@ -5159,7 +5100,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
if (Caston_spell_id) {
if (IsValidSpell(Caston_spell_id) && (Caston_spell_id != spell_id))
SpellFinished(Caston_spell_id, this, EQEmu::CastingSlot::Item, 0, -1, spells[Caston_spell_id].ResistDiff);
SpellFinished(Caston_spell_id, this, EQEmu::spells::CastingSlot::Item, 0, -1, spells[Caston_spell_id].ResistDiff);
}
return (value * lvlModifier / 100);
@@ -6722,10 +6663,10 @@ void Mob::TryTriggerThreshHold(int32 damage, int effect_id, Mob* attacker){
if (IsValidSpell(spell_id)) {
if (IsBeneficialSpell(spell_id))
SpellFinished(spell_id, this, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
SpellFinished(spell_id, this, EQEmu::spells::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
else if(attacker)
SpellFinished(spell_id, attacker, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
SpellFinished(spell_id, attacker, EQEmu::spells::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
}
}
}
+24 -63
View File
@@ -107,7 +107,7 @@ extern volatile bool is_zone_loaded;
extern WorldServer worldserver;
extern FastMath g_Math;
using EQEmu::CastingSlot;
using EQEmu::spells::CastingSlot;
// this is run constantly for every mob
void Mob::SpellProcess()
@@ -305,8 +305,9 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
}
//To prevent NPC ghosting when spells are cast from scripts
if (IsNPC() && IsMoving() && cast_time > 0)
SendPosition();
if (IsNPC() && IsMoving() && cast_time > 0) {
StopNavigation();
}
if(resist_adjust)
{
@@ -2665,23 +2666,6 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) {
action->effect_flag = 4;
if(spells[spell_id].pushback != 0.0f || spells[spell_id].pushup != 0.0f)
{
if(IsClient())
{
if(!IsBuffSpell(spell_id))
{
CastToClient()->SetKnockBackExemption(true);
}
}
}
if(IsClient() && IsEffectInSpell(spell_id, SE_ShadowStep))
{
CastToClient()->SetShadowStepExemption(true);
}
if(!IsEffectInSpell(spell_id, SE_BindAffinity))
{
CastToClient()->QueuePacket(packet);
@@ -3333,7 +3317,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
{
EQApplicationPacket *outapp = MakeBuffsPacket();
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQEmu::versions::bit_SoDAndLater);
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQEmu::versions::maskSoDAndLater);
if(IsClient() && GetTarget() == this)
CastToClient()->QueuePacket(outapp);
@@ -3343,7 +3327,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
if (IsNPC()) {
EQApplicationPacket *outapp = MakeBuffsPacket();
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQEmu::versions::bit_SoDAndLater, true);
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQEmu::versions::maskSoDAndLater, true);
safe_delete(outapp);
}
@@ -3947,13 +3931,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
if(spells[spell_id].pushback != 0.0f || spells[spell_id].pushup != 0.0f)
{
if(spelltar->IsClient())
{
if(!IsBuffSpell(spell_id))
{
spelltar->CastToClient()->SetKnockBackExemption(true);
}
} else if (RuleB(Spells, NPCSpellPush) && !spelltar->IsRooted() && spelltar->ForcedMovement == 0) {
if (RuleB(Spells, NPCSpellPush) && !spelltar->IsRooted() && spelltar->ForcedMovement == 0) {
spelltar->m_Delta.x += action->force * g_Math.FastSin(action->hit_heading);
spelltar->m_Delta.y += action->force * g_Math.FastCos(action->hit_heading);
spelltar->m_Delta.z += action->hit_pitch;
@@ -3961,11 +3939,6 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
}
}
if(spelltar->IsClient() && IsEffectInSpell(spell_id, SE_ShadowStep))
{
spelltar->CastToClient()->SetShadowStepExemption(true);
}
if(!IsEffectInSpell(spell_id, SE_BindAffinity))
{
if(spelltar != this && spelltar->IsClient()) // send to target
@@ -4929,12 +4902,11 @@ void Client::UnStun() {
void NPC::Stun(int duration) {
Mob::Stun(duration);
SetCurrentSpeed(0);
StopNavigation();
}
void NPC::UnStun() {
Mob::UnStun();
SetCurrentSpeed(GetRunspeed());
}
void Mob::Mesmerize()
@@ -4944,18 +4916,7 @@ void Mob::Mesmerize()
if (casting_spell_id)
InterruptSpell();
SendPosition();
/* this stuns the client for max time, with no way to break it
if (this->IsClient()){
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Stun, sizeof(Stun_Struct));
Stun_Struct* stunon = (Stun_Struct*) outapp->pBuffer;
stunon->duration = 0xFFFF;
this->CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
} else {
SetRunAnimSpeed(0);
}
*/
StopNavigation();
}
void Client::MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message)
@@ -5007,7 +4968,7 @@ void Client::MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message)
void Client::MemSpell(uint16 spell_id, int slot, bool update_client)
{
if(slot >= MAX_PP_MEMSPELL || slot < 0)
if(slot >= EQEmu::spells::SPELL_GEM_COUNT || slot < 0)
return;
if(update_client)
@@ -5029,7 +4990,7 @@ void Client::MemSpell(uint16 spell_id, int slot, bool update_client)
void Client::UnmemSpell(int slot, bool update_client)
{
if(slot > MAX_PP_MEMSPELL || slot < 0)
if(slot > EQEmu::spells::SPELL_GEM_COUNT || slot < 0)
return;
Log(Logs::Detail, Logs::Spells, "Spell %d forgotten from slot %d", m_pp.mem_spells[slot], slot);
@@ -5045,7 +5006,7 @@ void Client::UnmemSpell(int slot, bool update_client)
void Client::UnmemSpellBySpellID(int32 spell_id)
{
for(int i = 0; i < MAX_PP_MEMSPELL; i++) {
for(int i = 0; i < EQEmu::spells::SPELL_GEM_COUNT; i++) {
if(m_pp.mem_spells[i] == spell_id) {
UnmemSpell(i, true);
break;
@@ -5057,14 +5018,14 @@ void Client::UnmemSpellAll(bool update_client)
{
int i;
for(i = 0; i < MAX_PP_MEMSPELL; i++)
for(i = 0; i < EQEmu::spells::SPELL_GEM_COUNT; i++)
if(m_pp.mem_spells[i] != 0xFFFFFFFF)
UnmemSpell(i, update_client);
}
void Client::ScribeSpell(uint16 spell_id, int slot, bool update_client)
{
if(slot >= MAX_PP_SPELLBOOK || slot < 0)
if(slot >= EQEmu::spells::SPELLBOOK_SIZE || slot < 0)
return;
if(update_client)
@@ -5085,7 +5046,7 @@ void Client::ScribeSpell(uint16 spell_id, int slot, bool update_client)
void Client::UnscribeSpell(int slot, bool update_client)
{
if(slot >= MAX_PP_SPELLBOOK || slot < 0)
if(slot >= EQEmu::spells::SPELLBOOK_SIZE || slot < 0)
return;
Log(Logs::Detail, Logs::Spells, "Spell %d erased from spell book slot %d", m_pp.spell_book[slot], slot);
@@ -5107,7 +5068,7 @@ void Client::UnscribeSpellAll(bool update_client)
{
int i;
for(i = 0; i < MAX_PP_SPELLBOOK; i++)
for(i = 0; i < EQEmu::spells::SPELLBOOK_SIZE; i++)
{
if(m_pp.spell_book[i] != 0xFFFFFFFF)
UnscribeSpell(i, update_client);
@@ -5141,7 +5102,7 @@ void Client::UntrainDiscAll(bool update_client)
}
int Client::GetNextAvailableSpellBookSlot(int starting_slot) {
for (int i = starting_slot; i < MAX_PP_SPELLBOOK; i++) { //using starting_slot should help speed this up when we're iterating through a bunch of spells
for (int i = starting_slot; i < EQEmu::spells::SPELLBOOK_SIZE; i++) { //using starting_slot should help speed this up when we're iterating through a bunch of spells
if (!IsValidSpell(GetSpellByBookSlot(i)))
return i;
}
@@ -5150,7 +5111,7 @@ int Client::GetNextAvailableSpellBookSlot(int starting_slot) {
}
int Client::FindSpellBookSlotBySpellID(uint16 spellid) {
for(int i = 0; i < MAX_PP_SPELLBOOK; i++) {
for(int i = 0; i < EQEmu::spells::SPELLBOOK_SIZE; i++) {
if(m_pp.spell_book[i] == spellid)
return i;
}
@@ -5208,7 +5169,7 @@ bool Client::SpellBucketCheck(uint16 spell_id, uint32 char_id) {
std::string spell_bucket_name;
int spell_bucket_value;
int bucket_value;
std::string query = StringFormat("SELECT key, value FROM spell_buckets WHERE spellid = %i", spell_id);
std::string query = StringFormat("SELECT `key`, value FROM spell_buckets WHERE spellid = %i", spell_id);
auto results = database.QueryDatabase(query);
if (!results.Success())
return false;
@@ -5222,7 +5183,7 @@ bool Client::SpellBucketCheck(uint16 spell_id, uint32 char_id) {
if (spell_bucket_name.empty())
return true;
query = StringFormat("SELECT value FROM data_buckets WHERE key = '%i-%s'", char_id, spell_bucket_name.c_str());
query = StringFormat("SELECT value FROM data_buckets WHERE `key` = '%i-%s'", char_id, spell_bucket_name.c_str());
results = database.QueryDatabase(query);
if (!results.Success()) {
Log(Logs::General, Logs::Error, "Spell bucket %s for spell ID %i for char ID %i failed.", spell_bucket_name.c_str(), spell_id, char_id);
@@ -5449,7 +5410,7 @@ bool Mob::UseBardSpellLogic(uint16 spell_id, int slot)
spell_id != SPELL_UNKNOWN &&
slot != -1 &&
GetClass() == BARD &&
slot <= MAX_PP_MEMSPELL &&
slot <= EQEmu::spells::SPELL_GEM_COUNT &&
IsBardSong(spell_id)
);
}
@@ -5570,7 +5531,7 @@ void Mob::SendBuffsToClient(Client *c)
if(!c)
return;
if (c->ClientVersionBit() & EQEmu::versions::bit_SoDAndLater)
if (c->ClientVersionBit() & EQEmu::versions::maskSoDAndLater)
{
EQApplicationPacket *outapp = MakeBuffsPacket();
c->FastQueuePacket(&outapp);
@@ -5658,12 +5619,12 @@ int Client::GetCurrentBuffSlots() const
numbuffs++;
if (GetLevel() > 74)
numbuffs++;
return EQEmu::ClampUpper(numbuffs, EQEmu::constants::Lookup(m_ClientVersion)->LongBuffs);
return EQEmu::ClampUpper(numbuffs, EQEmu::spells::StaticLookup(m_ClientVersion)->LongBuffs);
}
int Client::GetCurrentSongSlots() const
{
return EQEmu::constants::Lookup(m_ClientVersion)->ShortBuffs; // AAs dont affect this
return EQEmu::spells::StaticLookup(m_ClientVersion)->ShortBuffs; // AAs dont affect this
}
void Client::InitializeBuffSlots()
+1 -1
View File
@@ -2700,7 +2700,7 @@ void TaskManager::SendTaskActivityShort(Client *c, int TaskID, int ActivityID, i
TaskActivityShort_Struct* tass;
if (c->ClientVersionBit() & EQEmu::versions::bit_RoFAndLater)
if (c->ClientVersionBit() & EQEmu::versions::maskRoFAndLater)
{
auto outapp = new EQApplicationPacket(OP_TaskActivity, 25);
outapp->WriteUInt32(ClientTaskIndex);
+5 -5
View File
@@ -135,7 +135,7 @@ void Trap::Trigger(Mob* trigger)
entity_list.MessageClose(trigger,false,100,13,"%s",message.c_str());
}
if(hiddenTrigger){
hiddenTrigger->SpellFinished(effectvalue, trigger, EQEmu::CastingSlot::Item, 0, -1, spells[effectvalue].ResistDiff);
hiddenTrigger->SpellFinished(effectvalue, trigger, EQEmu::spells::CastingSlot::Item, 0, -1, spells[effectvalue].ResistDiff);
}
break;
case trapTypeAlarm:
@@ -166,7 +166,7 @@ void Trap::Trigger(Mob* trigger)
{
auto randomOffset = glm::vec4(zone->random.Int(-5, 5),zone->random.Int(-5, 5),zone->random.Int(-5, 5), zone->random.Int(0, 249));
auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f);
auto new_npc = new NPC(tmp, nullptr, spawnPosition, FlyMode3);
auto new_npc = new NPC(tmp, nullptr, spawnPosition, GravityBehavior::Flying);
new_npc->AddLootTable();
if (new_npc->DropsGlobalLoot())
new_npc->CheckGlobalLootTables();
@@ -191,7 +191,7 @@ void Trap::Trigger(Mob* trigger)
{
auto randomOffset = glm::vec4(zone->random.Int(-2, 2), zone->random.Int(-2, 2), zone->random.Int(-2, 2), zone->random.Int(0, 249));
auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f);
auto new_npc = new NPC(tmp, nullptr, spawnPosition, FlyMode3);
auto new_npc = new NPC(tmp, nullptr, spawnPosition, GravityBehavior::Flying);
new_npc->AddLootTable();
if (new_npc->DropsGlobalLoot())
new_npc->CheckGlobalLootTables();
@@ -456,7 +456,7 @@ void Trap::CreateHiddenTrigger()
auto make_npc = new NPCType;
memcpy(make_npc, base_type, sizeof(NPCType));
make_npc->max_hp = 100000;
make_npc->cur_hp = 100000;
make_npc->current_hp = 100000;
strcpy(make_npc->name, "a_trap");
make_npc->runspeed = 0.0f;
make_npc->bodytype = BT_Special;
@@ -469,7 +469,7 @@ void Trap::CreateHiddenTrigger()
make_npc->trackable = 0;
make_npc->level = level;
strcpy(make_npc->special_abilities, "19,1^20,1^24,1^25,1");
NPC* npca = new NPC(make_npc, nullptr, glm::vec4(m_Position, 0.0f), FlyMode3);
NPC* npca = new NPC(make_npc, nullptr, glm::vec4(m_Position, 0.0f), GravityBehavior::Flying);
npca->GiveNPCTypeData(make_npc);
entity_list.AddNPC(npca);
+7
View File
@@ -14,25 +14,30 @@ WaterMap* WaterMap::LoadWaterMapfile(std::string zone_name) {
std::transform(zone_name.begin(), zone_name.end(), zone_name.begin(), ::tolower);
std::string file_path = Config->MapDir + "water/" + zone_name + std::string(".wtr");
Log(Logs::General, Logs::Debug, "Attempting to load water map with path %s", file_path.c_str());
FILE *f = fopen(file_path.c_str(), "rb");
if(f) {
char magic[10];
uint32 version;
if(fread(magic, 10, 1, f) != 1) {
Log(Logs::General, Logs::Debug, "Failed to load water map, error reading magic string in header.");
fclose(f);
return nullptr;
}
if(strncmp(magic, "EQEMUWATER", 10)) {
Log(Logs::General, Logs::Debug, "Failed to load water map, bad magic string in header.");
fclose(f);
return nullptr;
}
if(fread(&version, sizeof(version), 1, f) != 1) {
Log(Logs::General, Logs::Debug, "Failed to load water map, error reading version.");
fclose(f);
return nullptr;
}
Log(Logs::General, Logs::Debug, "Attempting to V%u load water map %s.", version, file_path.c_str());
if(version == 1) {
auto wm = new WaterMapV1();
if(!wm->Load(f)) {
@@ -56,10 +61,12 @@ WaterMap* WaterMap::LoadWaterMapfile(std::string zone_name) {
fclose(f);
return wm;
} else {
Log(Logs::General, Logs::Debug, "Failed to load water map, unsupported version V%u.", version);
fclose(f);
return nullptr;
}
}
Log(Logs::General, Logs::Debug, "Failed to load water map, could not open file for reading %s.", file_path.c_str());
return nullptr;
}
+68 -214
View File
@@ -30,6 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "quest_parser_collection.h"
#include "water_map.h"
#include "fastmath.h"
#include "mob_movement_manager.h"
#include <math.h>
#include <stdlib.h>
@@ -92,7 +93,7 @@ void NPC::StopWandering()
{ // stops a mob from wandering, takes him off grid and sends him back to spawn point
roamer = false;
CastToNPC()->SetGrid(0);
SendPosition();
StopNavigation();
Log(Logs::Detail, Logs::Pathing, "Stop Wandering requested.");
return;
}
@@ -149,7 +150,7 @@ void NPC::PauseWandering(int pausetime)
moving = false;
DistractedFromGrid = true;
Log(Logs::Detail, Logs::Pathing, "Paused Wandering requested. Grid %d. Resuming in %d ms (0=not until told)", GetGrid(), pausetime);
SendPosition();
StopNavigation();
if (pausetime < 1) { // negative grid number stops him dead in his tracks until ResumeWandering()
SetGrid(0 - GetGrid());
}
@@ -332,8 +333,6 @@ void NPC::CalculateNewWaypoint()
}
}
tar_ndx = 52;
// Preserve waypoint setting for quest controlled NPCs
if (cur_wp < 0)
cur_wp = old_wp;
@@ -391,13 +390,8 @@ void NPC::SetWaypointPause()
{
//Declare time to wait on current WP
if (cur_wp_pause == 0) {
AI_walking_timer->Start(100);
AI_walking_timer->Trigger();
}
else
if(cur_wp_pause > 0)
{
switch (pausetype)
{
case 0: //Random Half
@@ -413,31 +407,22 @@ void NPC::SetWaypointPause()
}
}
void NPC::SaveGuardSpot(bool iClearGuardSpot) {
if (iClearGuardSpot) {
Log(Logs::Detail, Logs::AI, "Clearing guard order.");
m_GuardPoint = glm::vec4();
}
else {
m_GuardPoint = m_Position;
void NPC::SaveGuardSpot(const glm::vec4 &pos)
{
m_GuardPoint = pos;
if (m_GuardPoint.w == 0)
m_GuardPoint.w = 0.0001; //hack to make IsGuarding simpler
Log(Logs::Detail, Logs::AI, "Setting guard position to %s", to_string(static_cast<glm::vec3>(m_GuardPoint)).c_str());
}
if (m_GuardPoint.w == 0)
m_GuardPoint.w = 0.0001; //hack to make IsGuarding simpler
LogF(Logs::Detail, Logs::AI, "Setting guard position to {0}", to_string(static_cast<glm::vec3>(m_GuardPoint)));
}
void NPC::NextGuardPosition() {
if (!CalculateNewPosition(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, GetMovespeed())) {
SetHeading(m_GuardPoint.w);
Log(Logs::Detail, Logs::AI, "Unable to move to next guard position. Probably rooted.");
}
else if ((m_Position.x == m_GuardPoint.x) && (m_Position.y == m_GuardPoint.y) && (m_Position.z == m_GuardPoint.z))
NavigateTo(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z);
if (IsPositionEqualWithinCertainZ(m_Position, m_GuardPoint, 5.0f))
{
if (moved)
{
moved = false;
SetCurrentSpeed(0);
}
}
}
@@ -446,179 +431,48 @@ float Mob::CalculateDistance(float x, float y, float z) {
return (float)sqrtf(((m_Position.x - x)*(m_Position.x - x)) + ((m_Position.y - y)*(m_Position.y - y)) + ((m_Position.z - z)*(m_Position.z - z)));
}
bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, bool check_z, bool calculate_heading) {
if (GetID() == 0)
return true;
if (speed <= 0) {
SetCurrentSpeed(0);
return true;
}
if ((m_Position.x - x == 0) && (m_Position.y - y == 0)) { //spawn is at target coords
return false;
}
else if ((std::abs(m_Position.x - x) < 0.1) && (std::abs(m_Position.y - y) < 0.1)) {
if (IsNPC()) {
entity_list.ProcessMove(CastToNPC(), x, y, z);
}
m_Position.x = x;
m_Position.y = y;
m_Position.z = z;
return true;
}
int compare_steps = 20;
if (tar_ndx < compare_steps && m_TargetLocation.x == x && m_TargetLocation.y == y) {
float new_x = m_Position.x + m_TargetV.x * tar_vector;
float new_y = m_Position.y + m_TargetV.y * tar_vector;
float new_z = m_Position.z + m_TargetV.z * tar_vector;
if (IsNPC()) {
entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z);
}
m_Position.x = new_x;
m_Position.y = new_y;
m_Position.z = new_z;
if (check_z && fix_z_timer.Check() && (!this->IsEngaged() || flee_mode || currently_fleeing)) {
this->FixZ();
}
tar_ndx++;
return true;
}
if (tar_ndx > 50) {
tar_ndx--;
}
else {
tar_ndx = 0;
}
m_TargetLocation = glm::vec3(x, y, z);
float nx = this->m_Position.x;
float ny = this->m_Position.y;
float nz = this->m_Position.z;
// float nh = this->heading;
m_TargetV.x = x - nx;
m_TargetV.y = y - ny;
m_TargetV.z = z - nz;
SetCurrentSpeed((int8)speed);
pRunAnimSpeed = speed;
#ifdef BOTS
if (IsClient() || IsBot())
#else
if (IsClient())
#endif
{
animation = speed / 2;
}
// --------------------------------------------------------------------------
// 2: get unit vector
// --------------------------------------------------------------------------
float mag = sqrtf(m_TargetV.x*m_TargetV.x + m_TargetV.y*m_TargetV.y + m_TargetV.z*m_TargetV.z);
tar_vector = (float)speed / mag;
// mob move fix
int numsteps = (int)(mag * 13.5f / (float)speed + 0.5f);
// mob move fix
if (numsteps < 20) {
if (numsteps > 1) {
tar_vector = 1.0f;
m_TargetV.x = m_TargetV.x / (float) numsteps;
m_TargetV.y = m_TargetV.y / (float) numsteps;
m_TargetV.z = m_TargetV.z / (float) numsteps;
float new_x = m_Position.x + m_TargetV.x;
float new_y = m_Position.y + m_TargetV.y;
float new_z = m_Position.z + m_TargetV.z;
if (IsNPC()) {
entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z);
}
m_Position.x = new_x;
m_Position.y = new_y;
m_Position.z = new_z;
if (calculate_heading) {
m_Position.w = CalculateHeadingToTarget(x, y);
}
tar_ndx = 20 - numsteps;
}
else {
if (IsNPC()) {
entity_list.ProcessMove(CastToNPC(), x, y, z);
}
m_Position.x = x;
m_Position.y = y;
m_Position.z = z;
}
}
else {
tar_vector /= 13.5f;
float dur = Timer::GetCurrentTime() - pLastChange;
if (dur < 0.0f) {
dur = 0.0f;
}
if (dur > 100.f) {
dur = 100.f;
}
tar_vector *= (dur / 100.0f);
float new_x = m_Position.x + m_TargetV.x * tar_vector;
float new_y = m_Position.y + m_TargetV.y * tar_vector;
float new_z = m_Position.z + m_TargetV.z * tar_vector;
if (IsNPC()) {
entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z);
}
m_Position.x = new_x;
m_Position.y = new_y;
m_Position.z = new_z;
if (calculate_heading) {
m_Position.w = CalculateHeadingToTarget(x, y);
}
}
if (check_z && fix_z_timer.Check() && !this->IsEngaged())
this->FixZ();
SetMoving(true);
moved = true;
m_Delta = glm::vec4(m_Position.x - nx, m_Position.y - ny, m_Position.z - nz, 0.0f);
if (IsClient()) {
SendPositionUpdate(1);
CastToClient()->ResetPositionTimer();
}
else {
SendPositionUpdate();
SetAppearance(eaStanding, false);
}
pLastChange = Timer::GetCurrentTime();
return true;
void Mob::WalkTo(float x, float y, float z)
{
mMovementManager->NavigateTo(this, x, y, z, MovementWalking);
}
bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool check_z, bool calculate_heading) {
return MakeNewPositionAndSendUpdate(x, y, z, speed, check_z);
void Mob::RunTo(float x, float y, float z)
{
mMovementManager->NavigateTo(this, x, y, z, MovementRunning);
}
void Mob::NavigateTo(float x, float y, float z)
{
if (IsRunning()) {
RunTo(x, y, z);
}
else {
WalkTo(x, y, z);
}
}
void Mob::RotateTo(float new_heading)
{
if (IsRunning()) {
RotateToRunning(new_heading);
}
else {
RotateToWalking(new_heading);
}
}
void Mob::RotateToWalking(float new_heading)
{
mMovementManager->RotateTo(this, new_heading, MovementWalking);
}
void Mob::RotateToRunning(float new_heading)
{
mMovementManager->RotateTo(this, new_heading, MovementRunning);
}
void Mob::StopNavigation() {
mMovementManager->StopNavigation(this);
}
void NPC::AssignWaypoints(int32 grid)
@@ -683,9 +537,6 @@ void NPC::AssignWaypoints(int32 grid)
if (wandertype == 1 || wandertype == 2 || wandertype == 5)
CalculateNewWaypoint();
if (wandertype == 1 || wandertype == 2 || wandertype == 5)
CalculateNewWaypoint();
}
void Mob::SendTo(float new_x, float new_y, float new_z) {
@@ -698,7 +549,7 @@ void Mob::SendTo(float new_x, float new_y, float new_z) {
m_Position.z = new_z;
Log(Logs::Detail, Logs::AI, "Sent To (%.3f, %.3f, %.3f)", new_x, new_y, new_z);
if (flymode == FlyMode1)
if (flymode == GravityBehavior::Flying)
return;
//fix up pathing Z, this shouldent be needed IF our waypoints
@@ -748,21 +599,18 @@ void Mob::SendToFixZ(float new_x, float new_y, float new_z) {
}
}
float Mob::GetFixedZ(glm::vec3 destination, int32 z_find_offset) {
float Mob::GetFixedZ(const glm::vec3 &destination, int32 z_find_offset) {
BenchTimer timer;
timer.reset();
float new_z = destination.z;
if (zone->HasMap() && RuleB(Map, FixZWhenMoving)) {
if (zone->HasMap()) {
if (flymode == 1 || flymode == 2)
if (flymode == GravityBehavior::Flying)
return new_z;
if (this->IsBoat())
return new_z;
if (zone->HasWaterMap() && zone->watermap->InWater(glm::vec3(m_Position)))
if (zone->HasWaterMap() && zone->watermap->InLiquid(glm::vec3(m_Position)))
return new_z;
/*
@@ -794,11 +642,19 @@ float Mob::GetFixedZ(glm::vec3 destination, int32 z_find_offset) {
}
void Mob::FixZ(int32 z_find_offset /*= 5*/, bool fix_client_z /*= false*/) {
glm::vec3 current_loc(m_Position);
if (IsClient() && !fix_client_z)
if (IsClient() && !fix_client_z) {
return;
}
if (flymode == GravityBehavior::Flying) {
return;
}
if (zone->watermap && zone->watermap->InLiquid(m_Position)) {
return;
}
glm::vec3 current_loc(m_Position);
float new_z = GetFixedZ(current_loc, z_find_offset);
if (new_z == m_Position.z)
@@ -958,8 +814,6 @@ void Mob::TryMoveAlong(float distance, float angle, bool send)
new_pos.z = GetFixedZ(new_pos);
Teleport(new_pos);
if (send)
SendPositionUpdate();
}
int ZoneDatabase::GetHighestGrid(uint32 zoneid) {
+1 -1
View File
@@ -1772,7 +1772,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
zone->GetLongName(),
zone->GetInstanceID()
);
RuleManager::Instance()->LoadRules(&database, RuleManager::Instance()->GetActiveRuleset());
RuleManager::Instance()->LoadRules(&database, RuleManager::Instance()->GetActiveRuleset(), true);
break;
}
case ServerOP_ReloadLogs: {
+17 -9
View File
@@ -53,6 +53,8 @@
#include "worldserver.h"
#include "zone.h"
#include "zone_config.h"
#include "mob_movement_manager.h"
#include "npc_scale_manager.h"
#include <time.h>
#include <ctime>
@@ -64,8 +66,6 @@
#define strcasecmp _stricmp
#endif
extern bool staticzone;
extern NetConnection net;
extern PetitionList petition_list;
@@ -73,6 +73,7 @@ extern QuestParserCollection* parse;
extern uint32 numclients;
extern WorldServer worldserver;
extern Zone* zone;
extern NpcScaleManager* npc_scale_manager;
Mutex MZoneShutdown;
@@ -861,6 +862,8 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
m_ucss_available = false;
m_last_ucss_update = 0;
mMovementManager = &MobMovementManager::Get();
}
Zone::~Zone() {
@@ -901,7 +904,7 @@ bool Zone::Init(bool iStaticZone) {
std::string r_name = RuleManager::Instance()->GetRulesetName(&database, default_ruleset);
if(r_name.size() > 0)
{
RuleManager::Instance()->LoadRules(&database, r_name.c_str());
RuleManager::Instance()->LoadRules(&database, r_name.c_str(), false);
}
}
@@ -1296,6 +1299,8 @@ bool Zone::Process() {
if(hotzone_timer.Check()) { UpdateHotzone(); }
mMovementManager->Process();
return true;
}
@@ -1504,18 +1509,22 @@ void Zone::RepopClose(const glm::vec4& client_position, uint32 repop_distance)
mod_repop();
}
void Zone::Repop(uint32 delay) {
void Zone::Repop(uint32 delay)
{
if(!Depop())
if (!Depop()) {
return;
}
LinkedListIterator<Spawn2*> iterator(spawn2_list);
LinkedListIterator<Spawn2 *> iterator(spawn2_list);
iterator.Reset();
while (iterator.MoreElements()) {
iterator.RemoveCurrent();
}
npc_scale_manager->LoadScaleData();
entity_list.ClearTrapPointers();
quest_manager.ClearAllTimers();
@@ -1632,8 +1641,7 @@ ZonePoint* Zone::GetClosestZonePoint(const glm::vec3& location, uint32 to, Clien
// 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)
client->CheatDetected(MQZoneUnknownDest, location.x, location.y, location.z); // Someone is trying to use /zone
//TODO cheat detection
Log(Logs::General, Logs::Status, "WARNING: Closest zone point for zone id %d is %f, you might need to update your zone_points table if you dont arrive at the right spot.", to, closest_dist);
Log(Logs::General, Logs::Status, "<Real Zone Points>. %s", to_string(location).c_str());
}
@@ -2242,7 +2250,7 @@ void Zone::DoAdventureActions()
const NPCType* tmp = database.LoadNPCTypesData(ds->data_id);
if(tmp)
{
NPC* npc = new NPC(tmp, nullptr, glm::vec4(ds->assa_x, ds->assa_y, ds->assa_z, ds->assa_h), FlyMode3);
NPC* npc = new NPC(tmp, nullptr, glm::vec4(ds->assa_x, ds->assa_y, ds->assa_z, ds->assa_h), GravityBehavior::Water);
npc->AddLootTable();
if (npc->DropsGlobalLoot())
npc->CheckGlobalLootTables();
+3
View File
@@ -79,6 +79,7 @@ class WaterMap;
extern EntityList entity_list;
struct NPCType;
struct ServerZoneIncomingClient_Struct;
class MobMovementManager;
class Zone
{
@@ -362,6 +363,8 @@ private:
bool m_ucss_available;
uint32 m_last_ucss_update;
MobMovementManager *mMovementManager;
};
#endif
+11 -9
View File
@@ -1204,12 +1204,12 @@ bool ZoneDatabase::LoadCharacterMemmedSpells(uint32 character_id, PlayerProfile_
auto results = database.QueryDatabase(query);
int i = 0;
/* Initialize Spells */
for (i = 0; i < MAX_PP_MEMSPELL; i++){
for (i = 0; i < EQEmu::spells::SPELL_GEM_COUNT; i++){
pp->mem_spells[i] = 0xFFFFFFFF;
}
for (auto row = results.begin(); row != results.end(); ++row) {
i = atoi(row[0]);
if (i < MAX_PP_MEMSPELL && atoi(row[1]) <= SPDAT_RECORDS){
if (i < EQEmu::spells::SPELL_GEM_COUNT && atoi(row[1]) <= SPDAT_RECORDS){
pp->mem_spells[i] = atoi(row[1]);
}
}
@@ -1227,12 +1227,12 @@ bool ZoneDatabase::LoadCharacterSpellBook(uint32 character_id, PlayerProfile_Str
auto results = database.QueryDatabase(query);
int i = 0;
/* Initialize Spells */
for (i = 0; i < MAX_PP_SPELLBOOK; i++){
for (i = 0; i < EQEmu::spells::SPELLBOOK_SIZE; i++){
pp->spell_book[i] = 0xFFFFFFFF;
}
for (auto row = results.begin(); row != results.end(); ++row) {
i = atoi(row[0]);
if (i < MAX_PP_SPELLBOOK && atoi(row[1]) <= SPDAT_RECORDS){
if (i < EQEmu::spells::SPELLBOOK_SIZE && atoi(row[1]) <= SPDAT_RECORDS){
pp->spell_book[i] = atoi(row[1]);
}
}
@@ -1535,7 +1535,7 @@ bool ZoneDatabase::SaveCharacterTribute(uint32 character_id, PlayerProfile_Struc
QueryDatabase(query);
/* Save Tributes only if we have values... */
for (int i = 0; i < EQEmu::invtype::TRIBUTE_SIZE; i++){
if (pp->tributes[i].tribute > 0 && pp->tributes[i].tribute != TRIBUTE_NONE){
if (pp->tributes[i].tribute >= 0 && pp->tributes[i].tribute != TRIBUTE_NONE){
std::string query = StringFormat("REPLACE INTO `character_tribute` (id, tier, tribute) VALUES (%u, %u, %u)", character_id, pp->tributes[i].tier, pp->tributes[i].tribute);
QueryDatabase(query);
Log(Logs::General, Logs::None, "ZoneDatabase::SaveCharacterTribute for character ID: %i, tier:%u tribute:%u done", character_id, pp->tributes[i].tier, pp->tributes[i].tribute);
@@ -2471,7 +2471,8 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
"npc_types.charm_avoidance_rating, "
"npc_types.charm_atk, "
"npc_types.skip_global_loot, "
"npc_types.rare_spawn "
"npc_types.rare_spawn, "
"npc_types.stuck_behavior "
"FROM npc_types %s",
where_condition.c_str()
);
@@ -2494,7 +2495,7 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
temp_npctype_data->race = atoi(row[3]);
temp_npctype_data->class_ = atoi(row[4]);
temp_npctype_data->max_hp = atoi(row[5]);
temp_npctype_data->cur_hp = temp_npctype_data->max_hp;
temp_npctype_data->current_hp = temp_npctype_data->max_hp;
temp_npctype_data->Mana = atoi(row[6]);
temp_npctype_data->gender = atoi(row[7]);
temp_npctype_data->texture = atoi(row[8]);
@@ -2660,6 +2661,7 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
temp_npctype_data->skip_global_loot = atoi(row[107]) != 0;
temp_npctype_data->rare_spawn = atoi(row[108]) != 0;
temp_npctype_data->stuck_behavior = atoi(row[109]);
// If NPC with duplicate NPC id already in table,
// free item we attempted to add.
@@ -2775,7 +2777,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
tmpNPCType->race = atoi(row[3]);
tmpNPCType->class_ = atoi(row[4]);
tmpNPCType->max_hp = atoi(row[5]);
tmpNPCType->cur_hp = tmpNPCType->max_hp;
tmpNPCType->current_hp = tmpNPCType->max_hp;
tmpNPCType->Mana = atoi(row[6]);
tmpNPCType->gender = atoi(row[7]);
tmpNPCType->texture = atoi(row[8]);
@@ -3644,7 +3646,7 @@ void ZoneDatabase::LoadBuffs(Client *client)
}
// We load up to the most our client supports
max_slots = EQEmu::constants::Lookup(client->ClientVersion())->LongBuffs;
max_slots = EQEmu::spells::StaticLookup(client->ClientVersion())->LongBuffs;
for (int index = 0; index < max_slots; ++index) {
if (!IsValidSpell(buffs[index].spellid))
continue;
+41 -39
View File
@@ -271,7 +271,12 @@ public:
void DeleteBuyLines(uint32 CharID);
void UpdateBuyLine(uint32 CharID, uint32 BuySlot, uint32 Quantity);
/* General Character Related Stuff */
/**
************************************************
* Character
************************************************
*/
bool SetServerFilters(char* name, ServerSideFilters_Struct *ssfs);
uint32 GetServerFilters(char* name, ServerSideFilters_Struct *ssfs);
@@ -284,46 +289,43 @@ public:
void RemoveTempFactions(Client *c);
void UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type, uint32 timestamp);
/* Character Data Loaders */
bool LoadCharacterFactionValues(uint32 character_id, faction_map & val_list);
bool LoadCharacterSpellBook(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterMemmedSpells(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterLanguages(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterDisciplines(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterSkills(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterData(uint32 character_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp);
bool LoadCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterMaterialColor(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterLeadershipAA(uint32 character_id, PlayerProfile_Struct* pp);
bool DeleteCharacterAAs(uint32 character_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterDye(uint32 character_id);
bool DeleteCharacterLeadershipAAs(uint32 character_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
/* Character Data Saves */
bool SaveCharacterBindPoint(uint32 character_id, const BindStruct &bind, uint32 bind_num);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level, uint32 charges);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
bool SaveCharacterLeadershipAA(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterData(uint32 character_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp);
bool LoadCharacterDisciplines(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterFactionValues(uint32 character_id, faction_map & val_list);
bool LoadCharacterLanguages(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterLeadershipAA(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterMaterialColor(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterMemmedSpells(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterSkills(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterSpellBook(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
/* Character Data Deletes */
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
bool DeleteCharacterLeadershipAAs(uint32 character_id);
bool DeleteCharacterAAs(uint32 character_id);
bool DeleteCharacterDye(uint32 character_id);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level, uint32 charges);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterBindPoint(uint32 character_id, const BindStruct &bind, uint32 bind_num);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterLeadershipAA(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
/* Character Inventory */
bool NoRentExpired(const char* name);
+2 -1
View File
@@ -36,7 +36,7 @@ struct NPCType
{
char name[64];
char lastname[70];
int32 cur_hp;
int32 current_hp;
int32 max_hp;
float size;
float runspeed;
@@ -143,6 +143,7 @@ struct NPCType
bool untargetable;
bool skip_global_loot;
bool rare_spawn;
int8 stuck_behavior;
};
namespace player_lootitem {
+5 -10
View File
@@ -95,7 +95,7 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
//unable to find a zone point... is there anything else
//that can be a valid un-zolicited zone request?
CheatDetected(MQZone, zc->x, zc->y, zc->z);
//Todo cheat detection
Message(13, "Invalid unsolicited zone request.");
Log(Logs::General, Logs::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%d'.", GetName(), target_zone_id);
SendZoneCancel(zc);
@@ -130,7 +130,7 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
//then we assume this is invalid.
if(!zone_point || zone_point->target_zone_id != target_zone_id) {
Log(Logs::General, Logs::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%d'.", GetName(), target_zone_id);
CheatDetected(MQGate, zc->x, zc->y, zc->z);
//todo cheat detection
SendZoneCancel(zc);
return;
}
@@ -252,7 +252,7 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
//for now, there are no other cases...
//could not find a valid reason for them to be zoning, stop it.
CheatDetected(MQZoneUnknownDest, 0.0, 0.0, 0.0);
//todo cheat detection
Log(Logs::General, Logs::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%s'. Not near a zone point.", GetName(), target_zone_name);
SendZoneCancel(zc);
return;
@@ -296,7 +296,6 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
void Client::SendZoneCancel(ZoneChange_Struct *zc) {
//effectively zone them right back to where they were
//unless we find a better way to stop the zoning process.
SetPortExemption(true);
EQApplicationPacket *outapp = nullptr;
outapp = new EQApplicationPacket(OP_ZoneChange, sizeof(ZoneChange_Struct));
ZoneChange_Struct *zc2 = (ZoneChange_Struct*)outapp->pBuffer;
@@ -316,8 +315,6 @@ void Client::SendZoneError(ZoneChange_Struct *zc, int8 err)
{
Log(Logs::General, Logs::Error, "Zone %i is not available because target wasn't found or character insufficent level", zc->zoneID);
SetPortExemption(true);
EQApplicationPacket *outapp = nullptr;
outapp = new EQApplicationPacket(OP_ZoneChange, sizeof(ZoneChange_Struct));
ZoneChange_Struct *zc2 = (ZoneChange_Struct*)outapp->pBuffer;
@@ -488,8 +485,6 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z
pShortZoneName = database.GetZoneName(zoneID);
database.GetZoneLongName(pShortZoneName, &pZoneName);
SetPortExemption(true);
if(!pZoneName) {
Message(13, "Invalid zone number specified");
safe_delete_array(pZoneName);
@@ -593,7 +588,7 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z
// If we are SoF and later and are respawning from hover, we want the real zone ID, else zero to use the old hack.
//
if(zone->GetZoneID() == zoneID) {
if ((ClientVersionBit() & EQEmu::versions::bit_SoFAndLater) && (!RuleB(Character, RespawnFromHover) || !IsHoveringForRespawn()))
if ((ClientVersionBit() & EQEmu::versions::maskSoFAndLater) && (!RuleB(Character, RespawnFromHover) || !IsHoveringForRespawn()))
gmg->bind_zone_id = 0;
else
gmg->bind_zone_id = zoneID;
@@ -669,7 +664,7 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z
m_Proximity = glm::vec3(m_Position);
//send out updates to people in zone.
SendPosition();
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
}
auto outapp =