Fix, cleanup and simplify the roambox logic and cleanup a bunch of other related code

This commit is contained in:
Akkadius 2018-08-18 18:12:18 -05:00
parent 7cc5b143fc
commit 4b6ab34fd9
9 changed files with 479 additions and 396 deletions

View File

@ -90,6 +90,7 @@ enum LogCategory {
FixZ, FixZ,
Food, Food,
Traps, Traps,
NPCRoamBox,
MaxCategoryID /* Don't Remove this*/ MaxCategoryID /* Don't Remove this*/
}; };
@ -144,7 +145,8 @@ static const char* LogCategoryName[LogCategory::MaxCategoryID] = {
"HP Update", "HP Update",
"FixZ", "FixZ",
"Food", "Food",
"Traps" "Traps",
"NPC Roam Box"
}; };
} }

View File

@ -3425,52 +3425,54 @@ void EntityList::ProcessMove(Client *c, const glm::vec3& location)
} }
} }
void EntityList::ProcessMove(NPC *n, float x, float y, float z) void EntityList::ProcessMove(NPC *n, float x, float y, float z) {
{
float last_x = n->GetX(); float last_x = n->GetX();
float last_y = n->GetY(); float last_y = n->GetY();
float last_z = n->GetZ(); float last_z = n->GetZ();
std::list<quest_proximity_event> events; std::list<quest_proximity_event> events;
for (auto iter = area_list.begin(); iter != area_list.end(); ++iter) { for (auto iter = area_list.begin(); iter != area_list.end(); ++iter) {
Area& a = (*iter);
Area &a = (*iter);
bool old_in = true; bool old_in = true;
bool new_in = true; bool new_in = true;
if (last_x < a.min_x || last_x > a.max_x || if (last_x < a.min_x || last_x > a.max_x ||
last_y < a.min_y || last_y > a.max_y || last_y < a.min_y || last_y > a.max_y ||
last_z < a.min_z || last_z > a.max_z) { last_z < a.min_z || last_z > a.max_z) {
old_in = false; old_in = false;
} }
if (x < a.min_x || x > a.max_x || if (x < a.min_x || x > a.max_x ||
y < a.min_y || y > a.max_y || y < a.min_y || y > a.max_y ||
z < a.min_z || z > a.max_z) { z < a.min_z || z > a.max_z) {
new_in = false; new_in = false;
} }
if (old_in && !new_in) { if (old_in && !new_in) {
//were in but are no longer. //were in but are no longer.
quest_proximity_event evt; quest_proximity_event evt;
evt.event_id = EVENT_LEAVE_AREA; evt.event_id = EVENT_LEAVE_AREA;
evt.client = nullptr; evt.client = nullptr;
evt.npc = n; evt.npc = n;
evt.area_id = a.id; evt.area_id = a.id;
evt.area_type = a.type; evt.area_type = a.type;
events.push_back(evt); events.push_back(evt);
} else if (!old_in && new_in) { }
else if (!old_in && new_in) {
//were not in but now are //were not in but now are
quest_proximity_event evt; quest_proximity_event evt;
evt.event_id = EVENT_ENTER_AREA; evt.event_id = EVENT_ENTER_AREA;
evt.client = nullptr; evt.client = nullptr;
evt.npc = n; evt.npc = n;
evt.area_id = a.id; evt.area_id = a.id;
evt.area_type = a.type; evt.area_type = a.type;
events.push_back(evt); events.push_back(evt);
} }
} }
for (auto iter = events.begin(); iter != events.end(); ++iter) { for (auto iter = events.begin(); iter != events.end(); ++iter) {
quest_proximity_event& evt = (*iter); quest_proximity_event &evt = (*iter);
std::vector<EQEmu::Any> args; std::vector<EQEmu::Any> args;
args.push_back(&evt.area_id); args.push_back(&evt.area_id);
args.push_back(&evt.area_type); args.push_back(&evt.area_type);

View File

@ -1481,8 +1481,14 @@ void Merc::AI_Process() {
if (RuleB(Mercs, MercsUsePathing) && zone->pathing) { if (RuleB(Mercs, MercsUsePathing) && zone->pathing) {
bool WaypointChanged, NodeReached; bool WaypointChanged, NodeReached;
glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), glm::vec3 Goal = UpdatePath(
GetRunspeed(), WaypointChanged, NodeReached); GetTarget()->GetX(),
GetTarget()->GetY(),
GetTarget()->GetZ(),
GetRunspeed(),
WaypointChanged,
NodeReached
);
if (WaypointChanged) if (WaypointChanged)
tar_ndx = 20; tar_ndx = 20;
@ -1588,7 +1594,7 @@ void Merc::AI_Process() {
} }
} }
if(IsMoving()) if (IsMoving())
SendPositionUpdate(); SendPositionUpdate();
else else
SendPosition(); SendPosition();

View File

@ -981,7 +981,7 @@ public:
inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);} inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);}
float CalculateHeadingToTarget(float in_x, float in_y) { return HeadingAngleToMob(in_x, in_y); } float CalculateHeadingToTarget(float in_x, float in_y) { return HeadingAngleToMob(in_x, in_y); }
virtual bool CalculateNewPosition(float x, float y, float z, int speed, bool checkZ = true, bool calcheading = true); virtual bool CalculateNewPosition(float x, float y, float z, float speed, bool check_z = true, bool calculate_heading = true);
float CalculateDistance(float x, float y, float z); float CalculateDistance(float x, float y, float z);
float GetGroundZ(float new_x, float new_y, float z_offset=0.0); float GetGroundZ(float new_x, float new_y, float z_offset=0.0);
void SendTo(float new_x, float new_y, float new_z); void SendTo(float new_x, float new_y, float new_z);
@ -989,7 +989,7 @@ public:
float GetZOffset() const; float GetZOffset() const;
float GetDefaultRaceSize() const; float GetDefaultRaceSize() const;
void FixZ(int32 z_find_offset = 5); void FixZ(int32 z_find_offset = 5);
float GetFixedZ(glm::vec3 position, int32 z_find_offset = 5); float GetFixedZ(glm::vec3 destination, int32 z_find_offset = 5);
void NPCSpecialAttacks(const char* parse, int permtag, bool reset = true, bool remove = false); void NPCSpecialAttacks(const char* parse, int permtag, bool reset = true, bool remove = false);
inline uint32 DontHealMeBefore() const { return pDontHealMeBefore; } inline uint32 DontHealMeBefore() const { return pDontHealMeBefore; }
@ -1165,7 +1165,7 @@ protected:
int _GetWalkSpeed() const; int _GetWalkSpeed() const;
int _GetRunSpeed() const; int _GetRunSpeed() const;
int _GetFearSpeed() const; int _GetFearSpeed() const;
virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, bool checkZ = true, bool calcHeading = true); 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_EngagedCastCheck() { return(false); }
virtual bool AI_PursueCastCheck() { return(false); } virtual bool AI_PursueCastCheck() { return(false); }
@ -1443,7 +1443,7 @@ protected:
std::unique_ptr<Timer> AI_feign_remember_timer; std::unique_ptr<Timer> AI_feign_remember_timer;
std::unique_ptr<Timer> AI_check_signal_timer; std::unique_ptr<Timer> AI_check_signal_timer;
std::unique_ptr<Timer> AI_scan_door_open_timer; std::unique_ptr<Timer> AI_scan_door_open_timer;
uint32 pLastFightingDelayMoving; uint32 time_until_can_move;
HateList hate_list; HateList hate_list;
std::set<uint32> feign_memory_list; std::set<uint32> feign_memory_list;
// This is to keep track of mobs we cast faction mod spells on // This is to keep track of mobs we cast faction mod spells on

View File

