From 478ca470836b4f28935b1a26f89337a09ed3f3dc Mon Sep 17 00:00:00 2001 From: gvcoman Date: Sun, 16 Nov 2008 14:38:02 -0500 Subject: Delete possessed AI only on creature delete. --HG-- branch : trunk --- src/game/Creature.cpp | 11 ++++++----- src/game/Creature.h | 2 +- src/game/Player.cpp | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 5e3d3ac9f8e..646feb4951f 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -147,7 +147,11 @@ Creature::~Creature() delete i_AI; i_AI = NULL; - DeletePossessedAI(); + if (i_AI_possessed) + { + delete i_AI_possessed; + i_AI_possessed = NULL; + } } void Creature::AddToWorld() @@ -555,13 +559,10 @@ void Creature::InitPossessedAI() i_AI->OnPossess(true); } -void Creature::DeletePossessedAI() +void Creature::DisablePossessedAI() { if (!i_AI_possessed) return; - delete i_AI_possessed; - i_AI_possessed = NULL; - // Signal the old AI that it's been re-enabled i_AI->OnPossess(false); } diff --git a/src/game/Creature.h b/src/game/Creature.h index be421f26ad2..fbebcb1e06e 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -457,7 +457,7 @@ class TRINITY_DLL_SPEC Creature : public Unit bool AIM_Initialize(); void InitPossessedAI(); - void DeletePossessedAI(); + void DisablePossessedAI(); void AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type); CreatureAI* AI() { return isPossessed() && i_AI_possessed ? i_AI_possessed : i_AI; } diff --git a/src/game/Player.cpp b/src/game/Player.cpp index ec882ef1154..0ebd331ed04 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -18896,8 +18896,8 @@ void Player::RemovePossess(bool attack) if(attack) target->AddThreat(this, 1000000.0f); } - // Delete the assigned possessed AI - ((Creature*)target)->DeletePossessedAI(); + // Disable the assigned possessed AI + ((Creature*)target)->DisablePossessedAI(); } } -- cgit v1.2.3 From 4cd86b2ed5fd320dd1adbbd64338513ef0d4a001 Mon Sep 17 00:00:00 2001 From: gvcoman Date: Mon, 17 Nov 2008 18:47:24 -0500 Subject: Added TARGET_UNIT_AREA_SCRIPT target to the list of target types using custom targets defined in spell_script_target. --HG-- branch : trunk --- src/game/Spell.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 64e9ba04bcc..c3670686679 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -1530,6 +1530,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list &TagUnitMap) }break; case TARGET_SCRIPT: case TARGET_SCRIPT_COORDINATES: + case TARGET_UNIT_AREA_SCRIPT: { SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id); SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id); -- cgit v1.2.3 From 868c2ef17592a047d48bdf618328eadf15aa9372 Mon Sep 17 00:00:00 2001 From: gvcoman Date: Mon, 17 Nov 2008 18:57:16 -0500 Subject: * Implemented new summon possessed summon type for spell 49352. * Unsummon all summon possessed units on summoning aura cancel. --HG-- branch : trunk --- src/game/SharedDefines.h | 2 +- src/game/Spell.cpp | 1 + src/game/SpellAuras.cpp | 8 -------- src/game/SpellEffects.cpp | 2 +- src/game/SpellHandler.cpp | 9 +++++++++ 5 files changed, 12 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 481598f71ea..dd097c68bcb 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -2069,7 +2069,7 @@ enum SummonType SUMMON_TYPE_CRITTER2 = 407, SUMMON_TYPE_CRITTER3 = 307, SUMMON_TYPE_UNKNOWN5 = 409, - SUMMON_TYPE_UNKNOWN2 = 427, + SUMMON_TYPE_POSESSED3 = 427, SUMMON_TYPE_POSESSED2 = 428 }; diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index c3670686679..eae232085ed 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -3863,6 +3863,7 @@ uint8 Spell::CanCast(bool strict) { case SUMMON_TYPE_POSESSED: case SUMMON_TYPE_POSESSED2: + case SUMMON_TYPE_POSESSED3: case SUMMON_TYPE_DEMON: case SUMMON_TYPE_SUMMON: { diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 37c02fb549d..3548c19e6bc 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -49,7 +49,6 @@ #include "GridNotifiers.h" #include "GridNotifiersImpl.h" #include "CellImpl.h" -#include "TemporarySummon.h" #define NULL_AURA_SLOT 0xFF @@ -2014,13 +2013,6 @@ void Aura::HandleAuraDummy(bool apply, bool Real) m_target->CastSpell(m_target,47287,true,NULL,this); return; } - - // Eye of Kilrogg, unsummon eye when aura is gone - if(GetId() == 126 && caster->GetTypeId() == TYPEID_PLAYER && caster->GetCharm()) - { - ((TemporarySummon*)caster->GetCharm())->UnSummon(); - return; - } } // AT APPLY & REMOVE diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index f32a89db2b4..9789200939b 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -3136,6 +3136,7 @@ void Spell::EffectSummonType(uint32 i) break; case SUMMON_TYPE_POSESSED: case SUMMON_TYPE_POSESSED2: + case SUMMON_TYPE_POSESSED3: EffectSummonPossessed(i); break; case SUMMON_TYPE_WILD: @@ -3160,7 +3161,6 @@ void Spell::EffectSummonType(uint32 i) EffectSummonTotem(i); break; case SUMMON_TYPE_UNKNOWN1: - case SUMMON_TYPE_UNKNOWN2: case SUMMON_TYPE_UNKNOWN3: case SUMMON_TYPE_UNKNOWN4: case SUMMON_TYPE_UNKNOWN5: diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index 3ed9c04a259..868ba1d0ff8 100644 --- a/src/game/SpellHandler.cpp +++ b/src/game/SpellHandler.cpp @@ -33,6 +33,7 @@ #include "MapManager.h" #include "ScriptCalls.h" #include "Totem.h" +#include "TemporarySummon.h" void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { @@ -370,6 +371,14 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket) ((Unit*)_player->GetFarsightTarget())->RemoveAurasDueToSpellByCancel(spellId); return; } + else if (spellInfo->Effect[i] == SPELL_EFFECT_SUMMON && + (spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED || + spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED2 || + spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED3)) + { + // Possession is removed in the UnSummon function + ((TemporarySummon*)caster->GetCharm())->UnSummon(); + } } } -- cgit v1.2.3 From 53de62cee0fb2923459241b46eaea2ab2051d974 Mon Sep 17 00:00:00 2001 From: gvcoman Date: Mon, 17 Nov 2008 19:36:38 -0500 Subject: Fix typo. --HG-- branch : trunk --- src/game/SpellHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index 868ba1d0ff8..10b955fb7af 100644 --- a/src/game/SpellHandler.cpp +++ b/src/game/SpellHandler.cpp @@ -377,7 +377,7 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket) spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED3)) { // Possession is removed in the UnSummon function - ((TemporarySummon*)caster->GetCharm())->UnSummon(); + ((TemporarySummon*)_player->GetCharm())->UnSummon(); } } } -- cgit v1.2.3 From df6a8e5f8e11e914843db0dc9c41f3a415587cfd Mon Sep 17 00:00:00 2001 From: gvcoman Date: Tue, 18 Nov 2008 15:52:52 -0500 Subject: Unsummon summon as possessed creatures on spell channeling interrupt. --HG-- branch : trunk --- src/game/Unit.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src') diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index ade913d8c26..264b81bd0cd 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -46,6 +46,7 @@ #include "GridNotifiersImpl.h" #include "CellImpl.h" #include "Path.h" +#include "TemporarySummon.h" #include @@ -3424,6 +3425,23 @@ void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id) m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel(); m_currentSpells[CURRENT_CHANNELED_SPELL]->SetReferencedFromCurrent(false); m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL; + + // Unsummon any summoned as possessed creatures on channel interrupt + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); + if (!spellInfo || !interrupted) + return; + for (int i = 0; i < 3; i++) + { + if (spellInfo->Effect[i] == SPELL_EFFECT_SUMMON && + (spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED || + spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED2 || + spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED3)) + { + // Possession is removed in the UnSummon function + if (GetCharm()) + ((TemporarySummon*)GetCharm())->UnSummon(); + } + } } } -- cgit v1.2.3 From 4495efa1aeaf58650dfcee95f709969cc33ce6c8 Mon Sep 17 00:00:00 2001 From: gvcoman Date: Thu, 20 Nov 2008 20:27:04 -0500 Subject: * Don't allow pets to attack in melee if owner is pacified. This applies for possessed "pets" as well. * Use proper spell ID in unsummoning possessed units on channeling interrupt. * Allow only once to init pet bar for CharmInfo * Export CharmInfo to be available to scripts * Allow to disable the melee attack command when initializing the pet action bar --HG-- branch : trunk --- src/game/PetHandler.cpp | 7 +++++++ src/game/PossessedAI.cpp | 4 ++-- src/game/Unit.cpp | 35 ++++++++++++++++++++++------------- src/game/Unit.h | 5 +++-- 4 files changed, 34 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index f95be3a9352..d912f42c22b 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -97,6 +97,13 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) break; case COMMAND_ATTACK: //spellid=1792 //ATTACK { + // Can't attack if owner is pacified + if (_player->HasAuraType(SPELL_AURA_MOD_PACIFY)) + { + //pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED); + //TODO: Send proper error message to client + return; + } // only place where pet can be player pet->clearUnitState(UNIT_STAT_FOLLOW); uint64 selguid = _player->GetSelection(); diff --git a/src/game/PossessedAI.cpp b/src/game/PossessedAI.cpp index 6b803303185..8abbb7f2603 100644 --- a/src/game/PossessedAI.cpp +++ b/src/game/PossessedAI.cpp @@ -24,7 +24,7 @@ void PossessedAI::AttackStart(Unit *u) { - if( !u ) + if( !u || i_pet.GetCharmer()->HasAuraType(SPELL_AURA_MOD_PACIFY)) return; if (i_pet.getVictim() && u != i_pet.getVictim()) @@ -95,7 +95,7 @@ void PossessedAI::UpdateAI(const uint32 diff) _stopAttack(); // i_victimGuid == 0 && i_pet.getVictim() == NULL now return; } - else if(i_pet.IsWithinCombatDist(i_pet.getVictim(), ATTACK_DISTANCE) && i_pet.isAttackReady()) + else if(i_pet.IsWithinCombatDist(i_pet.getVictim(), ATTACK_DISTANCE) && i_pet.isAttackReady() && !i_pet.GetCharmer()->HasAuraType(SPELL_AURA_MOD_PACIFY)) { i_pet.AttackerStateUpdate(i_pet.getVictim()); diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 264b81bd0cd..c54ab4b7f0d 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -3421,15 +3421,8 @@ void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id) // channeled spells are interrupted if they are not finished, even if they are delayed if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id==spell_id)) { - if (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) - m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel(); - m_currentSpells[CURRENT_CHANNELED_SPELL]->SetReferencedFromCurrent(false); - m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL; - // Unsummon any summoned as possessed creatures on channel interrupt - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); - if (!spellInfo || !interrupted) - return; + SpellEntry const *spellInfo = m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo; for (int i = 0; i < 3; i++) { if (spellInfo->Effect[i] == SPELL_EFFECT_SUMMON && @@ -3442,6 +3435,11 @@ void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id) ((TemporarySummon*)GetCharm())->UnSummon(); } } + + if (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) + m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel(); + m_currentSpells[CURRENT_CHANNELED_SPELL]->SetReferencedFromCurrent(false); + m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL; } } @@ -9820,7 +9818,7 @@ CharmInfo* Unit::InitCharmInfo(Unit *charm) } CharmInfo::CharmInfo(Unit* unit) -: m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_reactState(REACT_PASSIVE), m_petnumber(0) +: m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_reactState(REACT_PASSIVE), m_petnumber(0), m_barInit(false) { for(int i =0; i<4; ++i) { @@ -9831,6 +9829,9 @@ CharmInfo::CharmInfo(Unit* unit) void CharmInfo::InitPetActionBar() { + if (m_barInit) + return; + // the first 3 SpellOrActions are attack, follow and stay for(uint32 i = 0; i < 3; i++) { @@ -9845,17 +9846,25 @@ void CharmInfo::InitPetActionBar() PetActionBar[i + 3].Type = ACT_DISABLED; PetActionBar[i + 3].SpellOrAction = 0; } + m_barInit = true; } -void CharmInfo::InitEmptyActionBar() +void CharmInfo::InitEmptyActionBar(bool withAttack) { - for(uint32 x = 1; x < 10; ++x) + if (m_barInit) + return; + + for(uint32 x = 0; x < 10; ++x) { PetActionBar[x].Type = ACT_CAST; PetActionBar[x].SpellOrAction = 0; } - PetActionBar[0].Type = ACT_COMMAND; - PetActionBar[0].SpellOrAction = COMMAND_ATTACK; + if (withAttack) + { + PetActionBar[0].Type = ACT_COMMAND; + PetActionBar[0].SpellOrAction = COMMAND_ATTACK; + } + m_barInit = true; } void CharmInfo::InitPossessCreateSpells() diff --git a/src/game/Unit.h b/src/game/Unit.h index 028c590c06f..e9e44804444 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -640,7 +640,7 @@ struct CharmSpellEntry typedef std::list SharedVisionList; -struct CharmInfo +struct TRINITY_DLL_SPEC CharmInfo { public: explicit CharmInfo(Unit* unit); @@ -657,7 +657,7 @@ struct CharmInfo void InitPossessCreateSpells(); void InitCharmCreateSpells(); void InitPetActionBar(); - void InitEmptyActionBar(); + void InitEmptyActionBar(bool withAttack = true); //return true if successful bool AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate = ACT_DECIDE); void ToggleCreatureAutocast(uint32 spellid, bool apply); @@ -671,6 +671,7 @@ struct CharmInfo CommandStates m_CommandState; ReactStates m_reactState; uint32 m_petnumber; + bool m_barInit; }; // for clearing special attacks -- cgit v1.2.3 From 837ce55de88e33825eb66814d07d33c1f869f7a7 Mon Sep 17 00:00:00 2001 From: gvcoman Date: Fri, 21 Nov 2008 13:57:54 -0500 Subject: Added tonk mine and steam tonk scripts. --HG-- branch : trunk --- src/bindings/scripts/scripts/npc/npcs_special.cpp | 67 +++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'src') diff --git a/src/bindings/scripts/scripts/npc/npcs_special.cpp b/src/bindings/scripts/scripts/npc/npcs_special.cpp index 3e1cb0a9165..e0e53ab55b1 100644 --- a/src/bindings/scripts/scripts/npc/npcs_special.cpp +++ b/src/bindings/scripts/scripts/npc/npcs_special.cpp @@ -825,6 +825,63 @@ bool GossipSelect_npc_sayge(Player *player, Creature *_Creature, uint32 sender, return true; } +struct TRINITY_DLL_DECL npc_steam_tonkAI : public ScriptedAI +{ + npc_steam_tonkAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() {} + void Aggro(Unit *who) {} + + void OnPossess(bool apply) + { + if (apply) + { + // Initialize the action bar without the melee attack command + m_creature->InitCharmInfo(m_creature); + m_creature->GetCharmInfo()->InitEmptyActionBar(false); + } + } + +}; + +CreatureAI* GetAI_npc_steam_tonk(Creature *_Creature) +{ + return new npc_steam_tonkAI(_Creature); +} + +#define SPELL_TONK_MINE_DETONATE 25099 + +struct TRINITY_DLL_DECL npc_tonk_mineAI : public ScriptedAI +{ + npc_tonk_mineAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 ExplosionTimer; + + void Reset() + { + ExplosionTimer = 3000; + } + + void Aggro(Unit *who) {} + void AttackStart(Unit *who) {} + void MoveInLineOfSight(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if (ExplosionTimer < diff) + { + m_creature->CastSpell(m_creature, SPELL_TONK_MINE_DETONATE, true); + m_creature->setDeathState(DEAD); // unsummon it + } else + ExplosionTimer -= diff; + } +}; + +CreatureAI* GetAI_npc_tonk_mine(Creature *_Creature) +{ + return new npc_tonk_mineAI(_Creature); +} + void AddSC_npcs_special() { Script *newscript; @@ -875,4 +932,14 @@ void AddSC_npcs_special() newscript->pGossipHello = &GossipHello_npc_sayge; newscript->pGossipSelect = &GossipSelect_npc_sayge; m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_steam_tonk"; + newscript->GetAI = &GetAI_npc_steam_tonk; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_tonk_mine"; + newscript->GetAI = &GetAI_npc_tonk_mine; + m_scripts[nrscripts++] = newscript; } -- cgit v1.2.3 From 1bd37790b564be487ed16ae897484a4d8c80a2de Mon Sep 17 00:00:00 2001 From: gvcoman Date: Fri, 21 Nov 2008 19:12:44 -0500 Subject: Added SetAggressive calls to steam tonk and tonk mine scripts. --HG-- branch : trunk --- src/bindings/scripts/scripts/npc/npcs_special.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/bindings/scripts/scripts/npc/npcs_special.cpp b/src/bindings/scripts/scripts/npc/npcs_special.cpp index 61091ab54e2..ae23ea38f32 100644 --- a/src/bindings/scripts/scripts/npc/npcs_special.cpp +++ b/src/bindings/scripts/scripts/npc/npcs_special.cpp @@ -839,7 +839,11 @@ struct TRINITY_DLL_DECL npc_steam_tonkAI : public ScriptedAI // Initialize the action bar without the melee attack command m_creature->InitCharmInfo(m_creature); m_creature->GetCharmInfo()->InitEmptyActionBar(false); + + m_creature->SetAggressive(false); } + else + m_creature->SetAggressive(true); } }; @@ -853,7 +857,11 @@ CreatureAI* GetAI_npc_steam_tonk(Creature *_Creature) struct TRINITY_DLL_DECL npc_tonk_mineAI : public ScriptedAI { - npc_tonk_mineAI(Creature *c) : ScriptedAI(c) {Reset();} + npc_tonk_mineAI(Creature *c) : ScriptedAI(c) + { + m_creature->SetAggressive(false); + Reset(); + } uint32 ExplosionTimer; -- cgit v1.2.3 From a2c168155d2871aae22d1e4bccc3951525f6085d Mon Sep 17 00:00:00 2001 From: gvcoman Date: Fri, 21 Nov 2008 19:27:24 -0500 Subject: Fix line endings in npcs_special.cpp to LF. --HG-- branch : trunk --- src/bindings/scripts/scripts/npc/npcs_special.cpp | 1906 ++++++++++----------- 1 file changed, 953 insertions(+), 953 deletions(-) (limited to 'src') diff --git a/src/bindings/scripts/scripts/npc/npcs_special.cpp b/src/bindings/scripts/scripts/npc/npcs_special.cpp index ae23ea38f32..d762c8803e6 100644 --- a/src/bindings/scripts/scripts/npc/npcs_special.cpp +++ b/src/bindings/scripts/scripts/npc/npcs_special.cpp @@ -1,953 +1,953 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * 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 - */ - -/* ScriptData -SDName: Npcs_Special -SD%Complete: 100 -SDComment: To be used for special NPCs that are located globally. Support for quest 3861 (Cluck!), 6622 and 6624 (Triage) -SDCategory: NPCs -EndScriptData -*/ - -/* ContentData -npc_chicken_cluck 100% support for quest 3861 (Cluck!) -npc_dancing_flames 100% midsummer event NPC -npc_guardian 100% guardianAI used to prevent players from accessing off-limits areas. Not in use by SD2 -npc_injured_patient 100% patients for triage-quests (6622 and 6624) -npc_doctor 100% Gustaf Vanhowzen and Gregory Victor, quest 6622 and 6624 (Triage) -npc_mount_vendor 100% Regular mount vendors all over the world. Display gossip if player doesn't meet the requirements to buy -npc_rogue_trainer 80% Scripted trainers, so they are able to offer item 17126 for class quest 6681 -npc_sayge 100% Darkmoon event fortune teller, buff player based on answers given -EndContentData */ - -#include "precompiled.h" - -/*######## -# npc_chicken_cluck -#########*/ - -#define QUEST_CLUCK 3861 -#define EMOTE_A_HELLO "looks up at you quizzically. Maybe you should inspect it?" -#define EMOTE_H_HELLO "looks at you unexpectadly." -#define CLUCK_TEXT2 "starts pecking at the feed." -#define FACTION_FRIENDLY 84 -#define FACTION_CHICKEN 31 - -struct TRINITY_DLL_DECL npc_chicken_cluckAI : public ScriptedAI -{ - npc_chicken_cluckAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 ResetFlagTimer; - - void Reset() - { - ResetFlagTimer = 120000; - - m_creature->setFaction(FACTION_CHICKEN); - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - // Reset flags after a certain time has passed so that the next player has to start the 'event' again - if(m_creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) - { - if(ResetFlagTimer < diff) - EnterEvadeMode(); - else ResetFlagTimer -= diff; - } - - if(m_creature->SelectHostilTarget() && m_creature->getVictim()) - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_npc_chicken_cluck(Creature *_Creature) -{ - return new npc_chicken_cluckAI(_Creature); -} - -bool ReceiveEmote_npc_chicken_cluck( Player *player, Creature *_Creature, uint32 emote ) -{ - if( emote == TEXTEMOTE_CHICKEN ) - { - if( player->GetTeam() == ALLIANCE ) - { - if( rand()%30 == 1 ) - { - if( player->GetQuestStatus(QUEST_CLUCK) == QUEST_STATUS_NONE ) - { - _Creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); - _Creature->setFaction(FACTION_FRIENDLY); - _Creature->MonsterTextEmote(EMOTE_A_HELLO, 0); - } - } - } else - _Creature->MonsterTextEmote(EMOTE_H_HELLO,0); - } - if( emote == TEXTEMOTE_CHEER && player->GetTeam() == ALLIANCE ) - if( player->GetQuestStatus(QUEST_CLUCK) == QUEST_STATUS_COMPLETE ) - { - _Creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); - _Creature->setFaction(FACTION_FRIENDLY); - _Creature->MonsterTextEmote(CLUCK_TEXT2, 0); - } - - return true; -} - -bool QuestAccept_npc_chicken_cluck(Player *player, Creature *_Creature, const Quest *_Quest ) -{ - if(_Quest->GetQuestId() == QUEST_CLUCK) - ((npc_chicken_cluckAI*)_Creature->AI())->Reset(); - - return true; -} - -bool QuestComplete_npc_chicken_cluck(Player *player, Creature *_Creature, const Quest *_Quest) -{ - if(_Quest->GetQuestId() == QUEST_CLUCK) - ((npc_chicken_cluckAI*)_Creature->AI())->Reset(); - - return true; -} - -/*###### -## npc_dancing_flames -######*/ - -bool ReceiveEmote_npc_dancing_flames( Player *player, Creature *_Creature, uint32 emote ) -{ - if( emote == TEXTEMOTE_DANCE ) - _Creature->CastSpell(player,47057,false); - - return true; -} - -/*###### -## Triage quest -######*/ - -#define SAY_DOC1 "I'm saved! Thank you, doctor!" -#define SAY_DOC2 "HOORAY! I AM SAVED!" -#define SAY_DOC3 "Sweet, sweet embrace... take me..." - -struct Location -{ - float x, y, z, o; -}; - -#define DOCTOR_ALLIANCE 12939 - -static Location AllianceCoords[]= -{ - { // Top-far-right bunk as seen from entrance - -3757.38, -4533.05, 14.16, 3.62 - }, - { // Top-far-left bunk - -3754.36, -4539.13, 14.16, 5.13 - }, - { // Far-right bunk - -3749.54, -4540.25, 14.28, 3.34 - }, - { // Right bunk near entrance - -3742.10, -4536.85, 14.28, 3.64 - }, - { // Far-left bunk - -3755.89, -4529.07, 14.05, 0.57 - }, - { // Mid-left bunk - -3749.51, -4527.08, 14.07, 5.26 - }, - { // Left bunk near entrance - -3746.37, -4525.35, 14.16, 5.22 - }, -}; - -#define ALLIANCE_COORDS 7 - -//alliance run to where -#define A_RUNTOX -3742.96 -#define A_RUNTOY -4531.52 -#define A_RUNTOZ 11.91 - -#define DOCTOR_HORDE 12920 - -static Location HordeCoords[]= -{ - { // Left, Behind - -1013.75, -3492.59, 62.62, 4.34 - }, - { // Right, Behind - -1017.72, -3490.92, 62.62, 4.34 - }, - { // Left, Mid - -1015.77, -3497.15, 62.82, 4.34 - }, - { // Right, Mid - -1019.51, -3495.49, 62.82, 4.34 - }, - { // Left, front - -1017.25, -3500.85, 62.98, 4.34 - }, - { // Right, Front - -1020.95, -3499.21, 62.98, 4.34 - } -}; - -#define HORDE_COORDS 6 - -//horde run to where -#define H_RUNTOX -1016.44 -#define H_RUNTOY -3508.48 -#define H_RUNTOZ 62.96 - -const uint32 AllianceSoldierId[3] = -{ - 12938, // 12938 Injured Alliance Soldier - 12936, // 12936 Badly injured Alliance Soldier - 12937 // 12937 Critically injured Alliance Soldier -}; - -const uint32 HordeSoldierId[3] = -{ - 12923, //12923 Injured Soldier - 12924, //12924 Badly injured Soldier - 12925 //12925 Critically injured Soldier -}; - -/*###### -## npc_doctor (handles both Gustaf Vanhowzen and Gregory Victor) -######*/ - -struct TRINITY_DLL_DECL npc_doctorAI : public ScriptedAI -{ - uint64 Playerguid; - - uint32 SummonPatient_Timer; - uint32 SummonPatientCount; - uint32 PatientDiedCount; - uint32 PatientSavedCount; - - bool Event; - - std::list Patients; - std::vector Coordinates; - - npc_doctorAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset(){} - - void BeginEvent(Player* player); - void PatientDied(Location* Point); - void PatientSaved(Creature* soldier, Player* player, Location* Point); - void UpdateAI(const uint32 diff); - - void Aggro(Unit* who){} -}; - -/*##### -## npc_injured_patient (handles all the patients, no matter Horde or Alliance) -#####*/ - -struct TRINITY_DLL_DECL npc_injured_patientAI : public ScriptedAI -{ - npc_injured_patientAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint64 Doctorguid; - - Location* Coord; - - void Reset() - { - Doctorguid = 0; - - Coord = NULL; - //no select - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //no regen health - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - //to make them lay with face down - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_DEAD); - - uint32 mobId = m_creature->GetEntry(); - - switch (mobId) - { //lower max health - case 12923: - case 12938: //Injured Soldier - m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.75)); - break; - case 12924: - case 12936: //Badly injured Soldier - m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.50)); - break; - case 12925: - case 12937: //Critically injured Soldier - m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.25)); - break; - } - } - - void Aggro(Unit* who){} - - void SpellHit(Unit *caster, const SpellEntry *spell) - { - if (caster->GetTypeId() == TYPEID_PLAYER && m_creature->isAlive() && spell->Id == 20804) - { - if( (((Player*)caster)->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (((Player*)caster)->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE)) - { - if(Doctorguid) - { - Creature* Doctor = ((Creature*)Unit::GetUnit((*m_creature), Doctorguid)); - if(Doctor) - ((npc_doctorAI*)Doctor->AI())->PatientSaved(m_creature, ((Player*)caster), Coord); - } - } - //make not selectable - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //regen health - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - //stand up - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_NONE); - DoSay(SAY_DOC1,LANG_UNIVERSAL,NULL); - - uint32 mobId = m_creature->GetEntry(); - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - switch (mobId) - { - case 12923: - case 12924: - case 12925: - m_creature->GetMotionMaster()->MovePoint(0, H_RUNTOX, H_RUNTOY, H_RUNTOZ); - break; - case 12936: - case 12937: - case 12938: - m_creature->GetMotionMaster()->MovePoint(0, A_RUNTOX, A_RUNTOY, A_RUNTOZ); - break; - } - } - return; - } - - void UpdateAI(const uint32 diff) - { - if (m_creature->isAlive() && m_creature->GetHealth() > 6) - { //lower HP on every world tick makes it a useful counter, not officlone though - m_creature->SetHealth(uint32(m_creature->GetHealth()-5) ); - } - - if (m_creature->isAlive() && m_creature->GetHealth() <= 6) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->setDeathState(JUST_DIED); - m_creature->SetFlag(UNIT_DYNAMIC_FLAGS, 32); - - if(Doctorguid) - { - Creature* Doctor = ((Creature*)Unit::GetUnit((*m_creature), Doctorguid)); - if(Doctor) - ((npc_doctorAI*)Doctor->AI())->PatientDied(Coord); - } - } - } -}; - -CreatureAI* GetAI_npc_injured_patient(Creature *_Creature) -{ - return new npc_injured_patientAI (_Creature); -} - -/* -npc_doctor (continue) -*/ - -void npc_doctorAI::BeginEvent(Player* player) -{ - Playerguid = player->GetGUID(); - - SummonPatient_Timer = 10000; - SummonPatientCount = 0; - PatientDiedCount = 0; - PatientSavedCount = 0; - - switch(m_creature->GetEntry()) - { - case DOCTOR_ALLIANCE: - for(uint8 i = 0; i < ALLIANCE_COORDS; ++i) - Coordinates.push_back(&AllianceCoords[i]); - break; - - case DOCTOR_HORDE: - for(uint8 i = 0; i < HORDE_COORDS; ++i) - Coordinates.push_back(&HordeCoords[i]); - break; - } - - Event = true; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -} - -void npc_doctorAI::PatientDied(Location* Point) -{ - Player* player = ((Player*)Unit::GetUnit((*m_creature), Playerguid)); - if(player && ((player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE))) - { - PatientDiedCount++; - if (PatientDiedCount > 5 && Event) - { - if(player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) - player->FailQuest(6624); - else if(player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE) - player->FailQuest(6622); - - Event = false; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - Coordinates.push_back(Point); - } -} - -void npc_doctorAI::PatientSaved(Creature* soldier, Player* player, Location* Point) -{ - if(player && Playerguid == player->GetGUID()) - { - if((player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE)) - { - PatientSavedCount++; - if(PatientSavedCount == 15) - { - if(!Patients.empty()) - { - std::list::iterator itr; - for(itr = Patients.begin(); itr != Patients.end(); ++itr) - { - Creature* Patient = ((Creature*)Unit::GetUnit((*m_creature), *itr)); - if( Patient ) - Patient->setDeathState(JUST_DIED); - } - } - - if(player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) - player->AreaExploredOrEventHappens(6624); - else if(player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE) - player->AreaExploredOrEventHappens(6622); - - Event = false; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - Coordinates.push_back(Point); - } - } -} - -void npc_doctorAI::UpdateAI(const uint32 diff) -{ - if(Event && SummonPatientCount >= 20) - { - Event = false; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - if(Event) - if(SummonPatient_Timer < diff) - { - Creature* Patient = NULL; - Location* Point = NULL; - - if(Coordinates.empty()) - return; - - std::vector::iterator itr = Coordinates.begin()+rand()%Coordinates.size(); - uint32 patientEntry = 0; - - switch(m_creature->GetEntry()) - { - case DOCTOR_ALLIANCE: patientEntry = AllianceSoldierId[rand()%3]; break; - case DOCTOR_HORDE: patientEntry = HordeSoldierId[rand()%3]; break; - default: - error_log("SD2: Invalid entry for Triage doctor. Please check your database"); - return; - } - - Point = *itr; - - Patient = m_creature->SummonCreature(patientEntry, Point->x, Point->y, Point->z, Point->o, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - - if(Patient) - { - Patients.push_back(Patient->GetGUID()); - ((npc_injured_patientAI*)Patient->AI())->Doctorguid = m_creature->GetGUID(); - if(Point) - ((npc_injured_patientAI*)Patient->AI())->Coord = Point; - Coordinates.erase(itr); - } - SummonPatient_Timer = 10000; - SummonPatientCount++; - }else SummonPatient_Timer -= diff; -} - -bool QuestAccept_npc_doctor(Player *player, Creature *creature, Quest const *quest ) -{ - if((quest->GetQuestId() == 6624) || (quest->GetQuestId() == 6622)) - ((npc_doctorAI*)creature->AI())->BeginEvent(player); - - return true; -} - -CreatureAI* GetAI_npc_doctor(Creature *_Creature) -{ - return new npc_doctorAI (_Creature); -} - -/*###### -## npc_guardian -######*/ - -#define SPELL_DEATHTOUCH 5 -#define SAY_AGGRO "This area is closed!" - -struct TRINITY_DLL_DECL npc_guardianAI : public ScriptedAI -{ - npc_guardianAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if (m_creature->isAttackReady()) - { - m_creature->CastSpell(m_creature->getVictim(),SPELL_DEATHTOUCH, true); - m_creature->resetAttackTimer(); - } - } -}; - -CreatureAI* GetAI_npc_guardian(Creature *_Creature) -{ - return new npc_guardianAI (_Creature); -} - -/*###### -## npc_mount_vendor -######*/ - -bool GossipHello_npc_mount_vendor(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - bool canBuy; - canBuy = false; - uint32 vendor = _Creature->GetEntry(); - uint8 race = player->getRace(); - - switch (vendor) - { - case 384: //Katie Hunter - case 1460: //Unger Statforth - case 2357: //Merideth Carlson - case 4885: //Gregor MacVince - if (player->GetReputationRank(72) != REP_EXALTED && race != RACE_HUMAN) - player->SEND_GOSSIP_MENU(5855, _Creature->GetGUID()); - else canBuy = true; - break; - case 1261: //Veron Amberstill - if (player->GetReputationRank(47) != REP_EXALTED && race != RACE_DWARF) - player->SEND_GOSSIP_MENU(5856, _Creature->GetGUID()); - else canBuy = true; - break; - case 3362: //Ogunaro Wolfrunner - if (player->GetReputationRank(76) != REP_EXALTED && race != RACE_ORC) - player->SEND_GOSSIP_MENU(5841, _Creature->GetGUID()); - else canBuy = true; - break; - case 3685: //Harb Clawhoof - if (player->GetReputationRank(81) != REP_EXALTED && race != RACE_TAUREN) - player->SEND_GOSSIP_MENU(5843, _Creature->GetGUID()); - else canBuy = true; - break; - case 4730: //Lelanai - if (player->GetReputationRank(69) != REP_EXALTED && race != RACE_NIGHTELF) - player->SEND_GOSSIP_MENU(5844, _Creature->GetGUID()); - else canBuy = true; - break; - case 4731: //Zachariah Post - if (player->GetReputationRank(68) != REP_EXALTED && race != RACE_UNDEAD_PLAYER) - player->SEND_GOSSIP_MENU(5840, _Creature->GetGUID()); - else canBuy = true; - break; - case 7952: //Zjolnir - if (player->GetReputationRank(530) != REP_EXALTED && race != RACE_TROLL) - player->SEND_GOSSIP_MENU(5842, _Creature->GetGUID()); - else canBuy = true; - break; - case 7955: //Milli Featherwhistle - if (player->GetReputationRank(54) != REP_EXALTED && race != RACE_GNOME) - player->SEND_GOSSIP_MENU(5857, _Creature->GetGUID()); - else canBuy = true; - break; - case 16264: //Winaestra - if (player->GetReputationRank(911) != REP_EXALTED && race != RACE_BLOODELF) - player->SEND_GOSSIP_MENU(10305, _Creature->GetGUID()); - else canBuy = true; - break; - case 17584: //Torallius the Pack Handler - if (player->GetReputationRank(930) != REP_EXALTED && race != RACE_DRAENEI) - player->SEND_GOSSIP_MENU(10239, _Creature->GetGUID()); - else canBuy = true; - break; - } - - if (canBuy) - { - if (_Creature->isVendor()) - player->ADD_GOSSIP_ITEM( 1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - } - return true; -} - -bool GossipSelect_npc_mount_vendor(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if (action == GOSSIP_ACTION_TRADE) - player->SEND_VENDORLIST( _Creature->GetGUID() ); - - return true; -} - -/*###### -## npc_rogue_trainer -######*/ - -bool GossipHello_npc_rogue_trainer(Player *player, Creature *_Creature) -{ - if( _Creature->isQuestGiver() ) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( _Creature->isTrainer() ) - player->ADD_GOSSIP_ITEM(2, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); - - if( _Creature->isCanTrainingAndResetTalentsOf(player) ) - player->ADD_GOSSIP_ITEM(2, "I wish to unlearn my talents", GOSSIP_SENDER_MAIN, GOSSIP_OPTION_UNLEARNTALENTS); - - if( player->getClass() == CLASS_ROGUE && player->getLevel() >= 24 && !player->HasItemCount(17126,1) && !player->GetQuestRewardStatus(6681) ) - { - player->ADD_GOSSIP_ITEM(0, "", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(5996, _Creature->GetGUID()); - } else - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_rogue_trainer(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch( action ) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,21100,false); - break; - case GOSSIP_ACTION_TRAIN: - player->SEND_TRAINERLIST( _Creature->GetGUID() ); - break; - case GOSSIP_OPTION_UNLEARNTALENTS: - player->CLOSE_GOSSIP_MENU(); - player->SendTalentWipeConfirm( _Creature->GetGUID() ); - break; - } - return true; -} - -/*###### -## npc_sayge -######*/ - -#define SPELL_DMG 23768 //dmg -#define SPELL_RES 23769 //res -#define SPELL_ARM 23767 //arm -#define SPELL_SPI 23738 //spi -#define SPELL_INT 23766 //int -#define SPELL_STM 23737 //stm -#define SPELL_STR 23735 //str -#define SPELL_AGI 23736 //agi -#define SPELL_FORTUNE 23765 //faire fortune - -bool GossipHello_npc_sayge(Player *player, Creature *_Creature) -{ - if(_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( player->HasSpellCooldown(SPELL_INT) || - player->HasSpellCooldown(SPELL_ARM) || - player->HasSpellCooldown(SPELL_DMG) || - player->HasSpellCooldown(SPELL_RES) || - player->HasSpellCooldown(SPELL_STR) || - player->HasSpellCooldown(SPELL_AGI) || - player->HasSpellCooldown(SPELL_STM) || - player->HasSpellCooldown(SPELL_SPI) ) - player->SEND_GOSSIP_MENU(7393, _Creature->GetGUID()); - else - { - player->ADD_GOSSIP_ITEM(0, "Yes", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(7339, _Creature->GetGUID()); - } - - return true; -} - -void SendAction_npc_sayge(Player *player, Creature *_Creature, uint32 action) -{ - switch(action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(0, "Slay the Man", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->ADD_GOSSIP_ITEM(0, "Turn him over to liege", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->ADD_GOSSIP_ITEM(0, "Confiscate the corn", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - player->ADD_GOSSIP_ITEM(0, "Let him go and have the corn", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(7340, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(0, "Execute your friend painfully", GOSSIP_SENDER_MAIN+1, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Execute your friend painlessly", GOSSIP_SENDER_MAIN+2, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Let your friend go", GOSSIP_SENDER_MAIN+3, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(7341, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM(0, "Confront the diplomat", GOSSIP_SENDER_MAIN+4, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Show not so quiet defiance", GOSSIP_SENDER_MAIN+5, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Remain quiet", GOSSIP_SENDER_MAIN+2, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(7361, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM(0, "Speak against your brother openly", GOSSIP_SENDER_MAIN+6, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Help your brother in", GOSSIP_SENDER_MAIN+7, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Keep your brother out without letting him know", GOSSIP_SENDER_MAIN+8, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(7362, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM(0, "Take credit, keep gold", GOSSIP_SENDER_MAIN+5, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Take credit, share the gold", GOSSIP_SENDER_MAIN+4, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Let the knight take credit", GOSSIP_SENDER_MAIN+3, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(7363, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM(0, "Thanks", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - player->SEND_GOSSIP_MENU(7364, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - _Creature->CastSpell(player, SPELL_FORTUNE, false); - player->SEND_GOSSIP_MENU(7365, _Creature->GetGUID()); - break; - } -} - -bool GossipSelect_npc_sayge(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch(sender) - { - case GOSSIP_SENDER_MAIN: - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+1: - _Creature->CastSpell(player, SPELL_DMG, false); - player->AddSpellCooldown(SPELL_DMG,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+2: - _Creature->CastSpell(player, SPELL_RES, false); - player->AddSpellCooldown(SPELL_RES,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+3: - _Creature->CastSpell(player, SPELL_ARM, false); - player->AddSpellCooldown(SPELL_ARM,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+4: - _Creature->CastSpell(player, SPELL_SPI, false); - player->AddSpellCooldown(SPELL_SPI,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+5: - _Creature->CastSpell(player, SPELL_INT, false); - player->AddSpellCooldown(SPELL_INT,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+6: - _Creature->CastSpell(player, SPELL_STM, false); - player->AddSpellCooldown(SPELL_STM,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+7: - _Creature->CastSpell(player, SPELL_STR, false); - player->AddSpellCooldown(SPELL_STR,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+8: - _Creature->CastSpell(player, SPELL_AGI, false); - player->AddSpellCooldown(SPELL_AGI,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - } - return true; -} - -struct TRINITY_DLL_DECL npc_steam_tonkAI : public ScriptedAI -{ - npc_steam_tonkAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() {} - void Aggro(Unit *who) {} - - void OnPossess(bool apply) - { - if (apply) - { - // Initialize the action bar without the melee attack command - m_creature->InitCharmInfo(m_creature); - m_creature->GetCharmInfo()->InitEmptyActionBar(false); - - m_creature->SetAggressive(false); - } - else - m_creature->SetAggressive(true); - } - -}; - -CreatureAI* GetAI_npc_steam_tonk(Creature *_Creature) -{ - return new npc_steam_tonkAI(_Creature); -} - -#define SPELL_TONK_MINE_DETONATE 25099 - -struct TRINITY_DLL_DECL npc_tonk_mineAI : public ScriptedAI -{ - npc_tonk_mineAI(Creature *c) : ScriptedAI(c) - { - m_creature->SetAggressive(false); - Reset(); - } - - uint32 ExplosionTimer; - - void Reset() - { - ExplosionTimer = 3000; - } - - void Aggro(Unit *who) {} - void AttackStart(Unit *who) {} - void MoveInLineOfSight(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if (ExplosionTimer < diff) - { - m_creature->CastSpell(m_creature, SPELL_TONK_MINE_DETONATE, true); - m_creature->setDeathState(DEAD); // unsummon it - } else - ExplosionTimer -= diff; - } -}; - -CreatureAI* GetAI_npc_tonk_mine(Creature *_Creature) -{ - return new npc_tonk_mineAI(_Creature); -} - -void AddSC_npcs_special() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_chicken_cluck"; - newscript->GetAI = GetAI_npc_chicken_cluck; - newscript->pReceiveEmote = &ReceiveEmote_npc_chicken_cluck; - newscript->pQuestAccept = &QuestAccept_npc_chicken_cluck; - newscript->pQuestComplete = &QuestComplete_npc_chicken_cluck; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="npc_dancing_flames"; - newscript->pReceiveEmote = &ReceiveEmote_npc_dancing_flames; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="npc_injured_patient"; - newscript->GetAI = GetAI_npc_injured_patient; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="npc_doctor"; - newscript->GetAI = GetAI_npc_doctor; - newscript->pQuestAccept = &QuestAccept_npc_doctor; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="npc_guardian"; - newscript->GetAI = GetAI_npc_guardian; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="npc_mount_vendor"; - newscript->pGossipHello = &GossipHello_npc_mount_vendor; - newscript->pGossipSelect = &GossipSelect_npc_mount_vendor; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="npc_rogue_trainer"; - newscript->pGossipHello = &GossipHello_npc_rogue_trainer; - newscript->pGossipSelect = &GossipSelect_npc_rogue_trainer; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="npc_sayge"; - newscript->pGossipHello = &GossipHello_npc_sayge; - newscript->pGossipSelect = &GossipSelect_npc_sayge; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="npc_steam_tonk"; - newscript->GetAI = &GetAI_npc_steam_tonk; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="npc_tonk_mine"; - newscript->GetAI = &GetAI_npc_tonk_mine; - newscript->RegisterSelf(); -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * 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 + */ + +/* ScriptData +SDName: Npcs_Special +SD%Complete: 100 +SDComment: To be used for special NPCs that are located globally. Support for quest 3861 (Cluck!), 6622 and 6624 (Triage) +SDCategory: NPCs +EndScriptData +*/ + +/* ContentData +npc_chicken_cluck 100% support for quest 3861 (Cluck!) +npc_dancing_flames 100% midsummer event NPC +npc_guardian 100% guardianAI used to prevent players from accessing off-limits areas. Not in use by SD2 +npc_injured_patient 100% patients for triage-quests (6622 and 6624) +npc_doctor 100% Gustaf Vanhowzen and Gregory Victor, quest 6622 and 6624 (Triage) +npc_mount_vendor 100% Regular mount vendors all over the world. Display gossip if player doesn't meet the requirements to buy +npc_rogue_trainer 80% Scripted trainers, so they are able to offer item 17126 for class quest 6681 +npc_sayge 100% Darkmoon event fortune teller, buff player based on answers given +EndContentData */ + +#include "precompiled.h" + +/*######## +# npc_chicken_cluck +#########*/ + +#define QUEST_CLUCK 3861 +#define EMOTE_A_HELLO "looks up at you quizzically. Maybe you should inspect it?" +#define EMOTE_H_HELLO "looks at you unexpectadly." +#define CLUCK_TEXT2 "starts pecking at the feed." +#define FACTION_FRIENDLY 84 +#define FACTION_CHICKEN 31 + +struct TRINITY_DLL_DECL npc_chicken_cluckAI : public ScriptedAI +{ + npc_chicken_cluckAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 ResetFlagTimer; + + void Reset() + { + ResetFlagTimer = 120000; + + m_creature->setFaction(FACTION_CHICKEN); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + // Reset flags after a certain time has passed so that the next player has to start the 'event' again + if(m_creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) + { + if(ResetFlagTimer < diff) + EnterEvadeMode(); + else ResetFlagTimer -= diff; + } + + if(m_creature->SelectHostilTarget() && m_creature->getVictim()) + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_chicken_cluck(Creature *_Creature) +{ + return new npc_chicken_cluckAI(_Creature); +} + +bool ReceiveEmote_npc_chicken_cluck( Player *player, Creature *_Creature, uint32 emote ) +{ + if( emote == TEXTEMOTE_CHICKEN ) + { + if( player->GetTeam() == ALLIANCE ) + { + if( rand()%30 == 1 ) + { + if( player->GetQuestStatus(QUEST_CLUCK) == QUEST_STATUS_NONE ) + { + _Creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + _Creature->setFaction(FACTION_FRIENDLY); + _Creature->MonsterTextEmote(EMOTE_A_HELLO, 0); + } + } + } else + _Creature->MonsterTextEmote(EMOTE_H_HELLO,0); + } + if( emote == TEXTEMOTE_CHEER && player->GetTeam() == ALLIANCE ) + if( player->GetQuestStatus(QUEST_CLUCK) == QUEST_STATUS_COMPLETE ) + { + _Creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + _Creature->setFaction(FACTION_FRIENDLY); + _Creature->MonsterTextEmote(CLUCK_TEXT2, 0); + } + + return true; +} + +bool QuestAccept_npc_chicken_cluck(Player *player, Creature *_Creature, const Quest *_Quest ) +{ + if(_Quest->GetQuestId() == QUEST_CLUCK) + ((npc_chicken_cluckAI*)_Creature->AI())->Reset(); + + return true; +} + +bool QuestComplete_npc_chicken_cluck(Player *player, Creature *_Creature, const Quest *_Quest) +{ + if(_Quest->GetQuestId() == QUEST_CLUCK) + ((npc_chicken_cluckAI*)_Creature->AI())->Reset(); + + return true; +} + +/*###### +## npc_dancing_flames +######*/ + +bool ReceiveEmote_npc_dancing_flames( Player *player, Creature *_Creature, uint32 emote ) +{ + if( emote == TEXTEMOTE_DANCE ) + _Creature->CastSpell(player,47057,false); + + return true; +} + +/*###### +## Triage quest +######*/ + +#define SAY_DOC1 "I'm saved! Thank you, doctor!" +#define SAY_DOC2 "HOORAY! I AM SAVED!" +#define SAY_DOC3 "Sweet, sweet embrace... take me..." + +struct Location +{ + float x, y, z, o; +}; + +#define DOCTOR_ALLIANCE 12939 + +static Location AllianceCoords[]= +{ + { // Top-far-right bunk as seen from entrance + -3757.38, -4533.05, 14.16, 3.62 + }, + { // Top-far-left bunk + -3754.36, -4539.13, 14.16, 5.13 + }, + { // Far-right bunk + -3749.54, -4540.25, 14.28, 3.34 + }, + { // Right bunk near entrance + -3742.10, -4536.85, 14.28, 3.64 + }, + { // Far-left bunk + -3755.89, -4529.07, 14.05, 0.57 + }, + { // Mid-left bunk + -3749.51, -4527.08, 14.07, 5.26 + }, + { // Left bunk near entrance + -3746.37, -4525.35, 14.16, 5.22 + }, +}; + +#define ALLIANCE_COORDS 7 + +//alliance run to where +#define A_RUNTOX -3742.96 +#define A_RUNTOY -4531.52 +#define A_RUNTOZ 11.91 + +#define DOCTOR_HORDE 12920 + +static Location HordeCoords[]= +{ + { // Left, Behind + -1013.75, -3492.59, 62.62, 4.34 + }, + { // Right, Behind + -1017.72, -3490.92, 62.62, 4.34 + }, + { // Left, Mid + -1015.77, -3497.15, 62.82, 4.34 + }, + { // Right, Mid + -1019.51, -3495.49, 62.82, 4.34 + }, + { // Left, front + -1017.25, -3500.85, 62.98, 4.34 + }, + { // Right, Front + -1020.95, -3499.21, 62.98, 4.34 + } +}; + +#define HORDE_COORDS 6 + +//horde run to where +#define H_RUNTOX -1016.44 +#define H_RUNTOY -3508.48 +#define H_RUNTOZ 62.96 + +const uint32 AllianceSoldierId[3] = +{ + 12938, // 12938 Injured Alliance Soldier + 12936, // 12936 Badly injured Alliance Soldier + 12937 // 12937 Critically injured Alliance Soldier +}; + +const uint32 HordeSoldierId[3] = +{ + 12923, //12923 Injured Soldier + 12924, //12924 Badly injured Soldier + 12925 //12925 Critically injured Soldier +}; + +/*###### +## npc_doctor (handles both Gustaf Vanhowzen and Gregory Victor) +######*/ + +struct TRINITY_DLL_DECL npc_doctorAI : public ScriptedAI +{ + uint64 Playerguid; + + uint32 SummonPatient_Timer; + uint32 SummonPatientCount; + uint32 PatientDiedCount; + uint32 PatientSavedCount; + + bool Event; + + std::list Patients; + std::vector Coordinates; + + npc_doctorAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset(){} + + void BeginEvent(Player* player); + void PatientDied(Location* Point); + void PatientSaved(Creature* soldier, Player* player, Location* Point); + void UpdateAI(const uint32 diff); + + void Aggro(Unit* who){} +}; + +/*##### +## npc_injured_patient (handles all the patients, no matter Horde or Alliance) +#####*/ + +struct TRINITY_DLL_DECL npc_injured_patientAI : public ScriptedAI +{ + npc_injured_patientAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint64 Doctorguid; + + Location* Coord; + + void Reset() + { + Doctorguid = 0; + + Coord = NULL; + //no select + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + //no regen health + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + //to make them lay with face down + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_DEAD); + + uint32 mobId = m_creature->GetEntry(); + + switch (mobId) + { //lower max health + case 12923: + case 12938: //Injured Soldier + m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.75)); + break; + case 12924: + case 12936: //Badly injured Soldier + m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.50)); + break; + case 12925: + case 12937: //Critically injured Soldier + m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.25)); + break; + } + } + + void Aggro(Unit* who){} + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if (caster->GetTypeId() == TYPEID_PLAYER && m_creature->isAlive() && spell->Id == 20804) + { + if( (((Player*)caster)->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (((Player*)caster)->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE)) + { + if(Doctorguid) + { + Creature* Doctor = ((Creature*)Unit::GetUnit((*m_creature), Doctorguid)); + if(Doctor) + ((npc_doctorAI*)Doctor->AI())->PatientSaved(m_creature, ((Player*)caster), Coord); + } + } + //make not selectable + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + //regen health + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + //stand up + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_NONE); + DoSay(SAY_DOC1,LANG_UNIVERSAL,NULL); + + uint32 mobId = m_creature->GetEntry(); + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + switch (mobId) + { + case 12923: + case 12924: + case 12925: + m_creature->GetMotionMaster()->MovePoint(0, H_RUNTOX, H_RUNTOY, H_RUNTOZ); + break; + case 12936: + case 12937: + case 12938: + m_creature->GetMotionMaster()->MovePoint(0, A_RUNTOX, A_RUNTOY, A_RUNTOZ); + break; + } + } + return; + } + + void UpdateAI(const uint32 diff) + { + if (m_creature->isAlive() && m_creature->GetHealth() > 6) + { //lower HP on every world tick makes it a useful counter, not officlone though + m_creature->SetHealth(uint32(m_creature->GetHealth()-5) ); + } + + if (m_creature->isAlive() && m_creature->GetHealth() <= 6) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->setDeathState(JUST_DIED); + m_creature->SetFlag(UNIT_DYNAMIC_FLAGS, 32); + + if(Doctorguid) + { + Creature* Doctor = ((Creature*)Unit::GetUnit((*m_creature), Doctorguid)); + if(Doctor) + ((npc_doctorAI*)Doctor->AI())->PatientDied(Coord); + } + } + } +}; + +CreatureAI* GetAI_npc_injured_patient(Creature *_Creature) +{ + return new npc_injured_patientAI (_Creature); +} + +/* +npc_doctor (continue) +*/ + +void npc_doctorAI::BeginEvent(Player* player) +{ + Playerguid = player->GetGUID(); + + SummonPatient_Timer = 10000; + SummonPatientCount = 0; + PatientDiedCount = 0; + PatientSavedCount = 0; + + switch(m_creature->GetEntry()) + { + case DOCTOR_ALLIANCE: + for(uint8 i = 0; i < ALLIANCE_COORDS; ++i) + Coordinates.push_back(&AllianceCoords[i]); + break; + + case DOCTOR_HORDE: + for(uint8 i = 0; i < HORDE_COORDS; ++i) + Coordinates.push_back(&HordeCoords[i]); + break; + } + + Event = true; + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +} + +void npc_doctorAI::PatientDied(Location* Point) +{ + Player* player = ((Player*)Unit::GetUnit((*m_creature), Playerguid)); + if(player && ((player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE))) + { + PatientDiedCount++; + if (PatientDiedCount > 5 && Event) + { + if(player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) + player->FailQuest(6624); + else if(player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE) + player->FailQuest(6622); + + Event = false; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + Coordinates.push_back(Point); + } +} + +void npc_doctorAI::PatientSaved(Creature* soldier, Player* player, Location* Point) +{ + if(player && Playerguid == player->GetGUID()) + { + if((player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE)) + { + PatientSavedCount++; + if(PatientSavedCount == 15) + { + if(!Patients.empty()) + { + std::list::iterator itr; + for(itr = Patients.begin(); itr != Patients.end(); ++itr) + { + Creature* Patient = ((Creature*)Unit::GetUnit((*m_creature), *itr)); + if( Patient ) + Patient->setDeathState(JUST_DIED); + } + } + + if(player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(6624); + else if(player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(6622); + + Event = false; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + Coordinates.push_back(Point); + } + } +} + +void npc_doctorAI::UpdateAI(const uint32 diff) +{ + if(Event && SummonPatientCount >= 20) + { + Event = false; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + if(Event) + if(SummonPatient_Timer < diff) + { + Creature* Patient = NULL; + Location* Point = NULL; + + if(Coordinates.empty()) + return; + + std::vector::iterator itr = Coordinates.begin()+rand()%Coordinates.size(); + uint32 patientEntry = 0; + + switch(m_creature->GetEntry()) + { + case DOCTOR_ALLIANCE: patientEntry = AllianceSoldierId[rand()%3]; break; + case DOCTOR_HORDE: patientEntry = HordeSoldierId[rand()%3]; break; + default: + error_log("SD2: Invalid entry for Triage doctor. Please check your database"); + return; + } + + Point = *itr; + + Patient = m_creature->SummonCreature(patientEntry, Point->x, Point->y, Point->z, Point->o, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + + if(Patient) + { + Patients.push_back(Patient->GetGUID()); + ((npc_injured_patientAI*)Patient->AI())->Doctorguid = m_creature->GetGUID(); + if(Point) + ((npc_injured_patientAI*)Patient->AI())->Coord = Point; + Coordinates.erase(itr); + } + SummonPatient_Timer = 10000; + SummonPatientCount++; + }else SummonPatient_Timer -= diff; +} + +bool QuestAccept_npc_doctor(Player *player, Creature *creature, Quest const *quest ) +{ + if((quest->GetQuestId() == 6624) || (quest->GetQuestId() == 6622)) + ((npc_doctorAI*)creature->AI())->BeginEvent(player); + + return true; +} + +CreatureAI* GetAI_npc_doctor(Creature *_Creature) +{ + return new npc_doctorAI (_Creature); +} + +/*###### +## npc_guardian +######*/ + +#define SPELL_DEATHTOUCH 5 +#define SAY_AGGRO "This area is closed!" + +struct TRINITY_DLL_DECL npc_guardianAI : public ScriptedAI +{ + npc_guardianAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if (m_creature->isAttackReady()) + { + m_creature->CastSpell(m_creature->getVictim(),SPELL_DEATHTOUCH, true); + m_creature->resetAttackTimer(); + } + } +}; + +CreatureAI* GetAI_npc_guardian(Creature *_Creature) +{ + return new npc_guardianAI (_Creature); +} + +/*###### +## npc_mount_vendor +######*/ + +bool GossipHello_npc_mount_vendor(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + bool canBuy; + canBuy = false; + uint32 vendor = _Creature->GetEntry(); + uint8 race = player->getRace(); + + switch (vendor) + { + case 384: //Katie Hunter + case 1460: //Unger Statforth + case 2357: //Merideth Carlson + case 4885: //Gregor MacVince + if (player->GetReputationRank(72) != REP_EXALTED && race != RACE_HUMAN) + player->SEND_GOSSIP_MENU(5855, _Creature->GetGUID()); + else canBuy = true; + break; + case 1261: //Veron Amberstill + if (player->GetReputationRank(47) != REP_EXALTED && race != RACE_DWARF) + player->SEND_GOSSIP_MENU(5856, _Creature->GetGUID()); + else canBuy = true; + break; + case 3362: //Ogunaro Wolfrunner + if (player->GetReputationRank(76) != REP_EXALTED && race != RACE_ORC) + player->SEND_GOSSIP_MENU(5841, _Creature->GetGUID()); + else canBuy = true; + break; + case 3685: //Harb Clawhoof + if (player->GetReputationRank(81) != REP_EXALTED && race != RACE_TAUREN) + player->SEND_GOSSIP_MENU(5843, _Creature->GetGUID()); + else canBuy = true; + break; + case 4730: //Lelanai + if (player->GetReputationRank(69) != REP_EXALTED && race != RACE_NIGHTELF) + player->SEND_GOSSIP_MENU(5844, _Creature->GetGUID()); + else canBuy = true; + break; + case 4731: //Zachariah Post + if (player->GetReputationRank(68) != REP_EXALTED && race != RACE_UNDEAD_PLAYER) + player->SEND_GOSSIP_MENU(5840, _Creature->GetGUID()); + else canBuy = true; + break; + case 7952: //Zjolnir + if (player->GetReputationRank(530) != REP_EXALTED && race != RACE_TROLL) + player->SEND_GOSSIP_MENU(5842, _Creature->GetGUID()); + else canBuy = true; + break; + case 7955: //Milli Featherwhistle + if (player->GetReputationRank(54) != REP_EXALTED && race != RACE_GNOME) + player->SEND_GOSSIP_MENU(5857, _Creature->GetGUID()); + else canBuy = true; + break; + case 16264: //Winaestra + if (player->GetReputationRank(911) != REP_EXALTED && race != RACE_BLOODELF) + player->SEND_GOSSIP_MENU(10305, _Creature->GetGUID()); + else canBuy = true; + break; + case 17584: //Torallius the Pack Handler + if (player->GetReputationRank(930) != REP_EXALTED && race != RACE_DRAENEI) + player->SEND_GOSSIP_MENU(10239, _Creature->GetGUID()); + else canBuy = true; + break; + } + + if (canBuy) + { + if (_Creature->isVendor()) + player->ADD_GOSSIP_ITEM( 1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + } + return true; +} + +bool GossipSelect_npc_mount_vendor(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if (action == GOSSIP_ACTION_TRADE) + player->SEND_VENDORLIST( _Creature->GetGUID() ); + + return true; +} + +/*###### +## npc_rogue_trainer +######*/ + +bool GossipHello_npc_rogue_trainer(Player *player, Creature *_Creature) +{ + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( _Creature->isTrainer() ) + player->ADD_GOSSIP_ITEM(2, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); + + if( _Creature->isCanTrainingAndResetTalentsOf(player) ) + player->ADD_GOSSIP_ITEM(2, "I wish to unlearn my talents", GOSSIP_SENDER_MAIN, GOSSIP_OPTION_UNLEARNTALENTS); + + if( player->getClass() == CLASS_ROGUE && player->getLevel() >= 24 && !player->HasItemCount(17126,1) && !player->GetQuestRewardStatus(6681) ) + { + player->ADD_GOSSIP_ITEM(0, "", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(5996, _Creature->GetGUID()); + } else + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_rogue_trainer(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch( action ) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,21100,false); + break; + case GOSSIP_ACTION_TRAIN: + player->SEND_TRAINERLIST( _Creature->GetGUID() ); + break; + case GOSSIP_OPTION_UNLEARNTALENTS: + player->CLOSE_GOSSIP_MENU(); + player->SendTalentWipeConfirm( _Creature->GetGUID() ); + break; + } + return true; +} + +/*###### +## npc_sayge +######*/ + +#define SPELL_DMG 23768 //dmg +#define SPELL_RES 23769 //res +#define SPELL_ARM 23767 //arm +#define SPELL_SPI 23738 //spi +#define SPELL_INT 23766 //int +#define SPELL_STM 23737 //stm +#define SPELL_STR 23735 //str +#define SPELL_AGI 23736 //agi +#define SPELL_FORTUNE 23765 //faire fortune + +bool GossipHello_npc_sayge(Player *player, Creature *_Creature) +{ + if(_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( player->HasSpellCooldown(SPELL_INT) || + player->HasSpellCooldown(SPELL_ARM) || + player->HasSpellCooldown(SPELL_DMG) || + player->HasSpellCooldown(SPELL_RES) || + player->HasSpellCooldown(SPELL_STR) || + player->HasSpellCooldown(SPELL_AGI) || + player->HasSpellCooldown(SPELL_STM) || + player->HasSpellCooldown(SPELL_SPI) ) + player->SEND_GOSSIP_MENU(7393, _Creature->GetGUID()); + else + { + player->ADD_GOSSIP_ITEM(0, "Yes", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(7339, _Creature->GetGUID()); + } + + return true; +} + +void SendAction_npc_sayge(Player *player, Creature *_Creature, uint32 action) +{ + switch(action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM(0, "Slay the Man", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->ADD_GOSSIP_ITEM(0, "Turn him over to liege", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->ADD_GOSSIP_ITEM(0, "Confiscate the corn", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + player->ADD_GOSSIP_ITEM(0, "Let him go and have the corn", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(7340, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM(0, "Execute your friend painfully", GOSSIP_SENDER_MAIN+1, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Execute your friend painlessly", GOSSIP_SENDER_MAIN+2, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Let your friend go", GOSSIP_SENDER_MAIN+3, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(7341, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM(0, "Confront the diplomat", GOSSIP_SENDER_MAIN+4, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Show not so quiet defiance", GOSSIP_SENDER_MAIN+5, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Remain quiet", GOSSIP_SENDER_MAIN+2, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(7361, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM(0, "Speak against your brother openly", GOSSIP_SENDER_MAIN+6, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Help your brother in", GOSSIP_SENDER_MAIN+7, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Keep your brother out without letting him know", GOSSIP_SENDER_MAIN+8, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(7362, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->ADD_GOSSIP_ITEM(0, "Take credit, keep gold", GOSSIP_SENDER_MAIN+5, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Take credit, share the gold", GOSSIP_SENDER_MAIN+4, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Let the knight take credit", GOSSIP_SENDER_MAIN+3, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(7363, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM(0, "Thanks", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); + player->SEND_GOSSIP_MENU(7364, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+6: + _Creature->CastSpell(player, SPELL_FORTUNE, false); + player->SEND_GOSSIP_MENU(7365, _Creature->GetGUID()); + break; + } +} + +bool GossipSelect_npc_sayge(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch(sender) + { + case GOSSIP_SENDER_MAIN: + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+1: + _Creature->CastSpell(player, SPELL_DMG, false); + player->AddSpellCooldown(SPELL_DMG,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+2: + _Creature->CastSpell(player, SPELL_RES, false); + player->AddSpellCooldown(SPELL_RES,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+3: + _Creature->CastSpell(player, SPELL_ARM, false); + player->AddSpellCooldown(SPELL_ARM,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+4: + _Creature->CastSpell(player, SPELL_SPI, false); + player->AddSpellCooldown(SPELL_SPI,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+5: + _Creature->CastSpell(player, SPELL_INT, false); + player->AddSpellCooldown(SPELL_INT,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+6: + _Creature->CastSpell(player, SPELL_STM, false); + player->AddSpellCooldown(SPELL_STM,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+7: + _Creature->CastSpell(player, SPELL_STR, false); + player->AddSpellCooldown(SPELL_STR,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+8: + _Creature->CastSpell(player, SPELL_AGI, false); + player->AddSpellCooldown(SPELL_AGI,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + } + return true; +} + +struct TRINITY_DLL_DECL npc_steam_tonkAI : public ScriptedAI +{ + npc_steam_tonkAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() {} + void Aggro(Unit *who) {} + + void OnPossess(bool apply) + { + if (apply) + { + // Initialize the action bar without the melee attack command + m_creature->InitCharmInfo(m_creature); + m_creature->GetCharmInfo()->InitEmptyActionBar(false); + + m_creature->SetAggressive(false); + } + else + m_creature->SetAggressive(true); + } + +}; + +CreatureAI* GetAI_npc_steam_tonk(Creature *_Creature) +{ + return new npc_steam_tonkAI(_Creature); +} + +#define SPELL_TONK_MINE_DETONATE 25099 + +struct TRINITY_DLL_DECL npc_tonk_mineAI : public ScriptedAI +{ + npc_tonk_mineAI(Creature *c) : ScriptedAI(c) + { + m_creature->SetAggressive(false); + Reset(); + } + + uint32 ExplosionTimer; + + void Reset() + { + ExplosionTimer = 3000; + } + + void Aggro(Unit *who) {} + void AttackStart(Unit *who) {} + void MoveInLineOfSight(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if (ExplosionTimer < diff) + { + m_creature->CastSpell(m_creature, SPELL_TONK_MINE_DETONATE, true); + m_creature->setDeathState(DEAD); // unsummon it + } else + ExplosionTimer -= diff; + } +}; + +CreatureAI* GetAI_npc_tonk_mine(Creature *_Creature) +{ + return new npc_tonk_mineAI(_Creature); +} + +void AddSC_npcs_special() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_chicken_cluck"; + newscript->GetAI = GetAI_npc_chicken_cluck; + newscript->pReceiveEmote = &ReceiveEmote_npc_chicken_cluck; + newscript->pQuestAccept = &QuestAccept_npc_chicken_cluck; + newscript->pQuestComplete = &QuestComplete_npc_chicken_cluck; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_dancing_flames"; + newscript->pReceiveEmote = &ReceiveEmote_npc_dancing_flames; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_injured_patient"; + newscript->GetAI = GetAI_npc_injured_patient; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_doctor"; + newscript->GetAI = GetAI_npc_doctor; + newscript->pQuestAccept = &QuestAccept_npc_doctor; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_guardian"; + newscript->GetAI = GetAI_npc_guardian; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_mount_vendor"; + newscript->pGossipHello = &GossipHello_npc_mount_vendor; + newscript->pGossipSelect = &GossipSelect_npc_mount_vendor; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_rogue_trainer"; + newscript->pGossipHello = &GossipHello_npc_rogue_trainer; + newscript->pGossipSelect = &GossipSelect_npc_rogue_trainer; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_sayge"; + newscript->pGossipHello = &GossipHello_npc_sayge; + newscript->pGossipSelect = &GossipSelect_npc_sayge; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_steam_tonk"; + newscript->GetAI = &GetAI_npc_steam_tonk; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_tonk_mine"; + newscript->GetAI = &GetAI_npc_tonk_mine; + newscript->RegisterSelf(); +} -- cgit v1.2.3