Core/Maps: implement map based world states and implemented support for required world states in achievement criterias

*converted Erduax' conditional achievement to world state based handling as example
This commit is contained in:
Ovahlord committed 2021-06-13 10:48:41 +02:00
1 parent ea85a0031c
commit be239e4458
11 files changed
+82 -56

No files matched your search

@@ -0,0 +1 @@
DELETE FROM `achievement_criteria_data` WHERE `ScriptName`= 'achievement_dont_need_to_break_eggs';
@@ -2472,6 +2472,11 @@ bool AchievementMgr<T>::ConditionsSatisfied(AchievementCriteriaEntry const* crit
}
}
if (criteria->RequiredWorldStateID != 0)
if (Map* map = referencePlayer->GetMap())
if (map->GetWorldStateValue(criteria->RequiredWorldStateID) != criteria->RequiredWorldStateValue)
return false;
return true;
}
+2 -2
View File
@@ -614,8 +614,8 @@ struct AchievementCriteriaEntry
uint32 Timer_asset_ID; // 12 Alway appears with timed events, used internally to start the achievement, store
uint32 Timer_time; // 13 time limit in seconds
uint32 Ui_order; // 14 also used in achievement shift-links as index in state bitmask
//uint32 unk1; // 15 only one value, still unknown
//uint32 unk2; // 16 all zeros
uint32 RequiredWorldStateID; // 15
int32 RequiredWorldStateValue; // 16
uint32 AdditionalConditionType[MAX_ADDITIONAL_CRITERIA_CONDITIONS]; // 17-19
uint32 AdditionalConditionValue[MAX_ADDITIONAL_CRITERIA_CONDITIONS]; // 20-22
};
+1 -1
View File
@@ -25,7 +25,7 @@ char const Achievementfmt[] = "niixsxiixixxii";
const std::string CustomAchievementfmt = "pppaaaapapaapp";
const std::string CustomAchievementIndex = "ID";
char const AnimKitfmt[] = "nxx";
char const AchievementCriteriafmt[] = "niiiliiiisiiiiixxiiiiii";
char const AchievementCriteriafmt[] = "niiiliiiisiiiiiiiiiiiii";
char const AreaTableEntryfmt[] = "niiiiiiiiiisiiiiiffiiiiiii";
char const AreaGroupEntryfmt[] = "niiiiiii";
char const AreaPOIEntryfmt[] = "nxiiiiiiiiixffixixxixx";
@@ -9204,6 +9204,10 @@ void Player::SendInitWorldStates(uint32 zoneId, uint32 areaId)
break;
}
// insert map world states
if (Map* map = GetMap())
map->AppendWorldStates(packet.Worldstates);
SendDirectMessage(packet.Write());
SendBGWeekendWorldStates();
SendBattlefieldWorldStates();
+35
View File
@@ -49,6 +49,7 @@
#include "Weather.h"
#include "WeatherMgr.h"
#include "World.h"
#include "WorldStatePackets.h"
#include <unordered_set>
#include <vector>
@@ -4772,3 +4773,37 @@ void Map::UpdateAreaDependentAuras()
player->UpdateZoneDependentAuras(player->GetZoneId());
}
}
void Map::SetWorldState(uint32 worldStateId, int32 value, bool withUpdatePacket /*= true*/)
{
_worldStates[worldStateId] = value;
if (!withUpdatePacket)
return;
// Notify all players on the map
WorldPackets::WorldState::UpdateWorldState updateWorldState;
updateWorldState.VariableID = worldStateId;
updateWorldState.Value = value;
updateWorldState.Write();
Map::PlayerList const& players = GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if (Player* player = itr->GetSource())
player->SendDirectMessage(updateWorldState.GetRawPacket());
}
int32 Map::GetWorldStateValue(uint32 worldStateId) const
{
std::unordered_map<uint32, int32>::const_iterator itr = _worldStates.find(worldStateId);
if (itr != _worldStates.end())
return itr->second;
return 0;
}
void Map::AppendWorldStates(std::vector<WorldPackets::WorldState::WorldStateInfo>& worldStates)
{
for (std::pair<uint32, int32> worldState : _worldStates)
worldStates.emplace_back(worldState.first, worldState.second);
}
+14
View File
@@ -67,6 +67,14 @@ namespace Trinity { struct ObjectUpdater; }
namespace G3D { class Plane; }
namespace VMAP { enum class ModelIgnoreFlags : uint32; }
namespace WorldPackets
{
namespace WorldState
{
struct WorldStateInfo;
}
}
struct ScriptAction
{
ObjectGuid sourceGUID;
@@ -853,6 +861,10 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
// This will not affect any already-present creatures in the group
void SetSpawnGroupInactive(uint32 groupId) { SetSpawnGroupActive(groupId, false); }
// Sets and stores world state values that will be used by the AchievementMgr to check additional criterias that require world state values
void SetWorldState(uint32 worldStateId, int32 value, bool withUpdatePacket = true);
int32 GetWorldStateValue(uint32 worldStateId) const;
void AppendWorldStates(std::vector<WorldPackets::WorldState::WorldStateInfo>& worldStates);
private:
// Type specific code for add/remove to/from grid
@@ -939,6 +951,8 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
std::unordered_set<Corpse*> _corpseBones;
std::unordered_set<Object*> _updateObjects;
std::unordered_map<uint32 /*worldStateId*/, int32 /*value*/> _worldStates;
};
enum InstanceResetMethod
@@ -24,18 +24,18 @@ namespace WorldPackets
{
namespace WorldState
{
struct WorldStateInfo
{
WorldStateInfo(int32 variableID, int32 value)
: VariableID(variableID), Value(value) { }
int32 VariableID;
int32 Value;
};
class InitWorldStates final : public ServerPacket
{
public:
struct WorldStateInfo
{
WorldStateInfo(int32 variableID, int32 value)
: VariableID(variableID), Value(value) { }
int32 VariableID;
int32 Value;
};
InitWorldStates();
WorldPacket const* Write() override;
@@ -88,13 +88,7 @@ enum Events
enum Actions
{
ACTION_FINISH_CORRUPTION = 0,
ACTION_DESPAWN = 1,
ACTION_FAIL_ACHIEVEMENT = 0
};
enum Data
{
DATA_ACHIEVEMT_ENLIGIBLE = 1
ACTION_DESPAWN = 1
};
Position const facelessCorruptorPositions1[] =
@@ -140,13 +134,14 @@ enum ModelIds
struct boss_erudax : public BossAI
{
boss_erudax(Creature* creature) : BossAI(creature, DATA_ERUDAX), _achievementEnligible(true) { }
boss_erudax(Creature* creature) : BossAI(creature, DATA_ERUDAX) { }
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
instance->instance->SetWorldState(WORLD_STATE_ID_DONT_NEED_TO_BREAK_EGGS, 0);
events.ScheduleEvent(EVENT_BINDING_SHADOWS, 10s + 500ms);
events.ScheduleEvent(EVENT_ENFEEBLING_BLOW, 19s);
events.ScheduleEvent(EVENT_SHADOW_GALE, 26s);
@@ -176,13 +171,6 @@ struct boss_erudax : public BossAI
summons.DespawnAll();
}
void DoAction(int32 action) override
{
if (action == ACTION_FAIL_ACHIEVEMENT)
_achievementEnligible = false;
}
void JustSummoned(Creature* summon) override
{
summons.RemoveNotExisting(); // keeping the summon container clean
@@ -202,14 +190,6 @@ struct boss_erudax : public BossAI
}
}
uint32 GetData(uint32 type) const override
{
if (type == DATA_ACHIEVEMT_ENLIGIBLE)
return _achievementEnligible;
return 0;
}
void OnSpellCastFinished(SpellInfo const* spell, SpellFinishReason reason) override
{
if (spell->Id == SPELL_ENFEEBLING_BLOW && reason == SPELL_FINISHED_SUCCESSFUL_CAST)
@@ -294,7 +274,6 @@ private:
summons.DoAction(ACTION_DESPAWN, pred2);
}
bool _achievementEnligible;
ObjectGuid _shadowGaleStalkerGUID;
};
@@ -387,8 +366,8 @@ struct npc_erudax_faceless_corruptor : public ScriptedAI
_instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
break;
case EVENT_TWILIGHT_CORRUPTION:
if (Creature* erudax = _instance->GetCreature(DATA_ERUDAX))
erudax->AI()->DoAction(ACTION_FAIL_ACHIEVEMENT);
// Fail achievement by setting the required world state to 1 (0 is required for successful achievement)
_instance->instance->SetWorldState(WORLD_STATE_ID_DONT_NEED_TO_BREAK_EGGS, 1);
DoCastAOE(SPELL_TWILIGHT_CORRUPTION);
break;
case EVENT_UMBRAL_MENDING:
@@ -547,23 +526,6 @@ class spell_erudax_twilight_corruption_AuraScript : public AuraScript
}
};
class achievement_dont_need_to_break_eggs : public AchievementCriteriaScript
{
public:
achievement_dont_need_to_break_eggs() : AchievementCriteriaScript("achievement_dont_need_to_break_eggs") { }
bool OnCheck(Player* /*source*/, Unit* target)
{
if (!target)
return false;
if (target->GetMap()->IsHeroic())
return target->GetAI()->GetData(DATA_ACHIEVEMT_ENLIGIBLE);
return false;
}
};
void AddSC_boss_erudax()
{
RegisterGrimBatolCreatureAI(boss_erudax);
@@ -572,5 +534,4 @@ void AddSC_boss_erudax()
RegisterSpellScript(spell_erudax_shadow_gale);
RegisterSpellScript(spell_erudax_shadow_gale_aura);
RegisterSpellAndAuraScriptPair(spell_erudax_twilight_corruption, spell_erudax_twilight_corruption_AuraScript);
new achievement_dont_need_to_break_eggs();
}
@@ -92,6 +92,11 @@ enum GBSummonGroups
SUMMON_GROUP_BATTERED_DRAKES = 0
};
enum GBWorldStates
{
WORLD_STATE_ID_DONT_NEED_TO_BREAK_EGGS = 5117 // Erduax Achievement required world state
};
template<class AI, class T>
AI* GetGrimBatolAI(T* creature)
{
@@ -60,6 +60,7 @@ class instance_grim_batol : public InstanceMapScript
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
LoadObjectData(creatureData, nullptr);
instance->SetWorldState(WORLD_STATE_ID_DONT_NEED_TO_BREAK_EGGS, 0, false);
_initialized = false;
_destroyedNets = 0;
_batteredRedDrakeState = STATE_EMPRISONED;