Skip to content

refactor(items): the original items' tooltip texts come from their data - #816

Merged
Mosch0512 merged 20 commits into
sven-n:mainfrom
ezequielzacca:feat/item-tooltip-texts-to-data
Oct 23, 2026
Merged

Mosch0512 merged 20 commits into
sven-n:mainfrom
ezequielzacca:feat/item-tooltip-texts-to-data

Conversation

@ezequielzacca

@ezequielzacca ezequielzacca commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

This step's own changes: compare with #813. The diff of this PR also holds every earlier step of #815, since a PR from a fork can only target this repository's branches.

Summary

Step 2 of 6 of #815 (data-driven item tooltips). Stacked on #813: the first commits here are #813's. Only the last commit, refactor(items): the original items' tooltip texts come from their data, is this step, and this PR will be rebased once #813 merges.

The fixed texts the tooltip code wrote for 15 original items, one if (ip->Type == …) case each in RenderItemInfo(), are now these items' descriptions in the item data:

Item Text
Jewel of Chaos (12,15) It is used to combine Chaos items
Moonstone Pendant (13,38) I.D. of Kantur Chief Scientist. You can enter the Refinery Tower.
Jewel of Bless (14,13) It is used to increase your item level up to 6
Jewel of Soul (14,14) It is used to increase your item level up to 7,8,9
Jewel of Life (14,16) Increases item option by 1 level
Devil's Eye, Devil's Key (14,17), (14,18) It is used to combine items for a Devil Square Invitation
Jewel of Creation (14,22) Used to create fruits that increase stats
Jewel of Guardian (14,31) Create and improve items for siege
Gemstone (14,41) Jewel with impurities
Jewel of Harmony (14,42), Jewel of Elevation (14,161) Jewel for item reinforcement
Lower and Higher refining stone (14,43), (14,44) Grant actual power to reinforced item.
Jewel of Extension (14,160) Jewel used for repairing a Lucky Item.
  • Translations: each text keeps all 11 UI languages, taken from Game.<lang>.resx, written like item names (English first).
  • Removed:
    • the 14 cases in ZzzInventory.cpp;
    • the 12 .resx entries, in every language. Nothing else reads them: no accessor use is left, and no I18N::Game::Lookup() range reaches their legacy ids (572–574, 619, 621, 637, 1289, 2207–2210, 3305; an unknown id gives Lookup's fallback).
  • Stays code for now: the lines the tooltip computes from the item (the wings' damage and absorption, the Guardian Angel, the Imp, the Town Portal scroll's delay). They need placeholders and ItemStats.json values, steps 3 and 4 of [Architecture] Data-driven item tooltips: texts, placeholders and values from the item data (phase 8) #815.
  • Test: "The original items' tooltip texts are in their descriptions" checks that each of the 15 items has its text as its description, white, translated in every UI language.

What changes in game

The tooltips look as before, in both themes, with one difference: a description line wraps at the tooltip's width (#813). So a text wider than that now breaks onto a second line instead of making the box wider.

  • English: only the Moonstone Pendant's line wraps ("…You can enter the / Refinery Tower.").
  • Translations: longer texts wrap too. That fixes a bug: the tooltip's lines hold 100 characters, so the Russian Moonstone text (107) made the box run off the screen and ran into the next line ("…нефтеперерабатывающего Прочность: [1/120]"). It now reads as three lines inside the box.

Screenshots

Jewel of Bless: the same before and after.

Legacy theme Modern theme
Before
After
The item data of the "after" images (14,13)

src/bin/Data/Items/Group14_Potion.json:

{
  "number": 13,
  "name": {
    "en": "Jewel of Bless",
    "de": "Juwel des Segens",
    "es": "Joya de Bendición",
    "pt": "Joia da bênção"
  },
  "tags": ["jewel", "valuable"],
  "description": [
    {
      "text": {
        "en": "It is used to increase your item level up to 6",
        "de": "Wird verwendet, um das Gegenstandslevel auf bis zu 6 zu erhöhen",
        "es": "Se utiliza para aumentar el nivel de tu objeto hasta 6.",
        "id": "Ini digunakan untuk meningkatkan level item Anda hingga 6",
        "ja": "アイテムレベル6にUP時に使用",
        "pl": "Służy do podniesienia poziomu przedmiotu do 6",
        "pt": "É usado para aumentar o nível do seu item até 6",
        "ru": "Используется для повышения уровня вашего предмета до 6.",
        "tl": "Ginagamit ito upang taasan ang antas ng iyong item hanggang 6",
        "uk": "Він використовується для підвищення рівня вашого предмета до 6",
        "zh-TW": "它用於將您的物品等級提高到 6"
      }
    }
  ]
  …
}

Moonstone Pendant, English: the line wraps.

Legacy theme Modern theme
Before
After
The item data of the "after" images (13,38)

src/bin/Data/Items/Group13_Helper.json:

{
  "number": 38,
  "name": {
    "en": "Moonstone Pendant",
    "de": "Mondsteinanhänger",
    "es": "Pendiente de Piedra Lunar",
    "pt": "Pingente da pedra da lua"
  },
  "description": [
    {
      "text": {
        "en": "I.D. of Kantur Chief Scientist. You can enter the Refinery Tower.",
        "de": "Ausweis des Chefwissenschaftlers von Kantur. Sie können den Raffinerieturm betreten.",
        "es": "IDENTIFICACIÓN. del científico jefe de Kantur. Puedes ingresar a la Torre de la Refinería.",
        "id": "PENGENAL. dari Kepala Ilmuwan Kantur. Anda bisa memasuki Menara Kilang.",
        "ja": "カントルの首席研究員たちの入出許可証。精製の塔へ入ることが出来ます。",
        "pl": "ID. głównego naukowca Kantur. Możesz wejść do Refinery Tower.",
        "pt": "EU IA. do Cientista Chefe Kantur. Você pode entrar na Torre da Refinaria.",
        "ru": "ИДЕНТИФИКАТОР. главного научного сотрудника Кантура. Вы можете войти в Башню нефтеперерабатывающего завода.",
        "tl": "I.D. ng Kantur Chief Scientist. Maaari kang pumasok sa Refinery Tower.",
        "uk": "І.Д. головного наукового співробітника Кантур. Ви можете увійти до вежі нафтопереробного заводу.",
        "zh-TW": "ID。坎圖爾首席科學家。您可以進入煉油塔。"
      }
    }
  ]
  …
}

Moonstone Pendant, Russian: before, the box runs off the screen and the text runs into the durability line; after, it wraps inside the box.

Legacy theme Modern theme
Before
After
The item data of the "after" images (13,38)

src/bin/Data/Items/Group13_Helper.json:

{
  "number": 38,
  "name": {
    "en": "Moonstone Pendant",
    "de": "Mondsteinanhänger",
    "es": "Pendiente de Piedra Lunar",
    "pt": "Pingente da pedra da lua"
  },
  "description": [
    {
      "text": {
        "en": "I.D. of Kantur Chief Scientist. You can enter the Refinery Tower.",
        "de": "Ausweis des Chefwissenschaftlers von Kantur. Sie können den Raffinerieturm betreten.",
        "es": "IDENTIFICACIÓN. del científico jefe de Kantur. Puedes ingresar a la Torre de la Refinería.",
        "id": "PENGENAL. dari Kepala Ilmuwan Kantur. Anda bisa memasuki Menara Kilang.",
        "ja": "カントルの首席研究員たちの入出許可証。精製の塔へ入ることが出来ます。",
        "pl": "ID. głównego naukowca Kantur. Możesz wejść do Refinery Tower.",
        "pt": "EU IA. do Cientista Chefe Kantur. Você pode entrar na Torre da Refinaria.",
        "ru": "ИДЕНТИФИКАТОР. главного научного сотрудника Кантура. Вы можете войти в Башню нефтеперерабатывающего завода.",
        "tl": "I.D. ng Kantur Chief Scientist. Maaari kang pumasok sa Refinery Tower.",
        "uk": "І.Д. головного наукового співробітника Кантур. Ви можете увійти до вежі нафтопереробного заводу.",
        "zh-TW": "ID。坎圖爾首席科學家。您可以進入煉油塔。"
      }
    }
  ]
  …
}

The Jewel of Soul and the Gemstone were checked the same way and are unchanged in English.

Related issues

Step 2 of #815. Builds on #813 (step 1).

Checklist

  • I have read and followed docs/CODING_RULES.md.
  • I have built the project locally (see docs/build/README.md). Windows x64 Release; all 978 tests pass, including the new The original items' tooltip texts are in their descriptions. Changed lines pass clang-format 21.1.8 as CI checks them. In game (Release x64 against a local OpenMU), the tooltips of the Jewel of Bless, Jewel of Soul, Gemstone and Moonstone Pendant were compared before and after in both themes, and the Moonstone Pendant also in Russian.
  • Changes are focused on one concern; the diff is as small as it reasonably can be.

A "description" list in the item data: lines the tooltip shows for an
item after its own, each with a text written like the item's name
(plain English, or texts by language; "" is a blank line) and an
optional tooltip color by name. Read, written (left out when empty),
kept by the bmd import, and checked: a line longer than the tooltip's
99 characters gets a warning. The tooltip draws them in the UI's
language.

So a new item's text is data instead of another case in the tooltip
code. No shipped item has one yet; the original items keep their texts
in the tooltip code.
A description line longer than the tooltip's widest lines wraps there,
measured with the tooltip's font, and a "\n" in a text breaks the line,
so long texts need neither hand-split lines nor the 99-character limit
and its warning, which go. Each piece keeps the line's color.
The fixed texts the tooltip code wrote for 15 items, one case each, are
their item data's descriptions now: the jewels (Bless, Soul, Life, Chaos,
Creation, Guardian, Harmony, Extension, Elevation), Gemstone, the
refining stones, Devil's Eye and Key, and the Moonstone Pendant. Each
text keeps all 11 UI languages, taken from Game.<lang>.resx; the 12
entries leave the resx files, since nothing else reads them (no
accessor use, and no Lookup() range reaches their legacy ids).

