diff --git a/src/server/scripts/EasternKingdoms/ZulAman/instance_zulaman.cpp b/src/server/scripts/EasternKingdoms/ZulAman/instance_zulaman.cpp index 250f7b576..3ed706720 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/instance_zulaman.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/instance_zulaman.cpp @@ -15,13 +15,6 @@ * with this program. If not, see . */ -/* ScriptData -SDName: instance_zulaman -SD%Complete: 80 -SDComment: -SDCategory: Zul'Aman -EndScriptData */ - #include "InstanceMapScript.h" #include "InstanceScript.h" #include "Player.h" @@ -41,34 +34,40 @@ enum Misc struct SHostageInfo { uint32 npc, go; // FIXME go Not used - float x, y, z, o; + Position pos; }; static SHostageInfo HostageInfo[] = { - {23790, 186648, -57, 1343, 40.77f, 3.2f}, // bear - {23999, 187021, 400, 1414, 74.36f, 3.3f}, // eagle - {24001, 186672, -35, 1134, 18.71f, 1.9f}, // dragonhawk - {24024, 186667, 413, 1117, 6.32f, 3.1f} // lynx + {23790, 186648, { -57.0f, 1343.0f, 40.77f, 3.2f } }, // bear + {23999, 187021, { 400.0f, 1414.0f, 74.36f, 3.3f } }, // eagle + {24001, 186672, { -35.0f, 1134.0f, 18.71f, 1.9f } }, // dragonhawk + {24024, 186667, { 413.0f, 1117.0f, 6.32f, 3.1f } } // lynx }; Position const HarrisonJonesLoc = {120.687f, 1674.0f, 42.0217f, 1.59044f}; DoorData const doorData[] = { - { GO_ZULJIN_FIREWALL, DATA_ZULJIN, DOOR_TYPE_ROOM }, - { 0, 0, DOOR_TYPE_ROOM } // END + { GO_ZULJIN_FIREWALL, DATA_ZULJIN, DOOR_TYPE_ROOM }, + { GO_DOOR_HALAZZI, DATA_HALAZZI, DOOR_TYPE_ROOM }, + { GO_DOOR_AKILZON, DATA_AKILZON, DOOR_TYPE_ROOM }, + { GO_GATE_ZULJIN, DATA_HEXLORD, DOOR_TYPE_PASSAGE }, + { 0, 0, DOOR_TYPE_ROOM } // END }; ObjectData const creatureData[] = { - { NPC_SPIRIT_LYNX, DATA_SPIRIT_LYNX }, - { 0, 0 } + { NPC_SPIRIT_LYNX, DATA_SPIRIT_LYNX }, + { 0, 0 } }; ObjectData const gameObjectData[] = { - { 0, 0 } + { GO_STRANGE_GONG, DATA_STRANGE_GONG }, + { GO_MASSIVE_GATE, DATA_MASSIVE_GATE }, + { GO_GATE_HEXLORD, DATA_HEXLORD_GATE }, + { 0, 0 } }; BossBoundaryData const boundaries = @@ -79,304 +78,163 @@ BossBoundaryData const boundaries = class instance_zulaman : public InstanceMapScript { public: - instance_zulaman() - : InstanceMapScript("instance_zulaman", 568) - { - } + instance_zulaman() : InstanceMapScript("instance_zulaman", 568) { } struct instance_zulaman_InstanceMapScript : public InstanceScript { instance_zulaman_InstanceMapScript(Map* map) : InstanceScript(map) {} - ObjectGuid HarkorsSatchelGUID; - ObjectGuid TanzarsTrunkGUID; - ObjectGuid AshlisBagGUID; - ObjectGuid KrazsPackageGUID; - ObjectGuid StrangeGongGUID; - - ObjectGuid HexLordGateGUID; - ObjectGuid ZulJinGateGUID; - ObjectGuid MassiveGateGUID; - ObjectGuid AkilzonDoorGUID; - ObjectGuid HalazziDoorGUID; - - uint32 QuestTimer; - uint16 BossKilled; - uint16 QuestMinute; - uint16 ChestLooted; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - uint32 RandVendor[RAND_VENDOR]; - void Initialize() override { SetHeaders(DataHeader); - LoadObjectData(creatureData, gameObjectData); - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); SetBossNumber(MAX_ENCOUNTER); + SetPersistentDataCount(PersistentDataCount); + LoadObjectData(creatureData, gameObjectData); LoadBossBoundaries(boundaries); LoadDoorData(doorData); - QuestTimer = 0; - QuestMinute = 0; - BossKilled = 0; - ChestLooted = 0; - for (uint8 i = 0; i < RAND_VENDOR; ++i) RandVendor[i] = NOT_STARTED; + } - m_auiEncounter[DATA_GONGEVENT] = NOT_STARTED; + void OnPlayerEnter(Player* /*player*/) override + { + if (!scheduler.IsGroupScheduled(GROUP_TIMED_RUN)) + DoAction(ACTION_START_TIMED_RUN); } void OnGameObjectCreate(GameObject* go) override { - switch (go->GetEntry()) - { - case GO_DOOR_HALAZZI: - HalazziDoorGUID = go->GetGUID(); - break; - case GO_GATE_ZULJIN: - ZulJinGateGUID = go->GetGUID(); - break; - case GO_GATE_HEXLORD: - HexLordGateGUID = go->GetGUID(); - break; - case GO_MASSIVE_GATE: - MassiveGateGUID = go->GetGUID(); - break; - case GO_DOOR_AKILZON: - AkilzonDoorGUID = go->GetGUID(); - break; - - case GO_HARKORS_SATCHEL: - HarkorsSatchelGUID = go->GetGUID(); - break; - case GO_TANZARS_TRUNK: - TanzarsTrunkGUID = go->GetGUID(); - break; - case GO_ASHLIS_BAG: - AshlisBagGUID = go->GetGUID(); - break; - case GO_KRAZS_PACKAGE: - KrazsPackageGUID = go->GetGUID(); - break; - case GO_STRANGE_GONG: - StrangeGongGUID = go->GetGUID(); - break; - default: - break; - } - CheckInstanceStatus(); + if (go->GetEntry() == GO_GATE_HEXLORD) + CheckInstanceStatus(); InstanceScript::OnGameObjectCreate(go); } void SummonHostage(uint8 num) { - if (!QuestMinute) + if (!GetPersistentData(DATA_TIMED_RUN)) return; - Map::PlayerList const& PlayerList = instance->GetPlayers(); - if (PlayerList.IsEmpty()) - return; + instance->SummonCreature(HostageInfo[num].npc, HostageInfo[num].pos); + } - Map::PlayerList::const_iterator i = PlayerList.begin(); - if (Player* i_pl = i->GetSource()) + void DoAction(int32 actionId) override + { + if (actionId == ACTION_START_TIMED_RUN) { - if (Unit* Hostage = i_pl->SummonCreature(HostageInfo[num].npc, HostageInfo[num].x, HostageInfo[num].y, HostageInfo[num].z, HostageInfo[num].o, TEMPSUMMON_DEAD_DESPAWN, 0)) + if (uint32 timer = GetPersistentData(DATA_TIMED_RUN)) { - Hostage->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - Hostage->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 1); + DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, timer); } + + scheduler.Schedule(1min, GROUP_TIMED_RUN, [this](TaskContext context) + { + if (uint32 timer = GetPersistentData(DATA_TIMED_RUN)) + { + --timer; + DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 1); + DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, timer); + StorePersistentData(DATA_TIMED_RUN, timer); + context.Repeat(); + } + else + DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 0); + }); } } void CheckInstanceStatus() { - if (BossKilled >= DATA_HALAZZI) - HandleGameObject(HexLordGateGUID, true); - - if (BossKilled >= DATA_HEXLORD) - HandleGameObject(ZulJinGateGUID, true); - } - - std::string GetSaveData() override - { - OUT_SAVE_INST_DATA; - - std::ostringstream ss; - ss << "S " << BossKilled << ' ' << ChestLooted << ' ' << QuestMinute; - - OUT_SAVE_INST_DATA_COMPLETE; - return ss.str(); - } - - void Load(const char* load) override - { - if (!load) - return; - - std::istringstream ss(load); - char dataHead; // S - uint16 data1, data2, data3; - ss >> dataHead >> data1 >> data2 >> data3; - - if (dataHead == 'S') - { - BossKilled = data1; - ChestLooted = data2; - QuestMinute = data3; - } - else - { - LOG_ERROR("misc", "Zul'aman: corrupted save data."); - } + if (AllBossesDone({ DATA_NALORAKK, DATA_AKILZON, DATA_JANALAI, DATA_HALAZZI })) + HandleGameObject(ObjectGuid::Empty, true, GetGameObject(DATA_HEXLORD_GATE)); } void SetData(uint32 type, uint32 data) override { + if (type == TYPE_RAND_VENDOR_1) + RandVendor[0] = data; + else if (type == TYPE_RAND_VENDOR_2) + RandVendor[1] = data; + } + + bool SetBossState(uint32 type, EncounterState state) override + { + if (!InstanceScript::SetBossState(type, state)) + return false; + switch (type) { - case DATA_GONGEVENT: - m_auiEncounter[DATA_GONGEVENT] = data; - if (data == IN_PROGRESS) - SaveToDB(); - else if (data == DONE) - QuestMinute = 21; - break; case DATA_NALORAKK: - m_auiEncounter[DATA_NALORAKK] = data; - if (data == DONE) + if (state == DONE) { - if (QuestMinute) + if (uint32 timer = GetPersistentData(DATA_TIMED_RUN)) { - QuestMinute += 15; - DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, QuestMinute); + StorePersistentData(DATA_TIMED_RUN, timer += 15); + DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, timer); } SummonHostage(0); - SaveToDB(); } break; case DATA_AKILZON: - m_auiEncounter[DATA_AKILZON] = data; - HandleGameObject(AkilzonDoorGUID, data != IN_PROGRESS); - if (data == DONE) + if (state == DONE) { - if (QuestMinute) + if (uint32 timer = GetPersistentData(DATA_TIMED_RUN)) { - QuestMinute += 10; - DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, QuestMinute); + StorePersistentData(DATA_TIMED_RUN, timer += 10); + DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, timer); } SummonHostage(1); - SaveToDB(); } break; case DATA_JANALAI: - m_auiEncounter[DATA_JANALAI] = data; - if (data == DONE) + if (state == DONE) SummonHostage(2); - SaveToDB(); break; case DATA_HALAZZI: - m_auiEncounter[DATA_HALAZZI] = data; - HandleGameObject(HalazziDoorGUID, data != IN_PROGRESS); - if (data == DONE) SummonHostage(3); - SaveToDB(); + if (state == DONE) + SummonHostage(3); break; case DATA_HEXLORD: - m_auiEncounter[DATA_HEXLORD] = data; - if (data == IN_PROGRESS) - HandleGameObject(HexLordGateGUID, false); - else if (data == NOT_STARTED) + if (state == IN_PROGRESS) + HandleGameObject(ObjectGuid::Empty, false, GetGameObject(DATA_HEXLORD_GATE)); + else if (state == NOT_STARTED) CheckInstanceStatus(); - SaveToDB(); - break; - case DATA_CHESTLOOTED: - ++ChestLooted; - SaveToDB(); - break; - case TYPE_RAND_VENDOR_1: - RandVendor[0] = data; - break; - case TYPE_RAND_VENDOR_2: - RandVendor[1] = data; break; } - if (data == DONE) + if (state == DONE) { - ++BossKilled; - if (QuestMinute && BossKilled >= DATA_HALAZZI) + if (GetPersistentData(DATA_TIMED_RUN) && AllBossesDone({ DATA_NALORAKK, DATA_AKILZON, DATA_JANALAI, DATA_HALAZZI })) { - QuestMinute = 0; + StorePersistentData(DATA_TIMED_RUN, 0); DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 0); } + CheckInstanceStatus(); - SaveToDB(); } + + return true; } uint32 GetData(uint32 type) const override { - switch (type) - { - case DATA_GONGEVENT: - return m_auiEncounter[DATA_GONGEVENT]; - case DATA_NALORAKK: - return m_auiEncounter[DATA_NALORAKK]; - case DATA_AKILZON: - return m_auiEncounter[DATA_AKILZON]; - case DATA_JANALAI: - return m_auiEncounter[DATA_JANALAI]; - case DATA_HALAZZI: - return m_auiEncounter[DATA_HALAZZI]; - case DATA_HEXLORD: - return m_auiEncounter[DATA_HEXLORD]; - case DATA_ZULJIN: - return m_auiEncounter[DATA_ZULJIN]; - case DATA_CHESTLOOTED: - return ChestLooted; - case TYPE_RAND_VENDOR_1: - return RandVendor[0]; - case TYPE_RAND_VENDOR_2: - return RandVendor[1]; - default: - return 0; - } + if (type == TYPE_RAND_VENDOR_1) + return RandVendor[0]; + else if (type == TYPE_RAND_VENDOR_2) + return RandVendor[1]; + + return 0; } void Update(uint32 diff) override { - if (QuestMinute) - { - if (QuestTimer <= diff) - { - QuestMinute--; - SaveToDB(); - QuestTimer += 60000; - if (QuestMinute) - { - DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 1); - DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, QuestMinute); - } - else DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 0); - } - QuestTimer -= diff; - } + scheduler.Update(diff); } - ObjectGuid GetGuidData(uint32 type) const override - { - switch (type) - { - case GO_STRANGE_GONG: - return StrangeGongGUID; - case GO_MASSIVE_GATE: - return MassiveGateGUID; - } - - return ObjectGuid::Empty; - } + private: + uint32 RandVendor[RAND_VENDOR]; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp index 1f9e44d78..8896931d2 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp @@ -63,384 +63,177 @@ enum ForestFrog NPC_BRENNAN = 24453, NPC_HOLLEE = 24455, - // Says - SAY_MANNUTH_0 = 0, - SAY_MANNUTH_1 = 1, - SAY_MANNUTH_2 = 2, - SAY_MANNUTH_3 = 3, + // Adarrah is spawned elsewhere. + // So her text 0 isn't used in this instance. + SAY_THANKS_FREED = 0, + SAY_CHEST_SPAWN = 1, + SAY_CHEST_TALK = 2, + SAY_GOODBYE = 3, - SAY_DEEZ_0 = 0, - SAY_DEEZ_1 = 1, - SAY_DEEZ_2 = 2, - SAY_DEEZ_3 = 3, - - SAY_GALATHRYN_0 = 0, - SAY_GALATHRYN_1 = 1, - SAY_GALATHRYN_2 = 2, - SAY_GALATHRYN_3 = 3, - - SAY_ADARRAH_1 = 1, - SAY_ADARRAH_2 = 2, - SAY_ADARRAH_3 = 3, - SAY_ADARRAH_4 = 4, - - SAY_DARWEN_0 = 0, - SAY_DARWEN_1 = 1, - SAY_DARWEN_2 = 2, - SAY_DARWEN_3 = 3, - - SAY_FUDGERICK_0 = 0, - SAY_FUDGERICK_1 = 1, - SAY_FUDGERICK_2 = 2, - SAY_FUDGERICK_3 = 3, - - SAY_GUNTER_0 = 0, - SAY_GUNTER_1 = 1, - SAY_GUNTER_2 = 2, - - SAY_KYREN_0 = 0, - SAY_KYREN_1 = 1, - SAY_KYREN_2 = 2, - - SAY_MITZI_0 = 0, - SAY_MITZI_1 = 1, - SAY_MITZI_2 = 2, - SAY_MITZI_3 = 3, - - SAY_CHRISTIAN_0 = 0, - SAY_CHRISTIAN_1 = 1, - SAY_CHRISTIAN_2 = 2, - SAY_CHRISTIAN_3 = 3, - - SAY_BRENNAN_0 = 0, - SAY_BRENNAN_1 = 1, - SAY_BRENNAN_2 = 2, - SAY_BRENNAN_3 = 3, - - SAY_HOLLEE_0 = 0, - SAY_HOLLEE_1 = 1, - SAY_HOLLEE_2 = 2, - SAY_HOLLEE_3 = 3, - - POINT_DESPAWN = 1 + POINT_DESPAWN = 1, }; -class npc_forest_frog : public CreatureScript +struct npc_forest_frog : public ScriptedAI { -public: - npc_forest_frog() : CreatureScript("npc_forest_frog") { } - - struct npc_forest_frogAI : public ScriptedAI + npc_forest_frog(Creature* creature) : ScriptedAI(creature) { - npc_forest_frogAI(Creature* creature) : ScriptedAI(creature) + instance = creature->GetInstanceScript(); + } + + void JustEngagedWith(Unit* /*who*/) override { } + + void MovementInform(uint32 type, uint32 data) override + { + if (type == POINT_MOTION_TYPE && data == POINT_DESPAWN) + me->DespawnOrUnsummon(1000); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + if (eventTimer) { - instance = creature->GetInstanceScript(); + Player* player = ObjectAccessor::GetPlayer(me->GetMap(), PlayerGUID); + switch (events.ExecuteEvent()) + { + case 1: + + if (me->GetEntry() == NPC_ADARRAH) + Talk(SAY_THANKS_FREED + 1, player); + else + Talk(SAY_THANKS_FREED, player); + + eventTimer = 2; + events.ScheduleEvent(eventTimer, urand(4000, 5000)); + break; + case 2: + if (me->GetEntry() != NPC_GUNTER && me->GetEntry() != NPC_KYREN) // vendors don't kneel? + me->SetStandState(UNIT_STAND_STATE_KNEEL); + + switch (me->GetEntry()) + { + case NPC_MANNUTH: + case NPC_DEEZ: + case NPC_GALATHRYN: + DoCastSelf(SPELL_SUMMON_AMANI_CHARM_CHEST_2, true); + Talk(SAY_CHEST_SPAWN, player); + break; + case NPC_ADARRAH: + DoCastSelf(SPELL_SUMMON_AMANI_CHARM_CHEST_2, true); + Talk(SAY_CHEST_SPAWN + 1, player); + break; + case NPC_DARWEN: + case NPC_FUDGERICK: + DoCastSelf(SPELL_SUMMON_MONEY_BAG, true); + me->LoadEquipment(0, true); + Talk(SAY_CHEST_SPAWN, player); + break; + case NPC_KYREN: + case NPC_GUNTER: + Talk(SAY_CHEST_SPAWN, player); + break; + case NPC_MITZI: + case NPC_CHRISTIAN: + case NPC_BRENNAN: + case NPC_HOLLEE: + DoCastSelf(SPELL_SUMMON_AMANI_CHARM_CHEST_1, true); + Talk(SAY_CHEST_SPAWN, player); + break; + } + eventTimer = 3; + events.ScheduleEvent(eventTimer, urand(6000, 7000)); + break; + case 3: + me->SetStandState(EMOTE_ONESHOT_NONE); + + if (me->GetEntry() == NPC_ADARRAH) + Talk(SAY_CHEST_TALK + 1, player); + else + Talk(SAY_CHEST_TALK); + + eventTimer = 4; + if (me->GetEntry() == NPC_GUNTER || me->GetEntry() == NPC_KYREN) + events.ScheduleEvent(eventTimer, 5 * MINUTE * IN_MILLISECONDS); // vendors wait for 5 minutes before running away and despawning + else + events.ScheduleEvent(eventTimer, 6000); + break; + case 4: + me->HandleEmoteCommand(EMOTE_ONESHOT_WAVE); + + if (me->GetEntry() == NPC_ADARRAH) + Talk(SAY_GOODBYE + 1, player); + else + Talk(SAY_GOODBYE); + + eventTimer = 5; + events.ScheduleEvent(eventTimer, 2000); + break; + case 5: + + if (me->GetEntry() == NPC_ADARRAH) + DoCastSelf(SPELL_STEALTH_, true); + + if (me->GetPositionY() > 1290.0f) + me->GetMotionMaster()->MovePoint(POINT_DESPAWN, 118.2742f, 1400.657f, -9.118711f); + else + me->GetMotionMaster()->MovePoint(POINT_DESPAWN, 114.3155f, 1244.244f, -20.97606f); + eventTimer = 0; + break; + } + } + } + + void DoSpawnRandom() + { + auto const& entries = + { + NPC_MANNUTH, NPC_DEEZ, NPC_GALATHRYN, NPC_ADARRAH, NPC_FUDGERICK, NPC_DARWEN, NPC_MITZI, + NPC_CHRISTIAN, NPC_BRENNAN, NPC_HOLLEE + }; + + uint32 cEntry = Acore::Containers::SelectRandomContainerElement(entries); + + if (!instance->GetData(TYPE_RAND_VENDOR_1) && roll_chance_i(10)) + { + cEntry = NPC_GUNTER; + instance->SetData(TYPE_RAND_VENDOR_1, DONE); + } + else if (!instance->GetData(TYPE_RAND_VENDOR_2) && roll_chance_i(10)) + { + cEntry = NPC_KYREN; + instance->SetData(TYPE_RAND_VENDOR_2, DONE); } + // start generic rp + eventTimer = 1; + events.ScheduleEvent(eventTimer, 3000); + + me->UpdateEntry(cEntry); + } + + void SpellHit(Unit* caster, SpellInfo const* spell) override + { + if (spell->Id == SPELL_REMOVE_AMANI_CURSE && caster->IsPlayer() && me->GetEntry() == NPC_FOREST_FROG) + { + me->GetMotionMaster()->MoveIdle(); + me->SetFacingToObject(caster); + PlayerGUID = caster->GetGUID(); + + if (roll_chance_i(2)) + { + DoCast(caster, SPELL_PUSH_MOJO, true); + me->GetMotionMaster()->MovePoint(POINT_DESPAWN, caster->GetPosition()); + } + else + DoSpawnRandom(); + } + } + + private: InstanceScript* instance; EventMap events; uint8 eventTimer; ObjectGuid PlayerGUID; - - void Reset() override { } - - void JustEngagedWith(Unit* /*who*/) override { } - - void MovementInform(uint32 type, uint32 data) override - { - if (type == POINT_MOTION_TYPE && data == POINT_DESPAWN) - me->DespawnOrUnsummon(1000); - } - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - if (eventTimer) - { - Player* player = ObjectAccessor::GetPlayer(me->GetMap(), PlayerGUID); - switch (events.ExecuteEvent()) - { - case 1: - switch (me->GetEntry()) - { - case NPC_MANNUTH: - Talk(SAY_MANNUTH_0, player); - break; - case NPC_DEEZ: - Talk(SAY_DEEZ_0, player); - break; - case NPC_GALATHRYN: - Talk(SAY_GALATHRYN_0, player); - break; - case NPC_ADARRAH: - Talk(SAY_ADARRAH_1, player); - break; - case NPC_DARWEN: - Talk(SAY_DARWEN_0, player); - break; - case NPC_FUDGERICK: - Talk(SAY_FUDGERICK_0, player); - break; - case NPC_GUNTER: - Talk(SAY_GUNTER_0, player); - break; - case NPC_KYREN: - Talk(SAY_KYREN_0, player); - break; - case NPC_MITZI: - Talk(SAY_MITZI_0, player); - break; - case NPC_CHRISTIAN: - Talk(SAY_CHRISTIAN_0, player); - break; - case NPC_BRENNAN: - Talk(SAY_BRENNAN_0, player); - break; - case NPC_HOLLEE: - Talk(SAY_HOLLEE_0, player); - break; - } - eventTimer = 2; - events.ScheduleEvent(eventTimer, urand(4000, 5000)); - break; - case 2: - if (me->GetEntry() != NPC_GUNTER && me->GetEntry() != NPC_KYREN) // vendors don't kneel? - me->SetStandState(UNIT_STAND_STATE_KNEEL); - - switch (me->GetEntry()) - { - case NPC_MANNUTH: - DoCast(me, SPELL_SUMMON_AMANI_CHARM_CHEST_2, true); - Talk(SAY_MANNUTH_1, player); - break; - case NPC_DEEZ: - DoCast(me, SPELL_SUMMON_AMANI_CHARM_CHEST_2, true); - Talk(SAY_DEEZ_1, player); - break; - case NPC_GALATHRYN: - DoCast(me, SPELL_SUMMON_AMANI_CHARM_CHEST_2, true); - Talk(SAY_GALATHRYN_1, player); - break; - case NPC_ADARRAH: - DoCast(me, SPELL_SUMMON_AMANI_CHARM_CHEST_2, true); - Talk(SAY_ADARRAH_2, player); - break; - case NPC_DARWEN: - DoCast(me, SPELL_SUMMON_MONEY_BAG, true); - me->LoadEquipment(0, true); - Talk(SAY_DARWEN_1, player); - break; - case NPC_FUDGERICK: - DoCast(me, SPELL_SUMMON_MONEY_BAG, true); - me->LoadEquipment(0, true); - Talk(SAY_FUDGERICK_1, player); - break; - case NPC_GUNTER: - Talk(SAY_GUNTER_1, player); - break; - case NPC_KYREN: - Talk(SAY_KYREN_1, player); - break; - case NPC_MITZI: - DoCast(me, SPELL_SUMMON_AMANI_CHARM_CHEST_1, true); - Talk(SAY_MITZI_1, player); - break; - case NPC_CHRISTIAN: - DoCast(me, SPELL_SUMMON_AMANI_CHARM_CHEST_1, true); - Talk(SAY_CHRISTIAN_1, player); - break; - case NPC_BRENNAN: - DoCast(me, SPELL_SUMMON_AMANI_CHARM_CHEST_1, true); - Talk(SAY_BRENNAN_1, player); - break; - case NPC_HOLLEE: - DoCast(me, SPELL_SUMMON_AMANI_CHARM_CHEST_1, true); - Talk(SAY_HOLLEE_1, player); - break; - } - eventTimer = 3; - events.ScheduleEvent(eventTimer, urand(6000, 7000)); - break; - case 3: - me->SetStandState(EMOTE_ONESHOT_NONE); - switch (me->GetEntry()) - { - case NPC_MANNUTH: - Talk(SAY_MANNUTH_2, player); - break; - case NPC_DEEZ: - Talk(SAY_DEEZ_2, player); - break; - case NPC_GALATHRYN: - Talk(SAY_GALATHRYN_2, player); - break; - case NPC_ADARRAH: - Talk(SAY_ADARRAH_3, player); - break; - case NPC_DARWEN: - Talk(SAY_DARWEN_2, player); - break; - case NPC_FUDGERICK: - Talk(SAY_FUDGERICK_2, player); - break; - case NPC_GUNTER: - Talk(SAY_GUNTER_2, player); - break; - case NPC_KYREN: - Talk(SAY_KYREN_2, player); - break; - case NPC_MITZI: - Talk(SAY_MITZI_2, player); - break; - case NPC_CHRISTIAN: - Talk(SAY_CHRISTIAN_2, player); - break; - case NPC_BRENNAN: - Talk(SAY_BRENNAN_2, player); - break; - case NPC_HOLLEE: - Talk(SAY_HOLLEE_2, player); - break; - } - eventTimer = 4; - if (me->GetEntry() == NPC_GUNTER || me->GetEntry() == NPC_KYREN) - events.ScheduleEvent(eventTimer, 5 * MINUTE * IN_MILLISECONDS); // vendors wait for 5 minutes before running away and despawning - else - events.ScheduleEvent(eventTimer, 6000); - break; - case 4: - me->HandleEmoteCommand(EMOTE_ONESHOT_WAVE); - switch (me->GetEntry()) - { - case NPC_MANNUTH: - Talk(SAY_MANNUTH_3, player); - break; - case NPC_DEEZ: - Talk(SAY_DEEZ_3, player); - break; - case NPC_GALATHRYN: - Talk(SAY_GALATHRYN_3, player); - break; - case NPC_ADARRAH: - Talk(SAY_ADARRAH_4, player); - break; - case NPC_DARWEN: - Talk(SAY_DARWEN_3, player); - break; - case NPC_FUDGERICK: - Talk(SAY_FUDGERICK_3, player); - break; - case NPC_MITZI: - Talk(SAY_MITZI_3, player); - break; - case NPC_CHRISTIAN: - Talk(SAY_CHRISTIAN_3, player); - break; - case NPC_BRENNAN: - Talk(SAY_BRENNAN_3, player); - break; - case NPC_HOLLEE: - Talk(SAY_HOLLEE_3, player); - break; - } - eventTimer = 5; - events.ScheduleEvent(eventTimer, 2000); - break; - case 5: - switch (me->GetEntry()) - { - case NPC_ADARRAH: - DoCast(me, SPELL_STEALTH_, true); - break; - } - if (me->GetPositionY() > 1290.0f) - me->GetMotionMaster()->MovePoint(POINT_DESPAWN, 118.2742f, 1400.657f, -9.118711f); - else - me->GetMotionMaster()->MovePoint(POINT_DESPAWN, 114.3155f, 1244.244f, -20.97606f); - eventTimer = 0; - break; - } - } - } - - void DoSpawnRandom() - { - if (instance) - { - uint32 cEntry = NPC_MANNUTH; - switch (urand(0, 9)) - { - case 1: - cEntry = NPC_DEEZ; - break; - case 2: - cEntry = NPC_GALATHRYN; - break; - case 3: - cEntry = NPC_ADARRAH; - break; - case 4: - cEntry = NPC_FUDGERICK; - break; - case 5: - cEntry = NPC_DARWEN; - break; - case 6: - cEntry = NPC_MITZI; - break; - case 7: - cEntry = NPC_CHRISTIAN; - break; - case 8: - cEntry = NPC_BRENNAN; - break; - case 9: - cEntry = NPC_HOLLEE; - break; - } - - if (!instance->GetData(TYPE_RAND_VENDOR_1) && roll_chance_i(10)) - { - cEntry = NPC_GUNTER; - instance->SetData(TYPE_RAND_VENDOR_1, DONE); - } - else if (!instance->GetData(TYPE_RAND_VENDOR_2) && roll_chance_i(10)) - { - cEntry = NPC_KYREN; - instance->SetData(TYPE_RAND_VENDOR_2, DONE); - } - - // start generic rp - eventTimer = 1; - events.ScheduleEvent(eventTimer, 3000); - - me->UpdateEntry(cEntry); - } - } - - void SpellHit(Unit* caster, SpellInfo const* spell) override - { - if (spell->Id == SPELL_REMOVE_AMANI_CURSE && caster->IsPlayer() && me->GetEntry() == NPC_FOREST_FROG) - { - me->GetMotionMaster()->MoveIdle(); - me->SetFacingToObject(caster); - PlayerGUID = caster->GetGUID(); - - if (roll_chance_i(2)) - { - DoCast(caster, SPELL_PUSH_MOJO, true); - me->GetMotionMaster()->MovePoint(POINT_DESPAWN, caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ()); - } - else - DoSpawnRandom(); - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetZulAmanAI(creature); - } }; /*###### @@ -467,8 +260,6 @@ public: bool IsLoot; ObjectGuid PlayerGUID; - void Reset() override { } - void JustEngagedWith(Unit* /*who*/) override { } void JustDied(Unit* /*killer*/) override @@ -508,21 +299,14 @@ public: creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); - InstanceScript* instance = creature->GetInstanceScript(); - if (instance) + float x, y, z; + creature->GetPosition(x, y, z); + for (uint8 i = 0; i < 4; ++i) { - //uint8 progress = instance->GetData(DATA_CHESTLOOTED); - instance->SetData(DATA_CHESTLOOTED, 0); - float x, y, z; - creature->GetPosition(x, y, z); - uint32 entry = creature->GetEntry(); - for (uint8 i = 0; i < 4; ++i) + if (HostageEntry[i] == creature->GetEntry()) { - if (HostageEntry[i] == entry) - { - creature->SummonGameObject(ChestEntry[i], x - 2, y, z, 0, 0, 0, 0, 0, 0); - break; - } + creature->SummonGameObject(ChestEntry[i], x - 2, y, z, 0, 0, 0, 0, 0, 0); + break; } } @@ -591,201 +375,172 @@ enum Weapons WEAPON_SPEAR = 13631 }; -class npc_harrison_jones : public CreatureScript +struct npc_harrison_jones : public ScriptedAI { -public: - npc_harrison_jones() : CreatureScript("npc_harrison_jones") + npc_harrison_jones(Creature* creature) : ScriptedAI(creature) { + _instance = creature->GetInstanceScript(); } - struct npc_harrison_jonesAI : public ScriptedAI + void Reset() override { - npc_harrison_jonesAI(Creature* creature) : ScriptedAI(creature) + _gongEvent = 0; + _gongTimer = 0; + uiTargetGUID.Clear(); + } + + void JustEngagedWith(Unit* /*who*/) override { } + + void sGossipSelect(Player* player, uint32 sender, uint32 action) override + { + if (me->GetCreatureTemplate()->GossipMenuId == sender && !action) { - instance = creature->GetInstanceScript(); + CloseGossipMenuFor(player); + me->SetFacingToObject(player); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + Talk(SAY_HARRISON_0); + _gongEvent = GONG_EVENT_1; + _gongTimer = 4000; } + } - InstanceScript* instance; + void SpellHit(Unit*, SpellInfo const* spell) override + { + if (spell->Id == SPELL_COSMETIC_SPEAR_THROW) + { + me->RemoveAllAuras(); + me->SetEntry(NPC_HARRISON_JONES_2); + me->SetDisplayId(MODEL_HARRISON_JONES_2); + me->SetTarget(); + me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_DEAD); + me->SetDynamicFlag(UNIT_DYNFLAG_DEAD); + _instance->StorePersistentData(DATA_TIMED_RUN, 21); + _instance->DoAction(ACTION_START_TIMED_RUN); + } + } + void UpdateAI(uint32 diff) override + { + if (_gongEvent) + { + if (_gongTimer <= diff) + { + switch (_gongEvent) + { + case GONG_EVENT_1: + me->GetMotionMaster()->MovePath(HARRISON_MOVE_1, false); + _gongEvent = GONG_EVENT_2; + _gongTimer = 12000; + break; + case GONG_EVENT_2: + me->SetFacingTo(6.235659f); + Talk(SAY_HARRISON_1); + DoCastSelf(SPELL_BANGING_THE_GONG); + me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_MACE)); + me->SetSheath(SHEATH_STATE_MELEE); + _gongEvent = GONG_EVENT_3; + _gongTimer = 4000; + break; + case GONG_EVENT_3: + if (GameObject* gong = _instance->GetGameObject(DATA_STRANGE_GONG)) + gong->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); + _gongEvent = GONG_EVENT_4; + _gongTimer = 105000; + break; + case GONG_EVENT_4: + me->RemoveAura(SPELL_BANGING_THE_GONG); + if (GameObject* gong = _instance->GetGameObject(DATA_STRANGE_GONG)) + gong->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); + + // Players are Now Saved to instance at SPECIAL (Player should be notified?) + me->GetMotionMaster()->MovePath(HARRISON_MOVE_2, false); + _gongEvent = GONG_EVENT_5; + _gongTimer = 5000; + break; + case GONG_EVENT_5: + me->SetEntry(NPC_HARRISON_JONES_1); + me->SetDisplayId(MODEL_HARRISON_JONES_1); + Talk(SAY_HARRISON_2); + _gongTimer = 12000; + _gongEvent = GONG_EVENT_6; + break; + case GONG_EVENT_6: + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_USE_STANDING); + Talk(SAY_HARRISON_3); + _gongTimer = 7000; + _gongEvent = GONG_EVENT_7; + break; + case GONG_EVENT_7: + if (!uiTargetGUID) + { + std::list targetList; + GetCreatureListWithEntryInGrid(targetList, me, NPC_AMANISHI_GUARDIAN, 26.0f); + if (!targetList.empty()) + { + for (auto const& creature : targetList) + { + if (creature) + { + creature->SetImmuneToPC(true); + creature->SetReactState(REACT_PASSIVE); + + if (creature->GetPositionX() > 120) + { + creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_SPEAR)); + creature->AI()->SetData(0, 1); + } + else + creature->AI()->SetData(0, 2); + } + } + } + } + + if (GameObject* gate = _instance->GetGameObject(DATA_MASSIVE_GATE)) + gate->SetGoState(GO_STATE_ACTIVE); + _gongTimer = 2000; + _gongEvent = GONG_EVENT_8; + break; + case GONG_EVENT_8: + DoCastSelf(SPELL_STEALTH); + me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(0)); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + me->GetMotionMaster()->MovePath(HARRISON_MOVE_3, false); + _gongTimer = 1000; + _gongEvent = 0; + break; + case GONG_EVENT_9: + me->GetMotionMaster()->MovePoint(0, 120.687f, 1674.0f, 42.0217f); + _gongTimer = 12000; + _gongEvent = GONG_EVENT_10; + break; + case GONG_EVENT_10: + me->SetFacingTo(1.59044f); + _gongEvent = 11; + _gongTimer = 6000; + break; + case GONG_EVENT_11: + me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + _gongEvent = 0; + _gongTimer = 1000; + break; + } + } + else + _gongTimer -= diff; + } + } + + private: + InstanceScript* _instance; uint8 _gongEvent; uint32 _gongTimer; ObjectGuid uiTargetGUID; - - void Reset() override - { - _gongEvent = 0; - _gongTimer = 0; - uiTargetGUID.Clear(); - } - - void JustEngagedWith(Unit* /*who*/) override { } - - void sGossipSelect(Player* player, uint32 sender, uint32 action) override - { - if (me->GetCreatureTemplate()->GossipMenuId == sender && !action) - { - CloseGossipMenuFor(player); - me->SetFacingToObject(player); - me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); - Talk(SAY_HARRISON_0); - _gongEvent = GONG_EVENT_1; - _gongTimer = 4000; - } - } - - void SpellHit(Unit*, SpellInfo const* spell) override - { - if (spell->Id == SPELL_COSMETIC_SPEAR_THROW) - { - me->RemoveAllAuras(); - me->SetEntry(NPC_HARRISON_JONES_2); - me->SetDisplayId(MODEL_HARRISON_JONES_2); - me->SetTarget(); - me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_DEAD); - me->SetDynamicFlag(UNIT_DYNFLAG_DEAD); - instance->SetData(DATA_GONGEVENT, DONE); - } - } - - void UpdateAI(uint32 diff) override - { - if (_gongEvent) - { - if (_gongTimer <= diff) - { - switch (_gongEvent) - { - case GONG_EVENT_1: - me->GetMotionMaster()->MovePath(HARRISON_MOVE_1, false); - _gongEvent = GONG_EVENT_2; - _gongTimer = 12000; - break; - case GONG_EVENT_2: - me->SetFacingTo(6.235659f); - Talk(SAY_HARRISON_1); - DoCast(me, SPELL_BANGING_THE_GONG); - me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_MACE)); - me->SetSheath(SHEATH_STATE_MELEE); - _gongEvent = GONG_EVENT_3; - _gongTimer = 4000; - break; - case GONG_EVENT_3: - if (GameObject* gong = me->GetMap()->GetGameObject(instance->GetGuidData(GO_STRANGE_GONG))) - gong->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - _gongEvent = GONG_EVENT_4; - _gongTimer = 105000; - break; - case GONG_EVENT_4: - me->RemoveAura(SPELL_BANGING_THE_GONG); - if (GameObject* gong = me->GetMap()->GetGameObject(instance->GetGuidData(GO_STRANGE_GONG))) - gong->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - - // trigger or gong will need to be scripted to set IN_PROGRESS after enough hits. - // This is temp workaround. - instance->SetData(DATA_GONGEVENT, IN_PROGRESS); // to be removed. - - if (instance->GetData(DATA_GONGEVENT) == IN_PROGRESS) - { - // Players are Now Saved to instance at SPECIAL (Player should be notified?) - me->GetMotionMaster()->MovePath(HARRISON_MOVE_2, false); - _gongEvent = GONG_EVENT_5; - _gongTimer = 5000; - } - else - { - _gongTimer = 1000; - _gongEvent = GONG_EVENT_9; - } - break; - case GONG_EVENT_5: - me->SetEntry(NPC_HARRISON_JONES_1); - me->SetDisplayId(MODEL_HARRISON_JONES_1); - Talk(SAY_HARRISON_2); - _gongTimer = 12000; - _gongEvent = GONG_EVENT_6; - break; - case GONG_EVENT_6: - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_USE_STANDING); - Talk(SAY_HARRISON_3); - _gongTimer = 7000; - _gongEvent = GONG_EVENT_7; - break; - case GONG_EVENT_7: - if (!uiTargetGUID) - { - std::list targetList; - GetCreatureListWithEntryInGrid(targetList, me, NPC_AMANISHI_GUARDIAN, 26.0f); - if (!targetList.empty()) - { - for (std::list::const_iterator itr = targetList.begin(); itr != targetList.end(); ++itr) - { - if (Creature* ptarget = *itr) - { - if (ptarget->GetPositionX() > 120) - { - ptarget->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_SPEAR)); - ptarget->SetImmuneToPC(true); - ptarget->SetReactState(REACT_PASSIVE); - ptarget->AI()->SetData(0, 1); - } - else - { - ptarget->SetImmuneToPC(true); - ptarget->SetReactState(REACT_PASSIVE); - ptarget->AI()->SetData(0, 2); - } - } - } - } - } - - if (GameObject* gate = me->GetMap()->GetGameObject(instance->GetGuidData(GO_MASSIVE_GATE))) - gate->SetGoState(GO_STATE_ACTIVE); - _gongTimer = 2000; - _gongEvent = GONG_EVENT_8; - break; - case GONG_EVENT_8: - DoCast(me, SPELL_STEALTH); - me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(0)); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - me->GetMotionMaster()->MovePath(HARRISON_MOVE_3, false); - _gongTimer = 1000; - _gongEvent = 0; - break; - case GONG_EVENT_9: - me->GetMotionMaster()->MovePoint(0, 120.687f, 1674.0f, 42.0217f); - _gongTimer = 12000; - _gongEvent = GONG_EVENT_10; - break; - case GONG_EVENT_10: - me->SetFacingTo(1.59044f); - _gongEvent = 11; - _gongTimer = 6000; - break; - case GONG_EVENT_11: - me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); - - instance->SetData(DATA_GONGEVENT, NOT_STARTED); - _gongEvent = 0; - _gongTimer = 1000; - break; - } - } - else - _gongTimer -= diff; - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetZulAmanAI(creature); - } }; void AddSC_zulaman() { - new npc_forest_frog(); + RegisterZulAmanCreatureAI(npc_forest_frog); new npc_zulaman_hostage(); - new npc_harrison_jones(); + RegisterZulAmanCreatureAI(npc_harrison_jones); } diff --git a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.h b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.h index a15512712..86092f918 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.h +++ b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.h @@ -25,18 +25,19 @@ enum DataTypes { - DATA_GONGEVENT = 0, - DATA_NALORAKK = 1, - DATA_AKILZON = 2, - DATA_JANALAI = 3, - DATA_HALAZZI = 4, - DATA_HEXLORD = 5, - DATA_ZULJIN = 6, - MAX_ENCOUNTER = 7, - DATA_SPIRIT_LYNX = 8, - DATA_CHESTLOOTED = 9, - TYPE_RAND_VENDOR_1 = 10, - TYPE_RAND_VENDOR_2 = 11 + DATA_NALORAKK = 0, + DATA_AKILZON = 1, + DATA_JANALAI = 2, + DATA_HALAZZI = 3, + DATA_HEXLORD = 4, + DATA_ZULJIN = 5, + MAX_ENCOUNTER = 6, + DATA_SPIRIT_LYNX = 7, + TYPE_RAND_VENDOR_1 = 8, + TYPE_RAND_VENDOR_2 = 9, + DATA_STRANGE_GONG = 10, + DATA_MASSIVE_GATE = 11, + DATA_HEXLORD_GATE = 12 }; enum CreatureIds @@ -69,6 +70,15 @@ enum GameobjectIds GO_STRANGE_GONG = 187359 }; +enum MiscIds +{ + DATA_TIMED_RUN = 0, + ACTION_START_TIMED_RUN = 0, + GROUP_TIMED_RUN = 1 +}; + +uint32 constexpr PersistentDataCount = 1; + template inline AI* GetZulAmanAI(T* obj) {