Skip to content

Commit

Permalink
Merge pull request #86 from Crypto137/loot-drops
Browse files Browse the repository at this point in the history
Implement non-item loot drop types
  • Loading branch information
Crypto137 authored Oct 19, 2024
2 parents f19aefd + 3c48aa0 commit fd2934d
Show file tree
Hide file tree
Showing 45 changed files with 2,412 additions and 510 deletions.
2 changes: 1 addition & 1 deletion src/MHServerEmu.Billing/BillingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ private bool OnBuyItemFromCatalog(PlayerConnection playerConnection, MailboxMess
{
case ItemPrototype itemProto:
// Give the player the item they are trying to "buy"
player.Game.LootManager.GiveItem(player, itemProto.DataRef);
player.Game.LootManager.GiveItem(itemProto.DataRef, player);
break;

case PlayerStashInventoryPrototype playerStashInventoryProto:
Expand Down
24 changes: 20 additions & 4 deletions src/MHServerEmu.Games/Behavior/AIController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -325,12 +325,23 @@ public void Think()
Brain.ThinkCountPerFrame = 0;
}
bool thinking = true;

if (Owner.TestStatus(EntityStatus.PendingDestroy) == false
&& Owner.TestStatus(EntityStatus.Destroyed) == false && thinking)
{
float thinkTime = 500; // slow think
if (TargetEntity != null || AssistedEntity != null)
thinkTime = 100; // fast think
float thinkTime;
int aiCustomThinkRateMS = Blackboard.AICustomThinkRateMS;
if (aiCustomThinkRateMS <= 0)
{
thinkTime = TargetEntity != null || AssistedEntity != null
? 100.0f // slow think
: 500.0f; // fast think
}
else
{
thinkTime = aiCustomThinkRateMS;
}

ScheduleAIThinkEvent(TimeSpan.FromMilliseconds(thinkTime) * Game.Random.NextFloat(0.9f, 1.1f));
}

Expand Down Expand Up @@ -560,7 +571,7 @@ private void ThrowForwardFromOwner(PrototypeId throwPowerRef)
}
}

private void ScheduleAIEvent<TEvent>(EventPointer<TEvent> eventPointer, TimeSpan timeOffset)
public void ScheduleAIEvent<TEvent>(EventPointer<TEvent> eventPointer, TimeSpan timeOffset)
where TEvent : CallMethodEvent<AIController>, new()
{
var scheduler = Game?.GameEventScheduler;
Expand Down Expand Up @@ -588,6 +599,11 @@ public class ThrownObjectPickedUpEvent : CallMethodEventParam1<AIController, Tim
protected override CallbackDelegate GetCallback() => (controller, time) => controller.ThrownObjectPickedUp(time);
}

public class EnableAIEvent : CallMethodEvent<AIController>
{
protected override CallbackDelegate GetCallback() => (controller) => controller.SetIsEnabled(true);
}

#endregion
}
}
8 changes: 8 additions & 0 deletions src/MHServerEmu.Games/Behavior/BehaviorBlackboard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public class BehaviorBlackboard: IPropertyChangeWatcher
public Vector3 MoveToCurrentPathNodePos { get; set; }
public Dictionary<ulong, long> DamageMap { get; set; }

public int AICustomThinkRateMS { get; private set; }

