rendered paste body// That is the Scruct how create the Generic Formula i wan, For BOSS AI that scruct should be personalise for the BOSS AI//She is used by AI()->Update()im still not satisfied on where that is... but for moment i gave time on AI thinkingstruct CreatureSpellCasting{ CreatureSpellCasting() : spellIndex(-1), targetGUID(0), runningTimer(0), oldTargetRange(0.0f),range(0.0f), started(false),reached(false),dynamicTarget(false) { spellBook = NULL; } CreatureSpellBook *spellBook; int8 spellIndex; uint64 targetGUID; uint32 runningTimer; float oldTargetRange, range; bool started, reached, dynamicTarget; void reset(bool resetRange = false) { spellIndex = -1; targetGUID = 0; runningTimer = 0; range = 0.0f; started = false; reached = false; dynamicTarget = false; if(resetRange) oldTargetRange = 0.0f; }};//All below are into CORE now and no more into script...same as other, im still not satisfied on where that is... but for moment i gave time on AI thinking// ++ Need to be sure all that is very portable, for any Kind of desing into spellCasting Structureenum CreatureSpellSelectTarget{ SELECT_TARGET_DONTCARE = 0, //All target types allowed SELECT_TARGET_SELF, //Only Self casting SELECT_TARGET_SINGLE_ENEMY, //Only Single Enemy SELECT_TARGET_AOE_ENEMY, //Only AoE Enemy SELECT_TARGET_ANY_ENEMY, //AoE or Single Enemy SELECT_TARGET_SINGLE_FRIEND, //Only Single Friend SELECT_TARGET_AOE_FRIEND, //Only AoE Friend SELECT_TARGET_ANY_FRIEND, //AoE or Single Friend};enum CreatureSpellSelectEffect{ SELECT_EFFECT_DONTCARE = 0, //All spell effects allowed SELECT_EFFECT_DAMAGE, //Spell does damage SELECT_EFFECT_HEALING, //Spell does healing SELECT_EFFECT_AURA, //Spell applies an aura};enum CreatureSpellIndex{ CREATURE_SPELL_MIN, CREATURE_SPELL_ATTACK_1 = 0, //Normal Attack CREATURE_SPELL_ATTACK_2, CREATURE_SPELL_ATTACK_3, CREATURE_SPELL_ATTACK_4, CREATURE_SPELL_ATTACK_5, CREATURE_SPELL_ATTACK_MAX, CREATURE_SPELL_SPEED_1 = 5, //When target Run Away CREATURE_SPELL_SPEED_2, CREATURE_SPELL_SPEED_MAX, CREATURE_SPELL_STUNT_1 = 7, CREATURE_SPELL_STUNT_2, //When target Run Closer CREATURE_SPELL_STUNT_MAX, CREATURE_SPELL_HEALING_1 = 9, //When Less Life Or Friend Target CREATURE_SPELL_HEALING_2, CREATURE_SPELL_HEALING_MAX, CREATURE_SPELL_BUFF_1 = 11, //When Begin of the fight Or Friend Target CREATURE_SPELL_BUFF_2, CREATURE_SPELL_BUFF_MAX, CREATURE_SPELL_INTERRUPT_1 = 13, //Select When Target is Casting Channeling Spell CREATURE_SPELL_INTERRUPT_MAX, CREATURE_SPELL_MAX = 14};struct CreatureSpellInfo{ CreatureSpellInfo() : id(NULL), recoveryTime(0), unknow1(0),buffDuration(0),cost(0), targets(0), usingDBC(false) { range[0] = 0.0f; range[1] = 0.0f; } uint8 targets,effects; uint32 id,recoveryTime,unknow1,buffDuration,cost; float range[2]; bool usingDBC, isDelayed;};typedef std::map<uint8,CreatureSpellInfo> CreatureSpellInfoMap;struct CreatureSpellBook{ CreatureSpellBook() : entry(0) { info.clear(); } uint32 entry; CreatureSpellInfoMap info; bool hasHealing() { CreatureSpellInfoMap::iterator spellItr; for(uint8 i = CREATURE_SPELL_HEALING_1; i < CREATURE_SPELL_HEALING_MAX; ++i) { spellItr = info.find(i); if( spellItr != info.end() && spellItr->second.id) return true; } return false; }};// Into script.dll// Select Spell Functionvoid ScriptedAI::AISelectSpell(CreatureSpellCasting *spellCasting, Unit *dynamicTarget, bool special){ uint16 chosenSpellId; std::list<uint8> spellIndexFound; spellIndexFound.clear(); if(spellCasting->spellIndex > -1 || !spellCasting->spellBook || m_creature->HasSpellCooldown() ) return; /*if(special && m_creature->m_spellsCoolDown[CREATURE_SPELL_SPECIAL_1] < 1 ) { spellCasting->spellId = m_creature->spellBook->spells[CREATURE_SPELL_SPECIAL_1]; if(spellCasting->spellId && AICheckTakePower(spellCasting->spellId)) { Unit *creatureTarget = m_creature->GetUnit(*m_creature, m_creature->GetUInt64Value(UNIT_FIELD_TARGET)); if(spellAddon[spellCasting->spellId].targets != TARGET_SELF && creatureTarget) AIMotionTarget(creatureTarget,AIFollowRange(spellCasting->spellId)); spellCasting->castingTimer = spellAddon[spellCasting->spellId].castTime; return; } return; // Cause Special case //AICast(m_creature->getVictim(), spellId, CREATURE_SPELL_SPECIAL_1, waitDuration); }*/ Unit *enemyTarget = NULL; Unit *friendTarget = NULL; if(dynamicTarget) { if(m_creature->IsHostileTo(dynamicTarget)) enemyTarget = dynamicTarget; else friendTarget = dynamicTarget; } else if(AICheckFriendTarget()) friendTarget = m_creature->GetUnit(*m_creature, m_creature->GetUInt64Value(UNIT_FIELD_TARGET)); else if(AICheckVictimTarget()) enemyTarget = m_creature->getVictim(); if( friendTarget ) { if( friendTarget->isAlive() ) { //heal Friend spellIndexFound.clear(); for(uint8 i = CREATURE_SPELL_HEALING_1; i < CREATURE_SPELL_HEALING_MAX; i++) { CreatureSpellInfo *spellInfo = &spellCasting->spellBook->info[i]; if( spellInfo->id && !m_creature->HasSpellCooldown(spellInfo->id) && AICheckTakePower(i) ) spellIndexFound.push_front(i); } if( spellIndexFound.size() > 0 && AIHPPercent(friendTarget) < 70) { chosenSpellId = 0; std::list<uint8>::iterator itr = spellIndexFound.begin(); for (uint8 randomIndex = irand(0,spellIndexFound.size()-1); 0 < randomIndex; --randomIndex)++itr; spellCasting->spellIndex = (*itr); chosenSpellId = spellCasting->spellBook->info[(*itr)].id; //DoDoSay("Healing(Friend): %u",chosenSpellId); spellCasting->targetGUID = friendTarget->GetGUID(); SetSpellMaxRange(spellCasting); if(!dynamicTarget) AIMotionTarget(friendTarget,(rand_norm()*spellCasting->range)+1.0f); return; } //Buff Friend spellIndexFound.clear(); for(uint8 i = CREATURE_SPELL_BUFF_1; i < CREATURE_SPELL_BUFF_MAX; i++) { CreatureSpellInfo *spellInfo = &spellCasting->spellBook->info[i]; if( spellInfo->id && !m_creature->HasSpellCooldown(spellInfo->id) && AICheckTakePower(i) ) spellIndexFound.push_front(i); } if( spellIndexFound.size() > 0 ) { srand(getMSTime()); chosenSpellId = 0; std::list<uint8>::iterator itr = spellIndexFound.begin(); for (uint8 randomIndex = irand(0,spellIndexFound.size()-1); 0 < randomIndex; --randomIndex)++itr; spellCasting->spellIndex = (*itr); chosenSpellId = spellCasting->spellBook->info[(*itr)].id; //DoDoSay("Buff Friend: %u",chosenSpellId); spellCasting->targetGUID = friendTarget->GetGUID(); SetSpellMaxRange(spellCasting); if(!dynamicTarget) AIMotionTarget(friendTarget,(rand_norm()*spellCasting->range)+1.0f); return; } } } else if(enemyTarget) { if(!dynamicTarget) { float distance = sqrt(m_creature->GetDistance2dSq(enemyTarget)); if( !spellCasting->oldTargetRange ) spellCasting->oldTargetRange = distance; // Target Is Casting a Channeled Spell if( enemyTarget->HasSpellChannelActiveTimer() ) { //Cast Intterupted Spell if we have available } // Target Is Running Away, try speed-up to get to her. // Far from what i wan... Need to correct that situation if( distance > spellCasting->oldTargetRange && (enemyTarget->hasUnitState(UNIT_STAT_MOVING) || !enemyTarget->IsStopped())) { spellCasting->oldTargetRange = distance; spellIndexFound.clear(); for(uint8 i = CREATURE_SPELL_SPEED_1; i < CREATURE_SPELL_SPEED_MAX; i++) { CreatureSpellInfo *spellInfo = &spellCasting->spellBook->info[i]; if( spellInfo->id && !m_creature->HasSpellCooldown(spellInfo->id) && AICheckTakePower(i) ) spellIndexFound.push_front(i); } if( spellIndexFound.size() > 0 ) { srand(getMSTime()); chosenSpellId = 0; std::list<uint8>::iterator itr = spellIndexFound.begin(); for (uint8 randomIndex = irand(0,spellIndexFound.size()-1); 0 < randomIndex; --randomIndex)++itr; spellCasting->spellIndex = (*itr); chosenSpellId = spellCasting->spellBook->info[(*itr)].id; //DoDoSay("Speed: %u",chosenSpellId); SetSpellMaxRange(spellCasting); if( !(spellCasting->spellBook->info[(*itr)].targets & (1 << (SELECT_TARGET_ANY_FRIEND-1))) ) { spellCasting->targetGUID = m_creature->GetGUID(); AICast(spellCasting); spellCasting->reset(); //AIMotionTarget(enemyTarget); } else { AIMotionTarget(enemyTarget); spellCasting->targetGUID = enemyTarget->GetGUID(); } //spellCasting->spellBook->castingTimer = spellCasting->spellBook->info[(*itr)].castingTime; return; } } //Potentiel Charge, but for sure Target is comming to Us // Far from what i wan... Need to correct that situation if( distance < spellCasting->oldTargetRange /*&& !enemyTarget->IsStopped()*/) { spellCasting->oldTargetRange = distance; spellIndexFound.clear(); for(uint8 i = CREATURE_SPELL_STUNT_1; i < CREATURE_SPELL_STUNT_MAX; i++) { CreatureSpellInfo *spellInfo = &spellCasting->spellBook->info[i]; if( spellInfo->id && !m_creature->HasSpellCooldown(spellInfo->id) && AICheckTakePower(i) ) spellIndexFound.push_front(i); } if( spellIndexFound.size() > 0 ) { srand(getMSTime()); chosenSpellId = 0; std::list<uint8>::iterator itr = spellIndexFound.begin(); for (uint8 randomIndex = irand(0,spellIndexFound.size()-1); 0 < randomIndex; --randomIndex)++itr; spellCasting->spellIndex = (*itr); chosenSpellId = spellCasting->spellBook->info[(*itr)].id; //DoDoSay("Stun: %u",chosenSpellId); SetSpellMaxRange(spellCasting); if( !(spellCasting->spellBook->info[chosenSpellId].targets & (1 << (SELECT_TARGET_SELF-1))) ) spellCasting->targetGUID = m_creature->GetGUID(); else { AIMotionTarget(enemyTarget,(rand_norm()*spellCasting->range)+1.0f); spellCasting->targetGUID = enemyTarget->GetGUID(); } //spellCasting->spellBook->castingTimer = spellCasting->spellBook->info[(*itr)].castingTime; spellCasting->targetGUID = enemyTarget->GetGUID(); return; } } } //Healing if( AIHPPercent(m_creature) < irand(40,90) ) { spellIndexFound.clear(); for(uint8 i = CREATURE_SPELL_HEALING_1; i < CREATURE_SPELL_HEALING_MAX; i++) { CreatureSpellInfo *spellInfo = &spellCasting->spellBook->info[i]; if( spellInfo->id && !m_creature->HasSpellCooldown(spellInfo->id) && AICheckTakePower(i) ) spellIndexFound.push_front(i); } if( spellIndexFound.size() > 0 ) { srand(getMSTime()); chosenSpellId = 0; std::list<uint8>::iterator itr = spellIndexFound.begin(); for (uint8 randomIndex = irand(0,spellIndexFound.size()-1); 0 < randomIndex; --randomIndex)++itr; spellCasting->spellIndex = (*itr); chosenSpellId = spellCasting->spellBook->info[(*itr)].id; //DoDoSay("Healing: %u",chosenSpellId); //spellCasting->spellBook->castingTimer = spellCasting->spellBook->info[(*itr)].castingTime; spellCasting->targetGUID = m_creature->GetGUID(); SetSpellMaxRange(spellCasting); return; } } else //Buff { spellIndexFound.clear(); for(uint8 i = CREATURE_SPELL_BUFF_1; i < CREATURE_SPELL_BUFF_MAX; i++) { CreatureSpellInfo *spellInfo = &spellCasting->spellBook->info[i]; if( spellInfo->id && !m_creature->HasSpellCooldown(spellInfo->id) && AICheckTakePower(i) ) spellIndexFound.push_front(i); } if( spellIndexFound.size() > 0 ) { srand(getMSTime()); chosenSpellId = 0; std::list<uint8>::iterator itr = spellIndexFound.begin(); for (uint8 randomIndex = irand(0,spellIndexFound.size()-1); 0 < randomIndex; --randomIndex)++itr; spellCasting->spellIndex = (*itr); chosenSpellId = spellCasting->spellBook->info[(*itr)].id; //DoDoSay("Buff: %u",chosenSpellId); //spellCasting->spellBook->castingTimer = spellCasting->spellBook->info[(*itr)].castingTime; spellCasting->targetGUID = m_creature->GetGUID(); SetSpellMaxRange(spellCasting); return; } } //Attack Spell spellIndexFound.clear(); for(uint8 i = CREATURE_SPELL_ATTACK_1; i < CREATURE_SPELL_ATTACK_MAX; i++) { CreatureSpellInfo *spellInfo = &spellCasting->spellBook->info[i]; if( spellInfo->id && !m_creature->HasSpellCooldown(spellInfo->id) && AICheckTakePower(i) ) spellIndexFound.push_front(i); } if( spellIndexFound.size() ) { srand(getMSTime()); chosenSpellId = 0; std::list<uint8>::iterator itr = spellIndexFound.begin(); for (uint8 randomIndex = irand(0,spellIndexFound.size()-1); 0 < randomIndex; --randomIndex)++itr; spellCasting->spellIndex = (*itr); chosenSpellId = spellCasting->spellBook->info[(*itr)].id; //DoDoSay("Attack: %u",chosenSpellId); spellCasting->targetGUID = enemyTarget->GetGUID(); SetSpellMaxRange(spellCasting); if(!dynamicTarget) AIMotionTarget(enemyTarget,spellCasting->range/1.1f); return; } if(!dynamicTarget && m_creature->IsStopped()) //Debug, got to be removed... AIMotionTarget(enemyTarget,1.5f); }}// Spell Casting from AI()->Update() //Spell Casting if(spellCasting->spellIndex > -1) { Unit *target = m_creature->GetUnit( (*m_creature),m_creature->GetUInt64Value(UNIT_FIELD_TARGET) ); Unit *spellTarget = NULL; if( spellCasting->targetGUID != m_creature->GetGUID() ) spellTarget = m_creature->GetUnit((*m_creature),spellCasting->targetGUID ); else spellTarget = ((Unit*)m_creature); bool dynamicTarget = false; if(spellCasting->targetGUID != m_creature->GetGUID() && spellCasting->targetGUID != m_creature->GetUInt64Value(UNIT_FIELD_TARGET)) dynamicTarget = true; if(spellTarget) { if( !spellCasting->reached ) { if(dynamicTarget) { if( m_creature->IsWithinDistInMap(spellTarget, spellCasting->range) ) spellCasting->reached = true; else { spellCasting->reset(); return; } } else { if( spellTarget->GetGUID() == m_creature->GetGUID() || m_creature->IsWithinDistInMap(spellTarget, spellCasting->range) ) spellCasting->reached = true; else { spellCasting->runningTimer += diff; if(spellCasting->runningTimer > irand(1000*CREATURE_WAIT_REACH_RATE,2000*CREATURE_WAIT_REACH_RATE) ) { //DoDoSay("Too Long To Reach Target, IsStopped:%u ",m_creature->IsStopped()); spellCasting->runningTimer = 0; spellCasting->reset(); /*AICast() Cast Spell On Demand */ } return; } } //if( !spellCasting->reached && m_creature->IsStopped() ) // Hack //AIMotionTarget(target,1.0f); } if( spellCasting->reached ) { if(!spellCasting->started) { if(!m_creature->IsStopped() && spellCasting->spellBook->info[spellCasting->spellIndex].isDelayed) m_creature->StopMoving(); AICast(spellCasting); lastAction = getMSTime(); } //Spell Finish else if( m_creature->m_currentSpells[CURRENT_CHANNELED_SPELL] ) { if( !m_creature->HasSpellChannelActiveTimer() ) { //if(!dynamicTarget && target && target->isAlive() && m_creature->hasUnitState(UNIT_STAT_FOLLOW)) //AIMotionTarget(target, spellCasting->range/2); spellCasting->reset(); } } else { spellCasting->reset(); //if(!dynamicTarget && target && target->isAlive() && m_creature->hasUnitState(UNIT_STAT_FOLLOW)) //AIMotionTarget(target); } } } else if(dynamicTarget) //Bad dynamicTarget Target { if(!spellCasting->reached) spellCasting->reset(); } else //Bad Target { if(!spellCasting->reached) spellCasting->reset(true); } return; }