The lines the tooltip code computes from the item (wings, Guardian
Angel, Imp, Town Portal scroll) stay code for now.

A test checks that each of the 15 items has its text as its description,
in every UI language.
@Mosch0512 Mosch0512 self-assigned this Oct 21, 2026
…iptions

# Conflicts:
#	src/source/Data/GameData/ItemData/ItemEnumNames.cpp
#	src/source/Data/GameData/ItemData/ItemEnumNames.h
…tip-texts-to-data

# Conflicts:
#	src/Localization/Game.pl.resx
It measured the whole line after every letter. A tooltip is built every frame while an item is hovered, and through
the SDL_ttf renderer each measured prefix is a new text for the shared text cache, which empties itself when full.
Now a line is measured when a word ends, and letter by letter only inside a word wider than a whole line. Compared
with the old version on 200,000 random texts: the same lines, except where the old one left a line wider than the
limit (a word too wide for a line, after a break), and about half the measure calls.
…ike names

Review of sven-n#813:
- A blank line inside a description text ("a\n\nb", or a leading "\n") wrote an empty row, and an empty row ends the
  tooltip in both renderers and in the height count: the rest of the tooltip was gone. A blank piece is now the
  tooltip's own blank row, "\n", as a blank line is.
- The description stopped at TextList's end, but the rows after it are written unchecked, so a long description
  wrote past the array. TextList, TextListColor, TextBold and Size have 32 rows more than the original client's 50,
  and the description writes at most those 32: it never takes the room the rest of the tooltip needs. The files that
  declared the arrays themselves with 50 rows use ZzzInventory.h's declarations now.
- The block is WriteItemDescriptionLines (rule 1), with the measure passed in, so a test can check its rows; the wrap
  width moved from the item data header to it, and the row width comes from TextList.
- Description texts get the checks names get: the English text is required, a language code has only letters,
  digits and "-", and a language the game has no texts in is a warning.
- The color names are in the anonymous namespace with the other tables, and a color without a name fails to compile.
… texts in the items design

Review of sven-n#813: the description comes after the damage, defense and speed lines and before durability, the
requirements and the options; the Dark Horse and Dark Raven show it only in shops. The items design records the
split this step makes: an item's own tooltip texts are client-only fields of its item file (D15, D22, the field
table), which the exchange file of phase 7 leaves out, and phase 8 goes in the steps of sven-n#815.
…tip-texts-to-data

# Conflicts:
#	docs/item-data.md
…s stay English

sven-n#843 makes the item database's display locale the item names' language, which is English when "Translate item
names" is off. The description read its texts in that locale, so the whole description turned English with the
names. It is read in the UI's language now: only the names follow the option.
…tip-texts-to-data

# Conflicts:
#	docs/item-data.md

@Mosch0512 Mosch0512 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verdict: ready to merge once #813 lands. Everything below is non-blocking. I reviewed this step's own changes, against #813's branch. The move is exact:

  • The texts: I compared every moved text (15 items × 11 languages) with the deleted .resx entries by script. All 165 match, with no % escapes or special characters lost. No other item got a description, and no other item field changed.
  • Nothing else reads the removed texts:
    • no accessor use is left, and no other file names them;
    • no data file points at their ids, including the recipe texts in mix.bmd, which I decoded;
    • no computed id reaches them; for example, the Kanturu event's 2170 + result stops at 2177.
  • Mapping and order: each removed case maps to the item number its data now uses, ITEM_POTION + 160/161 included. The texts sit where the code wrote them.

