void SmartAI::EnterCombat(Unit* enemy) { if (IsAIControlled()) me->InterruptNonMeleeSpells(false); // must be before ProcessEvents GetScript()->ProcessEventsFor(SMART_EVENT_AGGRO, enemy); if (!IsAIControlled()) return; mLastOOCPos = me->GetPosition(); SetRun(mRun); if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == POINT_MOTION_TYPE) me->GetMotionMaster()->MovementExpired(); }
void SmartAI::SetCombatMove(bool on) { if (mCanCombatMove == on) return; mCanCombatMove = on; if (!IsAIControlled()) return; if (!HasEscortState(SMART_ESCORT_ESCORTING)) { if (on && me->GetVictim()) { if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == IDLE_MOTION_TYPE) { SetRun(mRun); me->GetMotionMaster()->MoveChase(me->GetVictim()); me->CastStop(); } } else { if (me->HasUnitState(UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE)) return; me->GetMotionMaster()->MovementExpired(); me->GetMotionMaster()->Clear(true); me->StopMoving(); me->GetMotionMaster()->MoveIdle(); } } }
void SmartAI::SetCombatMove(bool on) { if (mCanCombatMove == on) return; mCanCombatMove = on; if (!IsAIControlled()) return; if (!HasEscortState(SMART_ESCORT_ESCORTING)) { if (on && me->GetVictim()) { if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == IDLE_MOTION_TYPE) { SetRun(mRun); me->GetMotionMaster()->MoveChase(me->GetVictim()); me->CastStop(); } } else { me->StopMoving(); if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) me->GetMotionMaster()->Clear(false); me->GetMotionMaster()->MoveIdle(); } } }
void SmartAI::SetCombatMove(bool on) { if (mCanCombatMove == on) return; mCanCombatMove = on; if (!IsAIControlled()) return; if (me->IsEngaged()) { if (on) { if (!me->HasReactState(REACT_PASSIVE) && me->GetVictim() && !me->GetMotionMaster()->HasMovementGenerator([](MovementGenerator const* movement) -> bool { return movement->Mode == MOTION_MODE_DEFAULT && movement->Priority == MOTION_PRIORITY_NORMAL; })) { SetRun(mRun); me->GetMotionMaster()->MoveChase(me->GetVictim()); } } else if (MovementGenerator* movement = me->GetMotionMaster()->GetMovementGenerator([](MovementGenerator const* a) -> bool { return a->GetMovementGeneratorType() == CHASE_MOTION_TYPE && a->Mode == MOTION_MODE_DEFAULT && a->Priority == MOTION_PRIORITY_NORMAL; })) me->GetMotionMaster()->Remove(movement); } }
void SmartAI::JustEngagedWith(Unit* enemy) { if (IsAIControlled()) me->InterruptNonMeleeSpells(false); // must be before ProcessEvents GetScript()->ProcessEventsFor(SMART_EVENT_AGGRO, enemy); }
void SmartAI::UpdateAI(uint32 diff) { GetScript()->OnUpdate(diff); UpdatePath(diff); UpdateDespawn(diff); /// @todo move to void if (!mFollowGuid.IsEmpty()) { if (mFollowArrivedTimer < diff) { if (me->FindNearestCreature(mFollowArrivedEntry, INTERACTION_DISTANCE, true)) { StopFollow(); return; } mFollowArrivedTimer = 1000; } else mFollowArrivedTimer -= diff; } if (!IsAIControlled()) return; if (!UpdateVictim()) return; if (mCanAutoAttack) DoMeleeAttackIfReady(); }
void SmartAI::ReturnToLastOOCPos() { if (!IsAIControlled()) return; me->SetWalk(false); me->GetMotionMaster()->MovePoint(SMART_ESCORT_LAST_OOC_POINT, me->GetHomePosition()); }
void SmartAI::ReturnToLastOOCPos() { if (!IsAIControlled()) return; SetRun(mRun); me->GetMotionMaster()->MovePoint(SMART_ESCORT_LAST_OOC_POINT, mLastOOCPos); }
void Client::ProcessMovePC(uint32 zoneID, uint32 instance_id, float x, float y, float z, float heading, uint8 ignorerestrictions, ZoneMode zm) { // From what I have read, dragged corpses should stay with the player for Intra-zone summons etc, but we can implement that later. ClearDraggedCorpses(); if(zoneID == 0) zoneID = zone->GetZoneID(); if(zoneID == zone->GetZoneID() && instance_id == zone->GetInstanceID()) { // TODO: Determine if this condition is necessary. if(IsAIControlled()) { GMMove(x, y, z); return; } if(GetPetID() != 0) { //if they have a pet and they are staying in zone, move with them Mob *p = GetPet(); if(p != nullptr){ p->SetPetOrder(SPO_Follow); p->GMMove(x+15, y, z); //so it dosent have to run across the map. } } } switch(zm) { case GateToBindPoint: ZonePC(zoneID, instance_id, x, y, z, heading, ignorerestrictions, zm); break; case EvacToSafeCoords: case ZoneToSafeCoords: ZonePC(zoneID, instance_id, x, y, z, heading, ignorerestrictions, zm); break; case GMSummon: Message(15, "You have been summoned by a GM!"); ZonePC(zoneID, instance_id, x, y, z, heading, ignorerestrictions, zm); break; case ZoneToBindPoint: ZonePC(zoneID, instance_id, x, y, z, heading, ignorerestrictions, zm); break; case ZoneSolicited: ZonePC(zoneID, instance_id, x, y, z, heading, ignorerestrictions, zm); break; case SummonPC: Message(15, "You have been summoned!"); ZonePC(zoneID, instance_id, x, y, z, heading, ignorerestrictions, zm); break; case Rewind: Message(15, "Rewinding to previous location."); ZonePC(zoneID, instance_id, x, y, z, heading, ignorerestrictions, zm); break; default: LogFile->write(EQEMuLog::Error, "Client::ProcessMovePC received a reguest to perform an unsupported client zone operation."); break; } }
void SmartAI::DamageTaken(Unit* doneBy, uint32& damage) { GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED, doneBy, damage); if (!IsAIControlled()) // don't allow players to use unkillable units return; if (mInvincibilityHpLevel && (damage >= me->GetHealth() - mInvincibilityHpLevel)) damage = me->GetHealth() - mInvincibilityHpLevel; // damage should not be nullified, because of player damage req. }
void SmartAI::MoveInLineOfSight(Unit* who) { if (!who) return; GetScript()->OnMoveInLineOfSight(who); if (!IsAIControlled()) return; if (HasEscortState(SMART_ESCORT_ESCORTING) && AssistPlayerInCombatAgainst(who)) return; CreatureAI::MoveInLineOfSight(who); }
void SmartAI::MoveInLineOfSight(Unit* who) { if (!who) return; GetScript()->OnMoveInLineOfSight(who); if (!IsAIControlled()) return; if (AssistPlayerInCombatAgainst(who)) return; CreatureAI::MoveInLineOfSight(who); }
void SmartAI::EnterEvadeMode(EvadeReason /*why*/) { if (mEvadeDisabled) { GetScript()->ProcessEventsFor(SMART_EVENT_EVADE); return; } if (!IsAIControlled()) { me->AttackStop(); return; } if (!_EnterEvadeMode()) return; me->AddUnitState(UNIT_STATE_EVADE); GetScript()->ProcessEventsFor(SMART_EVENT_EVADE); // must be after _EnterEvadeMode (spells, auras, ...) SetRun(mRun); if (Unit* owner = me->GetCharmerOrOwner()) { me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); me->ClearUnitState(UNIT_STATE_EVADE); } else if (HasEscortState(SMART_ESCORT_ESCORTING)) { AddEscortState(SMART_ESCORT_RETURNING); ReturnToLastOOCPos(); } else if (Unit* target = mFollowGuid ? ObjectAccessor::GetUnit(*me, mFollowGuid) : nullptr) { me->GetMotionMaster()->MoveFollow(target, mFollowDist, mFollowAngle); // evade is not cleared in MoveFollow, so we can't keep it me->ClearUnitState(UNIT_STATE_EVADE); } else me->GetMotionMaster()->MoveTargetedHome(); if (!me->HasUnitState(UNIT_STATE_EVADE)) GetScript()->OnReset(); }
void SmartAI::UpdateAI(uint32 diff) { CheckConditions(diff); GetScript()->OnUpdate(diff); UpdatePath(diff); UpdateFollow(diff); UpdateDespawn(diff); if (!IsAIControlled()) return; if (!UpdateVictim()) return; if (mCanAutoAttack) DoMeleeAttackIfReady(); }
bool SmartAI::AssistPlayerInCombatAgainst(Unit* who) { if (me->HasReactState(REACT_PASSIVE) || !IsAIControlled()) return false; if (!who || !who->GetVictim()) return false; // experimental (unknown) flag not present if (!(me->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_CAN_ASSIST)) return false; // not a player if (!who->EnsureVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()) return false; if (!who->isInAccessiblePlaceFor(me)) return false; if (!CanAIAttack(who)) return false; // we cannot attack in evade mode if (me->IsInEvadeMode()) return false; // or if enemy is in evade mode if (who->GetTypeId() == TYPEID_UNIT && who->ToCreature()->IsInEvadeMode()) return false; if (!me->IsValidAssistTarget(who->GetVictim())) return false; // too far away and no free sight if (me->IsWithinDistInMap(who, SMART_MAX_AID_DIST) && me->IsWithinLOSInMap(who)) { me->EngageWithTarget(who); return true; } return false; }
void SmartAI::AttackStart(Unit* who) { // dont allow charmed npcs to act on their own if (!IsAIControlled()) { if (who) me->Attack(who, mCanAutoAttack); return; } if (who && me->Attack(who, mCanAutoAttack)) { me->GetMotionMaster()->Clear(MOTION_PRIORITY_NORMAL); me->PauseMovement(); if (mCanCombatMove) { SetRun(mRun); me->GetMotionMaster()->MoveChase(who); } } }
bool SmartAI::AssistPlayerInCombatAgainst(Unit* who) { if (me->HasReactState(REACT_PASSIVE) || !IsAIControlled()) return false; if (!who || !who->GetVictim()) return false; //experimental (unknown) flag not present if (!(me->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_CAN_ASSIST)) return false; //not a player if (!who->EnsureVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()) return false; //never attack friendly if (me->IsFriendlyTo(who)) return false; //too far away and no free sight? if (me->IsWithinDistInMap(who, SMART_MAX_AID_DIST) && me->IsWithinLOSInMap(who)) { //already fighting someone? if (!me->GetVictim()) { AttackStart(who); return true; } else { who->SetInCombatWith(me); me->AddThreat(who, 0.0f); return true; } } return false; }
void SmartAI::EndPath(bool fail) { RemoveEscortState(SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING); _path.nodes.clear(); _waypointPauseTimer = 0; if (_escortNPCFlags) { me->SetFlag(UNIT_NPC_FLAGS, _escortNPCFlags); _escortNPCFlags = 0; } ObjectVector const* targets = GetScript()->GetStoredTargetVector(SMART_ESCORT_TARGETS, *me); if (targets && mEscortQuestID) { if (targets->size() == 1 && GetScript()->IsPlayer((*targets->begin()))) { Player* player = targets->front()->ToPlayer(); if (!fail && player->IsAtGroupRewardDistance(me) && !player->HasCorpse()) player->GroupEventHappens(mEscortQuestID, me); if (fail) player->FailQuest(mEscortQuestID); if (Group* group = player->GetGroup()) { for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next()) { Player* groupGuy = groupRef->GetSource(); if (!groupGuy->IsInMap(player)) continue; if (!fail && groupGuy->IsAtGroupRewardDistance(me) && !groupGuy->HasCorpse()) groupGuy->AreaExploredOrEventHappens(mEscortQuestID); else if (fail) groupGuy->FailQuest(mEscortQuestID); } } } else { for (WorldObject* target : *targets) { if (GetScript()->IsPlayer(target)) { Player* player = target->ToPlayer(); if (!fail && player->IsAtGroupRewardDistance(me) && !player->HasCorpse()) player->AreaExploredOrEventHappens(mEscortQuestID); else if (fail) player->FailQuest(mEscortQuestID); } } } } // End Path events should be only processed if it was SUCCESSFUL stop or stop called by SMART_ACTION_WAYPOINT_STOP if (fail) return; GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_ENDED, nullptr, _currentWaypointNode, GetScript()->GetPathId()); if (_repeatWaypointPath) { if (IsAIControlled()) StartPath(mRun, GetScript()->GetPathId(), _repeatWaypointPath); } else GetScript()->SetPathId(0); if (mDespawnState == 1) StartDespawn(); }
void SmartAI::EndPath(bool fail) { GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_ENDED, nullptr, mLastWP->id, GetScript()->GetPathId()); RemoveEscortState(SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING); mWayPoints = nullptr; mCurrentWPID = 0; mWPPauseTimer = 0; mLastWP = nullptr; if (mCanRepeatPath) { if (IsAIControlled()) StartPath(mRun, GetScript()->GetPathId(), true); } else GetScript()->SetPathId(0); ObjectList* targets = GetScript()->GetTargetList(SMART_ESCORT_TARGETS); if (targets && mEscortQuestID) { if (targets->size() == 1 && GetScript()->IsPlayer((*targets->begin()))) { Player* player = (*targets->begin())->ToPlayer(); if (!fail && player->IsAtGroupRewardDistance(me) && !player->HasCorpse()) player->GroupEventHappens(mEscortQuestID, me); if (fail && player->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE) player->FailQuest(mEscortQuestID); if (Group* group = player->GetGroup()) { for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next()) { Player* groupGuy = groupRef->GetSource(); if (!fail && groupGuy->IsAtGroupRewardDistance(me) && !groupGuy->HasCorpse()) groupGuy->AreaExploredOrEventHappens(mEscortQuestID); if (fail && groupGuy->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE) groupGuy->FailQuest(mEscortQuestID); } } } else { for (ObjectList::iterator iter = targets->begin(); iter != targets->end(); ++iter) { if (GetScript()->IsPlayer((*iter))) { Player* player = (*iter)->ToPlayer(); if (!fail && player->IsAtGroupRewardDistance(me) && !player->HasCorpse()) player->AreaExploredOrEventHappens(mEscortQuestID); if (fail && player->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE) player->FailQuest(mEscortQuestID); } } } } if (mDespawnState == 1) StartDespawn(); }