Skip to content

feat(items): item descriptions in the item data - #813

Merged
Mosch0512 merged 13 commits into
sven-n:mainfrom
ezequielzacca:feat/item-descriptions
Oct 23, 2026
Merged

Mosch0512 merged 13 commits into
sven-n:mainfrom
ezequielzacca:feat/item-descriptions

Conversation

@ezequielzacca

@ezequielzacca ezequielzacca commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Step 1 of 6 of #815 (data-driven item tooltips, phase 8 of the data-driven items design). This step only adds the format and draws it; the next steps move the original items' texts into the data, add named placeholders filled from the item and its stats, and finally build the whole tooltip from data.

Adds an optional description list to the item data (src/bin/Data/Items/Group*.json): lines the item tooltip shows after the item's stats. Today every item text is a case in the tooltip code (ZzzInventory.cpp); with this, a new item brings its text as data.

For example, the Jewel of Bless's line ("It is used to increase your item level up to 6", today a case in the tooltip code) would read in its item data:

"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.",
      "pt": "É usado para aumentar o nível do seu item até 6"
    }
  }
]
  • text is written like name: a plain English text or the texts by language; an empty text ({"text": ""}) is a blank line.
  • color is one of the tooltip colors by name (blue, yellow, red, …); white when left out.
  • A long line wraps at about the width of the original tooltips' widest lines (measured with the tooltip's font), and in a text breaks the line there; each piece keeps the line's color.
  • Read and written by the item JSON (left out when empty), kept by the bmd import, documented in docs/item-data.md.
  • The tooltip draws the lines in the UI's language.

No shipped item uses it yet, and the original items keep their texts in the tooltip code, so nothing changes in game.

Screenshots

The Jewel of Bless's tooltip in the client built from main and from this branch, in both UI themes.

main

Legacy theme Modern theme

This branch, no item data changed: the same tooltip.

Legacy theme Modern theme