@ -30,6 +30,7 @@
#include "string_ids.h" #include "string_ids.h"
#include "water_map.h" #include "water_map.h"
#include "fastmath.h" #include "fastmath.h"
#include "../common/data_verification.h"
#include <glm/gtx/projection.hpp> #include <glm/gtx/projection.hpp>
#include <algorithm> #include <algorithm>
@ -459,8 +460,8 @@ void NPC::AI_Init()
roambox_min_x = 0; roambox_min_x = 0;
roambox_min_y = 0; roambox_min_y = 0;
roambox_distance = 0; roambox_distance = 0;
roambox_movingto_x = 0; roambox_destination_x = 0;
roambox_movingto_y = 0; roambox_destination_y = 0;
roambox_min_delay = 2500; roambox_min_delay = 2500;
roambox_delay = 2500; roambox_delay = 2500;
} }
@ -476,9 +477,9 @@ void Mob::AI_Start(uint32 iMoveDelay) {
return; return;
if (iMoveDelay) if (iMoveDelay)
pLastFightingDelayMoving = Timer::GetCurrentTime() + iMoveDelay; time_until_can_move = Timer::GetCurrentTime() + iMoveDelay;
else else
pLastFightingDelayMoving = 0; time_until_can_move = 0;
pAIControlled = true; pAIControlled = true;
AI_think_timer = std::unique_ptr<Timer>(new Timer(AIthink_duration)); AI_think_timer = std::unique_ptr<Timer>(new Timer(AIthink_duration));
@ -1053,7 +1054,7 @@ void Mob::AI_Process() {
if (IsCasting()) if (IsCasting())
return; return;
bool engaged = IsEngaged(); bool engaged = IsEngaged();
bool doranged = false; bool doranged = false;
if (!zone->CanDoCombat() || IsPetStop() || IsPetRegroup()) { if (!zone->CanDoCombat() || IsPetStop() || IsPetRegroup()) {
@ -1063,7 +1064,7 @@ void Mob::AI_Process() {
if (moving) { if (moving) {
if (AI_scan_door_open_timer->Check()) { if (AI_scan_door_open_timer->Check()) {
auto &door_list = entity_list.GetDoorsList(); auto &door_list = entity_list.GetDoorsList();
for (auto itr : door_list) { for (auto itr : door_list) {
Doors *door = itr.second; Doors *door = itr.second;
@ -1096,39 +1097,46 @@ void Mob::AI_Process() {
// Begin: Additions for Wiz Fear Code // Begin: Additions for Wiz Fear Code
// //
if(RuleB(Combat, EnableFearPathing)){ if (RuleB(Combat, EnableFearPathing)) {
if(currently_fleeing) { if (currently_fleeing) {
if((IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) && !IsPetStop() && !IsPetRegroup()) { if ((IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) && !IsPetStop() &&
!IsPetRegroup()) {
//make sure everybody knows were not moving, for appearance sake //make sure everybody knows were not moving, for appearance sake
if(IsMoving()) if (IsMoving()) {
{ if (target)
if(target)
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY())); SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY()));
SetCurrentSpeed(0); SetCurrentSpeed(0);
moved=false; moved = false;
} }
//continue on to attack code, ensuring that we execute the engaged code //continue on to attack code, ensuring that we execute the engaged code
engaged = true; engaged = true;
} else { }
if(AI_movement_timer->Check()) { else {
if (AI_movement_timer->Check()) {
// Check if we have reached the last fear point // Check if we have reached the last fear point
if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) && if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) &&
(std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) { (std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) {
// Calculate a new point to run to // Calculate a new point to run to
CalculateNewFearpoint(); CalculateNewFearpoint();
} }
if(!RuleB(Pathing, Fear) || !zone->pathing) if (!RuleB(Pathing, Fear) || !zone->pathing) {
{ CalculateNewPosition(
CalculateNewPosition(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, GetFearSpeed(), true); m_FearWalkTarget.x,
m_FearWalkTarget.y,
m_FearWalkTarget.z,
GetFearSpeed(),
true
);
} }
else else {
{
bool WaypointChanged, NodeReached; bool WaypointChanged, NodeReached;
glm::vec3 Goal = UpdatePath(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, glm::vec3 Goal = UpdatePath(
GetFearSpeed(), WaypointChanged, NodeReached); m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z,
GetFearSpeed(), WaypointChanged, NodeReached
);
if(WaypointChanged) if (WaypointChanged)
tar_ndx = 20; tar_ndx = 20;
CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetFearSpeed()); CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetFearSpeed());
@ -1154,7 +1162,7 @@ void Mob::AI_Process() {
this->FixZ(); this->FixZ();
if (target_distance <= 15 && !this->CheckLosFN(this->GetTarget())) { if (target_distance <= 15 && !this->CheckLosFN(this->GetTarget())) {
Mob* target = this->GetTarget(); Mob *target = this->GetTarget();
m_Position.x = target->GetX(); m_Position.x = target->GetX();
m_Position.y = target->GetY(); m_Position.y = target->GetY();
@ -1183,10 +1191,8 @@ void Mob::AI_Process() {
// from above, so no extra blind checks needed // from above, so no extra blind checks needed
if ((IsRooted() && !GetSpecialAbility(IGNORE_ROOT_AGGRO_RULES)) || IsBlind()) if ((IsRooted() && !GetSpecialAbility(IGNORE_ROOT_AGGRO_RULES)) || IsBlind())
SetTarget(hate_list.GetClosestEntOnHateList(this)); SetTarget(hate_list.GetClosestEntOnHateList(this));
else else {
{ if (AI_target_check_timer->Check()) {
if (AI_target_check_timer->Check())
{
if (IsFocused()) { if (IsFocused()) {
if (!target) { if (!target) {
SetTarget(hate_list.GetEntWithMostHateOnList(this)); SetTarget(hate_list.GetEntWithMostHateOnList(this));
@ -1248,21 +1254,16 @@ void Mob::AI_Process() {
bool is_combat_range = CombatRange(target); bool is_combat_range = CombatRange(target);
if (is_combat_range) if (is_combat_range) {
{ if (AI_movement_timer->Check()) {
if (AI_movement_timer->Check()) if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) {
{
if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w)
{
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SendPosition(); SendPosition();
} }
SetCurrentSpeed(0); SetCurrentSpeed(0);
} }
if (IsMoving()) if (IsMoving()) {
{ if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) {
if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w)
{
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SendPosition(); SendPosition();
} }
@ -1287,7 +1288,7 @@ void Mob::AI_Process() {
if (zone->random.Roll(flurry_chance)) { if (zone->random.Roll(flurry_chance)) {
ExtraAttackOptions opts; ExtraAttackOptions opts;
int cur = GetSpecialAbilityParam(SPECATK_FLURRY, 2); int cur = GetSpecialAbilityParam(SPECATK_FLURRY, 2);
if (cur > 0) if (cur > 0)
opts.damage_percent = cur / 100.0f; opts.damage_percent = cur / 100.0f;
@ -1322,7 +1323,7 @@ void Mob::AI_Process() {
if (owner) { if (owner) {
int16 flurry_chance = owner->aabonuses.PetFlurry + int16 flurry_chance = owner->aabonuses.PetFlurry +
owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry; owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry;
if (flurry_chance && zone->random.Roll(flurry_chance)) if (flurry_chance && zone->random.Roll(flurry_chance))
Flurry(nullptr); Flurry(nullptr);
@ -1330,21 +1331,22 @@ void Mob::AI_Process() {
} }
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()) { if ((IsPet() || IsTempPet()) && IsPetOwnerClient()) {
if (spellbonuses.PC_Pet_Rampage[0] || itembonuses.PC_Pet_Rampage[0] || aabonuses.PC_Pet_Rampage[0]) { if (spellbonuses.PC_Pet_Rampage[0] || itembonuses.PC_Pet_Rampage[0] ||
int chance = spellbonuses.PC_Pet_Rampage[0] + itembonuses.PC_Pet_Rampage[0] + aabonuses.PC_Pet_Rampage[0]; aabonuses.PC_Pet_Rampage[0]) {
int chance = spellbonuses.PC_Pet_Rampage[0] + itembonuses.PC_Pet_Rampage[0] +
aabonuses.PC_Pet_Rampage[0];
if (zone->random.Roll(chance)) { if (zone->random.Roll(chance)) {
Rampage(nullptr); Rampage(nullptr);
} }
} }
} }
if (GetSpecialAbility(SPECATK_RAMPAGE) && !specialed) if (GetSpecialAbility(SPECATK_RAMPAGE) && !specialed) {
{
int rampage_chance = GetSpecialAbilityParam(SPECATK_RAMPAGE, 0); int rampage_chance = GetSpecialAbilityParam(SPECATK_RAMPAGE, 0);
rampage_chance = rampage_chance > 0 ? rampage_chance : 20; rampage_chance = rampage_chance > 0 ? rampage_chance : 20;
if (zone->random.Roll(rampage_chance)) { if (zone->random.Roll(rampage_chance)) {
ExtraAttackOptions opts; ExtraAttackOptions opts;
int cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 3); int cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 3);
if (cur > 0) { if (cur > 0) {
opts.damage_flat = cur; opts.damage_flat = cur;
} }
@ -1373,13 +1375,12 @@ void Mob::AI_Process() {
} }
} }
if (GetSpecialAbility(SPECATK_AREA_RAMPAGE) && !specialed) if (GetSpecialAbility(SPECATK_AREA_RAMPAGE) && !specialed) {
{
int rampage_chance = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 0); int rampage_chance = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 0);
rampage_chance = rampage_chance > 0 ? rampage_chance : 20; rampage_chance = rampage_chance > 0 ? rampage_chance : 20;
if (zone->random.Roll(rampage_chance)) { if (zone->random.Roll(rampage_chance)) {
ExtraAttackOptions opts; ExtraAttackOptions opts;
int cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 3); int cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 3);
if (cur > 0) { if (cur > 0) {
opts.damage_flat = cur; opts.damage_flat = cur;
} }
@ -1421,7 +1422,7 @@ void Mob::AI_Process() {
} }
AI_EngagedCastCheck(); AI_EngagedCastCheck();
} //end is within combat rangepet } //end is within combat rangepet
else { else {
//we cannot reach our target... //we cannot reach our target...
//underwater stuff only works with water maps in the zone! //underwater stuff only works with water maps in the zone!
@ -1434,7 +1435,7 @@ void Mob::AI_Process() {
Heal(); Heal();
BuffFadeAll(); BuffFadeAll();
AI_walking_timer->Start(100); AI_walking_timer->Start(100);
pLastFightingDelayMoving = Timer::GetCurrentTime(); time_until_can_move = Timer::GetCurrentTime();
return; return;
} }
else if (tar != nullptr) { else if (tar != nullptr) {
@ -1445,8 +1446,7 @@ void Mob::AI_Process() {
} }
// See if we can summon the mob to us // See if we can summon the mob to us
if (!HateSummon()) if (!HateSummon()) {
{
//could not summon them, check ranged... //could not summon them, check ranged...
if (GetSpecialAbility(SPECATK_RANGED_ATK)) if (GetSpecialAbility(SPECATK_RANGED_ATK))
doranged = true; doranged = true;
@ -1456,18 +1456,18 @@ void Mob::AI_Process() {
if (AI_PursueCastCheck()) { if (AI_PursueCastCheck()) {
//we did something, so do not process movement. //we did something, so do not process movement.
} }
else if (AI_movement_timer->Check() && target) else if (AI_movement_timer->Check() && target) {
{
if (!IsRooted()) { if (!IsRooted()) {
Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", target->GetName()); Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", target->GetName());
if (!RuleB(Pathing, Aggro) || !zone->pathing) if (!RuleB(Pathing, Aggro) || !zone->pathing)
CalculateNewPosition(target->GetX(), target->GetY(), target->GetZ(), GetRunspeed()); CalculateNewPosition(target->GetX(), target->GetY(), target->GetZ(), GetRunspeed());
else else {
{
bool WaypointChanged, NodeReached; bool WaypointChanged, NodeReached;
glm::vec3 Goal = UpdatePath(target->GetX(), target->GetY(), target->GetZ(), glm::vec3 Goal = UpdatePath(
GetRunspeed(), WaypointChanged, NodeReached); target->GetX(), target->GetY(), target->GetZ(),
GetRunspeed(), WaypointChanged, NodeReached
);
if (WaypointChanged) if (WaypointChanged)
tar_ndx = 20; tar_ndx = 20;
@ -1492,69 +1492,64 @@ void Mob::AI_Process() {
if (IsPetStop()) // pet stop won't be engaged, so we will always get here and we want the above branch to execute if (IsPetStop()) // pet stop won't be engaged, so we will always get here and we want the above branch to execute
return; return;
if(zone->CanDoCombat() && AI_feign_remember_timer->Check()) { if (zone->CanDoCombat() && AI_feign_remember_timer->Check()) {
// 6/14/06 // 6/14/06
// Improved Feign Death Memory // Improved Feign Death Memory
// check to see if any of our previous feigned targets have gotten up. // check to see if any of our previous feigned targets have gotten up.
std::set<uint32>::iterator RememberedCharID; std::set<uint32>::iterator RememberedCharID;
RememberedCharID = feign_memory_list.begin(); RememberedCharID = feign_memory_list.begin();
while (RememberedCharID != feign_memory_list.end()) { while (RememberedCharID != feign_memory_list.end()) {
Client* remember_client = entity_list.GetClientByCharID(*RememberedCharID); Client *remember_client = entity_list.GetClientByCharID(*RememberedCharID);
if (remember_client == nullptr) { if (remember_client == nullptr) {
//they are gone now... //they are gone now...
RememberedCharID = feign_memory_list.erase(RememberedCharID); RememberedCharID = feign_memory_list.erase(RememberedCharID);
} else if (!remember_client->GetFeigned()) { }
AddToHateList(remember_client->CastToMob(),1); else if (!remember_client->GetFeigned()) {
AddToHateList(remember_client->CastToMob(), 1);
RememberedCharID = feign_memory_list.erase(RememberedCharID); RememberedCharID = feign_memory_list.erase(RememberedCharID);
break; break;
} else { }
else {
//they are still feigned, carry on... //they are still feigned, carry on...
++RememberedCharID; ++RememberedCharID;
} }
} }
} }
if (AI_IdleCastCheck()) if (AI_IdleCastCheck()) {
{
//we processed a spell action, so do nothing else. //we processed a spell action, so do nothing else.
} }
else if (zone->CanDoCombat() && CastToNPC()->WillAggroNPCs() && AI_scan_area_timer->Check()) else if (zone->CanDoCombat() && CastToNPC()->WillAggroNPCs() && AI_scan_area_timer->Check()) {
{
/* /*
* NPC to NPC aggro checking, npc needs npc_aggro flag * NPC to NPC aggro checking, npc needs npc_aggro flag
*/ */
Mob *temp_target = entity_list.AICheckNPCtoNPCAggro(this, GetAggroRange(), GetAssistRange());
Mob* temp_target = entity_list.AICheckNPCtoNPCAggro(this, GetAggroRange(), GetAssistRange()); if (temp_target) {
if (temp_target){
AddToHateList(temp_target); AddToHateList(temp_target);
} }
AI_scan_area_timer->Disable(); AI_scan_area_timer->Disable();
AI_scan_area_timer->Start(RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax)), false); AI_scan_area_timer->Start(
RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax)),
false
);
} }
else if (AI_movement_timer->Check() && !IsRooted()) else if (AI_movement_timer->Check() && !IsRooted()) {
{ if (IsPet()) {
if (IsPet())
{
// we're a pet, do as we're told // we're a pet, do as we're told
switch (pStandingPetOrder) switch (pStandingPetOrder) {
{ case SPO_Follow: {
case SPO_Follow:
{
Mob* owner = GetOwner(); Mob *owner = GetOwner();
if(owner == nullptr) if (owner == nullptr)
break; break;
//if(owner->IsClient())
// printf("Pet start pos: (%f, %f, %f)\n", GetX(), GetY(), GetZ());
glm::vec4 ownerPos = owner->GetPosition(); glm::vec4 ownerPos = owner->GetPosition();
float dist = DistanceSquared(m_Position, ownerPos); float dist = DistanceSquared(m_Position, ownerPos);
float distz = ownerPos.z - m_Position.z; float distz = ownerPos.z - m_Position.z;
if (dist >= 400 || distz > 100) if (dist >= 400 || distz > 100) {
{
int speed = GetWalkspeed(); int speed = GetWalkspeed();
if (dist >= 1225) // 35 if (dist >= 1225) // 35
speed = GetRunspeed(); speed = GetRunspeed();
@ -1565,46 +1560,27 @@ void Mob::AI_Process() {
SendPositionUpdate(); SendPositionUpdate();
moved = true; moved = true;
} }
else else {
{ CalculateNewPosition(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
CalculateNewPosition(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
} }
} }
else else {
{ if (moved) {
if(moved)
{
this->FixZ(); this->FixZ();
SetCurrentSpeed(0); SetCurrentSpeed(0);
moved = false; moved = false;
} }
} }
/*
//fix up Z
float zdiff = GetZ() - owner->GetZ();
if(zdiff < 0)
zdiff = 0 - zdiff;
if(zdiff > 2.0f) {
SendTo(GetX(), GetY(), owner->GetZ());
SendPosition();
}
if(owner->IsClient())
printf("Pet pos: (%f, %f, %f)\n", GetX(), GetY(), GetZ());
*/
break; break;
} }
case SPO_Sit: case SPO_Sit: {
{
SetAppearance(eaSitting, false); SetAppearance(eaSitting, false);
break; break;
} }
case SPO_Guard: case SPO_Guard: {
{
//only NPCs can guard stuff. (forced by where the guard movement code is in the AI) //only NPCs can guard stuff. (forced by where the guard movement code is in the AI)
if(IsNPC()) { if (IsNPC()) {
CastToNPC()->NextGuardPosition(); CastToNPC()->NextGuardPosition();
} }
break; break;
@ -1613,25 +1589,23 @@ void Mob::AI_Process() {
if (IsPetRegroup()) if (IsPetRegroup())
return; return;
} }
/* Entity has been assigned another entity to follow */ /* Entity has been assigned another entity to follow */
else if (GetFollowID()) else if (GetFollowID()) {
{ Mob *follow = entity_list.GetMob(GetFollowID());
Mob* follow = entity_list.GetMob(GetFollowID()); if (!follow) { SetFollowID(0); }
if (!follow) SetFollowID(0); else {
else float dist2 = DistanceSquared(m_Position, follow->GetPosition());
{ int followdist = GetFollowDistance();
float dist2 = DistanceSquared(m_Position, follow->GetPosition());
int followdist = GetFollowDistance();
if (dist2 >= followdist) // Default follow distance is 100 if (dist2 >= followdist) // Default follow distance is 100
{ {
int speed = GetWalkspeed(); int speed = GetWalkspeed();
if (dist2 >= followdist + 150) if (dist2 >= followdist + 150) {
speed = GetRunspeed(); speed = GetRunspeed();
}
CalculateNewPosition(follow->GetX(), follow->GetY(), follow->GetZ(), speed); CalculateNewPosition(follow->GetX(), follow->GetY(), follow->GetZ(), speed);
} }
else else {
{
moved = false; moved = false;
SetCurrentSpeed(0); SetCurrentSpeed(0);
} }
@ -1640,20 +1614,21 @@ void Mob::AI_Process() {
else //not a pet, and not following somebody... else //not a pet, and not following somebody...
{ {
// dont move till a bit after you last fought // dont move till a bit after you last fought
if (pLastFightingDelayMoving < Timer::GetCurrentTime()) if (time_until_can_move < Timer::GetCurrentTime()) {
{ if (this->IsClient()) {
if (this->IsClient())
{ /**
// LD timer expired, drop out of world * LD timer expired, drop out of world
if (this->CastToClient()->IsLD()) */
if (this->CastToClient()->IsLD()) {
this->CastToClient()->Disconnect(); this->CastToClient()->Disconnect();
}
return; return;
} }
if(IsNPC()) if (IsNPC()) {
{ if (RuleB(NPC, SmartLastFightingDelayMoving) && !feign_memory_list.empty()) {
if(RuleB(NPC, SmartLastFightingDelayMoving) && !feign_memory_list.empty())
{
minLastFightingDelayMoving = 0; minLastFightingDelayMoving = 0;
maxLastFightingDelayMoving = 0; maxLastFightingDelayMoving = 0;
} }
@ -1661,93 +1636,84 @@ void Mob::AI_Process() {
CastToNPC()->AI_DoMovement(); CastToNPC()->AI_DoMovement();
} }
} }
} }
} // else if (AImovement_timer->Check()) }
} }
//Do Ranged attack here //Do Ranged attack here
if(doranged) if (doranged) {
{
RangedAttack(target); RangedAttack(target);
} }
} }
void NPC::AI_DoMovement() { void NPC::AI_DoMovement() {
float walksp = GetMovespeed();
if(walksp <= 0.0f)
return; //this is idle movement at walk speed, and we are unable to walk right now.
if (roambox_distance > 0) { float move_speed = GetMovespeed();
if (
roambox_movingto_x > roambox_max_x
|| roambox_movingto_x < roambox_min_x
|| roambox_movingto_y > roambox_max_y
|| roambox_movingto_y < roambox_min_y
)
{
float movedist = roambox_distance*roambox_distance;
float movex = zone->random.Real(0, movedist);
float movey = movedist - movex;
movex = sqrtf(movex);
movey = sqrtf(movey);
movex *= zone->random.Int(0, 1) ? 1 : -1;
movey *= zone->random.Int(0, 1) ? 1 : -1;
roambox_movingto_x = GetX() + movex;
roambox_movingto_y = GetY() + movey;
//Try to calculate new coord using distance.
if (roambox_movingto_x > roambox_max_x || roambox_movingto_x < roambox_min_x)
roambox_movingto_x -= movex * 2;
if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y)
roambox_movingto_y -= movey * 2;
//New coord is still invalid, ignore distance and just pick a new random coord.
//If we're here we may have a roambox where one side is shorter than the specified distance. Commons, Wkarana, etc.
if (roambox_movingto_x > roambox_max_x || roambox_movingto_x < roambox_min_x)
roambox_movingto_x = zone->random.Real(roambox_min_x+1,roambox_max_x-1);
if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y)
roambox_movingto_y = zone->random.Real(roambox_min_y+1,roambox_max_y-1);
Log(Logs::Detail, Logs::AI,
"Roam Box: d=%.3f (%.3f->%.3f,%.3f->%.3f): Go To (%.3f,%.3f)",
roambox_distance, roambox_min_x, roambox_max_x, roambox_min_y,
roambox_max_y, roambox_movingto_x, roambox_movingto_y);
}
Log(Logs::Detail, Logs::AI, "Roam Box: d=%.3f (%.3f->%.3f,%.3f->%.3f): Go To (%.3f,%.3f)",
roambox_distance, roambox_min_x, roambox_max_x, roambox_min_y, roambox_max_y, roambox_movingto_x, roambox_movingto_y);
float new_z = this->FindGroundZ(m_Position.x, m_Position.y, 5) + GetZOffset(); if (move_speed <= 0.0f) {
return;
if (!CalculateNewPosition(roambox_movingto_x, roambox_movingto_y, new_z, walksp, true))
{
this->FixZ(); // FixZ on final arrival point.
roambox_movingto_x = roambox_max_x + 1; // force update
pLastFightingDelayMoving = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay);
SetMoving(false);
SendPosition(); // makes mobs stop clientside
}
} }
else if (roamer)
{ /**
if (AI_walking_timer->Check()) * Roambox logic sets precedence
{ */
movetimercompleted=true; if (roambox_distance > 0) {
if (!IsMoving()) {
auto move_x = static_cast<float>(zone->random.Real(-roambox_distance, roambox_distance));
auto move_y = static_cast<float>(zone->random.Real(-roambox_distance, roambox_distance));
roambox_destination_x = EQEmu::Clamp((GetX() + move_x), roambox_min_x, roambox_min_y);
roambox_destination_y = EQEmu::Clamp((GetY() + move_y), roambox_min_y, roambox_max_y);
this->FixZ();
Log(Logs::Detail,
Logs::NPCRoamBox,
"Calculate | NPC: %s distance %.3f | min_x %.3f | max_x %.3f | final_x %.3f | min_y %.3f | max_y %.3f | final_y %.3f",
this->GetCleanName(),
roambox_distance,
roambox_min_x,
roambox_max_x,
roambox_destination_x,
roambox_min_y,
roambox_max_y,
roambox_destination_y);
}
if (!CalculateNewPosition(roambox_destination_x, roambox_destination_y, GetFixedZ(m_Position), move_speed, true)) {
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;
AI_walking_timer->Disable(); AI_walking_timer->Disable();
} }
int32 gridno = CastToNPC()->GetGrid(); int32 gridno = CastToNPC()->GetGrid();
if (gridno > 0 || cur_wp==-2) { if (gridno > 0 || cur_wp == -2) {
if (movetimercompleted==true) { // time to pause at wp is over if (movetimercompleted == true) { // time to pause at wp is over
AI_SetupNextWaypoint(); AI_SetupNextWaypoint();
} // endif (movetimercompleted==true) } // endif (movetimercompleted==true)
else if (!(AI_walking_timer->Enabled())) else if (!(AI_walking_timer->Enabled())) { // currently moving
{ // currently moving
bool doMove = true; bool doMove = true;
if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY()) if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY()) { // are we there yet? then stop
{ // are we there yet? then stop Log(Logs::Detail,
Log(Logs::Detail, Logs::AI, "We have reached waypoint %d (%.3f,%.3f,%.3f) on grid %d", cur_wp, GetX(), GetY(), GetZ(), GetGrid()); Logs::AI,
"We have reached waypoint %d (%.3f,%.3f,%.3f) on grid %d",
cur_wp,
GetX(),
GetY(),
GetZ(),
GetGrid());
SetWaypointPause(); SetWaypointPause();
SetAppearance(eaStanding, false); SetAppearance(eaStanding, false);
SetMoving(false); SetMoving(false);
@ -1773,36 +1739,45 @@ void NPC::AI_DoMovement() {
} }
// wipe feign memory since we reached our first waypoint // wipe feign memory since we reached our first waypoint
if(cur_wp == 1) if (cur_wp == 1)
ClearFeignMemory(); ClearFeignMemory();
} }
if (doMove) if (doMove) { // not at waypoint yet or at 0 pause WP, so keep moving
{ // not at waypoint yet or at 0 pause WP, so keep moving if (!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0))
if(!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0)) CalculateNewPosition(
CalculateNewPosition(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, true); m_CurrentWayPoint.x,
else m_CurrentWayPoint.y,
{ m_CurrentWayPoint.z,
bool WaypointChanged; move_speed,
bool NodeReached; true
glm::vec3 Goal = UpdatePath(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, WaypointChanged, NodeReached); );
if(WaypointChanged) 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; tar_ndx = 20;
if(NodeReached) if (NodeReached)
entity_list.OpenDoorsNear(CastToNPC()); entity_list.OpenDoorsNear(CastToNPC());
CalculateNewPosition(Goal.x, Goal.y, Goal.z, walksp, true); CalculateNewPosition(Goal.x, Goal.y, Goal.z, move_speed, true);
} }
} }
} }
} // endif (gridno > 0) } // endif (gridno > 0)
// handle new quest grid command processing // handle new quest grid command processing
else if (gridno < 0) else if (gridno < 0) { // this mob is under quest control
{ // this mob is under quest control if (movetimercompleted == true) { // time to pause has ended
if (movetimercompleted==true) SetGrid(0 - GetGrid()); // revert to AI control
{ // 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()); Log(Logs::Detail, Logs::Pathing, "Quest pathing is finished. Resuming on grid %d", GetGrid());
SetAppearance(eaStanding, false); SetAppearance(eaStanding, false);
@ -1812,39 +1787,55 @@ void NPC::AI_DoMovement() {
} }
} }
else if (IsGuarding()) else if (IsGuarding()) {
{
bool CP2Moved; bool CP2Moved;
if(!RuleB(Pathing, Guard) || !zone->pathing) if (!RuleB(Pathing, Guard) || !zone->pathing) {
CP2Moved = CalculateNewPosition(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, walksp); CP2Moved = CalculateNewPosition(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, move_speed);
else }
{ else {
if(!((m_Position.x == m_GuardPoint.x) && (m_Position.y == m_GuardPoint.y) && (m_Position.z == m_GuardPoint.z))) if (!((m_Position.x == m_GuardPoint.x) && (m_Position.y == m_GuardPoint.y) &&
{ (m_Position.z == m_GuardPoint.z))) {
bool WaypointChanged, NodeReached; bool WaypointChanged, NodeReached;
glm::vec3 Goal = UpdatePath(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, walksp, WaypointChanged, NodeReached);
if(WaypointChanged) glm::vec3 Goal = UpdatePath(
m_GuardPoint.x,
m_GuardPoint.y,
m_GuardPoint.z,
move_speed,
WaypointChanged,
NodeReached
);
if (WaypointChanged) {
tar_ndx = 20; tar_ndx = 20;
}
if(NodeReached) if (NodeReached) {
entity_list.OpenDoorsNear(CastToNPC()); entity_list.OpenDoorsNear(CastToNPC());
}
CP2Moved = CalculateNewPosition(Goal.x, Goal.y, Goal.z, walksp); CP2Moved = CalculateNewPosition(Goal.x, Goal.y, Goal.z, move_speed);
} }
else else {
CP2Moved = false; CP2Moved = false;
}
} }
if (!CP2Moved) if (!CP2Moved) {
{ if (moved) {
if(moved) { Log(Logs::Detail,
Log(Logs::Detail, Logs::AI, "Reached guard point (%.3f,%.3f,%.3f)", m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z); Logs::AI,
"Reached guard point (%.3f,%.3f,%.3f)",
m_GuardPoint.x,
m_GuardPoint.y,
m_GuardPoint.z);
ClearFeignMemory(); ClearFeignMemory();
moved=false; moved = false;
if (GetTarget() == nullptr || DistanceSquared(m_Position, GetTarget()->GetPosition()) >= 5*5 ) if (GetTarget() == nullptr || DistanceSquared(m_Position, GetTarget()->GetPosition()) >= 5 * 5) {
{
SetHeading(m_GuardPoint.w); SetHeading(m_GuardPoint.w);
} else { }
else {
FaceTarget(GetTarget()); FaceTarget(GetTarget());
} }
SetCurrentSpeed(0); SetCurrentSpeed(0);
@ -1968,11 +1959,11 @@ void Mob::AI_Event_NoLongerEngaged() {
if (!IsAIControlled()) if (!IsAIControlled())
return; return;
this->AI_walking_timer->Start(RandomTimer(3000,20000)); this->AI_walking_timer->Start(RandomTimer(3000,20000));
pLastFightingDelayMoving = Timer::GetCurrentTime(); time_until_can_move = Timer::GetCurrentTime();
if (minLastFightingDelayMoving == maxLastFightingDelayMoving) if (minLastFightingDelayMoving == maxLastFightingDelayMoving)
pLastFightingDelayMoving += minLastFightingDelayMoving; time_until_can_move += minLastFightingDelayMoving;
else else
pLastFightingDelayMoving += zone->random.Int(minLastFightingDelayMoving, maxLastFightingDelayMoving); time_until_can_move += zone->random.Int(minLastFightingDelayMoving, maxLastFightingDelayMoving);
// So mobs don't keep running as a ghost until AIwalking_timer fires // So mobs don't keep running as a ghost until AIwalking_timer fires
// if they were moving prior to losing all hate // 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 // except if we're a pet, then we might run into some issues with pets backing off when they should immediately be moving

View File

@ -242,8 +242,8 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
roambox_max_y = -2; roambox_max_y = -2;
roambox_min_x = -2; roambox_min_x = -2;
roambox_min_y = -2; roambox_min_y = -2;
roambox_movingto_x = -2; roambox_destination_x = -2;
roambox_movingto_y = -2; roambox_destination_y = -2;
roambox_min_delay = 1000; roambox_min_delay = 1000;
roambox_delay = 1000; roambox_delay = 1000;
p_depop = false; p_depop = false;

View File

@ -311,9 +311,17 @@ public:
void SaveGuardSpot(bool iClearGuardSpot = false); void SaveGuardSpot(bool iClearGuardSpot = false);
inline bool IsGuarding() const { return(m_GuardPoint.w != 0); } inline bool IsGuarding() const { return(m_GuardPoint.w != 0); }
void SaveGuardSpotCharm(); void SaveGuardSpotCharm();
void RestoreGuardSpotCharm();
void AI_SetRoambox(float iDist, float iRoamDist, uint32 iDelay = 2500, uint32 iMinDelay = 2500); void RestoreGuardSpotCharm();
void AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay = 2500, uint32 iMinDelay = 2500);
void AI_SetRoambox(
float max_distance,
float roam_distance_variance,
uint32 delay = 2500,
uint32 min_delay = 2500
);
void AI_SetRoambox(float distance, float max_x, float min_x, float max_y, float min_y, uint32 delay = 2500, uint32 min_delay = 2500);
//mercenary stuff //mercenary stuff
void LoadMercTypes(); void LoadMercTypes();
@ -530,8 +538,8 @@ protected:
float roambox_min_x; float roambox_min_x;
float roambox_min_y; float roambox_min_y;
float roambox_distance; float roambox_distance;
float roambox_movingto_x; float roambox_destination_x;
float roambox_movingto_y; float roambox_destination_y;
uint32 roambox_delay; uint32 roambox_delay;
uint32 roambox_min_delay; uint32 roambox_min_delay;

View File

@ -141,118 +141,181 @@ uint32 Spawn2::despawnTimer(uint32 despawn_timer)
bool Spawn2::Process() { bool Spawn2::Process() {
IsDespawned = false; IsDespawned = false;
if(!Enabled()) if (!Enabled())
return true; return true;
//grab our spawn group //grab our spawn group
SpawnGroup* sg = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_); SpawnGroup *spawn_group = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_);
if(NPCPointerValid() && (sg->despawn == 0 || condition_id != 0)) if (NPCPointerValid() && (spawn_group->despawn == 0 || condition_id != 0)) {
return true; return true;
}
if (timer.Check()) { if (timer.Check()) {
timer.Disable(); timer.Disable();
Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Timer has triggered", spawn2_id); Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Timer has triggered", spawn2_id);
//first check our spawn condition, if this isnt active //first check our spawn condition, if this isnt active
//then we reset the timer and try again next time. //then we reset the timer and try again next time.
if(condition_id != SC_AlwaysEnabled if (condition_id != SC_AlwaysEnabled
&& !zone->spawn_conditions.Check(condition_id, condition_min_value)) { && !zone->spawn_conditions.Check(condition_id, condition_min_value)) {
Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: spawning prevented by spawn condition %d", spawn2_id, condition_id); Log(Logs::Detail,
Logs::Spawns,
"Spawn2 %d: spawning prevented by spawn condition %d",
spawn2_id,
condition_id);
Reset(); Reset();
return(true); return (true);
} }
if (sg == nullptr) { if (spawn_group == nullptr) {
database.LoadSpawnGroupsByID(spawngroup_id_,&zone->spawn_group_list); database.LoadSpawnGroupsByID(spawngroup_id_, &zone->spawn_group_list);
sg = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_); spawn_group = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_);
} }
if (sg == nullptr) { if (spawn_group == nullptr) {
Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Unable to locate spawn group %d. Disabling.", spawn2_id, spawngroup_id_); Log(Logs::Detail,
Logs::Spawns,
"Spawn2 %d: Unable to locate spawn group %d. Disabling.",
spawn2_id,
spawngroup_id_);
return false; return false;
} }
//have the spawn group pick an NPC for us //have the spawn group pick an NPC for us
uint32 npcid = sg->GetNPCType(); uint32 npcid = spawn_group->GetNPCType();
if (npcid == 0) { if (npcid == 0) {
Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn group %d did not yeild an NPC! not spawning.", spawn2_id, spawngroup_id_); Log(Logs::Detail,
Reset(); //try again later (why?) Logs::Spawns,
return(true); "Spawn2 %d: Spawn group %d did not yeild an NPC! not spawning.",
spawn2_id,
spawngroup_id_);
Reset(); //try again later (why?)
return (true);
} }
//try to find our NPC type. //try to find our NPC type.
const NPCType* tmp = database.LoadNPCTypesData(npcid); const NPCType *tmp = database.LoadNPCTypesData(npcid);
if (tmp == nullptr) { if (tmp == nullptr) {
Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn group %d yeilded an invalid NPC type %d", spawn2_id, spawngroup_id_, npcid); Log(Logs::Detail,
Reset(); //try again later Logs::Spawns,
return(true); "Spawn2 %d: Spawn group %d yeilded an invalid NPC type %d",
spawn2_id,
spawngroup_id_,
npcid);
Reset(); //try again later
return (true);
} }
if(tmp->unique_spawn_by_name) if (tmp->unique_spawn_by_name) {
{ if (!entity_list.LimitCheckName(tmp->name)) {
if(!entity_list.LimitCheckName(tmp->name)) Log(Logs::Detail,
{ Logs::Spawns,
Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn group %d yeilded NPC type %d, which is unique and one already exists.", spawn2_id, spawngroup_id_, npcid); "Spawn2 %d: Spawn group %d yeilded NPC type %d, which is unique and one already exists.",
timer.Start(5000); //try again in five seconds. spawn2_id,
return(true); spawngroup_id_,
npcid);
timer.Start(5000); //try again in five seconds.
return (true);
} }
} }
if(tmp->spawn_limit > 0) { if (tmp->spawn_limit > 0) {
if(!entity_list.LimitCheckType(npcid, tmp->spawn_limit)) { if (!entity_list.LimitCheckType(npcid, tmp->spawn_limit)) {
Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn group %d yeilded NPC type %d, which is over its spawn limit (%d)", spawn2_id, spawngroup_id_, npcid, tmp->spawn_limit); Log(Logs::Detail,
timer.Start(5000); //try again in five seconds. Logs::Spawns,
return(true); "Spawn2 %d: Spawn group %d yeilded NPC type %d, which is over its spawn limit (%d)",
spawn2_id,
spawngroup_id_,
npcid,
tmp->spawn_limit);
timer.Start(5000); //try again in five seconds.
return (true);
} }
} }
bool ignore_despawn = false; bool ignore_despawn = false;
if (npcthis) if (npcthis) {
{
ignore_despawn = npcthis->IgnoreDespawn(); ignore_despawn = npcthis->IgnoreDespawn();
} }
if (ignore_despawn) if (ignore_despawn) {
{
return true; return true;
} }
if (sg->despawn != 0 && condition_id == 0 && !ignore_despawn) if (spawn_group->despawn != 0 && condition_id == 0 && !ignore_despawn) {
{
zone->Despawn(spawn2_id); zone->Despawn(spawn2_id);
} }
if (IsDespawned) if (IsDespawned) {
{
return true; return true;
} }
currentnpcid = npcid; 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), FlyMode3);
npc->mod_prespawn(this); npc->mod_prespawn(this);
npcthis = npc; npcthis = npc;
npc->AddLootTable(); npc->AddLootTable();
if (npc->DropsGlobalLoot()) if (npc->DropsGlobalLoot()) {
npc->CheckGlobalLootTables(); npc->CheckGlobalLootTables();
}
npc->SetSp2(spawngroup_id_); npc->SetSp2(spawngroup_id_);
npc->SaveGuardPointAnim(anim); npc->SaveGuardPointAnim(anim);
npc->SetAppearance((EmuAppearance)anim); npc->SetAppearance((EmuAppearance) anim);
entity_list.AddNPC(npc); entity_list.AddNPC(npc);
//this limit add must be done after the AddNPC since we need the entity ID. //this limit add must be done after the AddNPC since we need the entity ID.
entity_list.LimitAddNPC(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()) { * Roambox init
Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Group %d spawned %s (%d) at (%.3f, %.3f, %.3f).", spawn2_id, spawngroup_id_, npc->GetName(), npcid, x, y, z); */
if (spawn_group->roamdist && spawn_group->roambox[0] && spawn_group->roambox[1] && spawn_group->roambox[2] &&
spawn_group->roambox[3] && spawn_group->delay && spawn_group->min_delay) {
npc->AI_SetRoambox(
spawn_group->roamdist,
spawn_group->roambox[0],
spawn_group->roambox[1],
spawn_group->roambox[2],
spawn_group->roambox[3],
spawn_group->delay,
spawn_group->min_delay
);
}
if (zone->InstantGrids()) {
Log(Logs::Detail,
Logs::Spawns,
"Spawn2 %d: Group %d spawned %s (%d) at (%.3f, %.3f, %.3f).",
spawn2_id,
spawngroup_id_,
npc->GetName(),
npcid,
x,
y,
z);
LoadGrid(); LoadGrid();
} else { }
Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Group %d spawned %s (%d) at (%.3f, %.3f, %.3f). Grid loading delayed.", spawn2_id, spawngroup_id_, tmp->name, npcid, x, y, z); else {
Log(Logs::Detail,
Logs::Spawns,
"Spawn2 %d: Group %d spawned %s (%d) at (%.3f, %.3f, %.3f). Grid loading delayed.",
spawn2_id,
spawngroup_id_,
tmp->name,
npcid,
x,
y,
z);
} }
} }
return true; return true;
} }
@ -266,11 +329,11 @@ void Spawn2::Disable()
} }
void Spawn2::LoadGrid() { void Spawn2::LoadGrid() {
if(!npcthis) if (!npcthis)
return; return;
if(grid_ < 1) if (grid_ < 1)
return; return;
if(!entity_list.IsMobInZone(npcthis)) if (!entity_list.IsMobInZone(npcthis))
return; return;
//dont set an NPC's grid until its loaded for them. //dont set an NPC's grid until its loaded for them.
npcthis->SetGrid(grid_); npcthis->SetGrid(grid_);
@ -278,7 +341,6 @@ void Spawn2::LoadGrid() {
Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Loading grid %d for %s", spawn2_id, grid_, npcthis->GetName()); Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Loading grid %d for %s", spawn2_id, grid_, npcthis->GetName());
} }
/* /*
All three of these actions basically say that the mob which was All three of these actions basically say that the mob which was
associated with this spawn point is no longer relavent. associated with this spawn point is no longer relavent.

View File

@ -42,19 +42,27 @@ struct wp_distance
int index; int index;
}; };
void NPC::AI_SetRoambox(float iDist, float iRoamDist, uint32 iDelay, uint32 iMinDelay) { void NPC::AI_SetRoambox(float max_distance, float roam_distance_variance, uint32 delay, uint32 min_delay) {
AI_SetRoambox(iDist, GetX() + iRoamDist, GetX() - iRoamDist, GetY() + iRoamDist, GetY() - iRoamDist, iDelay, iMinDelay); AI_SetRoambox(
max_distance,
GetX() + roam_distance_variance,
GetX() - roam_distance_variance,
GetY() + roam_distance_variance,
GetY() - roam_distance_variance,
delay,
min_delay
);
} }
void NPC::AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay, uint32 iMinDelay) { void NPC::AI_SetRoambox(float distance, float max_x, float min_x, float max_y, float min_y, uint32 delay, uint32 min_delay) {
roambox_distance = iDist; roambox_distance = distance;
roambox_max_x = iMaxX; roambox_max_x = max_x;
roambox_min_x = iMinX; roambox_min_x = min_x;
roambox_max_y = iMaxY; roambox_max_y = max_y;
roambox_min_y = iMinY; roambox_min_y = min_y;
roambox_movingto_x = roambox_max_x + 1; // this will trigger a recalc roambox_destination_x = roambox_max_x + 1; // this will trigger a recalc
roambox_delay = iDelay; roambox_delay = delay;
roambox_min_delay = iMinDelay; roambox_min_delay = min_delay;
} }
void NPC::DisplayWaypointInfo(Client *c) { void NPC::DisplayWaypointInfo(Client *c) {
@ -199,7 +207,7 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot)
} }
cur_wp_pause = 0; cur_wp_pause = 0;
pLastFightingDelayMoving = 0; time_until_can_move = 0;
if (AI_walking_timer->Enabled()) if (AI_walking_timer->Enabled())
AI_walking_timer->Start(100); AI_walking_timer->Start(100);
} }
@ -438,22 +446,16 @@ 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))); 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, int speed, bool checkZ, bool calcHeading) { bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, bool check_z, bool calculate_heading) {
if (GetID() == 0) if (GetID() == 0)
return true; return true;
if (speed <= 0) if (speed <= 0) {
{
SetCurrentSpeed(0); SetCurrentSpeed(0);
return true; return true;
} }
if ((m_Position.x - x == 0) && (m_Position.y - y == 0)) {//spawn is at target coords if ((m_Position.x - x == 0) && (m_Position.y - y == 0)) {//spawn is at target coords
if (m_Position.z - z != 0) {
m_Position.z = z;
Log(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f): Jumping pure Z.", x, y, z);
return true;
}
return false; return false;
} }
else if ((std::abs(m_Position.x - x) < 0.1) && (std::abs(m_Position.y - y) < 0.1)) { else if ((std::abs(m_Position.x - x) < 0.1) && (std::abs(m_Position.y - y) < 0.1)) {
@ -464,16 +466,17 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
m_Position.x = x; m_Position.x = x;
m_Position.y = y; m_Position.y = y;
m_Position.z = z; m_Position.z = z;
return true; return true;
} }
bool send_update = false;
int compare_steps = 20; int compare_steps = 20;
if (tar_ndx < compare_steps && m_TargetLocation.x == x && m_TargetLocation.y == y) { 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_x = m_Position.x + m_TargetV.x * tar_vector;
float new_y = m_Position.y + m_TargetV.y*tar_vector; float new_y = m_Position.y + m_TargetV.y * tar_vector;
float new_z = m_Position.z + m_TargetV.z*tar_vector; float new_z = m_Position.z + m_TargetV.z * tar_vector;
if (IsNPC()) { if (IsNPC()) {
entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z); entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z);
} }
@ -482,21 +485,22 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
m_Position.y = new_y; m_Position.y = new_y;
m_Position.z = new_z; m_Position.z = new_z;
if(checkZ && fix_z_timer.Check() && if (check_z && fix_z_timer.Check() && (!this->IsEngaged() || flee_mode || currently_fleeing)) {
(!this->IsEngaged() || flee_mode || currently_fleeing))
this->FixZ(); this->FixZ();
}
tar_ndx++; tar_ndx++;
return true; return true;
} }
if (tar_ndx > 50) {
if (tar_ndx>50) {
tar_ndx--; tar_ndx--;
} }
else { else {
tar_ndx = 0; tar_ndx = 0;
} }
m_TargetLocation = glm::vec3(x, y, z); m_TargetLocation = glm::vec3(x, y, z);
float nx = this->m_Position.x; float nx = this->m_Position.x;
@ -530,14 +534,12 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
// mob move fix // mob move fix
if (numsteps<20) if (numsteps < 20) {
{ if (numsteps > 1) {
if (numsteps>1)
{
tar_vector = 1.0f; tar_vector = 1.0f;
m_TargetV.x = m_TargetV.x / (float)numsteps; m_TargetV.x = m_TargetV.x / (float) numsteps;
m_TargetV.y = m_TargetV.y / (float)numsteps; m_TargetV.y = m_TargetV.y / (float) numsteps;
m_TargetV.z = m_TargetV.z / (float)numsteps; m_TargetV.z = m_TargetV.z / (float) numsteps;
float new_x = m_Position.x + m_TargetV.x; float new_x = m_Position.x + m_TargetV.x;
float new_y = m_Position.y + m_TargetV.y; float new_y = m_Position.y + m_TargetV.y;
@ -549,12 +551,12 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
m_Position.x = new_x; m_Position.x = new_x;
m_Position.y = new_y; m_Position.y = new_y;
m_Position.z = new_z; m_Position.z = new_z;
if (calcHeading) if (calculate_heading) {
m_Position.w = CalculateHeadingToTarget(x, y); m_Position.w = CalculateHeadingToTarget(x, y);
}
tar_ndx = 20 - numsteps; tar_ndx = 20 - numsteps;
} }
else else {
{
if (IsNPC()) { if (IsNPC()) {
entity_list.ProcessMove(CastToNPC(), x, y, z); entity_list.ProcessMove(CastToNPC(), x, y, z);
} }
@ -578,9 +580,10 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
tar_vector *= (dur / 100.0f); tar_vector *= (dur / 100.0f);
float new_x = m_Position.x + m_TargetV.x*tar_vector; float new_x = m_Position.x + m_TargetV.x * tar_vector;
float new_y = m_Position.y + m_TargetV.y*tar_vector; float new_y = m_Position.y + m_TargetV.y * tar_vector;
float new_z = m_Position.z + m_TargetV.z*tar_vector; float new_z = m_Position.z + m_TargetV.z * tar_vector;
if (IsNPC()) { if (IsNPC()) {
entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z); entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z);
} }
@ -588,11 +591,12 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
m_Position.x = new_x; m_Position.x = new_x;
m_Position.y = new_y; m_Position.y = new_y;
m_Position.z = new_z; m_Position.z = new_z;
if (calcHeading) if (calculate_heading) {
m_Position.w = CalculateHeadingToTarget(x, y); m_Position.w = CalculateHeadingToTarget(x, y);
}
} }
if (checkZ && fix_z_timer.Check() && !this->IsEngaged()) if (check_z && fix_z_timer.Check() && !this->IsEngaged())
this->FixZ(); this->FixZ();
SetMoving(true); SetMoving(true);
@ -600,13 +604,11 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
m_Delta = glm::vec4(m_Position.x - nx, m_Position.y - ny, m_Position.z - nz, 0.0f); m_Delta = glm::vec4(m_Position.x - nx, m_Position.y - ny, m_Position.z - nz, 0.0f);
if (IsClient()) if (IsClient()) {
{
SendPositionUpdate(1); SendPositionUpdate(1);
CastToClient()->ResetPositionTimer(); CastToClient()->ResetPositionTimer();
} }
else else {
{
SendPositionUpdate(); SendPositionUpdate();
SetAppearance(eaStanding, false); SetAppearance(eaStanding, false);
} }
@ -615,8 +617,8 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
return true; return true;
} }
bool Mob::CalculateNewPosition(float x, float y, float z, int speed, bool checkZ, bool calcHeading) { bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool check_z, bool calculate_heading) {
return MakeNewPositionAndSendUpdate(x, y, z, speed); return MakeNewPositionAndSendUpdate(x, y, z, speed, check_z);
} }
void NPC::AssignWaypoints(int32 grid) void NPC::AssignWaypoints(int32 grid)
@ -746,10 +748,11 @@ void Mob::SendToFixZ(float new_x, float new_y, float new_z) {
} }
} }
float Mob::GetFixedZ(glm::vec3 dest, int32 z_find_offset) { float Mob::GetFixedZ(glm::vec3 destination, int32 z_find_offset) {
BenchTimer timer; BenchTimer timer;
timer.reset(); timer.reset();
float new_z = dest.z;
float new_z = destination.z;
if (zone->HasMap() && RuleB(Map, FixZWhenMoving)) { if (zone->HasMap() && RuleB(Map, FixZWhenMoving)) {
@ -765,7 +768,7 @@ float Mob::GetFixedZ(glm::vec3 dest, int32 z_find_offset) {
/* /*
* Any more than 5 in the offset makes NPC's hop/snap to ceiling in small corridors * Any more than 5 in the offset makes NPC's hop/snap to ceiling in small corridors
*/ */
new_z = this->FindDestGroundZ(dest, z_find_offset); new_z = this->FindDestGroundZ(destination, z_find_offset);
if (new_z != BEST_Z_INVALID) { if (new_z != BEST_Z_INVALID) {
new_z += this->GetZOffset(); new_z += this->GetZOffset();
@ -776,9 +779,15 @@ float Mob::GetFixedZ(glm::vec3 dest, int32 z_find_offset) {
auto duration = timer.elapsed(); auto duration = timer.elapsed();
Log(Logs::Moderate, Logs::FixZ, Log(Logs::Moderate,
"Mob::GetFixedZ() (%s) returned %4.3f at %4.3f, %4.3f, %4.3f - Took %lf", Logs::FixZ,
this->GetCleanName(), new_z, dest.x, dest.y, dest.z, duration); "Mob::GetFixedZ() (%s) returned %4.3f at %4.3f, %4.3f, %4.3f - Took %lf",
this->GetCleanName(),
new_z,
destination.x,
destination.y,
destination.z,
duration);
} }
return new_z; return new_z;
@ -790,16 +799,19 @@ void Mob::FixZ(int32 z_find_offset /*= 5*/) {
if (!IsClient() && new_z != m_Position.z) { if (!IsClient() && new_z != m_Position.z) {
if ((new_z > -2000) && new_z != BEST_Z_INVALID) { if ((new_z > -2000) && new_z != BEST_Z_INVALID) {
if (RuleB(Map, MobZVisualDebug)) if (RuleB(Map, MobZVisualDebug)) {
this->SendAppearanceEffect(78, 0, 0, 0, 0); this->SendAppearanceEffect(78, 0, 0, 0, 0);
}
m_Position.z = new_z; m_Position.z = new_z;
} else { }
if (RuleB(Map, MobZVisualDebug)) else {
if (RuleB(Map, MobZVisualDebug)) {
this->SendAppearanceEffect(103, 0, 0, 0, 0); this->SendAppearanceEffect(103, 0, 0, 0, 0);
}
Log(Logs::General, Logs::FixZ, "%s is failing to find Z %f", Log(Logs::General, Logs::FixZ, "%s is failing to find Z %f",
this->GetCleanName(), std::abs(m_Position.z - new_z)); this->GetCleanName(), std::abs(m_Position.z - new_z));
} }
} }
} }