mirror of
https://github.com/ZhengPeiRu21/mod-individual-progression
synced 2025-11-29 23:44:51 +08:00
509 lines
16 KiB
C++
509 lines
16 KiB
C++
/*
|
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Affero General Public License as published by the
|
|
* Free Software Foundation; either version 3 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 Affero General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "GossipDef.h"
|
|
#include "Player.h"
|
|
#include "ScriptedEscortAI.h"
|
|
#include "ScriptedGossip.h"
|
|
#include "SpellAuras.h"
|
|
#include "TaskScheduler.h"
|
|
|
|
#include "ProgressionSystem.h"
|
|
|
|
enum WindsorEnum
|
|
{
|
|
QUEST_JAIL_BREAK = 4322,
|
|
|
|
// Texts
|
|
SAY_AGGRO = 0,
|
|
SAY_START_ESCORT = 1,
|
|
SAY_DUGHAL_CELL_1 = 2,
|
|
SAY_DUGHAL_CELL_2 = 3,
|
|
SAY_EQUIPMENT_1 = 4,
|
|
SAY_EQUIPMENT_2 = 5,
|
|
SAY_EQUIPMENT_3 = 6,
|
|
SAY_EQUIPMENT_4 = 7,
|
|
SAY_JAZ_CELL_1 = 8,
|
|
SAY_JAZ_CELL_2 = 9,
|
|
SAY_SHILL_CELL_1 = 10,
|
|
SAY_SHILL_CELL_2 = 11,
|
|
SAY_SHILL_CELL_3 = 12,
|
|
SAY_CREST_CELL_1 = 13,
|
|
SAY_CREST_CELL_2 = 14,
|
|
SAY_TOBIAS_CELL_1 = 15,
|
|
SAY_TOBIAS_CELL_2 = 16,
|
|
SAY_FREE_1 = 17,
|
|
SAY_FREE_2 = 18,
|
|
|
|
//
|
|
SAY_PRISONER_AGGRO = 0,
|
|
|
|
SAY_TOBIAS_FREED = 0,
|
|
SAY_TOBIAS_FREED_2 = 1,
|
|
|
|
// Creatures
|
|
NPC_MARSHAL_REGINALD_WINDSOR = 9682,
|
|
NPC_SHILL_DINGER = 9678,
|
|
NPC_CREST_KILLER = 9680,
|
|
NPC_OGRABISI = 9677,
|
|
NPC_DUGHAL_STORMWING = 9022,
|
|
NPC_JAZ = 9681,
|
|
NPC_TOBIAS_SEECHER = 9679,
|
|
|
|
// Objects
|
|
GO_SUPPLY_ROOM_DOOR = 170561,
|
|
GO_SUPPLY_CRATE = 166872,
|
|
|
|
EVENT_RESUME_ESCORT = 1,
|
|
|
|
SPELL_WINDSOR_DEVOTION = 10293,
|
|
SPELL_WINDSOR_FRENZY = 15167
|
|
};
|
|
|
|
class ActivePrisonerEvent : public BasicEvent
|
|
{
|
|
public:
|
|
ActivePrisonerEvent(Creature* target) : _target(target) { }
|
|
|
|
bool Execute(uint64 /*time*/, uint32 /*diff*/)
|
|
{
|
|
_target->SetFaction(16);
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
Creature* _target;
|
|
};
|
|
|
|
class npc_marshal_windsor : public CreatureScript
|
|
{
|
|
public:
|
|
npc_marshal_windsor() : CreatureScript("npc_marshal_windsor") { }
|
|
|
|
struct npc_marshal_windsorAI : public npc_escortAI
|
|
{
|
|
npc_marshal_windsorAI(Creature* creature) : npc_escortAI(creature)
|
|
{
|
|
_instance = creature->GetInstanceScript();
|
|
}
|
|
|
|
void SetGUID(ObjectGuid playerGUID, int32 /*id*/) override
|
|
{
|
|
_playerGUID = playerGUID;
|
|
Start(true, false, playerGUID, 0, false, false);
|
|
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_IMMUNE_TO_PC);
|
|
}
|
|
|
|
void UpdateAI(uint32 diff) override
|
|
{
|
|
npc_escortAI::UpdateAI(diff);
|
|
|
|
_events.Update(diff);
|
|
_scheduler.Update(diff);
|
|
|
|
while (uint32 eventId = _events.ExecuteEvent())
|
|
{
|
|
if (eventId == EVENT_RESUME_ESCORT)
|
|
SetEscortPaused(false);
|
|
}
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
|
|
void AttackStart(Unit* who) override
|
|
{
|
|
if (who && !who->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC))
|
|
npc_escortAI::AttackStart(who);
|
|
}
|
|
|
|
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgEff*/, SpellSchoolMask /*mask*/) override
|
|
{
|
|
if (me->HealthBelowPctDamaged(40, damage) && !me->HasAura(SPELL_WINDSOR_FRENZY))
|
|
{
|
|
DoCastAOE(SPELL_WINDSOR_FRENZY);
|
|
}
|
|
}
|
|
|
|
void DoAction(int32 actionId) override
|
|
{
|
|
if (actionId == 0)
|
|
{
|
|
SetEscortPaused(false);
|
|
}
|
|
}
|
|
|
|
void EnterCombat(Unit* who) override
|
|
{
|
|
Talk(SAY_AGGRO, who);
|
|
}
|
|
|
|
void WaypointReached(uint32 id) override
|
|
{
|
|
switch (id)
|
|
{
|
|
case 1:
|
|
Talk(SAY_START_ESCORT);
|
|
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
|
|
break;
|
|
case 7:
|
|
me->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
|
|
if (Player* player = ObjectAccessor::FindPlayer(_playerGUID))
|
|
{
|
|
Talk(SAY_DUGHAL_CELL_1, player);
|
|
}
|
|
|
|
if (Creature* dughal = me->FindNearestCreature(NPC_DUGHAL_STORMWING, 100.0f))
|
|
{
|
|
if (!dughal->IsAlive())
|
|
dughal->Respawn(true);
|
|
|
|
dughal->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
|
}
|
|
SetEscortPaused(true);
|
|
break;
|
|
case 9:
|
|
Talk(SAY_DUGHAL_CELL_2);
|
|
break;
|
|
case 14:
|
|
if (Player* player = ObjectAccessor::FindPlayer(_playerGUID))
|
|
Talk(SAY_EQUIPMENT_1, player);
|
|
break;
|
|
case 15:
|
|
me->HandleEmoteCommand(EMOTE_ONESHOT_USE_STANDING);
|
|
break;
|
|
case 16:
|
|
if (GameObject* door = me->FindNearestGameObject(GO_SUPPLY_ROOM_DOOR, 50.0f))
|
|
_instance->DoUseDoorOrButton(door->GetGUID());
|
|
break;
|
|
case 18:
|
|
Talk(SAY_EQUIPMENT_2);
|
|
break;
|
|
case 19:
|
|
me->HandleEmoteCommand(EMOTE_ONESHOT_USE_STANDING);
|
|
break;
|
|
case 20:
|
|
if (GameObject* crate = me->FindNearestGameObject(GO_SUPPLY_CRATE, 15.0f))
|
|
crate->SetGoState(GO_STATE_ACTIVE);
|
|
break;
|
|
case 21:
|
|
me->UpdateEntry(NPC_MARSHAL_REGINALD_WINDSOR);
|
|
break;
|
|
case 22:
|
|
SetEscortPaused(true);
|
|
_events.ScheduleEvent(EVENT_RESUME_ESCORT, 8000);
|
|
if (Player* player = ObjectAccessor::FindPlayer(_playerGUID))
|
|
{
|
|
me->GetMotionMaster()->Clear();
|
|
me->SetFacingToObject(player);
|
|
Talk(SAY_EQUIPMENT_3, player);
|
|
me->SetFaction(player->GetFaction());
|
|
}
|
|
DoCast(me, SPELL_WINDSOR_DEVOTION);
|
|
HandleDevotionAura();
|
|
break;
|
|
case 23:
|
|
Talk(SAY_EQUIPMENT_4);
|
|
me->GetMotionMaster()->Clear();
|
|
if (Player* player = ObjectAccessor::FindPlayer(_playerGUID))
|
|
me->SetFacingToObject(player);
|
|
break;
|
|
case 30:
|
|
me->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
|
|
Talk(SAY_JAZ_CELL_1);
|
|
SchedulePrisonerActivation(NPC_OGRABISI);
|
|
SchedulePrisonerActivation(NPC_JAZ);
|
|
SetEscortPaused(true);
|
|
|
|
_scheduler.Schedule(5s, [this](TaskContext task)
|
|
{
|
|
Creature* ograbisi = me->FindNearestCreature(NPC_OGRABISI, 100.0f);
|
|
Creature* jaz = me->FindNearestCreature(NPC_JAZ, 100.0f);
|
|
|
|
if (jaz || ograbisi)
|
|
{
|
|
task.Repeat();
|
|
}
|
|
else
|
|
{
|
|
SetEscortPaused(false);
|
|
}
|
|
});
|
|
|
|
break;
|
|
case 32:
|
|
Talk(SAY_JAZ_CELL_2);
|
|
break;
|
|
case 35:
|
|
me->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
|
|
Talk(SAY_SHILL_CELL_1);
|
|
SchedulePrisonerActivation(NPC_SHILL_DINGER);
|
|
SetEscortPaused(true);
|
|
|
|
_scheduler.Schedule(5s, [this](TaskContext task)
|
|
{
|
|
if (Creature* shill = me->FindNearestCreature(NPC_SHILL_DINGER, 50.0f))
|
|
{
|
|
task.Repeat();
|
|
}
|
|
else
|
|
{
|
|
SetEscortPaused(false);
|
|
}
|
|
});
|
|
break;
|
|
case 37:
|
|
Talk(SAY_SHILL_CELL_2);
|
|
break;
|
|
case 38:
|
|
Talk(SAY_SHILL_CELL_3);
|
|
break;
|
|
case 45:
|
|
me->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
|
|
Talk(SAY_CREST_CELL_1);
|
|
SchedulePrisonerActivation(NPC_CREST_KILLER);
|
|
SetEscortPaused(true);
|
|
|
|
_scheduler.Schedule(5s, [this](TaskContext task)
|
|
{
|
|
if (Creature* prisioner = me->FindNearestCreature(NPC_CREST_KILLER, 50.0f))
|
|
{
|
|
task.Repeat();
|
|
}
|
|
else
|
|
{
|
|
SetEscortPaused(false);
|
|
}
|
|
});
|
|
break;
|
|
case 47:
|
|
Talk(SAY_CREST_CELL_2);
|
|
break;
|
|
case 49:
|
|
if (Creature* tobias = me->FindNearestCreature(NPC_TOBIAS_SEECHER, 200.0f))
|
|
{
|
|
if (!tobias->IsAlive())
|
|
{
|
|
tobias->Respawn(true);
|
|
}
|
|
|
|
tobias->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
|
}
|
|
Talk(SAY_TOBIAS_CELL_1);
|
|
SetEscortPaused(true);
|
|
break;
|
|
case 51:
|
|
if (Player* player = ObjectAccessor::FindPlayer(_playerGUID))
|
|
{
|
|
Talk(SAY_TOBIAS_CELL_2, player);
|
|
}
|
|
break;
|
|
case 57:
|
|
Talk(SAY_FREE_1);
|
|
me->GetMotionMaster()->Clear();
|
|
if (Player* player = ObjectAccessor::FindPlayer(_playerGUID))
|
|
{
|
|
me->SetFacingToObject(player);
|
|
}
|
|
break;
|
|
case 58:
|
|
Talk(SAY_FREE_2);
|
|
|
|
if (Player* player = ObjectAccessor::FindPlayer(_playerGUID))
|
|
{
|
|
player->GroupEventHappens(QUEST_JAIL_BREAK, me);
|
|
me->SetFacingTo(5.196206f);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void JustDied(Unit* /*killer*/) override
|
|
{
|
|
Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers();
|
|
|
|
for (auto const& itr : PlayerList)
|
|
{
|
|
if (Player* player = itr.GetSource())
|
|
{
|
|
if (player->GetQuestStatus(QUEST_JAIL_BREAK) == QUEST_STATUS_INCOMPLETE)
|
|
{
|
|
player->FailQuest(QUEST_JAIL_BREAK);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandleDevotionAura()
|
|
{
|
|
Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers();
|
|
|
|
for (auto const& itr : PlayerList)
|
|
{
|
|
if (Player* player = itr.GetSource())
|
|
{
|
|
if (Aura* aura = player->AddAura(SPELL_WINDSOR_DEVOTION, player))
|
|
{
|
|
aura->SetDuration(10 * MINUTE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SchedulePrisonerActivation(uint32 entry)
|
|
{
|
|
if (Creature* prisoner = me->FindNearestCreature(entry, 250.0f))
|
|
{
|
|
if (!prisoner->IsAlive())
|
|
{
|
|
prisoner->Respawn(true);
|
|
}
|
|
|
|
prisoner->m_Events.AddEvent(new ActivePrisonerEvent(prisoner), prisoner->m_Events.CalculateTime(5000));
|
|
}
|
|
}
|
|
|
|
private:
|
|
EventMap _events;
|
|
ObjectGuid _playerGUID;
|
|
InstanceScript* _instance;
|
|
TaskScheduler _scheduler;
|
|
};
|
|
|
|
bool OnQuestAccept(Player* player, Creature* me, Quest const* quest) override
|
|
{
|
|
if (!me->GetInstanceScript())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (quest->GetQuestId() == QUEST_JAIL_BREAK)
|
|
{
|
|
me->AI()->SetGUID(player->GetGUID());
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
|
|
me->SetFaction(player->GetFaction());
|
|
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
|
|
return false;
|
|
}
|
|
|
|
CreatureAI* GetAI(Creature* creature) const override
|
|
{
|
|
return new npc_marshal_windsorAI(creature);
|
|
}
|
|
};
|
|
|
|
class npc_jail_break_dughal_or_seecher : public CreatureScript
|
|
{
|
|
public:
|
|
npc_jail_break_dughal_or_seecher() : CreatureScript("npc_jail_break_dughal_or_seecher") { }
|
|
|
|
struct npc_jail_break_dughal_or_seecherAI : public npc_escortAI
|
|
{
|
|
npc_jail_break_dughal_or_seecherAI(Creature* creature) : npc_escortAI(creature)
|
|
{
|
|
|
|
if (creature->GetEntry() == NPC_DUGHAL_STORMWING)
|
|
{
|
|
AddWaypoint(0, 280.42f, -82.86f, -77.12f, 0);
|
|
AddWaypoint(1, 287.64f, -87.01f, -76.79f, 0);
|
|
AddWaypoint(2, 354.63f, -64.95f, -67.53f, 0);
|
|
}
|
|
else
|
|
{
|
|
AddWaypoint(0, 549.21f, -281.07f, -75.27f);
|
|
AddWaypoint(1, 554.39f, -267.39f, -73.68f);
|
|
AddWaypoint(2, 533.59f, -249.38f, -67.04f);
|
|
AddWaypoint(3, 519.44f, -217.02f, -59.34f);
|
|
AddWaypoint(4, 506.55f, -153.49f, -62.34f);
|
|
}
|
|
}
|
|
|
|
void WaypointReached(uint32 id) override
|
|
{
|
|
if (me->GetEntry() == NPC_DUGHAL_STORMWING && id == 2)
|
|
{
|
|
if (Creature* windsor = me->FindNearestCreature(9023, 200.0f))
|
|
{
|
|
windsor->AI()->DoAction(0);
|
|
}
|
|
}
|
|
else if (me->GetEntry() == NPC_TOBIAS_SEECHER && id == 4)
|
|
{
|
|
if (Creature* windsor = me->FindNearestCreature(NPC_MARSHAL_REGINALD_WINDSOR, 200.0f))
|
|
{
|
|
windsor->AI()->DoAction(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DoAction(int32 actionId) override
|
|
{
|
|
if (actionId == 0)
|
|
{
|
|
Start(false, true, ObjectGuid::Empty, 0, false, false);
|
|
}
|
|
}
|
|
};
|
|
|
|
bool OnGossipHello(Player* player, Creature* me) override
|
|
{
|
|
if (player->GetQuestStatus(QUEST_JAIL_BREAK) == QUEST_STATUS_INCOMPLETE)
|
|
{
|
|
std::string message = "You're free, Dughal! Get out of here!";
|
|
|
|
if (me->GetEntry() == NPC_TOBIAS_SEECHER)
|
|
message = "Get out of here, Tobias, you're free!";
|
|
|
|
AddGossipItemFor(player, GOSSIP_ICON_CHAT, message, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
|
SendGossipMenuFor(player, me->GetEntry() == NPC_DUGHAL_STORMWING ? 2846 : 2847, me->GetGUID());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OnGossipSelect(Player* player, Creature* me, uint32 /*menuId*/, uint32 gossipListId) override
|
|
{
|
|
CloseGossipMenuFor(player);
|
|
uint32 const action = player->PlayerTalkClass->GetGossipOptionAction(gossipListId);
|
|
|
|
if (action == 0)
|
|
{
|
|
me->AI()->Talk(0, player);
|
|
me->AI()->DoAction(0);
|
|
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
|
return true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
CreatureAI* GetAI(Creature* creature) const override
|
|
{
|
|
return new npc_jail_break_dughal_or_seecherAI(creature);
|
|
}
|
|
};
|
|
|
|
void AddSC_quest_jail_break_60_2()
|
|
{
|
|
new npc_marshal_windsor();
|
|
new npc_jail_break_dughal_or_seecher();
|
|
}
|