public BehaviorBlackboard(Agent owner)
{
_owner = owner;
Expand Down Expand Up @@ -76,6 +78,12 @@ public void Detach(bool removeFromAttachedCollection)

public void OnPropertyChange(PropertyId id, PropertyValue newValue, PropertyValue oldValue, SetPropertyFlags flags)
{
if (flags.HasFlag(SetPropertyFlags.Refresh) == false)
{
if (id.Enum == PropertyEnum.AICustomThinkRateMS)
AICustomThinkRateMS = newValue;
}

_owner.AIController?.Brain?.OnPropertyChange(id, newValue, oldValue, flags);
}

Expand Down
1 change: 1 addition & 0 deletions src/MHServerEmu.Games/Behavior/BehaviorSensorySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using MHServerEmu.Core.Helpers;
using MHServerEmu.Core.VectorMath;
using MHServerEmu.Games.Behavior.StaticAI;
using MHServerEmu.Games.Common;
using MHServerEmu.Games.Entities;
using MHServerEmu.Games.Entities.Avatars;
using MHServerEmu.Games.GameData.Prototypes;
Expand Down
1 change: 1 addition & 0 deletions src/MHServerEmu.Games/Behavior/StaticAI/SelectEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using MHServerEmu.Core.Collisions;
using MHServerEmu.Core.Extensions;
using MHServerEmu.Core.Logging;
using MHServerEmu.Games.Common;
using MHServerEmu.Games.Entities;
using MHServerEmu.Games.GameData;
using MHServerEmu.Games.GameData.Prototypes;
Expand Down
10 changes: 5 additions & 5 deletions src/MHServerEmu.Games/Common/AdminCommandManager.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

using Gazillion;
using Gazillion;
using MHServerEmu.Games.Network;

namespace MHServerEmu.Games.Common
Expand All @@ -12,7 +11,7 @@ public class AdminCommandManager
public AdminCommandManager(Game game)
{
_game = game;
_flags = AdminFlags.LocomotionSync;
_flags = AdminFlags.LocomotionSync | AdminFlags.CurrencyItemsConvertToggle;
}

public bool TestAdminFlag(AdminFlags flag)
Expand Down Expand Up @@ -42,8 +41,9 @@ public static void SendVerify(PlayerConnection playerConnection, string message)
}

[Flags]
public enum AdminFlags
public enum AdminFlags : ulong // Descriptions from 1.0.4932.0:
{
LocomotionSync = 1 << 1,
LocomotionSync = 1 << 1, // Toggles experimental locomotion sync mode
CurrencyItemsConvertToggle = 1 << 47 // Turns on/off conversion of Currency Items to Currency properties
}
}
Original file line number Diff line number Diff line change
@@ -1,37 +1,66 @@
using MHServerEmu.Core.Collisions;
using MHServerEmu.Core.Logging;
using MHServerEmu.Core.VectorMath;
using MHServerEmu.Games.Behavior;
using MHServerEmu.Games.Behavior.StaticAI;
using MHServerEmu.Games.Entities;
using MHServerEmu.Games.Entities.Items;
using MHServerEmu.Games.GameData.Prototypes;
using MHServerEmu.Games.Properties;
using MHServerEmu.Games.Regions;