This branch, with an example description (only in the screenshot's local item data, not in this PR): a blank line, a blue line that wraps to the tooltip's width, and a yellow line with a \n. The jewel's own line is still written by the tooltip code, after the description: the original items keep their texts in code for now, and moving them into the item data is step 2 of #815.

"description": [
  {"text": ""},
  {"text": "Drop it on an item in your inventory to raise the item's level by one, from +0 up to +6. The jewel is used up.", "color": "blue"},
  {"text": "A line break in the text\nstarts a new line", "color": "yellow"}
]
Legacy theme Modern theme

Related issues

Step 1 of #815. Part of phase 8 (data-driven tooltips, D15) of the data-driven items design (#628).

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 977 tests pass, including the new An item's description is kept through write and read. Changed lines pass clang-format 21.1.8 as CI checks them.
  • 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.
@nitoygo
nitoygo requested a review from Mosch0512 October 21, 2026 14:02
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.
@ezequielzacca
ezequielzacca force-pushed the feat/item-descriptions branch from f155727 to efcd7ff Compare October 21, 2026 14:15
@Mosch0512 Mosch0512 self-assigned this Oct 21, 2026
…iptions

# Conflicts:
#	src/source/Data/GameData/ItemData/ItemEnumNames.cpp
#	src/source/Data/GameData/ItemData/ItemEnumNames.h

@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: changes requested for two items; the rest is non-blocking. The format is a good first step for #815. The description lines are LocalizedStrings like item names, as phase 8 of the items design asks; colors are names checked at load; and nothing changes in game. I also looked at the later steps (#816 to #836). They only add fields to ItemDescriptionLine, so data written for this step stays valid. The drawing code, though, is carried over almost unchanged to the end of the stack (WriteItemDescriptionLines in #836), so the two bugs below survive all 16 PRs unless they're fixed here.

Required

  • A blank line inside a text ("a\n\nb", or a text that starts with \n) cuts off the rest of the tooltip (inline, ZzzInventory.cpp:3754).
  • The 50-row check stops the description, but the rows after it are written without a check, so a long description writes past the end of TextList (inline, ZzzInventory.cpp:3752).

Non-blocking

  • Description texts get none of the checks that item names get: English required, valid language codes, a warning for languages the game can't show (inline, ItemJsonFormat.cpp:409).
  • The wrap measures the line again after every letter, every frame, through SDL_ttf's shared text cache (inline, ZzzInventory.cpp:3735).
  • Rule 1 of the coding rules: the new block could be its own function (inline, ZzzInventory.cpp:3730).
  • The wrap width is a tooltip value in the item data header (inline, ItemDefinition.h:96).
  • The docs say the lines come "after its stats", but they come before durability, the requirements and the options (inline, item-data.md:84).
  • No test covers turning a description into tooltip rows (inline, test_item_json.cpp:288).
  • The color name table sits outside the file's anonymous namespace and is sized with a literal 14 (inline, ItemEnumNames.cpp:94).
  • %.99ls (ZzzInventory.cpp:3754) hard-codes TextList's row width. "%.*ls" with std::size(TextList[0]) - 1 ties it to the array.
  • The Dark Horse and the Dark Raven show no description outside shops. Their tooltip goes to giPetManager::RenderPetItemInfo and returns at ZzzInventory.cpp:1662, before the description is written. That line isn't in the diff, so there's no inline comment. Either draw the description there too, or mention the exception in the docs.
  • The items design doesn't know about this yet. D15 and phase 8 plan the tooltips as JSON of their own, converted from the ItemTooltip* files. D22 keeps client-only display data out of the item files ("the item files keep what client and server share, and only those take part in the OpenMU exchange"). This PR puts client-only tooltip texts into the item files, as #815 plans. That split makes sense, especially with the shared texts and the layout in Data/Items/Tooltips/Tooltip.json later in the stack. But it should be written into D15, D22 and phase 8 in this PR, where the decision is made. Phase 7's exchange file then has to leave description out.
  • The first commit's message still says a line longer than 99 characters gets a warning. The wrap commit removed that check.

Follow-up (the stack)

  • All 16 PRs of #815 target main, so each diff holds every earlier step (#836 is +16,089/−12,674). On GitHub, a reviewer can't see one step's own change. Basing each PR on the previous step's branch would let each step be reviewed on its own.

What I checked: I read the diff, the code around it in RenderItemInfo, both tooltip renderers (RenderTipTextList and the RmlUi tooltip's BuildLines), WrapTextToWidth, the SDL_ttf measuring and the item data checks. I also read the items design, the roadmap and the later steps up to #836. I built WrapTextToWidth on its own with g++ and ran it on texts with blank lines. I didn't build the client or run the game. CI: no checks ran on this PR.

{
if (TextNum >= static_cast<int>(std::size(TextList)))
break;
mu_swprintf(TextList[TextNum], L"%.99ls", piece.c_str());

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.

Required. WrapTextToWidth returns an empty piece for a blank line inside a text. I ran it on a few texts:

  • "Line one\n\nLine two" gives [Line one] [] [Line two]
  • "\nLeading break" gives [] [Leading break]
  • "One\n \nTwo" gives [One] [] [Two]

The empty piece is written here as L"". Both tooltip renderers treat an empty row as the end of the list: BuildLines (LegacyTextListTooltip.cpp:46) and RenderTipTextList (line 282). The height count at line 5156 stops there too. So everything after it is gone: the rest of the description, the jewel's own text, durability, requirements, options, the set and socket lines and the expiry date.

The docs say \n breaks the line, so \n\n is the natural way to leave a gap. No shipped text uses \n yet, also not in the later steps. So this shows up first with custom item data, or with the tooltip editor of step 6.

Writing L"\n" for an empty piece fixes it. The blank-line branch above then only has to produce one L"\n" piece, so both cases can share this loop.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed: WrapTextToWidth returns an empty piece for a blank line inside a text, and BuildLines, RenderTipTextList and the height count all stop at an empty row. Fixed in f62aa0c: a blank piece is written as the tooltip's own blank row ("\n"), the same way as a blank line, in one loop. Test: "A blank line inside a description text is a blank tooltip row, not the tooltip's end" ("a\n\nb", a leading "\n", a blank line). It fails on the old code (3 checks) and passes now.

const std::wstring text = Core::Text::FromUtf8(line.text.Get(g_ItemDatabase.GetDisplayLocale()));
for (const std::wstring& piece : WrapTextToWidth(text, Data::Items::ItemDescriptionWrapWidth, measure))
{
if (TextNum >= static_cast<int>(std::size(TextList)))

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.

Required. This check stops the description at 50 rows, but the code after it adds rows without a check. Line 4730 writes L"\n" into TextList[TextNum] for every item. The jewel lines from line 3761, the options, RenderSetOptionListInItem, the socket lines and the expiry date follow. So when the description fills TextList, the next write goes to TextList[50], past the array into the globals next to it. ShowLegacyTextList then reads rows beyond 50 too.

A description that wraps to about 45 pieces is enough, for example in a server's own item files. Nothing limits its size at load: the first commit's ValidateDescription went away with the wrap commit.

A limit at load (an issue for a description with more than a set number of lines), or stopping here with room left for the rest of the tooltip, would fix it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed: TextList is [50][100], and from line 4730 on nothing checks the bounds. Fixed in f62aa0c by giving the description rows of its own:

  • TextList, TextListColor, TextBold and Size have MaxItemDescriptionRows (32) rows on top of the original 50 (MaxTextListRows).
  • The description writes at most those 32, so it never takes the room the rest of the tooltip had before descriptions existed.
  • Six files declared the arrays themselves with 50 rows. They use ZzzInventory.h's declarations now; MSVC's decorated names include the size, so a stale one fails to link rather than going unnoticed.

Later in the stack (#830) the description has a second part after the options; both parts share the 32 rows through a budget the caller holds. Test: "A description writes at most its own rows, leaving the tooltip's rows to the rest".

}

ItemDescriptionLine line;
const bool read = Json::ReadLocalizedString(*text, field + "." + Keys::Text, line.text,

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. The docs say text "is written like name", but names get checks that description texts don't (items design, section 2 "Validation"; ValidateName and ValidateNameLocales):

  • a missing English text is an error;
  • a language code may only have letters, digits and -;
  • a language the game has no UI texts for gets a warning.

Without these checks, {"text": {"de": "…"}}, or a typo like {"DE": "…"}, loads with no issue. In English the line then just disappears: Get returns the empty English text, WrapTextToWidth returns nothing, and not even a blank line is drawn. From step 2 on, many translated texts move into the data, so these checks pay off early. Missing description translations aren't counted anywhere either, unlike names in Item Translations, but that can come with the editor.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed, done in f62aa0c. A description text gets the checks a name gets:

  • the English text is required, except for a blank line;
  • a language code has only letters, digits and -;
  • a language the game has no texts in is a warning (with the names' check in ValidateNameLocales).

The same checks went into the later steps, where their texts appear: Tooltip.json's texts (#824), level values (#827) and name lines (#833). Every language in the shipped data is a UI language, so no new warnings. The missing-translation counts can come with the editor (step 6), as you say.

if (const Data::Items::ItemDefinition* definition = g_ItemDatabase.Find(ip->Type))
{
g_pRenderText->SetFont(g_hFont);
const auto measure = [](const wchar_t* text, size_t length)

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. The tooltip is built every frame while an item is hovered. WrapTextToWidth calls this lambda after every letter, with the whole line so far. Each call goes through SdlTtfTextCache::Prepare: a linear search over up to 256 entries and, for a new string, TTF_CreateText with shaping. Every prefix is a new string, so a 150-letter description adds about 130 entries to a cache that all UI text shares. When that cache is full it is emptied completely, and every text on screen is created again.

Measuring only when a word ends would make this cheap. The language could also be picked at load, as SetDisplayLocale does for name; section 1 of the items design asks for "No hash maps or string lookups at runtime". Once placeholders come in step 3, the filled text depends on the item and the hero, so the wrap itself has to stay per tooltip. Cheap measuring is what matters.

This lambda is also the third copy of the same measure function, after MeasureInReferenceUnits (ChatCommandWindow.cpp:65) and the one in CustomMessageBox.cpp:47.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed: the line was measured after every letter, and each prefix was a new entry in the shared text cache. Fixed in 94af869:

  • WrapTextToWidth measures a line once per word ending.
  • It measures letter by letter only inside a word wider than a whole line.

I compared it with the old version on 200,000 random texts with characters of different widths:

  • the lines are the same, except where the old version left a line wider than the limit (a word too wide for a line, after a break);
  • the new one has about half the measure calls on that mix, and fewer on real text with longer words.

The language is still picked per line. With placeholders from step 3 on, the text is filled per tooltip anyway, as you note, so measuring was the costly part. The measure function stays separate from MeasureInReferenceUnits and the message box's: those measure in other units (reference units, the message box's font), the tooltip in its own font.

TextListColor[TextNum] = TEXT_COLOR_WHITE; TextBold[TextNum] = false; TextNum++;
}
}
// The item data's description in the UI's language: each line wrapped to the tooltip's width and at its line

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. Rule 1 of docs/CODING_RULES.md: "When touching a large function, extract at least one logical block into its own function before you're done." RenderItemInfo is about 3,600 lines long, and this block is a natural WriteItemDescriptionLines(const ITEM&), which #821 extracts later anyway. Doing it here also makes building the rows testable (see the comment on the test).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in f62aa0c: the block is WriteItemDescriptionLines(definition, …, measure) in ZzzInventory.cpp, declared in ZzzInventory.h. It takes the item definition and the measure function, so the new tests check its rows directly. Later steps extend that function rather than the block (#830 merges its own extraction into it).


// How wide a description line is drawn before it wraps, in the tooltip's text units: about the widest lines of the
// original tooltips.
constexpr int ItemDescriptionWrapWidth = 200;

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 is a tooltip layout value ("in the tooltip's text units") in the item data definition, and only ZzzInventory.cpp uses it. Rule 5 of docs/CODING_RULES.md keeps UI and data apart, so it fits better next to the tooltip code.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Moved in f62aa0c: ItemDescriptionWrapWidth is a constant of the tooltip code in ZzzInventory.cpp now, out of ItemDefinition.h.

Comment thread docs/item-data.md Outdated
| Field | Meaning |
|---|---|
| `tags` | Categories the game code asks for, e.g. `["mount", "flying"]`; see [Tags](#tags) |
| `description` | Lines the tooltip shows for the item, after its stats (the original client's items still have their texts in the tooltip code, written after the description). Each line is `{"text": ..., "color": ...}`: `text` is written like `name` (a plain English text, or the texts by language), an empty text (`{"text": ""}`) is a blank line, a long line wraps at about the width of the original tooltips' widest lines, and `\n` in a text breaks the line there. `color` is one of the tooltip colors: `white` (left out), `blue`, `red`, `yellow`, `green`, `darkRed`, `purple`, `darkBlue`, `darkYellow`, `greenBlue`, `gray`, `redPurple`, `violet`, `orange`. A client-only field; the bmd import keeps it |

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. "after its stats" is true for the jewels, but the block sits before durability, the requirements, the options and the set and socket lines. On a weapon, the description shows between the speed lines and durability. Saying where it goes avoids surprises, for example "after the damage, defense and speed lines, before durability and the requirements".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 8b26e65: "after its damage, defense and speed lines and before its durability, requirements and options". The row also says the Dark Horse and Dark Raven show it only in shops, describes the checks and the 32-row limit, and that \n\n leaves a blank line.

CHECK(read.sellable);
}

TEST_CASE("An item's description is kept through write and read [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 tests the file format well. Nothing tests how a description becomes tooltip rows: blank lines, \n, wrapping and the 50-row limit. A test of the extracted function, or of WrapTextToWidth with "a\n\nb", would have caught the blank-line bug.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added tests/data/test_item_descriptions.cpp in f62aa0c. It's in test_item_database_files, which links Winmain.cpp, as the tooltip code needs. It tests:

  • blank lines inside a text and at its start;
  • wrapping to the width in the line's color;
  • the row limit;
  • the checks.

test_text_line_wrap gained cases for a blank line inside a text, measuring once per word, and a too-wide word after a break.

}};
} // namespace

constexpr std::array<EnumName<ItemTextColor>, 14> ItemTextColorNames = {{

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. Every other name table is in the anonymous namespace above; this one is outside it and sized with a literal 14. A color added to ItemTextColor without a name gives no compile error. Such a color is then saved as a number, and reading the file refuses a number that has no name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in f62aa0c:

  • The table is in the anonymous namespace, sized by ItemTextColorCount (ItemTextColor::Count, as ItemRequirement does).
  • A static_assert checks that every entry is set and in value order, so a color added without a name fails to compile.

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.
…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.
@ezequielzacca

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review. I checked each point against the code before changing anything, and they all held. The inline comments have the details; the rest:

Every branch builds, and its tests pass on Windows (MSVC), with no new clang-format issues on the changed lines.

A line that starts with spaces and whose first word is wider than the
line was broken at those spaces, which left an empty line above the
word. In a tooltip that is an extra blank row. The spaces now go with
the break instead of becoming a line of their own; the text's own blank
lines stay.
@Mosch0512

Copy link
Copy Markdown
Collaborator

I pushed a small fix to this branch, b9a7430, so please pull before your next push.

WrapTextToWidth broke an indented line in front of a word too wide for the line, which left an empty line above the word. In the tooltip that's an extra blank half row, for example above the link in "Event info:\n https://forum.myserver.com/events/christmas-2026". Now the spaces go with the break, and blank lines written on purpose (\n\n) stay. A new case in test_text_line_wrap.cpp fails without the fix.

Every later step of the stack has the same TextLineWrap.cpp, so please carry it up the stack too.

@Mosch0512
Mosch0512 merged commit d4a3c94 into sven-n:main Oct 23, 2026
8 checks passed
@ezequielzacca

Copy link
Copy Markdown
Contributor Author

Thanks! b9a7430 came into the whole stack with main (#817–#836 now merge main after #813 and #816 landed), so every step has the fixed TextLineWrap.cpp and the new line-wrap test.

Mosch0512 pushed a commit that referenced this pull request Oct 25, 2026
… line never writes an empty row

As the review of #813 asked for description texts:
- Tooltip.json's texts (shared texts and layout lines' own texts) get the checks item names get: the English text is
  required (a blank line has none), a language code has only letters, digits and "-", and a translation in a
  language the game has no texts in is a warning (ValidateTooltipTextLocales, when the item data loads).
- A layout line whose text comes out empty in the UI's language writes the tooltip's blank row ("\n"): an empty row
  ends the tooltip. Its row width comes from TextList instead of a literal 99.
Mosch0512 pushed a commit that referenced this pull request Oct 25, 2026
…n texts

As the review of #813 asked for description texts: an item's level values with their translations 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). One helper checks a description line's and a level value's text.
ezequielzacca added a commit to ezequielzacca/MuMain that referenced this pull request Oct 25, 2026
… Archangel and the Command Fruit come from the data

The 30 cases of the second item chain that write texts with values move
into the items' descriptions, as their first lines: the quest items, the
event, Doppelganger and Varka tickets (with their map's name written in),
the elite potions, buff scrolls, elixirs and seals, the cherry blossom
items, the cash shop cards, the gamble items, the Wizard's Ring by level,
the wing-mix charms, the Secromicon items, the Chaos Castle and paid
channel tickets and the Heart. The reset fruits, the Talisman of
Resurrection, the socket seeds and spheres and the Sign of Dimensions
stay code: their lines need the game (reset points, the saved revive
place, the socket system, the signs still needed). Texts written more
than once are shared texts of the tooltip file; the .resx texts only
these cases used are gone.

The Weapon of Archangel's lines, a preview of the reward weapon its +
level stands for (+0 the staff, +1 the sword, +2 the crossbow: damage,
speed, requirements and options), are its description now, with the
sword's and crossbow's skill mana from the skill data.

"Can be equipped by Dark Lord" of the Command Fruits (+4) was white for
every hero; like every other line that names an item's classes, it is
white for a Dark Lord and dark red for the others now ("class:darkLord").

Tooltips that change: lines longer than the tooltip's width wrap, as
description lines do since sven-n#813 (the tickets', seals' and Secromicon
papers' long lines, the Weapon of Archangel's longest); the cash shop
cards and cherry blossom branches lose the empty full-height line they
wrote for a text no .resx has (legacy ids 2535-2537 and 2551-2556); the
Master Seal of Ascension shows its own lines again without the wing-mix
charm's, which it got when sven-n#820 moved its case out of the chain ahead of
the charms' (its number is in the charms' range). The Weapon of
Archangel's speed and requirement lines above +2, which the item never
has, showed uninitialized values; they're gone.

The tooltip snapshot records eleven variants per item (plain, full,
ancient, harmony, each option alone, worn, broken and expired) and blank
lines without color or style: they show none, and what their slot kept of
an earlier tooltip made the recorded hashes change with unrelated
tooltips.
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