All pastes #1074678 Raw Edit

Untitled

public text v1 · immutable
#1074678 ·published 2008-07-17 20:04 UTC
rendered paste body
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<Player> &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;