Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-06-22 16:09:16 +08:00
23 changed files with 174 additions and 53 deletions

View File

@@ -887,7 +887,7 @@ void Player::FailQuest(uint32 questId)
{
QuestStatus qStatus = GetQuestStatus(questId);
// xinef: if quest is marked as failed, dont do it again
if ((qStatus != QUEST_STATUS_INCOMPLETE) && (!quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED)))
if ((qStatus != QUEST_STATUS_INCOMPLETE) && (!quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_CAN_FAIL_IN_ANY_STATE)))
return;
SetQuestStatus(questId, QUEST_STATUS_FAILED);

View File

@@ -108,6 +108,14 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
mutualChase = true;
}
// Prevent almost infinite spinning for pets with mutualTarget
// _mutualChase is false for previous check
if (angle && !mutualChase && !_mutualChase && mutualTarget && chaseRange < meleeRange && cOwner && cOwner->IsPet())
{
angle = Optional<ChaseAngle>();
mutualChase = true;
}
// periodically check if we're already in the expected range...
i_recheckDistance.Update(time_diff);
if (i_recheckDistance.Passed())

View File

@@ -157,23 +157,25 @@ enum QuestSpecialFlags
{
QUEST_SPECIAL_FLAGS_NONE = 0x000,
// Trinity flags for set SpecialFlags in DB if required but used only at server
QUEST_SPECIAL_FLAGS_REPEATABLE = 0x001, // Set by 1 in SpecialFlags from DB
QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT = 0x002, // Set by 2 in SpecialFlags from DB (if required area explore, spell SPELL_EFFECT_QUEST_COMPLETE casting, table `FECT_QUEST_COMPLETE casting, table `*_script` command SCRIPT_COMMAND_QUEST_EXPLORED use, set from script)
QUEST_SPECIAL_FLAGS_AUTO_ACCEPT = 0x004, // Set by 4 in SpecialFlags in DB if the quest is to be auto-accepted.
QUEST_SPECIAL_FLAGS_DF_QUEST = 0x008, // Set by 8 in SpecialFlags in DB if the quest is used by Dungeon Finder.
QUEST_SPECIAL_FLAGS_MONTHLY = 0x010, // Set by 16 in SpecialFlags in DB if the quest is reset at the begining of the month
QUEST_SPECIAL_FLAGS_CAST = 0x020, // Set by 32 in SpecialFlags in DB if the quest requires RequiredOrNpcGo killcredit but NOT kill (a spell cast)
QUEST_SPECIAL_FLAGS_NO_REP_SPILLOVER = 0x040, // Set by 64 in SpecialFlags in DB if the quest does not share rewarded reputation with other allied factions
QUEST_SPECIAL_FLAGS_REPEATABLE = 0x0001, // Set by 1 in SpecialFlags from DB
QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT = 0x0002, // Set by 2 in SpecialFlags from DB (if required area explore, spell SPELL_EFFECT_QUEST_COMPLETE casting, table `FECT_QUEST_COMPLETE casting, table `*_script` command SCRIPT_COMMAND_QUEST_EXPLORED use, set from script)
QUEST_SPECIAL_FLAGS_AUTO_ACCEPT = 0x0004, // Set by 4 in SpecialFlags in DB if the quest is to be auto-accepted.
QUEST_SPECIAL_FLAGS_DF_QUEST = 0x0008, // Set by 8 in SpecialFlags in DB if the quest is used by Dungeon Finder.
QUEST_SPECIAL_FLAGS_MONTHLY = 0x0010, // Set by 16 in SpecialFlags in DB if the quest is reset at the begining of the month
QUEST_SPECIAL_FLAGS_CAST = 0x0020, // Set by 32 in SpecialFlags in DB if the quest requires RequiredOrNpcGo killcredit but NOT kill (a spell cast)
QUEST_SPECIAL_FLAGS_NO_REP_SPILLOVER = 0x0040, // Set by 64 in SpecialFlags in DB if the quest does not share rewarded reputation with other allied factions
QUEST_SPECIAL_FLAGS_CAN_FAIL_IN_ANY_STATE = 0x0080, // Set by 128 in SpecialFlags in DB if the quest is allowed to fail in Player::FailQuest() independant of its current state
// room for more custom flags
QUEST_SPECIAL_FLAGS_DB_ALLOWED = QUEST_SPECIAL_FLAGS_REPEATABLE | QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT | QUEST_SPECIAL_FLAGS_AUTO_ACCEPT |
QUEST_SPECIAL_FLAGS_DF_QUEST | QUEST_SPECIAL_FLAGS_MONTHLY | QUEST_SPECIAL_FLAGS_CAST | QUEST_SPECIAL_FLAGS_NO_REP_SPILLOVER,
QUEST_SPECIAL_FLAGS_DF_QUEST | QUEST_SPECIAL_FLAGS_MONTHLY | QUEST_SPECIAL_FLAGS_CAST | QUEST_SPECIAL_FLAGS_NO_REP_SPILLOVER |
QUEST_SPECIAL_FLAGS_CAN_FAIL_IN_ANY_STATE,
QUEST_SPECIAL_FLAGS_DELIVER = 0x080, // Internal flag computed only
QUEST_SPECIAL_FLAGS_SPEAKTO = 0x100, // Internal flag computed only
QUEST_SPECIAL_FLAGS_KILL = 0x200, // Internal flag computed only
QUEST_SPECIAL_FLAGS_TIMED = 0x400, // Internal flag computed only
QUEST_SPECIAL_FLAGS_PLAYER_KILL = 0x800 // Internal flag computed only
QUEST_SPECIAL_FLAGS_DELIVER = 0x0100, // Internal flag computed only
QUEST_SPECIAL_FLAGS_SPEAKTO = 0x0200, // Internal flag computed only
QUEST_SPECIAL_FLAGS_KILL = 0x0400, // Internal flag computed only
QUEST_SPECIAL_FLAGS_TIMED = 0x0800, // Internal flag computed only
QUEST_SPECIAL_FLAGS_PLAYER_KILL = 0x1000 // Internal flag computed only
};
struct QuestLocale

