Skip to content

feat(items): use figurines and charms inside the inventory - #1470

Open
icheat2win wants to merge 1 commit into
MUnique:masterfrom
icheat2win:feat/inventory-charms
Open

icheat2win wants to merge 1 commit into
MUnique:masterfrom
icheat2win:feat/inventory-charms

Conversation

@icheat2win

Copy link
Copy Markdown
Contributor

Adds the Hawk and Goat Figurines and the (Golden) Oak and Maple Charms (13/128-133) of issue #1339. A right click inside the inventory (BF 20) puts them in use, which is stored in the durability like in the original game (254 in use, 255 not in use). While in use, their power-ups apply. Only one item of the same kind can be in use, and the use ends when the item leaves the inventory.

The Worn Horseshoe (13/134) is left out, because there's no attribute for the item drop rate yet.

Claude-Session: https://claude.ai/code/session_011xNc75fJTee8EPxDxQxuGi

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-14T18:39:01.222758Z f9cd937 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@codacy-production

codacy-production Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 83 complexity · 18 duplication

Metric Results
Complexity 83
Duplication 18

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 79006ad10a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}

item.Height = height;
item.Durability = 255;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Exclude inventory-use items from quantity and stack handling

For a single charm created through the GM item command or a permanent shop product, these slot-less definitions are classified as stackable by DataModel.ItemExtensions.IsStackable() because their definition durability is 255. GameMasterItemFactory.CreateItem and InventoryProductDelivery.CreateItems therefore initialize the item's durability to 1, which SetItemInUseAsync rejects because it only accepts 254/255. The same classification also lets stack moves modify these state bytes as quantities without updating the bonuses. Exclude inventory-use items from quantity/stack handling and initialize their instances to the inactive state.

Useful? React with 👍 / 👎.