namespace MHServerEmu.Games.Behavior
namespace MHServerEmu.Games.Common
{
public class Combat

[Flags]
public enum CombatTargetFlags
{
None = 0,
Flag0 = 1 << 0,
CheckInvulnerable = 1 << 1,
CheckAgent = 1 << 2,
CheckItem = 1 << 3,
IgnoreAggroDistance = 1 << 4,
IgnoreAggroDropRange = 1 << 5,
IgnoreAggroLOSChance = 1 << 6,
IgnoreStealth = 1 << 7,
IgnoreDead = 1 << 8,
IgnoreHostile = 1 << 9,
IgnoreLOS = 1 << 10,
IgnoreTargetable = 1 << 11,
}

public enum CombatTargetType
{
Hostile,
Ally
}

public static class Combat
{
// NOTE: In the client this class is referenced as D:\mirrorBuilds_source05\MarvelGame_v52\Source\Game\Game\Combat\Combat.cpp,
// but it's awkward for namespaces and classes to use the same names in C#, so we moved both combat classes to Common.

private static readonly Logger Logger = LogManager.CreateLogger();

public static List<WorldEntity> GetTargetsInRange(Agent aggressor, float rangeMax, float rangeMin, CombatTargetType targetType,
CombatTargetFlags flags, AIEntityAttributePrototype[] attributes)
{
List<WorldEntity> targets = new ();
List<WorldEntity> targets = new();
if (aggressor == null) return targets;
if (aggressor.Region == null)
{
Logger.Warn($"Agent not in region when trying to count targets in range! Agent: {aggressor}");
Logger.Warn($"GetTargetsInRange(): Agent not in region when trying to count targets in range! Agent: {aggressor}");
return targets;
}

Sphere volume = new (aggressor.RegionLocation.Position, rangeMax + aggressor.Bounds.GetRadius());
Sphere volume = new(aggressor.RegionLocation.Position, rangeMax + aggressor.Bounds.GetRadius());
foreach (WorldEntity target in aggressor.Region.IterateEntitiesInVolume(volume, new(EntityRegionSPContextFlags.ActivePartition)))
{
if (target == null) continue;
if (ValidTarget(aggressor.Game, aggressor, target, targetType, false, flags)
&& (attributes == null || PassesAttributesCheck(aggressor, target, attributes))
&& (rangeMin == 0f || (aggressor.GetDistanceTo(target, true) >= rangeMin)))
&& (rangeMin == 0f || aggressor.GetDistanceTo(target, true) >= rangeMin))
targets.Add(target);
}

Expand All @@ -45,17 +74,17 @@ public static int GetNumTargetsInRange(Agent aggressor, float rangeMax, float ra
if (aggressor == null) return numTargets;
if (aggressor.Region == null)
{
Logger.Warn($"Agent not in region when trying to count targets in range! Agent: {aggressor}");
Logger.Warn($"GetNumTargetsInRange(): Agent not in region when trying to count targets in range! Agent: {aggressor}");
return numTargets;
}
Sphere volume = new (aggressor.RegionLocation.Position, rangeMax + aggressor.Bounds.GetRadius());

Sphere volume = new(aggressor.RegionLocation.Position, rangeMax + aggressor.Bounds.GetRadius());
foreach (WorldEntity target in aggressor.Region.IterateEntitiesInVolume(volume, new(EntityRegionSPContextFlags.ActivePartition)))
{
if (target == null) continue;
if (ValidTarget(aggressor.Game, aggressor, target, targetType, false, flags)
&& (attributes == null || PassesAttributesCheck(aggressor, target, attributes))
&& (rangeMin == 0.0f || (aggressor.GetDistanceTo(target, true) >= rangeMin)))
&& (attributes == null || PassesAttributesCheck(aggressor, target, attributes))
&& (rangeMin == 0.0f || aggressor.GetDistanceTo(target, true) >= rangeMin))
numTargets++;
}

Expand All @@ -70,7 +99,7 @@ private static bool PassesAttributesCheck(Agent aggressor, WorldEntity target, A
return true;
}

public static bool ValidTarget(Game game, Agent aggressor, WorldEntity target, CombatTargetType targetType, bool inTarget,
public static bool ValidTarget(Game game, Agent aggressor, WorldEntity target, CombatTargetType targetType, bool inTarget,
CombatTargetFlags flags = CombatTargetFlags.None, AlliancePrototype allianceOverride = null, float aggroRangeOverride = 0.0f)
{
if (game == null || aggressor == null || target == null || aggressor == target) return false;
Expand Down Expand Up @@ -115,20 +144,20 @@ public static bool ValidTarget(Game game, Agent aggressor, WorldEntity target, C
{
case CombatTargetType.Hostile:
if (aggressor.IsHostileTo(target, allianceProto) == false) return false;
aggroRange = (aggroRangeOverride > 0.0f) ? aggroRangeOverride : aggressorsController.AggroRangeHostile;
aggroRange = aggroRangeOverride > 0.0f ? aggroRangeOverride : aggressorsController.AggroRangeHostile;
break;
case CombatTargetType.Ally:
if (aggressor.IsFriendlyTo(target, allianceProto) == false) return false;
aggroRange = (aggroRangeOverride > 0.0f) ? aggroRangeOverride : aggressorsController.AggroRangeHostile;
aggroRange = aggroRangeOverride > 0.0f ? aggroRangeOverride : aggressorsController.AggroRangeHostile;
break;
default:
Logger.Warn("Invalid combat target type.");
Logger.Warn("ValidTarget(): Invalid combat target type.");
break;
}
}

if (inTarget)
{
if (inTarget)
{
BehaviorBlackboard aggressorBlackboard = aggressorsController.Blackboard;
if (flags.HasFlag(CombatTargetFlags.IgnoreAggroDropRange) == false)
if (CheckAggroDistance(aggressor, target, aggressorBlackboard.PropertyCollection[PropertyEnum.AIAggroDropRange]) == false)
Expand Down Expand Up @@ -158,7 +187,7 @@ private static bool CheckAggroDistance(Agent aggressor, WorldEntity target, floa
if (distance > 0.0)
{
float distanceSq = distance * distance;
if (distanceSq < Vector3.DistanceSquared2D(aggressor.RegionLocation.Position, target.RegionLocation.Position))
if (distanceSq < Vector3.DistanceSquared2D(aggressor.RegionLocation.Position, target.RegionLocation.Position))
return false;
}
return true;
Expand All @@ -173,12 +202,12 @@ public static ulong GetClosestValidHostileTarget(Agent aggressor, float aggroRan
var aggressorPosition = aggressor.RegionLocation.Position;
float closestDistanceSq = float.MaxValue;
ulong closestTargetId = 0;
Sphere volume = new (aggressorPosition, aggroRange);
foreach (var target in region.IterateEntitiesInVolume(volume, new (EntityRegionSPContextFlags.ActivePartition)))
Sphere volume = new(aggressorPosition, aggroRange);
foreach (var target in region.IterateEntitiesInVolume(volume, new(EntityRegionSPContextFlags.ActivePartition)))
{
if (target == null) continue;
if (ValidTarget(aggressor.Game, aggressor, target, CombatTargetType.Hostile, false))
{
{
var distanceSq = Vector3.DistanceSquared(aggressorPosition, target.RegionLocation.Position);
if (distanceSq < closestDistanceSq)
{
Expand All @@ -190,7 +219,7 @@ public static ulong GetClosestValidHostileTarget(Agent aggressor, float aggroRan
return closestTargetId;
}

public static bool GetValidTargetsInSphere(Agent aggressor, float aggroRange, List<ulong> targets, CombatTargetType targetType,
public static bool GetValidTargetsInSphere(Agent aggressor, float aggroRange, List<ulong> targets, CombatTargetType targetType,
in SelectEntity.SelectEntityContext selectionContext, ref WorldEntity bestTargetSoFar, ref float bestValue, CombatTargetFlags flags)
{
if (aggressor == null || aggroRange <= 0.0f) return false;
Expand All @@ -199,13 +228,13 @@ public static bool GetValidTargetsInSphere(Agent aggressor, float aggroRange, Li
Game game = aggressor.Game;
if (game == null) return false;

Sphere volume = new (aggressor.RegionLocation.Position, aggroRange);
foreach (WorldEntity worldEntity in region.IterateEntitiesInVolume(volume, new (EntityRegionSPContextFlags.ActivePartition)))
Sphere volume = new(aggressor.RegionLocation.Position, aggroRange);
foreach (WorldEntity worldEntity in region.IterateEntitiesInVolume(volume, new(EntityRegionSPContextFlags.ActivePartition)))
{
if (worldEntity == null) continue;
if (ValidTarget(game, aggressor, worldEntity, targetType, false, flags, null, aggroRange))
{
targets.Add(worldEntity.Id);
targets.Add(worldEntity.Id);
if (SelectEntity.EntityMatchesSelectionCriteria(selectionContext, worldEntity, ref bestTargetSoFar, ref bestValue))
break;
}
Expand All @@ -214,28 +243,4 @@ public static bool GetValidTargetsInSphere(Agent aggressor, float aggroRange, Li
return targets.Count > 0;
}
}

[Flags]
public enum CombatTargetFlags
{
None = 0,
Flag0 = 1 << 0,
CheckInvulnerable = 1 << 1,
CheckAgent = 1 << 2,
CheckItem = 1 << 3,
IgnoreAggroDistance = 1 << 4,
IgnoreAggroDropRange = 1 << 5,
IgnoreAggroLOSChance = 1 << 6,
IgnoreStealth = 1 << 7,
IgnoreDead = 1 << 8,
IgnoreHostile = 1 << 9,
IgnoreLOS = 1 << 10,
IgnoreTargetable = 1 << 11,
}

public enum CombatTargetType
{
Hostile,
Ally
}
}
Loading

0 comments on commit fd2934d

Please sign in to comment.