void JustDied(Unit* /*victim*/) { if (pInstance) pInstance->SetData(DATA_HEXLORDEVENT, DONE); me->MonsterYell(YELL_DEATH, LANG_UNIVERSAL, 0); DoPlaySoundToSet(me, SOUND_YELL_DEATH); for (uint8 i = 0; i < 4 ; ++i) { Unit* Temp = Unit::GetUnit((*me), AddGUID[i]); if (Temp && Temp->isAlive()) Temp->DealDamage(Temp, Temp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } }
void DamageTaken(Unit* /*done_by*/, uint32 &damage) { Unit* pOtherBoss = GetOtherBoss(); if (pOtherBoss) { float dPercent = ((float)damage) / ((float)me->GetMaxHealth()); int odmg = (int)(dPercent * ((float)pOtherBoss->GetMaxHealth())); int ohealth = pOtherBoss->GetHealth()-odmg; pOtherBoss->SetHealth(ohealth > 0 ? ohealth : 0); if (ohealth <= 0) { pOtherBoss->setDeathState(JUST_DIED); pOtherBoss->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); } } }
bool PlayerbotClassAI::DoSupportRaid(Player *gPlayer, float radius, bool dResurrect, bool dGroupHeal, bool dHeal, bool dCure, bool dBuff) { bool needHeal = false; if (dGroupHeal || dHeal) { uint8 cntNeedHeal = 0; uint8 raidHPPercent = GetHealthPercentRaid(gPlayer, cntNeedHeal); if (dGroupHeal && raidHPPercent <=90 && cntNeedHeal > 1) { if (HealGroup(gPlayer, raidHPPercent, cntNeedHeal)) return true; } if (raidHPPercent < 60 ) needHeal = true; } //std::list<Unit*> unitList; //gPlayer->GetRaidMember(unitList,30); Group *pGroup = gPlayer->GetGroup(); if (!pGroup) return false; for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) { Unit* tPlayer = itr->getSource(); if(!tPlayer || gPlayer->IsHostileTo(tPlayer)) continue; if(GetPlayerBot()->GetAreaId() != tPlayer->GetAreaId()) continue; if(!m_bot->IsWithinDistInMap(tPlayer, radius)) { continue; } if(tPlayer->isDead()) // May be we can rez { if(!dResurrect) continue; if(needHeal) continue; //First heal others needing heal if(tPlayer->GetGUID() == GetPlayerBot()->GetGUID()) continue; if(tPlayer->IsNonMeleeSpellCasted(true)) continue; //Already rez if(RezTarget(tPlayer)) { return true; } else continue; } if (dHeal) { uint8 tarHPPercent = tPlayer->GetHealth()*100 / tPlayer->GetMaxHealth(); if (tarHPPercent < 100 && HealTarget(tPlayer, tarHPPercent)) return true; } if (needHeal && dHeal) continue; //First heal others needing heal if (dCure && CureTarget(tPlayer)) return true; if (dBuff && BuffPlayer(tPlayer)) return true; } return false; }
void JustDied(Unit *victim) { DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); DoPlaySoundToSet(m_creature, SOUND_DEATH); //despawn copy if(Demon) { Unit *pUnit = NULL; pUnit = Unit::GetUnit((*m_creature), Demon); if(pUnit) pUnit->DealDamage(pUnit, pUnit->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } if(pInstance) pInstance->SetData(DATA_LEOTHERASTHEBLINDEVENT, 0); }
void HandleOnHit() { if (!GetCaster()) return; Unit* caster = GetCaster(); if (!GetHitUnit()) return; if (!GetSpellInfo()) return; Unit* target = GetHitUnit(); int bp = target->GetHealth() * 0.5; caster->CastCustomSpell(target, GetSpellInfo()->Id, &bp, NULL, NULL, true); }
void IFighterTask::OnUnitDamaged(CCircuitUnit* unit, CEnemyUnit* attacker) { CCircuitAI* circuit = manager->GetCircuit(); int frame = circuit->GetLastFrame(); CCircuitDef* cdef = unit->GetCircuitDef(); Unit* u = unit->GetUnit(); const float healthPerc = u->GetHealth() / u->GetMaxHealth(); if (unit->GetShield() != nullptr) { const float minShield = circuit->GetSetupManager()->GetEmptyShield(); if ((healthPerc > cdef->GetRetreat()) && unit->IsShieldCharged(minShield)) { if (cdef->IsRoleHeavy() && (healthPerc < 0.9f)) { circuit->GetBuilderManager()->EnqueueRepair(IBuilderTask::Priority::NOW, unit); } return; } } else if ((healthPerc > cdef->GetRetreat()) && !unit->IsDisarmed(frame)) { if (cdef->IsRoleHeavy() && (healthPerc < 0.9f)) { circuit->GetBuilderManager()->EnqueueRepair(IBuilderTask::Priority::NOW, unit); } return; } else if (healthPerc < 0.2f) { // stuck units workaround: they don't shoot and don't see distant threat CRetreatTask* task = manager->GetCircuit()->GetMilitaryManager()->EnqueueRetreat(); manager->AssignTask(unit, task); return; } CThreatMap* threatMap = circuit->GetThreatMap(); const float range = cdef->GetMaxRange(); if ((target == nullptr) || !target->IsInLOS()) { CRetreatTask* task = circuit->GetMilitaryManager()->EnqueueRetreat(); manager->AssignTask(unit, task); return; } const AIFloat3& pos = unit->GetPos(frame); if ((target->GetPos().SqDistance2D(pos) > SQUARE(range)) || (threatMap->GetThreatAt(unit, pos) * 2 > threatMap->GetUnitThreat(unit))) { CRetreatTask* task = circuit->GetMilitaryManager()->EnqueueRetreat(); manager->AssignTask(unit, task); return; } cowards.insert(unit); }
void JustDied(Unit *killer) { for(uint8 i = 0; i < 2; ++i) { if(PortalGUID[i]) { Unit* Portal = Unit::GetUnit((*me), PortalGUID[i]); if(Portal) Portal->DealDamage(Portal, Portal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); PortalGUID[i] = 0; } } DoScriptText(SAY_DEATH, me); if(pInstance) pInstance->SetData(DATA_TERESTIAN, DONE); }
void EnfeebleHealthEffect() { const SpellEntry *info = GetSpellStore()->LookupEntry(SPELL_ENFEEBLE_EFFECT); if (!info) return; ThreatList const& tList = m_creature->getThreatManager().getThreatList(); std::vector<Unit *> targets; if (tList.empty()) return; //begin + 1 , so we don't target the one with the highest threat ThreatList::const_iterator itr = tList.begin(); std::advance(itr, 1); for(; itr!= tList.end(); ++itr) //store the threat list in a different container { Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); //only on alive players if (target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER) targets.push_back(target); } //cut down to size if we have more than 5 targets while(targets.size() > 5) targets.erase(targets.begin()+rand()%targets.size()); int i = 0; for(std::vector<Unit *>::iterator iter = targets.begin(); iter!= targets.end(); ++iter, ++i) { Unit *target = *iter; if (target) { enfeeble_targets[i] = target->GetGUID(); enfeeble_health[i] = target->GetHealth(); target->CastSpell(target, SPELL_ENFEEBLE, true, 0, 0, m_creature->GetGUID()); target->SetHealth(1); } } }
uint32 AbsorbDamage(uint32 School, uint32* dmg) { Unit* caster = GetUnitCaster(); if(caster == NULL) return 0; int health_pct = caster->GetHealthPct(); uint32 cur_health = caster->GetHealth(); uint32 max_health = caster->GetMaxHealth(); uint32 new_health_pct = (cur_health - *dmg) * 100 / max_health; // "Damage that would take you below $s1% health or taken while you are at $s1% health is reduced by $52284s1%." if((health_pct > 35 && new_health_pct < 35) || health_pct == 35) { uint32 dmg_absorbed = *dmg * (GetSpellProto()->EffectBasePoints[0] + 1) / 100; *dmg -= dmg_absorbed; return dmg_absorbed; } else return 0; }
void UpdateAI(const uint32 uiDiff) { //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if(m_bCanShatter) if(m_uiShatterTimer < uiDiff) { ShatterGolem(); m_bCanShatter = false; }else m_uiShatterTimer -= uiDiff; for(uint8 i=0; i<3; ++i) { Unit* pGolem = Unit::GetUnit(*m_creature, m_uiGolemsGUID[i][0]); if(pGolem && pGolem->isAlive()) if(pGolem->GetHealth()*100 / pGolem->GetMaxHealth() < 1) m_uiGolemsGUID[i][1] = 1; } if(!m_bCanShatter && m_uiGolemsGUID[0][1] == 1 && m_uiGolemsGUID[1][1] == 1 && m_uiGolemsGUID[2][1] == 1) { DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHATTERING_STOMP_N : SPELL_SHATTERING_STOMP_H); m_uiShatterTimer = 3000; m_bCanShatter = true; } // Health check if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < (100-(20*m_uiHealthAmountModifier))) { SummonGolems(); ++m_uiHealthAmountModifier; DoScriptText(urand(0, 1) ? SAY_FORGE_1 : SAY_FORGE_2, m_creature); } DoMeleeAttackIfReady(); }
void SetPhaseOne() { DoScriptText(SAY_HEART_CLOSED, me); if (me->HasAura(SPELL_SUBMERGE)) me->RemoveAurasDueToSpell(SPELL_SUBMERGE); DoCast(me, SPELL_STAND); // Just for the case this isn't done by the spell above. me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE); me->SetReactState(REACT_AGGRESSIVE); phase = PHASE_ONE; events.SetPhase(PHASE_ONE); events.RescheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT / 2, 0, PHASE_ONE); events.RescheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB, 0, PHASE_ONE); events.RescheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX)*2, 0, PHASE_ONE); Unit* heart = FindHeart(); if (!heart) return; heart->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE); heart->RemoveAurasDueToSpell(SPELL_EXPOSED_HEART); if (!hardMode) { if (!transferHealth) // Not settled == heart did not die if ( uint32 healthDiff = (heart->GetMaxHealth() - heart->GetHealth()) ) { me->DealDamage(me, healthDiff); me->LowerPlayerDamageReq(healthDiff); } // Note: if the heart did not go down enough or the players sucked too much (heal through bots), we may have jumped back in heart-phase // Otherwise, damage to the heart got mirrored to the XT002, thus one or more of the heart-phases can be excluded. RecalcHeartPhase(); } }
void Reset() { for(uint8 i = 0; i < 2; ++i) { if(PortalGUID[i]) { Unit* Portal = Unit::GetUnit((*me), PortalGUID[i]); if(Portal) Portal->DealDamage(Portal, Portal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); PortalGUID[i] = 0; } } CheckKilrekTimer = 30000; SacrificeTimer = 30000; ShadowboltTimer = 5000; SummonTimer = 10000; BerserkTimer = 600000; SummonedPortals = false; Berserk = false; if (pInstance) pInstance->SetData(TYPE_TERESTIAN, NOT_STARTED); me->RemoveAurasDueToSpell(SPELL_BROKEN_PACT); if (Minion* Kilrek = me->GetFirstMinion()) { if (!Kilrek->isAlive()) { Kilrek->UnSummon(); DoCast(me, SPELL_SUMMON_IMP, true); } } else DoCast(me, SPELL_SUMMON_IMP, true); }
uint32 NextStep(uint32 Step) { Unit* Spark = Unit::GetUnit((*me), SparkGUID); switch(Step) { case 0: return 99999; case 1: //DespawnNagaFlag(true); DoScriptText(EMOTE_SPARK, Spark); return 1000; case 2: DoScriptText(GEEZLE_SAY_1, me, Spark); if (Spark) { Spark->SetInFront(me); me->SetInFront(Spark); } return 5000; case 3: DoScriptText(SPARK_SAY_2, Spark); return 7000; case 4: DoScriptText(SPARK_SAY_3, Spark); return 8000; case 5: DoScriptText(GEEZLE_SAY_4, me, Spark); return 8000; case 6: DoScriptText(SPARK_SAY_5, Spark); return 9000; case 7: DoScriptText(SPARK_SAY_6, Spark); return 8000; case 8: DoScriptText(GEEZLE_SAY_7, me, Spark); return 2000; case 9: me->GetMotionMaster()->MoveTargetedHome(); if (Spark) Spark->GetMotionMaster()->MovePoint(0, -5030.95f, -11291.99f, 7.97f); return 20000; case 10: if (Spark) Spark->DealDamage(Spark,Spark->GetHealth(),NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); //DespawnNagaFlag(false); me->SetVisibility(VISIBILITY_OFF); default: return 99999999; } }
bool PlayerbotShamanAI::HealGroup (Unit *target, uint8 hp, uint8 &countNeedHeal) { Player *m_bot = GetPlayerBot(); if (countNeedHeal < 2) { return false; } Unit *rTarget = DoSelectLowestHpFriendly(30,500); if (!rTarget || rTarget->isDead() || rTarget->GetHealth() * 100 / rTarget->GetMaxHealth() > 80 ) { return false; } if (hp < 65 && RIPTIDE && rTarget->HasAura(RIPTIDE,m_bot->GetGUID()) && CastSpell(CHAIN_HEAL, rTarget)) { return true; } if (hp < 85 && CastSpell(RIPTIDE, rTarget)) { return true; } if (hp < 75 && CastSpell(CHAIN_HEAL, rTarget,true,true)) { return true; } return false; }
void Absorb(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount) { Unit* caster = GetCaster(); if (!caster) return; int32 remainingHealth = caster->GetHealth() - dmgInfo.GetDamage(); int32 cauterizeHeal = caster->CountPctFromMaxHealth(40); if (caster->ToPlayer()->HasSpellCooldown(SPELL_MAGE_CAUTERIZE_DAMAGE)) return; if (!roll_chance_i(absorbChance)) return; if (remainingHealth <= 0) { absorbAmount = dmgInfo.GetDamage(); caster->CastCustomSpell(caster, SPELL_MAGE_CAUTERIZE_DAMAGE, NULL,&cauterizeHeal, NULL, true, NULL, aurEff); caster->ToPlayer()->AddSpellCooldown(SPELL_MAGE_CAUTERIZE_DAMAGE, 0, time(NULL) + 60); } }
void PlayerbotPaladinAI::DoNonCombatActions() { PlayerbotAI *ai = GetAI(); Player *m_bot = GetPlayerBot(); if (!m_bot || !ai || m_bot->isDead()) { return; } //If Casting or Eating/Drinking return if (m_bot->HasUnitState(UNIT_STATE_CASTING)) { return; } if (m_bot->getStandState() == UNIT_STAND_STATE_SIT) { return; } //buff and heal raid if (DoSupportRaid(m_bot)) { return; } //heal pets and bots Unit *target = DoSelectLowestHpFriendly(40, 1000); if (target && target->isAlive() && HealTarget(target, target->GetHealth()*100 / target->GetMaxHealth())) { return; } //mana/hp check //Don't bother with eating, if low on hp, just let it heal themself if (m_bot->getRace() == (uint8) RACE_UNDEAD_PLAYER && ai->GetHealthPercent() < 75 && CastSpell(R_CANNIBALIZE,m_bot)) { return; } if (m_bot->GetHealth() < m_bot->GetMaxHealth() && CastSpell(FLASH_OF_LIGHT,m_bot)) { return; } if (ai->GetManaPercent() < 70) { ai->Feast(); } } //end DoNonCombatActions
void HandleDamage() { Unit* caster = GetCaster(); if (caster->GetTypeId() != TYPEID_PLAYER) return; Unit* target = GetHitUnit(); int32 damage = GetHitDamage(); // Glyph cooldown reset when target was failed to kill if (AuraEffect* glyph = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 1980, EFFECT_0)) if (target && target->GetHealthPct() <= glyph->GetAmount() && !caster->HasAura(95652)) if (int32(target->GetHealth()) > damage) { caster->ToPlayer()->RemoveSpellCooldown(32379, true); caster->CastSpell(caster, 95652, true); } // Pain and Suffering reduces damage if (AuraEffect* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, PRIEST_ICON_ID_PAIN_AND_SUFFERING, EFFECT_1)) AddPct(damage, aurEff->GetAmount()); caster->CastCustomSpell(caster, SPELL_PRIEST_SHADOW_WORD_DEATH, &damage, 0, 0, true); }
void SetPhaseOne() { Talk(SAY_HEART_CLOSED); Talk(EMOTE_HEART_CLOSED); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->SetReactState(REACT_AGGRESSIVE); DoCastSelf(SPELL_STAND); _phase = 1; events.RescheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT / 2); events.RescheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB); events.RescheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX)); Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT_EXPOSED) : nullptr; if (!heart) return; heart->CastSpell(me, SPELL_HEART_RIDE_VEHICLE, true); heart->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); heart->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29); heart->RemoveAurasDueToSpell(SPELL_EXPOSED_HEART); if (!_hardMode) { if (!_transferHealth) _transferHealth = (heart->GetMaxHealth() - heart->GetHealth()); if (_transferHealth >= me->GetHealth()) _transferHealth = me->GetHealth() - 1; me->ModifyHealth(-((int32)_transferHealth)); me->LowerPlayerDamageReq(_transferHealth); } }
void UpdateAI(const uint32 diff) { if (!Vorpil) { me->DealDamage(me, me->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); return; } if (move <= diff) { if (sacrificed) { SpellEntry* spell = (SpellEntry*)GetSpellStore()->LookupEntry(HeroicMode ? H_SPELL_EMPOWERING_SHADOWS : SPELL_EMPOWERING_SHADOWS); if (spell) Vorpil->AddAura(new EmpoweringShadowsAura(spell, 0, NULL, Vorpil, me)); Vorpil->SetHealth(Vorpil->GetHealth() + Vorpil->GetMaxHealth() / 25); DoCast(me, SPELL_SHADOW_NOVA, true); me->DealDamage(me, me->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); return; } me->GetMotionMaster()->MoveFollow(Vorpil, 0, 0); if (me->GetDistance(Vorpil) < 3) { DoCast(me, SPELL_SACRIFICE, false); sacrificed = true; move = 500; return; } if (!Vorpil->IsInCombat() || Vorpil->isDead()) { me->DealDamage(me, me->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); return; } move = 1000; } else move -= diff; }
void UpdateAI(const uint32 diff) { if (!ArchimondeGUID) { if (pInstance) ArchimondeGUID = pInstance->GetData64(DATA_ARCHIMONDE); } if (CheckTimer <= diff) { if (ArchimondeGUID) { Unit* Archimonde = Unit::GetUnit((*me), ArchimondeGUID); if (Archimonde) { if ((((Archimonde->GetHealth()*100) / Archimonde->GetMaxHealth()) < 2) || !Archimonde->isAlive()) DoCast(me, SPELL_DENOUEMENT_WISP); else DoCast(Archimonde, SPELL_ANCIENT_SPARK); } } CheckTimer = 1000; } else CheckTimer -= diff; }
void DestroyPortals() { //we destroy portals during banish phase or when we die Unit* BeamerD = NULL; Unit* BeamerDhelp = NULL; BeamerD = Unit::GetUnit((*m_creature), BeamerGUID[0]); BeamerDhelp = Unit::GetUnit((*m_creature), BeamerhelpGUID[0]); if (BeamerD && BeamerD->isAlive()) { BeamerD->DealDamage(BeamerD, BeamerD->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); BeamerGUID[0] = 0; } if (BeamerDhelp && BeamerDhelp->isAlive()) { BeamerDhelp->DealDamage(BeamerDhelp, BeamerDhelp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); BeamerhelpGUID[0] = 0; } Unit* BeamerS = NULL; Unit* BeamerShelp = NULL; BeamerS = Unit::GetUnit((*m_creature), BeamerGUID[1]); BeamerShelp = Unit::GetUnit((*m_creature), BeamerhelpGUID[1]); if (BeamerS && BeamerS->isAlive()) { BeamerS->DealDamage(BeamerS, BeamerS->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); BeamerGUID[1] = 0; } if (BeamerShelp && BeamerShelp->isAlive()) { BeamerShelp->DealDamage(BeamerShelp, BeamerShelp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); BeamerhelpGUID[1] = 0; } Unit* BeamerP = NULL; Unit* BeamerPhelp = NULL; BeamerP = Unit::GetUnit((*m_creature), BeamerGUID[2]); BeamerPhelp = Unit::GetUnit((*m_creature), BeamerhelpGUID[2]); if (BeamerP && BeamerP->isAlive()) { BeamerP->DealDamage(BeamerP, BeamerP->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); BeamerGUID[2] = 0; } if (BeamerPhelp && BeamerPhelp->isAlive()) { BeamerPhelp->DealDamage(BeamerPhelp, BeamerPhelp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); BeamerhelpGUID[2] = 0; } }
/*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/ void WorldSession::HandleRequestPartyMemberStatsOpcode( WorldPacket &recv_data ) { DEBUG_LOG("WORLD: Received CMSG_REQUEST_PARTY_MEMBER_STATS"); uint64 Guid; recv_data >> Guid; Player *player = sObjectMgr.GetPlayer(Guid); if(!player) { WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 3+4+2); data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related data.appendPackGUID(Guid); data << uint32(GROUP_UPDATE_FLAG_STATUS); data << uint16(MEMBER_STATUS_OFFLINE); SendPacket(&data); return; } Unit *pet = player->GetCharmOrPet(); WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8); data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related data << player->GetPackGUID(); uint32 mask1 = 0x00040BFF; // common mask, real flags used 0x000040BFF if(pet) mask1 = 0xFFFFFFFF; // for hunters and other classes with pets Powers powerType = player->getPowerType(); data << uint32(mask1); // group update mask data << uint16(MEMBER_STATUS_ONLINE); // member's online status data << uint32(player->GetHealth()); // GROUP_UPDATE_FLAG_CUR_HP data << uint32(player->GetMaxHealth()); // GROUP_UPDATE_FLAG_MAX_HP data << uint8(powerType); // GROUP_UPDATE_FLAG_POWER_TYPE data << uint16(player->GetPower(powerType)); // GROUP_UPDATE_FLAG_CUR_POWER data << uint16(player->GetMaxPower(powerType)); // GROUP_UPDATE_FLAG_MAX_POWER data << uint16(player->getLevel()); // GROUP_UPDATE_FLAG_LEVEL data << uint16(player->GetZoneId()); // GROUP_UPDATE_FLAG_ZONE data << uint16(player->GetPositionX()); // GROUP_UPDATE_FLAG_POSITION data << uint16(player->GetPositionY()); // GROUP_UPDATE_FLAG_POSITION uint64 auramask = 0; size_t maskPos = data.wpos(); data << uint64(auramask); // placeholder for(uint8 i = 0; i < MAX_AURAS; ++i) { if(uint32 aura = player->GetVisibleAura(i)) { auramask |= (uint64(1) << i); data << uint32(aura); data << uint8(1); } } data.put<uint64>(maskPos, auramask); // GROUP_UPDATE_FLAG_AURAS if(pet) { Powers petpowertype = pet->getPowerType(); data << pet->GetObjectGuid(); // GROUP_UPDATE_FLAG_PET_GUID data << pet->GetName(); // GROUP_UPDATE_FLAG_PET_NAME data << uint16(pet->GetDisplayId()); // GROUP_UPDATE_FLAG_PET_MODEL_ID data << uint32(pet->GetHealth()); // GROUP_UPDATE_FLAG_PET_CUR_HP data << uint32(pet->GetMaxHealth()); // GROUP_UPDATE_FLAG_PET_MAX_HP data << uint8(petpowertype); // GROUP_UPDATE_FLAG_PET_POWER_TYPE data << uint16(pet->GetPower(petpowertype)); // GROUP_UPDATE_FLAG_PET_CUR_POWER data << uint16(pet->GetMaxPower(petpowertype)); // GROUP_UPDATE_FLAG_PET_MAX_POWER uint64 petauramask = 0; size_t petMaskPos = data.wpos(); data << uint64(petauramask); // placeholder for(uint8 i = 0; i < MAX_AURAS; ++i) { if(uint32 petaura = pet->GetVisibleAura(i)) { petauramask |= (uint64(1) << i); data << uint32(petaura); data << uint8(1); } } data.put<uint64>(petMaskPos, petauramask); // GROUP_UPDATE_FLAG_PET_AURAS data << (uint32) player->m_movementInfo.GetTransportDBCSeat(); } else { data << uint8(0); // GROUP_UPDATE_FLAG_PET_NAME data << uint64(0); // GROUP_UPDATE_FLAG_PET_AURAS } SendPacket(&data); }
void WorldSession::BuildPartyMemberStatsChangedPacket(Player *player, WorldPacket *data) { uint32 mask = player->GetGroupUpdateFlag(); if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) // if update power type, update current/max power also mask |= (GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER); if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) // same for pets mask |= (GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER); uint32 byteCount = 0; for (int i = 1; i < GROUP_UPDATE_FLAGS_COUNT; ++i) if (mask & (1 << i)) byteCount += GroupUpdateLength[i]; data->Initialize(SMSG_PARTY_MEMBER_STATS, 8 + 4 + byteCount); *data << player->GetPackGUID(); *data << uint32(mask); if (mask & GROUP_UPDATE_FLAG_STATUS) { if (player) { if (player->IsPvP()) *data << uint16(MEMBER_STATUS_ONLINE | MEMBER_STATUS_PVP); else *data << uint16(MEMBER_STATUS_ONLINE); } else *data << uint16(MEMBER_STATUS_OFFLINE); } if (mask & GROUP_UPDATE_FLAG_CUR_HP) *data << uint32(player->GetHealth()); if (mask & GROUP_UPDATE_FLAG_MAX_HP) *data << uint32(player->GetMaxHealth()); Powers powerType = player->getPowerType(); if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) *data << uint8(powerType); if (mask & GROUP_UPDATE_FLAG_CUR_POWER) *data << uint16(player->GetPower(powerType)); if (mask & GROUP_UPDATE_FLAG_MAX_POWER) *data << uint16(player->GetMaxPower(powerType)); if (mask & GROUP_UPDATE_FLAG_LEVEL) *data << uint16(player->getLevel()); if (mask & GROUP_UPDATE_FLAG_ZONE) *data << uint16(player->GetZoneId()); if (mask & GROUP_UPDATE_FLAG_POSITION) *data << uint16(player->GetPositionX()) << uint16(player->GetPositionY()); if (mask & GROUP_UPDATE_FLAG_AURAS) { const uint64& auramask = player->GetAuraUpdateMask(); *data << uint64(auramask); for(uint32 i = 0; i < MAX_AURAS; ++i) { if(auramask & (uint64(1) << i)) { *data << uint32(player->GetVisibleAura(i)); *data << uint8(1); } } } Unit *pet = player->GetCharmOrPet(); if (mask & GROUP_UPDATE_FLAG_PET_GUID) *data << (pet ? pet->GetObjectGuid() : ObjectGuid()); if (mask & GROUP_UPDATE_FLAG_PET_NAME) { if(pet) *data << pet->GetName(); else *data << uint8(0); } if (mask & GROUP_UPDATE_FLAG_PET_MODEL_ID) { if(pet) *data << uint16(pet->GetDisplayId()); else *data << uint16(0); } if (mask & GROUP_UPDATE_FLAG_PET_CUR_HP) { if(pet) *data << uint32(pet->GetHealth()); else *data << uint32(0); } if (mask & GROUP_UPDATE_FLAG_PET_MAX_HP) { if(pet) *data << uint32(pet->GetMaxHealth()); else *data << uint32(0); } if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) { if(pet) *data << uint8(pet->getPowerType()); else *data << uint8(0); } if (mask & GROUP_UPDATE_FLAG_PET_CUR_POWER) { if(pet) *data << uint16(pet->GetPower(pet->getPowerType())); else *data << uint16(0); } if (mask & GROUP_UPDATE_FLAG_PET_MAX_POWER) { if(pet) *data << uint16(pet->GetMaxPower(pet->getPowerType())); else *data << uint16(0); } if (mask & GROUP_UPDATE_FLAG_PET_AURAS) { if(pet) { const uint64& auramask = pet->GetAuraUpdateMask(); *data << uint64(auramask); for(uint32 i = 0; i < MAX_AURAS; ++i) { if(auramask & (uint64(1) << i)) { *data << uint32(pet->GetVisibleAura(i)); *data << uint8(1); } } } else *data << uint64(0); } if (mask & GROUP_UPDATE_FLAG_VEHICLE_SEAT) { *data << (uint32) player->m_movementInfo.GetTransportDBCSeat(); } }
void UpdateAI(const uint32 diff) { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (!DrainingCrystal) { uint32 maxPowerMana = m_creature->GetMaxPower(POWER_MANA); if (maxPowerMana && ((m_creature->GetPower(POWER_MANA)*100 / maxPowerMana) < 10)) { if (DrainLifeTimer < diff) { DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DRAIN_LIFE); DrainLifeTimer = 10000; }else DrainLifeTimer -= diff; // Heroic only if (!m_bIsRegularMode) { if (DrainManaTimer < diff) { DoCast(SelectUnit(SELECT_TARGET_RANDOM, 1), SPELL_DRAIN_MANA); DrainManaTimer = 10000; }else DrainManaTimer -= diff; } } if (FelExplosionTimer < diff) { if (!m_creature->IsNonMeleeSpellCasted(false)) { DoCast(m_creature, SPELL_FEL_EXPLOSION); FelExplosionTimer = 2000; } }else FelExplosionTimer -= diff; // If below 10% mana, start recharging maxPowerMana = m_creature->GetMaxPower(POWER_MANA); if (maxPowerMana && ((m_creature->GetPower(POWER_MANA)*100 / maxPowerMana) < 10)) { if (DrainCrystalTimer < diff) { SelectNearestCrystal(); if (m_bIsRegularMode) DrainCrystalTimer = urand(20000, 25000); else DrainCrystalTimer = urand(10000, 15000); }else DrainCrystalTimer -= diff; } }else { if (IsDraining) { if (EmpowerTimer < diff) { IsDraining = false; DrainingCrystal = false; DoScriptText(SAY_EMPOWERED, m_creature); Unit* CrystalChosen = Unit::GetUnit(*m_creature, CrystalGUID); if (CrystalChosen && CrystalChosen->isAlive()) // Use Deal Damage to kill it, not setDeathState. CrystalChosen->DealDamage(CrystalChosen, CrystalChosen->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); CrystalGUID = 0; m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); }else EmpowerTimer -= diff; } } DoMeleeAttackIfReady(); // No need to check if we are draining crystal here, as the spell has a stun. }
void PetAI::UpdateAI(const uint32 diff) { if (!m_creature->isAlive()) return; Unit* owner = m_creature->GetCharmerOrOwner(); m_updateAlliesTimer.Update(diff); if (m_updateAlliesTimer.Passed()) { UpdateAllies(); m_updateAlliesTimer.Reset(); } if (!inCombat && !m_savedTargetGuid.IsEmpty()) { if (Unit* saved_target = m_creature->GetMap()->GetUnit(m_savedTargetGuid)) { if (!saved_target->isAlive()) m_savedTargetGuid.Clear(); else if (!saved_target->IsCrowdControlled()) AttackStart(saved_target); } else m_savedTargetGuid.Clear(); } if (inCombat && (!m_creature->getVictim() || !m_creature->getVictim()->isAlive() || (m_creature->IsPet() && m_creature->GetCharmInfo()->HasState(CHARM_STATE_ACTION, ACTIONS_DISABLE)))) _stopAttack(); if (m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT) || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED)) { UpdateAIType(); return; } // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc. if (m_creature->getVictim()) { bool meleeReach = m_creature->CanReachWithMeleeAttack(m_creature->getVictim()); if (_needToStop()) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI (guid = %u) is stopping attack.", m_creature->GetGUIDLow()); _stopAttack(); return; } else if (!m_creature->getVictim()->isAlive()) // Stop attack if target dead { m_creature->InterruptNonMeleeSpells(false); _stopAttack(); return; } else if (sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI) && IsInCombat() && m_creature->getVictim() && m_creature->getVictim()->IsCrowdControlled()) // Stop attack if target under CC effect { m_savedTargetGuid = m_creature->getVictim()->GetObjectGuid(); m_creature->InterruptSpell(CURRENT_GENERIC_SPELL, true); if (!m_creature->IsNonMeleeSpellCasted(false, false, true)) _stopAttack(); return; } else if (m_creature->IsStopped() || meleeReach) { // required to be stopped cases if (m_creature->IsStopped() && m_creature->IsNonMeleeSpellCasted(false)) { if (m_creature->hasUnitState(UNIT_STAT_FOLLOW_MOVE)) m_creature->InterruptNonMeleeSpells(false); else return; } // not required to be stopped case else if (DoMeleeAttackIfReady()) { if (!m_creature->getVictim()) return; //if pet misses its target, it will also be the first in threat list m_creature->getVictim()->AddThreat(m_creature); if (_needToStop()) _stopAttack(); } } if (!m_creature->IsNonMeleeSpellCasted(true)) { m_attackDistanceRecheckTimer.Update(diff); if (m_attackDistanceRecheckTimer.Passed()) { m_attackDistanceRecheckTimer.Reset(); if (sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI) && m_AIType == PET_AI_RANGED) { float dist = m_creature->GetDistance(m_creature->getVictim()); if ((m_creature->CanReachWithMeleeAttack(m_creature->getVictim()) && m_creature->IsWithinDist(m_creature->GetOwner(), m_creature->GetMap()->GetVisibilityDistance() / 2.0f)) || dist > (m_attackDistance + 2.0f)) { MoveToVictim(m_creature->getVictim()); return; } } if (sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI)) { // AOE check } } } } else if (Unit* target = GetPrimaryTarget()) { AttackStart(target); } else if (owner && owner->IsInCombat()) { switch (m_creature->GetCharmState(CHARM_STATE_REACT)) { case REACT_DEFENSIVE: { if (!m_creature->getVictim() || !m_creature->getVictim()->isAlive() || (m_primaryTargetGuid.IsEmpty() && owner->getVictim() != m_creature->getVictim() && owner->getVictim()->isAlive())) AttackStart(owner->getAttackerForHelper()); break; } case REACT_AGGRESSIVE: { if (!m_creature->getVictim() || !m_creature->getVictim()->isAlive()) AttackStart(owner->getAttackerForHelper()); break; } case REACT_PASSIVE: default: break; } } UpdateAIType(); if (m_creature->IsNonMeleeSpellCasted(true)) return; // Autocast (casted only in combat or persistent spells in any state) if (!sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI) && m_AIType != PET_AI_PASSIVE) { typedef std::vector<std::pair<ObjectGuid, uint32> > TargetSpellList; TargetSpellList targetSpellStore; for (uint8 i = 0; i < m_creature->GetPetAutoSpellSize(); ++i) { uint32 spellID = m_creature->GetPetAutoSpellOnPos(i); if (!spellID) continue; SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellID); if (!spellInfo) continue; if (m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) continue; if (m_creature->HasSpellCooldown(spellInfo)) continue; // ignore some combinations of combat state and combat/noncombat spells if (!inCombat) { // ignore attacking spells, and allow only self/around spells if (!IsPositiveSpell(spellInfo->Id)) continue; // non combat spells allowed // only pet spells have IsNonCombatSpell and not fit this reqs: // Consume Shadows, Lesser Invisibility, so ignore checks for its if (!IsNonCombatSpell(spellInfo)) { // allow only spell without spell cost or with spell cost but not duration limit int32 duration = GetSpellDuration(spellInfo); if ((spellInfo->manaCost || spellInfo->ManaCostPercentage || spellInfo->manaPerSecond) && duration > 0) continue; // allow only spell without cooldown > duration int32 cooldown = GetSpellRecoveryTime(spellInfo); if (cooldown >= 0 && duration >= 0 && cooldown > duration) continue; } } else { // just ignore non-combat spells if (IsNonCombatSpell(spellInfo)) continue; } Unit* autoCastTarget = NULL; if (inCombat && m_creature->getVictim() && !m_creature->hasUnitState(UNIT_STAT_FOLLOW)) { SpellCastResult result = CanAutoCast(m_creature->getVictim(), spellInfo); if (result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT) autoCastTarget = m_creature->getVictim(); } if (!autoCastTarget) { for (GuidSet::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar) { Unit* target = m_creature->GetMap()->GetUnit(*tar); // Only buff targets that are in combat, unless the spell can only be cast while out of combat if (!target) continue; SpellCastResult result = CanAutoCast(target, spellInfo); if (result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT) { autoCastTarget = target; break; } } } if (autoCastTarget) targetSpellStore.push_back(TargetSpellList::value_type(autoCastTarget->GetObjectGuid(), spellInfo->Id)); } // found units to cast on to if (!targetSpellStore.empty()) { uint32 index = urand(0, targetSpellStore.size() - 1); if (Unit* target = m_creature->GetMap()->GetUnit(targetSpellStore[index].first)) m_creature->DoPetCastSpell(target, targetSpellStore[index].second); } } else { AutoSpellList currentSpells; switch (m_AIType) { case PET_AI_PASSIVE: { currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); break; } case PET_AI_SLACKER: { if (!IsInCombat()) break; if (m_creature->IsCrowdControlled() || (owner && owner->IsCrowdControlled())) currentSpells.push_back(GetSpellType(PET_SPELL_FREEACTION)); currentSpells.push_back(GetSpellType(PET_SPELL_DEFENCE)); currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_DEBUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_RANGED)); break; } case PET_AI_HEALER: { if (!IsInCombat()) break; if (m_creature->IsCrowdControlled() || (owner && owner->IsCrowdControlled())) currentSpells.push_back(GetSpellType(PET_SPELL_FREEACTION)); if (m_creature->GetHealth() < m_creature->GetMaxHealth() || (owner && (owner->GetHealth() < owner->GetMaxHealth()))) currentSpells.push_back(GetSpellType(PET_SPELL_HEAL)); currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_RANGED)); break; } case PET_AI_RANGED: { if (!IsInCombat()) break; if (m_creature->IsCrowdControlled() || (owner && owner->IsCrowdControlled())) currentSpells.push_back(GetSpellType(PET_SPELL_FREEACTION)); currentSpells.push_back(GetSpellType(PET_SPELL_RANGED)); currentSpells.push_back(GetSpellType(PET_SPELL_DEBUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); break; } case PET_AI_MELEE: case PET_AI_RANGED_NOAMMO: { if (!IsInCombat()) break; if (Unit* victim = m_creature->getVictim()) { if (!victim->getVictim() || (victim->getVictim()->GetObjectGuid() != m_creature->GetObjectGuid())) { currentSpells.push_back(GetSpellType(PET_SPELL_ATTACKSTART)); currentSpells.push_back(GetSpellType(PET_SPELL_THREAT)); } } if (m_creature->IsCrowdControlled() || (owner && owner->IsCrowdControlled())) currentSpells.push_back(GetSpellType(PET_SPELL_FREEACTION)); } /* no break here!*/ default: { if (!IsInCombat()) break; currentSpells.push_back(GetSpellType(PET_SPELL_MELEE)); currentSpells.push_back(GetSpellType(PET_SPELL_DEBUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_RANGED)); currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); break; } } if (!IsInCombat()) { currentSpells.push_back(GetSpellType(PET_SPELL_NONCOMBAT)); if (m_creature->GetHealthPercent() < 95.0f) currentSpells.push_back(GetSpellType(PET_SPELL_HEAL)); } else currentSpells.push_back(GetSpellType(PET_SPELL_SPECIAL)); for (AutoSpellList::const_iterator itr = currentSpells.begin(); itr != currentSpells.end(); ++itr) { uint32 spellID = *itr; if (!spellID) continue; SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellID); if (!spellInfo) continue; if (m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) continue; Unit* pTarget = m_creature->IsPet() ? ((Pet*)m_creature)->SelectPreferredTargetForSpell(spellInfo) : ((Creature*)m_creature)->SelectPreferredTargetForSpell(spellInfo); bool b_castOk = false; if (pTarget) { SpellCastResult result = CanAutoCast(pTarget, spellInfo); DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS,"PetAI::Update %s, AI %u try cast %u Target %s", m_creature->GetGuidStr().c_str(), m_AIType, spellID, pTarget ? pTarget->GetGuidStr().c_str() : "<none>"); switch (result) { case SPELL_FAILED_UNIT_NOT_INFRONT: { if (DoCastSpellIfCan(pTarget, spellID) == CAST_OK) { b_castOk = true; m_creature->SetInFront(pTarget); if (pTarget->GetTypeId() == TYPEID_PLAYER) m_creature->SendCreateUpdateToPlayer((Player*)pTarget); } break; } case SPELL_CAST_OK: { if (DoCastSpellIfCan(pTarget, spellID) == CAST_OK) b_castOk = true; break; } default: { Player* owner = (Player*)m_creature->GetOwner(); if (owner) Spell::SendCastResult(owner,spellInfo,0,result, true); DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS,"PetAI::Update cast %s, AI %u Target %s spell %u result %u", m_creature->GetGuidStr().c_str(), m_AIType, pTarget ? pTarget->GetGuidStr().c_str() : "<none>", spellID, result); break; } } } else continue; if (b_castOk) { m_creature->AddSpellAndCategoryCooldowns(spellInfo); if (m_creature->IsPet()) { if(((Pet*)m_creature)->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) m_creature->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); else m_creature->SendPetAIReaction(); } break; } } } }
void UpdateAI (const uint32 diff) { if (!UpdateVictim()) return; if (PhaseTwo) { me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->setDeathState(JUST_DIED); me->SetHealth(0); me->GetMotionMaster()->Clear(); me->clearUnitState(UNIT_STAT_ALL_STATE); me->LoadCreaturesAddon(true); return; } if (LorkhanDead) return; // Resurrect if (ThekalDead || ZathDead) if (!IsResurrecting && (CheckDeath_Timer - 2000) <= diff) { if (ZathDead) if (Unit* pZath = Unit::GetUnit(*me, ZathGUID)) pZath->CastSpell(pZath, SPELL_RESURRECT, false, 0, 0, pZath->GetGUID()); if (ThekalDead) if (Unit* pThekal = Unit::GetUnit(*me, ThekalGUID)) pThekal->CastSpell(pThekal, SPELL_RESURRECT, false, 0, 0, pThekal->GetGUID()); IsResurrecting = true; } else if (ThekalDead) CheckDeath_Timer -= diff; // Shield Timer if (Shield_Timer <= diff) { DoCast(me, SPELL_SHIELD); Shield_Timer = 61000; } else Shield_Timer -= diff; // BloodLust Timer if (BloodLust_Timer <= diff) { DoCast(me, SPELL_BLOODLUST); BloodLust_Timer = 20000 + rand()%8000; } else BloodLust_Timer -= diff; // Cast Greater heal on Thekal or Zath if they are in melee range. if (GreaterHeal_Timer <= diff) { if (instance) { Unit *pThekal = Unit::GetUnit((*me), ThekalGUID); Unit *pZath = Unit::GetUnit((*me), ZathGUID); if (!pThekal || !pZath) return; // Might use a loop and a vector in the future // Target lowest ally in range if (me->IsWithinMeleeRange(pThekal) && me->IsWithinMeleeRange(pZath)) if ((pThekal->GetHealth() / pThekal->GetMaxHealth()) < (pZath->GetHealth() / pZath->GetMaxHealth())) if ((pThekal->GetHealth() / pThekal->GetMaxHealth()) < (me->GetHealth() / me->GetMaxHealth())) DoCast(pThekal, SPELL_GREATERHEAL); else DoCast(me, SPELL_GREATERHEAL); else if ((pZath->GetHealth() / pZath->GetMaxHealth()) < (me->GetHealth() / me->GetMaxHealth())) DoCast(pZath, SPELL_GREATERHEAL); else DoCast(me, SPELL_GREATERHEAL); else if (me->IsWithinMeleeRange(pThekal) && !me->IsWithinMeleeRange(pZath)) if ((pThekal->GetHealth() / pThekal->GetMaxHealth()) < (me->GetHealth() / me->GetMaxHealth())) DoCast(pThekal, SPELL_GREATERHEAL); else DoCast(me, SPELL_GREATERHEAL); else if (!me->IsWithinMeleeRange(pThekal) && me->IsWithinMeleeRange(pZath)) if ((pZath->GetHealth() / pZath->GetMaxHealth()) < (me->GetHealth() / me->GetMaxHealth())) DoCast(pZath, SPELL_GREATERHEAL); else DoCast(me, SPELL_GREATERHEAL); else if (!me->IsWithinMeleeRange(pThekal) && !me->IsWithinMeleeRange(pZath)) DoCast(me, SPELL_GREATERHEAL); } GreaterHeal_Timer = 15000 + rand()%5000; } else GreaterHeal_Timer -= diff; // Disarm Timer if (Disarm_Timer <= diff) { DoCast(me->getVictim(), SPELL_DISARM); Disarm_Timer = 15000 + rand()%10000; } else Disarm_Timer -= diff; DoMeleeAttackIfReady(); }
void PlayerbotShamanAI::DoNextCombatManeuver(Unit *pTarget) { if (!pTarget || pTarget->isDead()) return; PlayerbotAI *ai = GetAI(); if (!ai) return; Player *m_bot = GetPlayerBot(); if (!m_bot || m_bot->isDead()) return; Unit *pVictim = pTarget->getVictim(); Unit *m_tank = FindMainTankInRaid(GetMaster()); if (!m_tank && m_bot->GetGroup() && GetMaster()->GetGroup() != m_bot->GetGroup()) { FindMainTankInRaid(m_bot); } if (!m_tank) { m_tank = m_bot; } uint32 masterHP = GetMaster()->GetHealth()*100 / GetMaster()->GetMaxHealth(); float pDist = m_bot->GetDistance(pTarget); uint8 pThreat = GetThreatPercent(pTarget); uint8 reqHeal = 0; uint8 OwnPartyHP = GetHealthPercentRaid(m_bot, reqHeal); switch(ai->GetScenarioType()) { case SCENARIO_DUEL: ((ai->GetHealthPercent() < 80 && CastSpell(LESSER_HEAL)) || CastSpell(LIGHTNING_BOLT, pTarget)); return; } // Cast CC breakers if any match found (include any dispels first) does not work yet //uint32 ccSpells[4] = { R_ESCAPE_ARTIST, R_EVERY_MAN_FOR_HIMSELF, R_WILL_OF_FORSAKEN, R_STONEFORM }; //if (ai->GetManaPercent() < 35) { ccSpells[0] = 0; ccSpells[1] = 0; } //We dont have any mana to waste... //if (castSelfCCBreakers(ccSpells)) { } // Most of them don't trigger gcd #pragma region Choose Actions // Choose actions accoring to talents if (m_tank->GetGUID() == m_bot->GetGUID()) { m_role=BOT_ROLE_TANK; } // Hey! I am Main Tank else if (TALENT_ENHANCEMENT) { m_role = BOT_ROLE_DPS_MELEE; } else if (TALENT_ELEMENTAL) { m_role = BOT_ROLE_DPS_RANGED; } else if (TALENT_RESTO) { m_role = BOT_ROLE_SUPPORT; } else { m_role = BOT_ROLE_DPS_MELEE; } //Unknown build or low level.. Mainly attack // if i am under attack and if i am not tank or offtank: change target if needed if (m_tank->GetGUID() != m_bot->GetGUID() && isUnderAttack() ) { if (pVictim && pVictim->GetGUID() == m_bot->GetGUID() && pDist <= 2) { } // My target is almost up to me, no need to search else //Have to select nearest target { Unit *curAtt = GetNearestAttackerOf(m_bot); if (curAtt && curAtt->GetGUID() != pTarget->GetGUID()) { m_bot->SetSelection(curAtt->GetGUID()); //ai->AddLootGUID(curAtt->GetGUID()); DoNextCombatManeuver(curAtt); //Restart new update to get variables fixed.. return; } } //my target is attacking me } #pragma endregion // Choose Weapon Enchant if (ChangeWeaponEnchants()) return; if (TALENT_ELEMENTAL){ if (!m_bot->HasAura(WATER_SHIELD) && CastSpell(WATER_SHIELD,m_bot)) { return; }} if (TALENT_ENHANCEMENT){ if (!m_bot->HasAura(LIGHTNING_SHIELD) && CastSpell(LIGHTNING_SHIELD,m_bot)) { return; }} if (TALENT_RESTO){ if (!m_bot->HasAura(WATER_SHIELD) && CastSpell(WATER_SHIELD,m_bot)) { return; }} // Choose shield /* if (EARTH_SHIELD && ai->GetHealthPercent() < 80 && isUnderAttack()) { if (CastSpell(EARTH_SHIELD,m_bot)) { return; } } else if (WATER_SHIELD && ai->GetManaPercent() < 40) { if (CastSpell(WATER_SHIELD,m_bot)) { return; } } else if (LIGHTNING_SHIELD && ( isUnderAttack() || m_tank->GetGUID() == m_bot->GetGUID() ) && !(m_bot->HasAura(WATER_SHIELD) && ai->GetManaPercent() < 80) ) { if (CastSpell(LIGHTNING_SHIELD,m_bot)) { return; } } else if (CastSpell(WATER_SHIELD,m_bot)) { return; } */ // If there's a cast stop if(m_bot->HasUnitState(UNIT_STAT_CASTING)) return; switch(m_role) { #pragma region BOT_ROLE_TANK / BOT_ROLE_OFFTANK case BOT_ROLE_TANK: case BOT_ROLE_OFFTANK: if (!TALENT_ELEMENTAL && !TALENT_RESTO) { TakePosition(pTarget); } else { TakePosition(pTarget,BOT_ROLE_DPS_RANGED); } // mob will come to you sooner or later no need to hurry // Do support stuff if (!m_bot->isMoving() && ChangeTotems(m_role)) { return; } if (ai->GetManaPercent() > 70 && DoSupportRaid(m_bot)) { return; } break; #pragma endregion #pragma region BOT_ROLE_DPS_MELEE case BOT_ROLE_DPS_MELEE: TakePosition(pTarget); // Do support stuff if (!m_bot->isMoving() && ChangeTotems(m_role)) { return; } if (ai->GetManaPercent() > 40 && DoSupportRaid(m_bot)) { return; } break; #pragma endregion #pragma region BOT_ROLE_DPS_RANGED case BOT_ROLE_DPS_RANGED: TakePosition(pTarget); // Do support stuff if (!m_bot->isMoving() && ChangeTotems(m_role)) { return; } if (ai->GetManaPercent() > 40 && DoSupportRaid(m_bot)) { return; } break; #pragma endregion #pragma region BOT_ROLE_SUPPORT case BOT_ROLE_SUPPORT: TakePosition(pTarget); // Do support stuff if (!m_bot->isMoving() && ChangeTotems(m_role)) { return; } if (DoSupportRaid(m_bot)) { return; } //heal pets and bots Unit *target = DoSelectLowestHpFriendly(40, 1000); if(target && target->isAlive() && HealTarget(target, target->GetHealth()*100 / target->GetMaxHealth()) ) { return; } break; #pragma endregion } #pragma region ShamanCommon //Defensive Stuff if (m_tank->GetGUID() != m_bot->GetGUID() && pVictim && pVictim->GetGUID() == m_bot->GetGUID() ) { if (pDist > 5 && CastSpell(FROST_SHOCK, pTarget)) { return; } if ((pTarget->GetCreatureType() == (uint32) CREATURE_TYPE_BEAST || pTarget->GetCreatureType() == (uint32) CREATURE_TYPE_HUMANOID) && CastSpell(HEX, pTarget)) { return; } // no gcd if (CastSpell(WIND_SHEAR, pTarget)) { } // no gcd } if (m_bot->getRace() == (uint8) RACE_BLOODELF && pDist < 8 && pTarget->IsNonMeleeSpellCasted(true) && CastSpell(R_ARCANE_TORRENT, pTarget)) { } //no gcd if (pTarget->IsNonMeleeSpellCasted(true) && CastSpell(WIND_SHEAR, pTarget)) { } //no gcd if (m_bot->getRace() == (uint8) RACE_TAUREN && pVictim && pVictim->GetGUID() == m_bot->GetGUID() && pDist < 8 && CastSpell(R_WAR_STOMP, pTarget)) { return; } //Catch if (pTarget->HasUnitMovementFlag(UNIT_FLAG_FLEEING)) { if (CastSpell(FROST_SHOCK,pTarget)) return; } //Buff and restores if ( ( (ai->GetHealthPercent() < 60 && isUnderAttack()) || (ai->GetManaPercent() < 30) ) && CastSpell(SHAMANISTIC_RAGE, m_bot)) { return; } if (m_bot->getRace() == (uint8) RACE_TROLL && CastSpell(R_BERSERKING,m_bot)) {} // no GCD if (m_bot->getRace() == (uint8) RACE_ORC && CastSpell(R_BLOOD_FURY,m_bot)) {} // no GCD if (!m_bot->HasAura(HEROISM) && !m_bot->HasAura(EXHAUSTION) && !m_bot->HasAura(SATED) && CastSpell(HEROISM,m_bot)) { return; } if (m_role != BOT_ROLE_SUPPORT && CastSpell(NATURES_SWIFTNESS, m_bot)) { } //healers keep it for healing no gcd else if (CastSpell(ELEMENTAL_MASTERY, m_bot)) { } //no gcd // If at threat limit, use WIND_SHEAR to reduce threat if (pThreat > threatThreshold && m_tank->GetGUID() != m_bot->GetGUID() && !isUnderAttack()) { if (m_tank->getVictim() && m_tank->getVictim()->GetGUID() != pTarget->GetGUID()) // I am attacking wrong target!! { m_bot->SetSelection(m_tank->getVictim()->GetGUID()); return; } else { if (CastSpell(WIND_SHEAR,pTarget)) { return; } //Lets see if we can manage else { return; } //use no spells and wait threat to be reduced } } if (TALENT_ELEMENTAL) { if (CastSpell(ELEMENTAL_MASTERY, m_bot)) { } //no gcd if (!pTarget->HasAura(FLAME_SHOCK,m_bot->GetGUID()) && CastSpell(FLAME_SHOCK,pTarget)) { return; } if (CastSpell(LAVA_BURST,pTarget)) { return; } if (CastSpell(CHAIN_LIGHTNING,pTarget)) { return; } if (CastSpell(LIGHTNING_BOLT,pTarget)) { return; } } //dps if (MAELSTROM_WEAPON) { Aura *maelaura = m_bot->GetAura(MAELSTROM_WEAPON); if (maelaura && maelaura->GetStackAmount() == 5) { if ((isUnderAttack(m_tank,3) || m_tank->GetGUID() == m_bot->GetGUID()) && CastSpell(CHAIN_LIGHTNING,pTarget,true,true)) { return; } if (CastSpell(LIGHTNING_BOLT,pTarget,true,true)) { return; } } } if (CastSpell(FLAME_SHOCK,pTarget)) { return; } if (CastSpell(STORMSTRIKE,pTarget,true,true)) { return; } //if (!TALENT_ENHANCEMENT && CanCast(LAVA_BURST,pTarget,true) && pTarget->HasAura(FLAME_SHOCK,m_bot->GetGUID()) && CastSpell(LAVA_BURST,pTarget,false)) { return; } if (CastSpell(FERAL_SPIRIT,m_bot)) { return; } if (CanCast(EARTH_SHOCK,pTarget,true) && (pTarget->HasAura(STORMSTRIKE,m_bot->GetGUID()) || pTarget->HasAura(FLAME_SHOCK,m_bot->GetGUID()) ) && CastSpell(EARTH_SHOCK,pTarget)) { return; } //if (CanCast(FLAME_SHOCK,pTarget) && CastSpell(FLAME_SHOCK,pTarget)) { return; } if (CastSpell(LAVA_LASH,pTarget,true,true)) { return; } if (CastSpell(FIRE_NOVA,pTarget)) { return; } //if ((isUnderAttack(m_tank,4) || m_tank->GetGUID() == m_bot->GetGUID()) && CastSpell(FIRE_NOVA,pTarget)) { return; } if (ai->GetManaPercent() > 60 && castDispel(PURGE,pTarget)) { return; } //PURGE but dont overpurge #pragma endregion // drink potion if support / healer (Other builds simply overuse mana and waste mana pots) if(ai->GetManaPercent() < 5 && (m_role == BOT_ROLE_SUPPORT || m_role == BOT_ROLE_HEALER) ) { Item *pItem = ai->FindPotion(); if(pItem != NULL) { if (pItem->GetSpell() && m_bot->HasSpellCooldown(pItem->GetSpell()) ) { return; } //pot is in cooldown ai->UseItem(*pItem); } } } //end DoNextCombatManeuver
uint32 NextStep(uint32 Step) { Unit* arca = Unit::GetUnit(*me, ArcanagosGUID); Map* map = me->GetMap(); switch (Step) { case 0: return 9999999; case 1: me->MonsterYell(SAY_DIALOG_MEDIVH_1, LANG_UNIVERSAL, 0); return 10000; case 2: if (arca) CAST_CRE(arca)->MonsterYell(SAY_DIALOG_ARCANAGOS_2, LANG_UNIVERSAL, 0); return 20000; case 3: me->MonsterYell(SAY_DIALOG_MEDIVH_3, LANG_UNIVERSAL, 0); return 10000; case 4: if (arca) CAST_CRE(arca)->MonsterYell(SAY_DIALOG_ARCANAGOS_4, LANG_UNIVERSAL, 0); return 20000; case 5: me->MonsterYell(SAY_DIALOG_MEDIVH_5, LANG_UNIVERSAL, 0); return 20000; case 6: if (arca) CAST_CRE(arca)->MonsterYell(SAY_DIALOG_ARCANAGOS_6, LANG_UNIVERSAL, 0); return 10000; case 7: FireArcanagosTimer = 500; return 5000; case 8: FireMedivhTimer = 500; DoCast(me, SPELL_MANA_SHIELD); return 10000; case 9: me->MonsterTextEmote(EMOTE_DIALOG_MEDIVH_7, 0, false); return 10000; case 10: if (arca) DoCast(arca, SPELL_CONFLAGRATION_BLAST, false); return 1000; case 11: if (arca) CAST_CRE(arca)->MonsterYell(SAY_DIALOG_ARCANAGOS_8, LANG_UNIVERSAL, 0); return 5000; case 12: arca->GetMotionMaster()->MovePoint(0, -11010.82f, -1761.18f, 156.47f); arca->setActive(true); arca->InterruptNonMeleeSpells(true); arca->SetSpeed(MOVE_FLIGHT, 2.0f); return 10000; case 13: me->MonsterYell(SAY_DIALOG_MEDIVH_9, LANG_UNIVERSAL, 0); return 10000; case 14: me->SetVisible(false); me->ClearInCombat(); if (map->IsDungeon()) { InstanceMap::PlayerList const &PlayerList = map->GetPlayers(); for (InstanceMap::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) { if (i->getSource()->isAlive()) { if (i->getSource()->GetQuestStatus(9645) == QUEST_STATUS_INCOMPLETE) i->getSource()->CompleteQuest(9645); } } } return 50000; case 15: arca->DealDamage(arca, arca->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); return 5000; default : return 9999999; } }
void DoIntro() { if(!Madrigosa) return; switch(IntroPhase) { case 0: DoScriptText(YELL_MADR_ICE_BARRIER, Madrigosa); IntroPhaseTimer = 5000; ++IntroPhase; break; case 1: me->SetInFront(Madrigosa); Madrigosa->SetInFront(me); DoScriptText(YELL_MADR_INTRO, Madrigosa, me); IntroPhaseTimer = 9000; ++IntroPhase; break; case 2: DoScriptText(YELL_INTRO, me, Madrigosa); IntroPhaseTimer = 13000; ++IntroPhase; break; case 3: DoCast(me, SPELL_INTRO_FROST_BLAST); Madrigosa->SetLevitate(true); me->AttackStop(); Madrigosa->AttackStop(); IntroFrostBoltTimer = 3000; IntroPhaseTimer = 28000; ++IntroPhase; break; case 4: DoScriptText(YELL_INTRO_BREAK_ICE, me); IntroPhaseTimer = 6000; ++IntroPhase; break; case 5: Madrigosa->CastSpell(me, SPELL_INTRO_ENCAPSULATE_CHANELLING, false); DoScriptText(YELL_MADR_TRAP, Madrigosa); DoCast(me, SPELL_INTRO_ENCAPSULATE); IntroPhaseTimer = 11000; ++IntroPhase; break; case 6: me->SetSpeed(MOVE_RUN, 4.0f, true); DoScriptText(YELL_INTRO_CHARGE, me); IntroPhaseTimer = 3000; ++IntroPhase; break; case 7: me->DealDamage(Madrigosa, Madrigosa->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, true); DoScriptText(YELL_MADR_DEATH, Madrigosa); me->SetFullHealth(); me->AttackStop(); me->SetSpeed(MOVE_RUN, 1.0f, true); IntroPhaseTimer = 3000; ++IntroPhase; break; case 8: DoScriptText(YELL_INTRO_KILL_MADRIGOSA, me); me->SetOrientation(0.14f); Madrigosa->setDeathState(CORPSE); IntroPhaseTimer = 5000; ++IntroPhase; break; case 9: DoScriptText(YELL_INTRO_TAUNT, me); IntroPhaseTimer = 5000; ++IntroPhase; break; case 10: EndIntro(); break; } }
void UpdateAI(const uint32 diff) { if(!UpdateVictim()) return; if(Cleanse_Timer < diff ) { std::list<Creature*> pList = FindFriendlyCC(30); if (!pList.empty()) { Unit* target = *(pList.begin()); DoCast(target,SPELL_CLEANSE_BW_VINDICATOR); } Cleanse_Timer = 3000+rand()%1000; } else Cleanse_Timer -= diff; if(FlashofLight_Timer < diff) { Unit* target = SelectLowestHpFriendly(50, 1000); if(target) { DoCast(target,SPELL_FLASHOFLIGHT_BW_VINDICATOR); if(target->GetHealth() <= target->GetMaxHealth()*0.5) FlashofLight_Timer = 2000; else FlashofLight_Timer = 2000 +rand()%7000; } } else FlashofLight_Timer -= diff; if(HammerofJustice_Timer < diff) { DoCast(m_creature->getVictim(),SPELL_HAMMEROFJUSTICE_BW_VINDICATOR); HammerofJustice_Timer = 18000; } else HammerofJustice_Timer -= diff; if(HammerofWrath_Timer < diff) { Map* pMap = m_creature->GetMap(); Map::PlayerList const &PlayerList = pMap->GetPlayers(); if (!PlayerList.isEmpty()) { for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) { Player *p = i->getSource(); if(p->isAlive() && p->GetHealth() <= p->GetMaxHealth()*0.2) { DoCast(p, SPELL_HAMMEROFWRATH_BW_VINDICATOR); break; } } } HammerofWrath_Timer = 3000+rand()%2000; } else HammerofWrath_Timer -= diff; DoMeleeAttackIfReady(); }