Comment on lines +173 to +176
if (fromItemStorage == player.Inventory && toItemStorage != player.Inventory && item.IsInUseInsideInventory())
{
// An item which is used inside the inventory, like a charm, is only used while it stays in the inventory.
item.Durability = InventoryUsedItemExtensions.NotInUseDurability;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reset the inventory-use state when dropping an active item

If an active charm is dropped, DropItemAction removes it through InventoryStorage.RemoveItemAsync without reaching this reset, so its durability stays 254. A player can activate one copy, drop it, activate another copy of the same kind, and pick up the first: InventoryStorage.AddItemAsync reinstates its power-ups without the duplicate check from SetItemInUseAsync. Both copies then grant their bonuses, and the sequence can be repeated. Clear the use state on real inventory exits such as drops, not only on storage moves.

Useful? React with 👍 / 👎.

/// <inheritdoc />
protected override ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration)
{
new CashShopItems(context, gameConfiguration).CreateFigurinesAndCharms();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reconnect existing shop products to the new item definitions

On an existing Season 6 database with the client-script shop catalog, product sequences 459–462 were initialized with null ItemDefinition references because these items did not exist. This update creates the definitions but never reconnects those products, whereas fresh initialization does. CashShopProductDelivery.GetDelivery consequently continues rejecting them even if the operator enables permanent variants. Rule 4 of docs/CODING_RULES.md requires upgrades to “ensure the final state”; relink the known null catalog references idempotently and cover that pre-upgrade state in the repair test.

AGENTS.md reference: AGENTS.md:L16-L17

Useful? React with 👍 / 👎.

Comment on lines +35 to +36
return item.Definition is { } definition
&& ItemConstants.ItemsUsedInsideInventory.Any(id => id.Group == definition.Group && id.Number == definition.Number);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Drive inventory-use eligibility from configuration

This helper decides inventory-use behavior solely from the fixed group/number list in ItemConstants, without an item-configuration or feature-configuration option. Rule 3 of docs/CODING_RULES.md forbids these configuration decisions in generic GameLogic and explicitly states that “Being hard-coded in the game client is not an exemption,” so the client-based justification on the new constants does not satisfy the rule. Represent eligibility in item configuration or a configurable feature plugin and have the shared logic read it instead of baking 13/128–134 into the behavior.

AGENTS.md reference: AGENTS.md:L16-L17

Useful? React with 👍 / 👎.

Comment thread src/GameLogic/InventoryStorage.cs Outdated
else if (item.IsUsedInsideInventory())
{
// An item which is used inside the inventory loses its power-ups, until it's added again.
this._player.Attributes?.RemoveInventoryUsedItemPowerUps(item);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve charm power-ups during inventory-only moves

With an active Oak Charm and current health above the unbuffed maximum, rearranging the charm within the inventory calls RemoveItemAsync, which disposes its power-up before AddItemAsync reinstalls it. Player.OnAttributeValueChanged immediately clamps current health to the temporarily lowered maximum, so moving the charm permanently loses health even though its use state never changes. The corresponding mana, shield, and ability bonuses have the same problem. Preserve the power-ups during inventory-only moves, or otherwise avoid publishing the intermediate lower maximum.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 27f7dfd029

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +225 to +228
if (item == this._itemMovedInsideInventory
|| !item.IsUsedInsideInventory(this._gameContext))
{
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Remove applied bonuses even after the feature is disabled

If an operator disables the feature or removes an item from its configuration while a player has an active charm, the live plugin configuration makes IsUsedInsideInventory return false. This guard then skips cleanup when the player drops or vaults that charm, leaving its power-ups in ItemPowerUps and granting the bonus after the item has left the inventory. Remove already-applied power-ups independently of current eligibility, and reset the item's use state on actual inventory exits.

Useful? React with 👍 / 👎.

}
else
{
this.OnItemAddedToInventory(convertedItem ?? item);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Synchronize temporary pickups with the normalized use state

When a player picks up a GM-created charm, GameMasterItemFactory supplies a TemporaryItem with durability 1. This new call normalizes only its persistent copy to 255. DroppedItem.TryPickUpAsync copies only the slot back to the temporary item, and PickupItemAction.PickupItemAsync passes that original object to IItemAppearPlugIn, so the item-added packet contains durability 1 while the server's inventory contains 255. Normalize the source too, or serialize the inserted persistent item, so the pickup response carries the actual inventory-use state.

Useful? React with 👍 / 👎.

Comment on lines +49 to +50
item.Durability = requestedDurability;
attributes.UpdateInventoryUsedItemPowerUps(item, player.GameContext);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Skip power-up rebuilds for unchanged inventory-use requests

If an already-active Oak Charm receives another valid activation request with durability 254, this unconditionally rebuilds its power-ups even though its state has not changed. UpdateInventoryUsedItemPowerUps disposes the existing bonus first, and Player.OnAttributeValueChanged immediately clamps current health to the temporarily lowered maximum before the bonus is restored. A repeated state-setting request therefore loses health when it exceeds the unbuffed maximum; the mana, shield, and ability bonuses have the same problem. Acknowledge unchanged requests without removing and recreating their power-ups.

Useful? React with 👍 / 👎.

@ze-dom

ze-dom commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

I think some of the values are not correct (https://muonlinefanz.com/guide/systems/cash-item-shop/#talisman). I will check it out more thoroughly and come back.

@ze-dom

ze-dom commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Shots taken with S6E3 client.

Hawk and Goat figurines/status add to Critical Damage and Excelent Damage chance, not bonus (tooltip incorrect/incomplete):
emu: 1, 2, 3 | MU online Fanz
They also can't be used at the same time.

Screenshot from 2026-11-12 16-13-51 Screenshot from 2026-11-12 16-13-57

Oak Charm is correct. Golden Oak Charm adds 100 HP and 500 SD.
They also can't be used at the same time.

Screenshot from 2026-11-12 16-14-02 Screenshot from 2026-11-12 16-14-10

Maple Charm and Golden Maple Charm have no rendering. Maybe they were never released or later? MU Fanz don't have them listed either. But the values are correct.
They also (probably) can't be used at the same time.

Screenshot from 2026-11-12 16-14-34 Screenshot from 2026-11-12 16-14-41

@sven-n sven-n left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This PR conflicts with current master, so I can't merge it. Please rebase it onto master. These files conflict:

  • src/GameLogic/Properties/PlugInResources.Designer.cs
  • src/GameLogic/Properties/PlugInResources.resx
  • src/Persistence/Initialization/Properties/ItemNames.Designer.cs
  • src/Persistence/Initialization/Properties/ItemNames.de.resx
  • src/Persistence/Initialization/Properties/ItemNames.resx
  • src/Persistence/Initialization/Properties/ItemNames.zh-CN.resx
  • src/Persistence/Initialization/Properties/PlugInResources.Designer.cs
  • src/Persistence/Initialization/Properties/PlugInResources.de.resx
  • src/Persistence/Initialization/Properties/PlugInResources.resx
  • src/Persistence/Initialization/Properties/PlugInResources.zh-CN.resx
  • tests/MUnique.OpenMU.Persistence.Initialization.Tests/ItemStatProfilesDataTest.cs

Most of them are resource files (.resx / .Designer.cs) which other merged PRs also extended. When you resolve them, keep the entries of both sides, and regenerate the designer file instead of merging it by hand. I'll review it in full once it's rebased.


Generated by Claude Code

@icheat2win
icheat2win force-pushed the feat/inventory-charms branch from 27f7dfd to 807ef82 Compare November 14, 2026 15:53

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 807ef8278c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +46 to +49
public override string Name => PlugInName;

/// <inheritdoc />
public override string Description => PlugInDescription;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Localize the update's exposed name and description

In a German or Chinese admin-panel session, the configuration-updates page still displays this update in English: Updates.UpdateViewModel reads IConfigurationUpdatePlugIn.Name and Description directly, not the localized [Display] metadata. These overrides return English constants instead of the translated resource entries added by this commit. Rule 10, “No user-facing literals,” in docs/CODING_RULES.md requires localized plugin and admin-panel text; return the corresponding resource properties here as well.

AGENTS.md reference: AGENTS.md:L16-L17

Useful? React with 👍 / 👎.

@sven-n sven-n left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the rebase. Using the items inside the inventory looks well thought out: the state lives in the durability (254/255), only one item of a kind is in use, and the use ends when the item leaves the inventory but not when it moves within it.

Unfortunately, #1504 was merged in the meantime and regenerated GameLogic/Properties/PlugInResources.Designer.cs, so this PR conflicts again (GameLogic/Properties/PlugInResources.*, PlayerMessage.*, GameServer/Properties/PlugInResources.*). Please rebase once more: keep the entries of both sides in the .resx files, then regenerate the designers.

While you're at it: the description says the Worn Horseshoe (13/134) is left out because there's no attribute for the item drop rate yet. #1459 is merged now and added Stats.BonusItemDropRate, so the horseshoe could be added, either here or in a follow-up.

(Your item PRs #1458, #1461, #1464, #1470 and #1471 all add to the same resource files, so each merge makes the others conflict again. I'll take whichever is ready first.)


Generated by Claude Code

Adds the Hawk and Goat Figurines and the (Golden) Oak and Maple Charms
(13/128-133) of issue MUnique#1339. A right click inside the inventory (BF 20)
puts them in use, which is stored in the durability like in the original
game (254 in use, 255 not in use). While in use, their power-ups apply.
Only one item of the same kind can be in use, and the use ends when the
item leaves the inventory.

The Worn Horseshoe (13/134) is left out, because there's no attribute for
the item drop rate yet.

Rebased onto master: this is the change of the earlier commits in one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xNc76CH3CGWUp5r4XmXWK
@icheat2win
icheat2win force-pushed the feat/inventory-charms branch from 807ef82 to f9cd937 Compare November 14, 2026 18:31
@ze-dom

ze-dom commented Nov 14, 2026

Copy link
Copy Markdown
Contributor

@sven-n , check my comment below

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants