Index: src/game/Creature.cpp =================================================================== --- src/game/Creature.cpp (revision 6319) +++ src/game/Creature.cpp (working copy) @@ -629,9 +629,31 @@ GossipOption* gso; GossipOption* ingso; + CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(GetEntry()); + std::string ScriptName = cinfo->ScriptName; + if(cinfo->npcflag == 1 && ScriptName == "script_bot_giver") + { + if(!pPlayer->HaveBot()) + { + pm->GetGossipMenu()->AddMenuItem((uint8)9, "Recruit Warrior", 60000, 60000, "Recruit Warrior", false); + pm->GetGossipMenu()->AddMenuItem((uint8)9, "Recruit Hunter", 60001, 60001, "Recruit Hunter", false); + pm->GetGossipMenu()->AddMenuItem((uint8)9, "Recruit Paladin", 60002, 60002, "Recruit Paladin", false); + //pm->GetGossipMenu()->AddMenuItem((uint8)9, "Recruit Deathknight", 60003, 60003, "Recruit Deathknight", false); + pm->GetGossipMenu()->AddMenuItem((uint8)9, "Recruit Shaman", 60004, 60004, "Recruit Shaman", false); + pm->GetGossipMenu()->AddMenuItem((uint8)9, "Recruit Rogue", 60005, 60005, "Recruter Rogue", false); + pm->GetGossipMenu()->AddMenuItem((uint8)3, "Recruit Druid", 60006, 60006, "Recruit Druid", false); + pm->GetGossipMenu()->AddMenuItem((uint8)3, "Recruit Mage", 60007, 60007, "Recruit Mage", false); + pm->GetGossipMenu()->AddMenuItem((uint8)3, "Recruter Priest", 60008, 60008, "Recruter Priest", false); + pm->GetGossipMenu()->AddMenuItem((uint8)3, "Recruit Warlock", 60009, 60009, "Recruit Warlock", false); + } + else + pm->GetGossipMenu()->AddMenuItem((uint8)0, "Do you want to abandon your recruit?", 60010, 60010, "Do you want to abandon your recruit?", false); + } + for( GossipOptionList::iterator i = m_goptions.begin( ); i != m_goptions.end( ); i++ ) { gso=&*i; + if(gso->GossipId == gossipid) { bool cantalking=true; @@ -700,6 +722,7 @@ case GOSSIP_OPTION_STABLEPET: case GOSSIP_OPTION_TABARDDESIGNER: case GOSSIP_OPTION_AUCTIONEER: + case GOSSIP_OPTION_BOT: break; // no checks default: sLog.outErrorDb("Creature %u (entry: %u) have unknown gossip option %u",GetGUIDLow(),GetCreatureInfo()->Entry,gso->Action); @@ -833,6 +856,8 @@ player->GetSession()->SendBattlegGroundList( GetGUID(), bgTypeId ); break; } + case GOSSIP_OPTION_BOT: + break; default: OnPoiSelect( player, gossip ); break; Index: src/game/Creature.h =================================================================== --- src/game/Creature.h (revision 6319) +++ src/game/Creature.h (working copy) @@ -53,7 +53,8 @@ GOSSIP_OPTION_STABLEPET = 14, //UNIT_NPC_FLAG_STABLE = 8192, GOSSIP_OPTION_ARMORER = 15, //UNIT_NPC_FLAG_ARMORER = 16384, GOSSIP_OPTION_UNLEARNTALENTS = 16, //UNIT_NPC_FLAG_TRAINER (bonus option for GOSSIP_OPTION_TRAINER) - GOSSIP_OPTION_UNLEARNPETSKILLS = 17 //UNIT_NPC_FLAG_TRAINER (bonus option for GOSSIP_OPTION_TRAINER) + GOSSIP_OPTION_UNLEARNPETSKILLS = 17, //UNIT_NPC_FLAG_TRAINER (bonus option for GOSSIP_OPTION_TRAINER) + GOSSIP_OPTION_BOT = 100 }; enum Gossip_Guard Index: src/game/NPCHandler.cpp =================================================================== --- src/game/NPCHandler.cpp (revision 6319) +++ src/game/NPCHandler.cpp (working copy) @@ -285,7 +285,15 @@ if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - if( unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider()) + CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(unit->GetEntry()); + std::string ScriptName = cinfo->ScriptName; + if(cinfo->npcflag == 1 && ScriptName == "script_bot_giver") + { + _player->TalkedToCreature(unit->GetEntry(),unit->GetGUID()); + unit->prepareGossipMenu(_player,GOSSIP_OPTION_BOT); + unit->sendPreparedGossip( _player ); + } + else if( unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider()) { unit->StopMoving(); //npcIsStopped[unit->GetGUID()] = true; @@ -343,7 +351,102 @@ // remove fake death if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + uint32 entry = 0; + uint32 BoTclass = 0; + uint32 BoTrace = 0; + switch(_player->PlayerTalkClass->GossipOptionSender(option)) + { + case 60000: BoTclass = 1; break; + case 60001: BoTclass = 3; break; + case 60002: BoTclass = 2; break; + /* case 60003: BoTclass = 6; break; */ //DEATH KNIGHT + case 60004: BoTclass = 7; break; + case 60005: BoTclass = 4; break; + case 60006: BoTclass = 11; break; + case 60007: BoTclass = 8; break; + case 60008: BoTclass = 5; break; + case 60009: BoTclass = 9; break; + case 60010: + { + //Abandon of bot + if(GetPlayer()->HaveBot()) + { + Creature* m_bot = GetPlayer()->GetBot(); + GetPlayer()->m_bot->DealDamage(GetPlayer()->m_bot, GetPlayer()->m_bot->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + GetPlayer()->m_bot->RemoveFromWorld(); + GetPlayer()->RemoveBot(); + GetPlayer()->PlayerTalkClass->CloseGossip(); + } + GetPlayer()->PlayerTalkClass->CloseGossip(); + break; + } + default: + break; + } + + if(!GetPlayer()->HaveBot() && (_player->PlayerTalkClass->GossipOptionSender(option) != 60010) + && (_player->PlayerTalkClass->GossipOptionSender(option) >= 60000)) + { + entry = 0; + QueryResult *coucount = NULL; + if(GetPlayer()->GetTeam()==ALLIANCE) + coucount = WorldDatabase.PQuery("SELECT count(entry) FROM creature_template WHERE scriptname = 'script_bot' and class = %u and (race = 1 or race = 3 or race = 4 or race = 7 or race = 11)", BoTclass); + else if(GetPlayer()->GetTeam()==HORDE) + coucount = WorldDatabase.PQuery("SELECT count(entry) FROM creature_template WHERE scriptname = 'script_bot' and class = %u and (race = 2 or race = 5 or race = 6 or race = 8 or race = 10)", BoTclass); + + if(coucount) + { + uint32 ranrand = coucount->Fetch()[0].GetUInt32(); + + uint32 m_rand = uint32(rand() % ranrand) + 1; + + QueryResult *result = NULL; + + if(GetPlayer()->GetTeam()==ALLIANCE) + result = WorldDatabase.PQuery("SELECT entry, race FROM creature_template WHERE scriptname = 'script_bot' and class = %u and (race = 1 or race = 3 or race = 4 or race = 7 or race = 11)", BoTclass); + else if(GetPlayer()->GetTeam()==HORDE) + result = WorldDatabase.PQuery("SELECT entry, race FROM creature_template WHERE scriptname = 'script_bot' and class = %u and (race = 2 or race = 5 or race = 6 or race = 8 or race = 10)", BoTclass); + uint32 tmp_rand = 0; + do + { + Field *fields = result->Fetch(); + entry = fields[0].GetUInt32(); + BoTrace = fields[1].GetUInt32(); + tmp_rand++; + if(tmp_rand == m_rand) + break; + }while (result->NextRow()); + + delete result; + delete coucount; + } + } + + if(!GetPlayer()->HaveBot() && (_player->PlayerTalkClass->GossipOptionSender(option) != 60010) + && (_player->PlayerTalkClass->GossipOptionSender(option) >= 60000) + && (entry != 0)) + { + Creature* BoT = GetPlayer()->SummonCreature(entry/*must be in DB*/, unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetOrientation(),TEMPSUMMON_DEAD_DESPAWN,0); + GetPlayer()->SetBot(BoT); + GetPlayer()->SetBotClass(BoTclass); + GetPlayer()->SetBotRace(BoTrace); + BoT->SetCharmerGUID(GetPlayer()->GetGUID()); + BoT->CombatStop(); + BoT->DeleteThreatList(); + BoT->AIM_Initialize(); + CharmInfo *charmInfoBoT = BoT->InitCharmInfo(BoT); + BoT->setFaction(GetPlayer()->getFaction()); + charmInfoBoT->SetReactState( REACT_AGGRESSIVE ); + charmInfoBoT->SetCommandState( COMMAND_FOLLOW ); + GetPlayer()->PlayerTalkClass->CloseGossip(); + } + else if((entry != 0) && (GetPlayer()->HaveBot())) + { + GetPlayer()->PlayerTalkClass->CloseGossip(); + } + if(!code.empty()) { Index: src/game/Player.cpp =================================================================== --- src/game/Player.cpp (revision 6319) +++ src/game/Player.cpp (working copy) @@ -330,6 +330,7 @@ m_lastDailyQuestTime = 0; m_regenTimer = 0; + m_weaponChangeTimer = 0; m_breathTimer = 0; m_isunderwater = 0; @@ -417,6 +418,17 @@ m_miniPet = 0; m_bgAfkReportedTimer = 0; + + ///////////////////// Bot System //////////////////////// + + m_botTimer = 0; + m_bot = NULL; + m_bot_form = 0; + m_bot_race = 0; + m_bot_class = 0; + m_bot_must_wait_for_spell_1 = 0; + m_bot_must_wait_for_spell_2 = 0; + m_bot_must_wait_for_spell_3 = 0; } Player::~Player () @@ -456,6 +468,14 @@ for(size_t x = 0; x < ItemSetEff.size(); x++) if(ItemSetEff[x]) delete ItemSetEff[x]; + + if(HaveBot()) + { + Creature* m_bot = GetBot(); + m_bot->DealDamage(m_bot, m_bot->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_bot->RemoveFromWorld(); + RemoveBot(); + } } void Player::CleanupsBeforeDelete() @@ -1078,6 +1098,14 @@ m_regenTimer -= p_time; } + if(m_botTimer > 0) + { + if(p_time >= m_botTimer) + m_botTimer = 0; + else + m_botTimer -= p_time; + } + if (m_weaponChangeTimer > 0) { if(p_time >= m_weaponChangeTimer) @@ -1111,6 +1139,7 @@ if (isAlive()) { RegenerateAll(); + RefreshBot(); } if (m_deathState == JUST_DIED) @@ -1731,6 +1760,647 @@ m_regenTimer = regenDelay; } +void Player::RefreshBot() +{ + if (m_botTimer != 0) + return; + uint32 refreshDelay = 100; + + if(HaveBot()) + { + Creature* m_bot = GetBot(); + if(!m_bot->isAlive()) + { + m_bot->RemoveFromWorld(); + RemoveBot(); + } + } + + if(HaveBot()) + { + //CHANGELEVEL SUPPORT + Creature* m_bot = GetBot(); + if(m_bot->getLevel() != getLevel()) + { + //DATABASE STATS + PlayerLevelInfo info; + objmgr.GetPlayerLevelInfo(GetBotRace(),GetBotClass(),getLevel(),&info); + + PlayerClassLevelInfo classInfo; + objmgr.GetPlayerClassLevelInfo(GetBotClass(),getLevel(),&classInfo); + + m_bot->SetLevel(getLevel()); + + //player -> m_bot->UpdateAllStats + for (int i = STAT_STRENGTH; i < MAX_STATS; i++) + { + //float value = m_bot->GetTotalStatValue(Stats(i)); + //m_bot->SetStat(Stats(i), (int32)value); + m_bot->SetStat(Stats(i), info.stats[i]); + } + + //player -> m_bot->UpdateAttackPowerAndDamage(); + float val2 = 0.0f; + float level = float(m_bot->getLevel()); + + UnitMods unitMod = UNIT_MOD_ATTACK_POWER; + + uint16 index = UNIT_FIELD_ATTACK_POWER; + uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS; + uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER; + + switch(m_bot->getClass()) + { + case CLASS_WARRIOR: val2 = level*3.0f + m_bot->GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; + case CLASS_PALADIN: val2 = level*3.0f + m_bot->GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; + case CLASS_ROGUE: val2 = level*2.0f + m_bot->GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break; + case CLASS_HUNTER: val2 = level*2.0f + m_bot->GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break; + case CLASS_SHAMAN: val2 = level*2.0f + m_bot->GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; + //case CLASS_DRUID: val2 = m_bot->GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; + case CLASS_DRUID: + { + //Check if Predatory Strikes is skilled + float mLevelMult = 0.0; + /*switch(m_bot->m_form) + { + case FORM_CAT: + case FORM_BEAR: + case FORM_DIREBEAR: + case FORM_MOONKIN: + { + Unit::AuraList const& mDummy = m_bot->GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) + { + // Predatory Strikes + if ((*itr)->GetSpellProto()->SpellIconID == 1563) + { + mLevelMult = (*itr)->GetModifier()->m_amount / 100.0f; + break; + } + } + break; + } + }*/ + switch(GetBotForm()) + { + case 892: + case 8571: + val2 = m_bot->getLevel()*(mLevelMult+2.0f) + m_bot->GetStat(STAT_STRENGTH)*2.0f + m_bot->GetStat(STAT_AGILITY) - 20.0f; break; + case 2281: + case 2289: + val2 = m_bot->getLevel()*(mLevelMult+3.0f) + m_bot->GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; + /*case FORM_MOONKIN: + val2 = m_bot->getLevel()*(mLevelMult+1.5f) + m_bot->GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;*/ + default: + val2 = m_bot->GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; + } + break; + } + case CLASS_MAGE: val2 = m_bot->GetStat(STAT_STRENGTH) - 10.0f; break; + case CLASS_PRIEST: val2 = m_bot->GetStat(STAT_STRENGTH) - 10.0f; break; + case CLASS_WARLOCK: val2 = m_bot->GetStat(STAT_STRENGTH) - 10.0f; break; + } + + m_bot->SetModifierValue(unitMod, BASE_VALUE, val2); + float base_attPower = m_bot->GetModifierValue(unitMod, BASE_VALUE) * m_bot->GetModifierValue(unitMod, BASE_PCT); + float attPowerMod = m_bot->GetModifierValue(unitMod, TOTAL_VALUE); + + float attPowerMultiplier = m_bot->GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; + + m_bot->SetUInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field + m_bot->SetUInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field + m_bot->SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field + + //automatically update weapon damage after attack power modification + m_bot->UpdateDamagePhysical(BASE_ATTACK); + + //player -> m_bot->UpdateAttackPowerAndDamage(true); // ---> STUPID CREATURE CAN NOT BE RANGED + + //player -> m_bot->UpdateArmor(); + float value = 0.0f; + unitMod = UNIT_MOD_ARMOR; + + value = m_bot->GetModifierValue(unitMod, BASE_VALUE); // base armor (from items) + value *= m_bot->GetModifierValue(unitMod, BASE_PCT); // armor percent from items + value += m_bot->GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats + value += m_bot->GetModifierValue(unitMod, TOTAL_VALUE); + + //add dynamic flat mods + /*AuraList const& mResbyIntellect = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT); + for(AuraList::const_iterator i = mResbyIntellect.begin();i != mResbyIntellect.end(); ++i) + if((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) + value += int32(GetStat(STAT_INTELLECT) * (*i)->GetModifier()->m_amount / 100.0f);*/ + + value *= m_bot->GetModifierValue(unitMod, TOTAL_PCT); + + m_bot->SetArmor(int32(value)); + + //player -> m_bot->UpdateMaxHealth(); + unitMod = UNIT_MOD_HEALTH; + + value = 0.0f; + //value = m_bot->GetModifierValue(unitMod, BASE_VALUE) /*+ m_bot->GetCreateHealth()*/; + value = classInfo.basehealth; + value *= m_bot->GetModifierValue(unitMod, BASE_PCT); + + //player -> m_bot->GetHealthBonusFromStamina() + float stamina = m_bot->GetStat(STAT_STAMINA); + + float baseStam = stamina < 20 ? stamina : 20; + float moreStam = stamina - baseStam; + + value += m_bot->GetModifierValue(unitMod, TOTAL_VALUE) + baseStam + (moreStam*10.0f); + value *= m_bot->GetModifierValue(unitMod, TOTAL_PCT); + + m_bot->SetMaxHealth((uint32)value); + //SOMETHING IS BAD HERE... + for(int i = POWER_MANA; i < MAX_POWERS; i++) + { + //player -> m_bot->UpdateMaxPower(Powers(i)); + UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + Powers(i)); + + //player -> m_bot->GetManaBonusFromIntellect() + float bonusPower = 0; + if(i == POWER_MANA) + { + float intellect = GetStat(STAT_INTELLECT); + float baseInt = intellect < 20 ? intellect : 20; + float moreInt = intellect - baseInt; + //float bonusPower = (i == POWER_MANA) ? (baseInt + (moreInt*15.0f)) : 0; + bonusPower = (baseInt + (moreInt*15.0f)); + float value = 0.0f; + value = classInfo.basemana; + value *= m_bot->GetModifierValue(unitMod, BASE_PCT); + value += m_bot->GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower; + value *= m_bot->GetModifierValue(unitMod, TOTAL_PCT); + m_bot->SetMaxPower(Powers(i), uint32(value)); + } + else + { + m_bot->SetMaxPower(Powers(i), uint32(classInfo.basemana)); + } + } + + /*ONLY FOR PLAYER*/ + /*player -> m_bot->UpdateAllCritPercentages(); + player -> m_bot->UpdateAllSpellCritChances(); + player -> m_bot->UpdateDefenseBonusesMod(); + UpdateShieldBlockValue(); + UpdateSpellDamageAndHealingBonus(); + UpdateManaRegen(); + UpdateExpertise(BASE_ATTACK); + UpdateExpertise(OFF_ATTACK); + for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) + UpdateResistances(i);*/ + + m_bot->SetHealth(GetMaxHealth()); + m_bot->SetPower(POWER_MANA, m_bot->GetMaxPower(POWER_MANA)); + m_bot->SetPower(POWER_ENERGY, m_bot->GetMaxPower(POWER_ENERGY)); + if(m_bot->GetPower(POWER_RAGE) > m_bot->GetMaxPower(POWER_RAGE)) + m_bot->SetPower(POWER_RAGE, m_bot->GetMaxPower(POWER_RAGE)); + m_bot->SetPower(POWER_FOCUS, 0); + m_bot->SetPower(POWER_HAPPINESS, 0); + } + + //MOUNT SUPPORT + if(IsMounted() && !m_bot->IsMounted()) + { + int m_mount = 0; + int m_rand = rand()%100; + + if(m_rand < 33) + m_mount = 1; + else if(m_rand > 64) + m_mount = 2; + else + m_mount = 3; + + if((GetBotClass()==11) && (GetBotRace()==4) && (m_bot->getLevel()<60)) + m_mount = 0; + if((GetBotClass()==11) && (GetBotRace()==6) && (m_bot->getLevel()<60)) + m_mount = 0; + + switch(GetBotRace()) + { + case 1: //Humain + { + if(getLevel() < 60) + { + switch(m_mount) + { + case 1: m_bot->Mount(2409); break; + case 2: m_bot->Mount(2404); break; + case 3: m_bot->Mount(2405); break; + default : break; + } + } + else + { + switch(m_mount) + { + case 1: m_bot->Mount(14338); break; + case 2: m_bot->Mount(14583); break; + case 3: m_bot->Mount(14582); break; + default : break; + } + } + break; + } + case 2: //Orc + { + if(getLevel() < 60) + { + switch(m_mount) + { + case 1: m_bot->Mount(247); break; + case 2: m_bot->Mount(2327); break; + case 3: m_bot->Mount(2328); break; + default : break; + } + } + else + { + switch(m_mount) + { + case 1: m_bot->Mount(14575); break; + case 2: m_bot->Mount(14574); break; + case 3: m_bot->Mount(14573); break; + default : break; + } + } + break; + } + case 3: //Nain + { + if(getLevel() < 60) + { + switch(m_mount) + { + case 1: m_bot->Mount(2785); break; + case 2: m_bot->Mount(2786); break; + case 3: m_bot->Mount(2736); break; + default : break; + } + } + else + { + switch(m_mount) + { + case 1: m_bot->Mount(14347); break; + case 2: m_bot->Mount(14576); break; + case 3: m_bot->Mount(14346); break; + default : break; + } + } + break; + } + case 4: //Elfe de la Nuit + { + if(getLevel() < 60) + { + switch(m_mount) + { + case 1: m_bot->Mount(6080); break; + case 2: m_bot->Mount(6448); break; + case 3: m_bot->Mount(6444); break; + default : break; + } + } + else + { + switch(m_mount) + { + case 1: m_bot->Mount(14632); break; + case 2: m_bot->Mount(14332); break; + case 3: m_bot->Mount(14331); break; + default : break; + } + } + break; + } + case 5: //Mort Vivant + { + if(getLevel() < 60) + { + switch(m_mount) + { + case 1: m_bot->Mount(10670); break; + case 2: m_bot->Mount(10671); break; + case 3: m_bot->Mount(10672); break; + default : break; + } + } + else + { + switch(m_mount) + { + case 1: m_bot->Mount(10721); break; + case 2: m_bot->Mount(10720); break; + case 3: m_bot->Mount(10719); break; + default : break; + } + } + break; + } + case 6: //Tauren + { + if(getLevel() < 60) + { + switch(m_mount) + { + case 1: m_bot->Mount(12246); break; + case 2: m_bot->Mount(11641); break; + case 3: m_bot->Mount(12245); break; + default : break; + } + } + else + { + switch(m_mount) + { + case 1: m_bot->Mount(14579); break; + case 2: m_bot->Mount(14349); break; + case 3: m_bot->Mount(14578); break; + default : break; + } + } + break; + } + case 7: //Gnome + { + if(getLevel() < 60) + { + switch(m_mount) + { + case 1: m_bot->Mount(9473); break; + case 2: m_bot->Mount(10661); break; + case 3: m_bot->Mount(6569); break; + default : break; + } + } + else + { + switch(m_mount) + { + case 1: m_bot->Mount(14376); break; + case 2: m_bot->Mount(14374); break; + case 3: m_bot->Mount(14377); break; + default : break; + } + } + break; + } + case 8: //Troll + { + if(getLevel() < 60) + { + switch(m_mount) + { + case 1: m_bot->Mount(6472); break; + case 2: m_bot->Mount(4806); break; + case 3: m_bot->Mount(6473); break; + default : break; + } + } + else + { + switch(m_mount) + { + case 1: m_bot->Mount(14344); break; + case 2: m_bot->Mount(14339); break; + case 3: m_bot->Mount(14342); break; + default : break; + } + } + break; + } + case 10: //Elfe de Sang + { + if(getLevel() < 60) + { + switch(m_mount) + { + case 1: m_bot->Mount(18696); break; + case 2: m_bot->Mount(19480); break; + case 3: m_bot->Mount(19478); break; + default : break; + } + } + else + { + switch(m_mount) + { + case 1: m_bot->Mount(19484); break; + case 2: m_bot->Mount(18697); break; + case 3: m_bot->Mount(19482); break; + default : break; + } + } + break; + } + case 11: //Draenei + { + if(getLevel() < 60) + { + switch(m_mount) + { + case 1: m_bot->Mount(17063); break; + case 2: m_bot->Mount(19870); break; + case 3: m_bot->Mount(19869); break; + default : break; + } + } + else + { + switch(m_mount) + { + case 1: m_bot->Mount(19871); break; + case 2: m_bot->Mount(19872); break; + case 3: m_bot->Mount(19873); break; + default : break; + } + } + break; + } + + } + /*NOT REALY SUPPORTED BY CLIENT BUT IT WORKS SO...*/ + m_bot->SetSpeed(MOVE_RUN, GetSpeed(MOVE_RUN), true); + } + + if(!IsMounted() && m_bot->IsMounted()) + { + m_bot->Unmount(); + CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(m_bot->GetEntry()); + m_bot->SetSpeed(MOVE_RUN, cinfo->speed, true); + } + + //SPELL AI CUSTOM SUPPORT + switch(GetBotClass()) + { + case 9: //WARLOCK SUMMON & DOT SUPPORT + { + //MIDNESS SPELL + if((GetBotMustWaitForSpell2() == 0) && (m_bot->isInCombat()) && (m_bot->GetHealth() > (m_bot->GetMaxHealth())/2)) + { + Creature* Summon1 = m_bot->SummonCreature(4677, m_bot->GetPositionX() - 2, m_bot->GetPositionY(), m_bot->GetPositionZ(), m_bot->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,20000); + Summon1->setFaction(getFaction()); + Summon1->SetLevel(getLevel()); + Summon1->CombatStop(); + Summon1->DeleteThreatList(); + Summon1->AIM_Initialize(); + Summon1->SetCharmerGUID(m_bot->GetGUID()); + CharmInfo *charmInfoSummon1 = Summon1->InitCharmInfo(Summon1); + charmInfoSummon1->SetReactState( REACT_AGGRESSIVE ); + charmInfoSummon1->SetCommandState( COMMAND_FOLLOW ); + + SetBotMustWaitForSpell2(30000); + } + //MORE POWERFULL SPELL + else if((GetBotMustWaitForSpell3() == 0) && (m_bot->isInCombat()) && (m_bot->GetHealth() < (m_bot->GetMaxHealth())/4)) + { + Creature* Summon1 = m_bot->SummonCreature(89, m_bot->GetPositionX(), m_bot->GetPositionY() + 2, m_bot->GetPositionZ(), m_bot->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,20000); + Summon1->setFaction(getFaction()); + Summon1->SetLevel(getLevel()); + Summon1->CombatStop(); + Summon1->DeleteThreatList(); + Summon1->AIM_Initialize(); + Summon1->SetCharmerGUID(m_bot->GetGUID()); + CharmInfo *charmInfoSummon1 = Summon1->InitCharmInfo(Summon1); + charmInfoSummon1->SetReactState( REACT_AGGRESSIVE ); + charmInfoSummon1->SetCommandState( COMMAND_FOLLOW ); + + Creature* Summon2 = m_bot->SummonCreature(89, m_bot->GetPositionX() + 2, m_bot->GetPositionY(), m_bot->GetPositionZ(), m_bot->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,20000); + Summon2->setFaction(getFaction()); + Summon2->SetLevel(getLevel()); + Summon2->CombatStop(); + Summon2->DeleteThreatList(); + Summon2->AIM_Initialize(); + Summon1->AIM_Initialize(); + Summon2->SetCharmerGUID(m_bot->GetGUID()); + CharmInfo *charmInfoSummon2 = Summon2->InitCharmInfo(Summon2); + charmInfoSummon2->SetReactState( REACT_AGGRESSIVE ); + charmInfoSummon2->SetCommandState( COMMAND_FOLLOW ); + + Creature* Summon3 = m_bot->SummonCreature(89, m_bot->GetPositionX() - 2, m_bot->GetPositionY(), m_bot->GetPositionZ(), m_bot->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,20000); + Summon3->setFaction(getFaction()); + Summon3->SetLevel(getLevel()); + Summon3->CombatStop(); + Summon3->DeleteThreatList(); + Summon3->AIM_Initialize(); + Summon3->AIM_Initialize(); + Summon3->SetCharmerGUID(m_bot->GetGUID()); + CharmInfo *charmInfoSummon3 = Summon3->InitCharmInfo(Summon3); + charmInfoSummon3->SetReactState( REACT_AGGRESSIVE ); + charmInfoSummon3->SetCommandState( COMMAND_FOLLOW ); + + SetBotMustWaitForSpell3(120000); + } + break; + } + case 11: //DRUID FORM SUPPORT + { + CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(m_bot->GetEntry()); + uint32 m_old_bot_form = m_bot->GetDisplayId(); + + if((GetBotMustWaitForSpell1() == 0) && (m_bot->IsInWater())) + { + if((GetBotRace()==4) && (m_bot->GetDisplayId()!=2428)) + m_bot->SetDisplayId(2428); + if((GetBotRace()==6) && (m_bot->GetDisplayId()!=2428)) + m_bot->SetDisplayId(2428); + SetBotForm(m_bot->GetDisplayId()); + SetBotMustWaitForSpell1(3000); + } + else if((GetBotMustWaitForSpell1() == 0) && (m_bot->isInCombat())) + { + if((GetBotRace()==4) && (m_bot->GetDisplayId()!=2281)) + m_bot->SetDisplayId(2281); + if((GetBotRace()==6) && (m_bot->GetDisplayId()!=2289)) + m_bot->SetDisplayId(2289); + SetBotForm(m_bot->GetDisplayId()); + SetBotMustWaitForSpell1(3000); + } + else if((GetBotMustWaitForSpell1() == 0) && (((IsMounted()) && (m_bot->getLevel()<60)) || (m_form == FORM_TRAVEL))) + { + if((GetBotRace()==4) && (m_bot->GetDisplayId()!=632)) + m_bot->SetDisplayId(632); + if((GetBotRace()==6) && (m_bot->GetDisplayId()!=632)) + m_bot->SetDisplayId(632); + SetBotForm(m_bot->GetDisplayId()); + SetBotMustWaitForSpell1(3000); + } + else if((GetBotMustWaitForSpell1() == 0) && (m_form == FORM_CAT)) + { + if((GetBotRace()==4) && (m_bot->GetDisplayId()!=892)) + m_bot->SetDisplayId(892); + if((GetBotRace()==6) && (m_bot->GetDisplayId()!=8571)) + m_bot->SetDisplayId(8571); + SetBotForm(m_bot->GetDisplayId()); + SetBotMustWaitForSpell1(3000); + } + + if(m_old_bot_form != GetBotForm()) + { + m_bot->SetSpeed(MOVE_SWIM, cinfo->speed, true); + m_bot->SetSpeed(MOVE_RUN, cinfo->speed, true); + if(GetBotForm() == 2428) + m_bot->SetSpeed(MOVE_SWIM, cinfo->speed * 1.50f, true); + if( (GetBotForm()==2281) || (GetBotForm()==2289) ) + {/* EMPTY : BOOST BEAR*/} + if(GetBotForm()==632) + m_bot->SetSpeed(MOVE_RUN, GetSpeed(MOVE_RUN), true); + if( (GetBotForm()==892) || (GetBotForm()==8571) ) + m_bot->SetSpeed(MOVE_RUN, GetSpeed(MOVE_RUN), true); + } + + //RESET FORMS + if( (!m_bot->IsInWater()) && (!m_bot->isInCombat()) && (!IsMounted()) && (m_form != FORM_TRAVEL) && (m_form != FORM_CAT) ) + { + if((GetBotRace()==4) && (m_bot->GetDisplayId()!=cinfo->DisplayID_A)) + m_bot->SetDisplayId(cinfo->DisplayID_A); + if((GetBotRace()==6) && (m_bot->GetDisplayId()!=cinfo->DisplayID_H)) + m_bot->SetDisplayId(cinfo->DisplayID_H); + m_bot->SetSpeed(MOVE_SWIM, cinfo->speed, true); + m_bot->SetSpeed(MOVE_RUN, cinfo->speed, true); + SetBotForm(m_bot->GetDisplayId()); + } + + //SPECIAL SPELL FOR DRUID + if((GetBotMustWaitForSpell2() == 0) && (GetHealth() < GetMaxHealth()/2)) + { + if((GetBotRace()==4) && (m_bot->GetDisplayId()!=cinfo->DisplayID_A)) + m_bot->SetDisplayId(cinfo->DisplayID_A); + if((GetBotRace()==6) && (m_bot->GetDisplayId()!=cinfo->DisplayID_H)) + m_bot->SetDisplayId(cinfo->DisplayID_H); + SetBotForm(m_bot->GetDisplayId()); + m_bot->SetSpeed(MOVE_SWIM, cinfo->speed, true); + m_bot->SetSpeed(MOVE_RUN, cinfo->speed, true); + m_bot->SendHealSpellLog(this, 5185, (m_bot->getLevel() / 2) * 100); + SetHealth(GetHealth() + (m_bot->getLevel() / 2) * 100); + SetBotMustWaitForSpell2(5000); + } + break; + } + }//END SWITCH + } + + if(GetBotMustWaitForSpell1() != 0) + { + SetBotMustWaitForSpell1(GetBotMustWaitForSpell1() - refreshDelay); + } + if(GetBotMustWaitForSpell2() != 0) + { + SetBotMustWaitForSpell2(GetBotMustWaitForSpell2() - refreshDelay); + } + if(GetBotMustWaitForSpell3() != 0) + { + SetBotMustWaitForSpell3(GetBotMustWaitForSpell3() - refreshDelay); + } + + m_botTimer = refreshDelay; +} + void Player::Regenerate(Powers power) { uint32 curValue = GetPower(power); Index: src/game/Player.h =================================================================== --- src/game/Player.h (revision 6319) +++ src/game/Player.h (working copy) @@ -1275,9 +1275,11 @@ void SendPetSkillWipeConfirm(); void CalcRage( uint32 damage,bool attacker ); void RegenerateAll(); + void RefreshBot(); void Regenerate(Powers power); void RegenerateHealth(); void setRegenTimer(uint32 time) {m_regenTimer = time;} + void setBotTimer(uint32 time) {m_botTimer = time;} void setWeaponChangeTimer(uint32 time) {m_weaponChangeTimer = time;} uint32 GetMoney() { return GetUInt32Value (PLAYER_FIELD_COINAGE); } @@ -1965,6 +1967,8 @@ GridReference &GetGridRef() { return m_gridRef; } + bool HaveBot(){if(m_bot==NULL) return false; else return true;} + protected: /*********************************************************/ @@ -2187,6 +2191,42 @@ float m_summon_x; float m_summon_y; float m_summon_z; + + /*********************************************************/ + /*** BOT SYSTEM ***/ + /*********************************************************/ + + Creature* m_bot; + uint8 m_bot_class; + uint8 m_bot_race; + uint32 m_bot_form; //Only for Druid + uint32 m_bot_must_wait_for_spell_1; //in ms + uint32 m_bot_must_wait_for_spell_2; //in ms + uint32 m_bot_must_wait_for_spell_3; //in ms + uint32 m_botTimer; + + Creature* GetBot(){return m_bot;} + void SetBot(Creature* bot){m_bot = bot;} + void RemoveBot(){ m_bot = NULL; m_bot_class = 0; m_bot_race = 0; m_bot_form = 0; + m_bot_must_wait_for_spell_1 = 0; m_bot_must_wait_for_spell_2 = 0; + m_bot_must_wait_for_spell_3 = 0; + } + + uint8 GetBotClass(){return m_bot_class;} + uint8 GetBotRace(){return m_bot_race;} + uint32 GetBotForm(){return m_bot_form;} + + void SetBotClass(uint8 botclass){m_bot_class = botclass;} + void SetBotRace(uint8 botrace){m_bot_race = botrace;} + void SetBotForm(uint32 form){m_bot_form = form;} + + void SetBotMustWaitForSpell1(uint32 wait){m_bot_must_wait_for_spell_1 = wait;} + uint32 GetBotMustWaitForSpell1(){return m_bot_must_wait_for_spell_1;} + void SetBotMustWaitForSpell2(uint32 wait){m_bot_must_wait_for_spell_2 = wait;} + uint32 GetBotMustWaitForSpell2(){return m_bot_must_wait_for_spell_2;} + void SetBotMustWaitForSpell3(uint32 wait){m_bot_must_wait_for_spell_3 = wait;} + uint32 GetBotMustWaitForSpell3(){return m_bot_must_wait_for_spell_3;} + private: // internal common parts for CanStore/StoreItem functions uint8 _CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool swap, Item *pSrcItem ) const;