void OnLoad() { if (_unit->IsSummon()) { Summon* s = TO< Summon* >(_unit); Unit* owner = s->GetOwner(); owner->CastSpell(_unit, 45204, true); // clone me owner->CastSpell(_unit, 58838, true); // inherit threat list // Mage mirror image spell if (_unit->GetCreatedBySpell() == 58833) { _unit->SetMaxHealth(2500); _unit->SetHealth(2500); _unit->SetMaxPower(POWER_TYPE_MANA, owner->GetMaxPower(POWER_TYPE_MANA)); _unit->SetPower(POWER_TYPE_MANA, owner->GetPower(POWER_TYPE_MANA)); SpellRange* range = NULL; AI_Spell sp1; sp1.entryId = 59638; sp1.spell = dbcSpell.LookupEntryForced(sp1.entryId); sp1.spellType = STYPE_DAMAGE; sp1.agent = AGENT_SPELL; sp1.spelltargetType = TTYPE_SINGLETARGET; sp1.cooldown = 0; sp1.cooldowntime = 0; sp1.Misc2 = 0; sp1.procCount = 0; sp1.procChance = 100; range = dbcSpellRange.LookupEntry(sp1.spell->rangeIndex); sp1.minrange = GetMinRange(range); sp1.maxrange = GetMaxRange(range); _unit->GetAIInterface()->addSpellToList(&sp1); AI_Spell sp2; sp2.entryId = 59637; sp2.spell = dbcSpell.LookupEntryForced(sp2.entryId); sp2.spellType = STYPE_DAMAGE; sp2.agent = AGENT_SPELL; sp2.spelltargetType = TTYPE_SINGLETARGET; sp2.cooldown = 0; sp2.cooldowntime = 0; sp2.Misc2 = 0; sp2.procCount = 0; sp2.procChance = 100; range = dbcSpellRange.LookupEntry(sp2.spell->rangeIndex); sp2.minrange = GetMinRange(range); sp2.maxrange = GetMaxRange(range); _unit->GetAIInterface()->addSpellToList(&sp2); } } }
SpellDesc* ArcScriptCreatureAI::AddSpell(uint32 pSpellId, TargetType pTargetType, float pChance, float pCastTime, int32 pCooldown, float pMinRange, float pMaxRange, bool pStrictRange, char* pText, TextType pTextType, uint32 pSoundId) { //Cannot add twice same spell id SpellDesc* NewSpell = FindSpellById(pSpellId); if( NewSpell ) return NewSpell; //Find spell info from spell id SpellEntry* Info = dbcSpell.LookupEntry(pSpellId); #ifdef USE_DBC_SPELL_INFO float CastTime = ( Info->CastingTimeIndex ) ? GetCastTime(dbcSpellCastTime.LookupEntry(Info->CastingTimeIndex)) : pCastTime; int32 Cooldown = Info->RecoveryTime; float MinRange = ( Info->rangeIndex ) ? GetMinRange(dbcSpellRange.LookupEntry(Info->rangeIndex)) : pMinRange; float MaxRange = ( Info->rangeIndex ) ? GetMaxRange(dbcSpellRange.LookupEntry(Info->rangeIndex)) : pMaxRange; sLog.outColor(TYELLOW, "ArcScriptCreatureAI::AddSpell(%u) : casttime=%.1f cooldown=%d minrange=%.1f maxrange=%.1f\n", pSpellId, CastTime, Cooldown, MinRange, MaxRange); #else float CastTime = pCastTime; int32 Cooldown = pCooldown; float MinRange = pMinRange; float MaxRange = pMaxRange; #endif //Create new spell NewSpell = new SpellDesc(Info, NULL, pTargetType, pChance, CastTime, Cooldown, MinRange, MaxRange, pStrictRange, pText, pTextType, pSoundId); mSpells.push_back(NewSpell); return NewSpell; }
bool DemonicCircleSummon(uint8_t /*effectIndex*/, Aura* a, bool apply) { Unit* m_target = a->GetTarget(); if (m_target->GetMapMgr() == nullptr) return true; if (apply) { GameObject* circle = m_target->GetMapMgr()->GetGameObject(a->GetTarget()->m_ObjectSlots[0]); SpellInfo const* sp = sSpellMgr.getSpellInfo(48020); if (circle != NULL && sp != NULL && m_target->CalcDistance(circle) <= GetMaxRange(sSpellRangeStore.LookupEntry(sp->getRangeIndex()))) { if (!m_target->HasAura(62388)) m_target->castSpell(m_target, 62388, true); } else m_target->RemoveAura(62388); } else { m_target->removeAllAurasById(62388); } return true; }
bool DemonicCircleSummon(uint32 i, Aura* a, bool apply) { Unit* m_target = a->GetTarget(); if(m_target->GetMapMgr() == NULL) return true; if(apply) { GameObject* circle = m_target->GetMapMgr()->GetGameObject(a->GetTarget()->m_ObjectSlots[ 0 ]); SpellEntry* sp = dbcSpell.LookupEntryForced(48020); if(circle != NULL && sp != NULL && m_target->CalcDistance(circle) <= GetMaxRange(sSpellRangeStore.LookupEntry(sp->rangeIndex))) { if(!m_target->HasAura(62388)) m_target->CastSpell(m_target, 62388, true); } else m_target->RemoveAura(62388); } else { m_target->RemoveAllAuraById(62388); } return true; }
void Pet::CreateAISpell(SpellEntry * info) { // Create an AI_Spell AI_Spell *sp = new AI_Spell; sp->agent = AGENT_SPELL; sp->entryId = GetEntry(); sp->floatMisc1 = 0; sp->maxrange = GetMaxRange(sSpellRange.LookupEntry(info->rangeIndex)); sp->minrange = GetMinRange(sSpellRange.LookupEntry(info->rangeIndex)); sp->Misc2 = 0; sp->procChance = 0; sp->procCount = 0; sp->procCounter = 0; sp->procEvent = 0; sp->spellCooldown = 0; sp->spellCooldownTimer = 0; sp->spellId = info->Id; sp->spellType = STYPE_DAMAGE; sp->spelltargetType = TTYPE_SINGLETARGET; if(info->Effect[0] == SPELL_EFFECT_APPLY_AURA) sp->agent = STYPE_BUFF; if(info->EffectImplicitTargetA[0] == 24) { float radius = ::GetRadius(sSpellRadius.LookupEntry(info->EffectRadiusIndex[0])); sp->maxrange = radius; sp->spelltargetType = TTYPE_SOURCE; } m_AISpellStore[info->Id] = sp; }
void TotemAI::UpdateAI(const uint32 diff) { if (i_totem.GetTotemType() != TOTEM_ACTIVE) return; if (!i_totem.isAlive() || i_totem.IsNonMeleeSpellCasted(false)) return; // Search spell SpellEntry const *spellInfo = sSpellStore.LookupEntry(i_totem.GetSpell()); if (!spellInfo) return; // Get spell rangy SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); float max_range = GetMaxRange(srange); // SPELLMOD_RANGE not applied in this place just because not existence range mods for attacking totems Unit* victim = NULL; // pointer to appropriate target if found any // Search victim if no, not attackable, or out of range, or friendly (possible in case duel end) if( !i_victimGuid || !(victim = ObjectAccessor::GetUnit(i_totem, i_victimGuid)) || !victim->isTargetableForAttack() || !i_totem.IsWithinDistInMap(victim, max_range) || i_totem.IsFriendlyTo(victim) || !victim->isVisibleForOrDetect(&i_totem,false) ) { CellPair p(MaNGOS::ComputeCellPair(i_totem.GetPositionX(),i_totem.GetPositionY())); Cell cell = RedZone::GetZone(p); cell.data.Part.reserved = ALL_DISTRICT; victim = NULL; MaNGOS::NearestAttackableUnitInObjectRangeCheck u_check(&i_totem, &i_totem, max_range); MaNGOS::UnitLastSearcher<MaNGOS::NearestAttackableUnitInObjectRangeCheck> checker(victim, u_check); TypeContainerVisitor<MaNGOS::UnitLastSearcher<MaNGOS::NearestAttackableUnitInObjectRangeCheck>, GridTypeMapContainer > grid_object_checker(checker); TypeContainerVisitor<MaNGOS::UnitLastSearcher<MaNGOS::NearestAttackableUnitInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker); CellLock<GridReadGuard> cell_lock(cell, p); cell_lock->Visit(cell_lock, grid_object_checker, *MapManager::Instance().GetMap(i_totem.GetMapId(), &i_totem)); cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(i_totem.GetMapId(), &i_totem)); } // If have target if (victim) { // remember i_victimGuid = victim->GetGUID(); // attack i_totem.SetInFront(victim); // client change orientation by self i_totem.CastSpell(victim, i_totem.GetSpell(), false); } else i_victimGuid = 0; }
// Spell Target Handling for type 35: Single Target Party Member (if not in party then the target can not be himself) // this one requeres more research void Spell::SpellTargetSingleTargetPartyMember(uint32 i, uint32 j) { if(!m_caster->IsInWorld()) return; Unit* Target = m_caster->GetMapMgr()->GetPlayer((uint32)m_targets.m_unitTarget); if(!Target) return; float r=GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex)); if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),Target,r*r)) _AddTargetForced(m_targets.m_unitTarget, i); }
/// Spell Target Handling for type 21: Single Target Friend void Spell::SpellTargetSingleTargetFriend(uint32 i, uint32 j) { Unit* Target; if(m_targets.m_unitTarget == m_caster->GetGUID()) Target = u_caster; else Target = m_caster->GetMapMgr() ? m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget) : NULL; if(!Target) return; float r= GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex)); if(IsInrange (m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),Target, r*r)) _AddTargetForced(Target->GetGUID(), i); }
SpellEntry const *Creature::reachWithSpellAttack(Unit *pVictim) { if(!pVictim) return NULL; for(uint32 i=0; i < CREATURE_MAX_SPELLS; i++) { if(!m_spells[i]) continue; SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_spells[i] ); if(!spellInfo) { sLog.outError("WORLD: unknown spell id %i\n", m_spells[i]); continue; } bool bcontinue = true; for(uint32 j=0;j<3;j++) { if( (spellInfo->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE ) || (spellInfo->Effect[j] == SPELL_EFFECT_INSTAKILL) || (spellInfo->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) || (spellInfo->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ) ) { bcontinue = false; break; } } if(bcontinue) continue; if(spellInfo->manaCost > GetPower(POWER_MANA)) continue; SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); float range = GetMaxRange(srange); float minrange = GetMinRange(srange); float dist = GetDistanceSq(pVictim); //if(!isInFront( pVictim, range ) && spellInfo->AttributesEx ) // continue; if( dist > range * range || dist < minrange * minrange ) continue; if(m_silenced) continue; return spellInfo; } return NULL; }
/// Spell Target Handling for type 57: Targeted Party Member void Spell::SpellTargetTargetPartyMember(uint32 i, uint32 j) { if(!m_caster->IsInWorld()) return; if (!m_caster->IsPet() && !m_caster->IsPlayer()) return; TargetsList* tmpMap=&m_targetUnits[i]; Unit* Target = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); Unit* Caster = static_cast<Unit*>(m_caster); if(!Target || !Caster) return; if (!Target->IsPet() && !Target->IsPlayer()) return; if (Caster->IsPet() && static_cast<Pet*>(Caster)->GetPetOwner() != NULL) Caster = static_cast<Pet*>(Caster)->GetPetOwner(); if(Target->IsPet() && static_cast<Pet*>(Target)->GetPetOwner() != NULL) Target = static_cast<Pet*>(Target)->GetPetOwner(); if (Caster != Target) { Group *c_group = static_cast<Player*>(Caster)->GetGroup(); if( !c_group ) return; //caster or caster master are not in group, cannot cast spell on this target Group *t_group = static_cast<Player*>(Target)->GetGroup(); if( !t_group ) return; //target does not have a group if( t_group != c_group ) return; //caster and target are not in same group } float r=GetMaxRange(dbcSpellRange.LookupEntry(GetProto()->rangeIndex)); if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),Target,r*r)) SafeAddTarget(tmpMap,m_targets.m_unitTarget); }
// FIXME: Scale objects according to distance and ignore those below a given threshold (which improves with better sensors) const Sensor::TrackCollection& Sensor::FindTracksInRange() const { assert(player); collection.clear(); // Find all units within range static float maxUnitRadius = XMLSupport::parse_float(vs_config->getVariable("graphics", "hud", "radar_search_extra_radius", "1000")); static bool allGravUnits = XMLSupport::parse_bool(vs_config->getVariable("graphics", "hud", "draw_gravitational_objects", "true")); UnitWithinRangeLocator<CollectRadarTracks> unitLocator(GetMaxRange(), maxUnitRadius); unitLocator.action.init(this, &collection, player); if (! is_null(player->location[Unit::UNIT_ONLY])) { findObjects(_Universe->activeStarSystem()->collidemap[Unit::UNIT_ONLY], player->location[Unit::UNIT_ONLY], &unitLocator); } if (allGravUnits) { Unit *target = player->Target(); Unit *gravUnit; bool foundtarget = false; for (un_kiter i = _Universe->activeStarSystem()->gravitationalUnits().constIterator(); (gravUnit = *i) != NULL; ++i) { unitLocator.action.acquire(gravUnit, UnitUtil::getDistance(player, gravUnit)); if (gravUnit == target) foundtarget = true; } if (target && !foundtarget) unitLocator.action.acquire(target, UnitUtil::getDistance(player, target)); } return collection; }
void TotemAI::UpdateAI(const uint32 diff) { if (!i_totem.isTotem() || !i_totem.isAlive() || i_totem.m_currentSpell) return; if (((Totem*)&i_totem)->GetTotemType() != TOTEM_ACTIVE) return; SpellEntry const *spellInfo = sSpellStore.LookupEntry(((Totem*)&i_totem)->GetSpell()); if (!spellInfo) return; SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); float max_range = GetMaxRange(srange); Unit *victim = ObjectAccessor::Instance().GetUnit(*(Unit*)&i_totem, i_victimGuid); // stop attacking dead or out of range victims if (victim && victim->isAlive() && i_totem.IsWithinDistInMap(victim, max_range)) { // if totem is not casting and it has a victim .. cast again AttackStart(victim); return; } else i_victimGuid = 0; }
void TotemAI::MoveInLineOfSight(Unit *u) { if (!i_totem.isTotem() || ((Totem*)&i_totem)->GetTotemType() != TOTEM_ACTIVE) return; if(i_totem.getVictim() || i_totem.IsFriendlyTo(u) || i_totem.IsNeutralToAll() || u->IsNeutralToAll()) return; if(!u->isTargetableForAttack()|| !IsVisible(u)) return; SpellEntry const *spellInfo = sSpellStore.LookupEntry(((Totem*)&i_totem)->GetSpell()); if (!spellInfo) return; SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); float attackRadius = GetMaxRange(srange); if(i_totem.IsWithinDistInMap(u, attackRadius)) { AttackStart(u); if(u->HasStealthAura()) u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); } }
/// Spell Target Handling for type 45: Chain,!!only for healing!! for chain lightning =6 void Spell::SpellTargetChainTargeting(uint32 i, uint32 j) { if( !m_caster->IsInWorld() ) return; TargetsList* tmpMap=&m_targetUnits[i]; //if selected target is party member, then jumps on party Unit* firstTarget; bool PartyOnly = false; float range = GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex));//this is probably wrong, //this is cast distance, not searching distance range *= range; firstTarget = m_caster->GetMapMgr()->GetPlayer((uint32)m_targets.m_unitTarget); if( firstTarget && p_caster != NULL ) { if( p_caster->InGroup() ) if( p_caster->GetSubGroup() == static_cast< Player* >( firstTarget )->GetSubGroup() ) PartyOnly=true; } else { firstTarget = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); if(!firstTarget) return; } uint32 jumps=m_spellInfo->EffectChainTarget[i]; if(m_spellInfo->SpellGroupType && u_caster) { SM_FIValue(u_caster->SM_FAdditionalTargets,(int32*)&jumps,m_spellInfo->SpellGroupType); } SafeAddTarget(tmpMap,firstTarget->GetGUID()); if(!jumps) return; jumps--; if(PartyOnly) { GroupMembersSet::iterator itr; SubGroup * pGroup = p_caster->GetGroup() ? p_caster->GetGroup()->GetSubGroup(p_caster->GetSubGroup()) : 0; if(pGroup) { p_caster->GetGroup()->Lock(); for(itr = pGroup->GetGroupMembersBegin(); itr != pGroup->GetGroupMembersEnd(); ++itr) { if(!(*itr)->m_loggedInPlayer || (*itr)->m_loggedInPlayer==u_caster || !(*itr)->m_loggedInPlayer->isAlive() ) continue; //we target stuff that has no full health. No idea if we must fill target list or not :( if( (*itr)->m_loggedInPlayer->GetUInt32Value( UNIT_FIELD_HEALTH ) == (*itr)->m_loggedInPlayer->GetUInt32Value( UNIT_FIELD_MAXHEALTH ) ) continue; if( sWorld.Collision && u_caster != NULL ) { if (u_caster->GetMapId() == (*itr)->m_loggedInPlayer->GetMapId() && !CollideInterface.CheckLOS(u_caster->GetMapId(),u_caster->GetPositionNC(),(*itr)->m_loggedInPlayer->GetPositionNC())) continue; } if( IsInrange(u_caster,(*itr)->m_loggedInPlayer, range) ) { SafeAddTarget(tmpMap,(*itr)->m_loggedInPlayer->GetGUID()); if(!--jumps) { p_caster->GetGroup()->Unlock(); return; } } } p_caster->GetGroup()->Unlock(); } }//find nearby friendly target else { std::set<Object*>::iterator itr; firstTarget->AquireInrangeLock(); //make sure to release lock before exit function ! for( itr = firstTarget->GetInRangeSetBegin(); itr != firstTarget->GetInRangeSetEnd(); itr++ ) { if( !(*itr)->IsUnit() || !((Unit*)(*itr))->isAlive()) continue; //we target stuff that has no full health. No idea if we must fill target list or not :( if( (*itr)->GetUInt32Value( UNIT_FIELD_HEALTH ) == (*itr)->GetUInt32Value( UNIT_FIELD_MAXHEALTH ) ) continue; if (sWorld.Collision) { if (u_caster->GetMapId() == (*itr)->GetMapId() && !CollideInterface.CheckLOS(u_caster->GetMapId(),u_caster->GetPositionNC(),(*itr)->GetPositionNC())) continue; } if(IsInrange(firstTarget,*itr, range)) { if(!isAttackable(u_caster,(Unit*)(*itr))) { SafeAddTarget(tmpMap,(*itr)->GetGUID()); if(!--jumps) { firstTarget->ReleaseInrangeLock(); return; } } } } firstTarget->ReleaseInrangeLock(); } }
/// Spell Target Handling for type 31: related to scripted effects void Spell::SpellTargetScriptedEffects( uint32 i, uint32 j ) { // Circle of healing or Wild Growth // - target top 5 hp deficient raid members around target. if( GetProto()->NameHash == SPELL_HASH_CIRCLE_OF_HEALING || GetProto()->NameHash == SPELL_HASH_WILD_GROWTH ) { if( p_caster == NULL || !p_caster->IsInWorld() ) return; TargetsList* tmpMap = &m_targetUnits[i]; Unit * pTarget = p_caster->GetMapMgr()->GetUnit( m_targets.m_unitTarget ); if( !pTarget ) return; if( p_caster == pTarget || IsInrange( p_caster->GetPositionX(), p_caster->GetPositionY(), p_caster->GetPositionZ(), pTarget, GetMaxRange( dbcSpellRange.LookupEntry( GetProto()->rangeIndex ) ) ) ) SafeAddTarget( tmpMap, pTarget->GetGUID() ); else { cancastresult = SPELL_FAILED_OUT_OF_RANGE; return; // No point targeting others if the target is not in casting range. } Group * group = p_caster->GetGroup(); if( group == NULL ) return; std::vector<Player*> raidList; std::vector<Player*>::iterator itr; uint32 count = group->GetSubGroupCount(); group->Lock(); for( uint32 k = 0; k < count; k++ ) { SubGroup * subgroup = group->GetSubGroup( k ); if( subgroup ) { for( GroupMembersSet::iterator itr = subgroup->GetGroupMembersBegin(); itr != subgroup->GetGroupMembersEnd(); ++itr ) { if( (*itr)->m_loggedInPlayer && m_caster != (*itr)->m_loggedInPlayer && IsInrange( pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), (*itr)->m_loggedInPlayer, GetRadius(i) ) ) raidList.push_back( (*itr)->m_loggedInPlayer ); } } } group->Unlock(); std::sort( raidList.begin(), raidList.end(), hpLessThan ); uint32 maxTargets = 4; if( GetProto()->NameHash == SPELL_HASH_CIRCLE_OF_HEALING && p_caster->HasSpell( 55675 ) ) // Glyph of circle of healing maxTargets++; for( itr = raidList.begin(); itr != raidList.end() && maxTargets > 0; ++itr, maxTargets-- ) { SafeAddTarget( tmpMap, (*itr)->GetGUID() ); } } else FillAllTargetsInArea( i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, GetRadius(i) ); }
/// Spell Target Handling for type 6 and 77: Single Target Enemy (grep thinks 77 fits in 6) void Spell::SpellTargetSingleTargetEnemy(uint32 i, uint32 j) { if(!m_caster->IsInWorld()) return; Unit * pTarget = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); if(!pTarget) return; if(p_caster && p_caster == pTarget) // spell bug: target is supposed to be a single enemy, not self { if(GetProto()) sLog.outDebug("Spell %lu has target single enemy, but is targeting the caster.", GetProto()->Id); } TargetsList* tmpMap=&m_targetUnits[i]; if(m_spellInfo->TargetCreatureType && pTarget->GetTypeId()==TYPEID_UNIT) { Creature* cr = static_cast< Creature* >( pTarget ); if( cr == NULL ) return; if( cr->GetCreatureInfo() ) if(!(1<<(cr->GetCreatureInfo()->Type-1) & m_spellInfo->TargetCreatureType)) return; } if(p_caster && pTarget != p_caster) { // this is mostly used for things like duels if(pTarget->IsPlayer() && !isAttackable(p_caster, pTarget, false)) { cancastresult = SPELL_FAILED_BAD_TARGETS; return; } /* HACK FIX */ /* Please replace if found correct way */ /* SPELL_AURA_SPELL_MAGNET */ int x; for( x = 0; x < 3; ++x ) if( m_spellInfo->EffectApplyAuraName[x] == SPELL_AURA_MOD_POSSESS || m_spellInfo->is_melee_spell ) break; if( pTarget && x == 3 && pTarget->m_magnetcaster != 0) { Unit *MagnetTarget = pTarget->GetMapMgr()->GetUnit(pTarget->m_magnetcaster); if ( MagnetTarget && m_spellInfo->School ) { m_magnetTarget = pTarget->m_magnetcaster; pTarget = MagnetTarget; // Redirected } } } uint8 did_hit_result = DidHit(i,pTarget); if(did_hit_result != SPELL_DID_HIT_SUCCESS) SafeAddModeratedTarget(pTarget->GetGUID(), did_hit_result); else SafeAddTarget(tmpMap, pTarget->GetGUID()); if( m_spellInfo->EffectChainTarget[i] ) { //number of additional targets uint32 jumps = m_spellInfo->EffectChainTarget[i] - 1; // extra targets by auras if( u_caster ) SM_FIValue( u_caster->SM_FAdditionalTargets,(int32*)&jumps, m_spellInfo->SpellGroupType ); float range = GetMaxRange( dbcSpellRange.LookupEntry( m_spellInfo->rangeIndex ) );//this is probably wrong range *= range; std::set<Object*>::iterator itr,itr2; m_caster->AquireInrangeLock(); //make sure to release lock before exit function ! for( itr2 = m_caster->GetInRangeSetBegin(); itr2 != m_caster->GetInRangeSetEnd(); ) { itr = itr2; itr2++; if((*itr)->GetGUID()==m_targets.m_unitTarget) continue; if( !((*itr)->IsUnit()) || !((Unit*)(*itr))->isAlive() || ((*itr)->IsCreature() && ((Creature*)(*itr))->IsTotem())) continue; if( sWorld.Collision && u_caster != NULL ) { if (u_caster->GetMapId() == (*itr)->GetMapId() && !CollideInterface.CheckLOS(u_caster->GetMapId(),u_caster->GetPositionNC(),(*itr)->GetPositionNC())) continue; } if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),(*itr),range)) { if(isAttackable(u_caster,(Unit*)(*itr))) { did_hit_result = DidHit(i,((Unit*)*itr)); if(did_hit_result==SPELL_DID_HIT_SUCCESS) SafeAddTarget(tmpMap, (*itr)->GetGUID()); else SafeAddModeratedTarget((*itr)->GetGUID(), did_hit_result); if(!--jumps) { m_caster->ReleaseInrangeLock(); return; } } } } m_caster->ReleaseInrangeLock(); } }
void GameObject::InitAI() { if(pInfo == NULL) return; // this fixes those fuckers in booty bay if(pInfo->SpellFocus == 0 && pInfo->sound1 == 0 && pInfo->sound2 == 0 && pInfo->sound3 != 0 && pInfo->sound5 != 3 && pInfo->sound9 == 1) return; uint32 spellid = 0; switch(pInfo->Type) { case GAMEOBJECT_TYPE_TRAP: { spellid = pInfo->sound3; }break; case GAMEOBJECT_TYPE_SPELL_FOCUS://redirect to properties of another go { uint32 new_entry = pInfo->sound2; if(new_entry) { pInfo = GameObjectNameStorage.LookupEntry( new_entry ); if(pInfo == NULL) { Log.Warning("GameObject","Redirected gameobject %u doesn't seem to exists in database, skipping",new_entry); return; } if(pInfo->sound3) spellid = pInfo->sound3; } }break; case GAMEOBJECT_TYPE_RITUAL: { m_ritualmembers = new uint32[pInfo->SpellFocus]; memset(m_ritualmembers,0,sizeof(uint32)*pInfo->SpellFocus); }break; case GAMEOBJECT_TYPE_CHEST: { Lock *pLock = dbcLock.LookupEntry(GetInfo()->SpellFocus); if(pLock) { for(uint32 i = 0; i < 5; i++) { if(pLock->locktype[i]) { if(pLock->locktype[i] == 2) //locktype; { //herbalism and mining; if(pLock->lockmisc[i] == LOCKTYPE_MINING || pLock->lockmisc[i] == LOCKTYPE_HERBALISM) { CalcMineRemaining(true); } } } } } else if(pInfo->Type == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING) { Health = pInfo->SpellFocus + pInfo->sound5; } } } //Null out gossip_script here, will be set with sScriptMgr.register_go_gossip_script (if any). pInfo->gossip_script = NULL; myScript = sScriptMgr.CreateAIScriptClassForGameObject(GetEntry(), this); // hackfix for bad spell in BWL if(!spellid || spellid == 22247) return; SpellEntry *sp= dbcSpell.LookupEntry(spellid); if(!sp) { spell = NULL; return; } else { spell = sp; } //ok got valid spell that will be casted on target when it comes close enough //get the range for that float r = 0; for(uint32 i = 0; i < 3; i++) { if(sp->Effect[i]) { float t = GetDBCCastTime(dbcSpellRadius.LookupEntry(sp->EffectRadiusIndex[i])); if(t > r) r = t; } } if(r < 0.1)//no range r = GetMaxRange(dbcSpellRange.LookupEntry(sp->rangeIndex)); range = r*r;//square to make code faster checkrate = 20;//once in 2 seconds }
/// Spell Target Handling for type 45: Chain,!!only for healing!! for chain lightning =6 void Spell::SpellTargetChainTargeting(uint32 i, uint32 j) { if( !m_caster->IsInWorld() ) return; //if selected target is party member, then jumps on party Unit* firstTarget; bool PartyOnly = false; float range = GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex));//this is probably wrong, //this is cast distance, not searching distance range *= range; firstTarget = m_caster->GetMapMgr()->GetPlayer((uint32)m_targets.m_unitTarget); if( firstTarget && p_caster != NULL ) { if( p_caster->InGroup() ) if( p_caster->GetSubGroup() == TO_PLAYER( firstTarget )->GetSubGroup() ) PartyOnly=true; } else { firstTarget = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); if(!firstTarget) return; } uint32 jumps=m_spellInfo->EffectChainTarget[i]; if(m_spellInfo->SpellGroupType && u_caster) { SM_FIValue(u_caster->SM[SMT_ADDITIONAL_TARGET][0],(int32*)&jumps,m_spellInfo->SpellGroupType); } _AddTargetForced(firstTarget->GetGUID(), i); if(!jumps) return; jumps--; if(PartyOnly) { GroupMembersSet::iterator itr; SubGroup * pGroup = p_caster->GetGroup() ? p_caster->GetGroup()->GetSubGroup(p_caster->GetSubGroup()) : 0; if(pGroup) { p_caster->GetGroup()->Lock(); for(itr = pGroup->GetGroupMembersBegin(); itr != pGroup->GetGroupMembersEnd(); itr++) { if(!(*itr)->m_loggedInPlayer || (*itr)->m_loggedInPlayer == u_caster || (*itr)->m_loggedInPlayer->GetUInt32Value(UNIT_FIELD_HEALTH) == (*itr)->m_loggedInPlayer->GetUInt32Value(UNIT_FIELD_MAXHEALTH)) continue; if(IsInrange(u_caster->GetPositionX(),u_caster->GetPositionY(),u_caster->GetPositionZ(),(*itr)->m_loggedInPlayer, range)) { _AddTargetForced((*itr)->m_loggedInPlayer->GetGUID(), i); if(!--jumps) { p_caster->GetGroup()->Unlock(); return; } } } p_caster->GetGroup()->Unlock(); } }//find nearby friendly target else { unordered_set<Object*>::iterator itr; for( itr = firstTarget->GetInRangeSetBegin(); itr != firstTarget->GetInRangeSetEnd(); ++itr ) { if( !(*itr)->IsUnit() || !TO_UNIT(*itr)->isAlive()) continue; if(IsInrange(firstTarget->GetPositionX(),firstTarget->GetPositionY(),firstTarget->GetPositionZ(),*itr, range)) { if(!isAttackable(u_caster,TO_UNIT(*itr)) && (*itr)->GetUInt32Value(UNIT_FIELD_HEALTH) != (*itr)->GetUInt32Value(UNIT_FIELD_MAXHEALTH)) { _AddTargetForced((*itr)->GetGUID(), i); if(!--jumps) return; } } } } }
void GameObject::InitAI() { if(!pInfo) return; // this fixes those fuckers in booty bay if(pInfo->SpellFocus == 0 && pInfo->sound1 == 0 && pInfo->sound2 == 0 && pInfo->sound3 != 0 && pInfo->sound5 != 3 && pInfo->sound9 == 1) return; if(pInfo->DisplayID == 1027)//Shaman Shrine { if(pInfo->ID != 177964 && pInfo->ID != 153556) { //Deactivate //SetUInt32Value(GAMEOBJECT_DYN_FLAGS, 0); } } uint32 spellid = 0; if(pInfo->Type==GAMEOBJECT_TYPE_TRAP) { spellid = pInfo->sound3; } else if(pInfo->Type == GAMEOBJECT_TYPE_SPELL_FOCUS) { // get spellid from attached gameobject - by sound2 field if( pInfo->sound2 == 0 ) return; if( GameObjectNameStorage.LookupEntry( pInfo->sound2 ) == NULL ) return; spellid = GameObjectNameStorage.LookupEntry( pInfo->sound2 )->sound3; } else if(pInfo->Type == GAMEOBJECT_TYPE_RITUAL) { m_ritualmembers = new uint32[pInfo->SpellFocus]; memset(m_ritualmembers,0,sizeof(uint32)*pInfo->SpellFocus); } else if(pInfo->Type == GAMEOBJECT_TYPE_CHEST) { Lock *pLock = dbcLock.LookupEntry(GetInfo()->SpellFocus); if(pLock) { for(uint32 i=0; i < 5; i++) { if(pLock->locktype[i]) { if(pLock->locktype[i] == 2) //locktype; { //herbalism and mining; if(pLock->lockmisc[i] == LOCKTYPE_MINING || pLock->lockmisc[i] == LOCKTYPE_HERBALISM) { CalcMineRemaining(true); } } } } } } else if ( pInfo->Type == GAMEOBJECT_TYPE_FISHINGHOLE ) { CalcFishRemaining( true ); } myScript = sScriptMgr.CreateAIScriptClassForGameObject(GetEntry(), this); // hackfix for bad spell in BWL if(!spellid || spellid == 22247) return; SpellEntry *sp= dbcSpell.LookupEntry(spellid); if(!sp) { spell = NULL; return; } else { spell = sp; } //ok got valid spell that will be casted on target when it comes close enough //get the range for that float r = 0; for(uint32 i=0;i<3;i++) { if(sp->Effect[i]) { float t = GetRadius(dbcSpellRadius.LookupEntry(sp->EffectRadiusIndex[i])); if(t > r) r = t; } } if(r < 0.1)//no range r = GetMaxRange(dbcSpellRange.LookupEntry(sp->rangeIndex)); range = r*r;//square to make code faster checkrate = 20;//once in 2 seconds }
// Spell Target Handling for type 6 and 77: Single Target Enemy (grep thinks 77 fits in 6) void Spell::SpellTargetSingleTargetEnemy(uint32 i, uint32 j) { if(!m_caster->IsInWorld()) return; Unit* pTarget = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); if(!pTarget) return; if(m_spellInfo->TargetCreatureType && pTarget->GetTypeId()==TYPEID_UNIT) { Creature* cr = TO_CREATURE( pTarget ); if( cr == NULL ) return; if( cr->GetCreatureInfo() ) if(!(1<<(cr->GetCreatureInfo()->Type-1) & m_spellInfo->TargetCreatureType)) return; } if(p_caster && pTarget != p_caster) { // this is mostly used for things like duels if(pTarget->IsPlayer() && !isAttackable(p_caster, pTarget, false)) { cancastresult = SPELL_FAILED_BAD_TARGETS; return; } } // magnet!!!!! if( pTarget->IsPlayer() && TO_PLAYER(pTarget)->m_magnetAura != NULL && m_magnetTarget == NULL ) { if(!m_spellInfo->is_melee_spell && GetType() == SPELL_DMG_TYPE_MAGIC ) { // redirect it to the magnet m_magnetTarget = TO_PLAYER(pTarget)->m_magnetAura->GetUnitCaster(); // clear the magnet aura TO_PLAYER(pTarget)->m_magnetAura->Remove(); } } if( m_magnetTarget != NULL ) { // if the target exists, shoot it at him. if( m_magnetTarget != NULL && m_magnetTarget->IsInWorld() && !m_magnetTarget->isDead() ) pTarget = m_magnetTarget; } _AddTarget(pTarget, i); if(m_spellInfo->EffectChainTarget[i]) { uint32 jumps=m_spellInfo->EffectChainTarget[i]-1; float range=GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex));//this is probably wrong range*=range; unordered_set<Object*>::iterator itr; for( itr = m_caster->GetInRangeSetBegin(); itr != m_caster->GetInRangeSetEnd(); ++itr ) { if((*itr)->GetGUID()==m_targets.m_unitTarget) continue; if( !((*itr)->IsUnit()) || !TO_UNIT(*itr)->isAlive()) continue; if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),(*itr),range)) { if(isAttackable(u_caster,TO_UNIT(*itr))) { _AddTarget(TO_UNIT(*itr), i); if(!--jumps) return; } } } } }
void CPageDisplay::Update() { int max_rate[NUM_STATUS_BARS]; CString max_range_text; double stat_double; CString stat_string; // Setting ranges on status bar display based on selections. for ( int i = 0; i < NUM_STATUS_BARS; i++ ) { max_rate[i] = GetMaxRange( &(barcharts[i].results[GetWhichPerf()]), barcharts[i].result_to_display ); } // If the results to display are the same, giving them the same ranges for easier comparisons. for ( i = 0; i < NUM_STATUS_BARS - 1; i++) { for ( int j = i; j < NUM_STATUS_BARS; j++ ) { if ( barcharts[i].result_to_display == barcharts[j].result_to_display ) { if ( max_rate[i] > max_rate[j] ) max_rate[j] = max_rate[i]; else max_rate[i] = max_rate[j]; } } } // Setting ranges on status bar and displaying range value. for ( i = 0; i < NUM_STATUS_BARS; i++ ) { ( (CProgressCtrl*)GetDlgItem( PRate1 + i ) )->SetRange( 0, max_rate[i] ); // See if results are displaying a percentage. if ( ( barcharts[i].result_to_display >= CPU_UTILIZATION_RESULT ) && ( barcharts[i].result_to_display <= IRQ_UTILIZATION_RESULT ) ) { max_range_text.Format( "%d %%", max_rate[i] ); // display % sign ( (CStatic*)GetDlgItem( TRate1MAX + i ) )->SetWindowText( max_range_text ); } else { max_range_text.Format( "%d", max_rate[i] ); // displaying a rate ( (CStatic*)GetDlgItem( TRate1MAX + i ) )->SetWindowText( max_range_text ); } // Update the name. SetDlgItemText( TWorker1 + i, barcharts[i].name ); // Get the performance data to display (a number and a string) GetDisplayData( &(barcharts[i].results[GetWhichPerf()]), barcharts[i].result_to_display, &stat_double, &stat_string ); // Update the appropriate progress bar ((CProgressCtrl *) GetDlgItem( PRate1 + i ))->SetPos( (int) stat_double ); // Display the new value to the user ((CStatic *) GetDlgItem( TRate1 + i ))->SetWindowText( stat_string ); } // Update the data. UpdateWindow(); // Update the big meter dialog, if it exists. if ( m_dlgBigMeter.is_displayed ) m_dlgBigMeter.UpdateDisplay(); }
BlueDragonAI(Creature* pCreature) : MoonScriptCreatureAI( pCreature ) { AI_Spell* NewSpell = new AI_Spell; NewSpell->spell = dbcSpell.LookupEntry( 45848 ); NewSpell->agent = AGENT_SPELL; NewSpell->entryId = _unit->GetEntry(); NewSpell->maxrange = GetMaxRange( dbcSpellRange.LookupEntry( NewSpell->spell->rangeIndex ) ); NewSpell->minrange = GetMinRange( dbcSpellRange.LookupEntry( NewSpell->spell->rangeIndex ) ); NewSpell->spelltargetType = TTYPE_SINGLETARGET; NewSpell->spellType = STYPE_DAMAGE; NewSpell->cooldown = objmgr.GetPetSpellCooldown( NewSpell->spell->Id ); NewSpell->cooldowntime = 0; NewSpell->autocast_type = AUTOCAST_EVENT_NONE; NewSpell->floatMisc1 = 0; NewSpell->Misc2 = 0; NewSpell->procChance = 0; NewSpell->procCount=0; _unit->GetAIInterface()->addSpellToList( NewSpell ); NewSpell = new AI_Spell; NewSpell->spell = dbcSpell.LookupEntry( 45856 ); NewSpell->agent = AGENT_SPELL; NewSpell->entryId = _unit->GetEntry(); NewSpell->maxrange = GetMaxRange( dbcSpellRange.LookupEntry( NewSpell->spell->rangeIndex ) ); NewSpell->minrange = GetMinRange( dbcSpellRange.LookupEntry( NewSpell->spell->rangeIndex ) ); NewSpell->spelltargetType = TTYPE_CASTER; NewSpell->spellType = STYPE_BUFF; NewSpell->cooldown = objmgr.GetPetSpellCooldown( NewSpell->spell->Id ); NewSpell->cooldowntime = 0; NewSpell->autocast_type = AUTOCAST_EVENT_NONE; NewSpell->floatMisc1 = 0; NewSpell->Misc2 = 0; NewSpell->procChance = 0; NewSpell->procCount=0; _unit->GetAIInterface()->addSpellToList( NewSpell ); NewSpell = new AI_Spell; NewSpell->spell = dbcSpell.LookupEntry( 45860 ); NewSpell->agent = AGENT_SPELL; NewSpell->entryId = _unit->GetEntry(); NewSpell->maxrange = GetMaxRange( dbcSpellRange.LookupEntry( NewSpell->spell->rangeIndex ) ); NewSpell->minrange = GetMinRange( dbcSpellRange.LookupEntry( NewSpell->spell->rangeIndex ) ); NewSpell->spelltargetType = TTYPE_SINGLETARGET; NewSpell->spellType = STYPE_BUFF; NewSpell->cooldown = objmgr.GetPetSpellCooldown( NewSpell->spell->Id ); NewSpell->cooldowntime = 0; NewSpell->autocast_type = AUTOCAST_EVENT_NONE; NewSpell->floatMisc1 = 0; NewSpell->Misc2 = 0; NewSpell->procChance = 0; NewSpell->procCount=0; _unit->GetAIInterface()->addSpellToList( NewSpell ); NewSpell = new AI_Spell; NewSpell->spell = dbcSpell.LookupEntry( 45862 ); NewSpell->agent = AGENT_SPELL; NewSpell->entryId = _unit->GetEntry(); NewSpell->maxrange = GetMaxRange( dbcSpellRange.LookupEntry( NewSpell->spell->rangeIndex ) ); NewSpell->minrange = GetMinRange( dbcSpellRange.LookupEntry( NewSpell->spell->rangeIndex ) ); NewSpell->spelltargetType = TTYPE_SINGLETARGET; NewSpell->spellType = STYPE_BUFF; NewSpell->cooldown = objmgr.GetPetSpellCooldown( NewSpell->spell->Id ); NewSpell->cooldowntime = 0; NewSpell->autocast_type = AUTOCAST_EVENT_NONE; NewSpell->floatMisc1 = 0; NewSpell->Misc2 = 0; NewSpell->procChance = 0; NewSpell->procCount=0; _unit->GetAIInterface()->addSpellToList( NewSpell ); RegisterAIUpdateEvent( 500 ); };
void GameObject::InitAI() { if(!pInfo) return; // this fixes those fuckers in booty bay if(pInfo->SpellFocus == 0 && pInfo->sound1 == 0 && pInfo->sound2 == 0 && pInfo->sound3 != 0 && pInfo->sound5 != 3 && pInfo->sound9 == 1) return; if(pInfo->DisplayID == 1027)//Shaman Shrine { if(pInfo->ID != 177964 || pInfo->ID != 153556) { //Deactivate //SetUInt32Value(GAMEOBJECT_DYN_FLAGS, 0); } } uint32 spellid = 0; if(pInfo->Type==GAMEOBJECT_TYPE_TRAP) { spellid = pInfo->sound3; } else if(pInfo->Type == GAMEOBJECT_TYPE_SPELL_FOCUS)//redirect to properties of another go { uint32 new_entry = pInfo->sound2; if(!new_entry) return; pInfo = GameObjectNameStorage.LookupEntry( new_entry ); if(!pInfo) return; spellid = pInfo->sound3; } else if(pInfo->Type == GAMEOBJECT_TYPE_RITUAL) { m_ritualmembers = new uint32[pInfo->SpellFocus]; memset(m_ritualmembers,0,sizeof(uint32)*pInfo->SpellFocus); } myScript = sScriptMgr.CreateAIScriptClassForGameObject(GetEntry(), this); // hackfix for bad spell in BWL if(!spellid || spellid == 22247) return; SpellEntry *sp= sSpellStore.LookupEntry(spellid); if(!sp) { spell = NULL; return; } else { spell = sp; } //ok got valid spell that will be casted on target when it comes close enough //get the range for that float r = 0; for(uint32 i=0;i<3;i++) { if(sp->Effect[i]) { float t = GetRadius(sSpellRadius.LookupEntry(sp->EffectRadiusIndex[i])); if(t > r) r = t; } } if(r < 0.1)//no range r = GetMaxRange(sSpellRange.LookupEntry(sp->rangeIndex)); range = r*r;//square to make code faster checkrate = 20;//once in 2 seconds }
bool Sensor::InRange(const Track& track) const { return (track.GetDistance() <= GetMaxRange()); }
void ObjectMgr::LoadExtraCreatureProtoStuff() { { StorageContainerIterator<CreatureProto> * itr = CreatureProtoStorage.MakeIterator(); CreatureProto* cn; while(!itr->AtEnd()) { cn = itr->Get(); // Process spell fields for( uint32 i = 0; i < MAX_CREATURE_PROTO_SPELLS; i++ ){ if( cn->AISpells[ i ] == 0 ) continue; SpellEntry *sp = dbcSpell.LookupEntryForced( cn->AISpells[ i ] ); if( sp == NULL ) continue; if( ( sp->Attributes & ATTRIBUTES_PASSIVE ) == 0 ) cn->castable_spells.push_back( sp->Id ); else cn->start_auras.insert( sp->Id ); } // process creature spells from creaturespelldata.dbc if( cn->spelldataid != 0 ){ CreatureSpellDataEntry* spe = dbcCreatureSpellData.LookupEntry( cn->spelldataid ); for( uint32 i = 0; i < 3; i++ ){ if( spe->Spells[ i ] == 0 ) continue; SpellEntry *sp = dbcSpell.LookupEntryForced( spe->Spells[ i ] ); if( sp == NULL ) continue; if( ( sp->Attributes & ATTRIBUTES_PASSIVE ) == 0 ) cn->castable_spells.push_back( sp->Id ); else cn->start_auras.insert( sp->Id ); } } if(cn->aura_string) { string auras = string(cn->aura_string); vector<string> aurs = StrSplit(auras, " "); for(vector<string>::iterator it = aurs.begin(); it != aurs.end(); ++it) { uint32 id = atol((*it).c_str()); if(id) cn->start_auras.insert(id); } } if(!cn->MinHealth) cn->MinHealth = 1; if(!cn->MaxHealth) cn->MaxHealth = 1; if(cn->AttackType > SCHOOL_ARCANE) cn->AttackType = SCHOOL_NORMAL; cn->m_canFlee = cn->m_canRangedAttack = cn->m_canCallForHelp = false; cn->m_fleeHealth = 0.0f; // please.... m_fleeDuration is a uint32... //cn->m_fleeDuration = 0.0f; cn->m_fleeDuration = 0; if(!itr->Inc()) break; } itr->Destruct(); } { StorageContainerIterator<CreatureInfo> * itr = CreatureNameStorage.MakeIterator(); CreatureInfo* ci; while(!itr->AtEnd()) { ci = itr->Get(); ci->lowercase_name = string(ci->Name); for(uint32 j = 0; j < ci->lowercase_name.length(); ++j) ci->lowercase_name[j] = static_cast<char>(tolower(ci->lowercase_name[j])); // Darvaleo 2008/08/15 - Copied lowercase conversion logic from ItemPrototype task for(int i = 0; i < NUM_MONSTER_SAY_EVENTS; i++) ci->MonsterSay[i] = objmgr.HasMonsterSay(ci->Id, MONSTER_SAY_EVENTS(i)); if(!itr->Inc()) break; } itr->Destruct(); } // Load AI Agents if(Config.MainConfig.GetBoolDefault("Server", "LoadAIAgents", true)) { QueryResult* result = WorldDatabase.Query("SELECT * FROM ai_agents"); CreatureProto* cn; if(result != NULL) { AI_Spell* sp; SpellEntry* spe; uint32 entry; do { Field* fields = result->Fetch(); entry = fields[0].GetUInt32(); cn = CreatureProtoStorage.LookupEntry(entry); spe = dbcSpell.LookupEntryForced(fields[6].GetUInt32()); if(spe == NULL) { Log.Error("AIAgent", "For %u has nonexistent spell %u.", fields[0].GetUInt32(), fields[6].GetUInt32()); continue; } if(!cn) continue; sp = new AI_Spell; sp->entryId = fields[0].GetUInt32(); sp->instance_mode = fields[1].GetUInt32(); sp->agent = fields[2].GetUInt16(); sp->procChance = fields[4].GetUInt32(); sp->procCount = fields[5].GetUInt32(); sp->spell = spe; sp->spellType = static_cast<uint8>(fields[7].GetUInt32()); int32 targettype = fields[8].GetInt32(); if(targettype == -1) sp->spelltargetType = static_cast<uint8>(GetAiTargetType(spe)); else sp->spelltargetType = static_cast<uint8>(targettype); sp->cooldown = fields[9].GetInt32(); sp->floatMisc1 = fields[10].GetFloat(); sp->autocast_type = (uint32) - 1; sp->cooldowntime = getMSTime(); sp->procCounter = 0; sp->Misc2 = fields[11].GetUInt32(); if(sp->agent == AGENT_SPELL) { if(!sp->spell) { LOG_DEBUG("SpellId %u in ai_agent for %u is invalid.", (unsigned int)fields[6].GetUInt32(), (unsigned int)sp->entryId); delete sp; sp = NULL; continue; } if(sp->spell->Effect[0] == SPELL_EFFECT_LEARN_SPELL || sp->spell->Effect[1] == SPELL_EFFECT_LEARN_SPELL || sp->spell->Effect[2] == SPELL_EFFECT_LEARN_SPELL) { LOG_DEBUG("Teaching spell %u in ai_agent for %u", (unsigned int)fields[6].GetUInt32(), (unsigned int)sp->entryId); delete sp; sp = NULL; continue; } sp->minrange = GetMinRange(dbcSpellRange.LookupEntry(sp->spell->rangeIndex)); sp->maxrange = GetMaxRange(dbcSpellRange.LookupEntry(sp->spell->rangeIndex)); //omg the poor darling has no clue about making ai_agents if(sp->cooldown == (uint32) - 1) { //now this will not be exact cooldown but maybe a bigger one to not make him spam spells to often int cooldown; SpellDuration* sd = dbcSpellDuration.LookupEntry(sp->spell->DurationIndex); int Dur = 0; int Casttime = 0; //most of the time 0 int RecoveryTime = sp->spell->RecoveryTime; if(sp->spell->DurationIndex) Dur =::GetDuration(sd); Casttime = GetCastTime(dbcSpellCastTime.LookupEntry(sp->spell->CastingTimeIndex)); cooldown = Dur + Casttime + RecoveryTime; if(cooldown < 0) sp->cooldown = 2000; //huge value that should not loop while adding some timestamp to it else sp->cooldown = cooldown; } /* //now apply the moron filter if(sp->procChance== 0) { //printf("SpellId %u in ai_agent for %u is invalid.\n", (unsigned int)fields[5].GetUInt32(), (unsigned int)sp->entryId); delete sp; sp = NULL; continue; } if(sp->spellType== 0) { //right now only these 2 are used if(IsBeneficSpell(sp->spell)) sp->spellType==STYPE_HEAL; else sp->spellType==STYPE_BUFF; } if(sp->spelltargetType== 0) sp->spelltargetType = RecommandAISpellTargetType(sp->spell); */ } if(sp->agent == AGENT_RANGED) { cn->m_canRangedAttack = true; delete sp; sp = NULL; } else if(sp->agent == AGENT_FLEE) { cn->m_canFlee = true; if(sp->floatMisc1) cn->m_canFlee = (sp->floatMisc1 > 0.0f ? true : false); else cn->m_fleeHealth = 0.2f; if(sp->Misc2) cn->m_fleeDuration = sp->Misc2; else cn->m_fleeDuration = 10000; delete sp; sp = NULL; } else if(sp->agent == AGENT_CALLFORHELP) { cn->m_canCallForHelp = true; if(sp->floatMisc1) cn->m_callForHelpHealth = 0.2f; delete sp; sp = NULL; } else { cn->spells.push_back(sp); } } while(result->NextRow()); delete result; } } }
float CUnitTable::GetScore(const UnitDef* udef, UnitCategory cat) { const int m = (ai->uh->AllUnitsByType[udef->id]).size(); const int n = udef->maxThisUnit; if (m >= n) { // if we've hit the build-limit for this // type of unit, make sure GetUnitByScore() // won't pick it for construction anyway return 0.0f; } if (udef->minWaterDepth > 0) { // we can't swim yet return 0.0f; } const int frame = ai->cb->GetCurrentFrame(); const float cost = ((udef->metalCost * METAL2ENERGY) + udef->energyCost) + 0.1f; const float currentIncome = INCOMEMULTIPLIER * (ai->cb->GetEnergyIncome() + (ai->cb->GetMetalIncome() * METAL2ENERGY)) + frame / 2; const float Hitpoints = udef->health; const float buildTime = udef->buildTime + 0.1f; const float RandNum = ai->math->RandNormal(4, 3, 1) + 1; float benefit = 0.0f; float aoe = 0.0f; float dps = 0.0f; int unitcounter = 0; bool candevelop = false; switch (cat) { case CAT_ENERGY: { // KLOOTNOTE: factor build-time into this as well? // (so benefit values generally lie closer together) float baseBenefit = udef->energyMake - udef->energyUpkeep; if (udef->windGenerator > 0.0f) { const float minWind = ai->cb->GetMinWind(); const float maxWind = ai->cb->GetMaxWind(); const float avgWind = (minWind + maxWind) * 0.5f; const float avgEffi = std::min(avgWind / udef->windGenerator, 1.0f); if (avgEffi >= 0.4f) { baseBenefit += avgWind; } } if (udef->tidalGenerator > 0.0f) { baseBenefit += ai->cb->GetTidalStrength(); } // filter geothermals if (udef->needGeo) { baseBenefit = 0.0f; } // KLOOTNOTE: dividing by cost here as well means // benefit is inversely proportional to square of // cost, so expensive generators are quadratically // less likely to be built if original calculation // of score is used // benefit /= cost; benefit = (baseBenefit / buildTime) * float((rand() % 2) + 1); } break; case CAT_MEX: { benefit = pow(udef->extractsMetal, 4.0f); } break; case CAT_MMAKER: { // benefit = ((udef->metalMake - udef->metalUpkeep) / udef->energyUpkeep) + 0.01f; benefit = (udef->metalMake - udef->metalUpkeep) / (udef->energyUpkeep + 0.01f); } break; case CAT_G_ATTACK: { dps = GetCurrentDamageScore(udef); aoe = ((udef->weapons.size())? ((udef->weapons.front()).def)->areaOfEffect: 0.0f); if (udef->canfly && !udef->hoverAttack) { // TODO: improve to set reload-time to the bomber's // turnspeed vs. movespeed (eg. time taken for a run) dps /= 6; } benefit = pow((aoe + 80), 1.5f) * pow(GetMaxRange(udef) + 200, 1.5f) * pow(dps, 1.0f) * pow(udef->speed + 40, 1.0f) * pow(Hitpoints, 1.0f) * pow(RandNum, 2.5f) * pow(cost, -0.5f); if (udef->canfly || udef->canhover) { // general hack: reduce feasibility of aircraft for 20 mins // and that of hovercraft permanently, should mostly prefer // real L2 units to hovers benefit = (udef->canfly && frame >= (30 * 60 * 20))? benefit: benefit * 0.01f; } } break; case CAT_DEFENCE: { aoe = ((udef->weapons.size())? ((udef->weapons.front()).def)->areaOfEffect: 0.0f); benefit = pow((aoe + 80), 1.5f) * pow(GetMaxRange(udef), 2.0f) * pow(GetCurrentDamageScore(udef), 1.5f) * pow(Hitpoints, 0.5f) * pow(RandNum, 2.5f) * pow(cost, -1.0f); } break; case CAT_BUILDER: { for (unsigned int i = 0; i != unitTypes[udef->id].canBuildList.size(); i++) { if (unitTypes[unitTypes[udef->id].canBuildList[i]].category == CAT_FACTORY) { candevelop = true; } } // builder units that cannot construct any // factories are worthless, prevent them // from being chosen via GetUnitByScore() // (they might have other uses though, eg. // nano-towers) if (!candevelop) { benefit = 0.0f; } else { benefit = pow(udef->buildSpeed, 1.0f) * pow(udef->speed, 0.5f) * pow(Hitpoints, 0.3f) * pow(RandNum, 0.4f); } } break; case CAT_FACTORY: { // benefit of a factory is dependant on the kind of // offensive units it can build, but EE-hubs are only // capable of building other buildings for (unsigned int i = 0; i != unitTypes[udef->id].canBuildList.size(); i++) { const int buildOpt = unitTypes[udef->id].canBuildList[i]; const UnitCategory buildOptCat = unitTypes[buildOpt].category; if (buildOptCat == CAT_G_ATTACK || buildOptCat == CAT_FACTORY) { if (unitTypes[buildOpt].def != udef) { // KLOOTNOTE: guard against infinite recursion (BuildTowers in // PURE trigger this since they are able to build themselves) benefit += GetScore(unitTypes[buildOpt].def, buildOptCat); unitcounter++; } } } if (unitcounter > 0) { benefit /= (unitcounter * pow(float(ai->uh->AllUnitsByType[udef->id].size() + 1), 3.0f)); benefit /= ((m > 0)? (m * 2.0f): 1.0f); } else { benefit = 0.0f; } } break; case CAT_MSTOR: { benefit = pow((udef->metalStorage), 1.0f) * pow(Hitpoints, 1.0f); } break; case CAT_ESTOR: { benefit = pow((udef->energyStorage), 1.0f) * pow(Hitpoints, 1.0f); } break; case CAT_NUKE: { // KLOOTNOTE: should factor damage into this as well float metalCost = udef->stockpileWeaponDef->metalcost; float energyCost = udef->stockpileWeaponDef->energycost; float supplyCost = udef->stockpileWeaponDef->supplycost; float denom = metalCost + energyCost + supplyCost + 1.0f; float range = udef->stockpileWeaponDef->range; benefit = (udef->stockpileWeaponDef->areaOfEffect + range) / denom; } break; /* case CAT_ANTINUKE: { benefit = udef->stockpileWeaponDef->coverageRange; } break; case CAT_SHIELD: { benefit = udef->shieldWeaponDef->shieldRadius; } break; */ default: benefit = 0.0f; } benefit *= unitTypes[udef->id].costMultiplier; // return (benefit / (currentIncome + cost)); // return ((benefit / cost) * currentIncome); return ((currentIncome / cost) * benefit); }
bool ChatHandler::HandleAddAIAgentCommand(const char* args, WorldSession *m_session) { char* agent = strtok((char*)args, " "); if(!agent) return false; char* procEvent = strtok(NULL, " "); if(!procEvent) return false; char* procChance = strtok(NULL, " "); if(!procChance) return false; char* procCount = strtok(NULL, " "); if(!procCount) return false; char* spellId = strtok(NULL, " "); if(!spellId) return false; char* spellType = strtok(NULL, " "); if(!spellType) return false; char* spelltargetType = strtok(NULL, " "); if(!spelltargetType) return false; char* spellCooldown = strtok(NULL, " "); if(!spellCooldown) return false; char* floatMisc1 = strtok(NULL, " "); if(!floatMisc1) return false; char* Misc2 = strtok(NULL, " "); if(!Misc2) return false; Creature* target = m_session->GetPlayer()->GetMapMgr()->GetCreature(GET_LOWGUID_PART(m_session->GetPlayer()->GetSelection())); if(!target) { RedSystemMessage(m_session, "You have to select a Creature!"); return false; } std::stringstream qry; qry << "INSERT INTO ai_agents SET entry = '" << target->GetUInt32Value(OBJECT_FIELD_ENTRY) << "', type = '" << atoi(agent) << "', event = '" << atoi(procEvent)<< "', chance = '" << atoi(procChance)<< "', maxcount = '" << atoi(procCount)<< "', spell = '" << atoi(spellId)<< "', spelltype = '" << atoi(spellType)<< "', targettype_overwrite = '" << atoi(spelltargetType)<< "', cooldown_overwrite = '" << atoi(spellCooldown)<< "', floatMisc1 = '" << atof(floatMisc1)<< "', Misc2 ='" << atoi(Misc2)<< "'"; WorldDatabase.Execute( qry.str().c_str( ) ); AI_Spell * sp = new AI_Spell; sp->agent = atoi(agent); sp->procChance = atoi(procChance); /* sp->procCount = atoi(procCount);*/ sp->spell = dbcSpell.LookupEntry(atoi(spellId)); sp->spellType = atoi(spellType); // sp->spelltargetType = atoi(spelltargetType); sp->floatMisc1 = (float)atof(floatMisc1); sp->Misc2 = (uint32)atof(Misc2); sp->cooldown = (uint32)atoi(spellCooldown); sp->procCount=0; sp->procCounter=0; sp->cooldowntime=0; sp->minrange = GetMinRange(dbcSpellRange.LookupEntry(dbcSpell.LookupEntry(atoi(spellId))->rangeIndex)); sp->maxrange = GetMaxRange(dbcSpellRange.LookupEntry(dbcSpell.LookupEntry(atoi(spellId))->rangeIndex)); target->GetProto()->spells.push_back(sp); if(sp->agent == AGENT_CALLFORHELP) target->GetAIInterface()->m_canCallForHelp = true; else if(sp->agent == AGENT_FLEE) target->GetAIInterface()->m_canFlee = true; else if(sp->agent == AGENT_RANGED) target->GetAIInterface()->m_canRangedAttack = true; else target->GetAIInterface()->addSpellToList(sp); return true; }
void Spell::AddChainTargets(uint32 i, uint32 TargetType, float r, uint32 maxtargets) { if(!m_caster->IsInWorld()) return; Object* targ = m_caster->GetMapMgr()->_GetObject(m_targets.m_unitTarget); if(targ == NULL) return; TargetsList* list = &m_targetUnits[i]; //if selected target is party member, then jumps on party Unit* firstTarget = NULL; if(targ->IsUnit()) firstTarget = TO_UNIT(targ); else firstTarget = u_caster; bool RaidOnly = false; float range = GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex));//this is probably wrong, //this is cast distance, not searching distance range *= range; //is this party only? Player* casterFrom = TO< Player* >(u_caster->GetPlayerOwner()); Player* pfirstTargetFrom = TO< Player* >(firstTarget->GetPlayerOwner()); if(casterFrom != NULL && pfirstTargetFrom != NULL && casterFrom->GetGroup() == pfirstTargetFrom->GetGroup()) RaidOnly = true; uint32 jumps = m_spellInfo->EffectChainTarget[i]; //range range /= jumps; //hacky, needs better implementation! if(m_spellInfo->SpellGroupType && u_caster != NULL) SM_FIValue(u_caster->SM_FAdditionalTargets, (int32*)&jumps, m_spellInfo->SpellGroupType); AddTarget(i, TargetType, firstTarget); if(jumps <= 1 || list->size() == 0) //1 because we've added the first target, 0 size if spell is resisted return; ObjectSet::iterator itr; for(itr = firstTarget->GetInRangeSetBegin(); itr != firstTarget->GetInRangeSetEnd(); itr++) { if(!(*itr)->IsUnit() || !TO_UNIT((*itr))->isAlive()) continue; if(RaidOnly && !pfirstTargetFrom->InRaid(TO_UNIT(*itr))) continue; //healing spell, full health target = NONO if(IsHealingSpell(m_spellInfo) && TO_UNIT(*itr)->GetHealthPct() == 100) continue; size_t oldsize; if(IsInrange(firstTarget->GetPositionX(), firstTarget->GetPositionY(), firstTarget->GetPositionZ(), (*itr), range)) { oldsize = list->size(); AddTarget(i, TargetType, (*itr)); if(list->size() == oldsize || list->size() >= jumps) //either out of jumps or a resist return; } } }
void ObjectMgr::LoadExtraCreatureProtoStuff() { { StorageContainerIterator<CreatureProto> * itr = CreatureProtoStorage.MakeIterator(); CreatureProto * cn; while(!itr->AtEnd()) { cn = itr->Get(); if(itr->Get()->aura_string) { string auras = string(itr->Get()->aura_string); vector<string> aurs = StrSplit(auras, " "); for(vector<string>::iterator it = aurs.begin(); it != aurs.end(); ++it) { uint32 id = atol((*it).c_str()); if(id) itr->Get()->start_auras.insert( id ); } } if(!itr->Get()->MinHealth) itr->Get()->MinHealth = 1; if(!itr->Get()->MaxHealth) itr->Get()->MaxHealth = 1; if (itr->Get()->AttackType > SCHOOL_ARCANE) itr->Get()->AttackType = SCHOOL_NORMAL; cn->m_canFlee = cn->m_canRangedAttack = cn->m_canCallForHelp = false; cn->m_fleeHealth = 0.0f; // please.... m_fleeDuration is a uint32... //cn->m_fleeDuration = 0.0f; cn->m_fleeDuration = 0; if(!itr->Inc()) break; } itr->Destruct(); } { StorageContainerIterator<CreatureInfo> * itr = CreatureNameStorage.MakeIterator(); CreatureInfo * ci; while(!itr->AtEnd()) { ci = itr->Get(); ci->lowercase_name = string(ci->Name); for(uint32 j = 0; j < ci->lowercase_name.length(); ++j) ci->lowercase_name[j] = tolower(ci->lowercase_name[j]); // Darvaleo 2008/08/15 - Copied lowercase conversion logic from ItemPrototype task ci->gossip_script = sScriptMgr.GetDefaultGossipScript(); if(!itr->Inc()) break; } itr->Destruct(); } { StorageContainerIterator<Quest> * itr = QuestStorage.MakeIterator(); Quest * qst; while(!itr->AtEnd()) { qst = itr->Get(); qst->pQuestScript = NULL; if( !itr->Inc() ) break; } itr->Destruct(); } // Load AI Agents QueryResult * result = WorldDatabase.Query( "SELECT * FROM ai_agents" ); CreatureProto * cn; if( result != NULL ) { AI_Spell *sp; SpellEntry * spe; uint32 entry; if(Config.OptionsConfig.GetBoolDefault("Server", "LoadAIAgents", true)) { do { Field *fields = result->Fetch(); entry = fields[0].GetUInt32(); cn = CreatureProtoStorage.LookupEntry(entry); spe = dbcSpell.LookupEntryForced(fields[5].GetUInt32()); if( spe == NULL ) { Log.Warning("AIAgent", "For %u has nonexistant spell %u.", fields[0].GetUInt32(), fields[5].GetUInt32()); } if(!cn) continue; sp = new AI_Spell; sp->entryId = fields[0].GetUInt32(); sp->agent = fields[1].GetUInt16(); sp->procChance = fields[3].GetUInt32(); sp->procCount = fields[4].GetUInt32(); sp->spell = spe; sp->spellType = fields[6].GetUInt32(); sp->spelltargetType = fields[7].GetUInt32(); sp->cooldown = fields[8].GetUInt32(); sp->floatMisc1 = fields[9].GetFloat(); sp->autocast_type=(uint32)-1; sp->custom_pointer=false; sp->cooldowntime=getMSTime(); sp->procCounter=0; /* if (!sp->procCountDB) sp->procCount = uint32(-1); else sp->procCount = sp->procCountDB;*/ sp->Misc2 = fields[10].GetUInt32(); if(sp->agent == AGENT_SPELL) { if(!sp->spell) { //printf("SpellId %u in ai_agent for %u is invalid.\n", (unsigned int)fields[5].GetUInt32(), (unsigned int)sp->entryId); delete sp; continue; } if(sp->spell->Effect[0] == SPELL_EFFECT_LEARN_SPELL || sp->spell->Effect[1] == SPELL_EFFECT_LEARN_SPELL || sp->spell->Effect[2] == SPELL_EFFECT_LEARN_SPELL) { //printf("Teaching spell %u in ai_agent for %u\n", (unsigned int)fields[5].GetUInt32(), (unsigned int)sp->entryId); delete sp; continue; } sp->minrange = GetMinRange(dbcSpellRange.LookupEntry(sp->spell->rangeIndex)); sp->maxrange = GetMaxRange(dbcSpellRange.LookupEntry(sp->spell->rangeIndex)); //omg the poor darling has no clue about making ai_agents if(sp->cooldown==0xffffffff) { //now this will not be exact cooldown but maybe a bigger one to not make him spam spells to often int cooldown; SpellDuration *sd=dbcSpellDuration.LookupEntry(sp->spell->DurationIndex); int Dur=0; int Casttime=0;//most of the time 0 int RecoveryTime=sp->spell->RecoveryTime; if(sp->spell->DurationIndex) Dur =::GetDuration(sd); Casttime=GetCastTime(dbcSpellCastTime.LookupEntry(sp->spell->CastingTimeIndex)); cooldown=Dur+Casttime+RecoveryTime; if(cooldown<0) sp->cooldown=0;//huge value that should not loop while adding some timestamp to it else sp->cooldown=cooldown; } /* //now apply the morron filter if(sp->procChance==0) { //printf("SpellId %u in ai_agent for %u is invalid.\n", (unsigned int)fields[5].GetUInt32(), (unsigned int)sp->entryId); delete sp; continue; } if(sp->spellType==0) { //right now only these 2 are used if(IsBeneficSpell(sp->spell)) sp->spellType==STYPE_HEAL; else sp->spellType==STYPE_BUFF; } if(sp->spelltargetType==0) sp->spelltargetType = RecommandAISpellTargetType(sp->spell); */ } if(sp->agent == AGENT_RANGED) { cn->m_canRangedAttack = true; delete sp; } else if(sp->agent == AGENT_FLEE) { cn->m_canFlee = true; if(sp->floatMisc1) cn->m_canFlee = (sp->floatMisc1>0.0f ? true : false); else cn->m_fleeHealth = 0.2f; if(sp->Misc2) cn->m_fleeDuration = sp->Misc2; else cn->m_fleeDuration = 10000; delete sp; } else if(sp->agent == AGENT_CALLFORHELP) { cn->m_canCallForHelp = true; if(sp->floatMisc1) cn->m_callForHelpHealth = 0.2f; delete sp; } else { cn->spells.push_back(sp); } } while( result->NextRow() ); } delete result; } }