Index: configure.ac
===================================================================
--- configure.ac (revision 4771)
+++ configure.ac (working copy)
@@ -48,9 +48,22 @@
pthread_create();,
[], [AC_MSG_ERROR([Missing pthread])])
])
+
+# LibEvent Checking
+# Default: /usr/local/bin
+LEVENT_INCLUDES="-I/usr/local/include $LEVENT_INCLUDES"
+LEVENT_LIB="-L/usr/local/lib -levent $LEVENT_LIB"
+AC_ARG_WITH(libeventdir,
+AC_HELP_STRING([--with_libeventdir=DIRECTORY],[base directory for libevent]))
+if test "$with_libeventdir" != "no"; then
+LEVENT_INCLUDES="-I$with_libeventdir/include $LEVENT_INCLUDES"
+LEVENT_LIB="-L$with_libeventdir/lib -levent $LEVENT_LIB"
+fi
+
AC_CHECK_LIB( z, compress, [ZLIB=-lz],[AC_MSG_ERROR([Missing zlib])] )
AC_CHECK_LIB( compat, ftime, [COMPATLIB=-lcompat] )
AC_CHECK_LIB( crypto, SHA1_Init, [SSLLIB=-lssl], [AC_MSG_ERROR([Missing openssl])])
+AC_CHECK_LIB( event, event_init, [], [AC_MSG_ERROR(libevent is missing, install it or use --with-libevent=DIR.)])
AC_ARG_WITH(postgresql,
[ --with-postgresql Use PostgreSQL as a backend (default: no)],
@@ -162,6 +175,7 @@
AC_CHECK_HEADERS([mysql.h mysql/mysql.h])
AC_CHECK_HEADERS([libpq-fe.h])
AC_CHECK_HEADERS([zlib.h])
+AC_CHECK_HEADERS([event.h])
## Check for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
@@ -186,6 +200,8 @@
AC_CHECK_FUNCS([atexit ftime gethostbyaddr gethostbyname gethostname gettimeofday memmove memset pow realpath select socket sqrt strchr strdup strerror strstr])
## Export defined variables
+AC_SUBST(LEVENT_LIB)
+AC_SUBST(LEVENT_INCLUDES)
AC_SUBST(ZLIB)
AC_SUBST(COMPATLIB)
AC_SUBST(SSLLIB)
@@ -223,7 +239,9 @@
src/mangosd/Makefile
src/mangosd/mangosd.conf
src/bindings/Makefile
- src/bindings/universal/Makefile
+ src/bindings/ScriptDev2/Makefile
+ src/bindings/ScriptDev2/sql/Makefile
+ src/bindings/ScriptDev2/sql/Updates/Makefile
])
## Disabled Makefiles, until they are ready for a successful make and
Index: src/bindings/Makefile.am
===================================================================
--- src/bindings/Makefile.am (revision 4771)
+++ src/bindings/Makefile.am (working copy)
@@ -14,4 +14,4 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-SUBDIRS = universal
+SUBDIRS = ScriptDev2
Index: src/game/AggressorAI.cpp
===================================================================
--- src/game/AggressorAI.cpp (revision 4773)
+++ src/game/AggressorAI.cpp (working copy)
@@ -38,7 +38,7 @@
return PERMIT_BASE_NO;
}
-AggressorAI::AggressorAI(Creature &c) : i_creature(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK)
+AggressorAI::AggressorAI(Creature &c) : i_creature(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK), pAISpellSystem(&c)
{
}
@@ -111,8 +111,10 @@
}
void
-AggressorAI::UpdateAI(const uint32 /*diff*/)
+AggressorAI::UpdateAI(const uint32 diff)
{
+ pAISpellSystem.Update(diff);
+
// update i_victimGuid if i_creature.getVictim() !=0 and changed
if(!i_creature.SelectHostilTarget() || !i_creature.getVictim())
return;
Index: src/game/AggressorAI.h
===================================================================
--- src/game/AggressorAI.h (revision 4773)
+++ src/game/AggressorAI.h (working copy)
@@ -21,6 +21,7 @@
#include "CreatureAI.h"
#include "Timer.h"
+#include "AISpellSystem.h"
class Creature;
@@ -45,6 +46,7 @@
static int Permissible(const Creature *);
private:
+ AISpellSystem pAISpellSystem;
Creature &i_creature;
uint64 i_victimGuid;
AggressorState i_state;
Index: src/game/AISpellSystem.cpp
===================================================================
--- src/game/AISpellSystem.cpp (revision 0)
+++ src/game/AISpellSystem.cpp (revision 0)
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2005,2006,2007 MaNGOS
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "AISpellSystem.h"
+#include "../shared/WorldPacket.h"
+#include "Unit.h"
+#include "Creature.h"
+#include "Player.h"
+#include "Spell.h"
+
+//Global Cooldown
+#define AI_GCD 1500
+
+//0 - NONE, 1 - Self, 2 - Enemy, 3 - AE enemy, 4 - Friendly, 5 - Area Friendly
+enum SpellTargetType
+{
+ SPELL_T_NULL = 0,
+ SPELL_T_SELF = 1,
+ SPELL_T_ENEMY = 2,
+ SPELL_T_AOEENEMY = 4,
+ SPELL_T_FRIEND = 8,
+ SPELL_T_AOEFRIEND = 16,
+};
+
+//0 - NONE, 1 - Damage, 2 - Heal, 3 - Damage over time, 4 - heal over time, 5 - Crowd Control, 6 - Snare, 7 - Buff, 8 - Debuff
+enum SpellEffectType
+{
+ SPELL_E_NULL = 0,
+ SPELL_E_DAMAGE = 1,
+ SPELL_E_HEAL = 2,
+ SPELL_E_DOT = 4,
+ SPELL_E_HOT = 8,
+ SPELL_E_CC = 16,
+ SPELL_E_SNARE = 32, //not used right now
+ SPELL_E_BUFF = 64,
+ SPELL_E_DEBUFF = 128,
+};
+
+//Also could be called the priority type. Later types = higher priority
+enum SpellType
+{
+ TYPE_NONE = 0,
+ TYPE_BUFF,
+ TYPE_AREA_DAMAGE,
+ TYPE_DIRECT_DAMAGE,
+ TYPE_CROWD_CONTROL,
+ TYPE_SNARE,
+ TYPE_DEBUFF,
+ TYPE_DAMAGE_OVER_TIME,
+ TYPE_HEAL_OVER_TIME,
+ TYPE_AREA_HEAL,
+ TYPE_HEAL,
+ TYPE_SELF_HEAL,
+
+};
+
+struct SpellHolder
+{
+ // Constants
+ uint32 SpellId;
+ uint32 RangeMin;
+ uint32 RangeMax;
+ uint32 Radius;
+ uint32 Duration;
+ uint32 CastTime;
+ uint32 Cooldown;
+ uint32 PowerCost;
+ uint8 PowerType;
+
+ uint8 Classication;
+ uint8 Targets;
+
+ // Variables
+ uint32 CooldownRemaining;
+};
+
+bool Sort(SpellHolder* SH1, SpellHolder* SH2)
+{
+ return (SH1->Classication > SH2->Classication);
+}
+
+AISpellSystem::AISpellSystem(Creature* pCreature)
+{
+ ASSERT(pCreature);
+
+ m_Unit = pCreature;
+
+ //We know size of spells is always 4
+ ClassifySpells(pCreature->m_spells, 4);
+
+ if (m_SpellList.size() > 1)
+ m_SpellList.sort(std::ptr_fun(Sort));
+}
+AISpellSystem::AISpellSystem(Unit* pUnit, const uint32* pSpellArray, const uint32 Size)
+{
+ ASSERT(pUnit);
+
+ m_Unit = pUnit;
+ ClassifySpells(pSpellArray, Size);
+
+ if (m_SpellList.size() > 1)
+ m_SpellList.sort(std::ptr_fun(Sort));
+}
+
+AISpellSystem::~AISpellSystem()
+{
+
+ if (!m_SpellList.empty())
+ for (std::list::iterator i = m_SpellList.begin(); i != m_SpellList.end(); ++i)
+ {
+ SpellHolder* pSpell = (*i);
+ delete pSpell;
+ }
+
+ m_SpellList.clear();
+}
+
+void AISpellSystem::ClassifySpells(const uint32* pSpellArray, const uint32 Size)
+{
+ if (!pSpellArray || !Size)
+ return;
+
+ //Different Entries we need to get cross referenced information from
+ SpellEntry const* TempSpell;
+ SpellRangeEntry const* TempRange;
+ SpellRadiusEntry const* TempRadius;
+ SpellDurationEntry const* TempDuration;
+ SpellCastTimesEntry const* TempCastTime;
+
+ uint32 TargetType = SPELL_T_NULL;
+ uint32 EffectType = SPELL_E_NULL;
+
+ //Check if each spell is viable(set it to null if not)
+ for (uint32 i = 0; i < Size; i++)
+ {
+
+ TempSpell = sSpellStore.LookupEntry(pSpellArray[i]);
+
+ //This spell doesn't exist
+ if (!TempSpell)
+ continue;
+
+ //Gather spell Target information and Effect information
+ for (int j=0; j<3; j++)
+ {
+ //***TARGETS***
+
+ //self
+ if ( TempSpell->EffectImplicitTargetA[j] == TARGET_SELF ||
+ TempSpell->EffectImplicitTargetB[j] == TARGET_SELF)
+ TargetType |= SPELL_T_SELF;
+ else
+
+ //single enemy
+ if ( TempSpell->EffectImplicitTargetA[j] == TARGET_CHAIN_DAMAGE ||
+ TempSpell->EffectImplicitTargetA[j] == TARGET_CURRENT_SELECTED_ENEMY ||
+ TempSpell->EffectImplicitTargetB[j] == TARGET_CHAIN_DAMAGE ||
+ TempSpell->EffectImplicitTargetB[j] == TARGET_CURRENT_SELECTED_ENEMY)
+ TargetType |= SPELL_T_ENEMY;
+ else
+
+ //AoE at enemy
+ if ( TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA ||
+ TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT ||
+ TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED ||
+ TempSpell->EffectImplicitTargetB[j] == TARGET_ALL_ENEMY_IN_AREA ||
+ TempSpell->EffectImplicitTargetB[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT ||
+ TempSpell->EffectImplicitTargetB[j] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED)
+ TargetType |= SPELL_T_AOEENEMY;
+ else
+
+ //single friend
+ if ( TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_FRIEND ||
+ TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_PARTY ||
+ TempSpell->EffectImplicitTargetB[j] == TARGET_SINGLE_FRIEND ||
+ TempSpell->EffectImplicitTargetB[j] == TARGET_SINGLE_PARTY)
+ TargetType |= SPELL_T_FRIEND;
+ else
+
+ //aoe friends
+ if ( TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_PARTY_AROUND_CASTER ||
+ TempSpell->EffectImplicitTargetA[j] == TARGET_AREAEFFECT_PARTY ||
+ TempSpell->EffectImplicitTargetB[j] == TARGET_ALL_PARTY_AROUND_CASTER ||
+ TempSpell->EffectImplicitTargetB[j] == TARGET_AREAEFFECT_PARTY)
+ TargetType |= SPELL_T_AOEFRIEND;
+
+ //***EFFECTS***
+
+ //damage effect
+ if ( TempSpell->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE ||
+ TempSpell->Effect[j] == SPELL_EFFECT_INSTAKILL ||
+ TempSpell->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE ||
+ TempSpell->Effect[j] == SPELL_EFFECT_HEALTH_LEECH)
+ EffectType |= SPELL_E_DAMAGE;
+ else
+
+ //healing effect
+ if ( TempSpell->Effect[j] == SPELL_EFFECT_HEAL ||
+ TempSpell->Effect[j] == SPELL_EFFECT_HEAL_MAX_HEALTH ||
+ TempSpell->Effect[j] == SPELL_EFFECT_HEAL_MECHANICAL )
+ EffectType |= SPELL_E_HEAL;
+ else
+
+ //Aura based effects
+ if ( TempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA ||
+ TempSpell->Effect[j] == SPELL_EFFECT_PERSISTENT_AREA_AURA ||
+ TempSpell->Effect[j] == SPELL_EFFECT_APPLY_AREA_AURA)
+ {
+
+ //damage over time
+ if ( TempSpell->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
+ TempSpell->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH)
+ EffectType |= SPELL_E_DOT;
+ else
+
+ //heal over time
+ if ( TempSpell->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_HEAL )
+ EffectType |= SPELL_E_HOT;
+ else
+
+ //CC
+ if ( TempSpell->EffectApplyAuraName[j] == SPELL_AURA_MOD_CONFUSE ||
+ TempSpell->EffectApplyAuraName[j] == SPELL_AURA_MOD_FEAR ||
+ TempSpell->EffectApplyAuraName[j] == SPELL_AURA_MOD_STUN ||
+ TempSpell->EffectApplyAuraName[j] == SPELL_AURA_MOD_ROOT ||
+ TempSpell->EffectApplyAuraName[j] == SPELL_AURA_MOD_SILENCE ||
+ TempSpell->EffectApplyAuraName[j] == SPELL_AURA_MOD_PACIFY_SILENCE ||
+ TempSpell->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE)
+ EffectType |= SPELL_E_CC;
+ else
+
+ //Buff
+ if ( IsPositiveEffect(pSpellArray[i], j))
+ EffectType |= SPELL_E_BUFF;
+ else
+
+ //Debuff
+ if ( !IsPositiveEffect(pSpellArray[i], j))
+ EffectType |= SPELL_E_DEBUFF;
+
+ //Mind Control
+ //SPELL_AURA_MOD_POSSESS
+ //SPELL_AURA_MOD_CHARM
+ //SPELL_AURA_PERSUADED
+ //SPELL_AURA_AOE_CHARM
+
+ }
+ }
+
+ //*** Final Catagorization ***
+
+ //Create a new holder for these spells
+ SpellHolder* pSpellHolder = new SpellHolder;
+
+ ASSERT(pSpellHolder);
+
+ pSpellHolder->Classication = TYPE_NONE;
+
+ //Reverse priority
+ //This classifies each spell by its most powerful effect
+ if (EffectType & SPELL_E_BUFF)
+ pSpellHolder->Classication = TYPE_BUFF;
+
+ if (EffectType & SPELL_E_DAMAGE)
+ if (TargetType & SPELL_T_ENEMY)
+ pSpellHolder->Classication = TYPE_DIRECT_DAMAGE;
+ else pSpellHolder->Classication = TYPE_AREA_DAMAGE;
+
+ if (EffectType & SPELL_E_CC)
+ pSpellHolder->Classication = TYPE_CROWD_CONTROL;
+
+ if (EffectType & SPELL_E_SNARE)
+ pSpellHolder->Classication = TYPE_SNARE;
+
+ if (EffectType & SPELL_E_DEBUFF)
+ pSpellHolder->Classication = TYPE_DEBUFF;
+
+ if (EffectType & SPELL_E_DOT)
+ pSpellHolder->Classication = TYPE_DAMAGE_OVER_TIME;
+
+ if (EffectType & SPELL_E_HOT)
+ pSpellHolder->Classication = TYPE_HEAL_OVER_TIME;
+
+ if (EffectType & SPELL_E_HEAL)
+ if (TargetType & SPELL_T_SELF)
+ pSpellHolder->Classication = TYPE_SELF_HEAL;
+ else if (TargetType & SPELL_T_FRIEND)
+ pSpellHolder->Classication = TYPE_HEAL;
+ else if (TargetType & SPELL_T_AOEFRIEND)
+ pSpellHolder->Classication = TYPE_AREA_HEAL;
+
+ TempRange = sSpellRangeStore.LookupEntry(TempSpell->rangeIndex);
+ TempRadius = sSpellRadiusStore.LookupEntry(TempSpell->EffectRadiusIndex[0]);
+ TempDuration = sSpellDurationStore.LookupEntry(TempSpell->DurationIndex);
+ TempCastTime = sCastTimesStore.LookupEntry(TempSpell->CastingTimeIndex);
+
+ // Constants
+ pSpellHolder->CastTime = TempCastTime ? TempCastTime->CastTime : 0;
+ pSpellHolder->Cooldown = TempSpell->RecoveryTime;
+ pSpellHolder->Duration = TempDuration ? TempDuration->Duration[0] : 0;
+ pSpellHolder->Radius = TempRadius ? TempRadius->Radius : 0;
+ pSpellHolder->PowerCost = TempSpell->manaCost;
+ pSpellHolder->PowerType = TempSpell->powerType;
+ pSpellHolder->RangeMax = TempRange ? TempRange->maxRange : 0;
+ pSpellHolder->RangeMin = TempRange ? TempRange->minRange : 0;
+ pSpellHolder->SpellId = pSpellArray[i];
+ pSpellHolder->Targets = TargetType;
+
+ // Reset Variables
+ pSpellHolder->CooldownRemaining = 0;
+
+ m_SpellList.push_back(pSpellHolder);
+ }
+}
+
+bool AISpellSystem::Cast(SpellHolder* pSpell)
+{
+ //Silenced so we can't cast
+ if (m_Unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
+ return false;
+
+ //Check for power
+ if (m_Unit->GetPower((Powers)(pSpell->PowerType)) < pSpell->PowerCost)
+ return false;
+
+ //Still on cooldown
+ if (pSpell->CooldownRemaining)
+ return false;
+
+ //Holder for Target. If target remains null spell will not be casted.
+ Unit* pTarget = NULL;
+
+ //Individual checks based on classification
+ switch (pSpell->Classication)
+ {
+ //Replace with checks for friendly units hp when possible
+ case TYPE_SELF_HEAL:
+ case TYPE_HEAL:
+ case TYPE_AREA_HEAL:
+ case TYPE_HEAL_OVER_TIME:
+
+ ASSERT(m_Unit->GetMaxHealth());
+
+ if (m_Unit->GetHealth()*3/m_Unit->GetMaxHealth() < 2 &&
+ !m_Unit->HasAura(pSpell->SpellId, 0) && !m_Unit->HasAura(pSpell->SpellId, 1) && !m_Unit->HasAura(pSpell->SpellId, 2))
+ pTarget = m_Unit;
+ break;
+
+ case TYPE_DEBUFF:
+ case TYPE_DAMAGE_OVER_TIME:
+ {
+ Unit* pTemp;
+
+ if (m_Unit->getThreatManager().getThreatList().empty())
+ break;
+
+ std::list::iterator i = m_Unit->getThreatManager().getThreatList().begin();
+ for (; i!=m_Unit->getThreatManager().getThreatList().end(); ++i)
+ {
+ pTemp = Unit::GetUnit((*m_Unit),(*i)->getUnitGuid());
+
+ if (pTemp && pTemp->isAlive() &&
+ !pTemp->HasAura(pSpell->SpellId, 0) && !pTemp->HasAura(pSpell->SpellId, 1) && !pTemp->HasAura(pSpell->SpellId, 2) &&
+ (m_Unit->GetDistanceSq(pTemp) < pSpell->RangeMax*pSpell->RangeMax && m_Unit->GetDistanceSq(pTemp) > pSpell->RangeMin*pSpell->RangeMin))
+ {
+ pTarget = pTemp;
+
+ //Set cooldown = to duration of spell to prevent spamming of dots and debuffs
+ //pSpell->CooldownRemaining = pSpell->Duration;
+ break;
+ }
+ }
+ }
+ break;
+
+ case TYPE_CROWD_CONTROL:
+ case TYPE_SNARE:
+ {
+ if (m_Unit->getThreatManager().getThreatList().size() < 2)
+ break;
+
+ Unit* pTemp;
+
+ std::list::iterator i = m_Unit->getThreatManager().getThreatList().begin();
+ for (; i!=m_Unit->getThreatManager().getThreatList().end(); ++i)
+ {
+ pTemp = Unit::GetUnit((*m_Unit),(*i)->getUnitGuid());
+
+ if (pTemp && pTemp->isAlive() && m_Unit->getVictim() != pTemp &&
+ !pTemp->HasAura(pSpell->SpellId, 0) && !pTemp->HasAura(pSpell->SpellId, 1) && !pTemp->HasAura(pSpell->SpellId, 2) &&
+ (m_Unit->GetDistanceSq(pTemp) < pSpell->RangeMax*pSpell->RangeMax && m_Unit->GetDistanceSq(pTemp) > pSpell->RangeMin*pSpell->RangeMin))
+ {
+ pTarget = pTemp;
+ break;
+ }
+ }
+ }
+ break;
+
+ case TYPE_AREA_DAMAGE:
+ {
+ //Check that at least 2 players are within range
+ Unit* pTemp;
+ uint32 PlayersInRange = 0;
+
+ if (m_Unit->getThreatManager().getThreatList().size() < 2)
+ break;
+
+ std::list::iterator i = m_Unit->getThreatManager().getThreatList().begin();
+ for (; i!=m_Unit->getThreatManager().getThreatList().end(); ++i)
+ {
+ pTemp = Unit::GetUnit((*m_Unit),(*i)->getUnitGuid());
+ if (pTemp && pTemp->isAlive() &&
+ (m_Unit->GetDistanceSq(pTemp) < pSpell->Radius))
+ {
+ PlayersInRange++;
+ }
+ }
+
+ //More than 1 player in range
+ if (PlayersInRange > 1)
+ pTarget = m_Unit;
+ }
+ break;
+
+ case TYPE_DIRECT_DAMAGE:
+ {
+ //This causes the creature to cast on the first player that this target is allowed to hit (range issues etc)
+ //Threat list is always in order from Highest threat to lowest
+ Unit* pTemp;
+
+ if (m_Unit->getThreatManager().getThreatList().empty())
+ break;
+
+ std::list::iterator i = m_Unit->getThreatManager().getThreatList().begin();
+ for (; i!=m_Unit->getThreatManager().getThreatList().end(); ++i)
+ {
+ pTemp = Unit::GetUnit((*m_Unit),(*i)->getUnitGuid());
+ if (pTemp && pTemp->isAlive() &&
+ (m_Unit->GetDistanceSq(pTemp) < pSpell->RangeMax*pSpell->RangeMax && m_Unit->GetDistanceSq(pTemp) > pSpell->RangeMin*pSpell->RangeMin))
+ {
+ pTarget = pTemp;
+ break;
+ }
+ }
+ }
+ break;
+
+ case TYPE_BUFF:
+ //Later replace with checks for other creatures in area
+ if (!m_Unit->HasAura(pSpell->SpellId, 0) && !m_Unit->HasAura(pSpell->SpellId, 1) && !m_Unit->HasAura(pSpell->SpellId, 2) &&
+ (!m_Unit->isInCombat() || m_Unit->GetPower((Powers)pSpell->PowerType) > m_Unit->GetMaxPower((Powers)pSpell->PowerType)-pSpell->PowerCost))
+ pTarget = m_Unit;
+ break;
+
+ case TYPE_NONE:
+ //Simply attempt to cast on current target since we have no idea what this spell does
+ pTarget = m_Unit->getVictim();
+ break;
+ };
+
+ if (!pTarget)
+ return false;
+
+ //Cast spell
+ m_Unit->CastSpell(pTarget, pSpell->SpellId, false);
+ pSpell->CooldownRemaining += pSpell->Cooldown + AI_GCD;
+
+ return true;
+}
+
+bool AISpellSystem::Update(const uint32 diff)
+{
+ if (!m_Unit || m_SpellList.empty())
+ return false;
+
+ //Decrease cooldowns
+ for (std::list::iterator i = m_SpellList.begin(); i != m_SpellList.end(); ++i)
+ {
+ if ((*i)->CooldownRemaining)
+ if ((*i)->CooldownRemaining > diff)
+ (*i)->CooldownRemaining -= diff;
+ else (*i)->CooldownRemaining = 0;
+ }
+
+ //Prevent Movement while casting
+ if (m_Unit->IsNonMeleeSpellCasted(false))
+ {
+ m_Unit->StopMoving();
+
+ return true;
+ }
+
+ //Cast first valid spell
+ for (std::list::iterator i = m_SpellList.begin(); i != m_SpellList.end(); ++i)
+ {
+ //Cast returns true if the spell was properly cast
+ if (Cast((*i)))
+ break;
+ }
+
+ return true;
+}
Index: src/game/AISpellSystem.h
===================================================================
--- src/game/AISpellSystem.h (revision 0)
+++ src/game/AISpellSystem.h (revision 0)
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2005,2006,2007 MaNGOS
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Unit.h"
+
+class Creature;
+struct SpellHolder;
+
+class AISpellSystem
+{
+public:
+ AISpellSystem(Creature*);
+ AISpellSystem(Unit*, const uint32* pSpellArray, const uint32 Size);
+ ~AISpellSystem();
+
+ bool Update(const uint32);
+
+private:
+ Unit* m_Unit;
+ std::list m_SpellList;
+
+ void ClassifySpells(const uint32* pSpellArray, const uint32 Size);
+ bool Cast(SpellHolder*);
+};
Index: src/game/BattleGroundMgr.cpp
===================================================================
--- src/game/BattleGroundMgr.cpp (revision 4773)
+++ src/game/BattleGroundMgr.cpp (working copy)
@@ -79,10 +79,34 @@
else
m_QueuedPlayers[queue_id].Horde++;
- /* temporary BG queue status message
- std::ostringstream str;
- str << "Battleground queue invited status: horde: " << m_QueuedPlayers[queue_id].Horde << ", aliance: " << m_QueuedPlayers[queue_id].Alliance;
- plr->Say(str.str(), LANG_UNIVERSAL);*/
+ /* temporary BG queue status message */
+ //#TODO: add proper check for the number of players in queue
+ if ( m_QueuedPlayers[queue_id].Alliance == 5 || m_QueuedPlayers[queue_id].Alliance == 7 || m_QueuedPlayers[queue_id].Alliance == 10 ||
+ m_QueuedPlayers[queue_id].Horde == 5 || m_QueuedPlayers[queue_id].Horde == 7 || m_QueuedPlayers[queue_id].Horde == 10 )
+ {
+ std::ostringstream str;
+ str << "Battleground queue invited status for ";
+ switch (bgTypeId)
+ {
+ case 1:
+ str << "Alterac Valley"; break;
+ case 2:
+ str << "Warsong Gulch"; break;
+ case 3:
+ str << "Arathi Basin"; break;
+ //#TODO: add other cases
+ default:
+ str << "other bg / arena"; break;
+ }
+ str << ", for level ";
+ if(plr->getLevel()!=sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
+ str << (int)(plr->getLevel()/10)*10 << " - " << (int)(plr->getLevel()/10)*10+9;
+ else
+ str << plr->getLevel();
+ str << ":\n Horde: " << m_QueuedPlayers[queue_id].Horde << ", Alliance: " << m_QueuedPlayers[queue_id].Alliance;
+ sWorld.SendWorldText(str.str().c_str(), NULL);
+ }
+ /* plr->Say(str.str(), LANG_UNIVERSAL);*/
this->Update(bgTypeId, queue_id);
}
Index: src/game/Chat.cpp
===================================================================
--- src/game/Chat.cpp (revision 4773)
+++ src/game/Chat.cpp (working copy)
@@ -265,15 +265,18 @@
{ "die", SEC_ADMINISTRATOR, &ChatHandler::HandleDieCommand, "", NULL },
{ "revive", SEC_ADMINISTRATOR, &ChatHandler::HandleReviveCommand, "", NULL },
{ "dismount", SEC_PLAYER, &ChatHandler::HandleDismountCommand, "", NULL },
+ { "activequests", SEC_PLAYER, &ChatHandler::HandleActiveQuestsCommand, "", NULL },
{ "setmodel", SEC_GAMEMASTER, &ChatHandler::HandleSetModelCommand, "", NULL },
{ "factionid", SEC_GAMEMASTER, &ChatHandler::HandleFactionIdCommand, "", NULL },
{ "listgm", SEC_PLAYER, &ChatHandler::HandleGMListCommand, "", NULL },
+ { "bug", SEC_PLAYER, &ChatHandler::HandleBugCommand, "", NULL },
{ "gm", SEC_MODERATOR, &ChatHandler::HandleGMmodeCommand, "", NULL },
{ "gps", SEC_MODERATOR, &ChatHandler::HandleGPSCommand, "", NULL },
{ "guid", SEC_GAMEMASTER, &ChatHandler::HandleGUIDCommand, "", NULL },
{ "help", SEC_PLAYER, &ChatHandler::HandleHelpCommand, "", NULL },
{ "info", SEC_PLAYER, &ChatHandler::HandleInfoCommand, "", NULL },
{ "npcinfo", SEC_ADMINISTRATOR, &ChatHandler::HandleNpcInfoCommand, "", NULL },
+ { "creatureinfo", SEC_PLAYER, &ChatHandler::HandleCreatureInfoCommand, "", NULL },
{ "npcinfoset", SEC_ADMINISTRATOR, &ChatHandler::HandleNpcInfoSetCommand, "", NULL },
{ "addvendoritem",SEC_GAMEMASTER, &ChatHandler::HandleAddVendorItemCommand, "", NULL },
{ "delvendoritem",SEC_GAMEMASTER, &ChatHandler::HandleDelVendorItemCommand, "", NULL },
@@ -840,4 +843,4 @@
}
return obj;
-}
\ No newline at end of file
+}
Index: src/game/Chat.h
===================================================================
--- src/game/Chat.h (revision 4773)
+++ src/game/Chat.h (working copy)
@@ -91,6 +91,7 @@
bool HandleDismountCommand(const char* args);
bool HandleSaveCommand(const char* args);
bool HandleGMListCommand(const char* args);
+ bool HandleBugCommand(const char* args);
bool HandleNamegoCommand(const char* args);
bool HandleGonameCommand(const char* args);
@@ -254,6 +255,7 @@
bool HandleExploreCheatCommand(const char* args);
bool HandleTextEmoteCommand(const char* args);
bool HandleNpcInfoCommand(const char* args);
+ bool HandleCreatureInfoCommand(const char* args);
bool HandleNpcInfoSetCommand(const char* args);
bool HandleHoverCommand(const char* args);
bool HandleLevelUpCommand(const char* args);
@@ -292,6 +294,7 @@
bool HandleLookupSkillCommand(const char* args);
bool HandleLookupSpellCommand(const char* args);
bool HandleLookupQuestCommand(const char* args);
+ bool HandleActiveQuestsCommand(const char* args);
bool HandleLookupCreatureCommand(const char* args);
bool HandleLookupObjectCommand(const char* args);
bool HandlePasswordCommand(const char* args);
Index: src/game/Group.cpp
===================================================================
--- src/game/Group.cpp (revision 4773)
+++ src/game/Group.cpp (working copy)
@@ -575,6 +575,7 @@
{
uint16 dest;
LootItem *item = &(roll->loot->items[roll->itemSlot]);
+ if(!item){roll->loot->NotifyItemRemoved(roll->itemSlot); roll->loot->unlootedCount--; RollId.erase(roll); return;}
uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count, false );
if ( msg == EQUIP_ERR_OK )
{
Index: src/game/Language.h
===================================================================
--- src/game/Language.h (revision 4773)
+++ src/game/Language.h (working copy)
@@ -375,6 +375,7 @@
#define LANG_COMMAND_GRAVEYARDERROR "No faction in Graveyard with id= #%u , fix your DB"
#define LANG_COMMAND_GRAVEYARD_NOTEAM "invalid team, please fix database"
#define LANG_COMMAND_GRAVEYARD_ANY "any"
+#define LANG_COMMAND_BUGREPORTED "Aciu %s, Atsimink kad sita komanda galima naudoti tik norint pranesti zaidimo klaidas."
#define LANG_COMMAND_GRAVEYARD_ALLIANCE "alliance"
#define LANG_COMMAND_GRAVEYARD_HORDE "horde"
#define LANG_COMMAND_GRAVEYARDNEAREST "Graveyard #%u (faction: %s) is nearest from linked to zone #%u."
@@ -478,6 +479,7 @@
#define LANG_MOVEGENS_UNKNOWN "Unknown movement generator (%u)"
#define LANG_NPCINFO_CHAR "Player selected NPC\nGUID: %u.\nFaction: %u.\nnpcFlags: %u.\nEntry: %u.\nDisplayID: %u (Native: %u)."
+#define LANG_CREATUREINFO_CHAR "Player selected Creature\nGUID: %u.\nEntry: %u."
#define LANG_NPCINFO_LEVEL "Level: %u."
#define LANG_NPCINFO_HEALTH "Health (base): %u. (max): %u. (current): %u."
#define LANG_NPCINFO_FLAGS "Field Flags: %u.\nDynamic Flags: %u.\nFaction Template: %u."
Index: src/game/Level0.cpp
===================================================================
--- src/game/Level0.cpp (revision 4773)
+++ src/game/Level0.cpp (working copy)
@@ -297,3 +297,52 @@
SendSysMessage(LANG_BAD_VALUE);
return true;
}
+
+bool ChatHandler::HandleCreatureInfoCommand(const char* args)
+{
+ Creature* target = getSelectedCreature();
+
+ if(!target)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ return true;
+ }
+
+ uint32 Entry = target->GetUInt32Value(OBJECT_FIELD_ENTRY);
+ CreatureInfo const* cInfo = target->GetCreatureInfo();
+
+ PSendSysMessage(LANG_CREATUREINFO_CHAR, target->GetDBTableGUIDLow(), Entry);
+
+ return true;
+}
+
+bool ChatHandler::HandleBugCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ std::string bug=args;
+ WorldDatabase.escape_string(bug);
+ PSendSysMessage(LANG_COMMAND_BUGREPORTED, m_session->GetPlayerName());
+ WorldDatabase.PExecute("INSERT INTO `bugs` (`name`, `bug`) VALUES ('%s', '%s')", m_session->GetPlayerName(), bug.c_str());
+ return true;
+}
+
+bool ChatHandler::HandleActiveQuestsCommand(const char* args)
+{
+ QuestStatusMap* qmap = &(m_session->GetPlayer()->getQuestStatusMap());
+ for(QuestStatusMap::iterator itr=qmap->begin(); itr!=qmap->end(); ++itr)
+ {
+ if(itr->second.m_status == QUEST_STATUS_INCOMPLETE)
+ {
+ std::ostringstream str;
+ str << "Quest id #" << itr->first;
+ QueryResult *result=WorldDatabase.PQuery("SELECT `Title` FROM `quest_template` WHERE `entry`='%u'", itr->first);
+ if(result)
+ { str << " - " << result->Fetch()[0].GetCppString(); delete result; }
+ str << " is active.";
+ PSendSysMessage(str.str().c_str());
+ }
+ }
+ return true;
+}
\ No newline at end of file
Index: src/game/Spell.cpp
===================================================================
--- src/game/Spell.cpp (revision 4773)
+++ src/game/Spell.cpp (working copy)
@@ -2554,6 +2554,8 @@
else if(m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MECHANIC_IMMUNITY)
mechanic_immune |= 1 << m_spellInfo->EffectMiscValue[i];
}
+ //immune movement impairement and loss of control
+ if(m_spellInfo->Id==(uint32)42292)mechanic_immune=0x9967da6;
//Check whether the cast should be prevented by any state you might have.
uint8 prevented_reason = 0;
@@ -3417,7 +3419,7 @@
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
{
if(m_caster->GetTypeId() != TYPEID_PLAYER) return SPELL_FAILED_TARGET_NOT_PLAYER;
- if(m_spellInfo->rangeIndex == 1 || m_spellInfo->rangeIndex == 2 || m_spellInfo->rangeIndex == 7)
+ if(m_spellInfo->rangeIndex == 1 || m_spellInfo->rangeIndex == 2 || m_spellInfo->rangeIndex == 6 || m_spellInfo->rangeIndex == 7)
break;
Item *pItem = ((Player*)m_caster)->GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED );
if(!pItem || pItem->IsBroken() || pItem->GetProto()->Class != ITEM_CLASS_WEAPON )
Index: src/game/SpellAuras.cpp
===================================================================
--- src/game/SpellAuras.cpp (revision 4773)
+++ src/game/SpellAuras.cpp (working copy)
@@ -2645,8 +2645,9 @@
void Aura::HandleModMechanicImmunity(bool apply, bool Real)
{
- uint32 mechanic = m_modifier.m_miscvalue;
-
+ uint32 mechanic = 1 << m_modifier.m_miscvalue;
+ //immune movement impairement and loss of control
+ if(GetId()==(uint32)42292)mechanic=0x9967da6;
if(apply)
{
Unit::AuraMap& Auras = m_target->GetAuras();
@@ -2655,7 +2656,10 @@
next = iter;
next++;
SpellEntry const *spell = iter->second->GetSpellProto();
- if(spell->Mechanic == mechanic && !iter->second->IsPositive() && spell->Id != GetId())
+ if( (1<Mechanic) & mechanic //check for mechanic mask
+ && !( spell->Attributes & 0x20000000) //spells unaffected by invulnerability
+ && !iter->second->IsPositive() //only remove negative spells
+ && spell->Id != GetId())
{
m_target->RemoveAurasDueToSpell(spell->Id);
if(Auras.empty())
Index: src/game/SpellEffects.cpp
===================================================================
--- src/game/SpellEffects.cpp (revision 4773)
+++ src/game/SpellEffects.cpp (working copy)
@@ -2887,7 +2887,7 @@
bool criticalhit = false;
WeaponAttackType attType = BASE_ATTACK;
- if(m_spellInfo->rangeIndex != 1 && m_spellInfo->rangeIndex != 2 && m_spellInfo->rangeIndex != 7)
+ if(m_spellInfo->rangeIndex != 1 && m_spellInfo->rangeIndex != 2 && m_spellInfo->rangeIndex != 6 && m_spellInfo->rangeIndex != 7)
{
attType = RANGED_ATTACK;
@@ -2952,7 +2952,7 @@
// take ammo
if(m_caster->GetTypeId() == TYPEID_PLAYER)
{
- if(m_spellInfo->rangeIndex != 1 && m_spellInfo->rangeIndex != 2 && m_spellInfo->rangeIndex != 7)
+ if(m_spellInfo->rangeIndex != 1 && m_spellInfo->rangeIndex != 2 && m_spellInfo->rangeIndex != 6 && m_spellInfo->rangeIndex != 7)
{
Item *pItem = ((Player*)m_caster)->GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED );
if(!pItem || pItem->IsBroken())
Index: src/game/Unit.cpp
===================================================================
--- src/game/Unit.cpp (revision 4773)
+++ src/game/Unit.cpp (working copy)
@@ -3998,7 +3998,40 @@
CastSpell(pVictim,37378,true,castItem,triggredByAura);
return;
}
+ // Windfury weapon
+ case 33757:
+ case 33756:
+ case 33755:
+ case 33754:
+ case 33727:
+ {
+ // never proc from another windfury attack or the AP bonus will stack and we will get really huge criticals
+ if ( !procSpell || ( procSpell->Id != 25504 && procSpell->Id != 33750 ) ){
+ // give us temporary AP bonus
+ if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(25504) )
+ return;
+
+ HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(dummySpell->EffectBasePoints[0]+1), true);
+
+ int32 EffectBasePoints0 = CalculateDamage(BASE_ATTACK);
+
+ CastCustomSpell(pVictim,25504,&EffectBasePoints0,NULL,NULL,true,NULL,triggredByAura);
+ // cooldown
+ ((Player*)this)->AddSpellCooldown(25504,0,time(NULL) + 3);
+
+ if (haveOffhandWeapon())
+ {
+ int32 EffectBasePoints0 = CalculateDamage(OFF_ATTACK);
+ CastCustomSpell(pVictim,33750,&EffectBasePoints0,NULL,NULL,true,NULL,triggredByAura);
+ // cooldown
+ ((Player*)this)->AddSpellCooldown(33750,0,time(NULL) + 3);
+ }
+
+ // remove it
+ HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(dummySpell->EffectBasePoints[0]+1), false);
+ }
+ }
default: break;
}
Index: src/mangosd/Makefile.am
===================================================================
--- src/mangosd/Makefile.am (revision 4771)
+++ src/mangosd/Makefile.am (working copy)
@@ -33,8 +33,8 @@
WorldRunnable.h
## Link world daemon against the shared library
-mangos_worldd_LDADD = ../bindings/universal/libmangosscript.la ../game/libmangosgame.a ../shared/libmangosdatabase.a ../shared/libmangosconfig.a ../shared/libmangosauth.a ../shared/libmangosshared.a ../shared/libmangosvmaps.a ../shared/libmangosnetwork.a ../framework/libmangosframework.a ../../dep/src/zthread/libZThread.la ../../dep/src/g3dlite/libg3dlite.a
-mangos_worldd_LDFLAGS = -L../../dep/src/zthread -L../../dep/src/g3dlite -L../bindings/universal/ $(MYSQL_LIBS) $(POSTGRE_LIBS) -L$(libdir) $(ZLIB) $(COMPATLIB) $(SSLLIB) -export-dynamic
+mangos_worldd_LDADD = ../bindings/ScriptDev2/libmangosscript.la ../game/libmangosgame.a ../shared/libmangosdatabase.a ../shared/libmangosconfig.a ../shared/libmangosauth.a ../shared/libmangosshared.a ../shared/libmangosvmaps.a ../shared/libmangosnetwork.a ../framework/libmangosframework.a ../../dep/src/zthread/libZThread.la ../../dep/src/g3dlite/libg3dlite.a
+mangos_worldd_LDFLAGS = -L../../dep/src/zthread -L../../dep/src/g3dlite -L../bindings/ScriptDev2/ $(MYSQL_LIBS) $(POSTGRE_LIBS) -L$(libdir) $(ZLIB) $(COMPATLIB) $(SSLLIB) -export-dynamic
## Additional files to include when running 'make dist'
# Include world daemon configuration
Index: src/shared/Network/Socket.cpp
===================================================================
--- src/shared/Network/Socket.cpp (revision 4771)
+++ src/shared/Network/Socket.cpp (working copy)
@@ -345,6 +345,15 @@
SetCloseAndDelete();
return INVALID_SOCKET;
}
+
+ optval = 1;
+ if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_TCP, TCP_NODELAY)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ closesocket(s);
+ SetCloseAndDelete();
+ return INVALID_SOCKET;
+ }
}
return s;
}
@@ -1254,3 +1263,6 @@
+
+
+