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:
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user