fix(Scripts/HowlingFjord): Harrowmeiser and Petrov Gossips (#26875)

This commit is contained in:
Gultask
2026-07-31 06:05:21 -03:00
committed by GitHub
parent adcd88a0b0
commit 21abfe0bc4
3 changed files with 185 additions and 0 deletions
@@ -36,6 +36,7 @@ enum ZeppelinEvent
EVENT_UC_TO_OG_DEPARTURE = 15321,
EVENT_UC_TO_GROMGOL_DEPARTURE = 15313,
EVENT_GROMGOL_TO_UC_DEPARTURE = 15315,
EVENT_WK_DEPARTURE = 15430,
};
enum ZeppelinMaster
@@ -55,6 +56,11 @@ enum ZeppelinMaster
NPC_KRENDLE_BIGPOCKETS = 34766,
};
enum ZeppelinTransport
{
GO_WESTGUARD_ZEPPELIN = 186371,
};
const float SEARCH_RANGE_ZEPPELIN_MASTER = 32.0f;
enum ZeppelinPassenger
@@ -15,8 +15,15 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CreatureScript.h"
#include "GameObjectAI.h"
#include "GameObjectScript.h"
#include "Map.h"
#include "Player.h"
#include "ScriptedGossip.h"
#include "TaskScheduler.h"
#include "Transport.h"
#include "TransportMgr.h"
#include "WorldState.h"
#include "transport_zeppelin.h"
@@ -101,9 +108,166 @@ struct go_transport_the_purple_princess : GameObjectAI
}
};
// 186371 Zeppelin - Westguard Keep to Shattered Straits
struct go_transport_westguard_zeppelin : GameObjectAI
{
go_transport_westguard_zeppelin(GameObject* object) : GameObjectAI(object) { };
void EventInform(uint32 eventId) override
{
if (eventId != EVENT_WK_ARRIVAL)
return;
if (Creature* creature = me->FindNearestCreature(NPC_HARROWMEISER, SEARCH_RANGE_ZEPPELIN_MASTER))
creature->AI()->Talk(0);
// the dock is covered by two stop frames of 60s each, so EVENT_WK_DEPARTURE
// only fires two minutes later - warn one minute before it does
_scheduler.Schedule(1min, [this](TaskContext /*context*/)
{
if (Creature* creature = me->FindNearestCreature(NPC_HARROWMEISER, SEARCH_RANGE_ZEPPELIN_MASTER))
creature->AI()->Talk(1);
});
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
enum WestguardZeppelinGossip
{
GOSSIP_TEXT_PETROV_EN_ROUTE = 11322,
GOSSIP_TEXT_PETROV_ARRIVING = 11324,
GOSSIP_TEXT_HARROWMEISER_DOCKED = 11328,
GOSSIP_TEXT_HARROWMEISER_ARRIVING = 11330,
GOSSIP_TEXT_HARROWMEISER_EN_ROUTE = 11332,
};
// The two "en route" texts above read "in less than $3078w minutes". The client
// substitutes that token with the world state below, so it renders 0 unless a value
// has been pushed to the player first.
enum WestguardZeppelinWorldState
{
WORLD_STATE_ZEPPELIN_ETA = 3078,
};
enum WestguardZeppelinState
{
ZEPPELIN_STATE_EN_ROUTE,
ZEPPELIN_STATE_ARRIVING,
ZEPPELIN_STATE_DOCKED,
};
// Reports where the Westguard Keep zeppelin is in its path. While it is still touring the
// bay the remaining minutes are pushed to the player as WORLD_STATE_ZEPPELIN_ETA.
WestguardZeppelinState GetWestguardZeppelinState(Player* player, Map* map)
{
MotionTransport const* zeppelin = nullptr;
for (Transport* transport : map->GetAllTransports())
if (transport->GetEntry() == GO_WESTGUARD_ZEPPELIN)
{
zeppelin = transport->ToMotionTransport();
break;
}
if (!zeppelin || !zeppelin->GetPeriod())
return ZEPPELIN_STATE_EN_ROUTE;
uint32 dockArriveTime = 0;
uint32 dockDepartTime = 0;
for (KeyFrame const& frame : zeppelin->GetKeyFrames())
{
if (frame.Node->arrivalEventID == EVENT_WK_ARRIVAL)
dockArriveTime = frame.ArriveTime;
else if (frame.Node->departureEventID == EVENT_WK_DEPARTURE)
dockDepartTime = frame.DepartureTime;
}
if (!dockArriveTime)
return ZEPPELIN_STATE_EN_ROUTE;
uint32 const period = zeppelin->GetPeriod();
uint32 const timer = zeppelin->GetPathProgress() % period;
// the dock is covered by the last and the first stop frame of the path, so the docked
// window normally wraps the end of one period into the start of the next
bool const docked = dockArriveTime > dockDepartTime
? timer >= dockArriveTime || timer < dockDepartTime
: timer >= dockArriveTime && timer < dockDepartTime;
if (docked)
return ZEPPELIN_STATE_DOCKED;
// modular so it stays correct whichever way around the two stop frames sit
uint32 const msUntilArrival = (dockArriveTime + period - timer) % period;
if (msUntilArrival <= MINUTE * IN_MILLISECONDS)
return ZEPPELIN_STATE_ARRIVING;
// the texts read "less than X minutes", so round up
player->SendUpdateWorldState(WORLD_STATE_ZEPPELIN_ETA,
(msUntilArrival + MINUTE * IN_MILLISECONDS - 1) / (MINUTE * IN_MILLISECONDS));
return ZEPPELIN_STATE_EN_ROUTE;
}
// 23823 Harrowmeiser
class npc_harrowmeiser : public CreatureScript
{
public:
npc_harrowmeiser() : CreatureScript("npc_harrowmeiser") { }
bool OnGossipHello(Player* player, Creature* creature) override
{
uint32 textId = GOSSIP_TEXT_HARROWMEISER_EN_ROUTE;
switch (GetWestguardZeppelinState(player, creature->GetMap()))
{
case ZEPPELIN_STATE_DOCKED:
textId = GOSSIP_TEXT_HARROWMEISER_DOCKED;
break;
case ZEPPELIN_STATE_ARRIVING:
textId = GOSSIP_TEXT_HARROWMEISER_ARRIVING;
break;
default:
break;
}
SendGossipMenuFor(player, textId, creature->GetGUID());
return true;
}
};
// 23895 Bombardier Petrov
class npc_bombardier_petrov : public CreatureScript
{
public:
npc_bombardier_petrov() : CreatureScript("npc_bombardier_petrov") { }
bool OnGossipHello(Player* player, Creature* creature) override
{
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
// he has no docked text of his own, "she's almost here" covers being at the dock too
uint32 const textId = GetWestguardZeppelinState(player, creature->GetMap()) == ZEPPELIN_STATE_EN_ROUTE
? GOSSIP_TEXT_PETROV_EN_ROUTE
: GOSSIP_TEXT_PETROV_ARRIVING;
SendGossipMenuFor(player, textId, creature->GetGUID());
return true;
}
};
void AddSC_transport_zeppelins()
{
RegisterGameObjectAI(go_transport_the_iron_eagle);
RegisterGameObjectAI(go_transport_the_thundercaller);
RegisterGameObjectAI(go_transport_the_purple_princess);
RegisterGameObjectAI(go_transport_westguard_zeppelin);
new npc_harrowmeiser();
new npc_bombardier_petrov();
}