View File

@@ -3710,6 +3710,7 @@ void Spell::cancel(bool bySelf)
return;
uint32 oldState = m_spellState;
bool autoRepeat = m_autoRepeat;
m_spellState = SPELL_STATE_FINISHED;
m_autoRepeat = false;
@@ -3724,9 +3725,11 @@ void Spell::cancel(bool bySelf)
}
[[fallthrough]];
case SPELL_STATE_DELAYED:
SendInterrupted(SPELL_FAILED_INTERRUPTED);
SendInterrupted(0);
// xinef: fixes bugged gcd reset in some cases
if (!autoRepeat)
SendCastResult(SPELL_FAILED_INTERRUPTED);
break;
case SPELL_STATE_CASTING:
if (!bySelf)
{

View File

@@ -676,10 +676,10 @@ struct npc_midsummer_ribbon_pole_target : public ScriptedAI
}
// prevent duplicates
if (std::find(_dancerList.begin(), _dancerList.end(), dancer) != _dancerList.end())
if (std::find(_dancerList.begin(), _dancerList.end(), dancer->GetGUID()) != _dancerList.end())
return;
_dancerList.push_back(dancer);
_dancerList.push_back(dancer->GetGUID());
}
void LocateRibbonPole()
@@ -707,10 +707,11 @@ struct npc_midsummer_ribbon_pole_target : public ScriptedAI
return;
// remove non-dancing players from list
std::erase_if(_dancerList, [](Player* dancer)
{
return !dancer->HasAura(SPELL_RIBBON_POLE_PERIODIC_VISUAL);
});
std::erase_if(_dancerList, [this](ObjectGuid dancerGUID)
{
Player* dancer = ObjectAccessor::GetPlayer(*me, dancerGUID);
return !dancer || !dancer->HasAura(SPELL_RIBBON_POLE_PERIODIC_VISUAL);
});
}
void DoFlameCircleChecks()
@@ -788,9 +789,7 @@ struct npc_midsummer_ribbon_pole_target : public ScriptedAI
for (uint8 i = 0; (i < MAX_COUNT_SPEW_LAVA_TARGETS) && (i < _dancerList.size()); i++)
{
Player* dancerTarget = _dancerList[i];
if (dancerTarget)
if (Player* dancerTarget = ObjectAccessor::GetPlayer(*me, _dancerList[i]))
{
Creature* fireSpiralBunny = dancerTarget->SummonCreature(NPC_RIBBON_POLE_FIRE_SPIRAL_BUNNY, dancerTarget->GetPositionX(), dancerTarget->GetPositionY(), dancerTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
if (fireSpiralBunny)
@@ -823,7 +822,7 @@ struct npc_midsummer_ribbon_pole_target : public ScriptedAI
}
private:
std::vector<Player*> _dancerList;
GuidVector _dancerList;
GameObject* _ribbonPole;
Creature* _bunny;
};

View File

@@ -530,7 +530,7 @@ public:
}
context.Repeat(timerptr[_currentWave]);
if (++_currentWave < maxWaves && _bossWave)
if (++_currentWave < maxWaves && _bossWave != TO_BE_DECIDED)
{
DoUpdateWorldState(WORLD_STATE_WAVES, _currentWave);
DoUpdateWorldState(WORLD_STATE_ENEMY, 1);

View File

@@ -153,6 +153,8 @@ enum ThrallWarchief : uint32
AREA_CAMP_TAURAJO = 378,
AREA_CROSSROADS = 380,
GO_UNADORNED_SPIKE = 175787,
// What the Wind Carries (ID: 6566)
QUEST_WHAT_THE_WIND_CARRIES = 6566,
GOSSIP_MENU_THRALL = 3664,
@@ -246,35 +248,50 @@ public:
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->GetMap()->LoadGrid(heraldOfThrallPos.GetPositionX(), heraldOfThrallPos.GetPositionY());
me->SummonCreature(NPC_HERALD_OF_THRALL, heraldOfThrallPos, TEMPSUMMON_TIMED_DESPAWN, 20 * IN_MILLISECONDS);
_scheduler.Schedule(2s, [this](TaskContext /*context*/)
me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
scheduler.Schedule(1s, [this](TaskContext /*context*/)
{
if (GameObject* spike = me->FindNearestGameObject(GO_UNADORNED_SPIKE, 10.0f))
{
Talk(SAY_THRALL_ON_QUEST_REWARD_0);
})
.Schedule(13s, [this](TaskContext /*context*/)
spike->SetGoState(GO_STATE_ACTIVE);
}
}).Schedule(2s, [this](TaskContext /*context*/)
{
Talk(SAY_THRALL_ON_QUEST_REWARD_0);
}).Schedule(9s, [this](TaskContext /*context*/)
{
Talk(SAY_THRALL_ON_QUEST_REWARD_1);
DoCastAOE(SPELL_WARCHIEF_BLESSING, true);
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->GetMap()->DoForAllPlayers([&](Player* player)
{
Talk(SAY_THRALL_ON_QUEST_REWARD_1);
})
.Schedule(15s, [this](TaskContext /*context*/)
{
DoCastAOE(SPELL_WARCHIEF_BLESSING, true);
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->GetMap()->DoForAllPlayers([&](Player* p)
if (player->IsAlive() && !player->IsGameMaster())
{
if (player->GetAreaId() == AREA_ORGRIMMAR)
{
if (p->IsAlive() && !p->IsGameMaster())
{
if (p->GetAreaId() == AREA_ORGRIMMAR || p->GetAreaId() == AREA_RAZOR_HILL || p->GetAreaId() == AREA_CROSSROADS || p->GetAreaId() == AREA_CAMP_TAURAJO)
{
p->CastSpell(p, SPELL_WARCHIEF_BLESSING, true);
}
}
});
player->CastSpell(player, SPELL_WARCHIEF_BLESSING, true);
}
}
});
}).Schedule(19s, [this](TaskContext /*context*/)
{
me->GetMap()->DoForAllPlayers([&](Player* player)
{
if (player->IsAlive() && !player->IsGameMaster())
{
if (player->GetAreaId() == AREA_CROSSROADS)
{
player->CastSpell(player, SPELL_WARCHIEF_BLESSING, true);
}
}
});
});
}
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
scheduler.Update(diff);
if (!UpdateVictim())
return;
@@ -295,9 +312,6 @@ public:
DoMeleeAttackIfReady();
}
protected:
TaskScheduler _scheduler;
};
};