Non-blocking

  • The test checks the English text, and that each language has some text, but not the translations themselves. With the .resx entries deleted here, a copy mistake couldn't be caught later (inline, test_item_database_files.cpp:235).
  • Some moved texts carry machine-translation errors, for example the Portuguese Moonstone text's "EU IA." (inline, Group13_Helper.json:991).
  • Three texts are written out twice, each with all 11 languages, until the shared texts of #827 (inline, Group14_Potion.json:2563).
  • The test re-implements the file's FindItem helper (inline, test_item_database_files.cpp:264).
  • The description row of the fields table is now one cell of about 1,700 characters (inline, item-data.md:114).

Note: the wrap fix I pushed to #813 (b9a7430) isn't in this branch yet. It comes in with your next merge of #813's branch.

What I checked: I read this step's diff, the tooltip code around the removed cases, and every I18N::Game::Lookup() call. I compared the item data with the deleted .resx entries in all 11 languages. I didn't build the client or run the game. CI: the Linux and macOS builds and Quality Gates pass.

}

// The texts the tooltip code wrote for these items are their descriptions now, in every UI language.
TEST_CASE("The original items' tooltip texts are in their descriptions [data][items]")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Non-blocking. This checks each item's English text, and that every UI language has some text. It doesn't check that the translations are the ones the deleted .resx entries had. Since this PR deletes those entries, nothing in the repo can catch a copy mistake later, for example the two refining stones' German texts swapped. The roadmap's D26 and section 4 of the items design ask that a move from code into data is compared with the old code.

I compared all 15 items × 11 languages with the deleted entries by script, and they match exactly, so nothing is wrong today. Saying in the description how the texts were checked against the .resx files would leave a record, since the comparison can't be repeated after this PR.

Comment thread src/bin/Data/Items/Group13_Helper.json
Comment thread src/bin/Data/Items/Group14_Potion.json
Comment thread tests/data/test_item_database_files.cpp Outdated
Comment thread docs/item-data.md Outdated
The description's row in the fields table had grown to one cell of about
1,700 characters. The row now says what the field is and links to a
Descriptions section, which has the line format, an example and what the
tooltip does with the lines.
@Mosch0512

Copy link
Copy Markdown
Collaborator

I pushed two small commits for two of the review's points to this branch, so please pull before your next push:

  • ead9815: the tooltip text test finds its items with the file's FindItem.
  • 2f5017a: docs/item-data.md gets a Descriptions section. The description row of the fields table now only says what the field is and links to it. The section has the line format, an example, and what the tooltip does with the lines, with nothing left out.

The later steps of the stack change that description row, so merging this branch into them will conflict there. Their additions (placeholders, shared texts, conditions, …) now go into the Descriptions section instead, and the row stays short.

@Mosch0512
Mosch0512 merged commit e409798 into sven-n:main Oct 23, 2026
7 checks passed
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.

2 participants