Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/GameLogic/PlayerActions/Skills/AreaSkillAttackAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ private async ValueTask PerformAutomaticHitsAsync(Player player, ushort extraTar
return;
}

// Skills that move attacker to target (e.g., Twisting Slash, Death Stab) require a weapon
if (skill.MovesToTarget && player.Inventory?.GetRandomOffensiveItem() is null)
{
return;
}
Comment on lines +172 to +175

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current check using player.Inventory?.GetRandomOffensiveItem() is null is not sufficient to prevent casting weapon-based skills without a weapon. The GetRandomOffensiveItem method can return a pendant, which would allow the check to pass even if no weapon is equipped. This would allow the exploit to persist for players who have a pendant but no weapon.

The check should be more specific to only consider items in weapon slots that are actual weapons (not shields or ammunition).

You might need to add using MUnique.OpenMU.DataModel.Entities; for the Item type if it's not already available in the file's scope.

        if (skill.MovesToTarget)
        {
            var inventory = player.Inventory;
            var left = inventory?.GetItem(InventoryConstants.LeftHandSlot);
            var right = inventory?.GetItem(InventoryConstants.RightHandSlot);

            static bool IsWeapon(Item? item)
            {
                // A weapon is an item in a hand slot which is not a shield or ammunition.
                const byte ShieldItemGroup = 6;
                return item?.Definition is not null && !item.Definition.IsAmmunition && item.Definition.Group != ShieldItemGroup;
            }

            if (!IsWeapon(left) && !IsWeapon(right))
            {
                return;
            }
        }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a more simple fix: Each weapon adds 1 to the Stats.EquippedWeaponCount, so just check if it's greater than 0, and it should work.

        if (skill.MovesToTarget && player.Attributes[Stats.EquippedWeaponCount] > 0)


if (player.Attributes[Stats.AmmunitionConsumptionRate] > player.Attributes[Stats.AmmunitionAmount])
{
return;
Expand Down
1 change: 1 addition & 0 deletions src/Web/AdminPanel/Pages/EditConfigGrid.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ private async Task OnCreateButtonClickAsync()
var modalType = typeof(ModalCreateNew<>).MakeGenericType(this.Type!);

parameters.Add(nameof(ModalCreateNew<object>.Item), newObject);
parameters.Add(nameof(ModalCreateNew<object>.PersistenceContext), creationContext);
var options = new ModalOptions
{
DisableBackgroundCancel = true,
Expand Down