View File

@@ -158,7 +158,9 @@ enum Points
enum Misc
{
MAX_FLAMECALLERS = 3
MAX_FLAMECALLERS = 3,
QUEST_SUMMON_AHUNE = 11691,
ITEM_MAGMA_TOTEM = 34953
};
Position const SummonPositions[] =
@@ -307,8 +309,8 @@ struct npc_frozen_core : public ScriptedAI
if (Creature* ahune = _instance->GetCreature(DATA_AHUNE))
Unit::Kill(me, ahune);
DoCast(SPELL_SUMMON_LOOT_MISSILE);
DoCast(SPELL_MINION_DESPAWNER);
DoCastSelf(SPELL_SUMMON_LOOT_MISSILE, true);
DoCastSelf(SPELL_MINION_DESPAWNER, true);
}
void DoAction(int32 action) override
@@ -662,6 +664,9 @@ struct go_ahune_ice_stone : public GameObjectAI
{
ClearGossipMenuFor(player);
player->DestroyItemCount(ITEM_MAGMA_TOTEM, 1, true, false);
player->AreaExploredOrEventHappens(QUEST_SUMMON_AHUNE); //auto rewarded
if (Creature* ahuneBunny = _instance->GetCreature(DATA_AHUNE_BUNNY))
ahuneBunny->AI()->DoAction(ACTION_START_EVENT);