Core/GameObjects: Implemented gathering nodes (gameobject type 50)

Port From (https://github.com/TrinityCore/TrinityCore/commit/1011cb73c92ddb90589452f70a1dd33830689e32)
This commit is contained in:
hondacrx
2022-10-22 22:24:44 -04:00
parent 4cb55ce37b
commit 66ad9f4ce0
9 changed files with 259 additions and 58 deletions
@@ -2410,6 +2410,64 @@ namespace Game.Entities
player.SendPacket(gameObjectUILink);
return;
}
case GameObjectTypes.GatheringNode: //50
{
Player player = user.ToPlayer();
if (player == null)
return;
GameObjectTemplate info = GetGoInfo();
if (!m_personalLoot.ContainsKey(player.GetGUID()))
{
if (info.GatheringNode.chestLoot != 0)
{
Loot newLoot = new(GetMap(), GetGUID(), LootType.Chest, null);
m_personalLoot[player.GetGUID()] = newLoot;
newLoot.FillLoot(info.GatheringNode.chestLoot, LootStorage.Gameobject, player, true, false, GetLootMode(), GetMap().GetDifficultyLootItemContext());
}
if (info.GatheringNode.triggeredEvent != 0)
GameEvents.Trigger(info.GatheringNode.triggeredEvent, player, this);
// triggering linked GO
uint trapEntry = info.GatheringNode.linkedTrap;
if (trapEntry != 0)
TriggeringLinkedGameObject(trapEntry, player);
if (info.GatheringNode.xpDifficulty != 0 && info.GatheringNode.xpDifficulty < 10)
{
QuestXPRecord questXp = CliDB.QuestXPStorage.LookupByKey(player.GetLevel());
if (questXp != null)
{
uint xp = Quest.RoundXPValue(questXp.Difficulty[info.GatheringNode.xpDifficulty]);
if (xp != 0)
player.GiveXP(xp, null);
}
}
spellId = info.GatheringNode.spell;
}
if (m_personalLoot.Count >= info.GatheringNode.MaxNumberofLoots)
{
SetGoState(GameObjectState.Active);
SetDynamicFlag(GameObjectDynamicLowFlags.NoInterract);
}
if (GetLootState() != LootState.Activated)
{
SetLootState(LootState.Activated, player);
if (info.GatheringNode.ObjectDespawnDelay != 0)
DespawnOrUnsummon(TimeSpan.FromSeconds(info.GatheringNode.ObjectDespawnDelay));
}
// Send loot
Loot loot = GetLootForPlayer(player);
if (loot != null)
player.SendLoot(loot);
break;
}
default:
if (GetGoType() >= GameObjectTypes.Max)
Log.outError(LogFilter.Server, "GameObject.Use(): unit (type: {0}, guid: {1}, name: {2}) tries to use object (guid: {3}, entry: {4}, name: {5}) of unknown type ({6})",
@@ -2859,6 +2917,20 @@ namespace Game.Entities
}
break;
}
case GameObjectTypes.GatheringNode:
{
SetGoStateFor(GameObjectState.Active, looter);
ObjectFieldData objMask = new();
GameObjectFieldData goMask = new();
objMask.MarkChanged(objMask.DynamicFlags);
UpdateData udata = new(GetMapId());
BuildValuesUpdateForPlayerWithMask(udata, objMask.GetUpdateMask(), goMask.GetUpdateMask(), looter);
udata.BuildPacket(out UpdateObject packet);
looter.SendPacket(packet);
break;
}
}
}
@@ -3132,6 +3204,9 @@ namespace Game.Entities
public float GetInteractionDistance()
{
if (GetGoInfo().GetInteractRadiusOverride() != 0)
return (float)GetGoInfo().GetInteractRadiusOverride() / 100.0f;
switch (GetGoType())
{
case GameObjectTypes.AreaDamage:
@@ -3377,6 +3452,19 @@ namespace Game.Entities
|| m_goValue.CapturePoint.State == BattlegroundCapturePointState.HordeCaptured;
}
public bool MeetsInteractCondition(Player user)
{
if (m_goInfo.GetConditionID1() == 0)
return true;
PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(m_goInfo.GetConditionID1());
if (playerCondition != null)
if (!ConditionManager.IsPlayerMeetingCondition(user, playerCondition))
return false;
return true;
}
Dictionary<ObjectGuid, PerPlayerState> GetOrCreatePerPlayerStates()
{
if (m_perPlayerState == null)
+128 -45
View File
@@ -163,7 +163,7 @@ namespace Game.Entities
public newflagdrop NewFlagDrop;
[FieldOffset(68)]
public Garrisonbuilding garrisonBuilding;
public garrisonbuilding GarrisonBuilding;
[FieldOffset(68)]
public garrisonplot GarrisonPlot;
@@ -274,6 +274,89 @@ namespace Game.Entities
}
}
public uint GetConditionID1() => type switch
{
GameObjectTypes.Door => Door.conditionID1,
GameObjectTypes.Button => Button.conditionID1,
GameObjectTypes.QuestGiver => QuestGiver.conditionID1,
GameObjectTypes.Chest => Chest.conditionID1,
GameObjectTypes.Generic => Generic.conditionID1,
GameObjectTypes.Trap => Trap.conditionID1,
GameObjectTypes.Chair => Chair.conditionID1,
GameObjectTypes.SpellFocus => SpellFocus.conditionID1,
GameObjectTypes.Text => Text.conditionID1,
GameObjectTypes.Goober => Goober.conditionID1,
GameObjectTypes.Camera => Camera.conditionID1,
GameObjectTypes.Ritual => Ritual.conditionID1,
GameObjectTypes.Mailbox => MailBox.conditionID1,
GameObjectTypes.SpellCaster => SpellCaster.conditionID1,
GameObjectTypes.FlagStand => FlagStand.conditionID1,
GameObjectTypes.AuraGenerator => AuraGenerator.conditionID1,
GameObjectTypes.GuildBank => GuildBank.conditionID1,
GameObjectTypes.NewFlag => NewFlag.conditionID1,
GameObjectTypes.ItemForge => ItemForge.conditionID1,
GameObjectTypes.GatheringNode => GatheringNode.conditionID1,
_ => 0,
};
public uint GetInteractRadiusOverride() => type switch
{
GameObjectTypes.Door => Door.InteractRadiusOverride,
GameObjectTypes.Button => Button.InteractRadiusOverride,
GameObjectTypes.QuestGiver => QuestGiver.InteractRadiusOverride,
GameObjectTypes.Chest => Chest.InteractRadiusOverride,
GameObjectTypes.Binder => Binder.InteractRadiusOverride,
GameObjectTypes.Generic => Generic.InteractRadiusOverride,
GameObjectTypes.Trap => Trap.InteractRadiusOverride,
GameObjectTypes.Chair => Chair.InteractRadiusOverride,
GameObjectTypes.SpellFocus => SpellFocus.InteractRadiusOverride,
GameObjectTypes.Text => Text.InteractRadiusOverride,
GameObjectTypes.Goober => Goober.InteractRadiusOverride,
GameObjectTypes.Transport => Transport.InteractRadiusOverride,
GameObjectTypes.AreaDamage => AreaDamage.InteractRadiusOverride,
GameObjectTypes.Camera => Camera.InteractRadiusOverride,
GameObjectTypes.MapObjTransport => MoTransport.InteractRadiusOverride,
GameObjectTypes.DuelArbiter => DuelFlag.InteractRadiusOverride,
GameObjectTypes.FishingNode => FishingNode.InteractRadiusOverride,
GameObjectTypes.Ritual => Ritual.InteractRadiusOverride,
GameObjectTypes.Mailbox => MailBox.InteractRadiusOverride,
GameObjectTypes.GuardPost => GuardPost.InteractRadiusOverride,
GameObjectTypes.SpellCaster => SpellCaster.InteractRadiusOverride,
GameObjectTypes.MeetingStone => MeetingStone.InteractRadiusOverride,
GameObjectTypes.FlagStand => FlagStand.InteractRadiusOverride,
GameObjectTypes.FishingHole => FishingHole.InteractRadiusOverride,
GameObjectTypes.FlagDrop => FlagDrop.InteractRadiusOverride,
GameObjectTypes.ControlZone => ControlZone.InteractRadiusOverride,
GameObjectTypes.AuraGenerator => AuraGenerator.InteractRadiusOverride,
GameObjectTypes.DungeonDifficulty => DungeonDifficulty.InteractRadiusOverride,
GameObjectTypes.BarberChair => BarberChair.InteractRadiusOverride,
GameObjectTypes.DestructibleBuilding => DestructibleBuilding.InteractRadiusOverride,
GameObjectTypes.GuildBank => GuildBank.InteractRadiusOverride,
GameObjectTypes.TrapDoor => TrapDoor.InteractRadiusOverride,
GameObjectTypes.NewFlag => NewFlag.InteractRadiusOverride,
GameObjectTypes.NewFlagDrop => NewFlagDrop.InteractRadiusOverride,
GameObjectTypes.GarrisonBuilding => GarrisonBuilding.InteractRadiusOverride,
GameObjectTypes.GarrisonPlot => GarrisonPlot.InteractRadiusOverride,
GameObjectTypes.CapturePoint => CapturePoint.InteractRadiusOverride,
GameObjectTypes.PhaseableMo => PhaseableMO.InteractRadiusOverride,
GameObjectTypes.GarrisonMonument => GarrisonMonument.InteractRadiusOverride,
GameObjectTypes.GarrisonShipment => GarrisonShipment.InteractRadiusOverride,
GameObjectTypes.GarrisonMonumentPlaque => GarrisonMonumentPlaque.InteractRadiusOverride,
GameObjectTypes.ItemForge => ItemForge.InteractRadiusOverride,
GameObjectTypes.UILink => UILink.InteractRadiusOverride,
GameObjectTypes.KeystoneReceptacle => KeystoneReceptacle.InteractRadiusOverride,
GameObjectTypes.GatheringNode => GatheringNode.InteractRadiusOverride,
GameObjectTypes.ChallengeModeReward => ChallengeModeReward.InteractRadiusOverride,
GameObjectTypes.SiegeableMo => SiegeableMO.InteractRadiusOverride,
GameObjectTypes.PvpReward => PvpReward.InteractRadiusOverride,
GameObjectTypes.PlayerChoiceChest => PlayerChoiceChest.InteractRadiusOverride,
GameObjectTypes.LegendaryForge => LegendaryForge.InteractRadiusOverride,
GameObjectTypes.GarrTalentTree => GarrTalentTree.InteractRadiusOverride,
GameObjectTypes.WeeklyRewardChest => WeeklyRewardChest.InteractRadiusOverride,
_ => 0
};
public uint GetRequireLOS() => type switch
{
GameObjectTypes.Button => Button.requireLOS,
@@ -287,48 +370,27 @@ namespace Game.Entities
_ => 0,
};
public uint GetLockId()
public uint GetLockId() => type switch
{
switch (type)
{
case GameObjectTypes.Door:
return Door.open;
case GameObjectTypes.Button:
return Button.open;
case GameObjectTypes.QuestGiver:
return QuestGiver.open;
case GameObjectTypes.Chest:
return Chest.open;
case GameObjectTypes.Trap:
return Trap.open;
case GameObjectTypes.Goober:
return Goober.open;
case GameObjectTypes.AreaDamage:
return AreaDamage.open;
case GameObjectTypes.Camera:
return Camera.open;
case GameObjectTypes.FlagStand:
return FlagStand.open;
case GameObjectTypes.FishingHole:
return FishingHole.open;
case GameObjectTypes.FlagDrop:
return FlagDrop.open;
case GameObjectTypes.NewFlag:
return NewFlag.open;
case GameObjectTypes.NewFlagDrop:
return NewFlagDrop.open;
case GameObjectTypes.CapturePoint:
return CapturePoint.open;
case GameObjectTypes.GatheringNode:
return GatheringNode.open;
case GameObjectTypes.ChallengeModeReward:
return ChallengeModeReward.open;
case GameObjectTypes.PvpReward:
return PvpReward.open;
default:
return 0;
}
}
GameObjectTypes.Door => Door.open,
GameObjectTypes.Button => Button.open,
GameObjectTypes.QuestGiver => QuestGiver.open,
GameObjectTypes.Chest => Chest.open,
GameObjectTypes.Trap => Trap.open,
GameObjectTypes.Goober => Goober.open,
GameObjectTypes.AreaDamage => AreaDamage.open,
GameObjectTypes.Camera => Camera.open,
GameObjectTypes.FlagStand => FlagStand.open,
GameObjectTypes.FishingHole => FishingHole.open,
GameObjectTypes.FlagDrop => FlagDrop.open,
GameObjectTypes.NewFlag => NewFlag.open,
GameObjectTypes.NewFlagDrop => NewFlagDrop.open,
GameObjectTypes.CapturePoint => CapturePoint.open,
GameObjectTypes.GatheringNode => GatheringNode.open,
GameObjectTypes.ChallengeModeReward => ChallengeModeReward.open,
GameObjectTypes.PvpReward => PvpReward.open,
_ => 0,
};
// despawn at targeting of cast?
public bool GetDespawnPossibility()
@@ -378,7 +440,14 @@ namespace Game.Entities
return 0;
}
}
public uint GetNotInCombat() => type switch
{
GameObjectTypes.Chest => Chest.notInCombat,
GameObjectTypes.GatheringNode => GatheringNode.notInCombat,
_ => 0,
};
/// <summary>
/// despawn at uses amount
/// </summary>
@@ -492,6 +561,20 @@ namespace Game.Entities
}
}
public uint GetTrivialSkillHigh() => type switch
{
GameObjectTypes.Chest => Chest.trivialSkillHigh,
GameObjectTypes.GatheringNode => GatheringNode.trivialSkillHigh,
_ => 0,
};
public uint GetTrivialSkillLow() => type switch
{
GameObjectTypes.Chest => Chest.trivialSkillLow,
GameObjectTypes.GatheringNode => GatheringNode.trivialSkillLow,
_ => 0,
};
// Cooldown preventing goober and traps to cast spell
public uint GetCooldown()
{
@@ -1182,7 +1265,7 @@ namespace Game.Entities
public uint InteractRadiusOverride; // 2 Interact Radius Override (in hundredths), int, Min value: 0, Max value: 2147483647, Default value: 0
}
public struct Garrisonbuilding
public struct garrisonbuilding
{
public int SpawnMap; // 0 Spawn Map, References: Map, NoValue = -1
public uint InteractRadiusOverride; // 1 Interact Radius Override (in hundredths), int, Min value: 0, Max value: 2147483647, Default value: 0
@@ -1395,7 +1478,7 @@ namespace Game.Entities
public uint open; // 1 open, References: Lock_, NoValue = 0
public uint InteractRadiusOverride; // 2 Interact Radius Override (in hundredths), int, Min value: 0, Max value: 2147483647, Default value: 0
}
public struct clientmodel
{
public uint LargeAOI; // 0 Large AOI, enum { false, true, }; Default: false
@@ -154,10 +154,19 @@ namespace Game.Entities
else
dynFlags &= ~GameObjectDynamicLowFlags.NoInterract;
break;
case GameObjectTypes.GatheringNode:
if (gameObject.ActivateToQuest(receiver))
dynFlags |= GameObjectDynamicLowFlags.Activate | GameObjectDynamicLowFlags.Sparkle | GameObjectDynamicLowFlags.Highlight;
if (gameObject.GetGoStateFor(receiver.GetGUID()) == GameObjectState.Active)
dynFlags |= GameObjectDynamicLowFlags.Depleted;
break;
default:
break;
}
if (!gameObject.MeetsInteractCondition(receiver))
dynFlags |= GameObjectDynamicLowFlags.NoInterract;
unitDynFlags = ((uint)pathProgress << 16) | (uint)dynFlags;
}
}
+26 -8
View File
@@ -1257,16 +1257,34 @@ namespace Game.Entities
}
return false;
}
public bool UpdateGatherSkill(uint SkillId, uint SkillValue, uint RedLevel, uint Multiplicator = 1)
public bool UpdateGatherSkill(uint SkillId, uint SkillValue, uint RedLevel, uint Multiplicator = 1, WorldObject obj = null)
{
return UpdateGatherSkill((SkillType)SkillId, SkillValue, RedLevel, Multiplicator);
return UpdateGatherSkill((SkillType)SkillId, SkillValue, RedLevel, Multiplicator, obj);
}
public bool UpdateGatherSkill(SkillType SkillId, uint SkillValue, uint RedLevel, uint Multiplicator = 1)
public bool UpdateGatherSkill(SkillType SkillId, uint SkillValue, uint RedLevel, uint Multiplicator = 1, WorldObject obj = null)
{
Log.outDebug(LogFilter.Player, "UpdateGatherSkill(SkillId {0} SkillLevel {1} RedLevel {2})", SkillId, SkillValue, RedLevel);
uint gathering_skill_gain = WorldConfig.GetUIntValue(WorldCfg.SkillGainGathering);
uint grayLevel = RedLevel + 100;
uint greenLevel = RedLevel + 50;
uint yellowLevel = RedLevel + 25;
GameObject go = obj?.ToGameObject();
if (go != null)
{
if (go.GetGoInfo().GetTrivialSkillLow() != 0)
yellowLevel = go.GetGoInfo().GetTrivialSkillLow();
if (go.GetGoInfo().GetTrivialSkillHigh() != 0)
grayLevel = go.GetGoInfo().GetTrivialSkillHigh();
greenLevel = (yellowLevel + grayLevel) / 2;
}
// For skinning and Mining chance decrease with level. 1-74 - no decrease, 75-149 - 2 times, 225-299 - 8 times
switch (SkillId)
{
@@ -1281,7 +1299,7 @@ namespace Game.Entities
case SkillType.KulTiranHerbalism:
case SkillType.Jewelcrafting:
case SkillType.Inscription:
return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel + 100, RedLevel + 50, RedLevel + 25) * (int)Multiplicator, gathering_skill_gain);
return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, grayLevel, greenLevel, yellowLevel) * (int)Multiplicator, gathering_skill_gain);
case SkillType.Skinning:
case SkillType.Skinning2:
case SkillType.OutlandSkinning:
@@ -1292,9 +1310,9 @@ namespace Game.Entities
case SkillType.LegionSkinning:
case SkillType.KulTiranSkinning:
if (WorldConfig.GetIntValue(WorldCfg.SkillChanceSkinningSteps) == 0)
return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel + 100, RedLevel + 50, RedLevel + 25) * (int)Multiplicator, gathering_skill_gain);
return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, grayLevel, greenLevel, yellowLevel) * (int)Multiplicator, gathering_skill_gain);
else
return UpdateSkillPro(SkillId, (int)(SkillGainChance(SkillValue, RedLevel + 100, RedLevel + 50, RedLevel + 25) * Multiplicator) >> (int)(SkillValue / WorldConfig.GetIntValue(WorldCfg.SkillChanceSkinningSteps)), gathering_skill_gain);
return UpdateSkillPro(SkillId, (int)(SkillGainChance(SkillValue, grayLevel, greenLevel, yellowLevel) * Multiplicator) >> (int)(SkillValue / WorldConfig.GetIntValue(WorldCfg.SkillChanceSkinningSteps)), gathering_skill_gain);
case SkillType.Mining:
case SkillType.Mining2:
case SkillType.OutlandMining:
@@ -1305,9 +1323,9 @@ namespace Game.Entities
case SkillType.LegionMining:
case SkillType.KulTiranMining:
if (WorldConfig.GetIntValue(WorldCfg.SkillChanceMiningSteps) == 0)
return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel + 100, RedLevel + 50, RedLevel + 25) * (int)Multiplicator, gathering_skill_gain);
return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, grayLevel, greenLevel, yellowLevel) * (int)Multiplicator, gathering_skill_gain);
else
return UpdateSkillPro(SkillId, (int)(SkillGainChance(SkillValue, RedLevel + 100, RedLevel + 50, RedLevel + 25) * Multiplicator) >> (int)(SkillValue / WorldConfig.GetIntValue(WorldCfg.SkillChanceMiningSteps)), gathering_skill_gain);
return UpdateSkillPro(SkillId, (int)(SkillGainChance(SkillValue, grayLevel, greenLevel, yellowLevel) * Multiplicator) >> (int)(SkillValue / WorldConfig.GetIntValue(WorldCfg.SkillChanceMiningSteps)), gathering_skill_gain);
}
return false;
}
+2 -2
View File
@@ -750,9 +750,9 @@ namespace Game.Garrisons
}
}
if (go.GetGoType() == GameObjectTypes.GarrisonBuilding && go.GetGoInfo().garrisonBuilding.SpawnMap != 0)
if (go.GetGoType() == GameObjectTypes.GarrisonBuilding && go.GetGoInfo().GarrisonBuilding.SpawnMap != 0)
{
foreach (var cellGuids in Global.ObjectMgr.GetMapObjectGuids((uint)go.GetGoInfo().garrisonBuilding.SpawnMap, map.GetDifficultyID()))
foreach (var cellGuids in Global.ObjectMgr.GetMapObjectGuids((uint)go.GetGoInfo().GarrisonBuilding.SpawnMap, map.GetDifficultyID()))
{
foreach (var spawnId in cellGuids.Value.creatures)
{
+1 -1
View File
@@ -4182,7 +4182,7 @@ namespace Game
break;
case GameObjectTypes.GarrisonBuilding:
{
int transportMap = got.garrisonBuilding.SpawnMap;
int transportMap = got.GarrisonBuilding.SpawnMap;
if (transportMap != 0)
_transportMaps.Add((ushort)transportMap);
}
+1 -1
View File
@@ -296,7 +296,7 @@ namespace Game
else
go.SetLootState(LootState.Ready);
}
else if (go.IsFullyLooted())
else if (go.GetGoType() != GameObjectTypes.GatheringNode && go.IsFullyLooted())
go.SetLootState(LootState.JustDeactivated);
go.OnLootRelease(player);
+3
View File
@@ -5242,6 +5242,9 @@ namespace Game.Spells
lockId = go.GetGoInfo().GetLockId();
if (lockId == 0)
return SpellCastResult.BadTargets;
if (go.GetGoInfo().GetNotInCombat() != 0 && m_caster.ToUnit().IsInCombat())
return SpellCastResult.AffectingCombat;
}
else if (itm != null)
lockId = itm.GetTemplate().GetLockID();
+1 -1
View File
@@ -1300,7 +1300,7 @@ namespace Game.Spells
{
// Allow one skill-up until respawned
if (!gameObjTarget.IsInSkillupList(player.GetGUID()) &&
player.UpdateGatherSkill(skillId, pureSkillValue, (uint)reqSkillValue))
player.UpdateGatherSkill(skillId, pureSkillValue, (uint)reqSkillValue, 1, gameObjTarget))
gameObjTarget.AddToSkillupList(player.GetGUID());
}
else if (itemTarget != null)