diff --git a/.gitignore b/.gitignore index 9835259003..2a0d92bce8 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,12 @@ build-linux/ !src/bin/Data/Interface/ !src/bin/Data/Interface/RmlUi/ !src/bin/Data/Interface/RmlUi/** +# The classic theme's original interface and login art (themes/classic). +!src/bin/Data/Interface/Classic/ +!src/bin/Data/Interface/Classic/** +!src/bin/Data/Logo/ +!src/bin/Data/Logo/Classic/ +!src/bin/Data/Logo/Classic/** # Item data (JSON, written by the item editor) is source-controlled. !src/bin/Data/Items/ !src/bin/Data/Items/** diff --git a/docs/rmlui-ui-system/theming-and-modding.md b/docs/rmlui-ui-system/theming-and-modding.md index 34f7755d67..7cb97e4521 100644 --- a/docs/rmlui-ui-system/theming-and-modding.md +++ b/docs/rmlui-ui-system/theming-and-modding.md @@ -1,8 +1,8 @@ # Theming & Modding How to edit and select themes, use shared design tokens, and supply custom assets. The client -ships `legacy` and `modern`, plus `legacy-inherited-test` for checking inheritance without visual -overrides. Additional theme folders work without recompilation and can inherit an existing theme. +ships `legacy`, `modern` and `classic` (the 0.97 interface, below), plus `legacy-inherited-test` +for checking inheritance without visual overrides. Additional theme folders work without recompilation and can inherit an existing theme. A separate user/mod override layer is not implemented. ## Shared markup and theme-specific structure @@ -118,11 +118,19 @@ RML, templates, RCSS and theme-local images use the first matching whole file. A stylesheet replaces its ancestor's file; rules are not automatically combined. Paths to common assets outside the theme folder keep their ordinary meaning. -`[Tokens]`, `[Capabilities]` and `[Fonts]` inherit individual keys. A child value wins, including +`[Tokens]`, `[Capabilities]`, `[Fonts]` and `[Stacking]` inherit individual keys. A child value wins, including `NativeTextSize=0` or an empty font entry. Display names stay specific to the child. Names use letters, digits, `_` and `-` and are normalized to lowercase. Missing ancestors, invalid names and inheritance cycles make a theme unavailable for selection. +`[Stacking]` moves one of the theme's documents in the stacking order, when its layout makes two +documents overlap the other way round. The classic theme puts its HUD under the windows +(`main_frame.rml=1.95`; the lowest window is 2.0), so a window docked or dragged over the bar's +ends covers the dragons there, as in 0.97, and its chat input over the windows and under the +tooltips (`chat_input.rml=10.65`; tooltips are 10.69). The depths are the original windows' layer +depths, listed in `UI/RmlBridge/RmlStackingOrder.cpp`; a document the theme does not list keeps +its own. + 1. Create `src/bin/Data/Interface/RmlUi/themes//`. 2. Declare `Base=legacy` or `Base=modern` in `[Theme]`, or supply your own complete stylesheets. Every window links `base.rcss` for shared rules such as buttons, checkbox states, backdrops @@ -339,6 +347,40 @@ families for the session, so a family loaded by an earlier theme remains availab a theme retries optional files; restart the client to replace a font file whose family is already loaded. Referencing a player's installed font does not package it with the theme. +## The classic (0.97) theme + +`RmlTheme=classic` gives the interface of the original 0.97 client, drawn with its own art. It +inherits `legacy` and restyles the login box, server list, character select and creation, HUD, +inventory, character, party, NPC shop, storage, trade, Chaos Machine, guild, event entries, +message boxes, confirmations, the Esc menus, the command window (D) and chat. The NPC menus that +share the Esc menu's document keep legacy's look, as 0.97 has none of them. Where the Season 1 and +2 clients, which kept the classic interface, add a part for something MuMain has, the theme draws +it as they did instead of hiding it: on the HUD the SD column and the command window and friend +buttons, in the character window the quest and pet buttons, in the inventory the personal shop +button. A window 0.97 does not have follows those clients, else the closest classic window. The +art lives outside the RmlUi tree, in `Data/Interface/Classic` and `Data/Logo/Classic`, so its file +names cannot collide with S6 files of the same name. + +What changes for the player, besides the look: + +- **Character creation:** the class is chosen with arrows, which step through the classes the + client enables. +- **World:** no map title when entering a map. + +The HUD model also exposes what the classic bar shows and the S6 bar does not: `party_open` / +`guild_open` / `command_open` with `mainframe_party_click` / `mainframe_guild_click` / +`mainframe_command_click` (the command window under the D key's rules) and their tooltips, and +`coord_x` / `coord_y`. + +The character creation model has `job_previous` / `job_next`: the enabled class before and after +the selected one, or -1, for a theme that steps through the classes with arrows +(`charmake_select_job(job_next)`) instead of a button per class. + +The pet / durability HUD (`item_endurance.rml`) marks `#pets` with `.in-party` while the hero is +in a party, so a theme can keep the pet column clear of the party list. The classic theme also +places the pet column, the party list and the event HUDs from `--world-left` / `--world-right`, so +they move aside when windows open, as in 0.97. + ## Coordinates, scaling, and positioning — what a theme actually controls ### Scaling: a global user setting, opt-in per element diff --git a/src/bin/Data/Interface/Classic/099b/Cursorid.OZT b/src/bin/Data/Interface/Classic/099b/Cursorid.OZT new file mode 100644 index 0000000000..34f1675e85 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/Cursorid.OZT differ diff --git a/src/bin/Data/Interface/Classic/099b/Cursorid_wnd.OZJ b/src/bin/Data/Interface/Classic/099b/Cursorid_wnd.OZJ new file mode 100644 index 0000000000..dd0764a6de Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/Cursorid_wnd.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/DuelWindow.OZJ b/src/bin/Data/Interface/Classic/099b/DuelWindow.OZJ new file mode 100644 index 0000000000..61d1d0e031 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/DuelWindow.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/Menu01.OZJ b/src/bin/Data/Interface/Classic/099b/Menu01.OZJ new file mode 100644 index 0000000000..0e61ecf2a1 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/Menu01.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/Menu03.OZJ b/src/bin/Data/Interface/Classic/099b/Menu03.OZJ new file mode 100644 index 0000000000..b2777f444b Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/Menu03.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/Menu04.tga b/src/bin/Data/Interface/Classic/099b/Menu04.tga new file mode 100644 index 0000000000..191e1729fd Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/Menu04.tga differ diff --git a/src/bin/Data/Interface/Classic/099b/btn_pshop.OZJ b/src/bin/Data/Interface/Classic/099b/btn_pshop.OZJ new file mode 100644 index 0000000000..d4d396f83f Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/btn_pshop.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/btn_pshop2.OZJ b/src/bin/Data/Interface/Classic/099b/btn_pshop2.OZJ new file mode 100644 index 0000000000..06c1a50adb Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/btn_pshop2.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/character_ex.tga b/src/bin/Data/Interface/Classic/099b/character_ex.tga new file mode 100644 index 0000000000..721309afe6 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/character_ex.tga differ diff --git a/src/bin/Data/Interface/Classic/099b/check.OZT b/src/bin/Data/Interface/Classic/099b/check.OZT new file mode 100644 index 0000000000..2ade027a4b Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/check.OZT differ diff --git a/src/bin/Data/Interface/Classic/099b/cmdType.OZJ b/src/bin/Data/Interface/Classic/099b/cmdType.OZJ new file mode 100644 index 0000000000..4764579572 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/cmdType.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/coin.OZJ b/src/bin/Data/Interface/Classic/099b/coin.OZJ new file mode 100644 index 0000000000..2d04bc43ea Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/coin.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/command.ozj b/src/bin/Data/Interface/Classic/099b/command.ozj new file mode 100644 index 0000000000..44ea178777 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/command.ozj differ diff --git a/src/bin/Data/Interface/Classic/099b/dialogue2_2.ozt b/src/bin/Data/Interface/Classic/099b/dialogue2_2.ozt new file mode 100644 index 0000000000..1e1423ab97 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/dialogue2_2.ozt differ diff --git a/src/bin/Data/Interface/Classic/099b/dialogue2_3.ozt b/src/bin/Data/Interface/Classic/099b/dialogue2_3.ozt new file mode 100644 index 0000000000..5b42652b5d Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/dialogue2_3.ozt differ diff --git a/src/bin/Data/Interface/Classic/099b/dialogue2_4.ozt b/src/bin/Data/Interface/Classic/099b/dialogue2_4.ozt new file mode 100644 index 0000000000..cadce873ef Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/dialogue2_4.ozt differ diff --git a/src/bin/Data/Interface/Classic/099b/dialogue2_5.ozt b/src/bin/Data/Interface/Classic/099b/dialogue2_5.ozt new file mode 100644 index 0000000000..177b166203 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/dialogue2_5.ozt differ diff --git a/src/bin/Data/Interface/Classic/099b/dialogue2_6.ozt b/src/bin/Data/Interface/Classic/099b/dialogue2_6.ozt new file mode 100644 index 0000000000..579b33320d Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/dialogue2_6.ozt differ diff --git a/src/bin/Data/Interface/Classic/099b/dialogue2_7.ozt b/src/bin/Data/Interface/Classic/099b/dialogue2_7.ozt new file mode 100644 index 0000000000..c57a13a8c5 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/dialogue2_7.ozt differ diff --git a/src/bin/Data/Interface/Classic/099b/dialogue2_8.ozt b/src/bin/Data/Interface/Classic/099b/dialogue2_8.ozt new file mode 100644 index 0000000000..ccecb489bb Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/dialogue2_8.ozt differ diff --git a/src/bin/Data/Interface/Classic/099b/dialogue3.ozt b/src/bin/Data/Interface/Classic/099b/dialogue3.ozt new file mode 100644 index 0000000000..fc06cde1f7 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/dialogue3.ozt differ diff --git a/src/bin/Data/Interface/Classic/099b/dialogue4.ozt b/src/bin/Data/Interface/Classic/099b/dialogue4.ozt new file mode 100644 index 0000000000..923674d0cb Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/dialogue4.ozt differ diff --git a/src/bin/Data/Interface/Classic/099b/dialogue4_1.ozt b/src/bin/Data/Interface/Classic/099b/dialogue4_1.ozt new file mode 100644 index 0000000000..b5e9565a24 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/dialogue4_1.ozt differ diff --git a/src/bin/Data/Interface/Classic/099b/menu01_new2.OZJ b/src/bin/Data/Interface/Classic/099b/menu01_new2.OZJ new file mode 100644 index 0000000000..a34d933207 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/menu01_new2.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/newui_Bar_switch01.OZJ b/src/bin/Data/Interface/Classic/099b/newui_Bar_switch01.OZJ new file mode 100644 index 0000000000..0dc8df60e9 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/newui_Bar_switch01.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/newui_Bar_switch02.OZJ b/src/bin/Data/Interface/Classic/099b/newui_Bar_switch02.OZJ new file mode 100644 index 0000000000..445aec2be7 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/newui_Bar_switch02.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/pet1.OZJ b/src/bin/Data/Interface/Classic/099b/pet1.OZJ new file mode 100644 index 0000000000..fc243378d4 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/pet1.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/pet2.OZJ b/src/bin/Data/Interface/Classic/099b/pet2.OZJ new file mode 100644 index 0000000000..e65df9acd1 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/pet2.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/quest1.OZJ b/src/bin/Data/Interface/Classic/099b/quest1.OZJ new file mode 100644 index 0000000000..462535fe63 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/quest1.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/quest2.OZJ b/src/bin/Data/Interface/Classic/099b/quest2.OZJ new file mode 100644 index 0000000000..8a144eef55 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/quest2.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/setitem.OZJ b/src/bin/Data/Interface/Classic/099b/setitem.OZJ new file mode 100644 index 0000000000..f030d587cd Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/setitem.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/skill2.OZJ b/src/bin/Data/Interface/Classic/099b/skill2.OZJ new file mode 100644 index 0000000000..158fe33a2d Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/skill2.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/text_button.OZJ b/src/bin/Data/Interface/Classic/099b/text_button.OZJ new file mode 100644 index 0000000000..ee6a3b19e5 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/text_button.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/webzenmail.OZJ b/src/bin/Data/Interface/Classic/099b/webzenmail.OZJ new file mode 100644 index 0000000000..141076f5bd Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/webzenmail.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/win_button.OZT b/src/bin/Data/Interface/Classic/099b/win_button.OZT new file mode 100644 index 0000000000..0510bbf57c Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/win_button.OZT differ diff --git a/src/bin/Data/Interface/Classic/099b/win_check.OZT b/src/bin/Data/Interface/Classic/099b/win_check.OZT new file mode 100644 index 0000000000..919c387587 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/win_check.OZT differ diff --git a/src/bin/Data/Interface/Classic/099b/win_letter.OZJ b/src/bin/Data/Interface/Classic/099b/win_letter.OZJ new file mode 100644 index 0000000000..016ba5ddc3 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/win_letter.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/win_mail.OZT b/src/bin/Data/Interface/Classic/099b/win_mail.OZT new file mode 100644 index 0000000000..9459c58a94 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/win_mail.OZT differ diff --git a/src/bin/Data/Interface/Classic/099b/win_man.OZJ b/src/bin/Data/Interface/Classic/099b/win_man.OZJ new file mode 100644 index 0000000000..9e16d30f9e Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/win_man.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/win_mark.OZT b/src/bin/Data/Interface/Classic/099b/win_mark.OZT new file mode 100644 index 0000000000..28b493f87e Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/win_mark.OZT differ diff --git a/src/bin/Data/Interface/Classic/099b/win_push.OZJ b/src/bin/Data/Interface/Classic/099b/win_push.OZJ new file mode 100644 index 0000000000..8f7304c30b Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/win_push.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/win_question.OZT b/src/bin/Data/Interface/Classic/099b/win_question.OZT new file mode 100644 index 0000000000..43bfeabeaa Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/win_question.OZT differ diff --git a/src/bin/Data/Interface/Classic/099b/win_resize.OZT b/src/bin/Data/Interface/Classic/099b/win_resize.OZT new file mode 100644 index 0000000000..d6d6c73a76 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/win_resize.OZT differ diff --git a/src/bin/Data/Interface/Classic/099b/win_scrollbar.OZJ b/src/bin/Data/Interface/Classic/099b/win_scrollbar.OZJ new file mode 100644 index 0000000000..e3d96056dc Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/win_scrollbar.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/win_size.OZJ b/src/bin/Data/Interface/Classic/099b/win_size.OZJ new file mode 100644 index 0000000000..cd747e0625 Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/win_size.OZJ differ diff --git a/src/bin/Data/Interface/Classic/099b/win_titlebar.OZJ b/src/bin/Data/Interface/Classic/099b/win_titlebar.OZJ new file mode 100644 index 0000000000..cbaf215bcc Binary files /dev/null and b/src/bin/Data/Interface/Classic/099b/win_titlebar.OZJ differ diff --git a/src/bin/Data/Interface/Classic/Accept_box01.ozj b/src/bin/Data/Interface/Classic/Accept_box01.ozj new file mode 100644 index 0000000000..de7b56a14e Binary files /dev/null and b/src/bin/Data/Interface/Classic/Accept_box01.ozj differ diff --git a/src/bin/Data/Interface/Classic/Accept_box02.ozj b/src/bin/Data/Interface/Classic/Accept_box02.ozj new file mode 100644 index 0000000000..8779907b45 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Accept_box02.ozj differ diff --git a/src/bin/Data/Interface/Classic/Back1.ozj b/src/bin/Data/Interface/Classic/Back1.ozj new file mode 100644 index 0000000000..e80dbef487 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Back1.ozj differ diff --git a/src/bin/Data/Interface/Classic/Back2.ozj b/src/bin/Data/Interface/Classic/Back2.ozj new file mode 100644 index 0000000000..b82eef01ec Binary files /dev/null and b/src/bin/Data/Interface/Classic/Back2.ozj differ diff --git a/src/bin/Data/Interface/Classic/Back3.ozj b/src/bin/Data/Interface/Classic/Back3.ozj new file mode 100644 index 0000000000..19a6d32f66 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Back3.ozj differ diff --git a/src/bin/Data/Interface/Classic/Bar.ozj b/src/bin/Data/Interface/Classic/Bar.ozj new file mode 100644 index 0000000000..c399332201 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Bar.ozj differ diff --git a/src/bin/Data/Interface/Classic/Buy_01.ozj b/src/bin/Data/Interface/Classic/Buy_01.ozj new file mode 100644 index 0000000000..bf806616fe Binary files /dev/null and b/src/bin/Data/Interface/Classic/Buy_01.ozj differ diff --git a/src/bin/Data/Interface/Classic/Buy_02.ozj b/src/bin/Data/Interface/Classic/Buy_02.ozj new file mode 100644 index 0000000000..649c015ada Binary files /dev/null and b/src/bin/Data/Interface/Classic/Buy_02.ozj differ diff --git a/src/bin/Data/Interface/Classic/Cancel.ozj b/src/bin/Data/Interface/Classic/Cancel.ozj new file mode 100644 index 0000000000..f17ae855f7 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Cancel.ozj differ diff --git a/src/bin/Data/Interface/Classic/Cancel2.ozj b/src/bin/Data/Interface/Classic/Cancel2.ozj new file mode 100644 index 0000000000..c554662304 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Cancel2.ozj differ diff --git a/src/bin/Data/Interface/Classic/Cursor.ozt b/src/bin/Data/Interface/Classic/Cursor.ozt new file mode 100644 index 0000000000..69c1bd5e9e Binary files /dev/null and b/src/bin/Data/Interface/Classic/Cursor.ozt differ diff --git a/src/bin/Data/Interface/Classic/Cursorattack.ozt b/src/bin/Data/Interface/Classic/Cursorattack.ozt new file mode 100644 index 0000000000..ac518a0d2b Binary files /dev/null and b/src/bin/Data/Interface/Classic/Cursorattack.ozt differ diff --git a/src/bin/Data/Interface/Classic/Cursordontmove.ozt b/src/bin/Data/Interface/Classic/Cursordontmove.ozt new file mode 100644 index 0000000000..83f528b3d2 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Cursordontmove.ozt differ diff --git a/src/bin/Data/Interface/Classic/Cursoreye.ozt b/src/bin/Data/Interface/Classic/Cursoreye.ozt new file mode 100644 index 0000000000..2730b25b9a Binary files /dev/null and b/src/bin/Data/Interface/Classic/Cursoreye.ozt differ diff --git a/src/bin/Data/Interface/Classic/Cursorget.ozt b/src/bin/Data/Interface/Classic/Cursorget.ozt new file mode 100644 index 0000000000..9d0319d93f Binary files /dev/null and b/src/bin/Data/Interface/Classic/Cursorget.ozt differ diff --git a/src/bin/Data/Interface/Classic/Cursorleanagainst.ozt b/src/bin/Data/Interface/Classic/Cursorleanagainst.ozt new file mode 100644 index 0000000000..9c91e455b1 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Cursorleanagainst.ozt differ diff --git a/src/bin/Data/Interface/Classic/Cursorpush.ozt b/src/bin/Data/Interface/Classic/Cursorpush.ozt new file mode 100644 index 0000000000..50332cfe4d Binary files /dev/null and b/src/bin/Data/Interface/Classic/Cursorpush.ozt differ diff --git a/src/bin/Data/Interface/Classic/Cursorrepair.ozt b/src/bin/Data/Interface/Classic/Cursorrepair.ozt new file mode 100644 index 0000000000..d951e60dda Binary files /dev/null and b/src/bin/Data/Interface/Classic/Cursorrepair.ozt differ diff --git a/src/bin/Data/Interface/Classic/Cursorsitdown.ozt b/src/bin/Data/Interface/Classic/Cursorsitdown.ozt new file mode 100644 index 0000000000..31c4f62e48 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Cursorsitdown.ozt differ diff --git a/src/bin/Data/Interface/Classic/Cursortalk.ozt b/src/bin/Data/Interface/Classic/Cursortalk.ozt new file mode 100644 index 0000000000..7f5e868251 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Cursortalk.ozt differ diff --git a/src/bin/Data/Interface/Classic/Dialogue1.ozj b/src/bin/Data/Interface/Classic/Dialogue1.ozj new file mode 100644 index 0000000000..05d1ce091f Binary files /dev/null and b/src/bin/Data/Interface/Classic/Dialogue1.ozj differ diff --git a/src/bin/Data/Interface/Classic/Dialogue2.ozj b/src/bin/Data/Interface/Classic/Dialogue2.ozj new file mode 100644 index 0000000000..13f1cdcd8b Binary files /dev/null and b/src/bin/Data/Interface/Classic/Dialogue2.ozj differ diff --git a/src/bin/Data/Interface/Classic/Dialogue2_1.ozj b/src/bin/Data/Interface/Classic/Dialogue2_1.ozj new file mode 100644 index 0000000000..eb1835fcf0 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Dialogue2_1.ozj differ diff --git a/src/bin/Data/Interface/Classic/Exit_01.ozj b/src/bin/Data/Interface/Classic/Exit_01.ozj new file mode 100644 index 0000000000..9e9fc9768e Binary files /dev/null and b/src/bin/Data/Interface/Classic/Exit_01.ozj differ diff --git a/src/bin/Data/Interface/Classic/Exit_02.ozj b/src/bin/Data/Interface/Classic/Exit_02.ozj new file mode 100644 index 0000000000..d34c4c32bc Binary files /dev/null and b/src/bin/Data/Interface/Classic/Exit_02.ozj differ diff --git a/src/bin/Data/Interface/Classic/Font.ozt b/src/bin/Data/Interface/Classic/Font.ozt new file mode 100644 index 0000000000..0487bc3184 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Font.ozt differ diff --git a/src/bin/Data/Interface/Classic/Fontinput.ozt b/src/bin/Data/Interface/Classic/Fontinput.ozt new file mode 100644 index 0000000000..7276fd3383 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Fontinput.ozt differ diff --git a/src/bin/Data/Interface/Classic/Fonttest.ozt b/src/bin/Data/Interface/Classic/Fonttest.ozt new file mode 100644 index 0000000000..831708e806 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Fonttest.ozt differ diff --git a/src/bin/Data/Interface/Classic/Guild.ozj b/src/bin/Data/Interface/Classic/Guild.ozj new file mode 100644 index 0000000000..6419f33e6b Binary files /dev/null and b/src/bin/Data/Interface/Classic/Guild.ozj differ diff --git a/src/bin/Data/Interface/Classic/Guild.ozt b/src/bin/Data/Interface/Classic/Guild.ozt new file mode 100644 index 0000000000..3aab951905 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Guild.ozt differ diff --git a/src/bin/Data/Interface/Classic/Inventorybox2.ozj b/src/bin/Data/Interface/Classic/Inventorybox2.ozj new file mode 100644 index 0000000000..38e8e9ddcd Binary files /dev/null and b/src/bin/Data/Interface/Classic/Inventorybox2.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_Back02.OZJ b/src/bin/Data/Interface/Classic/Item_Back02.OZJ new file mode 100644 index 0000000000..32ddc9ab22 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_Back02.OZJ differ diff --git a/src/bin/Data/Interface/Classic/Item_back01.ozj b/src/bin/Data/Interface/Classic/Item_back01.ozj new file mode 100644 index 0000000000..b74679ec6c Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_back01.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_boots.ozj b/src/bin/Data/Interface/Classic/Item_boots.ozj new file mode 100644 index 0000000000..152d117323 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_boots.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_box.ozj b/src/bin/Data/Interface/Classic/Item_box.ozj new file mode 100644 index 0000000000..aac1232b48 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_box.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_cap.ozj b/src/bin/Data/Interface/Classic/Item_cap.ozj new file mode 100644 index 0000000000..2b869571ff Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_cap.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_fairy.ozj b/src/bin/Data/Interface/Classic/Item_fairy.ozj new file mode 100644 index 0000000000..a539d996f6 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_fairy.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_gloves.ozj b/src/bin/Data/Interface/Classic/Item_gloves.ozj new file mode 100644 index 0000000000..0c5b724da3 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_gloves.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_lower.ozj b/src/bin/Data/Interface/Classic/Item_lower.ozj new file mode 100644 index 0000000000..310951bed7 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_lower.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_money.ozj b/src/bin/Data/Interface/Classic/Item_money.ozj new file mode 100644 index 0000000000..9d9ad72f30 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_money.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_necklace.ozj b/src/bin/Data/Interface/Classic/Item_necklace.ozj new file mode 100644 index 0000000000..7e0008089d Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_necklace.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_ring.ozj b/src/bin/Data/Interface/Classic/Item_ring.ozj new file mode 100644 index 0000000000..402e89f48a Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_ring.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_upper.ozj b/src/bin/Data/Interface/Classic/Item_upper.ozj new file mode 100644 index 0000000000..01a654778c Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_upper.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_weapon01.ozj b/src/bin/Data/Interface/Classic/Item_weapon01.ozj new file mode 100644 index 0000000000..3af1c7eb1e Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_weapon01.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_weapon02.ozj b/src/bin/Data/Interface/Classic/Item_weapon02.ozj new file mode 100644 index 0000000000..5e409e3ffd Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_weapon02.ozj differ diff --git a/src/bin/Data/Interface/Classic/Item_wing.ozj b/src/bin/Data/Interface/Classic/Item_wing.ozj new file mode 100644 index 0000000000..4b2b828395 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Item_wing.ozj differ diff --git a/src/bin/Data/Interface/Classic/Level01.ozj b/src/bin/Data/Interface/Classic/Level01.ozj new file mode 100644 index 0000000000..19d9cc790c Binary files /dev/null and b/src/bin/Data/Interface/Classic/Level01.ozj differ diff --git a/src/bin/Data/Interface/Classic/Level_01.ozj b/src/bin/Data/Interface/Classic/Level_01.ozj new file mode 100644 index 0000000000..2ddee8704f Binary files /dev/null and b/src/bin/Data/Interface/Classic/Level_01.ozj differ diff --git a/src/bin/Data/Interface/Classic/Level_02.ozj b/src/bin/Data/Interface/Classic/Level_02.ozj new file mode 100644 index 0000000000..d9a43fc5d1 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Level_02.ozj differ diff --git a/src/bin/Data/Interface/Classic/Level_box.ozj b/src/bin/Data/Interface/Classic/Level_box.ozj new file mode 100644 index 0000000000..3b4a03b016 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Level_box.ozj differ diff --git a/src/bin/Data/Interface/Classic/Lock_01.ozj b/src/bin/Data/Interface/Classic/Lock_01.ozj new file mode 100644 index 0000000000..7a661235f8 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Lock_01.ozj differ diff --git a/src/bin/Data/Interface/Classic/Lock_02.ozj b/src/bin/Data/Interface/Classic/Lock_02.ozj new file mode 100644 index 0000000000..25eda23857 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Lock_02.ozj differ diff --git a/src/bin/Data/Interface/Classic/Lock_03.ozj b/src/bin/Data/Interface/Classic/Lock_03.ozj new file mode 100644 index 0000000000..380139e7d3 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Lock_03.ozj differ diff --git a/src/bin/Data/Interface/Classic/Lock_04.ozj b/src/bin/Data/Interface/Classic/Lock_04.ozj new file mode 100644 index 0000000000..7a5acebbb3 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Lock_04.ozj differ diff --git a/src/bin/Data/Interface/Classic/Menu01_new.ozj b/src/bin/Data/Interface/Classic/Menu01_new.ozj new file mode 100644 index 0000000000..87a9d8cf2e Binary files /dev/null and b/src/bin/Data/Interface/Classic/Menu01_new.ozj differ diff --git a/src/bin/Data/Interface/Classic/Menu02.ozj b/src/bin/Data/Interface/Classic/Menu02.ozj new file mode 100644 index 0000000000..63405c8823 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Menu02.ozj differ diff --git a/src/bin/Data/Interface/Classic/Menu03_new.ozj b/src/bin/Data/Interface/Classic/Menu03_new.ozj new file mode 100644 index 0000000000..450272d147 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Menu03_new.ozj differ diff --git a/src/bin/Data/Interface/Classic/Menu03_new_ag.ozj b/src/bin/Data/Interface/Classic/Menu03_new_ag.ozj new file mode 100644 index 0000000000..806881fd04 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Menu03_new_ag.ozj differ diff --git a/src/bin/Data/Interface/Classic/Menu04.ozt b/src/bin/Data/Interface/Classic/Menu04.ozt new file mode 100644 index 0000000000..935cb16937 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Menu04.ozt differ diff --git a/src/bin/Data/Interface/Classic/Menu_blue.ozj b/src/bin/Data/Interface/Classic/Menu_blue.ozj new file mode 100644 index 0000000000..c8d487d938 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Menu_blue.ozj differ diff --git a/src/bin/Data/Interface/Classic/Menu_character.ozj b/src/bin/Data/Interface/Classic/Menu_character.ozj new file mode 100644 index 0000000000..99f283a801 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Menu_character.ozj differ diff --git a/src/bin/Data/Interface/Classic/Menu_green.ozj b/src/bin/Data/Interface/Classic/Menu_green.ozj new file mode 100644 index 0000000000..fedbf24cca Binary files /dev/null and b/src/bin/Data/Interface/Classic/Menu_green.ozj differ diff --git a/src/bin/Data/Interface/Classic/Menu_inventory.ozj b/src/bin/Data/Interface/Classic/Menu_inventory.ozj new file mode 100644 index 0000000000..d66d98fa34 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Menu_inventory.ozj differ diff --git a/src/bin/Data/Interface/Classic/Menu_party.ozj b/src/bin/Data/Interface/Classic/Menu_party.ozj new file mode 100644 index 0000000000..cfbbcc53b4 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Menu_party.ozj differ diff --git a/src/bin/Data/Interface/Classic/Menu_red.ozj b/src/bin/Data/Interface/Classic/Menu_red.ozj new file mode 100644 index 0000000000..dd59226a18 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Menu_red.ozj differ diff --git a/src/bin/Data/Interface/Classic/Message_box.ozj b/src/bin/Data/Interface/Classic/Message_box.ozj new file mode 100644 index 0000000000..3cbd2b9bfa Binary files /dev/null and b/src/bin/Data/Interface/Classic/Message_box.ozj differ diff --git a/src/bin/Data/Interface/Classic/Message_box1.ozj b/src/bin/Data/Interface/Classic/Message_box1.ozj new file mode 100644 index 0000000000..791f39afda Binary files /dev/null and b/src/bin/Data/Interface/Classic/Message_box1.ozj differ diff --git a/src/bin/Data/Interface/Classic/Message_box1_40x6.ozj b/src/bin/Data/Interface/Classic/Message_box1_40x6.ozj new file mode 100644 index 0000000000..9822d17a27 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Message_box1_40x6.ozj differ diff --git a/src/bin/Data/Interface/Classic/Message_box1_440x300.ozj b/src/bin/Data/Interface/Classic/Message_box1_440x300.ozj new file mode 100644 index 0000000000..d736ab34cb Binary files /dev/null and b/src/bin/Data/Interface/Classic/Message_box1_440x300.ozj differ diff --git a/src/bin/Data/Interface/Classic/Message_box1_60x5.ozj b/src/bin/Data/Interface/Classic/Message_box1_60x5.ozj new file mode 100644 index 0000000000..d456a0ea69 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Message_box1_60x5.ozj differ diff --git a/src/bin/Data/Interface/Classic/Message_box2.ozj b/src/bin/Data/Interface/Classic/Message_box2.ozj new file mode 100644 index 0000000000..31b49c5c55 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Message_box2.ozj differ diff --git a/src/bin/Data/Interface/Classic/Message_box2_230.ozj b/src/bin/Data/Interface/Classic/Message_box2_230.ozj new file mode 100644 index 0000000000..55f0cf4611 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Message_box2_230.ozj differ diff --git a/src/bin/Data/Interface/Classic/Message_box2_268.ozj b/src/bin/Data/Interface/Classic/Message_box2_268.ozj new file mode 100644 index 0000000000..7f9e7bb11f Binary files /dev/null and b/src/bin/Data/Interface/Classic/Message_box2_268.ozj differ diff --git a/src/bin/Data/Interface/Classic/Message_box2_440.ozj b/src/bin/Data/Interface/Classic/Message_box2_440.ozj new file mode 100644 index 0000000000..ee401f96fe Binary files /dev/null and b/src/bin/Data/Interface/Classic/Message_box2_440.ozj differ diff --git a/src/bin/Data/Interface/Classic/MiniMap.OZT b/src/bin/Data/Interface/Classic/MiniMap.OZT new file mode 100644 index 0000000000..1eb1f781b8 Binary files /dev/null and b/src/bin/Data/Interface/Classic/MiniMap.OZT differ diff --git a/src/bin/Data/Interface/Classic/Mix_button1.ozj b/src/bin/Data/Interface/Classic/Mix_button1.ozj new file mode 100644 index 0000000000..7f7432a8c9 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Mix_button1.ozj differ diff --git a/src/bin/Data/Interface/Classic/Mix_button2.ozj b/src/bin/Data/Interface/Classic/Mix_button2.ozj new file mode 100644 index 0000000000..94b1184032 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Mix_button2.ozj differ diff --git a/src/bin/Data/Interface/Classic/Money_01.ozj b/src/bin/Data/Interface/Classic/Money_01.ozj new file mode 100644 index 0000000000..20eadbf705 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Money_01.ozj differ diff --git a/src/bin/Data/Interface/Classic/Money_02.ozj b/src/bin/Data/Interface/Classic/Money_02.ozj new file mode 100644 index 0000000000..50b0c25aa4 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Money_02.ozj differ diff --git a/src/bin/Data/Interface/Classic/Nis_back.ozj b/src/bin/Data/Interface/Classic/Nis_back.ozj new file mode 100644 index 0000000000..4337b9eaa1 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_back.ozj differ diff --git a/src/bin/Data/Interface/Classic/Nis_bar.ozj b/src/bin/Data/Interface/Classic/Nis_bar.ozj new file mode 100644 index 0000000000..1677c4de92 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_bar.ozj differ diff --git a/src/bin/Data/Interface/Classic/Nis_btnalpha.ozj b/src/bin/Data/Interface/Classic/Nis_btnalpha.ozj new file mode 100644 index 0000000000..f28f4effed Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_btnalpha.ozj differ diff --git a/src/bin/Data/Interface/Classic/Nis_btnarrow.ozj b/src/bin/Data/Interface/Classic/Nis_btnarrow.ozj new file mode 100644 index 0000000000..90ed10c20f Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_btnarrow.ozj differ diff --git a/src/bin/Data/Interface/Classic/Nis_btnchat.ozj b/src/bin/Data/Interface/Classic/Nis_btnchat.ozj new file mode 100644 index 0000000000..2f8c305151 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_btnchat.ozj differ diff --git a/src/bin/Data/Interface/Classic/Nis_btnend.ozj b/src/bin/Data/Interface/Classic/Nis_btnend.ozj new file mode 100644 index 0000000000..5b1fc9f404 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_btnend.ozj differ diff --git a/src/bin/Data/Interface/Classic/Nis_btnmax.ozj b/src/bin/Data/Interface/Classic/Nis_btnmax.ozj new file mode 100644 index 0000000000..ad0de8961c Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_btnmax.ozj differ diff --git a/src/bin/Data/Interface/Classic/Nis_btnmin.ozj b/src/bin/Data/Interface/Classic/Nis_btnmin.ozj new file mode 100644 index 0000000000..e089ec440c Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_btnmin.ozj differ diff --git a/src/bin/Data/Interface/Classic/Nis_btnsize.ozj b/src/bin/Data/Interface/Classic/Nis_btnsize.ozj new file mode 100644 index 0000000000..01dbf20bc6 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_btnsize.ozj differ diff --git a/src/bin/Data/Interface/Classic/Nis_hframe.ozj b/src/bin/Data/Interface/Classic/Nis_hframe.ozj new file mode 100644 index 0000000000..c10f2bb51e Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_hframe.ozj differ diff --git a/src/bin/Data/Interface/Classic/Nis_rsframe.ozj b/src/bin/Data/Interface/Classic/Nis_rsframe.ozj new file mode 100644 index 0000000000..63cea44798 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_rsframe.ozj differ diff --git a/src/bin/Data/Interface/Classic/Nis_rsframe.ozt b/src/bin/Data/Interface/Classic/Nis_rsframe.ozt new file mode 100644 index 0000000000..53c5eb2684 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_rsframe.ozt differ diff --git a/src/bin/Data/Interface/Classic/Nis_vframe.ozj b/src/bin/Data/Interface/Classic/Nis_vframe.ozj new file mode 100644 index 0000000000..6f62b5775c Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_vframe.ozj differ diff --git a/src/bin/Data/Interface/Classic/Nis_vframe_tall.ozj b/src/bin/Data/Interface/Classic/Nis_vframe_tall.ozj new file mode 100644 index 0000000000..73d525a895 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Nis_vframe_tall.ozj differ diff --git a/src/bin/Data/Interface/Classic/Ok.ozj b/src/bin/Data/Interface/Classic/Ok.ozj new file mode 100644 index 0000000000..17798d0080 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Ok.ozj differ diff --git a/src/bin/Data/Interface/Classic/Ok2.ozj b/src/bin/Data/Interface/Classic/Ok2.ozj new file mode 100644 index 0000000000..5e66f9b4cc Binary files /dev/null and b/src/bin/Data/Interface/Classic/Ok2.ozj differ diff --git a/src/bin/Data/Interface/Classic/Progress.ozj b/src/bin/Data/Interface/Classic/Progress.ozj new file mode 100644 index 0000000000..a58c9e5844 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Progress.ozj differ diff --git a/src/bin/Data/Interface/Classic/Progress_add.ozt b/src/bin/Data/Interface/Classic/Progress_add.ozt new file mode 100644 index 0000000000..a7c846e8de Binary files /dev/null and b/src/bin/Data/Interface/Classic/Progress_add.ozt differ diff --git a/src/bin/Data/Interface/Classic/Progress_back.ozj b/src/bin/Data/Interface/Classic/Progress_back.ozj new file mode 100644 index 0000000000..4b5391d8d7 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Progress_back.ozj differ diff --git a/src/bin/Data/Interface/Classic/Repair_01.ozj b/src/bin/Data/Interface/Classic/Repair_01.ozj new file mode 100644 index 0000000000..8980e2ecdb Binary files /dev/null and b/src/bin/Data/Interface/Classic/Repair_01.ozj differ diff --git a/src/bin/Data/Interface/Classic/Repair_02.ozj b/src/bin/Data/Interface/Classic/Repair_02.ozj new file mode 100644 index 0000000000..87c2210ddb Binary files /dev/null and b/src/bin/Data/Interface/Classic/Repair_02.ozj differ diff --git a/src/bin/Data/Interface/Classic/Sell_01.ozj b/src/bin/Data/Interface/Classic/Sell_01.ozj new file mode 100644 index 0000000000..25d6a1f6fe Binary files /dev/null and b/src/bin/Data/Interface/Classic/Sell_01.ozj differ diff --git a/src/bin/Data/Interface/Classic/Sell_02.ozj b/src/bin/Data/Interface/Classic/Sell_02.ozj new file mode 100644 index 0000000000..3a6ea18288 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Sell_02.ozj differ diff --git a/src/bin/Data/Interface/Classic/Skill.ozj b/src/bin/Data/Interface/Classic/Skill.ozj new file mode 100644 index 0000000000..a15475e2b5 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Skill.ozj differ diff --git a/src/bin/Data/Interface/Classic/Trading_line.ozj b/src/bin/Data/Interface/Classic/Trading_line.ozj new file mode 100644 index 0000000000..be0cf63323 Binary files /dev/null and b/src/bin/Data/Interface/Classic/Trading_line.ozj differ diff --git a/src/bin/Data/Interface/Classic/s1/DuelWindow.OZJ b/src/bin/Data/Interface/Classic/s1/DuelWindow.OZJ new file mode 100644 index 0000000000..61d1d0e031 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s1/DuelWindow.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s1/DuelWindow_add.ozt b/src/bin/Data/Interface/Classic/s1/DuelWindow_add.ozt new file mode 100644 index 0000000000..08b3729329 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s1/DuelWindow_add.ozt differ diff --git a/src/bin/Data/Interface/Classic/s1/Menu03_new.OZJ b/src/bin/Data/Interface/Classic/s1/Menu03_new.OZJ new file mode 100644 index 0000000000..88f2d79eca Binary files /dev/null and b/src/bin/Data/Interface/Classic/s1/Menu03_new.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s1/Quest1.OZJ b/src/bin/Data/Interface/Classic/s1/Quest1.OZJ new file mode 100644 index 0000000000..462535fe63 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s1/Quest1.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s1/Quest2.OZJ b/src/bin/Data/Interface/Classic/s1/Quest2.OZJ new file mode 100644 index 0000000000..8a144eef55 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s1/Quest2.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s1/btn_pshop.OZJ b/src/bin/Data/Interface/Classic/s1/btn_pshop.OZJ new file mode 100644 index 0000000000..d4d396f83f Binary files /dev/null and b/src/bin/Data/Interface/Classic/s1/btn_pshop.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s1/btn_pshop2.OZJ b/src/bin/Data/Interface/Classic/s1/btn_pshop2.OZJ new file mode 100644 index 0000000000..06c1a50adb Binary files /dev/null and b/src/bin/Data/Interface/Classic/s1/btn_pshop2.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s1/menu01_new2.OZJ b/src/bin/Data/Interface/Classic/s1/menu01_new2.OZJ new file mode 100644 index 0000000000..a34d933207 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s1/menu01_new2.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s1/pet1.OZJ b/src/bin/Data/Interface/Classic/s1/pet1.OZJ new file mode 100644 index 0000000000..fc243378d4 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s1/pet1.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s1/pet2.OZJ b/src/bin/Data/Interface/Classic/s1/pet2.OZJ new file mode 100644 index 0000000000..e65df9acd1 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s1/pet2.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s1/text_button.OZJ b/src/bin/Data/Interface/Classic/s1/text_button.OZJ new file mode 100644 index 0000000000..ee6a3b19e5 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s1/text_button.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s1/win_letter.OZJ b/src/bin/Data/Interface/Classic/s1/win_letter.OZJ new file mode 100644 index 0000000000..016ba5ddc3 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s1/win_letter.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s1/win_push.OZJ b/src/bin/Data/Interface/Classic/s1/win_push.OZJ new file mode 100644 index 0000000000..8f7304c30b Binary files /dev/null and b/src/bin/Data/Interface/Classic/s1/win_push.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s2/buy0.OZT b/src/bin/Data/Interface/Classic/s2/buy0.OZT new file mode 100644 index 0000000000..993011bc33 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/buy0.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/buy1.OZT b/src/bin/Data/Interface/Classic/s2/buy1.OZT new file mode 100644 index 0000000000..f20f9f3cc5 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/buy1.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/buy2.OZT b/src/bin/Data/Interface/Classic/s2/buy2.OZT new file mode 100644 index 0000000000..d87620ec08 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/buy2.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/deco4.OZT b/src/bin/Data/Interface/Classic/s2/deco4.OZT new file mode 100644 index 0000000000..83d23aa22a Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/deco4.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/leftmenubt0.OZT b/src/bin/Data/Interface/Classic/s2/leftmenubt0.OZT new file mode 100644 index 0000000000..cbf307c0c1 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/leftmenubt0.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/leftmenubt1.OZT b/src/bin/Data/Interface/Classic/s2/leftmenubt1.OZT new file mode 100644 index 0000000000..13c1f9b0fa Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/leftmenubt1.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/menu01_new.OZJ b/src/bin/Data/Interface/Classic/s2/menu01_new.OZJ new file mode 100644 index 0000000000..c0a5fc5472 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/menu01_new.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s2/menu01_new2_sd.OZJ b/src/bin/Data/Interface/Classic/s2/menu01_new2_sd.OZJ new file mode 100644 index 0000000000..ff1ee7732a Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/menu01_new2_sd.OZJ differ diff --git a/src/bin/Data/Interface/Classic/s2/page0.OZT b/src/bin/Data/Interface/Classic/s2/page0.OZT new file mode 100644 index 0000000000..6d23f7cdb0 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/page0.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/page1.OZT b/src/bin/Data/Interface/Classic/s2/page1.OZT new file mode 100644 index 0000000000..af703f6592 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/page1.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/page2.OZT b/src/bin/Data/Interface/Classic/s2/page2.OZT new file mode 100644 index 0000000000..fe29b67766 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/page2.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/page3.OZT b/src/bin/Data/Interface/Classic/s2/page3.OZT new file mode 100644 index 0000000000..ab3927e7d1 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/page3.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/page4.OZT b/src/bin/Data/Interface/Classic/s2/page4.OZT new file mode 100644 index 0000000000..d038d86542 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/page4.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/page5.OZT b/src/bin/Data/Interface/Classic/s2/page5.OZT new file mode 100644 index 0000000000..1f6eef7297 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/page5.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/return0.OZT b/src/bin/Data/Interface/Classic/s2/return0.OZT new file mode 100644 index 0000000000..89b975e7fd Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/return0.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/return1.OZT b/src/bin/Data/Interface/Classic/s2/return1.OZT new file mode 100644 index 0000000000..7aef7c18ec Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/return1.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/return2.OZT b/src/bin/Data/Interface/Classic/s2/return2.OZT new file mode 100644 index 0000000000..d09cc77c7e Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/return2.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/topmenutabbt0.OZT b/src/bin/Data/Interface/Classic/s2/topmenutabbt0.OZT new file mode 100644 index 0000000000..535bf41987 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/topmenutabbt0.OZT differ diff --git a/src/bin/Data/Interface/Classic/s2/topmenutabbt1.OZT b/src/bin/Data/Interface/Classic/s2/topmenutabbt1.OZT new file mode 100644 index 0000000000..0dec7da2a3 Binary files /dev/null and b/src/bin/Data/Interface/Classic/s2/topmenutabbt1.OZT differ diff --git a/src/bin/Data/Interface/RmlUi/guild_info.rml b/src/bin/Data/Interface/RmlUi/guild_info.rml index d54fb4dfd3..768f2920a1 100644 --- a/src/bin/Data/Interface/RmlUi/guild_info.rml +++ b/src/bin/Data/Interface/RmlUi/guild_info.rml @@ -36,10 +36,11 @@ data-style-font-size="hint_line3.text_px + 'px'">{{hint_line3.text}} - -
-
-
+ +
+
+
-
+
- {{npc_name}} + + {{npc_name}}
{{quest_title}}
diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/README.md b/src/bin/Data/Interface/RmlUi/themes/classic/README.md new file mode 100644 index 0000000000..b85683da0d --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/README.md @@ -0,0 +1,31 @@ +# Classic theme + +The interface of the original 0.97 client, drawn with its own art. + +- **Inherits from `legacy`** (`theme.ini`, `[Theme] Base=legacy`). Ship a window's `.rcss` (or a + `.rml` fork) here only when restyling that window; everything else, tokens included, comes + from `legacy`. +- **Art** is the original files, unconverted: + - `Data/Interface/Classic/` — the 0.97 client's `Data/Interface`; + - `Data/Interface/Classic/099b/` — classic-era files the 0.99b client adds (not in 0.97); + - `Data/Interface/Classic/s1/`, `s2/` — files of the Season 1 and Season 2 clients, which kept + the classic interface, for the parts and windows 0.97 does not have (the bar's thirds with the + command window and friend buttons' boxes and the SD column, the quest, pet and personal shop + buttons, the duel crest, the quest book, Season 1's text button, the Season 2 cash shop's + pieces); + - `Data/Logo/Classic/` — the 0.97 login box and character select art. +- **Paths** are relative to the stylesheet: from a stylesheet here, `../../../Classic/Menu01_new.jpg` + and `../../../../Logo/Classic/0box.jpg`. The engine opens `.jpg` as `.OZJ` and `.tga` as `.OZT`. +- **Sizes**: an `@spritesheet` gives each sprite its real size. + `tools/classic_theme/oz_texture_sizes.py ../../../Classic --recursive` lists them. +- **Derived textures**: where 0.97 tiles or stretches a texture over a known size, the result ships + beside the originals (`Nis_vframe_tall`, `Message_box2_268`, `Message_box2_230`); where the + original drew a texture additively (its black ground vanishing), a copy with that as alpha + (`Progress_add`, `s1/DuelWindow_add`). All built by + `tools/classic_theme/make_classic_derived_textures.py`. +- **C++**: the HUD's extra parts are bound by `UI/HUD/MainFrameExtras`. + +Comments in each stylesheet name the 0.97 client function it follows (its address in `main.exe`) +and the positions in the original 640x480 frame. A window 0.97 does not have follows the Season 1 +or Season 2 client when that client has it (the function's address in that client's `main.exe`), +else it takes the parts of the closest classic window. diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/battle_soccer_score.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/battle_soccer_score.rcss new file mode 100644 index 0000000000..7b506581e0 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/battle_soccer_score.rcss @@ -0,0 +1,64 @@ +/* Classic theme for the guild war / battle soccer score (CBattleSoccerScore). The 0.97 client's + (004bc220): no frame, at the top of the area the open windows leave free, its x 20 + left of that area's centre (the classic workspace centres the 640 frame on it, so x 300): two + rows at y 4 and 19, each the guild mark (8 x 8) at 0, the score at 13 and the name at 30, bold on + a black 50% box, red (255, 60, 0) or blue (0, 150, 255). Legacy's rules first, then the classic + ones. */ + +/* Legacy theme for CBattleSoccerScore, reproducing the original's RenderBackImage()/ + RenderContents(): the 131 x 70 figure-ground back, then two lines from (x + 30, y + 33), 22 apart: + the score, the guild mark at + 21 (8 x 8) and the name at + 33, in the bold font on a 50% black + text box (SetBgColor(0, 0, 0, 128)), red (255, 60, 0) or blue (0, 150, 255). Reference px relative + to the window's top-left, under .screen's W/640 x H/480 stretch (see battle_soccer_score.rml). */ + +@spritesheet bss-back-sheet { src: "../../../newui_Figure_ground.tga"; bss-back: 0px 0px 131px 70px; } + +body { pointer-events: none; } + +.screen { + position: absolute; + left: 0; + top: 0; + width: 640px; + height: 480px; + transform-origin: left top; + pointer-events: none; +} + +#panel { position: absolute; width: 131px; height: 70px; font-family: "token(font-body)"; } +#back { position: absolute; left: 0; top: 0; width: 131px; height: 70px; decorator: image(bss-back); } + +.team { display: block; position: absolute; left: 30px; width: 100px; height: 8px; } +.team-text { + display: block; + position: absolute; + top: 0; + transform-origin: left top; + white-space: nowrap; + font-weight: bold; + color: #0096ff; + background-color: #00000080; +} +.team.red .team-text { color: #ff3c00; } +.team-score { left: 0; } +.team-name { left: 33px; } + +.mark { position: absolute; left: 21px; top: 0; width: 8px; height: 8px; } +.mark-cell { display: block; float: left; width: 1px; height: 1px; } + +/* RenderContents()'s own two rows. The container takes no space. */ +.teams { position: static; } +.team:nth-child(1) { top: 33px; } +.team:nth-child(2) { top: 55px; } + +/* The HUD takes no pointer events where it is placed (base.rcss gives a placed panel them). */ +#panel.slot-placed { pointer-events: none; } + +/* --- Classic ---------------------------------------------------------------------------------- */ +#back { display: none; } +.team { left: 0; } +.team:nth-child(1) { top: 4px; } +.team:nth-child(2) { top: 19px; } +.mark { left: 0; } +.team-score { left: 13px; } +.team-name { left: 30px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/blood_castle_enter.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/blood_castle_enter.rcss new file mode 100644 index 0000000000..3ca2e2e0a9 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/blood_castle_enter.rcss @@ -0,0 +1,8 @@ +/* Classic (0.97) Blood Castle entry. 0.97: "Messenger of Archangel", the description from y 64, + and six plates 140x33 from y 170, 40 apart, tinted (0.7, 0.7, 0.9), labelled in pale blue + (190, 220, 255). MuMain: the description from y 46 to 156, its eight bands from y 160 to 388, + above the Close at 395; more content scrolls. */ +.entry-lines { top: 46px; height: calc(110px * var(--root-scale)); } +.entry-buttons { top: 160px; height: calc(228px * var(--root-scale)); } +.entry-btn.enabled .entry-btn-art { image-color: #b3b3e6; } +.entry-btn.enabled .entry-label { color: rgb(190, 220, 255); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/buff_strip.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/buff_strip.rcss new file mode 100644 index 0000000000..6812fc2adb --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/buff_strip.rcss @@ -0,0 +1,3 @@ +/* Classic (0.97): no buff icons -- 0.97 showed buffs only as their effects on the character. */ + +#strip_slot, #panel { display: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/castle_window.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/castle_window.rcss new file mode 100644 index 0000000000..f445092ec9 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/castle_window.rcss @@ -0,0 +1,367 @@ +/* Classic theme for the Senatus (CCastleWindow). 0.97 has no Castle Siege; the Season 1 client's + (0062e680, docked at x 450): the 0.97 frame, the title bold white at y 15; Season 1's + tab strip: four win_button tabs 40 wide at x 15, 55, 95 and 135 from y 50 (the chosen one 2 + taller and white, the others 0.6 grey with a 1-unit (146, 144, 141) line under them at y 65), + labels bold; no S6 tables. + - Gates (00629120) / statues (0062b830): the heading bold at y 71, senatusmap (160 x 165) at + (15, 83), the gates at (82, 118), (64, 166), (100, 166), (48, 218), (82, 218), (116, 218) and + the statues at (82, 103), (82, 148), (64, 193), (100, 193) with their bars above them; Buy at + (70, 253); built: the figures centred at 253 / 267 (/ 281), Repair at (70, 281) (statue 296), + 0.97's divider (Trading_line) at 305 (317), the upgrade heading bold at 324 (332), the next + figures from x 30 at 348 / 366 (/ 383), the upgrade buttons at x 115, y 345 / 363 / 381. + - Tax (0062d410): the heading at y 72, the two rates on (0.5, 0.6, 0.5) boxes at 50% (140 x 24 + at (20, 87) and (20, 112)) with win_scrollbar's arrows (13 x 13) at x 157, the rates centred + on 175 at 95 and 120, the notes from (20, 140) / (26, 153) / (26, 166), Apply at (70, 181), the + rules bold (187, 123, 148) centred on 160 from x 15 at 201..261, Trading_line at 281, the + castle's zen bold white at 301, Withdraw at (70, 321), the footer at 347 / 359 / 371. + Buttons: Season 1's win_button 49 x 16, grey 0.8 at rest, white under the mouse, 0.6 pressed, + red (1, 0.4, 0.4) locked, labelled (230, 220, 200). The 0.97 Close at (25, 395). Legacy's rules + first, then the classic ones. */ + +/* Legacy theme for CCastleWindow (Senatus), reproducing its RenderFrame(), tabs and pages: the + docked_panel_frame.rcss frame (linked first; newui_item_back01 top), the four newui_guild_tab04 + tabs drawn 40 x 22 (the sprite's left 40 px, one unit apart from (12, 32); the selected one on + its second row, its label white, the others (181, 181, 181)), RenderOutlineUpper() / + RenderOutlineLower()'s newui_item_table01 / 02 / 03 pieces, senatusmap (160 x 165 of 256), + gate_button1 / 2 and suho_button1 / 2 (24 x 24 of 32), newui_myquest_Line (188 x 21), + newui_item_money2 (170 x 24), the boxes and texts in their bound colours, the 53 x 23 + newui_btn_empty_very_small buttons (locked ones tinted (100, 100, 100) with a grey label, never + hovered), the tax arrows (newui_Bt_scroll_up / dn, 15 x 13: up / over / down) at x 158 and the + exit button at (13, 391). Reference px inside #panel. */ + +@spritesheet cw-tab-sheet +{ + src: "../../../newui_guild_tab04.tga"; + cw-tab-up: 0px 0px 40px 22px; + cw-tab-down: 0px 22px 40px 22px; +} +@spritesheet cw-btn-sheet +{ + src: "../../../newui_btn_empty_very_small.tga"; + cw-btn-up: 0px 0px 53px 23px; + cw-btn-over: 0px 23px 53px 23px; + cw-btn-down: 0px 46px 53px 23px; +} +@spritesheet cw-up-sheet +{ + src: "../../../newui_Bt_scroll_up.jpg"; + cw-up-up: 0px 0px 15px 13px; + cw-up-over: 0px 13px 15px 13px; + cw-up-down: 0px 26px 15px 13px; +} +@spritesheet cw-dn-sheet +{ + src: "../../../newui_Bt_scroll_dn.jpg"; + cw-dn-up: 0px 0px 15px 13px; + cw-dn-over: 0px 13px 15px 13px; + cw-dn-down: 0px 26px 15px 13px; +} +@spritesheet cw-tl-sheet { src: "../../../newui_item_table01(L).tga"; cw-tl: 0px 0px 14px 14px; } +@spritesheet cw-tr-sheet { src: "../../../newui_item_table01(R).tga"; cw-tr: 0px 0px 14px 14px; } +@spritesheet cw-bl-sheet { src: "../../../newui_item_table02(L).tga"; cw-bl: 0px 0px 14px 14px; } +@spritesheet cw-br-sheet { src: "../../../newui_item_table02(R).tga"; cw-br: 0px 0px 14px 14px; } +@spritesheet cw-top-sheet { src: "../../../newui_item_table03(Up).tga"; cw-top: 0px 0px 1px 14px; } +@spritesheet cw-bottom-sheet { src: "../../../newui_item_table03(Dw).tga"; cw-bottom: 0px 0px 1px 14px; } +@spritesheet cw-left-sheet { src: "../../../newui_item_table03(L).tga"; cw-left: 0px 0px 14px 1px; } +@spritesheet cw-right-sheet { src: "../../../newui_item_table03(R).tga"; cw-right: 0px 0px 14px 1px; } +@spritesheet cw-map-sheet { src: "../../../senatusmap.jpg"; cw-map: 0px 0px 160px 165px; } +@spritesheet cw-gate-on-sheet { src: "../../../gate_button1.jpg"; cw-gate-on: 0px 0px 24px 24px; } +@spritesheet cw-gate-off-sheet { src: "../../../gate_button2.jpg"; cw-gate-off: 0px 0px 24px 24px; } +@spritesheet cw-statue-on-sheet { src: "../../../suho_button1.jpg"; cw-statue-on: 0px 0px 24px 24px; } +@spritesheet cw-statue-off-sheet { src: "../../../suho_button2.jpg"; cw-statue-off: 0px 0px 24px 24px; } +@spritesheet cw-line-sheet { src: "../../../newui_myquest_Line.tga"; cw-line: 0px 0px 188px 21px; } +@spritesheet cw-money-sheet { src: "../../../newui_item_money2.tga"; cw-money: 0px 0px 170px 24px; } + +.frame-top { decorator: image(docked-bg-top-b); } +#panel { pointer-events: none; } + +.cw-tabs { position: static; } +.cw-tab { position: absolute; top: 32px; width: 40px; height: 22px; pointer-events: auto; decorator: image(cw-tab-up); } +.cw-tab:nth-child(1) { left: 12px; } +.cw-tab:nth-child(2) { left: 53px; } +.cw-tab:nth-child(3) { left: 94px; } +.cw-tab:nth-child(4) { left: 135px; } +.cw-tab.selected { decorator: image(cw-tab-down); } +.cw-tab-label { color: #b5b5b5; } +.cw-tab.selected .cw-tab-label { color: #ffffff; } + +.sharp-text { display: block; position: absolute; white-space: nowrap; text-align: left; pointer-events: none; } + +.cw-btn { display: block; position: absolute; width: 53px; height: 23px; decorator: image(cw-btn-up); pointer-events: auto; } +.cw-btn:hover { decorator: image(cw-btn-over); } +.cw-btn:active { decorator: image(cw-btn-down); } +.cw-btn.locked, .cw-btn.locked:hover, .cw-btn.locked:active { decorator: image(cw-btn-up); image-color: #646464; } +.cw-label { left: 0; text-align: center; color: #ffffff; } +.cw-btn.locked .cw-label { color: #646464; } + +.tax-btn { position: absolute; left: 158px; width: 15px; height: 13px; pointer-events: auto; } +#tax_chaos_up { top: 73px; } +#tax_chaos_down { top: 86px; } +#tax_npc_up { top: 101px; } +#tax_npc_down { top: 114px; } +.tax-up { decorator: image(cw-up-up); } +.tax-up:hover { decorator: image(cw-up-over); } +.tax-up:active { decorator: image(cw-up-down); } +.tax-down { decorator: image(cw-dn-up); } +.tax-down:hover { decorator: image(cw-dn-over); } +.tax-down:active { decorator: image(cw-dn-down); } + +#btn_exit { top: 391px; pointer-events: auto; } + +/* The window's own text. Each line is named, so the theme decides where it sits, what colour it + is and how it is aligned; only its font size stays bound. Its width is reference px times --root-scale. */ +.cw-page, .cw-standing { position: static; } +.cw-heading, .cw-line, .cw-note, .cw-rule { text-align: center; } +.cw-heading { left: 15px; top: 13px; font-weight: bold; } +.cw-line { left: 0; font-weight: bold; } +.cw-note, .cw-rule { left: 15px; } +.cw-rule { font-weight: bold; } +.cw-stat { position: absolute; } +.cw-tab-label { left: 0; text-align: center; } + +/* The gate and statue pages. */ +#map_title { top: 61px; } +#improve_title { top: 294px; } +#stat_hp { left: 20px; top: 246px; } +#stat_defense { left: 20px; top: 259px; } +#stat_recover { left: 20px; top: 272px; } +#next_hp { left: 30px; top: 318px; } +#next_defense { left: 30px; top: 341px; } +#next_recover { left: 30px; top: 364px; } +#btn_buy { left: 68px; top: 250px; } +#btn_repair { left: 110px; top: 260px; } +#btn_hp { left: 110px; top: 310px; } +#btn_defense { left: 110px; top: 334px; } +#btn_recover { left: 110px; top: 358px; } + +/* The tax page. */ +#tax_title { top: 61px; } +#chaos_rate { top: 84px; } +#store_rate { top: 109px; } +#tax_note_1 { top: 162px; } +#tax_note_2 { top: 175px; } +#tax_note_3 { top: 188px; } +#tax_rule_1 { top: 208px; } +#tax_rule_2 { top: 220px; } +#tax_rule_3 { top: 232px; } +#tax_rule_4 { top: 244px; } +#tax_rule_5 { top: 256px; } +#tax_rule_6 { top: 268px; } +#tax_footer_1 { top: 350px; } +#tax_footer_2 { top: 362px; } +#tax_footer_3 { top: 374px; } +.cw-money-text { position: absolute; top: 303px; font-weight: bold; } +#zen_label { left: 14px; } +/* RT3_WRITE_RIGHT_TO_LEFT: the amount ends at x 170. */ +#castle_money { right: 20px; text-align: right; } +#btn_apply { left: 120px; top: 133px; } +#btn_withdraw { left: 120px; top: 322px; } + +/* A table's ten pieces, placed against its own origin; the instance says how tall it is. */ +.cw-table { position: absolute; left: 12px; width: 166px; } +.cw-table > div { position: absolute; } +.cw-table .t-tl { left: 0; top: 0; } +.cw-table .t-tr { left: 152px; top: 0; } +.cw-table .t-top { left: 13px; top: 0; width: 139px; } +.cw-table .t-fill { left: 3px; top: 1px; width: 158px; height: 15px; } +.cw-table .t-left { left: 0; top: 13px; } +.cw-table .t-right { left: 152px; top: 13px; } +.cw-table .t-bottom-inner { left: 3px; top: 7px; width: 158px; } +.cw-table .t-bl { left: 0; } +.cw-table .t-br { left: 152px; } +.cw-table .t-bottom { left: 13px; width: 139px; } + +.table-map { top: 57px; } +.table-map .t-left, .table-map .t-right { height: 165px; } +.table-map .t-bl, .table-map .t-br, .table-map .t-bottom { top: 172px; } +.table-improve { top: 290px; } +.table-improve .t-left, .table-improve .t-right { height: 78px; } +.table-improve .t-bl, .table-improve .t-br, .table-improve .t-bottom { top: 85px; } +.table-tax { top: 57px; } +.table-tax .t-left, .table-tax .t-right { height: 55px; } +.table-tax .t-bl, .table-tax .t-br, .table-tax .t-bottom { top: 62px; } + +.cw-map { position: absolute; left: 15px; top: 73px; width: 160px; height: 165px; } +.cw-separator { position: absolute; left: 1px; top: 278px; width: 188px; height: 21px; } +.cw-money { position: absolute; left: 10px; top: 296px; width: 170px; height: 24px; } +.tax-rate-back { position: absolute; left: 15px; width: 150px; height: 24px; } +.tax-rate-chaos { top: 75px; } +.tax-rate-store { top: 103px; } +.tax-divider { position: absolute; left: 15px; top: 91px; width: 158px; } + +/* The theme places each gate and statue; C++ supplies only live bar lengths. */ +.cw-item { position: absolute; width: 24px; height: 24px; pointer-events: auto; } +.cw-item.item-0 { left: 82px; top: 108px; } +.cw-item.item-1 { left: 64px; top: 156px; } +.cw-item.item-2 { left: 100px; top: 156px; } +.cw-item.item-3 { left: 48px; top: 208px; } +.cw-item.item-4 { left: 82px; top: 208px; } +.cw-item.item-5 { left: 116px; top: 208px; } +.cw-page.statue .cw-item.item-0 { left: 82px; top: 93px; } +.cw-page.statue .cw-item.item-1 { left: 82px; top: 138px; } +.cw-page.statue .cw-item.item-2 { left: 64px; top: 183px; } +.cw-page.statue .cw-item.item-3 { left: 100px; top: 183px; } +.cw-bars { position: static; pointer-events: none; } +.cw-icon { position: absolute; left: 0; top: 0; width: 24px; height: 24px; pointer-events: none; } +.bar { position: absolute; left: 0; height: 3px; } +.bar-gate-hp { top: -10px; } +.bar-gate-def-track, .bar-gate-def { top: -5px; } +.bar-gate-def-track { width: 24px; } +.edge-gate-top { top: -10px; width: 24px; height: 1px; } +.edge-gate-mid { top: -7px; width: 24px; height: 1px; } +.edge-gate-left { top: -10px; width: 1px; } +.edge-gate-right { left: 24px; top: -10px; width: 1px; } +.bar-statue-hp { top: -15px; } +.bar-statue-def { top: -10px; } +.bar-statue-rec { top: -5px; } +.bar-track.bar-statue-def, .bar-track.bar-statue-rec { width: 24px; } + +.cw-icon { decorator: image(cw-gate-off); } +.cw-item.current .cw-icon { decorator: image(cw-gate-on); } +.cw-item.statue .cw-icon { decorator: image(cw-statue-off); } +.cw-item.statue.current .cw-icon { decorator: image(cw-statue-on); } +.cw-map { decorator: image(cw-map); } + +.cw-heading, .cw-line { color: #dcdcdc; } +/* RenderGateManagingTab() turned the figures white and left them so. */ +.cw-stat, #tax_title, #chaos_rate, #store_rate, .cw-note, .cw-money-text { color: #ffffff; } +/* The tax rules kept the original's own 0xFF947BBB, read as an RGBA word. */ +.cw-rule { color: rgb(187, 123, 148); } + +.cw-table .t-tl { width: 14px; height: 14px; decorator: image(cw-tl); } +.cw-table .t-tr { width: 14px; height: 14px; decorator: image(cw-tr); } +.cw-table .t-bl { width: 14px; height: 14px; decorator: image(cw-bl); } +.cw-table .t-br { width: 14px; height: 14px; decorator: image(cw-br); } +.cw-table .t-top { height: 14px; decorator: image(cw-top); } +.cw-table .t-bottom, .cw-table .t-bottom-inner { height: 14px; decorator: image(cw-bottom); } +.cw-table .t-left { width: 14px; decorator: image(cw-left); } +.cw-table .t-right { width: 14px; decorator: image(cw-right); } +.cw-table .t-fill { background-color: rgba(0, 0, 0, 77); } +.tax-divider { height: 14px; decorator: image(cw-bottom); } +.cw-separator { decorator: image(cw-line); } +.cw-money { decorator: image(cw-money); } +.tax-rate-back { background-color: rgba(102, 102, 102, 128); } + +.bar-track { background-color: #ffffff; } +.bar-hp { background-color: #ff0000; } +.bar-defense { background-color: #00ff00; } +.bar-recover { background-color: #ffff00; } +.bar-edge { background-color: #000000; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#heading { width: calc(160px * var(--root-scale)); } +.cw-tab-label { width: calc(40px * var(--root-scale)); } +#map_title { width: calc(190px * var(--root-scale)); } +#improve_title { width: calc(190px * var(--root-scale)); } +.cw-label { width: calc(53px * var(--root-scale)); } +#tax_title { width: calc(190px * var(--root-scale)); } +#chaos_rate { width: calc(175px * var(--root-scale)); } +#store_rate { width: calc(175px * var(--root-scale)); } +#tax_note_1 { width: calc(160px * var(--root-scale)); } +#tax_note_2 { width: calc(160px * var(--root-scale)); } +#tax_note_3 { width: calc(160px * var(--root-scale)); } +#tax_rule_1 { width: calc(160px * var(--root-scale)); } +#tax_rule_2 { width: calc(160px * var(--root-scale)); } +#tax_rule_3 { width: calc(160px * var(--root-scale)); } +#tax_rule_4 { width: calc(160px * var(--root-scale)); } +#tax_rule_5 { width: calc(160px * var(--root-scale)); } +#tax_rule_6 { width: calc(160px * var(--root-scale)); } +#tax_footer_1 { width: calc(160px * var(--root-scale)); } +#tax_footer_2 { width: calc(160px * var(--root-scale)); } +#tax_footer_3 { width: calc(160px * var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet cw-classic-btn-sheet { src: "../../../win_button.tga"; cw-classic-btn: 0px 0px 49px 16px; } +@spritesheet cw-classic-line-sheet { src: ../../../Classic/Trading_line.jpg; cw-classic-line: 0px 0px 190px 10px; } +.cw-heading { top: 15px; color: #ffffff; } + +.cw-tab, .cw-tab.selected { top: 50px; width: 40px; height: 16px; decorator: image(cw-classic-btn fill); image-color: #999999; + box-sizing: border-box; border-bottom: 1px rgb(146, 144, 141); } +.cw-tab:nth-child(1) { left: 15px; } +.cw-tab:nth-child(2) { left: 55px; } +.cw-tab:nth-child(3) { left: 95px; } +.cw-tab:nth-child(4) { left: 135px; } +.cw-tab.selected { top: 48px; height: 18px; image-color: #ffffff; border-bottom-width: 0; } +.cw-tab-label, .cw-tab.selected .cw-tab-label { font-weight: bold; color: #e6dcc8; } + +.cw-table { display: none; } + +/* Gates and statues. */ +#map_title { top: 71px; } +.cw-map { left: 15px; top: 83px; } +.cw-item.item-0 { left: 82px; top: 118px; } +.cw-item.item-1 { left: 64px; top: 166px; } +.cw-item.item-2 { left: 100px; top: 166px; } +.cw-item.item-3 { left: 48px; top: 218px; } +.cw-item.item-4 { left: 82px; top: 218px; } +.cw-item.item-5 { left: 116px; top: 218px; } +.cw-page.statue .cw-item.item-0 { left: 82px; top: 103px; } +.cw-page.statue .cw-item.item-1 { left: 82px; top: 148px; } +.cw-page.statue .cw-item.item-2 { left: 64px; top: 193px; } +.cw-page.statue .cw-item.item-3 { left: 100px; top: 193px; } +.cw-stat#stat_hp, .cw-stat#stat_defense, .cw-stat#stat_recover { left: 0; text-align: center; width: calc(190px * var(--root-scale)); } +#stat_hp { top: 253px; } +#stat_defense { top: 267px; } +#stat_recover { top: 281px; } +/* The upgrade heading's divider (only with the item built): the improve table's fill carries it. */ +.cw-table.table-improve { display: block; left: 0; top: 305px; width: 190px; } +.table-improve > div { display: none; } +.cw-table.table-improve .t-fill { display: block; left: 0; top: 0; width: 190px; height: 10px; background-color: transparent; decorator: image(cw-classic-line); } +.cw-page.statue .cw-table.table-improve { top: 317px; } +#improve_title { top: 324px; } +#next_hp { left: 30px; top: 348px; } +#next_defense { left: 30px; top: 366px; } +#next_recover { left: 30px; top: 383px; } +#btn_buy { left: 70px; top: 253px; } +#btn_repair { left: 70px; top: 281px; } +#btn_hp { left: 115px; top: 345px; } +#btn_defense { left: 115px; top: 363px; } +#btn_recover { left: 115px; top: 381px; } +.cw-page.statue #btn_repair { top: 296px; } +.cw-page.statue #improve_title { top: 332px; } +.cw-page.statue #next_hp { top: 349px; } + +/* Tax. */ +#tax_title { top: 72px; } +.tax-rate-back { left: 20px; width: 140px; height: 24px; background-color: rgba(128, 153, 128, 128); } +.tax-rate-chaos { top: 87px; } +.tax-rate-store { top: 112px; } +.tax-divider { display: none; } +#chaos_rate { top: 95px; } +#store_rate { top: 120px; } +#tax_note_1 { left: 20px; top: 140px; text-align: left; } +#tax_note_2 { left: 26px; top: 153px; text-align: left; } +#tax_note_3 { left: 26px; top: 166px; text-align: left; } +#tax_rule_1 { top: 201px; } +#tax_rule_2 { top: 213px; } +#tax_rule_3 { top: 225px; } +#tax_rule_4 { top: 237px; } +#tax_rule_5 { top: 249px; } +#tax_rule_6 { top: 261px; } +.cw-separator { left: 0; top: 281px; width: 190px; height: 10px; decorator: image(cw-classic-line); } +.cw-money { display: none; } +.cw-money-text { top: 301px; } +#zen_label { left: 14px; } +#castle_money { right: 14px; } +#tax_footer_1 { top: 347px; } +#tax_footer_2 { top: 359px; } +#tax_footer_3 { top: 371px; } +.tax-btn, .tax-btn:hover, .tax-btn:active { left: 157px; width: 13px; height: 13px; } +#tax_chaos_up { top: 87px; } +#tax_chaos_down { top: 99px; } +#tax_npc_up { top: 112px; } +#tax_npc_down { top: 124px; } +.tax-up, .tax-up:hover { decorator: image(docked-scroll-up); } +.tax-down, .tax-down:hover { decorator: image(docked-scroll-down); } +.tax-up:active, .tax-down:active { filter: brightness(0.7); } +#btn_apply { left: 70px; top: 181px; } +#btn_withdraw { left: 70px; top: 321px; } + +.cw-btn, .cw-btn:hover, .cw-btn:active { width: 49px; height: 16px; decorator: image(cw-classic-btn fill); image-color: #cccccc; } +.cw-btn:hover { image-color: #ffffff; } +.cw-btn:active { image-color: #999999; } +.cw-btn.locked, .cw-btn.locked:hover, .cw-btn.locked:active { decorator: image(cw-classic-btn fill); image-color: #ff6666; } +.cw-label, .cw-btn.locked .cw-label { color: #e6dcc8; } +.cw-btn:active .cw-label { margin-left: calc(1px * var(--root-scale)); margin-top: calc(1px * var(--root-scale)); } +.cw-label { width: calc(49px * var(--root-scale)); } +#btn_exit { top: 395px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/catapult.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/catapult.rcss new file mode 100644 index 0000000000..1f66c06794 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/catapult.rcss @@ -0,0 +1,160 @@ +/* Classic theme for the catapult (CCatapultWindow). 0.97 has no Castle Siege; the Season 1 client's + (0043e500, docked at x 450): the 0.97 frame, the title bold (220, 220, 220) centred at + y 12, the three instructions at y 60, 75 and 90, 0.97's divider (Trading_line) at y 110 and 290, + no table; each target a 0.97 item cell (Item_box; InventoryBox2 once chosen) in a 1-unit + (1, 0.8, 0.6) border, tinted that orange under the mouse or chosen, its label bold + (220, 220, 220) centred on it: attack 32 x 32 at (20, 140), (78, 140), (136, 140), defence + 54 x 42 at (20, 140), (115, 140), and the big one 90 x 64 at (50, 200); Fire on a 0.97 text plate + (Message_box, 150 x 48 at (20, 325)), grey (0.5) until a target is chosen, its label 15 under its + top; the 0.97 Close at (20, 395). Legacy's rules first, then the classic ones. */ + +/* Legacy theme for CCatapultWindow, reproducing its RenderFrame()/RenderTexts()/RenderButtons(): + the docked_panel_frame.rcss frame (linked first; newui_item_back01 top), the title and three + lines bold (220, 220, 220) centred on 190 units at y 13 / 50 / 65 / 80, the item table from + (12, 116), the area buttons (newui_Btn_gate 46 x 36, newui_Btn_round 77 x 47: up / over / down), + the chosen one and a locked Shoot tinted (100, 100, 100) with a grey label and never hovered, + Shoot (newui_btn_empty 108 x 29) at (41, 250), the exit button. Reference px inside #panel. */ + +@spritesheet cp-gate-sheet +{ + src: "../../../newui_Btn_gate.tga"; + cp-gate-up: 0px 0px 46px 36px; + cp-gate-over: 0px 36px 46px 36px; + cp-gate-down: 0px 72px 46px 36px; +} +@spritesheet cp-round-sheet +{ + src: "../../../newui_Btn_round.tga"; + cp-round-up: 0px 0px 77px 47px; + cp-round-over: 0px 47px 77px 47px; + cp-round-down: 0px 94px 77px 47px; +} +@spritesheet cp-fire-sheet +{ + src: "../../../newui_btn_empty.tga"; + cp-fire-up: 0px 0px 108px 29px; + cp-fire-over: 0px 29px 108px 29px; + cp-fire-down: 0px 58px 108px 29px; +} +@spritesheet cp-edge-top-sheet { src: "../../../newui_item_table03(Up).tga"; cp-edge-top: 0px 0px 1px 14px; } +@spritesheet cp-edge-bottom-sheet { src: "../../../newui_item_table03(Dw).tga"; cp-edge-bottom: 0px 0px 1px 14px; } +@spritesheet cp-edge-left-sheet { src: "../../../newui_item_table03(L).tga"; cp-edge-left: 0px 0px 14px 1px; } +@spritesheet cp-edge-right-sheet { src: "../../../newui_item_table03(R).tga"; cp-edge-right: 0px 0px 14px 1px; } + +.frame-top { decorator: image(docked-bg-top-b); } +#panel { pointer-events: auto; } + +.sharp-text { display: block; position: absolute; white-space: nowrap; text-align: center; pointer-events: none; } +.cp-title { left: 0; top: 13px; font-weight: bold; color: #dcdcdc; } +.cp-line { left: 0; font-weight: bold; color: #dcdcdc; } +.cp-lines { position: static; } +.cp-line:nth-child(1) { top: 50px; } +.cp-line:nth-child(2) { top: 65px; } +.cp-line:nth-child(3) { top: 80px; } + +.t-edge-top, .t-edge-bottom, .t-edge-left, .t-edge-right, .t-corner { position: absolute; } +.t-edge-top { height: 14px; decorator: image(cp-edge-top); } +.t-edge-bottom { height: 14px; decorator: image(cp-edge-bottom); } +.t-edge-left { width: 14px; decorator: image(cp-edge-left); } +.t-edge-right { width: 14px; decorator: image(cp-edge-right); } +.t-corner { width: 14px; height: 14px; } +.t-tl { decorator: image(docked-corner-tl); } +.t-tr { decorator: image(docked-corner-tr); } +.t-bl { decorator: image(docked-corner-bl); } +.t-br { decorator: image(docked-corner-br); } + +.cp-area { display: block; position: absolute; width: 46px; height: 36px; decorator: image(cp-gate-up); pointer-events: auto; } +.cp-area:hover { decorator: image(cp-gate-over); } +.cp-area:active { decorator: image(cp-gate-down); } +.cp-area.big { width: 77px; height: 47px; decorator: image(cp-round-up); } +.cp-area.big:hover { decorator: image(cp-round-over); } +.cp-area.big:active { decorator: image(cp-round-down); } +.cp-area.locked, .cp-area.locked:hover, .cp-area.locked:active { decorator: image(cp-gate-up); image-color: #646464; } +.cp-area.big.locked, .cp-area.big.locked:hover, .cp-area.big.locked:active { decorator: image(cp-round-up); image-color: #646464; } + +#btn_fire { display: block; position: absolute; left: 41px; top: 250px; width: 108px; height: 29px; decorator: image(cp-fire-up); pointer-events: auto; } +#btn_fire:hover { decorator: image(cp-fire-over); } +#btn_fire:active { decorator: image(cp-fire-down); } +#btn_fire.locked, #btn_fire.locked:hover, #btn_fire.locked:active { decorator: image(cp-fire-up); image-color: #646464; } + +.cp-label { left: 0; color: #ffffff; } +.locked .cp-label { color: #646464; } + +/* The two modes' own target areas (kAttackAreas / kDefenseAreas). A label is centred on its + button, where C++ used to measure the text and halve the remainder. */ +.cp-areas { position: static; } +.cp-area-label { left: 0; text-align: center; } +.cp-areas.attack .cp-area:nth-child(1) { left: 22px; top: 135px; } +.cp-areas.attack .cp-area:nth-child(2) { left: 74px; top: 135px; } +.cp-areas.attack .cp-area:nth-child(3) { left: 126px; top: 135px; } +.cp-areas.attack .cp-area:nth-child(4) { left: 59px; top: 182px; } +.cp-areas.defense .cp-area:nth-child(1) { left: 18px; top: 125px; } +.cp-areas.defense .cp-area:nth-child(2) { left: 97px; top: 125px; } +.cp-areas.defense .cp-area:nth-child(3) { left: 56px; top: 179px; } + +/* The target table's frame, the shape the original drew it as. */ +.t-tl { left: 12px; top: 116px; } +.t-tr { left: 166px; top: 116px; } +.t-edge-top { left: 25px; top: 116px; width: 141px; } +.t-edge-left { left: 12px; top: 129px; height: 100px; } +.t-edge-right { left: 166px; top: 129px; height: 100px; } +.t-bl { left: 12px; top: 223px; } +.t-br { left: 166px; top: 223px; } +.t-edge-bottom { left: 25px; top: 223px; width: 141px; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +.cp-title { width: calc(100% * var(--root-scale)); } +.cp-line { width: calc(100% * var(--root-scale)); } +#btn_fire .cp-label { width: calc(108px * var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet cp-classic-line-sheet { src: ../../../Classic/Trading_line.jpg; cp-classic-line: 0px 0px 190px 10px; } +@spritesheet cp-classic-plate-sheet { src: ../../../Classic/Message_box.jpg; cp-classic-plate: 0px 0px 213px 64px; } +@spritesheet cp-classic-cell-sheet { src: ../../../Classic/Item_box.jpg; cp-classic-cell: 0px 0px 32px 32px; } +@spritesheet cp-classic-cell2-sheet { src: ../../../Classic/Inventorybox2.jpg; cp-classic-cell-chosen: 0px 0px 32px 32px; } +.cp-title { top: 12px; } +.cp-line:nth-child(1) { top: 60px; } +.cp-line:nth-child(2) { top: 75px; } +.cp-line:nth-child(3) { top: 90px; } +.t-edge-top, .t-edge-bottom, .t-edge-left, .t-edge-right, .t-corner { display: none; } +.frame-right, .frame-bottom { display: block; left: 0; width: 190px; height: 10px; decorator: image(cp-classic-line); } +.frame-right { top: 110px; } +.frame-bottom { top: 290px; } + +.cp-area, .cp-area:hover, .cp-area:active, .cp-area.big, .cp-area.big:hover, .cp-area.big:active { + box-sizing: border-box; + border-width: 1px; + border-color: rgb(255, 204, 153); + decorator: image(cp-classic-cell fill); + image-color: #ffffff; +} +.cp-area:hover, .cp-area.big:hover { image-color: rgb(255, 204, 153); } +.cp-area.locked, .cp-area.locked:hover, .cp-area.locked:active, +.cp-area.big.locked, .cp-area.big.locked:hover, .cp-area.big.locked:active { decorator: image(cp-classic-cell-chosen fill); image-color: rgb(255, 204, 153); } +.cp-area-label { font-weight: bold; color: #dcdcdc; } +.locked .cp-area-label { color: #dcdcdc; } +/* The drawn cells, 1 unit larger each way for the border. */ +.cp-area { width: 34px; height: 34px; } +.cp-area.big { width: 92px; height: 66px; } +.cp-areas.attack .cp-area:nth-child(1) { left: 19px; top: 139px; } +.cp-areas.attack .cp-area:nth-child(2) { left: 77px; top: 139px; } +.cp-areas.attack .cp-area:nth-child(3) { left: 135px; top: 139px; } +.cp-areas.attack .cp-area:nth-child(4) { left: 49px; top: 199px; } +.cp-areas.defense .cp-area:nth-child(1), .cp-areas.defense .cp-area:nth-child(2) { width: 56px; height: 44px; } +.cp-areas.defense .cp-area:nth-child(3) { width: 92px; height: 66px; } +/* Each label centred on its own cell (Season 1 centred it on the cell's middle). */ +/* A 120-unit box whose middle is the cell's, so a longer label spills to both sides. */ +.cp-area-label { left: -43px; width: calc(120px * var(--root-scale)); } +.cp-area.big .cp-area-label { left: -14px; } +.cp-areas.defense .cp-area:nth-child(1) .cp-area-label, .cp-areas.defense .cp-area:nth-child(2) .cp-area-label { left: -32px; } +.cp-areas.defense .cp-area:nth-child(3) .cp-area-label { left: -14px; } +.cp-areas.defense .cp-area:nth-child(1) { left: 19px; top: 139px; } +.cp-areas.defense .cp-area:nth-child(2) { left: 114px; top: 139px; } +.cp-areas.defense .cp-area:nth-child(3) { left: 49px; top: 199px; } + +#btn_fire, #btn_fire:hover, #btn_fire:active { left: 20px; top: 325px; width: 150px; height: 48px; decorator: image(cp-classic-plate fill); image-color: #ffffff; } +#btn_fire.locked, #btn_fire.locked:hover, #btn_fire.locked:active { decorator: image(cp-classic-plate fill); image-color: #808080; } +#btn_fire .cp-label { top: 15px; transform-origin: left top; transform: scale(calc(1 / var(--root-scale, 1))); font-weight: bold; color: #ffffff; } +#btn_fire.locked .cp-label { color: #ffffff; } +#btn_fire .cp-label { width: calc(150px * var(--root-scale)); } +#btn_exit { left: 20px; top: 395px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/char_info_balloon.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/char_info_balloon.rcss new file mode 100644 index 0000000000..cf22c7f30b --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/char_info_balloon.rcss @@ -0,0 +1,48 @@ +/* Classic (0.97) labels over the characters: the name above, then "class level", centred on the + projected point (the bottom centre of this 118x54 box, which CCharInfoBalloon places 190 units + over the feet in the classic scene). From the 0.97 client: no guild line, no background art; each line + on a half-transparent box the size of its text. */ + +.balloon { + position: absolute; + width: 118px; + height: 54px; + pointer-events: none; + font-family: "token(font-body)"; + font-size: 13px; +} +.balloon-bg, .balloon-guild { + display: none; +} +.balloon-name, .balloon-class { + position: absolute; + left: 59px; + transform: translateX(-50%); + white-space: nowrap; + padding: 0 2px; +} +.balloon-class { + top: 54px; + color: #ffffff; + background-color: rgba(0, 0, 0, 128); +} +/* Name colour by control status, as the 0.97 client: normal light blue on black; blocked + character on yellow, blocked items on cyan, operator on blue (black text). */ +.balloon-name { + top: 35px; + font-weight: bold; + color: #b4c8ff; + background-color: rgba(0, 0, 0, 128); +} +.balloon-name.name-blocked-character { + color: #000000; + background-color: rgba(255, 255, 0, 128); +} +.balloon-name.name-blocked-items { + color: #000000; + background-color: rgba(0, 255, 255, 128); +} +.balloon-name.name-operator { + color: #000000; + background-color: rgba(0, 0, 255, 128); +} diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/char_make.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/char_make.rcss new file mode 100644 index 0000000000..618653b992 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/char_make.rcss @@ -0,0 +1,167 @@ +/* Classic (0.97) NEW CHARACTER window. From the 0.97 client: New_Character01 (213x256) over + New_Character02 (213x119), centred at the top (x = 214, y = 11 of 640x480), dropping in; + positions below are in the window's own pixels. 1 original pixel = 1/480 of the screen height. + The text does not stretch with the art: 0.97 drew its font at screen pixels inside the stretched + frame, so it is 13rem, 13 px growing like the native text (the body is "scene-window-scale", + RmlNativeText.h). */ + +@spritesheet classic-charmake-top-sheet +{ + src: ../../../../Logo/Classic/New_character01.tga; + classic-charmake-top: 0px 0px 213px 256px; +} +@spritesheet classic-charmake-bottom-sheet +{ + src: ../../../../Logo/Classic/New_character02.tga; + classic-charmake-bottom: 0px 0px 213px 119px; +} +@spritesheet classic-charmake-arrow-previous-sheet +{ + src: ../../../../Logo/Classic/New_character001.jpg; + classic-arrow-previous: 0px 0px 20px 19px; +} +@spritesheet classic-charmake-arrow-next-sheet +{ + src: ../../../../Logo/Classic/New_character002.jpg; + classic-arrow-next: 0px 0px 20px 19px; +} +@spritesheet classic-charmake-arrow-previous2-sheet +{ + src: ../../../../Logo/Classic/New_character003.jpg; + classic-arrow-previous2: 0px 0px 20px 18px; +} +@spritesheet classic-charmake-arrow-next2-sheet +{ + src: ../../../../Logo/Classic/New_character004.jpg; + classic-arrow-next2: 0px 0px 20px 18px; +} +@spritesheet classic-charmake-cancel-sheet +{ + src: ../../../../Logo/Classic/New_character_cancel.jpg; + classic-charmake-cancel: 0px 0px 72px 21px; +} +@spritesheet classic-charmake-ok-sheet +{ + src: ../../../../Logo/Classic/New_character_ok.jpg; + classic-charmake-ok: 0px 0px 72px 21px; +} + +/* Drops from above the screen to y = 11 (0.52 s in 0.97). */ +@keyframes classic-charmake-drop +{ + from { transform: translateY(-72%); } + to { transform: translateY(0%); } +} + +body { + width: 100%; + height: 100%; + margin: 0; + pointer-events: none; + --px: calc(100vh / 480); +} + +#panel { + position: absolute; + width: 0; + height: 0; +} + +#classic_window { + position: absolute; + left: 50%; + top: calc(11 * var(--px)); + width: calc(213 * var(--px)); + height: calc(375 * var(--px)); + margin-left: calc(-106.5 * var(--px)); + font-family: "token(font-body)"; + font-size: 13rem; + color: #ffffff; + pointer-events: auto; + animation: 0.5s cubic-out 1 classic-charmake-drop; +} +.window-top { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: calc(256 * var(--px)); + decorator: image(classic-charmake-top); +} +.window-bottom { + position: absolute; + left: 0; + top: calc(256 * var(--px)); + width: 100%; + height: calc(119 * var(--px)); + decorator: image(classic-charmake-bottom); +} + +/* 3D portrait, drawn by C++ into a render target the size of this box (74x79 at (71, 90)). */ +#preview { + position: absolute; + left: calc(71 * var(--px)); + top: calc(90 * var(--px)); + width: calc(74 * var(--px)); + height: calc(79 * var(--px)); +} + +.char-make-name-field { + position: absolute; + left: calc(71 * var(--px)); + top: calc(178 * var(--px)); + width: calc(73 * var(--px)); + height: calc(16 * var(--px)); + padding: 0; + color: #ffe6d2; + background-color: transparent; + border-width: 0; + box-shadow: none; + decorator: none; +} + +.class-name { + position: absolute; + left: calc(71 * var(--px)); + top: calc(198 * var(--px)); + white-space: nowrap; +} + +/* Arrows: the pressed art shows only while the button is held; at the first / last class the + arrow is covered in black (80%), as in 0.97. */ +.arrow { + position: absolute; + width: calc(20 * var(--px)); + height: calc(19 * var(--px)); + cursor: pointer; +} +.arrow-previous { left: calc(149 * var(--px)); top: calc(196 * var(--px)); } +.arrow-next { left: calc(170 * var(--px)); top: calc(196 * var(--px)); } +.arrow-previous:active { decorator: image(classic-arrow-previous); } +.arrow-next:active { decorator: image(classic-arrow-next); } +.arrow.blocked { + background-color: rgba(0, 0, 0, 204); + pointer-events: none; +} +.arrow-row2 { + top: calc(215 * var(--px)); + height: calc(18 * var(--px)); +} +.arrow-previous-row2 { left: calc(149 * var(--px)); } +.arrow-next-row2 { left: calc(170 * var(--px)); } +.arrow-previous-row2:active { decorator: image(classic-arrow-previous2); } +.arrow-next-row2:active { decorator: image(classic-arrow-next2); } + +/* CANCEL and OK are part of the art; the plate lights up under the mouse. */ +.btn { + position: absolute; + top: calc(349 * var(--px)); + width: calc(72 * var(--px)); + height: calc(21 * var(--px)); + cursor: pointer; + decorator: none; +} +.btn-cancel { left: calc(21 * var(--px)); } +.btn-ok { left: calc(121 * var(--px)); } +.btn-cancel:hover, .btn-cancel:active { decorator: image(classic-charmake-cancel); } +.btn-ok:hover, .btn-ok:active { decorator: image(classic-charmake-ok); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/char_make.rml b/src/bin/Data/Interface/RmlUi/themes/classic/char_make.rml new file mode 100644 index 0000000000..73d14b8fd6 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/char_make.rml @@ -0,0 +1,37 @@ + + + Character Creation + + + + + +
+
+
+
+ + + + + +
{{job.label}}
+
+
+
+
+ +
+
+
+ +
diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/char_sel_main.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/char_sel_main.rcss new file mode 100644 index 0000000000..824e394dee --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/char_sel_main.rcss @@ -0,0 +1,187 @@ +/* Classic (0.97) character select frame and plates. From the 0.97 client. The 0.97 client stretches this 2D layer + with the window (x by width/640, y by height/480); so does this sheet, in percentages of the + 640x480 layout: the frame reaches the screen edges in 16:9, as in the current client. */ + +@spritesheet classic-charsel-frame-sheet-top +{ + src: ../../../../Logo/Classic/Interface01.tga; + classic-frame-top: 0px 0px 256px 86px; +} +@spritesheet classic-charsel-frame-sheet-upper +{ + src: ../../../../Logo/Classic/Interface02.tga; + classic-frame-column-upper: 0px 0px 64px 256px; +} +@spritesheet classic-charsel-frame-sheet-lower +{ + src: ../../../../Logo/Classic/Interface03.tga; + classic-frame-column-lower: 0px 0px 64px 224px; +} +@spritesheet classic-charsel-frame-sheet-base +{ + src: ../../../../Logo/Classic/Interface04.tga; + classic-frame-base: 0px 0px 256px 32px; +} +@spritesheet classic-charsel-create-sheet +{ + src: ../../../../Logo/Classic/New_character201.tga; + classic-plate-create: 0px 0px 199px 109px; +} +@spritesheet classic-charsel-create-hover-sheet +{ + src: ../../../../Logo/Classic/New_character202.jpg; + classic-plate-create-hover: 0px 0px 70px 25px; +} +@spritesheet classic-charsel-delete-sheet +{ + src: ../../../../Logo/Classic/Delete01.tga; + classic-plate-delete: 0px 0px 205px 88px; +} +@spritesheet classic-charsel-delete-hover-sheet +{ + src: ../../../../Logo/Classic/Delete02.jpg; + classic-plate-delete-hover: 0px 0px 70px 19px; +} +@spritesheet classic-charsel-ok-sheet +{ + src: ../../../../Logo/Classic/Ok01.tga; + classic-plate-ok: 0px 0px 205px 88px; +} +@spritesheet classic-charsel-ok-hover-sheet +{ + src: ../../../../Logo/Classic/Ok02.jpg; + classic-plate-ok-hover: 0px 0px 70px 19px; +} + +/* The NEW CHARACTER plate drops in from above the frame when the screen opens (-100 -> 4 of 480). */ +@keyframes classic-plate-drop +{ + from { transform: translateY(-95%); } + to { transform: translateY(0%); } +} + +body { + width: 100%; + height: 100%; + margin: 0; + pointer-events: none; +} + +/* ---- Frame: left halves are the right ones mirrored. ---- */ +#classic_frame { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + pointer-events: none; +} +.frame { position: absolute; } +.frame-top { top: 0; height: 17.9167%; width: 40%; } +.frame-base { top: 93.3333%; height: 6.6667%; width: 40%; } +.frame-top.frame-left, .frame-base.frame-left { left: 10%; } +.frame-top.frame-right, .frame-base.frame-right { left: 50%; } +.frame-column-upper { top: 0; height: 53.3333%; width: 10%; } +.frame-column-lower { top: 53.3333%; height: 46.6667%; width: 10%; } +.frame-column-upper.frame-left, .frame-column-lower.frame-left { left: 0; } +.frame-column-upper.frame-right, .frame-column-lower.frame-right { left: 90%; } + +.frame-top.frame-right { decorator: image(classic-frame-top); } +.frame-top.frame-left { decorator: image(classic-frame-top flip-horizontal); } +.frame-column-upper.frame-right { decorator: image(classic-frame-column-upper); } +.frame-column-upper.frame-left { decorator: image(classic-frame-column-upper flip-horizontal); } +.frame-column-lower.frame-right { decorator: image(classic-frame-column-lower); } +.frame-column-lower.frame-left { decorator: image(classic-frame-column-lower flip-horizontal); } +.frame-base.frame-right { decorator: image(classic-frame-base); } +.frame-base.frame-left { decorator: image(classic-frame-base flip-horizontal); } + +/* ---- Plates ---- */ +#panel { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + pointer-events: none; +} +.plate { + position: absolute; + pointer-events: none; +} +.plate.hidden { + display: none; +} +.hotspot { + position: absolute; + cursor: pointer; + pointer-events: auto; +} +.hotspot.disabled { + pointer-events: none; +} + +/* NEW CHARACTER: 199x109 at (221, 4); the word at (286, 79), 70x25. Dimmed when the account is + full. */ +.plate-create { + left: 34.5313%; + top: 0.8333%; + width: 31.0938%; + height: 22.7083%; + decorator: image(classic-plate-create); + animation: 0.45s cubic-out 1 classic-plate-drop; +} +.plate-create.disabled { + filter: brightness(0.5); +} +.plate-create .hotspot { + left: 32.6633%; + top: 68.8073%; + width: 35.1759%; + height: 22.9358%; +} +.plate-create .hotspot:hover { + decorator: image(classic-plate-create-hover); +} + +/* DELETE (left) and OK (right): 205x88 at (-2, 116) and (436, 116); the words at (126, 148) and + (443, 148), 70x19. */ +.plate-delete, .plate-connect { + top: 24.1667%; + width: 32.0313%; + height: 18.3333%; +} +.plate-delete { + left: -0.3125%; + decorator: image(classic-plate-delete); +} +.plate-connect { + left: 68.125%; + decorator: image(classic-plate-ok); +} +.plate-delete .hotspot, .plate-connect .hotspot { + top: 36.3636%; + width: 34.1463%; + height: 21.5909%; +} +.plate-delete .hotspot { left: 62.439%; } +.plate-connect .hotspot { left: 3.4146%; } +.plate-delete .hotspot:hover { decorator: image(classic-plate-delete-hover); } +.plate-connect .hotspot:hover { decorator: image(classic-plate-ok-hover); } + +/* Account with item-blocked characters: two lines centred at x = 320, y = 330 and 348 of 480, + black on half-transparent cyan. */ +#account_block_message { + position: absolute; + left: 0; + top: 68.75%; + width: 100%; + text-align: center; + pointer-events: none; +} +#account_block_message.hidden { + display: none; +} +.line { + color: #000000; + background-color: rgba(0, 255, 255, 128); +} diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/char_sel_main.rml b/src/bin/Data/Interface/RmlUi/themes/classic/char_sel_main.rml new file mode 100644 index 0000000000..413d738d0c --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/char_sel_main.rml @@ -0,0 +1,44 @@ + + + Character Select Bar + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
{{account_block_line1}}
+
{{account_block_line2}}
+
+ +
diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/character_info.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/character_info.rcss new file mode 100644 index 0000000000..e25da6dec3 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/character_info.rcss @@ -0,0 +1,180 @@ +/* Classic (0.97) character information window (C). From the 0.97 client: the name at the top, class and server + crossfading under it, the level in the first Level_box, the experience and spare points on dark + strips, the four stats each in a Level_box (75x21, every 60 units from y 116) with their derived + lines under it, the "+" buttons (level_01) at x 125 while there are points to spend, and the + points on a blue box. The frame and Close button come from docked_panel_frame.rcss. Text leaves + are counter-scaled (base.rcss): a width inside one is the reference width times --root-scale. */ + +@spritesheet chainfo-classic-box-sheet { src: ../../../Classic/Level_box.jpg; chainfo-classic-box: 0px 0px 75px 21px; } +@spritesheet chainfo-classic-plus-sheet { src: ../../../Classic/Level_01.jpg; chainfo-classic-plus: 0px 0px 24px 24px; } +@spritesheet chainfo-classic-plus2-sheet { src: ../../../Classic/Level_02.jpg; chainfo-classic-plus-pressed: 0px 0px 24px 24px; } + +.frame-top { decorator: image(docked-bg-top-a); } + +/* Name (0.97: a 120-wide box at x 35, y 12), class / server under it (x 22, y 22, 150 wide). */ +#name, #classname, #servername { + position: absolute; + left: 0; + width: calc(190px * var(--root-scale)); + text-align: center; + transform-origin: left top; + font-weight: bold; + pointer-events: none; +} +#name { top: 12px; } +#classname, #servername { top: 24px; color: #ffffff; } +#name.pk-0 { color: rgb(150, 255, 240); } +#name.pk-1 { color: rgb(100, 120, 255); } +#name.pk-2 { color: rgb(140, 180, 255); } +#name.pk-3 { color: rgb(200, 220, 255); } +#name.pk-4 { color: rgb(255, 150, 60); } +#name.pk-5 { color: rgb(255, 80, 30); } +#name.pk-6 { color: rgb(255, 0, 0); } + +/* The S6 summary frame is not in 0.97; its fill becomes the level's Level_box at (13, 56). */ +.summary-corner, .summary-edge, .point-probability-text { display: none; } +.summary-fill { + position: absolute; + left: 13px; + top: 56px; + width: 75px; + height: 21px; + decorator: image(chainfo-classic-box); + pointer-events: none; +} + +.level-text, .levelup-point-text, .exp-text, .point-text { + display: block; + position: absolute; + transform-origin: left top; + white-space: nowrap; + pointer-events: none; +} +/* Level at y 60, light grey: 0.97 centred it in its box; MuMain's text is longer (it adds the + resets), so it starts at the box's left instead. */ +.level-text { left: 17px; top: 60px; color: #e6e6e6; } +/* Points to spend: black on a blue box, 80 wide centred at (95, 50). */ +.levelup-point-text { + left: 95px; + top: 50px; + width: calc(80px * var(--root-scale)); + text-align: center; + color: #000000; + background-color: #1e6ec8; +} +.levelup-point-text.hidden { display: none; } +/* Experience (24, 80) white and spare points (24, 95) blue, on half-black strips. */ +.exp-text { left: 24px; top: 80px; color: #ffffff; background-color: rgba(0, 0, 0, 128); } +.point-text { left: 24px; top: 95px; color: #6496ff; background-color: rgba(0, 0, 0, 128); } + +/* Stats: Strength 116, Agility 176, Vitality 236, Energy 296 (boxes); the name on the left and + the value on the right of the box, in 0.97's gold; Command (Dark Lord) below them. */ +.attr-textbox { + position: absolute; + left: 13px; + width: 75px; + height: 21px; + decorator: image(chainfo-classic-box); + pointer-events: none; +} +.attr-textbox-str { top: 116px; } +.attr-textbox-agi { top: 176px; } +.attr-textbox-vit { top: 236px; } +.attr-textbox-ene { top: 296px; } +/* Command, the Dark Lord's fifth stat (shown only while the C++ says so, show_charisma): 0.97 has + no Dark Lord; the Season 1 client (005c3a40) draws one more box for class 4, 60 below Energy, + at y 356, its text and + button in step with the others. */ +.attr-textbox-cmd { top: 356px; } +.attr-textbox-cmd.hidden, .stat-btn-cmd.hidden { display: none; } + +.attr-label, .attr-value { + display: block; + position: absolute; + transform-origin: left top; + white-space: nowrap; + font-weight: bold; + color: #dfbf67; + pointer-events: none; +} +.attr-label { left: 17px; } +.attr-value { left: 13px; width: calc(71px * var(--root-scale)); text-align: right; } +.attr-label-str, .attr-value-str { top: 120px; } +.attr-label-agi, .attr-value-agi { top: 180px; } +.attr-label-vit, .attr-value-vit { top: 240px; } +.attr-label-ene, .attr-value-ene { top: 300px; } +.attr-label-cmd, .attr-value-cmd { top: 360px; } +.attr-value.attr-boosted, .attr-label.attr-boosted { color: rgb(100, 150, 255); } +.attr-value.attr-potion, .attr-label.attr-potion { color: rgb(255, 120, 0); } +.levelup-point-text.hidden, .attr-label.hidden, .attr-value.hidden { display: none; } + +/* Derived lines under each stat, white on half-black strips: Strength's from y 140, Agility's from + 200, Vitality's from 260, Energy's from 320. 0.97 set its one or two lines 15 apart; MuMain lists + up to three (attack rate, defence rate) in the 36 between a block's first line and the next box, + so the rows are 12: three of them end on that box at any panel scale. The rows follow the panel + while the text keeps its native size, so a taller row ran the third line onto the box where the + panel is smaller than the text (75% at 800x600). */ +.attr-lines { position: absolute; left: 24px; transform-origin: left top; pointer-events: none; } +.attr-lines span { display: block; white-space: nowrap; color: #ffffff; background-color: rgba(0, 0, 0, 128); } +.attr-lines span.boosted { color: rgb(100, 150, 255); } +.attr-lines span.buffed { color: rgb(255, 0, 240); } +.attr-lines-str { top: 140px; } +.attr-lines-agi { top: 200px; } +.attr-lines-vit { top: 260px; } +.attr-lines-ene { top: 320px; } +.attr-lines.attr-lines-str span { height: calc(12px * var(--root-scale)); } +.attr-lines.attr-lines-agi span { height: calc(12px * var(--root-scale)); } +.attr-lines.attr-lines-vit span { height: calc(12px * var(--root-scale)); } +.attr-lines.attr-lines-ene span { height: calc(12px * var(--root-scale)); } + +/* "+" (24x24 at x 125, beside each box), the second image while pressed. */ +.stat-btn { + position: absolute; + left: 125px; + width: 24px; + height: 24px; + decorator: image(chainfo-classic-plus); + cursor: pointer; + pointer-events: auto; +} +.stat-btn:active { decorator: image(chainfo-classic-plus-pressed); } +.stat-btn-str { top: 115px; } +.stat-btn-agi { top: 175px; } +.stat-btn-vit { top: 235px; } +.stat-btn-ene { top: 295px; } +.stat-btn-cmd { top: 355px; } + +/* The classic clients have no Master Level shortcut (Close shares .info-btn and stays). */ +.info-btn-masterlevel { display: none; } + +/* The Season 1 client's pet button (00421e40): pet1 (24x24) at (85, 395), beside Close, while the + character window is open; pet2 pressed. It opens the pet window. */ +@spritesheet chainfo-classic-pet-sheet { src: ../../../Classic/s1/pet1.jpg; chainfo-classic-pet: 0px 0px 24px 24px; } +@spritesheet chainfo-classic-pet2-sheet { src: ../../../Classic/s1/pet2.jpg; chainfo-classic-pet-pressed: 0px 0px 24px 24px; } +.info-btn-pet { + position: absolute; + left: 85px; + top: 395px; + width: 24px; + height: 24px; + cursor: pointer; + pointer-events: auto; + decorator: image(chainfo-classic-pet); +} +.info-btn-pet:active { decorator: image(chainfo-classic-pet-pressed); } + +/* The Season 1 client's quest button (00419f90): Quest1 (24x24) at (55, 395), between Close and the + pet button; Quest2 pressed. It opens the quest window. */ +@spritesheet chainfo-classic-quest-sheet { src: ../../../Classic/s1/Quest1.jpg; chainfo-classic-quest: 0px 0px 24px 24px; } +@spritesheet chainfo-classic-quest2-sheet { src: ../../../Classic/s1/Quest2.jpg; chainfo-classic-quest-pressed: 0px 0px 24px 24px; } +.info-btn-quest { + position: absolute; + left: 55px; + top: 395px; + width: 24px; + height: 24px; + cursor: pointer; + pointer-events: auto; + decorator: image(chainfo-classic-quest); +} +.info-btn-quest:active { decorator: image(chainfo-classic-quest-pressed); } +.btn-exit-label { display: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/chat_command.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/chat_command.rcss new file mode 100644 index 0000000000..4207e5449b --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/chat_command.rcss @@ -0,0 +1,102 @@ +/* Classic theme for the chat commands window (CChatCommandWindow, J). No classic client has it; on + the classic docked frame it takes the classic windows' parts: its two buttons on a 0.97 text plate + (Message_box, squashed to their 64x29) lit warm under the mouse, in place of S6's + newui_btn_empty_small. Legacy's layout and comments below. */ + +/* Legacy theme for CChatCommandWindow, reproducing its RenderBaseWindow()/pages/buttons: the + docked_panel_frame.rcss frame (linked first; newui_item_back01 top) stretched to the full dock + height (432); the texts left-aligned in their boxes in their own colours (bound), the title bold + and centred; each parameter value in a black box at alpha 160; the value field transparent, its text + (255, 255, 230) at alpha 210; the 64 x 29 left and right buttons (newui_btn_empty_small up / + over / down) at y 358 with a white label; the exit button. Reference px inside #panel. */ + +@spritesheet cc-btn-sheet +{ + src: "../../../newui_btn_empty_small.tga"; + cc-btn-up: 0px 0px 64px 29px; + cc-btn-over: 0px 29px 64px 29px; + cc-btn-down: 0px 58px 64px 29px; +} + +.frame-top { decorator: image(docked-bg-top-b); } +#panel { height: 432px; pointer-events: auto; } + +.sharp-text { display: block; position: absolute; white-space: nowrap; text-align: left; pointer-events: none; } +.cc-btn { + display: block; + position: absolute; + top: 358px; + width: 64px; + height: 29px; + decorator: image(cc-btn-up); + pointer-events: auto; +} +.cc-btn:hover { decorator: image(cc-btn-over); } +.cc-btn:active { decorator: image(cc-btn-down); } +#btn_left { left: 22px; } +#btn_right { left: 104px; } +.cc-label { left: 0; text-align: center; color: #ffffff; } + +/* The original's grid: the rows start at CONTENT_TOP, one ROW_HEIGHT apart; on the parameter page a + blank row comes before the parameters (35 apart: name, value box, gap) and before the actions. */ +.cc-page, .cc-rows { display: block; position: absolute; left: 22px; top: 36px; width: 146px; } +.cc-title, .cc-line, .cc-cell, .cc-row-line, .cc-param-label, .cc-param-value, .cc-remove-mark { + position: absolute; +} +.cc-title { left: 0; top: 12px; text-align: center; font-weight: bold; } +#cc_empty { left: 22px; top: 36px; } + +.cc-row, .cc-line-box { display: block; position: relative; height: 15px; } +.cc-row { pointer-events: auto; } +.cc-row-line, .cc-cell { left: 0; top: 0; } + +.cc-parameters, .cc-actions { display: block; padding-top: 15px; } +.cc-parameter { display: block; position: relative; height: 35px; } +.cc-param-label { left: 0; top: 0; } +.cc-value-box { position: absolute; left: 0; top: 15px; width: 146px; height: 16px; pointer-events: auto; } +.cc-param-value { left: 2px; top: 16px; } +.cc-value-field { position: absolute; left: 2px; top: 16px; } + +/* A template's label takes the row less the remove cell, which sits at its right edge. */ +.cc-template-hit { position: absolute; left: 0; top: 0; width: 131px; height: 15px; pointer-events: auto; } +.cc-template-label { left: 0; } +.cc-template-remove { position: absolute; left: 131px; top: 0; width: 15px; height: 15px; pointer-events: auto; } +.cc-remove-mark { left: 0; text-align: center; } + +/* The original's own TextColor table (ChatCommandWindow.cpp). */ +.cc-title { color: rgb(255, 220, 120); } +.cc-line, .cc-cell, .cc-param-label { color: rgb(220, 220, 220); } +.cc-row.favourite .cc-cell { color: rgb(255, 220, 120); } +.cc-row-line { color: rgb(200, 220, 255); } +.cc-param-label.missing { color: rgb(255, 150, 150); } +.cc-param-value { color: rgb(220, 220, 220); } +.cc-param-value.placeholder { color: rgb(200, 220, 255); } +.cc-action .cc-cell { color: rgb(150, 210, 255); } +.cc-remove-mark { color: rgb(255, 150, 150); } +.cc-value-box { background-color: rgba(0, 0, 0, 160); } +/* CUITextInputBox::SetTextColor(255, 255, 230, 210) -- used to arrive as a model colour. */ +.cc-value-field { + color: rgba(255, 255, 230, 210); + padding: 0; + border-width: 0; + border-radius: 0; + background-color: transparent; + pointer-events: auto; +} + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#cc_title { width: calc(100% * var(--root-scale)); } +#cc_empty { width: calc(146px * var(--root-scale)); } +.cc-cell { width: calc(146px * var(--root-scale)); } +.cc-row-line { width: calc(146px * var(--root-scale)); } +.cc-param-label { width: calc(146px * var(--root-scale)); } +.cc-param-value { width: calc(142px * var(--root-scale)); } +.cc-value-field { width: calc(142px * var(--root-scale)); height: calc(14px * var(--root-scale)); line-height: calc(14px * var(--root-scale)); } +.cc-cell.cc-template-label { width: calc(131px * var(--root-scale)); } +.cc-remove-mark { width: calc(15px * var(--root-scale)); } +.cc-label { width: calc(64px * var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet cc-classic-plate-sheet { src: ../../../Classic/Message_box.jpg; cc-classic-plate: 0px 0px 213px 64px; } +.cc-btn, .cc-btn:hover, .cc-btn:active { decorator: image(cc-classic-plate fill); } +.cc-btn:hover, .cc-btn:active { image-color: #ffd9b3; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/chat_input.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/chat_input.rcss new file mode 100644 index 0000000000..95f8ce2ab3 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/chat_input.rcss @@ -0,0 +1,74 @@ +/* Classic (0.97) chat input: the box 0.97 opened with Enter (004be4f0) -- dialogue1 + dialogue2 + (133x29 each, drawn 134 wide), 268x29, centred above the bar by the classic workspace.rcss; the message field + at (5, 7), 180 wide, and the whisper target at (190, 7), 50 wide (0.97's 191 and 376 in the + 640x480 frame). 0.97 has no chat-type or filter buttons: party and guild chat took a prefix. */ + +@spritesheet classic-chat-left-sheet { src: ../../../Classic/Dialogue1.jpg; classic-chat-left: 0px 0px 133px 29px; } +@spritesheet classic-chat-right-sheet { src: ../../../Classic/Dialogue2.jpg; classic-chat-right: 0px 0px 133px 29px; } + +#panel.workspace-placed { bottom: auto; transform-origin: left top; } +#panel { + position: absolute; + left: 50%; + bottom: 51dp; + margin-left: -134dp; + width: 268dp; + height: 29dp; + font-family: "token(font-body)"; + font-size: 1rem; + /* The bar takes the pointer, so a click on it never walks the character (legacy's rule: the + C++ asks IsPointerOver()). The two halves below take none, so the click lands here. */ + pointer-events: auto; +} +#panel.workspace-placed { margin-left: 0; } + +/* The two halves of the box are drawn by the first two (S6) chat-type buttons, the rest hidden. */ +.cib-btn { display: none; } +#btn_type_0, #btn_type_1 { + display: block; + position: absolute; + top: 0; + width: 134dp; + height: 29dp; + cursor: auto; + pointer-events: none; +} +#btn_type_0 { left: 0; decorator: image(classic-chat-left); } +#btn_type_1 { left: 134dp; decorator: image(classic-chat-right); } + +.cib-chat-field { + position: absolute; + left: 5dp; + top: 7dp; + width: 180dp; + height: 14dp; + font-size: 11dp; + color: rgb(255, 230, 210); + background-color: transparent; + border: 0 transparent; +} +.cib-whisper-field { + position: absolute; + left: 190dp; + top: 7dp; + width: 50dp; + height: 14dp; + font-size: 11dp; + color: rgb(200, 200, 200); + background-color: transparent; + border: 0 transparent; +} +.cib-whisper-field:disabled { + color: rgba(255, 255, 255, 100); + background-color: transparent; +} +/* Whispering off: the target dimmed under a red wash, as in legacy. */ +#whisper_block { + position: absolute; + left: 188dp; + top: 5dp; + width: 54dp; + height: 18dp; + background-color: rgba(128, 51, 51, 51); + pointer-events: none; +} diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/chat_log.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/chat_log.rcss new file mode 100644 index 0000000000..227d099f49 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/chat_log.rcss @@ -0,0 +1,203 @@ +/* Classic (0.97) chat log: no window, the messages at the top-left corner from y 13, each line on + a strip the size of its text, coloured by type as 0.97's RenderMessages (00480980) coloured + them. The workspace + (classic workspace.rcss) puts the window at the top-left corner. With the frame on (F5) it + becomes 0.97's "nis" window there (end of this file). */ + +#panel.workspace-placed { transform-origin: left top; } +#panel { + position: absolute; + left: 0; + top: 0; + width: 281dp; + font-family: "token(font-body)"; + font-size: 1rem; + pointer-events: none; +} + +/* The window fill, split three ways: whether it paints at all is frame state (.framed, native's + own RenderBackground() m_bShowFrame guard), how opaque it is comes from the user's cycled + transparency setting as a bound opacity, and its whole appearance is this rule's. #chat_backdrop sits + behind #lines so the fade never touches the text. + + Flat black here because that is what the original drew -- not a constraint. A theme can make this + a gradient, a ninepatch or a sprite by changing this one rule; `decorator` works, and the bound + opacity fades a decorator exactly as it fades a colour (see themes/modern/chat_log.rcss, which + does use a gradient). */ +#chat_backdrop { + display: none; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + z-index: 0; + background-color: rgb(0, 0, 0); +} +#panel.framed #chat_backdrop { display: block; } +/* Above the backdrop, and unfaded. */ +#lines { position: relative; z-index: 1; } + +/* Drag target for the 3-line-step resize. Native draws newui_Scrollbar_stretch across the full + window width, 10 tall, sitting just above the top edge. */ +@spritesheet chat-resize-sheet { + src: "../../../newui_Scrollbar_stretch.jpg"; + chat-resize: 0px 0px 281px 10px; +} +#resize_handle { + position: absolute; + left: 0; + bottom: -10dp; + width: 281dp; + height: 10dp; + decorator: image(chat-resize); + cursor: move; + pointer-events: auto; +} +#resize_handle:active { filter: brightness(0.7); } + +/* Messages stack from the BOTTOM up: with fewer lines than the window shows, native pushed the + text down by (showingLines - endLine - 1) line heights (RenderMessages()), so the first message + sits on the bottom row and earlier ones ride upward as new ones arrive. A flex column plus an + auto top margin on the first line reproduces that exactly, and degrades correctly once the list + overflows -- an auto margin absorbs free space when there is any and resolves to 0 when there + isn't, so it never pushes content out of the scrollable area the way justify-content:flex-end + would. */ +#lines { + position: absolute; + left: 0; + top: 13dp; + right: 4dp; + font-size: 11dp; + display: flex; + flex-direction: column; + /* Lines hug their own text rather than stretching to the pane: native passed no box width to + RenderText(), so the text renderer fell back to the MEASURED width for its background quad + (CUIRenderTextSDLTtf.cpp -- `if (layout.boxWidth == 0) boxWidth = measuredWidth`). Flex + defaults to align-items:stretch, which made every line a full-width bar instead. */ + align-items: flex-start; +} +/* 0.97 filled its six rows from the top. */ + +/* The message well must NOT be a hover target. Core::Input::IsMouseOverUI() gates click-to-move + on Rml::Context::IsMouseInteracting(), which is true for ANY pointer-events:auto element under + the cursor -- clicked or not -- so leaving .scroll-pane's own `pointer-events: auto` in place + here turned the whole chat area into a wall the player could not walk through. Native let world + clicks pass straight through this window (its UpdateMouseEvent() only consumed on the single + hover-transition frame), so nothing here may claim the cursor except the two controls that + genuinely need it. */ +#lines { pointer-events: none; } +.chat-line { pointer-events: none; } + +/* The scrollbar is the exception, and it has to opt back in explicitly at every level: its + generated children inherit pointer-events from #lines, which is now `none`. */ +#lines scrollbarvertical, +#lines scrollbarvertical slidertrack, +#lines scrollbarvertical sliderbar { pointer-events: auto; } + +/* Native's RenderFrame() draws the scrollbar AND the resize handle only while the frame is + shown, so hiding the frame (F5) takes the scrollbar with it. Width 0 rather than + overflow:hidden: native still scrolls on the wheel with the frame hidden (its wheel branch is + gated on hover, not on m_bShowFrame), and overflow:hidden would kill that too. */ +#lines scrollbarvertical { width: 0; } +#panel.framed #lines scrollbarvertical { width: 15dp; } + +/* No padding: native's background quad is exactly the measured text (RenderText() without a box). + Text size, height and the 15-unit row pitch come from chat_log.rml's bindings. flex-shrink 0: + with an explicit height, a flex item would otherwise shrink to fit a full well and the rows + would crowd together instead of scrolling. */ +.chat-line { + display: block; + white-space: nowrap; + flex-shrink: 0; + /* A line is the native renderer's line height, and the next starts a row pitch below it. */ + height: var(--line-px, 0px); + line-height: var(--line-px, 0px); + margin-bottom: calc(var(--row-px, 0px) - var(--line-px, 0px)); +} + +/* Per-type colours: 0.97's (00480980) for the types it had -- normal chat beige on black, whisper + black on yellow, system blue, error red, party black on cyan, guild black on blue; the S6-only + types keep legacy's. */ +.chat-line--chat { background-color: rgba(0, 0, 0, 150); color: rgb(230, 220, 200); } +.chat-line--whisper { background-color: rgba(255, 200, 50, 150); color: rgb(0, 0, 0); } +.chat-line--system { background-color: rgba(0, 0, 0, 150); color: rgb(100, 150, 255); } +.chat-line--error { background-color: rgba(0, 0, 0, 150); color: rgb(255, 30, 0); } +.chat-line--party { background-color: rgba(0, 200, 255, 150); color: rgb(0, 0, 0); } +.chat-line--guild { background-color: rgb(8, 72, 251); color: rgb(0, 0, 0); } +.chat-line--union { background-color: rgba(200, 200, 0, 200); color: rgb(0, 0, 0); } +.chat-line--gens { background-color: rgba(150, 200, 100, 200); color: rgb(0, 0, 0); } +.chat-line--gm { background-color: rgba(30, 30, 30, 200); color: rgb(250, 200, 50); font-weight: bold; } + +/* Native drops chat-line background alpha from 150 to 100 while the frame is shown, so the frame's + own fill reads through it -- the one per-type colour that depends on frame state. */ +#panel.framed .chat-line--chat { background-color: rgba(0, 0, 0, 100); } + +/* Native's pointed-message highlight. NOT a :hover rule -- these lines are pointer-events:none + so world clicks pass through, which also means they never receive hover. C++ resolves the + pointed line itself and pushes its index, exactly as native's own + m_bPointedMessage/m_iPointedMessageIndex pair did. */ +.chat-line--pointed { + background-color: rgba(30, 30, 30, 180); + color: rgb(255, 128, 255); +} + +/* The framed window (F5): 0.97's "nis" window (0040ce20), 268 wide: Message_box2 along the + top, nis_vframe down both sides, the black fill (its alpha the transparency setting) inside + them, the text 10 units in, + the scrollbar on nis_back with the nis_bar thumb and nis_btnarrow ends (the lower one flipped), + and the nis_rsframe grip at the top-right corner to drag the height. Lines on black lose their + strip in the window; whisper, party and guild keep theirs. */ +@spritesheet classic-nis-top-sheet { src: ../../../Classic/Message_box2_268.jpg; classic-nis-top: 0px 0px 268px 5px; } +@spritesheet classic-nis-side-sheet { src: ../../../Classic/Nis_vframe_tall.jpg; classic-nis-side: 0px 0px 5px 480px; } +@spritesheet classic-nis-back-sheet { src: ../../../Classic/Nis_back.jpg; classic-nis-back: 0px 0px 13px 1px; } +@spritesheet classic-nis-bar-sheet { src: ../../../Classic/Nis_bar.jpg; classic-nis-bar: 0px 0px 11px 1px; } +@spritesheet classic-nis-arrow-sheet { src: ../../../Classic/Nis_btnarrow.jpg; classic-nis-arrow: 0px 0px 13px 13px; } +@spritesheet classic-nis-grip-sheet { src: ../../../Classic/Nis_rsframe.tga; classic-nis-grip: 0px 0px 22px 12px; } + +#panel.framed { + width: 268dp; + /* 0.97's fill runs 15 units under the newest line (to y 432), where its chat buttons sit. */ + padding-bottom: 15dp; + /* 0.97 stretches Message_box2 over the width and stacks nis_vframe (5x40) down each side. The + game loads RmlUi textures clamped, so repeat does not tile: Message_box2_268 is the top already + stretched to the window's width and Nis_vframe_tall the side stacked 12 times, both drawn + unscaled and cut at the window's box. */ + decorator: image(classic-nis-top scale-none left top), image(classic-nis-side scale-none left top), + image(classic-nis-side scale-none right top); +} +#panel.framed #chat_backdrop { left: 5dp; right: 5dp; top: 5dp; } +#panel.framed #lines { left: 10dp; top: 8dp; right: 8dp; } +/* In the window the newest line is at the bottom and a short log rests on it (0040d610). */ +#panel.framed .chat-line:first-child { margin-top: auto; } +#panel.framed .chat-line--chat, +#panel.framed .chat-line--system, +#panel.framed .chat-line--error { background-color: transparent; } + +#panel.framed #lines scrollbarvertical { width: 13dp; } +#panel.framed #lines scrollbarvertical slidertrack { decorator: image(classic-nis-back fill); } +#panel.framed #lines scrollbarvertical sliderbar { + width: 11dp; + margin-left: 1dp; + height: auto; + min-height: 8dp; + decorator: image(classic-nis-bar fill); +} +#panel.framed #lines scrollbarvertical sliderarrowdec, +#panel.framed #lines scrollbarvertical sliderarrowinc { height: 13dp; pointer-events: auto; } +#panel.framed #lines scrollbarvertical sliderarrowdec { decorator: image(classic-nis-arrow); } +#panel.framed #lines scrollbarvertical sliderarrowinc { decorator: image(classic-nis-arrow flip-vertical); } +#panel.framed #lines scrollbarvertical sliderarrowdec:hover, +#panel.framed #lines scrollbarvertical sliderarrowinc:hover { filter: brightness(1.2); } + +#panel.framed #resize_handle { + left: auto; + right: 6dp; + top: -4dp; + bottom: auto; + width: 22dp; + height: 12dp; + decorator: image(classic-nis-grip); + /* Dragged up and down to size the window (CChatLogWindow follows the drag). */ + drag: drag; +} diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/chat_room.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/chat_room.rcss new file mode 100644 index 0000000000..a796e537f6 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/chat_room.rcss @@ -0,0 +1,176 @@ +/* Classic theme for a chat room: the Season 1 client's window (CUIChatWindow, the code this client's + own native window ran before its RmlUi port; same frame and palette as friend_shell.rcss, which + says where they come from). 0.97 has no friend chat. Inside the frame (5 units in, 21 down): + - the log from the top down to 16 above the bottom; with the participants shown (more than two, + or the invite list open), an 80-wide column at the right behind a 5-unit line (106,97,88 / + 37,37,37 three units / 106,97,88), and with the invite list another one left of it; + - a 106,97,88 line 16 above the bottom, then a black foot 15 high: the text field (no back) and + the invite button (win_button, 53x13, 54 from the right; the invite list's send button, 73x13, + 74 from the right). The window and its buttons are wider than Season 1's for longer captions. + 1dp is one of the window's units. */ + +@spritesheet cr-titlebar-sheet { src: "../../../win_titlebar.jpg"; cr-titlebar: 0px 0px 4px 15px; } +@spritesheet cr-size-sheet +{ + src: "../../../win_size.jpg"; + cr-minimize: 0px 0px 9px 9px; + cr-maximize: 9px 0px 9px 9px; + cr-restore: 9px 9px 9px 9px; + cr-close: 0px 9px 9px 9px; +} +@spritesheet cr-resize-sheet { src: "../../../win_resize.tga"; cr-resize-grip: 0px 0px 9px 9px; } +@spritesheet cr-button-sheet { src: "../../../win_button.tga"; cr-button: 0px 0px 49px 16px; } +@spritesheet cr-scroll-sheet +{ + src: "../../../win_scrollbar.jpg"; + cr-scroll-thumb: 0px 1px 11px 1px; + cr-scroll-up: 0px 3px 13px 13px; + cr-scroll-down: 0px 16px 13px 13px; +} + +/* An id beats .center-both's own transform (see legacy's chat_room.rcss). */ +#panel { transform: none; } +/* CUIChatWindow::Init(): SetSize(250, 170), SetLimitSize(250, 150), widened to 300 (min 290). + font-size 1rem, never dp: the theme sizes text natively. */ +#panel { width: 300dp; height: 170dp; min-width: 290dp; min-height: 150dp; max-width: 100%; max-height: 100%; font-family: "token(font-body)"; font-size: 1rem; color: rgb(230, 220, 200); } + +/* Season 1's frame (friend_shell.rcss): body black at 179, the 5-unit outline drawn in + CUIBaseWindow::DrawOutLine()'s order (the inner lines crossing into the corners), a dot in each + corner but the bottom-right one, where this resizeable window has its grip, and the title bar. */ +.window-shell-sprite-back { + left: 0; + right: 0; + top: 5dp; + bottom: 5dp; + background-color: rgba(0, 0, 0, 179); + decorator: linear-gradient(to right, transparent 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, transparent 4dp), + linear-gradient(to left, transparent 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, transparent 4dp); +} +.window-shell-sprite-top { + left: 0; + right: 0; + top: 0; + bottom: 0; + height: auto; + decorator: linear-gradient(to bottom, rgb(146, 134, 121) 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp), + linear-gradient(to top, rgb(146, 134, 121) 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp); +} +.window-shell-sprite-middle { + left: 0; + right: 0; + top: 1dp; + bottom: 1dp; + decorator: linear-gradient(to right, rgb(146, 134, 121) 1dp, transparent 1dp, transparent 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp), + linear-gradient(to left, rgb(146, 134, 121) 1dp, transparent 1dp, transparent 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp); +} +.window-shell-sprite-bottom { + left: 2dp; + right: 2dp; + top: 2dp; + bottom: auto; + height: 1dp; + decorator: linear-gradient(to right, rgb(173, 167, 150) 1dp, transparent 1dp), + linear-gradient(to left, rgb(173, 167, 150) 1dp, transparent 1dp); +} +#window_shell_footer { + left: 2dp; + right: auto; + top: auto; + bottom: 2dp; + width: 1dp; + height: 1dp; + background-color: rgb(173, 167, 150); +} +.window-shell-header-rail { + left: 5dp; + right: 5dp; + top: 5dp; + height: 16dp; + box-sizing: border-box; + border-left: 1dp rgb(136, 138, 147); + border-right: 1dp rgb(0, 0, 8); + border-bottom: 1dp rgb(106, 97, 88); + decorator: image(cr-titlebar fill); +} +.window-shell-header-title { left: 9dp; right: 50dp; top: 8dp; text-align: left; white-space: nowrap; overflow: hidden; color: rgb(230, 220, 200); } + +/* The client area: 5 units in from the sides and the bottom, 21 down. Each interactive part opts + back into pointer events. */ +.window-shell-content, .window-shell-content.has-title +{ + left: 5dp; + right: 5dp; + top: 21dp; + bottom: 5dp; + padding: 0; + display: block; + pointer-events: none; +} + +div { display: block; } +button { font-family: "token(font-body)"; font-size: 1rem; color: rgb(230, 220, 200); cursor: pointer; pointer-events: auto; } + +#window_controls { position: absolute; right: 2dp; top: -13dp; z-index: 10; pointer-events: auto; white-space: nowrap; } +#window_controls button { display: inline-block; width: 9dp; height: 9dp; margin-left: 2dp; padding: 0; box-sizing: border-box; } +#btn_minimize { decorator: image(cr-minimize); } +#btn_maximize { decorator: image(cr-maximize); } +#btn_maximize.restore { decorator: image(cr-restore); } +#btn_close { decorator: image(cr-close); } + +/* win_button stretched whole, pressed one unit in. */ +.btn { position: relative; display: inline-block; box-sizing: border-box; width: auto; height: 13dp; padding: 0 2dp; line-height: 13dp; vertical-align: top; text-align: center; overflow: hidden; pointer-events: auto; decorator: image(cr-button fill); } +/* base.rcss's .btn:hover / :active swap in legacy's button art; these keep win_button. */ +.btn:hover, .btn:active { decorator: image(cr-button fill); } +.btn:active { padding-top: 1dp; padding-left: 3dp; } +.hidden { display: none; } + +/* The log down to the foot; the participant and invite columns 80 wide, each behind its 5-unit + line (the column starts at it). */ +.scroll-pane { position: absolute; top: 0; bottom: 16dp; overflow: hidden scroll; background-color: transparent; pointer-events: auto; } +#chat_log { left: 0; right: 0; } +#chat_log.with-pals { right: 80dp; } +#chat_log.with-invite { right: 160dp; } +#pal_pane, #invite_pane { + width: 80dp; + padding-left: 5dp; + box-sizing: border-box; + decorator: linear-gradient(to right, rgb(106, 97, 88) 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp); +} +#pal_pane { right: 0; } +#pal_pane.with-invite { right: 80dp; } +#invite_pane { right: 0; } + +.line { padding: 0 4dp; } +.speaker { display: inline-block; color: rgb(255, 200, 50); } +.speaker:after { content: ": "; } +.say { display: inline-block; color: rgb(239, 220, 205); } +/* CUISimpleChatListBox::RenderDataLine()'s own colour table. */ +.say.t0 { color: rgb(0, 0, 0); background-color: rgb(255, 200, 50); } +.say.t1 { color: rgb(100, 150, 255); } +.say.t2 { color: rgb(255, 30, 0); } +.say.t4 { color: rgb(0, 0, 0); background-color: rgb(0, 200, 255); } +.say.t5 { color: rgb(0, 0, 0); background-color: rgb(0, 255, 150); } + +.pal { height: 13dp; line-height: 13dp; padding: 0 3dp; white-space: nowrap; overflow: hidden; cursor: pointer; } +.pal:hover { background-color: rgb(106, 97, 88); } +.pal.selected { background-color: rgb(146, 134, 121); color: rgb(0, 0, 0); } + +/* The foot: the line 16 above the bottom, black below it, the field from x 2 and the buttons at + the right. */ +#footer { position: absolute; left: 0; right: 0; bottom: 0; height: 16dp; padding: 1dp 1dp 0 2dp; box-sizing: border-box; white-space: nowrap; border-top: 1dp rgb(106, 97, 88); background-color: rgb(0, 0, 0); } +#chat_field { display: inline-block; box-sizing: border-box; width: 62%; height: 14dp; margin-right: 1%; vertical-align: top; background-color: transparent; border-width: 0; pointer-events: auto; } +#footer .btn { width: 64dp; margin-left: 1dp; } +#btn_invite_send { width: 84dp; } + +/* win_scrollbar, as the friend window's lists. */ +.scroll-pane scrollbarvertical { width: 13dp; margin: 0; } +.scroll-pane scrollbarvertical slidertrack { decorator: none; box-sizing: border-box; border-left: 1dp rgb(106, 97, 88); border-right: 1dp rgb(106, 97, 88); } +.scroll-pane scrollbarvertical sliderbar { height: auto; min-height: 6dp; margin: 0 1dp; decorator: image(cr-scroll-thumb fill); } +.scroll-pane scrollbarvertical sliderarrowdec, +.scroll-pane scrollbarvertical sliderarrowinc { width: 100%; height: 13dp; pointer-events: auto; } +.scroll-pane scrollbarvertical sliderarrowdec { decorator: image(cr-scroll-up); } +.scroll-pane scrollbarvertical sliderarrowinc { decorator: image(cr-scroll-down); } +.scroll-pane scrollbarvertical sliderarrowdec:active, +.scroll-pane scrollbarvertical sliderarrowinc:active { filter: brightness(0.7); } + +#resize { display: block; position: absolute; right: -4dp; bottom: -4dp; width: 9dp; height: 9dp; z-index: 10; pointer-events: auto; decorator: image(cr-resize-grip); cursor: resize; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/command_window.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/command_window.rcss new file mode 100644 index 0000000000..d9662699dd --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/command_window.rcss @@ -0,0 +1,81 @@ +/* Classic (0.97) theme for CCommandWindow (D). 0.97 has no command window (its player commands + are chat commands: /trade, /party, /guild...), so this is legacy's window in classic art: the + 0.97 frame comes from docked_panel_frame.rcss (linked first); the twelve buttons are 0.97's text + plate, Message_box (213x64) squashed to the button box as the 0.97 Esc menu does, lit warm under + the mouse and while armed as its plates are; the target box at + the pointer is the 0.99b client's Cursorid_wnd (128x32). Positions are legacy's (InitButtons(), + RenderBaseWindow()); coordinates are reference px inside #panel. */ + +@spritesheet classic-cmd-plate-sheet { src: ../../../Classic/Message_box.jpg; classic-cmd-plate: 0px 0px 213px 64px; } +@spritesheet classic-cmd-target-sheet { src: ../../../Classic/099b/Cursorid_wnd.jpg; classic-cmd-target: 0px 0px 128px 32px; } + +.frame-top { decorator: image(docked-bg-top-b); } +#panel { height: 432px; pointer-events: auto; } +/* The frame's pieces keep docked_panel_frame.rcss's 0.97 sizes (Item_Back02 is 177 tall from y + 256): legacy's side-piece height (323) would stretch it past the window's foot. */ + +/* RenderText(x + 60, y + 12, title, 72, 0, RT3_SORT_CENTER), bold white. */ +#title { + display: block; + position: absolute; + left: 60px; + top: 12px; + text-align: center; + white-space: nowrap; + color: #ffffff; + font-weight: bold; + pointer-events: none; +} + +/* InitButtons(): plates of 108x29, centred on the 190-wide panel (x 41), from y 33, 30 apart. */ +#buttons { position: absolute; left: 41px; top: 33px; width: 108px; } +.cmd-btn { + display: block; + position: relative; + width: 108px; + height: 29px; + margin-bottom: 1px; + decorator: image(classic-cmd-plate); + pointer-events: auto; +} +/* 0.97 redraws the plate under the mouse additively tinted (0.8, 0.6, 0.4), a warm brightening: + the plate is brightened and warmed, under the mouse and while the command is armed. */ +.cmd-btn:hover, .cmd-btn:active, .cmd-btn.selected { image-color: #ffe3c6; filter: brightness(1.7); } + +/* CButton::Render(): the label centred in the button box, white; the armed command's in bold. */ +.cmd-label { + display: block; + position: absolute; + left: 0; + text-align: center; + white-space: nowrap; + color: #ffffff; + pointer-events: none; +} +.cmd-btn.selected .cmd-label { font-weight: bold; } + +/* The target box: Cursorid_wnd (128x32, 0.99b's newui_cursorid_wnd) at the pointer + 5; the name in the big font, + centred on the box 7 units below its top, white, or red (255, 0, 0) out of reach. */ +#target { + position: absolute; + width: 128px; + height: 32px; + decorator: image(classic-cmd-target); + pointer-events: none; +} +#target_name { + display: block; + position: absolute; + left: 0; + top: 7px; + text-align: center; + white-space: nowrap; + color: #ffffff; + pointer-events: none; +} +#target.out-of-range #target_name { color: #ff0000; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#title { width: calc(72px * var(--root-scale)); } +.cmd-label { width: calc(108px * var(--root-scale)); } +#target_name { width: calc(128px * var(--root-scale)); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/crywolf.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/crywolf.rcss new file mode 100644 index 0000000000..fbea5a006b --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/crywolf.rcss @@ -0,0 +1,140 @@ +/* Classic theme for CCryWolf (crywolf.rml is forked here). 0.97 has no Crywolf; the Season 2 client + has, and draws its battle panel at the screen's top-left corner (0044bccd): + - in_main (122 x 98) at (0, 1), the five altars (13 x 13) at (4, 29), (16, 17), (30, 9), + (46, 5) and (62, 4), the dark elf icon (15 x 15) at (4, 81) and their count centred on x 57 at + y 85, (255, 148, 21); + - the statue's shield, in_main2 (30 high) from (4, 46), as long as the shield left; + - Balgass: in_bar (97 x 21) at (0, 98), his icon at (4, 101), "Balgass" centred on x 38 at + y 101 and his health (in_bar2, 8 high) from (25, 109); the latch in_deco (20 x 9) slides from + under the panel (y 98) to under the bar (119) as he comes; + - the clock: t_main (156 x 36) at (240, 396), the minutes centred on x 300 and the seconds on + x 327 at y 414 in FontTest digits 14 x 14, white, red while Balgass fights, no leading zeros. + The result (banner, rank table and letter, experience) is the same in both clients: legacy's. + Legacy's rules first, then the classic ones. */ + +/* Legacy theme for CCryWolf, reproducing its Render() at the 640x480 reference positions on + .screen's HUD board: the result banner (329 x 94) at y 50, the rank table (196 x 141) + at (230, 150), the rank label (110 x 28) at y 188 and the letter (29 x 28) at (370, 188), the + experience label (60 x 19) at (229, 235) and nine 15 x 19 digits from x 289; the battle panel + in_main-New (122 x 119) at (518, 278), the altars (13 x 13), the dark elf icon (15 x 15) at + (623, 358), t_main-New (104 x 37) at (538, 392), the dark elf count centred on x 582 at y 359 + and Balgass centred on x 600 at y 380 in the normal font, (255, 148, 21), Balgass's icon at + (623, 379) and his health bar (8 high) at (548, 388), the time's 14 x 14 FontTest digits at + y 402, the statue's shield bar (30 high) at y 323; the notice's lines at x 190 in the bold font + on a black box of alpha 170. */ + +body { pointer-events: none; } + +.screen { + pointer-events: none; + font-family: "token(font-body)"; +} + +img { position: absolute; } + +#banner { top: 50px; width: 329px; height: 94px; } +#rank_table { left: 230px; top: 150px; width: 196px; height: 141px; } +#rank_label { top: 188px; width: 110px; height: 28px; } +#rank_letter { left: 370px; top: 188px; width: 29px; height: 28px; } +#exp_label { left: 229px; top: 235px; width: 60px; height: 19px; } +.exp-digit { width: 15px; height: 19px; } + +#main { left: 518px; top: 278px; width: 122px; height: 119px; } +.altar { width: 13px; height: 13px; } +#dark_elf_icon { left: 623px; top: 358px; width: 15px; height: 15px; } +#plate { left: 538px; top: 392px; width: 104px; height: 37px; } +#balgass_icon { left: 623px; top: 379px; width: 15px; height: 15px; } +#balgass_bar { left: 548px; top: 388px; height: 8px; } +.timer-digit { top: 402px; width: 14px; height: 14px; } +/* RenderNumber2D(): 14-unit digits 9.8 apart, a run starting half its digit count's width left of + its x; the leading zeros are one-digit runs on x 570 and 597. */ +#minute_pad { left: 563px; } +#second_pad { left: 590px; } +#minutes .timer-digit { left: calc(580px - var(--n) * 7px + var(--i) * 9.8px); } +#seconds .timer-digit { left: calc(607px - var(--n) * 7px + var(--i) * 9.8px); } +#statue_bar { top: 323px; height: 30px; } + +.hud-text { + display: block; + position: absolute; + transform-origin: left top; + white-space: nowrap; + text-align: center; + color: #ff9415; +} +#dark_elf_text { left: 482px; top: 359px; } +#balgass_text { left: 500px; top: 380px; } + +.notice { + display: block; + position: absolute; + left: 190px; + transform-origin: left top; + white-space: nowrap; + font-weight: bold; + background-color: rgba(0, 0, 0, 170); +} + +/* The repeated sets, each counted inside its own container; the containers take no space. */ +.exp-digits, .altars, .notices { position: static; } + +/* RenderRank()'s nine experience digits, 15 units apart from x 289 at y 235. */ +.exp-digit:nth-child(1) { left: 289px; top: 235px; } +.exp-digit:nth-child(2) { left: 304px; top: 235px; } +.exp-digit:nth-child(3) { left: 319px; top: 235px; } +.exp-digit:nth-child(4) { left: 334px; top: 235px; } +.exp-digit:nth-child(5) { left: 349px; top: 235px; } +.exp-digit:nth-child(6) { left: 364px; top: 235px; } +.exp-digit:nth-child(7) { left: 379px; top: 235px; } +.exp-digit:nth-child(8) { left: 394px; top: 235px; } +.exp-digit:nth-child(9) { left: 409px; top: 235px; } + +/* The five altars, on the places the original's own table put them along the hill. */ +.altar:nth-child(1) { left: 565px; top: 280px; } +.altar:nth-child(2) { left: 582px; top: 282px; } +.altar:nth-child(3) { left: 598px; top: 286px; } +.altar:nth-child(4) { left: 613px; top: 294px; } +.altar:nth-child(5) { left: 625px; top: 306px; } + +/* The advance notice's four lines, 13 units apart from y 63, the first one its heading. */ +.notice:nth-child(1) { top: 63px; } +.notice:nth-child(2) { top: 76px; } +.notice:nth-child(3) { top: 89px; } +.notice:nth-child(4) { top: 102px; } +.notice { color: rgb(100, 150, 255); } +.notice.heading { color: rgb(100, 200, 255); } + +/* The clock reddens while Balgass is on the field. */ +.timer-digit { image-color: #ffffff; } +.timer-digit.urgent { image-color: rgb(255, 77, 77); } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#dark_elf_text { width: calc(200px * var(--root-scale)); } +#balgass_text { width: calc(200px * var(--root-scale)); } + +/* The data-for template row has no index of its own; it inherits this one. */ +.timer-run { --i: 0; } + +/* --- Classic: the Season 2 battle panel ------------------------------------------------------- */ +#main { left: 0; top: 1px; width: 122px; height: 98px; } +#deco, #deco_down { left: 4px; width: 20px; height: 9px; } +#deco { top: 98px; } +#deco_down { top: 119px; } +.altar:nth-child(1) { left: 4px; top: 29px; } +.altar:nth-child(2) { left: 16px; top: 17px; } +.altar:nth-child(3) { left: 30px; top: 9px; } +.altar:nth-child(4) { left: 46px; top: 5px; } +.altar:nth-child(5) { left: 62px; top: 4px; } +#dark_elf_icon { left: 4px; top: 81px; } +#dark_elf_text { left: -43px; top: 85px; } +#statue_bar { left: 4px; top: 46px; height: 30px; } +.unused { display: none; } +#balgass_frame { left: 0; top: 98px; width: 97px; height: 21px; } +#balgass_icon { left: 4px; top: 101px; } +#balgass_text { left: -62px; top: 101px; } +#balgass_bar { left: 25px; top: 109px; } +#plate { left: 240px; top: 396px; width: 156px; height: 36px; } +.timer-digit { top: 414px; } +#minute_pad, #second_pad { display: none; } +#minutes .timer-digit { left: calc(300px - var(--n) * 7px + var(--i) * 9.8px); } +#seconds .timer-digit { left: calc(327px - var(--n) * 7px + var(--i) * 9.8px); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/crywolf.rml b/src/bin/Data/Interface/RmlUi/themes/classic/crywolf.rml new file mode 100644 index 0000000000..39492608a8 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/crywolf.rml @@ -0,0 +1,83 @@ + + + + Crywolf (CCryWolf) + + + + + +
+
+ + + +
+ + + +
+
+
+
+ + + + +
+ + + {{dark_elf_text}} +
+ + + + {{balgass_text}} + +
+ + +
+ +
+ +
+ +
+ + +
+ +
+ {{n.text}} +
+
+
+ +
diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/cursed_temple_enter.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/cursed_temple_enter.rcss new file mode 100644 index 0000000000..56a601c990 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/cursed_temple_enter.rcss @@ -0,0 +1,85 @@ +/* Classic theme for the Illusion Temple entry window (CCursedTempleEnter). 0.97 and the Season 2 + client have no Illusion Temple; the window takes the Season 2 client's Kanturu entry box + (kanturu_enter.rcss): a 0.97 message box 213 x 250 (Message_box1 stones between Message_box2 + edges), the question bold (255, 176, 73) at y 13, the lines white and red as legacy's, the hero's + band on a red text box, 0.97's divider (Trading_line) above the buttons, and Season 1's + win_button (50 x 16) for Enter and Close at y 215, tinted as Season 2 tinted it. Legacy's rows + (the temple at 42, the bands 15 apart from 67, the members at 160). Reference px inside #panel. */ + +@spritesheet temple-classic-stone-sheet { src: ../../../Classic/Message_box1.jpg; temple-classic-stone: 0px 0px 213px 40px; } +@spritesheet temple-classic-edge-sheet { src: ../../../Classic/Message_box2.jpg; temple-classic-edge: 0px 0px 213px 5px; } +@spritesheet temple-classic-line-sheet { src: ../../../Classic/Trading_line.jpg; temple-classic-line: 0px 0px 190px 10px; } +@spritesheet temple-classic-btn-sheet { src: "../../../win_button.tga"; temple-classic-btn: 0px 0px 49px 16px; } + +#panel { + position: absolute; + transform-origin: left top; + width: 213px; + height: 250px; + font-family: "token(font-body)"; + pointer-events: auto; +} + +/* The stones: #back and the first five middle tiles, 40 apart from y 5; the edges: the top and the + bottom pieces. */ +#back { position: absolute; left: 0; top: 5px; width: 213px; height: 40px; decorator: image(temple-classic-stone); } +#frame_top { position: absolute; left: 0; top: 0; width: 213px; height: 5px; decorator: image(temple-classic-edge); } +.frame-middle { position: absolute; left: 0; width: 213px; height: 40px; decorator: image(temple-classic-stone); } +#frame_bottom { position: absolute; left: 0; top: 245px; width: 213px; height: 5px; decorator: image(temple-classic-edge); } +#line { position: absolute; left: 11px; top: 190px; width: 190px; height: 10px; decorator: image(temple-classic-line); } + +.sharp-text { display: block; position: absolute; white-space: nowrap; text-align: center; pointer-events: none; } +#title { left: 0; top: 13px; font-weight: bold; color: #ffb049; } +.temple-line { color: #ffffff; } +.temple-line.red { color: #ff0000; } +/* The frame tiles and the level bands are containers so each piece can be counted; the containers + themselves take no space. */ +.frame-middles, .temple-bands { position: static; } +.frame-middles .frame-middle:nth-child(1) { top: 45px; } +.frame-middles .frame-middle:nth-child(2) { top: 85px; } +.frame-middles .frame-middle:nth-child(3) { top: 125px; } +.frame-middles .frame-middle:nth-child(4) { top: 165px; } +.frame-middles .frame-middle:nth-child(5) { top: 205px; } +.frame-middles .frame-middle:nth-child(n+6) { display: none; } + +#ct_temple { left: 3px; top: 42px; } +#ct_members { left: 3px; top: 160px; } +#ct_notice { left: 0; top: 52px; } +.temple-band { position: absolute; left: 3px; width: 207px; height: 15px; margin-top: 67px; } +.temple-band:nth-child(1) { top: 0px; } +.temple-band:nth-child(2) { top: 15px; } +.temple-band:nth-child(3) { top: 30px; } +.temple-band:nth-child(4) { top: 45px; } +.temple-band:nth-child(5) { top: 60px; } +.temple-band:nth-child(6) { top: 75px; } +.temple-band .temple-line { left: 0; top: 0; } +.band-hero { position: absolute; left: 0; top: 0; width: 207px; background-color: #ff0000; + pointer-events: none; } + +.temple-btn { + display: block; + position: absolute; + top: 215px; + width: 50px; + height: 16px; + decorator: image(temple-classic-btn fill); + image-color: #cccccc; + pointer-events: auto; +} +.temple-btn:hover { image-color: #ffffff; } +.temple-btn:active { image-color: #999999; } +#btn_enter { left: 35px; } +#btn_close { left: 128px; } +.temple-label { left: 0; color: #e6dcc8; } +.temple-btn:active .temple-label { margin-left: calc(1px * var(--root-scale)); margin-top: calc(1px * var(--root-scale)); } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#title { width: calc(213px * var(--root-scale)); } +#ct_temple { width: calc(207px * var(--root-scale)); } +.temple-line { width: calc(207px * var(--root-scale)); } +#ct_members { width: calc(207px * var(--root-scale)); } +#ct_notice { width: calc(213px * var(--root-scale)); } +.temple-label { width: calc(50px * var(--root-scale)); } + +/* The native line height, counter-scaled out of the panel. */ +.band-hero { height: calc(var(--line-height) / var(--root-scale)); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/cursed_temple_result.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/cursed_temple_result.rcss new file mode 100644 index 0000000000..ae526e19cc --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/cursed_temple_result.rcss @@ -0,0 +1,170 @@ +/* Classic theme for the Illusion Temple result window (CCursedTempleResult). 0.97 and the Season 2 + client have no Illusion Temple; the window takes the classic entry boxes' parts + (cursed_temple_enter.rcss, the Season 2 client's Kanturu box): a 0.97 message box 230 x 290 (the + Message_box1 stones stretched to the width, as Season 2 stretched them for longer languages, + between Message_box2 edges), 0.97's divider (Trading_line) for the two lines and Season 1's + win_button (50 x 16) for Close at y 255, tinted as Season 2 tinted it. The banner, rows and + colours are legacy's (below). */ + +/* Legacy theme for CCursedTempleResult, reproducing its RenderFrame()/RenderResultPanel()/ + RenderText()/RenderButtons(): the message-box back (222 x 272 from y 2), the titled top + (newui_Message_03, 230 x 67), eleven middle tiles, the bottom and separator lines at y 45 and + 205; illusion_success / illusion_failure (351 x 115) 110 units above the window; the texts in + the normal font (the title and headings (255, 176, 73), the MU Alliance rows (100, 178, 251), + the Illusion Sorcery rows (254, 214, 55), the notice red), the hero's row on a red 220-unit + text box at x 2; Close (newui_btn_empty_very_small, 54 x 23) centred at y 245. Reference px + inside #panel. */ + +@spritesheet result-back-sheet { src: "../../../newui_msgbox_back.jpg"; result-back: 0px 0px 222px 272px; } +@spritesheet result-top-sheet { src: "../../../newui_Message_03.tga"; result-top: 0px 0px 230px 67px; } +@spritesheet result-middle-sheet { src: "../../../newui_msgbox_middle.tga"; result-middle: 0px 0px 230px 15px; } +@spritesheet result-bottom-sheet { src: "../../../newui_msgbox_bottom.tga"; result-bottom: 0px 0px 230px 50px; } +@spritesheet result-line-sheet { src: "../../../newui_Message_Line.tga"; result-line: 0px 0px 223px 21px; } +@spritesheet result-success-sheet { src: "../../../illusion_success.tga"; result-success: 0px 0px 351px 115px; } +@spritesheet result-failure-sheet { src: "../../../illusion_failure.tga"; result-failure: 0px 0px 351px 115px; } +@spritesheet result-btn-sheet +{ + src: "../../../newui_btn_empty_very_small.tga"; + result-btn-up: 0px 0px 54px 23px; + result-btn-over: 0px 23px 54px 23px; + result-btn-down: 0px 46px 54px 23px; +} + +#panel { + position: absolute; + transform-origin: left top; + width: 230px; + height: 282px; + font-family: "token(font-body)"; + pointer-events: auto; +} + +#back { position: absolute; left: 0; top: 2px; width: 222px; height: 272px; decorator: image(result-back); } +#frame_top { position: absolute; left: 0; top: 0; width: 230px; height: 67px; decorator: image(result-top); } +.frame-middle { position: absolute; left: 0; width: 230px; height: 15px; decorator: image(result-middle); } +#frame_bottom { position: absolute; left: 0; top: 232px; width: 230px; height: 50px; decorator: image(result-bottom); } +.line { position: absolute; left: 0; width: 223px; height: 21px; decorator: image(result-line); } + +.result-banner { position: absolute; left: calc(50% - 180px); top: -110px; width: 351px; height: 115px; pointer-events: none; } +.result-banner.success { decorator: image(result-success); } +.result-banner.failure { decorator: image(result-failure); } + +.hero-row { position: absolute; left: 2px; width: 220px; background-color: #ff0000; pointer-events: none; } + +.sharp-text { display: block; position: absolute; white-space: pre; text-align: center; pointer-events: none; } +.result-text.cell { text-align: left; } + +.result-btn { + display: block; + position: absolute; + left: 88px; + top: 245px; + width: 54px; + height: 23px; + decorator: image(result-btn-up); + pointer-events: auto; +} +.result-btn:hover { decorator: image(result-btn-over); } +.result-btn:active { decorator: image(result-btn-down); } +.result-label { left: 0; color: #ffffff; } + +/* RenderText()'s own rows: the title, the column heading and the reward notice centred on the + window, then one 15-unit row per player in each team's block. */ +.frame-middles, .result-rows { position: static; } +.result-line { position: absolute; left: 0; text-align: center; } +#ct_hero_list { top: 13px; } +#ct_column_header { top: 38px; } +/* RenderText()'s notice sits 55 above the window's bottom, the Close button 37. */ +#ct_reward_hint { top: 227px; } +/* The heading as one label per column, over its cells, rather than native's single centred string, + which ran past the frame once translated. */ +#ct_column_header { display: none; } +.column-label { top: 38px; } +.frame-middles .frame-middle:nth-child(1) { top: 67px; } +.frame-middles .frame-middle:nth-child(2) { top: 82px; } +.frame-middles .frame-middle:nth-child(3) { top: 97px; } +.frame-middles .frame-middle:nth-child(4) { top: 112px; } +.frame-middles .frame-middle:nth-child(5) { top: 127px; } +.frame-middles .frame-middle:nth-child(6) { top: 142px; } +.frame-middles .frame-middle:nth-child(7) { top: 157px; } +.frame-middles .frame-middle:nth-child(8) { top: 172px; } +.frame-middles .frame-middle:nth-child(9) { top: 187px; } +.frame-middles .frame-middle:nth-child(10) { top: 202px; } +.frame-middles .frame-middle:nth-child(11) { top: 217px; } +.line-upper { top: 45px; } +.line-lower { top: 205px; } + +.result-row { position: absolute; left: 0; width: 230px; height: 15px; } +.result-row:nth-child(1) { top: 0px; } +.result-row:nth-child(2) { top: 15px; } +.result-row:nth-child(3) { top: 30px; } +.result-row:nth-child(4) { top: 45px; } +.result-row:nth-child(5) { top: 60px; } +.result-row:nth-child(6) { top: 75px; } +.result-row:nth-child(7) { top: 90px; } +.result-row:nth-child(8) { top: 105px; } +.result-row:nth-child(9) { top: 120px; } +.result-row:nth-child(10) { top: 135px; } +.result-row:nth-child(11) { top: 150px; } +.result-row:nth-child(12) { top: 165px; } +.rows-allied .result-row { margin-top: 65px; } +.rows-illusion .result-row { margin-top: 140px; } +.result-cell { position: absolute; top: 0; } +/* Each column keeps native's offset and the room before the next one; a longer value ends in ".." + and scrolls on hover (base.rcss .marquee). */ +.result-cell, .column-label { text-align: left; } +.cell-team, .label-team { left: 5px; } +.cell-name, .label-name { left: 56px; } +.cell-class-name, .label-class-name { left: 106px; } +.cell-added-exp, .label-added-exp { left: 150px; } +.cell-point, .label-point { left: 190px; } +.hero-row { top: 0; } + +#ct_hero_list, #ct_column_header, .column-label { color: rgb(255, 176, 73); } +#ct_reward_hint { color: rgb(255, 0, 0); } +.rows-allied .result-cell { color: rgb(100, 178, 251); } +.rows-illusion .result-cell { color: rgb(254, 214, 55); } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#ct_hero_list { width: calc(230px * var(--root-scale)); } +#ct_column_header { width: calc(230px * var(--root-scale)); } +/* Inside the frame's edges. */ +#ct_reward_hint { left: 7px; width: calc(216px * var(--root-scale)); } +.cell-team, .label-team { width: calc(49px * var(--root-scale)); } +.cell-name, .label-name { width: calc(48px * var(--root-scale)); } +.cell-class-name, .label-class-name { width: calc(42px * var(--root-scale)); } +.cell-added-exp, .label-added-exp { width: calc(38px * var(--root-scale)); } +.cell-point, .label-point { width: calc(30px * var(--root-scale)); } +.result-label { width: calc(54px * var(--root-scale)); } + +/* The native line height, counter-scaled out of the panel. */ +.hero-row { height: calc(var(--line-height) / var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet result-classic-stone-sheet { src: ../../../Classic/Message_box1.jpg; result-classic-stone: 0px 0px 213px 40px; } +@spritesheet result-classic-edge-sheet { src: ../../../Classic/Message_box2.jpg; result-classic-edge: 0px 0px 213px 5px; } +@spritesheet result-classic-line-sheet { src: ../../../Classic/Trading_line.jpg; result-classic-line: 0px 0px 190px 10px; } +@spritesheet result-classic-btn-sheet { src: "../../../win_button.tga"; result-classic-btn: 0px 0px 49px 16px; } + +#panel { height: 290px; } +/* The stones: #back and the first six middle tiles, 40 apart from y 5; the edges at 0 and 285. */ +#back { top: 5px; width: 230px; height: 40px; decorator: image(result-classic-stone fill); } +#frame_top { height: 5px; decorator: image(result-classic-edge fill); } +.frame-middle { height: 40px; decorator: image(result-classic-stone fill); } +.frame-middles .frame-middle:nth-child(1) { top: 45px; } +.frame-middles .frame-middle:nth-child(2) { top: 85px; } +.frame-middles .frame-middle:nth-child(3) { top: 125px; } +.frame-middles .frame-middle:nth-child(4) { top: 165px; } +.frame-middles .frame-middle:nth-child(5) { top: 205px; } +.frame-middles .frame-middle:nth-child(6) { top: 245px; } +.frame-middles .frame-middle:nth-child(n+7) { display: none; } +#frame_bottom { top: 285px; height: 5px; decorator: image(result-classic-edge fill); } +.line { left: 20px; width: 190px; height: 10px; decorator: image(result-classic-line); } +.line-upper { top: 52px; } +.line-lower { top: 212px; } + +.result-btn { left: 90px; top: 255px; width: 50px; height: 16px; decorator: image(result-classic-btn fill); image-color: #cccccc; } +.result-btn:hover { decorator: image(result-classic-btn fill); image-color: #ffffff; } +.result-btn:active { decorator: image(result-classic-btn fill); image-color: #999999; } +.result-label { color: #e6dcc8; width: calc(50px * var(--root-scale)); } +.result-btn:active .result-label { margin-left: calc(1px * var(--root-scale)); margin-top: calc(1px * var(--root-scale)); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/cursed_temple_system.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/cursed_temple_system.rcss new file mode 100644 index 0000000000..60878f91b3 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/cursed_temple_system.rcss @@ -0,0 +1,201 @@ +/* Classic theme for the Illusion Temple HUD (CCursedTempleSystem; cursed_temple_system.rml is + forked here). 0.97 and the Season 2 client have no Illusion Temple; the time takes the Season 2 + client's event timer (00414514, the Kanturu hourglass, kanturu_info.rcss) at its place, the + bottom centre: hourglass (154 x 23 drawn 154 x 30) at (238, 405), the minutes centred on x 301 and + the seconds on 332 at y 414 in FontTest digits 14 x 14, 9.8 apart, orange (1, 0.6, 0.3) over a + black copy one unit down and right, the dot (3 x 9) between them at (314, 416). (S6's frame at the + right edge would sit under the 0.97 HUD's dragon.) The mini map, the skill panel and the score + are the event's own art (legacy's, below). */ + +/* Legacy theme for CCursedTempleSystem, reproducing its Render() at the 640x480 reference positions + on .screen's HUD board: the frames, the score effect's banners and digits, the digit runs and + the tutorial step's rows and the buttons are here; C++ still places the projected mini-map + markers. */ + +body { pointer-events: none; } + +.screen { + pointer-events: none; + font-family: "token(font-body)"; +} + +.sprite { position: absolute; } +/* The mini map's markers: C++ projects them from the original's (464, 299). */ +#mini_map_markers { position: absolute; left: 464px; top: 299px; } + +.tutorial-line { + display: block; + position: absolute; + left: 140px; + transform-origin: left top; + white-space: nowrap; +} + +/* The HUD's own frames, in the original's places. */ +@spritesheet ct-hud-sheet +{ + src: "../../../newui_ctgametimeframe.tga"; + ct-game-time-frame: 0px 0px 134px 37px; +} +@spritesheet ct-dot-sheet { src: "../../../dot.tga"; ct-dot: 0px 0px 3px 9px; } +@spritesheet ct-skill-frame-sheet { src: "../../../newui_ctskillframe.tga"; ct-skill-frame: 0px 0px 128px 53px; } +@spritesheet ct-minmap-sheet { src: "../../../newui_ctminmap.jpg"; ct-minmap: 0px 0px 128px 128px; } +@spritesheet ct-minmap-frame-sheet { src: "../../../newui_ctminmapframe.tga"; ct-minmap-frame: 0px 0px 128px 165px; } + +.panels, .score, .tutorial { position: static; } +#corner { position: absolute; left: 0; top: 0; width: 0; height: 0; } + +#game_time_frame { position: absolute; left: 506px; top: 393px; width: 134px; height: 37px; + decorator: image(ct-game-time-frame); } +#game_time_dot { position: absolute; left: 574.5px; top: 407.5px; width: 3px; height: 9px; decorator: image(ct-dot); } +#skill_frame { position: absolute; left: 512px; top: 179px; width: 128px; height: 53px; + decorator: image(ct-skill-frame); } +#mini_map { position: absolute; left: 512px; top: 263px; width: 128px; height: 128px; decorator: image(ct-minmap); } +#mini_map_frame { position: absolute; left: 512px; top: 232px; width: 128px; height: 165px; + decorator: image(ct-minmap-frame); } + +/* The digit runs, each starting half its digit count's width left of its x: RenderNumber() at + scale 1 (8.4-unit digits 6.72 apart) and 1.1 (9.6-unit digits 7.68 apart) in newui_number1, + RenderNumber2D() in FontTest (8-unit digits 5.6 apart). */ +.ct-digit { position: absolute; } +.ct-digit.blank { visibility: hidden; } +.ct-time-minutes .ct-digit, .ct-time-seconds .ct-digit { top: 404.5px; width: 9.6px; height: 12.8px; } +.ct-time-minutes .ct-digit { left: calc(559.5px - var(--n) * 4.8px + var(--i) * 7.68px); } +.ct-time-seconds .ct-digit { left: calc(594.5px - var(--n) * 4.8px + var(--i) * 7.68px); } +#ct_alpha .ct-digit, #ct_allied .ct-digit, #ct_illusion .ct-digit { top: 246px; width: 8px; height: 8px; } +#ct_alpha .ct-digit { left: calc(532px - var(--n) * 4px + var(--i) * 5.6px); } +#ct_allied .ct-digit { left: calc(583px - var(--n) * 4px + var(--i) * 5.6px); } +#ct_illusion .ct-digit { left: calc(627px - var(--n) * 4px + var(--i) * 5.6px); } +#ct_kills_needed .ct-digit, #ct_kills .ct-digit { top: 208px; width: 8.4px; height: 11.2px; } +#ct_kills_needed .ct-digit { left: calc(594px - var(--n) * 4.2px + var(--i) * 6.72px); } +#ct_kills .ct-digit { left: calc(616px - var(--n) * 4.2px + var(--i) * 6.72px); } +#skill_icon { position: absolute; left: 539px; top: 200px; width: 20px; height: 28px; } + +/* The panels' area, which holds the pointer, and the skill panel's hover zones (the original's + 18 x 24 boxes over the skill, the kill points it needs and the ones the hero has). */ +#ct_hud_area { position: absolute; left: 512px; top: 179px; width: 128px; height: 255px; } +.ct-hint { position: absolute; top: 203px; width: 18px; height: 24px; } +#ct_hint_skill { left: 540px; } +#ct_hint_kills_needed { left: 595px; } +#ct_hint_kills { left: 617px; } + +/* The buttons: the original's art, its up, over and down frames stacked. */ +@spritesheet ct-alpha-btn-sheet +{ + src: "../../../newui_Bt_clearness_illusion.jpg"; + ct-alpha-btn-up: 0px 0px 38px 24px; + ct-alpha-btn-over: 0px 24px 38px 24px; + ct-alpha-btn-down: 0px 48px 38px 24px; +} +@spritesheet ct-skill-up-btn-sheet +{ + src: "../../../newui_ctskillup.jpg"; + ct-skill-up-btn-up: 0px 0px 15px 13px; + ct-skill-up-btn-over: 0px 13px 15px 13px; + ct-skill-up-btn-down: 0px 26px 15px 13px; +} +@spritesheet ct-skill-down-btn-sheet +{ + src: "../../../newui_ctskilldown.jpg"; + ct-skill-down-btn-up: 0px 0px 15px 13px; + ct-skill-down-btn-over: 0px 13px 15px 13px; + ct-skill-down-btn-down: 0px 26px 15px 13px; +} +.ct-btn { position: absolute; cursor: pointer; pointer-events: auto; } +#ct_btn_alpha { left: 513px; top: 238px; width: 38px; height: 24px; decorator: image(ct-alpha-btn-up); } +#ct_btn_alpha:hover { decorator: image(ct-alpha-btn-over); } +#ct_btn_alpha:active { decorator: image(ct-alpha-btn-down); } +#ct_btn_skill_up { left: 562px; top: 201px; width: 15px; height: 13px; decorator: image(ct-skill-up-btn-up); } +#ct_btn_skill_up:hover { decorator: image(ct-skill-up-btn-over); } +#ct_btn_skill_up:active { decorator: image(ct-skill-up-btn-down); } +#ct_btn_skill_down { left: 562px; top: 214px; width: 15px; height: 13px; decorator: image(ct-skill-down-btn-up); } +#ct_btn_skill_down:hover { decorator: image(ct-skill-down-btn-over); } +#ct_btn_skill_down:active { decorator: image(ct-skill-down-btn-down); } + +/* The score effect's banners and digits. */ +@spritesheet ct-score-colon-sheet { src: "../../../newui_ctscorevs1.tga"; ct-score-colon: 0px 0px 20px 45px; } +@spritesheet ct-score-vs-sheet { src: "../../../newui_ctscorevs0.tga"; ct-score-vs: 0px 0px 49px 27px; } +@spritesheet ct-score-allied-sheet +{ + src: "../../../newui_ctscorealliedgaail.tga"; + ct-score-allied-badge: 0px 0px 40px 36px; +} +@spritesheet ct-score-illusion-sheet +{ + src: "../../../newui_ctscoreillsiongaail.tga"; + ct-score-illusion-badge: 0px 0px 40px 36px; +} +@spritesheet ct-score-left-sheet { src: "../../../newui_ctscoreleft.tga"; ct-score-left: 0px 0px 67px 125px; } +@spritesheet ct-score-right-sheet { src: "../../../newui_ctscoreright.tga"; ct-score-right: 0px 0px 67px 125px; } + +#score_allied_tens, #score_allied_ones, #score_illusion_tens, #score_illusion_ones { + position: absolute; + top: 160px; + width: 56px; + height: 66px; +} +#score_allied_tens { left: 196px; } +#score_allied_ones { left: 224px; } +#score_allied_ones.wide { left: 253px; } +#score_illusion_tens { left: 331px; } +#score_illusion_ones { left: 358px; } +#score_illusion_ones.wide { left: 388px; } +#score_colon { position: absolute; left: 310px; top: 168px; width: 20px; height: 45px; + decorator: image(ct-score-colon); } +#score_allied_badge { position: absolute; left: 232px; top: 115px; width: 40px; height: 36px; + decorator: image(ct-score-allied-badge); } +#score_vs { position: absolute; left: 292px; top: 123px; width: 49px; height: 27px; decorator: image(ct-score-vs); } +#score_illusion_badge { position: absolute; left: 367px; top: 115px; width: 40px; height: 36px; + decorator: image(ct-score-illusion-badge); } +#score_left_banner { position: absolute; left: 133px; top: 115px; width: 67px; height: 125px; + decorator: image(ct-score-left); } +#score_right_banner { position: absolute; left: 445px; top: 115px; width: 67px; height: 125px; + decorator: image(ct-score-right); } + +/* RenderTutorialStep()'s own rows: the step's title at y 50 and its three lines 14 units apart, + with the second row left empty as the original left it. */ +.tutorial-line { color: #ffffff; } +.tutorial-line.title { color: #ffb049; } +.tutorial-line:nth-child(1) { top: 50px; } +.tutorial-line:nth-child(2) { top: 78px; } +.tutorial-line:nth-child(3) { top: 92px; } +.tutorial-line:nth-child(4) { top: 106px; } + +/* The data-for template row has no index of its own; it inherits this one. */ +.ct-run { --i: 0; } + +/* --- Classic: the Season 2 hourglass timer ---------------------------------------------------- */ +@spritesheet ct-classic-glass-sheet { src: "../../../hourglass.tga"; ct-classic-glass: 0px 0px 154px 23px; } +@spritesheet ct-classic-digits-sheet +{ + src: ../../../Classic/Fonttest.tga; + ct-classic-d0: 0px 0px 16px 16px; + ct-classic-d1: 16px 0px 16px 16px; + ct-classic-d2: 32px 0px 16px 16px; + ct-classic-d3: 48px 0px 16px 16px; + ct-classic-d4: 64px 0px 16px 16px; + ct-classic-d5: 80px 0px 16px 16px; + ct-classic-d6: 96px 0px 16px 16px; + ct-classic-d7: 112px 0px 16px 16px; + ct-classic-d8: 128px 0px 16px 16px; + ct-classic-d9: 144px 0px 16px 16px; +} +#game_time_frame { left: 238px; top: 405px; width: 154px; height: 30px; decorator: image(ct-classic-glass); } +#game_time_dot { left: 314px; top: 416px; image-color: rgb(255, 153, 77); } +.ct-time-minutes .ct-digit, .ct-time-seconds .ct-digit { top: 414px; width: 14px; height: 14px; } +.ct-time-minutes .ct-digit { left: calc(301px - var(--n) * 7px + var(--i) * 9.8px); } +.ct-time-seconds .ct-digit { left: calc(332px - var(--n) * 7px + var(--i) * 9.8px); } +.ct-shadow.ct-time-minutes .ct-digit { top: 415px; left: calc(302px - var(--n) * 7px + var(--i) * 9.8px); } +.ct-shadow.ct-time-seconds .ct-digit { top: 415px; left: calc(333px - var(--n) * 7px + var(--i) * 9.8px); } +.ct-ft { image-color: rgb(255, 153, 77); } +.ct-shadow .ct-ft { image-color: #000000; } +.ct-ft.d0 { decorator: image(ct-classic-d0); } +.ct-ft.d1 { decorator: image(ct-classic-d1); } +.ct-ft.d2 { decorator: image(ct-classic-d2); } +.ct-ft.d3 { decorator: image(ct-classic-d3); } +.ct-ft.d4 { decorator: image(ct-classic-d4); } +.ct-ft.d5 { decorator: image(ct-classic-d5); } +.ct-ft.d6 { decorator: image(ct-classic-d6); } +.ct-ft.d7 { decorator: image(ct-classic-d7); } +.ct-ft.d8 { decorator: image(ct-classic-d8); } +.ct-ft.d9 { decorator: image(ct-classic-d9); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/cursed_temple_system.rml b/src/bin/Data/Interface/RmlUi/themes/classic/cursed_temple_system.rml new file mode 100644 index 0000000000..430808c1b4 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/cursed_temple_system.rml @@ -0,0 +1,124 @@ + + + + Illusion Temple HUD (CCursedTempleSystem) + + + + + +
+ +
+
+
+
+
+
+
+ + +
+ +
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ + +
+ + +
+ + +
+
+
+
+
+
+ +
+ {{l.text}} +
+
+ +
diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/devil_square_enter.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/devil_square_enter.rcss new file mode 100644 index 0000000000..c167a53bea --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/devil_square_enter.rcss @@ -0,0 +1,7 @@ +/* Classic (0.97) Devil Square entry. 0.97: the description from y 80, and four plates 140x35 from + y 210, 45 apart, labelled in red (255, 50, 20). MuMain: the description from y 48 to 148, its + seven bands from y 152 to 388, above the Close at 395; more content scrolls. */ +.entry-lines { top: 48px; height: calc(100px * var(--root-scale)); } +.entry-buttons { top: 152px; height: calc(236px * var(--root-scale)); } +.entry-btn { min-height: calc(28px * var(--root-scale)); } +.entry-btn.enabled .entry-label { color: rgb(255, 50, 20); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/docked_panel_frame.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/docked_panel_frame.rcss new file mode 100644 index 0000000000..343a574915 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/docked_panel_frame.rcss @@ -0,0 +1,90 @@ +/* Classic (0.97) frame for the docked single-document windows (character_info, my_quest_info, + pet_info, party_info): 0.97 drew its right-hand windows on Item_Back01 (190x256) over + Item_Back02 (190x177), with the Close button (exit_01, 24x24) at (25, 395). Link this before the window's own + .rcss, as with legacy. The group-box sprites the windows' contents use stay legacy's. */ + +@spritesheet docked-classic-back1-sheet { src: ../../../Classic/Item_back01.jpg; docked-bg-top-a: 0px 0px 190px 256px; } +@spritesheet docked-classic-back1b-sheet { src: ../../../Classic/Item_back01.jpg; docked-bg-top-b: 0px 0px 190px 256px; } +@spritesheet docked-classic-back2-sheet { src: ../../../Classic/Item_Back02.jpg; docked-classic-back2: 0px 0px 190px 177px; } + +@spritesheet docked-corner-tl-sheet { src: "../../../newui_item_table01(L).tga"; docked-corner-tl: 0px 0px 14px 14px; } +@spritesheet docked-corner-tr-sheet { src: "../../../newui_item_table01(R).tga"; docked-corner-tr: 0px 0px 14px 14px; } +@spritesheet docked-corner-bl-sheet { src: "../../../newui_item_table02(L).tga"; docked-corner-bl: 0px 0px 14px 14px; } +@spritesheet docked-corner-br-sheet { src: "../../../newui_item_table02(R).tga"; docked-corner-br: 0px 0px 14px 14px; } +@spritesheet docked-edge-top-sheet { src: "../../../newui_item_table03(Up).tga"; docked-edge-top: 0px 0px 1px 14px; } +@spritesheet docked-edge-bottom-sheet { src: "../../../newui_item_table03(Dw).tga"; docked-edge-bottom: 0px 0px 1px 14px; } +@spritesheet docked-edge-left-sheet { src: "../../../newui_item_table03(L).tga"; docked-edge-left: 0px 0px 14px 1px; } +@spritesheet docked-edge-right-sheet { src: "../../../newui_item_table03(R).tga"; docked-edge-right: 0px 0px 14px 1px; } + +@spritesheet docked-exit-sheet { src: ../../../Classic/Exit_01.jpg; docked-exit-btn: 0px 0px 24px 24px; } +@spritesheet docked-exit2-sheet { src: ../../../Classic/Exit_02.jpg; docked-exit-btn-pressed: 0px 0px 24px 24px; } + +#panel { + position: absolute; + transform-origin: left top; + width: 190px; + height: 433px; + font-family: "token(font-body)"; +} + +.frame-piece { position: absolute; pointer-events: none; } +/* The window's own .rcss picks .frame-top's sprite (docked-bg-top-a or -b): both are Item_Back01 + here. .frame-left carries Item_Back02; the other two pieces are not part of the 0.97 frame. */ +.frame-top { left: 0; top: 0; width: 190px; height: 256px; } +.frame-left { left: 0; top: 256px; width: 190px; height: 177px; decorator: image(docked-classic-back2); } +.frame-right, .frame-bottom { display: none; } + +.gbox-corner { position: absolute; width: 14px; height: 14px; pointer-events: none; } +.gbox-edge { position: absolute; pointer-events: none; } +.gbox-edge-top { height: 14px; decorator: image(docked-edge-top); } +.gbox-edge-bottom { height: 14px; decorator: image(docked-edge-bottom); } +.gbox-edge-left { width: 14px; decorator: image(docked-edge-left); } +.gbox-edge-right { width: 14px; decorator: image(docked-edge-right); } +.gbox-title-fill { position: absolute; background-color: token(surface-panel-title); pointer-events: none; } +.gbox-content-fill { position: absolute; background-color: token(surface-panel-content); pointer-events: none; } +.gbox-title-text { + display: block; + position: absolute; + text-align: center; + font-weight: bold; + font-size: 1em; + color: token(text-heading); + pointer-events: none; +} + +#btn_exit { + position: absolute; + left: 25px; + top: 395px; + width: 24px; + height: 24px; + cursor: pointer; + pointer-events: auto; + decorator: image(docked-exit-btn); +} +#btn_exit:active { decorator: image(docked-exit-btn-pressed); } + +#panel.fill-placement { box-sizing: border-box; } +/* 0.97 has no corner close. */ +#frame_corner_close { display: none; } + +/* Scrolling lists: the Season 1 client's win_scrollbar (as the classic social windows'), in place of + base.rcss's S6 track and knob: 13x13 arrows at both ends, the track between two 106,97,88 lines, + a grey thumb sized to the list. */ +@spritesheet docked-scroll-sheet +{ + src: "../../../win_scrollbar.jpg"; + docked-scroll-thumb: 0px 1px 11px 1px; + docked-scroll-up: 0px 3px 13px 13px; + docked-scroll-down: 0px 16px 13px 13px; +} +.scroll-pane scrollbarvertical { width: 13dp; margin: 0; } +.scroll-pane scrollbarvertical slidertrack { decorator: none; box-sizing: border-box; border-left: 1dp rgb(106, 97, 88); border-right: 1dp rgb(106, 97, 88); } +.scroll-pane scrollbarvertical sliderbar { height: auto; min-height: 6dp; margin: 0 1dp; decorator: image(docked-scroll-thumb fill); } +.scroll-pane scrollbarvertical sliderbar:active { filter: none; } +.scroll-pane scrollbarvertical sliderarrowdec, +.scroll-pane scrollbarvertical sliderarrowinc { width: 100%; height: 13dp; pointer-events: auto; } +.scroll-pane scrollbarvertical sliderarrowdec { decorator: image(docked-scroll-up); } +.scroll-pane scrollbarvertical sliderarrowinc { decorator: image(docked-scroll-down); } +.scroll-pane scrollbarvertical sliderarrowdec:active, +.scroll-pane scrollbarvertical sliderarrowinc:active { filter: brightness(0.7); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/doppelganger_enter_rows.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/doppelganger_enter_rows.rcss new file mode 100644 index 0000000000..9d1d122fc8 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/doppelganger_enter_rows.rcss @@ -0,0 +1,53 @@ +/* Classic rows for Lugard's Doppelganger entry (CDoppelGangerWindow). 0.97 has no such window; it takes the + classic Golden Archer's parts (gold_bowman.rcss): the 0.97 frame, the entry button on a 0.97 text + plate (Message_box, 120 x 22) lit warm under the mouse and darkened while locked, the 0.97 Close + (Exit_01, Exit_02 pressed) at (25, 395) in place of the bottom button, and 0.97's divider + (Trading_line) in place of the S6 separator. Legacy's rows first, then the classic rules. */ + +/* Where doppelganger_enter.rml's own lines and buttons sit. CDoppelGangerWindow's RenderTexts(): the name bold in its 160-unit box, the description centred on 190 from y 50, the buttons 53 x 23 at x 68. + The look they share is event_item_entry.rcss; only the rows are this document's. */ + +.entry-text:nth-child(1) { left: 15px; top: 13px; color: #dcdcdc; font-weight: bold; } +.entry-text:nth-child(2) { left: 0px; top: 50px; color: #dcdcdc; } +.entry-text:nth-child(3) { left: 0px; top: 65px; color: #dcdcdc; } +.entry-text:nth-child(4) { left: 0px; top: 80px; color: #dcdcdc; } +.entry-text:nth-child(5) { left: 0px; top: 95px; color: #dcdcdc; } +.entry-text:nth-child(6) { left: 0px; top: 110px; color: #dcdcdc; } +.entry-text:nth-child(7) { left: 0px; top: 170px; color: #dcdcdc; font-weight: bold; } +.entry-text:nth-child(8) { left: 0px; top: 260px; color: #dcdcdc; } +.entry-text:nth-child(9) { left: 0px; top: 280px; color: #dcdcdc; } + +.entry-btn:nth-child(1) { left: 68px; top: 190px; width: 53px; height: 23px; } +.entry-btn:nth-child(1) { decorator: image(item-entry-btn-up); } +.entry-btn:nth-child(1):hover { decorator: image(item-entry-btn-over); } +.entry-btn:nth-child(1):active { decorator: image(item-entry-btn-down); } +.entry-btn:nth-child(1).locked, .entry-btn:nth-child(1).locked:hover, .entry-btn:nth-child(1).locked:active { decorator: image(item-entry-btn-up); image-color: #646464; } + +.entry-btn:nth-child(2) { left: 68px; top: 360px; width: 53px; height: 23px; } +.entry-btn:nth-child(2) { decorator: image(item-entry-btn-up); } +.entry-btn:nth-child(2):hover { decorator: image(item-entry-btn-over); } +.entry-btn:nth-child(2):active { decorator: image(item-entry-btn-down); } +.entry-btn:nth-child(2).locked, .entry-btn:nth-child(2).locked:hover, .entry-btn:nth-child(2).locked:active { decorator: image(item-entry-btn-up); image-color: #646464; } + +/* The name's box is 160 wide. */ +.entry-text:nth-child(1) { width: 160px; } + +/* Where C++ draws the live 3D preview: the original's place and size. */ +.entry-item-box { position: absolute; left: 85px; top: 125px; width: 20px; height: 27px; pointer-events: none; } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet dg-classic-plate-sheet { src: ../../../Classic/Message_box.jpg; dg-classic-plate: 0px 0px 213px 64px; } +@spritesheet dg-classic-exit-sheet { src: ../../../Classic/Exit_01.jpg; dg-classic-exit: 0px 0px 24px 24px; } +@spritesheet dg-classic-exit2-sheet { src: ../../../Classic/Exit_02.jpg; dg-classic-exit-pressed: 0px 0px 24px 24px; } +@spritesheet dg-classic-line-sheet { src: ../../../Classic/Trading_line.jpg; dg-classic-line: 0px 0px 190px 10px; } + +.entry-line { left: 0; top: 225px; width: 190px; height: 10px; decorator: image(dg-classic-line); } +.entry-label { color: #ffffff; } +.entry-btn.locked .entry-label { color: #808080; } +.entry-btn:nth-child(1) { left: 35px; top: 190px; width: 120px; height: 22px; decorator: image(dg-classic-plate fill); image-color: #ffffff; } +.entry-btn:nth-child(1):hover, .entry-btn:nth-child(1):active { decorator: image(dg-classic-plate fill); image-color: #ffd9b3; } +.entry-btn:nth-child(1).locked, .entry-btn:nth-child(1).locked:hover, .entry-btn:nth-child(1).locked:active { decorator: image(dg-classic-plate fill); image-color: #666666; } +.entry-btn:nth-child(2) { left: 25px; top: 395px; width: 24px; height: 24px; decorator: image(dg-classic-exit); } +.entry-btn:nth-child(2):hover { decorator: image(dg-classic-exit); image-color: #ffffff; } +.entry-btn:nth-child(2):active { decorator: image(dg-classic-exit-pressed); image-color: #ffffff; } +.entry-btn:nth-child(2) .entry-label { display: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/duel_watch.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/duel_watch.rcss new file mode 100644 index 0000000000..346ef30d2b --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/duel_watch.rcss @@ -0,0 +1,95 @@ +/* Classic theme for Doorkeeper Titus's duel channels (CDuelWatchWindow). 0.97 and Season 1 have + no duel arena; the window takes the classic entry windows' parts: the 0.97 frame, 0.97's divider + (Trading_line, 190 x 10, centred on the S6 separator's row) and the Watch button on a 0.97 text + plate (Message_box, 120 x 22 at (35, 100)) tinted (0.9, 0.8, 0.7), lit white under the mouse, + darkened (0.4, 0.4, 0.5) with a grey label while locked, as the classic market's Warp. Legacy's + rules first, then the classic ones. */ + +/* Legacy theme for CDuelWatchWindow, reproducing its RenderFrame()/Render(): the + docked_panel_frame.rcss frame (linked first; newui_item_back01 top), "Doorkeeper Titus" bold + (220, 220, 220) centred on 160 units from x 15 at y 13, the prompt bold at y 50 centred on 190 + (left aligned when it overflows, like the original), three newui_myquest_Line separators + (188 x 21) at y 130 + 90 k, and per colosseum (90 units apart from y 50): the heading bold + (255, 255, 128) at + 20, "VS" red (255, 50, 50) centred at + 35 with the players centred in + 70-unit boxes at x 20 and 100, or "No duel on." white, and the 53 x 23 Watch button at + (68, 100): newui_btn_empty_very_small up / over / down, tinted (100, 100, 100) with a grey + label while locked. Coordinates are reference px inside #panel. */ + +@spritesheet dw-btn-sheet +{ + src: "../../../newui_btn_empty_very_small.tga"; + dw-btn-up: 0px 0px 53px 23px; + dw-btn-over: 0px 23px 53px 23px; + dw-btn-down: 0px 46px 53px 23px; +} +@spritesheet dw-line-sheet { src: "../../../newui_myquest_Line.tga"; dw-line: 0px 0px 188px 21px; } + +.frame-top { decorator: image(docked-bg-top-b); } +#panel { pointer-events: auto; } + +.sharp-text { display: block; position: absolute; white-space: nowrap; text-align: center; pointer-events: none; } + +#title { left: 15px; top: 13px; font-weight: bold; color: #dcdcdc; } +#subtitle { left: 0; top: 50px; font-weight: bold; color: #dcdcdc; } + +.line { position: absolute; left: 1px; width: 188px; height: 21px; decorator: image(dw-line); } + +.room { display: block; position: absolute; left: 0; width: 190px; height: 90px; } +.room-heading { left: 0; top: 70px; font-weight: bold; color: #ffff80; } +.room-vs { left: 0; top: 85px; color: #ff3232; } +.room-player { top: 85px; color: #ffffff; } +.room-player-1 { left: 20px; } +.room-player-2 { left: 100px; } +.room-empty { left: 0; top: 85px; color: #ffffff; } + +.watch-btn { + display: block; + position: absolute; + left: 68px; + top: 100px; + width: 53px; + height: 23px; + decorator: image(dw-btn-up); + image-color: #646464; + pointer-events: auto; +} +.watch-btn.enabled { image-color: #ffffff; } +.watch-btn.enabled:hover { decorator: image(dw-btn-over); } +.watch-btn.enabled:active { decorator: image(dw-btn-down); } +.watch-label { left: 0; color: #646464; } +.watch-btn.enabled .watch-label { color: #ffffff; } + +/* The three separators and the four colosseum blocks, 90 units apart as the original drew them. */ +.lines, .rooms { position: static; } +.lines .line:nth-child(1) { top: 130px; } +.lines .line:nth-child(2) { top: 220px; } +.lines .line:nth-child(3) { top: 310px; } +.room:nth-child(1) { top: 0; } +.room:nth-child(2) { top: 90px; } +.room:nth-child(3) { top: 180px; } +.room:nth-child(4) { top: 270px; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#title { width: calc(160px * var(--root-scale)); } +#subtitle { width: calc(190px * var(--root-scale)); } +.room-heading { width: calc(190px * var(--root-scale)); } +.room-vs { width: calc(190px * var(--root-scale)); } +.room-player.room-player-1 { width: calc(70px * var(--root-scale)); } +.room-player.room-player-2 { width: calc(70px * var(--root-scale)); } +.room-empty { width: calc(190px * var(--root-scale)); } +.watch-label { width: calc(53px * var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet dw-classic-line-sheet { src: ../../../Classic/Trading_line.jpg; dw-classic-line: 0px 0px 190px 10px; } +@spritesheet dw-classic-plate-sheet { src: ../../../Classic/Message_box.jpg; dw-classic-plate: 0px 0px 213px 64px; } +.line { left: 0; width: 190px; height: 10px; margin-top: 5px; decorator: image(dw-classic-line); } +.watch-btn { left: 35px; width: 120px; height: 22px; decorator: image(dw-classic-plate fill); image-color: #66667f; } +.watch-btn.enabled { image-color: #e6ccb3; } +.watch-btn.enabled:hover, .watch-btn.enabled:active { decorator: image(dw-classic-plate fill); image-color: #ffffff; } +.watch-label { color: #808080; font-weight: bold; } +.watch-btn.enabled .watch-label { color: #ffffff; } +.watch-label { width: calc(120px * var(--root-scale)); } +/* The window's only close is the corner one, which the classic frame hides: shown as the 0.97 + Close at (25, 395), the docked windows' place. */ +#frame_corner_close { display: block; position: absolute; left: 25px; top: 395px; width: 24px; height: 24px; cursor: pointer; pointer-events: auto; decorator: image(docked-exit-btn); } +#frame_corner_close:active { decorator: image(docked-exit-btn-pressed); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/duel_watch_frame.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/duel_watch_frame.rcss new file mode 100644 index 0000000000..52523a2385 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/duel_watch_frame.rcss @@ -0,0 +1,95 @@ +/* Classic theme for the spectator's duel HUD (CDuelWatchMainFrameWindow). 0.97 and Season 1 have + no duel arena: the bar keeps the arena's own art (menu_pk_*), the gauges and the score marks; + the exit is the 0.97 Close (Exit_01, Exit_02 pressed) at the bar's right end. Legacy's rules + first, then the classic ones. */ + +/* Legacy theme for CDuelWatchMainFrameWindow, reproducing its Render(): menu_pk_01 (256 x 51) at + 0, menu_pk_02 (128 x 51) at 256, menu_pk_03 (256 x 51) at 384; the gauge pieces where C++ places + them (their textures unscaled from texel 0, the left health bar mirrored); a score mark + (menu_pk_bt02, 16 x 17) per point at y 31; the names centred on 55 units at y 36 in the bold + font, white; the exit button newui_exit_00 (36 x 29) at (604, 22), registered without an over + image, so hovering keeps the up row and pressing shows the second. Reference px inside the + 640 x 51 #panel (the original's y 429 is its top), under .screen's uniform HUD scale. */ + +@spritesheet dwf-back1-sheet { src: "../../../menu_pk_01.jpg"; dwf-back1: 0px 0px 256px 51px; } +@spritesheet dwf-back2-sheet { src: "../../../menu_pk_02.jpg"; dwf-back2: 0px 0px 128px 51px; } +@spritesheet dwf-back3-sheet { src: "../../../menu_pk_03.jpg"; dwf-back3: 0px 0px 256px 51px; } +@spritesheet dwf-score-sheet { src: "../../../menu_pk_bt02.tga"; dwf-score: 0px 0px 16px 17px; } +@spritesheet dwf-exit-sheet +{ + src: "../../../newui_exit_00.tga"; + dwf-exit-up: 0px 0px 36px 29px; + dwf-exit-down: 0px 29px 36px 29px; +} + +body { pointer-events: none; } + +.screen { + position: absolute; + left: 0; + top: 0; + width: 640px; + height: 480px; + transform-origin: left top; + pointer-events: none; +} + +/* The HUD itself, at its workspace slot. */ +#panel { position: absolute; width: 640px; height: 51px; } + +#back1 { position: absolute; left: 0; top: 0; width: 256px; height: 51px; decorator: image(dwf-back1); } +#back2 { position: absolute; left: 256px; top: 0; width: 128px; height: 51px; decorator: image(dwf-back2); } +#back3 { position: absolute; left: 384px; top: 0; width: 256px; height: 51px; decorator: image(dwf-back3); } + +#fight { position: absolute; left: 0; top: 0; width: 640px; height: 51px; } +.gauge { position: absolute; } +.gauge.mirrored { transform: scale(-1, 1); } + +/* A mark per point, 17 apart: the left fighter's from x 57 rightwards, the right one's from x 566 + leftwards. */ +.score-row { display: flex; position: absolute; top: 31px; height: 17px; } +#score_hero { left: 57px; flex-direction: row; } +#score_enemy { right: 58px; flex-direction: row-reverse; } +.score { flex: 0 0 auto; width: 16px; height: 17px; decorator: image(dwf-score); } +#score_hero .score { margin-right: 1px; } +#score_enemy .score { margin-left: 1px; } + +.name { + display: block; + position: absolute; + top: 36px; + transform-origin: left top; + white-space: nowrap; + text-align: center; + font-family: "token(font-body)"; + font-weight: bold; + color: #ffffff; +} + +#exit { + position: absolute; + left: 604px; + top: 22px; + width: 36px; + height: 29px; + decorator: image(dwf-exit-up); + pointer-events: auto; +} +#exit:active { decorator: image(dwf-exit-down); } + +/* Each fighter's name on its own side, centred on 55 units as RenderText() centred it. */ +#name_hero { left: 240px; } +#name_enemy { left: 345px; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#name_hero { width: calc(55px * var(--root-scale)); } +#name_enemy { width: calc(55px * var(--root-scale)); } + +/* The HUD takes no pointer events where it is placed (base.rcss gives a placed panel them). */ +#panel.slot-placed { pointer-events: none; } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet dwf-classic-exit-sheet { src: ../../../Classic/Exit_01.jpg; dwf-classic-exit: 0px 0px 24px 24px; } +@spritesheet dwf-classic-exit2-sheet { src: ../../../Classic/Exit_02.jpg; dwf-classic-exit-pressed: 0px 0px 24px 24px; } +#exit { left: 610px; top: 24px; width: 24px; height: 24px; decorator: image(dwf-classic-exit); } +#exit:active { decorator: image(dwf-classic-exit-pressed); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/duel_watch_spectators.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/duel_watch_spectators.rcss new file mode 100644 index 0000000000..64c7467199 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/duel_watch_spectators.rcss @@ -0,0 +1,59 @@ +/* Classic theme for the duel spectator list (CDuelWatchUserListWindow). 0.97 has no spectators; + the list takes the classic party list's boxes (party_list.rcss, the 0.97 client's 004ef160): + dark (0.1 grey at 70%), no frame art, the name in white. Legacy's rules first, then the classic + ones. */ + +/* Legacy theme for CDuelWatchUserListWindow, reproducing its Render(): each box a flat fill (the + original's RenderColor() in the colour its frame left current, measured in the original client) + under Pk_box (57 x 17, its middle transparent), the name centred on it in the normal font. + Reference px under .screen's uniform HUD scale. */ + +@spritesheet dws-box-sheet { src: "../../../Pk_box.tga"; dws-box: 0px 0px 57px 17px; } + +body { pointer-events: none; } + +.screen { + position: absolute; + left: 0; + top: 0; + width: 640px; + height: 480px; + transform-origin: left top; + pointer-events: none; +} + +/* The window's position is the list's bottom-left corner: the slots stack upwards from it, 18 + apart, each a 57 x 17 box with the name centred on it, one unit down. */ +.anchor { position: absolute; width: 57px; height: 0; } +.stack { display: block; position: absolute; left: 0; bottom: 0; width: 57px; } +.slot { display: block; position: relative; width: 57px; height: 18px; } +.box { + position: absolute; + left: 0; + top: 0; + width: 57px; + height: 17px; + background-color: #6a6158; + decorator: image(dws-box); +} + +.name { + display: block; + position: absolute; + left: 0; + top: 1px; + transform-origin: left top; + white-space: nowrap; + text-align: center; + font-family: "token(font-body)"; + color: #ffffff; +} + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +.name { width: calc(57px * var(--root-scale)); line-height: calc(17px * var(--root-scale)); } + +/* The HUD takes no pointer events where it is placed (base.rcss gives a placed panel them). */ +#panel.slot-placed { pointer-events: none; } + +/* --- Classic ---------------------------------------------------------------------------------- */ +.box { decorator: none; background-color: rgba(26, 26, 26, 179); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/duel_window.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/duel_window.rcss new file mode 100644 index 0000000000..05202ffb62 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/duel_window.rcss @@ -0,0 +1,53 @@ +/* Classic theme for CDuelWindow (duel_window.rml is forked here). 0.97 has no duel; the Season 1 + client's score (00580440) is a band at the top of the area the open windows leave + free: black at 50%, 300 x 40 from y 20, centred, edged by 1-unit lines (0.65, 0.53, 0.34); the + names in the bold font with a black shadow one unit down and right, centred at y 30 (the hero + blue (0, 150, 255) 80 left of the centre, "vs" orange (255, 150, 0) on it, the opponent red + (255, 25, 25) 80 right of it), and the scores in the big font at y 48 under each name. The + classic workspace centres the 640 frame on the free area, so the band's left is 170 in it. + Reference px relative to the band's top-left, under .screen's W/640 x H/480 stretch. */ + +body { pointer-events: none; } + +.screen { + position: absolute; + left: 0; + top: 0; + width: 640px; + height: 480px; + transform-origin: left top; + pointer-events: none; +} + +#panel { position: absolute; width: 300px; height: 40px; font-family: "token(font-body)"; } +#back { + position: absolute; + left: 0; + top: 0; + width: 300px; + height: 40px; + box-sizing: border-box; + background-color: rgba(0, 0, 0, 128); + border-width: 1px; + border-color: rgb(166, 135, 87); +} + +/* Each text centred on its x: a 200-unit box (counter-scaled) whose middle is that x. */ +.duel-text { + display: block; + position: absolute; + transform-origin: left top; + white-space: nowrap; + text-align: center; + font-weight: bold; + width: calc(200px * var(--root-scale, 1)); + font-effect: shadow(1px 1px black); +} +.duel-text.hero { color: #0096ff; left: -30px; } +.duel-text.vs { color: #ff9600; left: 50px; } +.duel-text.enemy { color: #ff1919; left: 130px; } +#hero_name, #duel_vs, #enemy_name { top: 10px; } +.duel-text.score { top: 28px; font-effect: none; } + +/* The HUD takes no pointer events where it is placed (base.rcss gives a placed panel them). */ +#panel.slot-placed { pointer-events: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/duel_window.rml b/src/bin/Data/Interface/RmlUi/themes/classic/duel_window.rml new file mode 100644 index 0000000000..efbb4b77db --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/duel_window.rml @@ -0,0 +1,24 @@ + + + Duel + + + + + +
+
+
+ {{hero_name}} + vs + {{enemy_name}} + {{hero_score}} + {{enemy_score}} +
+
+ +
diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/empire_guardian_enter_rows.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/empire_guardian_enter_rows.rcss new file mode 100644 index 0000000000..7d72cb22bf --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/empire_guardian_enter_rows.rcss @@ -0,0 +1,57 @@ +/* Classic rows for Jerint's Imperial Guardian entry (CEmpireGuardianNPC). 0.97 has no such window; it takes the + classic Golden Archer's parts (gold_bowman.rcss): the 0.97 frame, the entry button on a 0.97 text + plate (Message_box, 120 x 22) lit warm under the mouse and darkened while locked, the 0.97 Close + (Exit_01, Exit_02 pressed) at (25, 395) in place of the bottom button, and 0.97's divider + (Trading_line) in place of the S6 separator. Legacy's rows first, then the classic rules. */ + +/* Where empire_guardian_enter.rml's own lines and buttons sit. CEmpireGuardianNPC's RenderTexts(): the headings bold in their 110-unit box centred on the panel, the warning red, the round-7 note on 200 units from x -5. + The look they share is event_item_entry.rcss; only the rows are this document's. */ + +.entry-text:nth-child(1) { left: 40px; top: 13px; color: #dcdcdc; font-weight: bold; } +.entry-text:nth-child(2) { left: 0px; top: 50px; color: #dcdcdc; } +.entry-text:nth-child(3) { left: 0px; top: 70px; color: #dcdcdc; } +.entry-text:nth-child(4) { left: 0px; top: 90px; color: #dcdcdc; } +.entry-text:nth-child(5) { left: 0px; top: 110px; color: #dcdcdc; } +.entry-text:nth-child(6) { left: 40px; top: 170px; color: rgb(255, 240, 0); font-weight: bold; } +.entry-text:nth-child(7) { left: 40px; top: 260px; color: rgb(255, 0, 0); font-weight: bold; } +.entry-text:nth-child(8) { left: -5px; top: 280px; color: #dcdcdc; } +.entry-text:nth-child(9) { left: -5px; top: 300px; color: #dcdcdc; } +.entry-text:nth-child(10) { left: -5px; top: 320px; color: #dcdcdc; } +.entry-text:nth-child(11) { left: 0px; top: 340px; color: #dcdcdc; } +.entry-text:nth-child(12) { left: 0px; top: 360px; color: #dcdcdc; } + +.entry-btn:nth-child(1) { left: 68px; top: 190px; width: 53px; height: 23px; } +.entry-btn:nth-child(1) { decorator: image(item-entry-btn-up); } +.entry-btn:nth-child(1):hover { decorator: image(item-entry-btn-over); } +.entry-btn:nth-child(1):active { decorator: image(item-entry-btn-down); } +.entry-btn:nth-child(1).locked, .entry-btn:nth-child(1).locked:hover, .entry-btn:nth-child(1).locked:active { decorator: image(item-entry-btn-up); image-color: #646464; } + +.entry-btn:nth-child(2) { left: 68px; top: 380px; width: 53px; height: 23px; } +.entry-btn:nth-child(2) { decorator: image(item-entry-btn-up); } +.entry-btn:nth-child(2):hover { decorator: image(item-entry-btn-over); } +.entry-btn:nth-child(2):active { decorator: image(item-entry-btn-down); } +.entry-btn:nth-child(2).locked, .entry-btn:nth-child(2).locked:hover, .entry-btn:nth-child(2).locked:active { decorator: image(item-entry-btn-up); image-color: #646464; } + +/* The bold lines' boxes are 110 wide, the party warning's 200. */ +.entry-text:nth-child(1), .entry-text:nth-child(6), .entry-text:nth-child(7) { width: 110px; } +.entry-text:nth-child(n+8) { width: 200px; } + +/* Where C++ draws the live 3D preview: the original's place and size. */ +.entry-item-box { position: absolute; left: 85px; top: 120px; width: 20px; height: 27px; pointer-events: none; } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet eg-classic-plate-sheet { src: ../../../Classic/Message_box.jpg; eg-classic-plate: 0px 0px 213px 64px; } +@spritesheet eg-classic-exit-sheet { src: ../../../Classic/Exit_01.jpg; eg-classic-exit: 0px 0px 24px 24px; } +@spritesheet eg-classic-exit2-sheet { src: ../../../Classic/Exit_02.jpg; eg-classic-exit-pressed: 0px 0px 24px 24px; } +@spritesheet eg-classic-line-sheet { src: ../../../Classic/Trading_line.jpg; eg-classic-line: 0px 0px 190px 10px; } + +.entry-line { left: 0; top: 225px; width: 190px; height: 10px; decorator: image(eg-classic-line); } +.entry-label { color: #ffffff; } +.entry-btn.locked .entry-label { color: #808080; } +.entry-btn:nth-child(1) { left: 35px; top: 190px; width: 120px; height: 22px; decorator: image(eg-classic-plate fill); image-color: #ffffff; } +.entry-btn:nth-child(1):hover, .entry-btn:nth-child(1):active { decorator: image(eg-classic-plate fill); image-color: #ffd9b3; } +.entry-btn:nth-child(1).locked, .entry-btn:nth-child(1).locked:hover, .entry-btn:nth-child(1).locked:active { decorator: image(eg-classic-plate fill); image-color: #666666; } +.entry-btn:nth-child(2) { left: 25px; top: 395px; width: 24px; height: 24px; decorator: image(eg-classic-exit); } +.entry-btn:nth-child(2):hover { decorator: image(eg-classic-exit); image-color: #ffffff; } +.entry-btn:nth-child(2):active { decorator: image(eg-classic-exit-pressed); image-color: #ffffff; } +.entry-btn:nth-child(2) .entry-label { display: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/event_entry.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/event_entry.rcss new file mode 100644 index 0000000000..affaf0cf81 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/event_entry.rcss @@ -0,0 +1,93 @@ +/* Classic (0.97) event entry windows (CEnterDevilSquare, CEnterBloodCastle), from the 0.97 + client's 004f3c50, on the shared markup's current contract (the description and the level bands + are bounded, scrolling flow panes; each band draws its art on .entry-btn-art): the + docked_panel_frame.rcss frame, the title in 0.97's 120-wide box at (35, 12), the description in + white, centred, wrapping inside its pane, and one Message_box plate per level band (0.97: 140 + wide at x 25), tinted (0.9, 0.8, 0.7) and lit white under the mouse, its label centred; a band the + hero cannot enter is darkened (0.4, 0.4, 0.5). MuMain lists more bands than 0.97 (7 and 8 against + 4 and 6), so the bands are lower and closer than 0.97's 33-35 / 40-45; each window's .rcss places + its panes. */ + +@spritesheet entry-classic-plate-sheet { src: ../../../Classic/Message_box.jpg; entry-classic-plate: 0px 0px 213px 64px; } + +.frame-top { decorator: image(docked-bg-top-b); } +#panel { pointer-events: auto; } + +#title { + display: block; + position: absolute; + left: 35px; + top: 12px; + --flow-w: 120px; + font-weight: bold; + line-height: 1.1; + text-align: center; + white-space: normal; + word-break: break-word; + color: #dcdcdc; + pointer-events: none; +} + +/* The panes: the description across the window inside its frame, the bands in 0.97's 140-wide + column at x 25 (the pane 150 wide, its scrollbar outside the plates). */ +.entry-lines, .entry-buttons { position: absolute; } +.entry-lines { + left: 12px; + --flow-w: 166px; + line-height: 1.1; + text-align: center; +} +.entry-line { + display: block; + white-space: normal; + word-break: break-word; + padding: 0 2px; + color: #ffffff; + pointer-events: none; +} +.entry-line + .entry-line { margin-top: 0.25em; } + +.entry-buttons { + left: 25px; + --flow-w: 155px; + font-weight: bold; + line-height: 1.1; +} +/* A block, not legacy's flex column: in this build an absolutely placed child of a flex item is + sized against the item's content, not its padded box, and the plate came out a strip. */ +.entry-btn { + display: block; + position: relative; + box-sizing: border-box; + width: calc(140px * var(--root-scale)); + min-height: calc(24px * var(--root-scale)); + padding: calc(4px * var(--root-scale)) calc(6px * var(--root-scale)); + pointer-events: auto; +} +.entry-btn + .entry-btn { margin-top: calc(3px * var(--root-scale)); } +.entry-btn-art { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + pointer-events: none; + decorator: image(entry-classic-plate fill); + image-color: #66667f; +} +.entry-btn.enabled .entry-btn-art { image-color: #e6ccb3; } +.entry-btn.enabled:hover .entry-btn-art, .entry-btn.enabled:active .entry-btn-art { image-color: #ffffff; } +.entry-label { + display: block; + position: relative; + text-align: center; + white-space: normal; + word-break: break-word; + color: #808080; + pointer-events: none; +} + +/* The panes are already physical-sized: their scrollbars too. */ +.entry-lines scrollbarvertical, .entry-buttons scrollbarvertical { width: calc(13px * var(--root-scale)); } + +.entry-exit-glyph { display: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/event_timer.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/event_timer.rcss new file mode 100644 index 0000000000..dcc531658f --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/event_timer.rcss @@ -0,0 +1,60 @@ +/* Classic (0.97) theme for the event time HUDs. 0.97 has only Blood Castle's (004bf2d0): no frame, + three lines centred at x 570 of its 640x480 frame, the kill count ("Monster: (k / n)") at y 345 + and "Remain time" at 357 in the normal font, the time at 367 in the big font, orange (255, 150, + 0), the time red under five minutes. Chaos Castle's and the Imperial Guardian's (no 0.97 + counterpart) take the same look. The rest is legacy's (newui_Figure_blood, 124 x 81, + lines at y 13 / 38 / 50 of it). Reference px relative to the window's top-left, under .screen's + W/640 x H/480 stretch; the classic workspace puts the window's top at y 351 and its centre at + x 575 (workspace.rcss). */ + +@spritesheet timer-back-sheet { src: "../../../newui_Figure_blood.tga"; timer-back: 0px 0px 124px 81px; } + +body { pointer-events: none; } + +.screen { + position: absolute; + left: 0; + top: 0; + width: 640px; + height: 480px; + transform-origin: left top; + pointer-events: none; +} + +#panel { position: absolute; width: 124px; height: 81px; font-family: "token(font-body)"; } +#back { position: absolute; left: 0; top: 0; width: 124px; height: 81px; decorator: image(timer-back); } + +.timer-text { + display: block; + position: absolute; + left: 0; + transform-origin: left top; + white-space: nowrap; + text-align: center; +} +#kills { top: 13px; } +#time_left { top: 38px; } +#time { top: 50px; font-weight: bold; } + +/* How pressing the line is: the original's own colours per state. */ +.timer-text.plain { color: #ffffff; } +.timer-text.standby { color: rgb(10, 200, 10); } +.timer-text.normal { color: rgb(255, 150, 0); } +.timer-text.closing { color: rgb(255, 70, 0); } +.timer-text.imminent { color: rgb(255, 32, 32); } +.timer-text.expiring { color: rgb(255, 0, 0); } + +/* Each line's box, in the panel's reference px, counter-scaled with the line: the frame's width, + or the Imperial Guardian's 110 centred on it. */ +.timer-text { --box-width: 124px; width: calc(var(--box-width) * var(--root-scale)); } +#panel.empire-guardian .timer-text { left: 7px; --box-width: 110px; } + +/* The HUD takes no pointer events where it is placed (base.rcss gives a placed panel them). */ +#panel.slot-placed { pointer-events: none; } + +/* 0.97: no frame, the lines 5 units left of the window's centre (x 570) at y 345, 357 and 367. */ +#back { display: none; } +#panel .timer-text, #panel.empire-guardian .timer-text { left: -5px; --box-width: 124px; } +#kills { top: -6px; } +#time_left { top: 6px; } +#time { top: 16px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/friend_shell.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/friend_shell.rcss new file mode 100644 index 0000000000..fd8be20785 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/friend_shell.rcss @@ -0,0 +1,241 @@ +/* Classic theme for the friends shell: the Season 1 client's window (CUIFriendWindow, the code this + client's own native window ran before its RmlUi port; Season 1's main.exe draws it with the same + palette, 480000.c). Not 0.97's: 0.97 has no friend system. Where legacy wraps the window in the + message box's stone frame, Season 1 drew flat lines in its window palette (SetLineColor()): + - the body black at 179/255, a 5-unit outline on every side (146,134,121 / 37,37,37 three units / + 106,97,88), and a 15-unit title bar (win_titlebar) at (6, 5) closed by a 106,97,88 line at y 20, + the title in bold at (9, 8) in 230,220,200, minimize / maximize / close (win_size, 9x9) at + w-38 / w-27 / w-16, y 8, the resize grip (win_resize) at the bottom-right corner; + - inside (5 units in, 21 down), a black strip with three 53x19 tabs drawn in lines (the selected + one 53,49,48 and open below, the others 26,22,21), "refuse chat" right-aligned on it, and from + y 21 the page: a 53,49,48 header band 16 high, the list, and a black foot 22 high with the + buttons (win_button, 50x14) at x 2, 53, 104 and 155, 17 above the bottom (64 wide here); + - list scrollbars of win_scrollbar: 13x13 arrows at both ends, the track between two lines, a + grey thumb sized to the list. + 1dp is one of the window's units. The window, its tabs and its buttons are wider than Season 1's + (below) for longer captions. */ + +@spritesheet fs-titlebar-sheet { src: "../../../win_titlebar.jpg"; fs-titlebar: 0px 0px 4px 15px; } +@spritesheet fs-size-sheet +{ + src: "../../../win_size.jpg"; + fs-minimize: 0px 0px 9px 9px; + fs-maximize: 9px 0px 9px 9px; + fs-restore: 9px 9px 9px 9px; + fs-close: 0px 9px 9px 9px; +} +@spritesheet fs-resize-sheet { src: "../../../win_resize.tga"; fs-resize-grip: 0px 0px 9px 9px; } +@spritesheet fs-button-sheet { src: "../../../win_button.tga"; fs-button: 0px 0px 49px 16px; } +@spritesheet fs-check-sheet { src: "../../../win_check.tga"; fs-check-mark: 0px 0px 5px 5px; } +@spritesheet fs-mail-sheet { src: "../../../win_mail.tga"; fs-mail-unread: 0px 0px 13px 9px; fs-mail-read: 0px 9px 13px 10px; } +@spritesheet fs-scroll-sheet +{ + src: "../../../win_scrollbar.jpg"; + fs-scroll-thumb: 0px 1px 11px 1px; + fs-scroll-up: 0px 3px 13px 13px; + fs-scroll-down: 0px 16px 13px 13px; +} + +/* The template's body carries base.rcss's .center-both; an id beats the positioned toggle's class + (see legacy's friend_shell.rcss). */ +#panel { transform: none; } +/* CUIFriendWindow::Init(): SetSize(250, 170), SetLimitSize(250, 150), widened to 300 (min 290) so + the tabs and buttons, widened too, hold longer captions than Season 1's Korean and English ones. + font-size 1rem, never dp: the theme sizes text natively (window_shell's body carries native-text). */ +#panel { width: 300dp; height: 170dp; min-width: 290dp; min-height: 150dp; max-width: 100%; max-height: 100%; font-family: "token(font-body)"; font-size: 1rem; color: rgb(230, 220, 200); } + +/* The frame: CUIBaseWindow::DrawOutLine(), in its drawing order. The top and bottom bands (146 / + 37 three units / 106) run the full width; then each side's 146 line and 106 line run the full + height (the 106 one from y 1 to h-1, so the inner lines cross into the corners), the sides' 37 + only between the bands; last, a 173,167,150 dot in the middle of each corner, all but the + bottom-right one, where a resizeable window has its grip. On the template's layers: the back + is the body (black at 179 from y 5 to h-5) with the sides' 37 bands, the top layer the two + horizontal bands, the middle layer the side lines over them, the bottom layer the two top dots + and the footer anchor (unused by this window) the bottom-left one. */ +.window-shell-sprite-back { + left: 0; + right: 0; + top: 5dp; + bottom: 5dp; + background-color: rgba(0, 0, 0, 179); + decorator: linear-gradient(to right, transparent 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, transparent 4dp), + linear-gradient(to left, transparent 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, transparent 4dp); +} +.window-shell-sprite-top { + left: 0; + right: 0; + top: 0; + bottom: 0; + height: auto; + decorator: linear-gradient(to bottom, rgb(146, 134, 121) 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp), + linear-gradient(to top, rgb(146, 134, 121) 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp); +} +/* The inner 106 lines start one unit in (y 1 to h-1): the outer 146 line keeps the corner. */ +.window-shell-sprite-middle { + left: 0; + right: 0; + top: 1dp; + bottom: 1dp; + decorator: linear-gradient(to right, rgb(146, 134, 121) 1dp, transparent 1dp, transparent 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp), + linear-gradient(to left, rgb(146, 134, 121) 1dp, transparent 1dp, transparent 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp); +} +.window-shell-sprite-bottom { + left: 2dp; + right: 2dp; + top: 2dp; + bottom: auto; + height: 1dp; + decorator: linear-gradient(to right, rgb(173, 167, 150) 1dp, transparent 1dp), + linear-gradient(to left, rgb(173, 167, 150) 1dp, transparent 1dp); +} +#window_shell_footer { + left: 2dp; + right: auto; + top: auto; + bottom: 2dp; + width: 1dp; + height: 1dp; + background-color: rgb(173, 167, 150); +} + +/* The title bar: win_titlebar stretched over (6, 5, w-12, 15), a one-unit edge each side, and the + line under it at y 20. It stays the drag handle. */ +.window-shell-header-rail { + left: 5dp; + right: 5dp; + top: 5dp; + height: 16dp; + box-sizing: border-box; + border-left: 1dp rgb(136, 138, 147); + border-right: 1dp rgb(0, 0, 8); + border-bottom: 1dp rgb(106, 97, 88); + decorator: image(fs-titlebar fill); +} +.window-shell-header-title { + left: 9dp; + right: 50dp; + top: 8dp; + text-align: left; + white-space: nowrap; + overflow: hidden; + color: rgb(230, 220, 200); +} + +/* The client area: 5 units in from the sides and the bottom, 21 down. pointer-events none: it + covers the title rail's neighbourhood, and each interactive part opts back in. */ +.window-shell-content, .window-shell-content.has-title +{ + left: 5dp; + right: 5dp; + top: 21dp; + bottom: 5dp; + padding: 0; + display: block; + pointer-events: none; +} + +div { display: block; } +button { font-family: "token(font-body)"; font-size: 1rem; color: rgb(230, 220, 200); cursor: pointer; pointer-events: auto; } + +/* Minimize, maximize and close at w-38, w-27 and w-16 (2 apart), y 8: relative to the client area, + 2 in from its right edge and 13 above it. */ +#window_controls { position: absolute; right: 2dp; top: -13dp; z-index: 10; pointer-events: auto; white-space: nowrap; } +#window_controls button { display: inline-block; width: 9dp; height: 9dp; margin-left: 2dp; padding: 0; box-sizing: border-box; } +#btn_minimize { decorator: image(fs-minimize); } +#btn_maximize { decorator: image(fs-maximize); } +#btn_maximize.restore { decorator: image(fs-restore); } +#btn_close { decorator: image(fs-close); } + +/* The tab strip: black, 20 high, the 106,97,88 line along its foot (y 20), which the selected tab + covers. The tabs 19 high from y 2 (Season 1: 53 wide; 66 here), captions centred, white when + selected or hovered. */ +#tabs { + position: absolute; + left: 0; + right: 0; + top: 0; + height: 21dp; + padding-top: 2dp; + box-sizing: border-box; + white-space: nowrap; + decorator: linear-gradient(to bottom, rgb(0, 0, 0) 20dp, rgb(106, 97, 88) 20dp); +} +#tabs .btn { + width: 66dp; + height: 18dp; + margin: 1dp 0 0 0; + padding: 0; + line-height: 16dp; + box-sizing: border-box; + border-top: 1dp rgb(106, 97, 88); + border-right: 1dp rgb(106, 97, 88); + border-bottom: 1dp rgb(106, 97, 88); + decorator: none; + background-color: rgb(26, 22, 21); +} +#tabs .btn.selected { + height: 19dp; + margin-top: 0; + line-height: 18dp; + border-bottom-width: 0; + border-left: 1dp rgb(106, 97, 88); + background-color: rgb(53, 49, 48); +} +#tabs .btn:hover, #tabs .btn.selected { color: #ffffff; } +#tabs .btn:active { padding-top: 0; } +#reject { position: absolute; right: 2dp; top: 0; height: 20dp; line-height: 20dp; padding: 0; background-color: transparent; z-index: 1; } + +/* win_button stretched whole over the button, pressed one unit in. In-flow inline boxes (base.rcss's + .btn is the absolute 108x30 hero button). */ +.btn { position: relative; display: inline-block; box-sizing: border-box; width: auto; height: 14dp; padding: 0 2dp; line-height: 14dp; vertical-align: top; text-align: center; overflow: hidden; pointer-events: auto; decorator: image(fs-button fill); } +/* base.rcss's .btn:hover / :active swap in legacy's button art; these keep win_button. */ +.btn:hover, .btn:active { decorator: image(fs-button fill); } +.btn:active { padding-top: 1dp; padding-left: 3dp; } +.headers .sorted { color: #ffffff; } + +.check { display: inline-block; width: 7dp; height: 7dp; margin-right: 3dp; margin-top: 6dp; box-sizing: border-box; background-color: rgb(106, 97, 88); border: 1dp rgb(146, 134, 121); } +.checked .check { decorator: image(fs-check-mark); } + +/* A page from y 21: the header band (0-15) and its line (16), the list, the line closing it and the + black foot (22 high) with the buttons 17 above the bottom. */ +.page { position: absolute; left: 0; right: 0; top: 21dp; bottom: 0; } +.headers { position: absolute; left: 0; right: 0; top: 0; height: 17dp; line-height: 16dp; white-space: nowrap; box-sizing: border-box; border-bottom: 1dp rgb(106, 97, 88); background-color: rgb(53, 49, 48); } +.headers button { display: inline-block; box-sizing: border-box; height: 16dp; padding: 0 4dp; line-height: 16dp; text-align: left; overflow: hidden; background-color: transparent; decorator: none; } +.headers button:hover { color: #ffffff; } +.scroll-pane { position: absolute; left: 0; right: 0; top: 17dp; bottom: 22dp; overflow: hidden scroll; background-color: transparent; pointer-events: auto; } + +.row { height: 13dp; line-height: 13dp; padding-left: 4dp; white-space: nowrap; overflow: hidden; cursor: pointer; } +.row:hover { background-color: rgb(106, 97, 88); } +.row.selected { background-color: rgb(146, 134, 121); color: rgb(0, 0, 0); } +.row span { display: inline-block; vertical-align: top; overflow: hidden; } +.row .check { margin-top: 3dp; } +.unread { font-weight: bold; } +.row .read_state { height: 9dp; margin-top: 2dp; decorator: image(fs-mail-unread); } +.row .read_state.read { decorator: image(fs-mail-read); } + +.friend_columns .name { width: 62%; } +.friend_columns .server { width: 38%; } +.mail_columns .check_column { display: inline-block; box-sizing: border-box; width: 7%; height: 13dp; padding: 0; vertical-align: top; background-color: transparent; decorator: none; } +.mail_columns .sender { width: 24%; } +.mail_columns .date { width: 24%; } +.mail_columns .subject { width: 34%; } +.mail_columns .read_state { width: 11%; } + +.actions { position: absolute; left: 0; right: 0; bottom: 0; height: 22dp; padding: 4dp 0 0 2dp; box-sizing: border-box; white-space: nowrap; border-top: 1dp rgb(106, 97, 88); background-color: rgb(0, 0, 0); } +.actions .btn { width: 64dp; margin-right: 1dp; } +.actions .btn.wide { width: 129dp; } + +/* win_scrollbar: the arrows at both ends (clickable, as Season 1's were), the track between two + 106,97,88 lines, the grey thumb sized to the list. */ +.scroll-pane scrollbarvertical { width: 13dp; margin: 0; } +.scroll-pane scrollbarvertical slidertrack { decorator: none; box-sizing: border-box; border-left: 1dp rgb(106, 97, 88); border-right: 1dp rgb(106, 97, 88); } +.scroll-pane scrollbarvertical sliderbar { height: auto; min-height: 6dp; margin: 0 1dp; decorator: image(fs-scroll-thumb fill); } +.scroll-pane scrollbarvertical sliderarrowdec, +.scroll-pane scrollbarvertical sliderarrowinc { width: 100%; height: 13dp; pointer-events: auto; } +.scroll-pane scrollbarvertical sliderarrowdec { decorator: image(fs-scroll-up); } +.scroll-pane scrollbarvertical sliderarrowinc { decorator: image(fs-scroll-down); } +.scroll-pane scrollbarvertical sliderarrowdec:active, +.scroll-pane scrollbarvertical sliderarrowinc:active { filter: brightness(0.7); } + +/* The resize grip at (w-10, h-10): 4 units out of the client area's bottom-right corner. */ +#resize { display: block; position: absolute; right: -4dp; bottom: -4dp; width: 9dp; height: 9dp; z-index: 10; pointer-events: auto; decorator: image(fs-resize-grip); cursor: resize; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/gate_switch.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/gate_switch.rcss new file mode 100644 index 0000000000..cd542bed1e --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/gate_switch.rcss @@ -0,0 +1,101 @@ +/* Classic theme for the castle gate switch (CGateSwitchWindow). 0.97 has no Castle Siege; the + Season 1 client's (0043f990, docked at x 450): the 0.97 frame, the title bold + (220, 220, 220) centred on 95 at y 12, 0.97's divider (Trading_line) at y 110 and 290, the three + lines as legacy's (the warning on a (160, 0, 0) box), DoorOP / DoorCL (155 x 168) at (17, 120) + with no table round it, the action on a 0.97 text plate (Message_box, 150 x 48 at (20, 325)), + its label (220, 220, 220) 10 under its top, the plate lit warm and the label white under the + mouse, and the 0.97 Close at (20, 395). Legacy's rules first, then the classic ones. */ + +/* Legacy theme for CGateSwitchWindow, reproducing its RenderFrame()/Render(): the + docked_panel_frame.rcss frame (linked first; newui_item_back01 top), the title bold + (220, 220, 220) in its 160-unit box at (15, 13), the three lines in the same bold grey centred on + x 95 at y 50 / 67 / 84 (the warning on a (160, 0, 0) text box), the item table round the gate, + doorCL / doorOP (155 x 168) at (17.5, 120), the newui_btn_empty button (108 x 29) at (41, 320), + the exit button at (13, 391). Reference px inside #panel. */ + +@spritesheet gs-gate-closed-sheet { src: "../../../doorCL.jpg"; gs-gate-closed: 0px 0px 155px 168px; } +@spritesheet gs-gate-opened-sheet { src: "../../../doorOP.jpg"; gs-gate-opened: 0px 0px 155px 168px; } +@spritesheet gs-edge-top-sheet { src: "../../../newui_item_table03(Up).tga"; gs-edge-top: 0px 0px 1px 14px; } +@spritesheet gs-edge-bottom-sheet { src: "../../../newui_item_table03(Dw).tga"; gs-edge-bottom: 0px 0px 1px 14px; } +@spritesheet gs-edge-left-sheet { src: "../../../newui_item_table03(L).tga"; gs-edge-left: 0px 0px 14px 1px; } +@spritesheet gs-edge-right-sheet { src: "../../../newui_item_table03(R).tga"; gs-edge-right: 0px 0px 14px 1px; } +@spritesheet gs-btn-sheet +{ + src: "../../../newui_btn_empty.tga"; + gs-btn-up: 0px 0px 108px 29px; + gs-btn-over: 0px 29px 108px 29px; + gs-btn-down: 0px 58px 108px 29px; +} + +.frame-top { decorator: image(docked-bg-top-b); } +#panel { pointer-events: auto; } + +.sharp-text { display: block; position: absolute; white-space: nowrap; text-align: center; pointer-events: none; } +#title { left: 15px; top: 13px; font-weight: bold; color: #dcdcdc; } +.gs-line { left: -55px; font-weight: bold; color: #dcdcdc; } +.gs-warning { background-color: #a00000; } + +.t-edge-top, .t-edge-bottom, .t-edge-left, .t-edge-right, .t-corner { position: absolute; } +.t-edge-top { height: 14px; decorator: image(gs-edge-top); } +.t-edge-bottom { height: 14px; decorator: image(gs-edge-bottom); } +.t-edge-left { width: 14px; decorator: image(gs-edge-left); } +.t-edge-right { width: 14px; decorator: image(gs-edge-right); } +.t-corner { width: 14px; height: 14px; } +.t-tl { decorator: image(docked-corner-tl); } +.t-tr { decorator: image(docked-corner-tr); } +.t-bl { decorator: image(docked-corner-bl); } +.t-br { decorator: image(docked-corner-br); } +#gate { position: absolute; left: 17.5px; top: 120px; width: 155px; height: 168px; decorator: image(gs-gate-closed); } +#gate.opened { decorator: image(gs-gate-opened); } + +#btn_toggle { + display: block; + position: absolute; + left: 41px; + top: 320px; + width: 108px; + height: 29px; + decorator: image(gs-btn-up); + pointer-events: auto; +} +#btn_toggle:hover { decorator: image(gs-btn-over); } +#btn_toggle:active { decorator: image(gs-btn-down); } +.gs-label { left: 0; color: #ffffff; } +#btn_exit { top: 391px; } + +/* The question's three lines and the table's frame, in the places the original drew them. */ +#gs_line_1 { top: 50px; } +#gs_line_2 { top: 67px; } +#gs_line_3 { top: 84px; } +.t-tl { left: 12px; top: 116px; } +.t-tr { left: 166px; top: 116px; } +.t-edge-top { left: 25px; top: 116px; width: 141px; } +.t-edge-left { left: 12px; top: 129px; height: 159px; } +.t-edge-right { left: 166px; top: 129px; height: 159px; } +.t-bl { left: 12px; top: 282px; } +.t-br { left: 166px; top: 282px; } +.t-edge-bottom { left: 25px; top: 282px; width: 141px; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#title { width: calc(160px * var(--root-scale)); } +#gs_line_1 { width: calc(300px * var(--root-scale)); } +#gs_line_2 { width: calc(300px * var(--root-scale)); } +#gs_line_3 { width: calc(300px * var(--root-scale)); } +.gs-label { width: calc(108px * var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet gs-classic-line-sheet { src: ../../../Classic/Trading_line.jpg; gs-classic-line: 0px 0px 190px 10px; } +@spritesheet gs-classic-plate-sheet { src: ../../../Classic/Message_box.jpg; gs-classic-plate: 0px 0px 213px 64px; } +#title { top: 12px; } +.t-edge-top, .t-edge-bottom, .t-edge-left, .t-edge-right, .t-corner { display: none; } +#gate { left: 17px; top: 120px; } +/* The two dividers: the frame's otherwise unused side pieces carry them. */ +.frame-right, .frame-bottom { display: block; left: 0; width: 190px; height: 10px; decorator: image(gs-classic-line); } +.frame-right { top: 110px; } +.frame-bottom { top: 290px; } +#btn_toggle { left: 20px; top: 325px; width: 150px; height: 48px; decorator: image(gs-classic-plate fill); } +#btn_toggle:hover, #btn_toggle:active { decorator: image(gs-classic-plate fill); image-color: #ffe3c6; filter: brightness(1.7); } +.gs-label { top: 10px; transform-origin: left top; transform: scale(calc(1 / var(--root-scale, 1))); color: #dcdcdc; font-weight: bold; } +#btn_toggle:hover .gs-label { color: #ffffff; } +.gs-label { width: calc(150px * var(--root-scale)); } +#btn_exit { left: 20px; top: 395px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/gateman.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/gateman.rcss new file mode 100644 index 0000000000..0e8e4cffdc --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/gateman.rcss @@ -0,0 +1,174 @@ +/* Classic theme for the gateman (CGatemanWindow, the Castle Hunting Area entry). 0.97 has no Castle + Siege; the Season 1 client's (00611d80, docked at x 450): the 0.97 frame, the title + bold white centred at y 15; the lord's page: the restriction bold at y 55, the members' lines at + 75 / 85 / 95, the check box (9 x 9 outline (146, 134, 121), win_check's mark) at (35, 115) with its + label at 55, the entry fee at (35, 133), the fee title bold at 163, the fee on a black 30% box + (90 x 30 at (20, 185)) ending at x 90, the fee buttons Season 1 text buttons 16 x 16 at (120, 183) + and (120, 203) with the CursorSitDown arrow over them (flipped for up), Apply at (70, 228), the + rules white at 253 / 266 / 279 and Enter at (70, 329); the member's and the guest's lines from + y 55, 10 apart, Enter under them. Buttons: Season 1's win_button 50 x 18, grey 0.8 at rest, white + under the mouse, 0.6 pressed, red (1, 0.4, 0.4) locked, labelled (230, 220, 200). The 0.97 Close + at (25, 395). Legacy's rules first, then the classic ones. */ + +/* Legacy theme for CGatemanWindow, reproducing its RenderFrame() and pages: the + docked_panel_frame.rcss frame (linked first; newui_item_back01 top), the texts in their bound + fonts and colours, the master's RenderCheckBox() (a 9 x 9 (146, 134, 121) outline at (35, 110), + win_check's 5 x 5 mark when public), the fee backdrop (black at alpha 77, 90 x 30 at (20, 180)), + the fee arrows (newui_Bt_scroll_up / dn, 15 x 13: up / over / down) at (118, 180) / (118, 196), + the 53 x 23 newui_btn_empty_very_small buttons (a locked Enter tinted (100, 100, 100) with a + grey label, never hovered), the exit button at (13, 391). Reference px inside #panel. */ + +@spritesheet gk-btn-sheet +{ + src: "../../../newui_btn_empty_very_small.tga"; + gk-btn-up: 0px 0px 53px 23px; + gk-btn-over: 0px 23px 53px 23px; + gk-btn-down: 0px 46px 53px 23px; +} +@spritesheet gk-up-sheet +{ + src: "../../../newui_Bt_scroll_up.jpg"; + gk-up-up: 0px 0px 15px 13px; + gk-up-over: 0px 13px 15px 13px; + gk-up-down: 0px 26px 15px 13px; +} +@spritesheet gk-dn-sheet +{ + src: "../../../newui_Bt_scroll_dn.jpg"; + gk-dn-up: 0px 0px 15px 13px; + gk-dn-over: 0px 13px 15px 13px; + gk-dn-down: 0px 26px 15px 13px; +} +@spritesheet gk-check-sheet { src: "../../../win_check.tga"; gk-check: 0px 0px 5px 5px; } + +.frame-top { decorator: image(docked-bg-top-b); } +#panel { pointer-events: none; } + +.sharp-text { display: block; position: absolute; white-space: nowrap; text-align: left; pointer-events: none; } + +#public_toggle { position: absolute; left: 35px; top: 110px; width: 100px; height: 16px; pointer-events: auto; } +#checkbox { position: absolute; left: 0; top: 0; width: 9px; height: 9px; pointer-events: none; border: 1px #928679; box-sizing: border-box; } +#check_mark { position: absolute; left: 1px; top: 1px; width: 5px; height: 5px; pointer-events: none; decorator: image(gk-check); } +#fee_back { position: absolute; left: 20px; top: 180px; width: 90px; height: 30px; background-color: rgba(0, 0, 0, 77); } + +.fee-btn { position: absolute; left: 118px; width: 15px; height: 13px; pointer-events: auto; } +.fee-up { top: 180px; decorator: image(gk-up-up); } +.fee-up:hover { decorator: image(gk-up-over); } +.fee-up:active { decorator: image(gk-up-down); } +.fee-down { top: 196px; decorator: image(gk-dn-up); } +.fee-down:hover { decorator: image(gk-dn-over); } +.fee-down:active { decorator: image(gk-dn-down); } + +.gk-btn { display: block; position: absolute; width: 53px; height: 23px; decorator: image(gk-btn-up); pointer-events: auto; } +.gk-btn:hover { decorator: image(gk-btn-over); } +.gk-btn:active { decorator: image(gk-btn-down); } +.gk-btn.locked, .gk-btn.locked:hover, .gk-btn.locked:active { decorator: image(gk-btn-up); image-color: #646464; } +.gk-label { left: 0; text-align: center; color: #ffffff; } +.gk-btn.locked .gk-label { color: #646464; } + +#btn_exit { top: 391px; pointer-events: auto; } + +/* The window's own text. Each line is named, so the theme decides where it sits, what colour it + is and how it is aligned; only its font size stays bound. Its width is reference px times --root-scale. */ +.gk-page { position: static; } +.gk-heading, .gk-line { text-align: center; } +.gk-heading { left: 15px; top: 13px; font-weight: bold; } +.gk-line { left: 0; } + +#restriction { top: 50px; font-weight: bold; } +#members_1 { top: 70px; } +#members_2 { top: 80px; } +#members_3 { top: 90px; } +#open_to_non_members { left: 55px; top: 110px; } +#entrance_fee { left: 35px; top: 128px; } +#fee_setting_label { top: 158px; font-weight: bold; } +/* RT3_WRITE_RIGHT_TO_LEFT: the text ends at x 80. */ +#view_fee { right: 110px; top: 190px; text-align: right; } +#fee_range { top: 248px; } +#fee_range_for { top: 261px; } +#fee_increment { top: 274px; } + +#member_question { top: 50px; font-weight: bold; } + +#guest_fee { top: 50px; font-weight: bold; } +#guest_pay_prompt { top: 60px; font-weight: bold; } +#guest_question { top: 70px; font-weight: bold; } +#denied_1 { top: 50px; font-weight: bold; } +#denied_2 { top: 60px; font-weight: bold; } +#denied_3 { top: 70px; font-weight: bold; } +#denied_4 { top: 80px; font-weight: bold; } + +/* The master's page pushes Enter below the fee controls. */ +#btn_confirm { left: 68px; top: 220px; } +#btn_enter { left: 68px; top: 100px; } +#panel.master #btn_enter { top: 320px; } + +.gk-heading, .gk-line, .gk-note { color: #dcdcdc; } +#fee_range, #fee_range_for, #fee_increment, #guest_pay_prompt, #guest_question { color: #ffffff; } +/* RenderGuestMode() reddened the fee the hero cannot pay. */ +#guest_fee { color: rgb(255, 255, 100); } +#guest_fee.unaffordable { color: rgb(255, 100, 50); } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#heading { width: calc(160px * var(--root-scale)); } +#restriction { width: calc(190px * var(--root-scale)); } +#members_1 { width: calc(190px * var(--root-scale)); } +#members_2 { width: calc(190px * var(--root-scale)); } +#members_3 { width: calc(190px * var(--root-scale)); } +#fee_setting_label { width: calc(190px * var(--root-scale)); } +#fee_range { width: calc(190px * var(--root-scale)); } +#fee_range_for { width: calc(190px * var(--root-scale)); } +#fee_increment { width: calc(190px * var(--root-scale)); } +#member_question { width: calc(190px * var(--root-scale)); } +#guest_fee { width: calc(190px * var(--root-scale)); } +#guest_pay_prompt { width: calc(190px * var(--root-scale)); } +#guest_question { width: calc(190px * var(--root-scale)); } +#denied_1 { width: calc(190px * var(--root-scale)); } +#denied_2 { width: calc(190px * var(--root-scale)); } +#denied_3 { width: calc(190px * var(--root-scale)); } +#denied_4 { width: calc(190px * var(--root-scale)); } +.gk-label { width: calc(53px * var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet gk-classic-btn-sheet { src: "../../../win_button.tga"; gk-classic-btn: 0px 0px 49px 16px; } +@spritesheet gk-classic-arrow-sheet { src: "../../../CursorSitDown.tga"; gk-classic-arrow: 0px 0px 32px 32px; } +.gk-heading { top: 15px; color: #ffffff; } +#restriction { top: 55px; } +#members_1 { top: 75px; } +#members_2 { top: 85px; } +#members_3 { top: 95px; } +#public_toggle { left: 35px; top: 115px; width: 150px; } +#checkbox { border-color: rgb(146, 134, 121); } +#open_to_non_members { left: 55px; top: 115px; } +#entrance_fee { left: 35px; top: 133px; } +#fee_setting_label { top: 163px; } +#fee_back { left: 20px; top: 185px; width: 90px; height: 30px; background-color: rgba(0, 0, 0, 77); } +#view_fee { right: 100px; top: 195px; } +.fee-btn, .fee-btn:hover, .fee-btn:active { left: 120px; width: 16px; height: 16px; image-color: #cccccc; } +.fee-up, .fee-up:hover, .fee-up:active { top: 183px; decorator: image(gk-classic-arrow flip-vertical fill), image(gk-classic-btn fill); } +.fee-down, .fee-down:hover, .fee-down:active { top: 203px; decorator: image(gk-classic-arrow fill), image(gk-classic-btn fill); } +.fee-btn:hover { image-color: #ffffff; } +.fee-btn:active { image-color: #999999; } +#fee_range { top: 253px; } +#fee_range_for { top: 266px; } +#fee_increment { top: 279px; } +#member_question { top: 55px; } +#guest_fee { top: 55px; } +#guest_pay_prompt { top: 65px; } +#guest_question { top: 75px; } +#denied_1 { top: 55px; } +#denied_2 { top: 65px; } +#denied_3 { top: 75px; } +#denied_4 { top: 85px; } + +.gk-btn, .gk-btn:hover, .gk-btn:active { width: 50px; height: 18px; decorator: image(gk-classic-btn fill); image-color: #cccccc; } +.gk-btn:hover { image-color: #ffffff; } +.gk-btn:active { image-color: #999999; } +.gk-btn.locked, .gk-btn.locked:hover, .gk-btn.locked:active { decorator: image(gk-classic-btn fill); image-color: #ff6666; } +.gk-label, .gk-btn.locked .gk-label { color: #e6dcc8; } +.gk-btn:active .gk-label { margin-left: calc(1px * var(--root-scale)); margin-top: calc(1px * var(--root-scale)); } +.gk-label { width: calc(50px * var(--root-scale)); } +#btn_confirm { left: 70px; top: 228px; } +#btn_enter { left: 70px; top: 100px; } +#panel.master #btn_enter { top: 329px; } +#btn_exit { top: 395px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/generic_confirm_dialog.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/generic_confirm_dialog.rcss new file mode 100644 index 0000000000..a37d561c46 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/generic_confirm_dialog.rcss @@ -0,0 +1,415 @@ +/* Classic (0.97) look for the generic confirm dialog (CGenericConfirmDialog): the stone box of the + in-game confirmations (RenderMessageBox 0051af50, codes 0x97 / 0x99: selling a dear item, + combining, a changed trade, a split server, using a fruit) and of the personal-code keypad + (FUN_004eb070). The box is Message_box2 (213x5) as the top edge, N strips of Message_box1 + (213x40, the stone with its golden sides) and Message_box2 again as the bottom edge, 213 wide + at x 213 with its top at y 100 of the 640x480 frame: 213x130 (three strips) for a + confirmation, 213x170 (four) for the keypad. OK is Ok / Ok2 and Cancel is Cancel / Cancel2 + (70x21, the second image under the mouse) at (234, 190) and (333, 190): 21 and 120 from the + box's left, 90 from its top. The lines are bold, 18 apart from y 130, golden (1.0, 0.7, 0) + with a warning line red. The keypad: eleven Item_box cells (32x32, tinted (0.85, 0.85, 0.65), + (1, 1, 0.8) under the mouse, Inventorybox2 while pressed) at (223 + 40 * (i % 5), + 154 + 38 * (i / 5)), the eleventh the delete key on Back1 / Back2 / Back3; the digits + (128, 128, 196) and the one under the mouse yellow (196, 196, 0); the digit field a Bar plate + (40x18) tinted 0.3 at y 134, 16 tall and 52 wide; OK and Cancel at (265, 239) and (343, 239), + beside the delete key. + + Copied from legacy's generic_confirm_dialog.rcss (a theme sheet replaces the whole file). + #panel is placed like the 0.97 box (overriding the markup's .center-both); every dimension is + dp -- the panel carries no transform:scale(root_scale) -- and text is rem (native text size, + RmlNativeText.h), as legacy does. What legacy has and 0.97 does not (the duel portrait, the + text field, the progress bar, the live 3D item, a labelled or third button) keeps legacy's + rule, over the 0.97 box. + + The lines' default colour stays white: generic_confirm_dialog.rml binds every line's colour + inline ('#ffffff' when the caller gives none) and an inline value outranks this sheet, so the + 0.97 gold needs the markup; a caller's own colour (the red warning line) shows as given. */ +#panel { + /* 0.97: centred horizontally, top edge at y 100, three strips tall (5 + 3 * 40 + 5 = 130; + legacy's 117 is the S6 cap and foot) for up to three lines and growing with each further + line -- so no centering transform and no fixed height: the flowing .gcd-body below sizes + it. y 100 counts from the 640x480 canvas top: the markup adds that canvas's offset + (canvas_top, RmlDialogCanvas.h) as margin-top. 213 wide, not legacy's 230: the 0.97 box + and its button places are 213 wide, so the edges are Message_box2 itself. */ + top: 100dp; + left: 50%; + margin-left: -106.5dp; + transform: none; + width: 213dp; + min-height: 130dp; + font-family: "token(font-body)"; + font-size: 1rem; + color: token(text-primary); +} +/* Optional taller variant (GenericDialogConfig::tallPanel): the keypad's four-strip box (5 + 4 * + 40 + 5 = 170; legacy's 240) -- the duel portrait sets it too and takes its own size below. The + bottom-anchored buttons and the edges follow the panel on their own. */ +#panel.tall { + min-height: 170dp; +} +/* The keypad's box: its lines start where 0.97 wrote the title (10 under the top edge, the + subtitle at 22), and OK and Cancel sit at (265, 239) and (343, 239) -- 52 and 130 from the + box's left, 10 above its bottom edge -- beside the delete key, whose row ends 8 above that + edge: the body keeps 2 under the grid (its cells leave 6 more) instead of the button blank. + The sides keep 6, so the five 40-wide columns fit (200) and the first cell starts 10 from the + box's left (x 223). 0.97's box is 170 tall with its field at 34 and its cells from 54; here + the two lines take their own rows, so the box grows past 170 by the same flow as any other. + The duel portrait, tall as well, takes its own placement back below. */ +#panel.tall .gcd-body { margin: 10dp 6dp 2dp 6dp; } +#panel.tall .gcd-btn-primary { left: 52dp; bottom: 10dp; } +#panel.tall .gcd-btn-primary.solo { left: 71dp; } +#panel.tall .gcd-btn-secondary, #panel.tall .gcd-btn-cancel { left: 130dp; bottom: 10dp; } + +/* The four sprite layers carry the 0.97 composite: the edges are Message_box2 at its own 213, the + middle the Message_box1 strips. */ +@spritesheet classic-gcd-edge-sheet { src: ../../../Classic/Message_box2.jpg; classic-gcd-edge: 0px 0px 213px 5px; } +@spritesheet classic-gcd-stone-sheet { src: ../../../Classic/Message_box1.jpg; classic-gcd-stone: 0px 0px 213px 40px; } +.gcd-sprite-back, .gcd-sprite-top, .gcd-sprite-middle, .gcd-sprite-bottom { + position: absolute; + left: 0; + right: 0; + pointer-events: none; +} +/* 0.97 has no backing behind its strips (legacy's newui_msgbox_back): the stone is opaque, so the + layer stays and draws nothing. */ +.gcd-sprite-back { left: 4dp; right: 4dp; top: 5dp; bottom: 5dp; decorator: none; } +.gcd-sprite-top { top: 0; height: 5dp; decorator: image(classic-gcd-edge); } +/* The strips, stacked from the top edge and cut at the bottom one (0.97 drew whole strips; a box + grown by lines shows part of the last). An atlas sprite repeats as clipped quads inside its + own rectangle (engine-findings.md, image repeat modes). */ +.gcd-sprite-middle { top: 5dp; bottom: 5dp; decorator: image(classic-gcd-stone repeat-y left top); } +.gcd-sprite-bottom { bottom: 0; height: 5dp; decorator: image(classic-gcd-edge); } +/* The overlay-portrait box is the duel request (CDuelMsgBox) and result. 0.97 has no duel; the + Season 1 client's request (005c8af0) is a 0.97 box at (213, 110), four stones tall + (5 + 4 * 40 + 5 = 170), its DuelWindow crest (128 x 128) at (256, 120) behind the text, the + caption bold (255, 207, 24) centred at y 141, the two lines at 180 and 200, each text over a + black copy one unit down and right, and OK / Cancel (70 x 21) at (237, 250) and (332, 250). + In the box: the caption at 31, the lines 20 apart ending at 106 (more lines grow upwards), the + buttons 24 and 119 from its left, 9 above its bottom. */ +#panel.portrait { + top: 110dp; + min-height: 170dp; +} +#panel.portrait .gcd-body { + margin: 27dp 6dp 64dp 6dp; + height: 79dp; /* 170 - 27 top - 64 under the last line */ + align-items: stretch; +} +#panel.portrait .gcd-text-col { + justify-content: flex-end; + overflow: visible; /* a fixed native box never scrolls */ +} +#panel.portrait .gcd-portrait2d-text { margin-bottom: auto; color: rgb(255, 207, 24); font-effect: shadow(1dp 1dp black); } +/* Positioned so they paint above the (positioned) crest, which comes first in the markup. Regular + weight unless the caller asks for bold, as Season 1 draws them. */ +#panel.portrait .gcd-line { + position: relative; + line-height: 20dp; + min-height: 20dp; /* an empty line keeps its row, as native draws every row at its own y */ + font-weight: normal; + font-effect: shadow(1dp 1dp black); +} +#panel.portrait .gcd-line.bold { font-weight: bold; } +#panel.portrait .gcd-btn-primary { left: 24dp; bottom: 9dp; } +#panel.portrait .gcd-btn-secondary, #panel.portrait .gcd-btn-cancel { left: 119dp; bottom: 9dp; } + +/* GenericDialogConfig::Portrait2D's own art -- the duel crest: Season 1's DuelWindow (128 x 128), + which Season 1 drew additively (its black square vanishes over the stone): the derived + DuelWindow_add (tools/classic_theme/make_classic_derived_textures.py) carries that as alpha. */ +@spritesheet portrait2d-sheet +{ + src: ../../../Classic/s1/DuelWindow_add.tga; + portrait2d-image: 0px 0px 128px 128px; +} + +/* 0.97 has no title banner (legacy's IMAGE_MSGBOX_TOP_TITLEBAR, newui_Message_03.tga, dropped + with its @spritesheet): a title is a bold line over the stone, so the rail stays and draws + nothing, and the title text below stays. */ +.gcd-header-rail { + position: absolute; + left: 0; + right: 0; + top: 0; + height: 67dp; + pointer-events: none; + decorator: none; +} +/* Title text over the box -- one centered line rather than native's exact pixel-wrap math -- 10 + under the top edge, where 0.97 centres the keypad's title (y 110). No conflict with + .gcd-body's own top blank below -- the title sits above that. */ +.gcd-header-title { + position: absolute; + left: 0; + right: 0; + top: 10dp; + text-align: center; + font-family: "token(font-body)"; + font-weight: bold; + color: token(accent-gold); + pointer-events: none; +} +.gcd-header-title.warning { color: token(semantic-warning); } +.gcd-header-title.error { color: token(semantic-danger); } + +/* Text floats transparently over the stone (painted by the sprite layers above it). 0.97's lines + start 30 under the top edge (y 130) and its buttons take the bottom 40 (90 from the top, 21 + tall, 19 above the bottom edge): a 30 top blank and a 46 bottom one (the buttons and a 6 gap). + The sides keep legacy's 184 text column ((213 - 184) / 2 = 14.5), native's wrap width + (MSGBOX_TEXT_MAXWIDTH 180 plus the renderer's ~2%); the bold 0.97 lines run a little wider, so + a long line may break one word earlier than in legacy. + + top+bottom (not top+height) deliberately -- this engine's box model is content-box only (no + box-sizing support anywhere in this codebase), so an explicit height combined with a bordered/ + padded box can push past the intended bottom edge. Anchoring both edges keeps the box's outer + size exact regardless of its own content. + + display:flex row: #gcd_item3d_anchor (item icon, left) + .gcd-text-col (fills the rest, right). + The title is NOT a child of this box -- it overlays #panel's own top edge instead. */ +.gcd-body { + /* In flow (not absolute) so the panel grows with it. */ + margin: 30dp 14.5dp 46dp 14.5dp; + /* Positioned so it paints above the sprite composite, which comes first in the markup. */ + position: relative; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; +} +/* Holds lines/input-row/progress-track. Fills .gcd-body's full height explicitly (rather than + relying on align-items, which wouldn't stretch under align-items:center) so the .scroll-pane + class it also carries has a real bound to scroll within once content grows taller than the + panel. The overflow/pointer-events rules and the whole scrollbar chrome now come from + base.rcss's .scroll-pane -- this element was the case they were generalized from, so only its + own layout stays here. */ +.gcd-text-col { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; + max-height: 320dp; + flex: 1 1 auto; +} +/* 0.97 draws the lines bold, 18 apart in the 640x480 frame (y 130, 148, 166: three lines fill the + 130 box, 30 + 3 * 18 + 46). Colour: see the header. */ +.gcd-line { + display: block; + width: 100%; + text-align: center; + white-space: normal; + line-height: 18dp; + min-height: 18dp; /* a blank line (" ") keeps its row, as native's AddMsg(L" ") does */ + font-weight: bold; + color: token(text-primary); +} +.gcd-line.bold { font-weight: bold; } + +/* The live 3D item: native C3DItemCommonMsgBox's 40x40 slot (C++ frames the item by this + element's drawn box: legacy's rule, untouched). */ +.gcd-item3d { + position: relative; + width: 40dp; + height: 40dp; + flex-shrink: 0; + margin-right: 8dp; +} +/* Collapses when there's no item, so .gcd-text-col alone fills the row. */ +.gcd-item3d.hidden { display: none; } +/* The model reaches past its slot, and past the panel, as natively: the image around it is far larger. */ +#gcd_item3d { position: absolute; left: -80dp; top: -80dp; width: 200dp; height: 200dp; pointer-events: none; } + +/* Optional 2D portrait (GenericDialogConfig::Portrait2D), Overlay layout (the default) -- a direct + #panel child at Season 1's crest position (y+10, 128x128), behind the text, unlike .gcd-item3d + (icon-left/text-right, that's the Beside layout below). */ +.gcd-portrait2d { + position: absolute; + left: 43dp; /* Season 1: 256 - 213 */ + top: 10dp; + width: 128dp; + height: 128dp; + decorator: image(portrait2d-image); +} +/* Same cascade-tie fix as .gcd-item3d above. */ +.gcd-portrait2d.hidden { display: none; } +/* Beside layout -- same row-sibling slot/sizing convention as .gcd-item3d, sized a little + larger since this reads as hero art rather than a small icon. No text overlay in this layout -- + .gcd-portrait2d-text is never a child of this element in the .rml. */ +.gcd-portrait2d-beside { + position: static; + width: 60dp; + height: 56dp; + flex-shrink: 0; + margin-right: 8dp; + margin-bottom: 0; + decorator: image(portrait2d-image); +} +/* The caption row over the crest (native draws it ON TOP of the art): native's bold yellow, first + row of .gcd-text-col, positioned so it paints above the (positioned) crest. */ +.gcd-portrait2d-text { + position: relative; + display: block; + width: 100%; + line-height: 20dp; + text-align: center; + font-weight: bold; + font-size: 1rem; + color: token(text-heading); +} +.gcd-portrait2d-text.hidden { display: none; } /* display: block above outranks .hidden */ + +/* Optional text-entry field -- see the .rml's own comment for the NumericKeypad-vs-Text split. + `.btn.gcd-keypad-btn`/`.gcd-keypad-delete` override `.btn`'s own `position: absolute` back to + static so they can flex-wrap into a grid instead of stacking on top of each other. */ +@spritesheet classic-gcd-plate-sheet { src: ../../../Classic/Bar.jpg; classic-gcd-plate: 0px 0px 40px 18px; } +@spritesheet classic-gcd-cell-sheet { src: ../../../Classic/Item_box.jpg; classic-gcd-cell: 0px 0px 32px 32px; } +@spritesheet classic-gcd-cell-pressed-sheet { src: ../../../Classic/Inventorybox2.jpg; classic-gcd-cell-pressed: 0px 0px 32px 32px; } +@spritesheet classic-gcd-delete-sheet { src: ../../../Classic/Back1.jpg; classic-gcd-delete: 0px 0px 32px 32px; } +@spritesheet classic-gcd-delete-hover-sheet { src: ../../../Classic/Back2.jpg; classic-gcd-delete-hover: 0px 0px 32px 32px; } +@spritesheet classic-gcd-delete-pressed-sheet { src: ../../../Classic/Back3.jpg; classic-gcd-delete-pressed: 0px 0px 32px 32px; } +.gcd-input-row { + display: flex; + flex-direction: column; + align-items: center; + margin-top: 4dp; +} +/* .gcd-input-row sets its own `display`, so an earlier same-specificity `.hidden { display: none; + }` (base.rcss) loses the cascade tie without this later, more specific override. */ +.gcd-input-row.hidden { display: none; } +/* The digit field: 0.97's Bar plate stretched to 52x16 and tinted 0.3, the digits C++ masks + centred on it in legacy's prompt colour (0.97's own is not known). */ +.gcd-keypad-display { + width: 52dp; + height: 16dp; + line-height: 16dp; + text-align: center; + color: token(text-prompt); + font-weight: bold; + letter-spacing: 4dp; + margin-bottom: 4dp; + decorator: image(classic-gcd-plate fill); + image-color: #4d4d4d; +} +/* Five 32x32 cells per row, 40 apart, the rows 38 apart (4 at each side of a cell, 6 under it); + the eleventh, the delete key, starts the third row at the left, where 0.97 draws it beside OK + and Cancel (#panel.tall above). */ +.gcd-keypad-grid { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + width: 200dp; +} +.gcd-keypad-grid.hidden { display: none; } /* same cascade-tie fix as .gcd-input-row above */ +.btn.gcd-keypad-btn, .btn.gcd-keypad-delete { + position: static; + width: 32dp; + height: 32dp; + margin: 0 4dp 6dp 4dp; + line-height: 26dp; /* the digit high in the cell, as 0.97 wrote it at (x + 12, y + 6) */ + font-size: 1rem; + font-weight: bold; +} +/* The digit cells: Item_box tinted (0.85, 0.85, 0.65), lit (1, 1, 0.8) under the mouse with its + digit yellow; a pressed one shows the sunk Inventorybox2. */ +.btn.gcd-keypad-btn { color: #8080c4; decorator: image(classic-gcd-cell); image-color: #d9d9a6; } +.btn.gcd-keypad-btn:hover { decorator: image(classic-gcd-cell); image-color: #ffffcc; color: #c4c400; } +.btn.gcd-keypad-btn:active { decorator: image(classic-gcd-cell-pressed); image-color: #ffffcc; } +/* The delete key's own art carries its arrow (Back1, Back2 under the mouse, Back3 while pressed), + so its "Del" label is hidden. */ +.btn.gcd-keypad-delete { decorator: image(classic-gcd-delete); color: rgba(0, 0, 0, 0); } +.btn.gcd-keypad-delete:hover { decorator: image(classic-gcd-delete-hover); } +.btn.gcd-keypad-delete:active { decorator: image(classic-gcd-delete-pressed); } +/* Text-mode field (no 0.97 counterpart in this box: legacy's rule): takes the same flow slot the + old native-widget position reference occupied, so the column layout is unchanged. Sizing only + -- fill/border/focus/selection come from base.rcss's shared .text-field. */ +.gcd-input-field { + position: static; + width: 150dp; + height: 18dp; + padding: 0 3dp; + font-size: 0.85rem; +} + +/* Optional progress bar (no 0.97 counterpart in this box: legacy's rule) -- same `x_fraction * + 100 + '%'` fill technique main_frame.rml's own HP/MP/AG/SD/EXP gauges use. */ +.gcd-progress-track { + width: 150dp; + height: 10dp; + margin-top: 4dp; + background-color: token(surface-recessed); + border: 1dp token(border-inner); +} +.gcd-progress-fill { + height: 100%; + background-color: token(accent-gold); +} + +/* 0.97's OK / Cancel plates (70x21, the second image under the mouse): paired at 21 and 120 from + the box's left (x 234 and 333), 90 from its top -- 19 above the bottom edge of the 130 box, so + they follow the growing panel from the bottom. A lone OK is centred (71, as 0.97's single OK + at x 284). A button with another label (Decrease / Gift / Discard...; 0.97 has none) gets the + plain 0.97 plate (Bar, 40x18) stretched to the same size, with its text, as + message_box_view.rcss does. + + Three fixed, named-role slots (primary/secondary/cancel -- see GenericDialogConfig's own + comment). `.gcd-btn-secondary` is a real second action (Decrease/Gift/Discard...), never + Cancel; `.gcd-btn-cancel` is the always-Cancel/Close slot. Every existing Ok/OkCancel consumer + always renders solo or paired (primary+cancel), never triple. Legacy's newui_button_ok / + newui_button_cancel sheets are dropped with the S6 art. */ +@spritesheet classic-gcd-ok-sheet { src: ../../../Classic/Ok.jpg; classic-gcd-ok: 0px 0px 70px 21px; } +@spritesheet classic-gcd-ok2-sheet { src: ../../../Classic/Ok2.jpg; classic-gcd-ok-hover: 0px 0px 70px 21px; } +@spritesheet classic-gcd-cancel-sheet { src: ../../../Classic/Cancel.jpg; classic-gcd-cancel: 0px 0px 70px 21px; } +@spritesheet classic-gcd-cancel2-sheet { src: ../../../Classic/Cancel2.jpg; classic-gcd-cancel-hover: 0px 0px 70px 21px; } +.btn.gcd-btn-primary, .btn.gcd-btn-secondary, .btn.gcd-btn-cancel { + bottom: 19dp; + width: 70dp; + height: 21dp; + line-height: 21dp; + font-size: 1rem; + color: #ffffff; + decorator: image(classic-gcd-plate fill); +} +.btn.gcd-btn-primary:hover, .btn.gcd-btn-secondary:hover, .btn.gcd-btn-cancel:hover { + decorator: image(classic-gcd-plate fill); + image-color: #ffe6b4; +} +.btn.gcd-btn-primary:active, .btn.gcd-btn-secondary:active, .btn.gcd-btn-cancel:active { + decorator: image(classic-gcd-plate fill); + image-color: #b4b4b4; +} +/* The stock OK / Cancel: 0.97's lettered plates, with the label text hidden. */ +.btn.gcd-btn-primary.stock-ok { decorator: image(classic-gcd-ok); image-color: #ffffff; color: rgba(0, 0, 0, 0); } +.btn.gcd-btn-primary.stock-ok:hover, .btn.gcd-btn-primary.stock-ok:active { decorator: image(classic-gcd-ok-hover); image-color: #ffffff; } +.btn.gcd-btn-cancel.stock-cancel { decorator: image(classic-gcd-cancel); image-color: #ffffff; color: rgba(0, 0, 0, 0); } +.btn.gcd-btn-cancel.stock-cancel:hover, .btn.gcd-btn-cancel.stock-cancel:active { decorator: image(classic-gcd-cancel-hover); image-color: #ffffff; } +.gcd-btn-primary { left: 21dp; } +.gcd-btn-primary.solo { left: 71dp; } +/* Paired: whichever of secondary/cancel is the sole second button sits in this one slot -- both + selectors share the position since only one is ever visible outside of `.triple`. */ +.gcd-btn-secondary, .gcd-btn-cancel { left: 120dp; } +/* Triple (all three shown, e.g. Create/Decrease/Cancel; 0.97 has none) -- native's own `triwidth = + panelWidth/3` centering (CUseFruitCheckMsgBox::SetButtonInfo(), CustomMessageBox.cpp), each + plate narrowed to 64 and centred within its own 213dp/3 = 71dp third. #panel-qualified so a + tall or portrait box's paired places above do not override it. */ +#panel .gcd-btn-primary.triple { left: 4dp; width: 64dp; } +#panel .gcd-btn-secondary.triple { left: 75dp; width: 64dp; } +#panel .gcd-btn-cancel.triple { left: 146dp; width: 64dp; } + +/* Scrolling lists: the Season 1 client's win_scrollbar (as the classic social windows'), in place of + base.rcss's S6 track and knob: 13x13 arrows at both ends, the track between two 106,97,88 lines, + a grey thumb sized to the list. */ +@spritesheet gcd-scroll-sheet +{ + src: "../../../win_scrollbar.jpg"; + gcd-scroll-thumb: 0px 1px 11px 1px; + gcd-scroll-up: 0px 3px 13px 13px; + gcd-scroll-down: 0px 16px 13px 13px; +} +.scroll-pane scrollbarvertical { width: 13dp; margin: 0; } +.scroll-pane scrollbarvertical slidertrack { decorator: none; box-sizing: border-box; border-left: 1dp rgb(106, 97, 88); border-right: 1dp rgb(106, 97, 88); } +.scroll-pane scrollbarvertical sliderbar { height: auto; min-height: 6dp; margin: 0 1dp; decorator: image(gcd-scroll-thumb fill); } +.scroll-pane scrollbarvertical sliderbar:active { filter: none; } +.scroll-pane scrollbarvertical sliderarrowdec, +.scroll-pane scrollbarvertical sliderarrowinc { width: 100%; height: 13dp; pointer-events: auto; } +.scroll-pane scrollbarvertical sliderarrowdec { decorator: image(gcd-scroll-up); } +.scroll-pane scrollbarvertical sliderarrowinc { decorator: image(gcd-scroll-down); } +.scroll-pane scrollbarvertical sliderarrowdec:active, +.scroll-pane scrollbarvertical sliderarrowinc:active { filter: brightness(0.7); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/generic_menu_dialog.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/generic_menu_dialog.rcss new file mode 100644 index 0000000000..1393a01fcb --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/generic_menu_dialog.rcss @@ -0,0 +1,686 @@ +/* Classic (0.97) theme for the generic menu dialog. The in-game Esc menu (kind "system-menu") + takes the 0.97 look of the client's RenderMessageBox (0051af50), message 0x6e in the game scene: + five Message_box plates (the 213x64 art squashed to 120x22) at x 260, y 60 + 30*i of the + 640x480 frame, one per button the C++ gives, in its order (Exit game, Select server, Switch + character, Options, Cancel); no panel art, no header, no darkening. The plate under the mouse + is redrawn additively in (0.8, 0.6, 0.4) and each label is centred in white at y + 5. The rules + are at the end of this file, scoped to #panel.system-menu. + + The Chaos Goblin's menu (kind "chaos-mix"), the trainer's (npc-menu, trainer-recover; the other + npc-menu menus take the trainer's box) and Lahap's (gem-integration) take the Season 2 client's + boxes (scoped to their kinds, at the end of this file). The other NPC menus (elpis, elpis-about, + reset-points, delgardo, cherry-blossom, and the menus without a kind) keep the S6 look: no + classic client has them. This file replaces themes/legacy/generic_menu_dialog.rcss whole, so + every rule below that is not scoped to the system menu is legacy's, verbatim; the four legacy + rules the system menu drops are marked where they stood. The shell's frame sprites and header + come from legacy's window_shell.rml/.rcss and are hidden here for the system menu only. + + From legacy: single document (unlike generic_confirm_dialog's fg/bg split) -- no item3D here, + so no compositing-order problem to solve. Frame/border/header chrome (sprite frame + optional + title banner) lives in window_shell.rml/.rcss, a template shared with any future consumer -- + not exclusive to this dialog (see that file's own comment). This file supplies only this + document's own content layout (lines/buttons), not the shell. + + #panel is placed like native's menu boxes (see #panel below); dp throughout (no + transform:scale(root_scale), like generic_confirm_dialog.rcss), text in rem (RmlNativeText.h). 230dp + matches native's own MSGBOX_WIDTH and generic_confirm_dialog.rcss's own panel width. The height + follows the content, as native's per-menu fixed heights were sized to theirs. */ +#panel { + /* Native menu boxes (CChaosMixMenuMsgBox, CTrainerMenuMsgBox, CSeedMasterMenuMsgBox...) sit + centred with their top edge at y=60 and are as tall as their content: no centering transform + and no fixed height here -- the shell's content box flows (below) and sizes the panel. A + consumer that passes its own position (.window-shell-positioned) keeps it. */ + top: 60dp; + left: 50%; + margin-left: -115dp; + transform: none; + width: 230dp; + height: auto; /* #panel is the document body, which base.rcss makes full-screen */ + min-height: 117dp; + font-family: "token(font-body)"; + font-size: 1rem; + color: token(text-primary); +} +#panel.window-shell-positioned { margin-left: 0; } +/* Below the dialog canvas offset (RmlDialogCanvas.h). */ +#panel { margin-top: var(--canvas-top, 0dp); } +/* A menu that names the native box it replaces (GenericMenuConfig::kind) gets that box's top edge + and fixed height (kinds below); the shell's content box is then placed inside it as + window_shell.rcss does, and its compact Close button sits where native's does, 20 above the + bottom edge. */ +#panel.native-frame .window-shell-content { + position: absolute; + top: 20dp; + bottom: 28dp; + left: 16dp; + right: 16dp; + margin: 0; + justify-content: flex-start; +} +#panel.native-frame .window-shell-content.has-title { top: 0; } +/* A native box never scrolls: its buttons sit at fixed offsets inside the fixed frame. */ +#panel.native-frame .gmd-button-row { overflow: visible; } +/* Legacy's CSystemMenuMsgBox inset (the first button 23 below the top edge) is dropped: the + classic system menu's content box is its column of plates (the block at the end of this file). */ +#panel.native-frame .gmd-button-cell.compact { + position: absolute; + left: 0; + bottom: -8dp; /* content box ends 28dp above the panel bottom; native Close is 20dp above it */ + margin: 0; +} +/* The shell's content box in flow (window_shell.rcss places it absolutely inside a fixed-height + panel), with native's text width: MSGBOX_WIDTH less ~16 each side. */ +#panel .window-shell-content { + position: relative; + top: auto; + bottom: auto; + left: auto; + right: auto; + margin: 20dp 16dp 28dp 16dp; + z-index: 1; /* above the shell's absolutely positioned sprite layers */ +} +#panel .window-shell-content.has-title { margin-top: 0; } + +.gmd-line { + display: block; + width: 100%; + text-align: center; + white-space: normal; + color: token(text-primary); /* native menu text is white */ + margin-bottom: 4dp; +} +.gmd-line.bold { font-weight: bold; } +.gmd-lines { display: block; width: 100%; } + +/* A native box drew each of its centred lines with RenderText(x + 10, y, text, MSGBOX_WIDTH - 20, + 0, RT3_SORT_CENTER): one line in a 210-wide box, shrunk to it when wider (base.rcss .native-fit). + The content box is 198 wide (16 inset), so the box reaches 6 past it on each side. */ +#panel.native-frame .gmd-line .native-fit { margin: 0 -6dp; } +/* CTrainerRecoverMsgBox draws each pet's status line under its button. */ +.gmd-button-cell.lines-below { flex-direction: column-reverse; } +#panel.native-frame .gmd-button-cell.lines-below .gmd-line { line-height: 18dp; margin: 0; } + +/* CElpisMsgBox's divider (newui_Message_Line.tga, 223x21) across the box at native_divider_top. */ +@spritesheet msgbox-line-sheet +{ + src: "../../../newui_Message_Line.tga"; + msgbox-line-image: 0px 0px 223px 21px; +} +.gmd-divider { + display: none; + position: absolute; + left: -16dp; /* the content box is inset 16dp from the panel edge */ + width: 223dp; + height: 21dp; + decorator: image(msgbox-line-image); +} + +/* No explicit column count -- row + flex-wrap lets the button count/width and the row's own + available width determine how many fit per line, same mechanism + generic_confirm_dialog.rcss's own numeric-keypad grid already proves. Every native consumer's + fixed 128dp button width only ever fits one per row within this panel, so this naturally + reproduces their own single-column stack with no config knob needed; a future consumer with + narrower buttons would simply wrap onto more columns on its own. + overflow/pointer-events follow the exact same reasoning as .gcd-text-col in + generic_confirm_dialog.rcss (shorthand order matters for scrollbar creation; pointer-events + must be re-opted-in or the generated scrollbar can't receive input). */ +.gmd-button-row { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; + width: 100%; + /* No max-height: the panel grows with its content (see #panel), so a percentage cap would + resolve against an auto height and hide the whole row. */ + overflow: hidden auto; + pointer-events: auto; +} +.gmd-button-row scrollbarvertical { width: 6dp; margin: 0; } +.gmd-button-row scrollbarvertical slidertrack { background-color: token(surface-recessed); } +.gmd-button-row scrollbarvertical sliderbar { background-color: token(control-thumb); } +.gmd-button-row scrollbarvertical sliderbar:hover, +.gmd-button-row scrollbarvertical sliderbar:active { background-color: token(control-thumb-hover); } +.gmd-button-row scrollbarvertical sliderarrowdec, +.gmd-button-row scrollbarvertical sliderarrowinc { width: 0; height: 0; } +.gmd-button-row scrollbarhorizontal { height: 0; } + +/* Repeated unit of .gmd-button-row -- one button plus its own optional description lines + (button.lines), stacked in a column so text that belongs to a specific button (e.g. + CChaosMixMenuMsgBox's per-recipe blurb) renders directly above that button instead of being + bunched into the shared .gmd-line summary above the whole row. Width mirrors .gmd-btn's own two + sizes below so .gmd-line's width:100% wraps to the same column the button itself occupies; the + margin that used to live on .gmd-btn moved here so row spacing is unchanged. Empty + button.lines (the common case) just means an empty cell around a plain button -- no visual + difference from before this existed. */ +.gmd-button-cell { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; /* one button per row, as native stacks them; lines span the box */ + margin: 0 0 6dp 0; /* native NPC menus step their buttons 35 apart */ +} +/* Legacy's CSystemMenuMsgBox gap (1dp between 29dp buttons, 30 apart) and button width (108dp, + MSGBOX_BTN_EMPTY_WIDTH) are dropped: the classic plates are at the end of this file. */ +.gmd-button-cell.compact { width: 100%; } +/* A button with its own description lines needs a bit more breathing room below it than a plain + one, so it doesn't read as crowded against whatever's next in the stack. */ +.gmd-button-cell.has-lines { margin-bottom: 10dp; } +/* GenericMenuConfig::columns == 2 -- sized to fit exactly 2 per row within .gmd-body's own content + width, accounting for the WORST case where .gmd-button-row's own vertical scrollbar appears + (10 buttons in 2 columns = 5 rows, tall enough to need it): 230dp panel - 32dp*2 margins = 166dp, + - 6dp scrollbar = 160dp available. Margin trimmed to 2dp/side (from the base rule's 3dp) to + leave more room for the button itself: 2*(width + 4dp cell margin) <= 160dp => width <= 76dp. + See .gmd-btn.cols-2 below for why this needs its own decorator instead of inheriting .btn's + fixed-pixel sprite, and for the button's own narrower content width (this engine has no + box-sizing -- its border/padding add to width, they don't come out of it). */ +.gmd-button-cell.cols-2 { width: 76dp; margin: 0 2dp 6dp 2dp; } + +/* .btn defaults to position:absolute (base.rcss) -- overridden back to static so buttons flow as + ordinary flex children, same technique .gcd-item3d-anchor/.btn.gcd-keypad-btn already use in + generic_confirm_dialog.rcss. 128dp/64dp match native's own two button sizes exactly + (MSGBOX_BTN_EMPTY_WIDTH/_SMALL_WIDTH, CommonMessageBox.h); 76dp (.cols-2 below) has no native + equivalent (columns==2 is dialog-only). + + The decorator is native's own button art (sheets below), stretched to each width as native + stretches it. */ +/* Native menu buttons draw newui_btn_empty(_small).tga -- three 29px-tall states stacked, the + 108/64px-wide art stretched to the button -- not the options window's op1_b_all art. */ +@spritesheet msgbox-btn-empty-sheet +{ + src: "../../../newui_btn_empty.tga"; + msgbox-btn-empty-idle: 0px 0px 108px 29px; + msgbox-btn-empty-hover: 0px 29px 108px 29px; + msgbox-btn-empty-active: 0px 58px 108px 29px; +} +@spritesheet msgbox-btn-empty-small-sheet +{ + src: "../../../newui_btn_empty_small.tga"; + msgbox-btn-empty-small-idle: 0px 0px 64px 29px; + msgbox-btn-empty-small-hover: 0px 29px 64px 29px; + msgbox-btn-empty-small-active: 0px 58px 64px 29px; +} +.gmd-btn { + position: static; + width: 128dp; /* native menus: MSGBOX_BTN_EMPTY_WIDTH + 20 */ + height: 29dp; /* MSGBOX_BTN_EMPTY_HEIGHT */ + line-height: 29dp; + decorator: image(msgbox-btn-empty-idle); +} +.gmd-btn:hover { decorator: image(msgbox-btn-empty-hover); } +.gmd-btn:active { decorator: image(msgbox-btn-empty-active); } +.gmd-btn.narrow { width: 108dp; } /* MSGBOX_BTN_EMPTY_WIDTH (CGemIntegrationMsgBox) */ +.gmd-btn.compact { width: 64dp; decorator: image(msgbox-btn-empty-small-idle); } +.gmd-btn.compact:hover { decorator: image(msgbox-btn-empty-small-hover); } +.gmd-btn.compact:active { decorator: image(msgbox-btn-empty-small-active); } +/* GenericMenuConfig::columns == 2 -- see .gmd-button-cell.cols-2 above for the width math (decorators + don't consume box-model space like border/padding do, so this matches the cell exactly, no + subtraction needed). Every button keeps the art's 29dp height: a long jewel name (e.g. "Higher + Refining Stone") wraps onto a second line set close under the first, the label centred in the + button. Idle/hover/active decorators are inherited unchanged from the base .gmd-btn rules above. */ +.gmd-btn.cols-2 { + width: 76dp; + display: flex; + align-items: center; + justify-content: center; + white-space: normal; +} +/* Text lives in its own element (not raw text directly in .gmd-btn) purely so a decorator change + here doesn't require touching the shared markup structure again; no stacking-order concerns + remain now that there's no separate absolutely-positioned fill sibling to compete with (an + element's own decorator always paints before its children are rendered). */ +.gmd-btn-label { + display: block; + width: 100%; + white-space: nowrap; /* native draws a label on one line, even past the art's edge */ +} +.gmd-btn.cols-2 .gmd-btn-label { padding: 0 2dp; line-height: 1.0; white-space: normal; } +/* .btn.disabled (base.rcss) already gives the exact look a disabled menu button needs -- + data-class-disabled="!button.enabled" just toggles that existing class, no new rule needed. */ + +/* GenericMenuConfig::highlightTitle: native's highlight orange (CChaosMixMenuMsgBox's title). */ +#panel.highlight-title .window-shell-header-title { color: #ff8000; } + +/* The native boxes, by GenericMenuConfig::kind. Each sits at its top edge (60 unless given) and is + 67 (top cap) + 15 per middle strip + 50 (bottom cap) tall. Offsets inside are from the panel's + top edge: the containing block is the shell's content box, which starts there in a titled box + and 20 lower in an untitled one. */ +/* system-menu is dropped from this pair (legacy: CSystemMenuMsgBox at 100, 192 tall): the classic + system menu takes 0.97's place and size at the end of this file. */ +#panel[data-kind="gem-integration"] { top: 100dp; height: 192dp; } +#panel[data-kind="cherry-blossom"] { height: 237dp; } +#panel[data-kind="npc-menu"], #panel[data-kind="trainer-recover"], +#panel[data-kind="reset-points"], #panel[data-kind="delgardo"] { height: 222dp; } +#panel[data-kind="elpis"], #panel[data-kind="elpis-about"] { height: 297dp; } +#panel[data-kind="chaos-mix"] { height: 312dp; } + +/* Where the box's RenderTexts() drew the lines: the first one's text top less half the line gap + (the glyphs, 9 tall, centre in their line box), one advance apart. */ +#panel[data-kind="npc-menu"] .gmd-lines, #panel[data-kind="trainer-recover"] .gmd-lines, +#panel[data-kind="elpis"] .gmd-lines, #panel[data-kind="elpis-about"] .gmd-lines, +#panel[data-kind="reset-points"] .gmd-lines, #panel[data-kind="delgardo"] .gmd-lines { + position: absolute; + left: 0; + right: 0; + width: auto; + top: 38.5dp; /* text at 43, 18 apart */ + line-height: 18dp; +} +#panel[data-kind="reset-points"] .gmd-lines { top: 48.5dp; } /* text at 53 */ +#panel[data-kind="delgardo"] .gmd-lines { top: 46.5dp; line-height: 12dp; } /* text at 48, 12 apart */ +#panel[data-kind] .gmd-lines .gmd-line { margin-bottom: 0; } +/* CElpisMsgBox's "about" texts: left-aligned, wrapped inside an inset (its x+30). */ +#panel[data-kind="elpis-about"] .gmd-lines { left: 16dp; right: 16dp; } +#panel[data-kind="elpis-about"] .gmd-lines .gmd-line { text-align: left; } +/* CElpisMsgBox's divider under the text. */ +#panel[data-kind="elpis"] .gmd-divider, #panel[data-kind="elpis-about"] .gmd-divider { display: block; top: 120dp; } + +/* The buttons at the box's offsets (the Close button stays 20 above the bottom edge unless given). */ +#panel[data-kind="gem-integration"] .gmd-button-cell, +#panel[data-kind="chaos-mix"] .gmd-button-cell:nth-child(-n+3), +#panel[data-kind="npc-menu"] .gmd-button-cell:nth-child(-n+2), +#panel[data-kind="delgardo"] .gmd-button-cell:nth-child(-n+2), +#panel[data-kind="trainer-recover"] .gmd-button-cell:nth-child(-n+2), +#panel[data-kind="elpis"] .gmd-button-cell:nth-child(-n+3), +#panel[data-kind="elpis-about"] .gmd-button-cell:nth-child(-n+3), +#panel[data-kind="reset-points"] .gmd-button-cell:nth-child(1) { + position: absolute; + left: 0; + right: 0; + width: auto; + margin: 0; +} +/* CGemIntegrationMsgBox: untitled, BTN_TOP_BLANK 60 then 40 apart, Close included. */ +#panel[data-kind="gem-integration"] .gmd-button-cell:nth-child(1) { top: 40dp; } +#panel[data-kind="gem-integration"] .gmd-button-cell:nth-child(2) { top: 80dp; } +#panel[data-kind="gem-integration"] .gmd-button-cell:nth-child(3) { top: 120dp; bottom: auto; } +#panel[data-kind="npc-menu"] .gmd-button-cell:nth-child(1), +#panel[data-kind="delgardo"] .gmd-button-cell:nth-child(1) { top: 85dp; } +#panel[data-kind="npc-menu"] .gmd-button-cell:nth-child(2), +#panel[data-kind="delgardo"] .gmd-button-cell:nth-child(2) { top: 120dp; } +#panel[data-kind="trainer-recover"] .gmd-button-cell:nth-child(1) { top: 65dp; } +#panel[data-kind="trainer-recover"] .gmd-button-cell:nth-child(2) { top: 115dp; } +#panel[data-kind="elpis"] .gmd-button-cell:nth-child(1), #panel[data-kind="elpis-about"] .gmd-button-cell:nth-child(1) { top: 145dp; } +#panel[data-kind="elpis"] .gmd-button-cell:nth-child(2), #panel[data-kind="elpis-about"] .gmd-button-cell:nth-child(2) { top: 175dp; } +#panel[data-kind="elpis"] .gmd-button-cell:nth-child(3), #panel[data-kind="elpis-about"] .gmd-button-cell:nth-child(3) { top: 205dp; } +#panel[data-kind="reset-points"] .gmd-button-cell:nth-child(1) { top: 105dp; } + +/* CChaosMixMenuMsgBox: each recipe's lines 15 apart from their own top (40, 125, 210, less half + the line gap), one line each as native draws them (a wrapped line would run into the button), + and the button 3 below them (at 85, 155, 225). */ +#panel[data-kind="chaos-mix"] .gmd-button-cell:nth-child(1) { top: 37dp; } +#panel[data-kind="chaos-mix"] .gmd-button-cell:nth-child(2) { top: 122dp; } +#panel[data-kind="chaos-mix"] .gmd-button-cell:nth-child(3) { top: 207dp; } +#panel[data-kind="chaos-mix"] .gmd-button-cell:nth-child(-n+3) .gmd-line { + white-space: nowrap; + margin-bottom: 0; + line-height: 15dp; +} +#panel[data-kind="chaos-mix"] .gmd-button-cell:nth-child(-n+3) .gmd-btn { margin-top: 3dp; } + +/* The classic (0.97) system menu: RenderMessageBox (0051af50), message 0x6e in the game scene. + Five Message_box plates (213x64, drawn squashed to 120x22) stacked at x 260, y 60 + 30*i of the + 640x480 frame -- Exit game, Select server, Switch character, Options, Cancel, the five buttons + ShowSystemMenuDialog (CustomMessageBox.cpp) gives, in that order -- with no panel art, no header + and no darkening. The plate under the mouse is lit (0.97 redraws it additively in (0.8, 0.6, + 0.4)) and its label is centred in white at y + 5 (1rem text centred in the 22dp plate). 1dp is + one unit of the dialog canvas, as for every box above. Scoped to #panel.system-menu + (data-class-system-menu) so no rule reaches the NPC menus. The menu still drags by any part that + is not a plate (GenericMenuDialog.cpp); the plates are .btn (base.rcss: drag: block) and keep + their data-hint tooltips. */ +@spritesheet classic-sysmenu-plate-sheet { src: ../../../Classic/Message_box.jpg; classic-sysmenu-plate: 0px 0px 213px 64px; } + +/* The S6 frame (newui_msgbox_* back, top, middle, bottom) and title rail of window_shell.rcss: + 0.97 draws nothing around its plates. */ +#panel.system-menu .window-shell-sprite-back, +#panel.system-menu .window-shell-sprite-top, +#panel.system-menu .window-shell-sprite-middle, +#panel.system-menu .window-shell-sprite-bottom, +#panel.system-menu .window-shell-header-rail { display: none; } + +/* The column of plates: 120 wide from x 260 (60 left of the frame's centre), its top edge at y 60, + 142 tall (five plates 30 apart, 22 each: y 60 to 202), below the dialog canvas offset like every + #panel above. */ +#panel.system-menu { + top: 60dp; + width: 120dp; + height: 142dp; + margin-left: -60dp; +} +/* The content box is the column itself: the first plate sits at its top edge. */ +#panel.system-menu.native-frame .window-shell-content { top: 0; bottom: 0; left: 0; right: 0; } +/* 30 apart: 22 of plate, 8 of gap. */ +#panel.system-menu .gmd-button-cell { margin-bottom: 8dp; } +/* Each button is one plate. The id-scoped rule outranks .gmd-btn's :hover/:active art above, so + the plate stays under the mouse and the press: 0.97 has no pressed plate, only the lit one. + 0.97 lights it by drawing it again additively in (0.8, 0.6, 0.4), i.e. the plate times + (1.8, 1.6, 1.4), clamped: image-color #ffe3c6 is that ratio with red at full (the value the + scene menu's sys_menu.rcss uses) and brightness(1.8) scales it back up to (1.8, 1.6, 1.4) + (brightness() is a verified filter of this renderer, engine-findings.md). The white label is + already at full, so the filter leaves it white. */ +#panel.system-menu .gmd-btn { + width: 120dp; + height: 22dp; + line-height: 22dp; + decorator: image(classic-sysmenu-plate); +} +#panel.system-menu .gmd-btn:hover { + image-color: #ffe3c6; + filter: brightness(1.8); +} +#panel.system-menu .gmd-btn-label { color: #ffffff; } + +/* The Chaos Goblin's menu (kind "chaos-mix", CChaosMixMenuMsgBox). 0.97 opens the Chaos Machine + straight from the goblin; this menu is the Season 2 client's message box 0x8e (RE\mains2: + drawn in 006a9ad0, clicked in 0069ed30's 0x8e branch), in the 640x480 frame: + - the box: Message_box2 (213x5) at (213, 60), five Message_box1 strips (213x40) each stretched + to 213x60 from y 65, Message_box2 again at y 365 -- 213x310, no title banner; + - the title (text 734) bold, orange (255, 128, 0), centred, its text top at y 75; + - three buttons, Message_box (213x64) squashed to 150x35 at x 245, y 130, 215 and 300, tinted + 0.7 grey and drawn white while the mouse is over them; their labels bold, (200, 240, 255), + centred, text top 12 under the button's; + - each button's lines regular, white, left-aligned at x 248, 10 apart, the text tops at 90, + 100 and 110 (the first button), 180 and 190 (the second), 270 (the third) -- centred here + (below); + - no Close button: the box closes with the Chaos Machine (Esc here, GenericMenuConfig's + onCancel, the Close button's own action). + Positions below are from the box's top-left (213, 60). The stone is the derived + Message_box1_60x5 (tools/classic_theme/make_classic_derived_textures.py): five strips already + stretched to 60, drawn unscaled. */ +@spritesheet classic-cm-edge-sheet { src: ../../../Classic/Message_box2.jpg; classic-cm-edge: 0px 0px 213px 5px; } +@spritesheet classic-cm-stone-sheet { src: ../../../Classic/Message_box1_60x5.jpg; classic-cm-stone: 0px 0px 213px 300px; } +@spritesheet classic-cm-plate-sheet { src: ../../../Classic/Message_box.jpg; classic-cm-plate: 0px 0px 213px 64px; } + +#panel[data-kind="chaos-mix"] { + width: 213dp; + height: 310dp; + margin-left: -106.5dp; +} +#panel[data-kind="chaos-mix"] .window-shell-sprite-back, +#panel[data-kind="chaos-mix"] .window-shell-header-rail { decorator: none; } +#panel[data-kind="chaos-mix"] .window-shell-sprite-top { height: 5dp; decorator: image(classic-cm-edge); } +#panel[data-kind="chaos-mix"] .window-shell-sprite-middle { top: 5dp; bottom: 5dp; decorator: image(classic-cm-stone fill); } +#panel[data-kind="chaos-mix"] .window-shell-sprite-bottom { height: 5dp; decorator: image(classic-cm-edge); } + +/* The title: a 10 line box around its text top at 15 (the glyphs, 9 tall, centre in it). */ +#panel[data-kind="chaos-mix"] .window-shell-header-title { + top: 14.5dp; + line-height: 10dp; + color: #ff8000; +} + +/* The content box is the whole box, so every offset below is from its top-left. */ +#panel[data-kind="chaos-mix"].native-frame .window-shell-content { top: 0; bottom: 0; left: 0; right: 0; } + +/* Each recipe's lines: 10 apart, the first line box 0.5 above its text top. Season 2 starts them + at x 35 (248), left-aligned, but MuMain's lines are longer than its and ran into the box's + right edge there: they are centred instead, between the stone's golden sides (8 in from each + edge), and a line wider than that is drawn smaller to fit it (.native-fit). */ +#panel[data-kind="chaos-mix"] .gmd-button-cell:nth-child(1) { top: 29.5dp; } +#panel[data-kind="chaos-mix"] .gmd-button-cell:nth-child(2) { top: 119.5dp; } +#panel[data-kind="chaos-mix"] .gmd-button-cell:nth-child(3) { top: 209.5dp; } +#panel[data-kind="chaos-mix"] .gmd-button-cell:nth-child(-n+3) .gmd-line { + align-self: stretch; /* the cell centres its children: the line spans it instead */ + width: auto; + margin: 0 8dp; + line-height: 10dp; + text-align: center; +} +#panel[data-kind="chaos-mix"].native-frame .gmd-line .native-fit { margin: 0; } + +/* The buttons at y 70, 155 and 240 of the box, below their 3, 2 and 1 lines. The id-scoped + rules outrank .gmd-btn's :hover/:active art above, so the plate stays under the mouse and the + press: Season 2 only draws it white. The label's text top is 12 under the button's: a 33 line + box from its top. */ +#panel[data-kind="chaos-mix"] .gmd-button-cell:nth-child(1) .gmd-btn { margin-top: 10.5dp; } +#panel[data-kind="chaos-mix"] .gmd-button-cell:nth-child(2) .gmd-btn { margin-top: 15.5dp; } +#panel[data-kind="chaos-mix"] .gmd-button-cell:nth-child(3) .gmd-btn { margin-top: 20.5dp; } +#panel[data-kind="chaos-mix"] .gmd-btn { + width: 150dp; + height: 35dp; + line-height: 33dp; + image-color: rgb(179, 179, 179); + decorator: image(classic-cm-plate fill); +} +#panel[data-kind="chaos-mix"] .gmd-btn:hover, +#panel[data-kind="chaos-mix"] .gmd-btn:active { image-color: #ffffff; decorator: image(classic-cm-plate fill); } +#panel[data-kind="chaos-mix"] .gmd-btn-label { font-weight: bold; color: rgb(200, 240, 255); } + +/* Season 2's box has no Close button. */ +#panel[data-kind="chaos-mix"] .gmd-button-cell.compact { display: none; } + +/* The NPC menus of kind "npc-menu" (the trainer, and the Lucky Item, seed master and seed researcher + menus, which no classic client has and which take the trainer's box) and the trainer's pet + recovery (kind "trainer-recover"): the Season 2 client's trainer boxes (RE\mains2: 00462c5b and + 00463377), in the 640x480 frame: + - the box: Message_box2 (213x5) at (213, 90), five Message_box1 rows (213x40) from y 90, and + Message_box2 again at y 290 -- 213x205; + - the title (text 1227) bold, centred on x 319 at y 100; Season 2 writes it black over a band of + (200, 200, 200) at 78%, which the theme takes orange (255, 128, 0) and bandless instead, as the + Chaos Goblin's and Lahap's titles (the user's choice); + - the lines centred on x 319, (200, 200, 200), their text tops at 120 and 140; + - two Message_box plates (213x64) squashed to 120x22 at x 259: at y 180 + and 210 in the menu, 150 and 210 in the recovery; their labels gold (223, 191, 103), text top + 5 under the plate's, drawn bold under the mouse; the recovery's status line 30 under each + plate's top; + - Close is exit_01 (24x24) at (394, 265), with no label. + The stat reset helper (reset-points), Delgado (delgardo) and the cherry blossom menu, which no + classic client has, take the same box: their lines from 30, 20 apart, and their buttons at 90 and + 120 (Delgado's three lines end above them), 90 (the reset's one) or 60, 90 and 120 (the cherry + blossom's three). + Positions below are from the box's top-left (213, 90). The stone is the derived + Message_box1_40x6 (six rows, unscaled), cut to the rows the box shows. */ +@spritesheet classic-tr-stone-sheet { src: ../../../Classic/Message_box1_40x6.jpg; classic-tr-stone: 0px 5px 213px 195px; classic-lh-stone: 0px 0px 213px 240px; } +@spritesheet classic-tr-plate-sheet { src: ../../../Classic/Message_box.jpg; classic-tr-plate: 0px 0px 213px 64px; } +@spritesheet classic-tr-exit-sheet { src: ../../../Classic/Exit_01.jpg; classic-tr-exit: 0px 0px 24px 24px; } +@spritesheet classic-tr-exit2-sheet { src: ../../../Classic/Exit_02.jpg; classic-tr-exit-pressed: 0px 0px 24px 24px; } + +#panel[data-kind="npc-menu"], #panel[data-kind="trainer-recover"], #panel[data-kind="reset-points"], #panel[data-kind="delgardo"], #panel[data-kind="cherry-blossom"] { + top: 90dp; + width: 213dp; + height: 205dp; + margin-left: -106.5dp; +} +#panel[data-kind="npc-menu"] .window-shell-sprite-back, #panel[data-kind="trainer-recover"] .window-shell-sprite-back, #panel[data-kind="reset-points"] .window-shell-sprite-back, #panel[data-kind="delgardo"] .window-shell-sprite-back, #panel[data-kind="cherry-blossom"] .window-shell-sprite-back, +#panel[data-kind="npc-menu"] .window-shell-header-rail, #panel[data-kind="trainer-recover"] .window-shell-header-rail, #panel[data-kind="reset-points"] .window-shell-header-rail, #panel[data-kind="delgardo"] .window-shell-header-rail, #panel[data-kind="cherry-blossom"] .window-shell-header-rail { decorator: none; } +#panel[data-kind="npc-menu"] .window-shell-sprite-top, #panel[data-kind="trainer-recover"] .window-shell-sprite-top, #panel[data-kind="reset-points"] .window-shell-sprite-top, #panel[data-kind="delgardo"] .window-shell-sprite-top, #panel[data-kind="cherry-blossom"] .window-shell-sprite-top { height: 5dp; decorator: image(classic-cm-edge); } +#panel[data-kind="npc-menu"] .window-shell-sprite-middle, #panel[data-kind="trainer-recover"] .window-shell-sprite-middle, #panel[data-kind="reset-points"] .window-shell-sprite-middle, #panel[data-kind="delgardo"] .window-shell-sprite-middle, #panel[data-kind="cherry-blossom"] .window-shell-sprite-middle { top: 5dp; bottom: 5dp; decorator: image(classic-tr-stone fill); } +#panel[data-kind="npc-menu"] .window-shell-sprite-bottom, #panel[data-kind="trainer-recover"] .window-shell-sprite-bottom, #panel[data-kind="reset-points"] .window-shell-sprite-bottom, #panel[data-kind="delgardo"] .window-shell-sprite-bottom, #panel[data-kind="cherry-blossom"] .window-shell-sprite-bottom { height: 5dp; decorator: image(classic-cm-edge); } +#panel[data-kind="npc-menu"].native-frame .window-shell-content, +#panel[data-kind="trainer-recover"].native-frame .window-shell-content, +#panel[data-kind="reset-points"].native-frame .window-shell-content, +#panel[data-kind="delgardo"].native-frame .window-shell-content, +#panel[data-kind="cherry-blossom"].native-frame .window-shell-content { top: 0; bottom: 0; left: 0; right: 0; } + +/* The title: a 13 line box at 10. */ +#panel[data-kind="npc-menu"] .window-shell-header-title, #panel[data-kind="trainer-recover"] .window-shell-header-title, #panel[data-kind="reset-points"] .window-shell-header-title, #panel[data-kind="delgardo"] .window-shell-header-title, #panel[data-kind="cherry-blossom"] .window-shell-header-title { + left: 5dp; + right: 5dp; + top: 10dp; + line-height: 13dp; + color: #ff8000; +} + +/* The lines: 20 apart, their text tops at 30 and 50 (a 20 line box 5.5 above each). */ +#panel[data-kind="npc-menu"] .gmd-lines, #panel[data-kind="trainer-recover"] .gmd-lines, #panel[data-kind="reset-points"] .gmd-lines, #panel[data-kind="delgardo"] .gmd-lines, #panel[data-kind="cherry-blossom"] .gmd-lines { top: 24.5dp; line-height: 20dp; } +#panel[data-kind="npc-menu"] .gmd-lines .gmd-line, #panel[data-kind="trainer-recover"] .gmd-lines .gmd-line, #panel[data-kind="reset-points"] .gmd-lines .gmd-line, #panel[data-kind="delgardo"] .gmd-lines .gmd-line, #panel[data-kind="cherry-blossom"] .gmd-lines .gmd-line { color: rgb(200, 200, 200); } + +/* The plates at 90 and 120 (menu), 60 and 120 (recovery), 46 from the box's left. The kind-scoped + rules outrank .gmd-btn's :hover/:active art above: Season 2 only draws the label bold. A label + longer than the plate (other languages, the menus Season 2 doesn't have) widens it, centred. */ +#panel[data-kind="npc-menu"] .gmd-button-cell:nth-child(1) { top: 90dp; } +#panel[data-kind="npc-menu"] .gmd-button-cell:nth-child(2) { top: 120dp; } +#panel[data-kind="trainer-recover"] .gmd-button-cell:nth-child(1) { top: 60dp; } +#panel[data-kind="trainer-recover"] .gmd-button-cell:nth-child(2) { top: 120dp; } +#panel[data-kind="reset-points"] .gmd-button-cell:nth-child(1), +#panel[data-kind="delgardo"] .gmd-button-cell:nth-child(1) { top: 90dp; } +#panel[data-kind="delgardo"] .gmd-button-cell:nth-child(2) { top: 120dp; } +#panel[data-kind="cherry-blossom"] .gmd-button-cell:nth-child(1) { top: 60dp; } +#panel[data-kind="cherry-blossom"] .gmd-button-cell:nth-child(2) { top: 90dp; } +#panel[data-kind="cherry-blossom"] .gmd-button-cell:nth-child(3) { top: 120dp; } +#panel[data-kind="npc-menu"] .gmd-btn, #panel[data-kind="trainer-recover"] .gmd-btn, #panel[data-kind="reset-points"] .gmd-btn, #panel[data-kind="delgardo"] .gmd-btn, #panel[data-kind="cherry-blossom"] .gmd-btn, +#panel[data-kind="npc-menu"] .gmd-btn:hover, #panel[data-kind="trainer-recover"] .gmd-btn:hover, #panel[data-kind="reset-points"] .gmd-btn:hover, #panel[data-kind="delgardo"] .gmd-btn:hover, #panel[data-kind="cherry-blossom"] .gmd-btn:hover, +#panel[data-kind="npc-menu"] .gmd-btn:active, #panel[data-kind="trainer-recover"] .gmd-btn:active, #panel[data-kind="reset-points"] .gmd-btn:active, #panel[data-kind="delgardo"] .gmd-btn:active, #panel[data-kind="cherry-blossom"] .gmd-btn:active { + width: auto; + min-width: 120dp; + padding: 0 6dp; + height: 22dp; + line-height: 21dp; + decorator: image(classic-tr-plate fill); +} +#panel[data-kind="npc-menu"] .gmd-btn-label, #panel[data-kind="trainer-recover"] .gmd-btn-label, #panel[data-kind="reset-points"] .gmd-btn-label, #panel[data-kind="delgardo"] .gmd-btn-label, #panel[data-kind="cherry-blossom"] .gmd-btn-label { color: rgb(223, 191, 103); } +#panel[data-kind="npc-menu"] .gmd-btn:hover .gmd-btn-label, #panel[data-kind="trainer-recover"] .gmd-btn:hover .gmd-btn-label, #panel[data-kind="reset-points"] .gmd-btn:hover .gmd-btn-label, #panel[data-kind="delgardo"] .gmd-btn:hover .gmd-btn-label, #panel[data-kind="cherry-blossom"] .gmd-btn:hover .gmd-btn-label { font-weight: bold; } +/* The recovery's status line under each plate, its text top 30 under the plate's. */ +#panel[data-kind="trainer-recover"].native-frame .gmd-button-cell.lines-below .gmd-line { margin-top: 2.5dp; line-height: 10dp; } + +/* Close: exit_01 at (181, 175), its label hidden. */ +#panel[data-kind="npc-menu"].native-frame .gmd-button-cell.compact, +#panel[data-kind="trainer-recover"].native-frame .gmd-button-cell.compact, +#panel[data-kind="reset-points"].native-frame .gmd-button-cell.compact, +#panel[data-kind="delgardo"].native-frame .gmd-button-cell.compact, +#panel[data-kind="cherry-blossom"].native-frame .gmd-button-cell.compact { + left: 181dp; + right: auto; + top: 175dp; + bottom: auto; + width: 24dp; +} +#panel[data-kind="npc-menu"] .gmd-btn.compact, #panel[data-kind="trainer-recover"] .gmd-btn.compact, #panel[data-kind="reset-points"] .gmd-btn.compact, #panel[data-kind="delgardo"] .gmd-btn.compact, #panel[data-kind="cherry-blossom"] .gmd-btn.compact, +#panel[data-kind="npc-menu"] .gmd-btn.compact:hover, #panel[data-kind="trainer-recover"] .gmd-btn.compact:hover, #panel[data-kind="reset-points"] .gmd-btn.compact:hover, #panel[data-kind="delgardo"] .gmd-btn.compact:hover, #panel[data-kind="cherry-blossom"] .gmd-btn.compact:hover { + width: 24dp; + min-width: 0; + padding: 0; + height: 24dp; + decorator: image(classic-tr-exit); +} +#panel[data-kind="npc-menu"] .gmd-btn.compact:active, #panel[data-kind="trainer-recover"] .gmd-btn.compact:active, #panel[data-kind="reset-points"] .gmd-btn.compact:active, #panel[data-kind="delgardo"] .gmd-btn.compact:active, #panel[data-kind="cherry-blossom"] .gmd-btn.compact:active { width: 24dp; min-width: 0; padding: 0; height: 24dp; decorator: image(classic-tr-exit-pressed); } +#panel[data-kind="npc-menu"] .gmd-btn.compact .gmd-btn-label, #panel[data-kind="trainer-recover"] .gmd-btn.compact .gmd-btn-label, #panel[data-kind="reset-points"] .gmd-btn.compact .gmd-btn-label, #panel[data-kind="delgardo"] .gmd-btn.compact .gmd-btn-label, #panel[data-kind="cherry-blossom"] .gmd-btn.compact .gmd-btn-label { visibility: hidden; } + +/* Lahap's jewel menu (kind "gem-integration"): the Season 2 client's message box 0xa1 (RE\mains2: + drawn in 006a9ad0), in the 640x480 frame: + - the box: Message_box2 (213x5) at (213, 120), six Message_box1 rows (213x40) from y 125, and + Message_box2 again at y 365 -- 213x250; + - the title (text 1801, MuMain's first line, bold orange) centred, its text top about 15 under + the box's, as the Chaos Goblin's; + - the lines (texts 1802 and 1803) white, left-aligned at x 248, their text tops at 150 and 160; + - two Message_box plates squashed to 150x35 at x 245, y 190 and 255, tinted 0.7 grey and drawn + white under the mouse; their labels bold, (200, 240, 255), centred, 12 under the plate's top; + - Close: a Message_box plate squashed to 81x25 at (279, 320), tinted 0.8 grey and white under + the mouse, its label like the others, 8 under its top. + Positions below are from the box's top-left (213, 120). */ +#panel[data-kind="gem-integration"] { + top: 120dp; + width: 213dp; + height: 250dp; + margin-left: -106.5dp; +} +#panel[data-kind="gem-integration"] .window-shell-sprite-back, +#panel[data-kind="gem-integration"] .window-shell-header-rail { decorator: none; } +#panel[data-kind="gem-integration"] .window-shell-sprite-top { height: 5dp; decorator: image(classic-cm-edge); } +#panel[data-kind="gem-integration"] .window-shell-sprite-middle { top: 5dp; bottom: 5dp; decorator: image(classic-lh-stone fill); } +#panel[data-kind="gem-integration"] .window-shell-sprite-bottom { height: 5dp; decorator: image(classic-cm-edge); } +#panel[data-kind="gem-integration"].native-frame .window-shell-content { top: 0; bottom: 0; left: 0; right: 0; } + +/* The title line centred at 15; the two lines under it left-aligned at 35, at 30 and 40 (10 line + boxes, 0.5 above each text top). */ +#panel[data-kind="gem-integration"] .gmd-lines { + position: absolute; + left: 0; + right: 0; + width: auto; + top: 14.5dp; + line-height: 10dp; +} +#panel[data-kind="gem-integration"] .gmd-lines .gmd-line { margin-bottom: 0; padding-left: 35dp; text-align: left; white-space: nowrap; } +#panel[data-kind="gem-integration"] .gmd-lines .gmd-line:first-child { margin-bottom: 5dp; padding-left: 0; text-align: center; } + +#panel[data-kind="gem-integration"] .gmd-button-cell:nth-child(1) { top: 70dp; } +#panel[data-kind="gem-integration"] .gmd-button-cell:nth-child(2) { top: 135dp; } +#panel[data-kind="gem-integration"] .gmd-btn, +#panel[data-kind="gem-integration"] .gmd-btn.narrow { + width: 150dp; + height: 35dp; + line-height: 33dp; + image-color: rgb(179, 179, 179); + decorator: image(classic-tr-plate fill); +} +#panel[data-kind="gem-integration"] .gmd-btn:hover, +#panel[data-kind="gem-integration"] .gmd-btn:active { image-color: #ffffff; decorator: image(classic-tr-plate fill); } +#panel[data-kind="gem-integration"] .gmd-btn-label { font-weight: bold; color: rgb(200, 240, 255); } +#panel[data-kind="gem-integration"] .gmd-button-cell:nth-child(3) { top: 200dp; bottom: auto; } +#panel[data-kind="gem-integration"] .gmd-btn.compact { + width: 81dp; + height: 25dp; + line-height: 25dp; + image-color: rgb(204, 204, 204); + decorator: image(classic-tr-plate fill); +} +#panel[data-kind="gem-integration"] .gmd-btn.compact:hover, +#panel[data-kind="gem-integration"] .gmd-btn.compact:active { image-color: #ffffff; decorator: image(classic-tr-plate fill); } + +/* Elpis (kinds "elpis" and "elpis-about"): the Season 2 client's window (RE\mains2: built in + 006d3959, drawn in the method that calls 006d3f52, buttons placed in 006d3b05), in the 640x480 + frame: + - the box: 214x250 at (213, 65): Message_box2 (5) at the top, six Message_box1 rows from 5, and + Message_box2 at 245; in the menu, two more Message_box2 strips across it at 30 and 145; + - the title (text 2206) white, from x 10 at y 15; + - the text in (255, 176, 73), left-aligned from (20, 50), 15 apart (MuMain passes its own colour + with the lines, so they keep it); + - three win_button buttons (49x16) drawn at 100x20, centred, at y 156, 189 and 222: tinted 0.8, + white under the mouse, 0.6 while pressed; their labels (230, 220, 200), centred. + Season 2's menu has no Close button (Esc does the same), so MuMain's is hidden. Its "about" pages + show only an OK button; here they keep the menu's three buttons and drop the two strips. + Positions below are from the box's top-left (213, 65). */ +@spritesheet classic-elpis-btn-sheet { src: "../../../win_button.tga"; classic-elpis-btn: 0px 0px 49px 16px; } + +#panel[data-kind="elpis"], #panel[data-kind="elpis-about"] { + top: 65dp; + width: 214dp; + height: 250dp; + margin-left: -107dp; +} +#panel[data-kind="elpis"] .window-shell-sprite-back, #panel[data-kind="elpis-about"] .window-shell-sprite-back, +#panel[data-kind="elpis-about"] .window-shell-header-rail { decorator: none; } +#panel[data-kind="elpis"] .window-shell-sprite-top, #panel[data-kind="elpis-about"] .window-shell-sprite-top { height: 5dp; decorator: image(classic-cm-edge fill); } +#panel[data-kind="elpis"] .window-shell-sprite-middle, #panel[data-kind="elpis-about"] .window-shell-sprite-middle { top: 5dp; bottom: 5dp; decorator: image(classic-lh-stone fill); } +#panel[data-kind="elpis"] .window-shell-sprite-bottom, #panel[data-kind="elpis-about"] .window-shell-sprite-bottom { height: 5dp; decorator: image(classic-cm-edge fill); } +#panel[data-kind="elpis"].native-frame .window-shell-content, +#panel[data-kind="elpis-about"].native-frame .window-shell-content { top: 0; bottom: 0; left: 0; right: 0; } + +/* The menu's two strips: the shell's title rail at 30, the divider at 145. */ +#panel[data-kind="elpis"] .window-shell-header-rail { top: 30dp; height: 5dp; decorator: image(classic-cm-edge fill); } +#panel[data-kind="elpis"] .gmd-divider { display: block; left: 0; top: 145dp; width: 214dp; height: 5dp; decorator: image(classic-cm-edge fill); } +#panel[data-kind="elpis-about"] .gmd-divider { display: none; } + +/* The title: a 10 line box around its text top at 15. */ +#panel[data-kind="elpis"] .window-shell-header-title, #panel[data-kind="elpis-about"] .window-shell-header-title { + left: 10dp; + right: 10dp; + top: 14.5dp; + line-height: 10dp; + color: #ffffff; +} + +/* The text from (20, 50), 15 apart, wrapped inside the stone's sides. */ +#panel[data-kind="elpis"] .gmd-lines, #panel[data-kind="elpis-about"] .gmd-lines { + left: 20dp; + right: 20dp; + top: 47dp; + line-height: 15dp; +} +#panel[data-kind="elpis"] .gmd-lines .gmd-line, #panel[data-kind="elpis-about"] .gmd-lines .gmd-line { font-weight: normal; text-align: left; } + +#panel[data-kind="elpis"] .gmd-button-cell:nth-child(1), #panel[data-kind="elpis-about"] .gmd-button-cell:nth-child(1) { top: 156dp; } +#panel[data-kind="elpis"] .gmd-button-cell:nth-child(2), #panel[data-kind="elpis-about"] .gmd-button-cell:nth-child(2) { top: 189dp; } +#panel[data-kind="elpis"] .gmd-button-cell:nth-child(3), #panel[data-kind="elpis-about"] .gmd-button-cell:nth-child(3) { top: 222dp; } +#panel[data-kind="elpis"] .gmd-btn, #panel[data-kind="elpis-about"] .gmd-btn, +#panel[data-kind="elpis"] .gmd-btn:hover, #panel[data-kind="elpis-about"] .gmd-btn:hover { + width: 100dp; + height: 20dp; + line-height: 20dp; + image-color: rgb(204, 204, 204); + decorator: image(classic-elpis-btn fill); +} +#panel[data-kind="elpis"] .gmd-btn:hover, #panel[data-kind="elpis-about"] .gmd-btn:hover { image-color: #ffffff; } +#panel[data-kind="elpis"] .gmd-btn:active, #panel[data-kind="elpis-about"] .gmd-btn:active { image-color: rgb(153, 153, 153); decorator: image(classic-elpis-btn fill); } +#panel[data-kind="elpis"] .gmd-btn-label, #panel[data-kind="elpis-about"] .gmd-btn-label { color: rgb(230, 220, 200); } +#panel[data-kind="elpis"] .gmd-button-cell.compact, #panel[data-kind="elpis-about"] .gmd-button-cell.compact { display: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/gens_ranking.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/gens_ranking.rcss new file mode 100644 index 0000000000..81fc415ace --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/gens_ranking.rcss @@ -0,0 +1,188 @@ +/* Classic theme for the Gens window (CGensRanking). 0.97 and the Season 1/2 clients have no Gens; the + window takes the classic docked windows' parts: the 0.97 frame (docked_panel_frame.rcss), the + two value rows on 0.97's text box (Level_box, stretched to the row as the character window's), + the rank mark and the description in frames of lines (230, 230, 153) like the classic pet + window's (Season 1), in place of the S6 rank back, tables and corners; the description's scroll + bar is the classic docked one (win_scrollbar). The family marks are the Gens art. Legacy's rules + first, then the classic ones. */ + +/* Legacy theme for CGensRanking, reproducing its RenderFrame()/RenderTexts(): the + docked_panel_frame.rcss frame (linked first; newui_item_back04 top), newui_gens_rankback + (170 x 88) at (13, 60) with the rank's 50 x 69 cell of Gens_mark_D_new / Gens_mark_V_new at + (30.5, 69.5), the two newui_cha_textbox02 rows (170 x 21), RenderInfoFrame()'s titled box at + (13, 250) (black at alpha 153 behind newui_item_table corners and edges), the scroll bar at + (170, 273), 110 tall (newui_scrollbar_up / m / down, newui_scroll_on thumb, newui_scroll_off while + inactive), the texts in their bound colours and fonts, the exit button. Reference px inside + #panel. */ + +@spritesheet gens-d-sheet +{ + src: "../../../Gens_mark_D_new.tga"; + gens-d-0: 0px 0px 50px 69px; + gens-d-1: 50px 0px 50px 69px; + gens-d-2: 100px 0px 50px 69px; + gens-d-3: 150px 0px 50px 69px; + gens-d-4: 200px 0px 50px 69px; + gens-d-5: 0px 69px 50px 69px; + gens-d-6: 50px 69px 50px 69px; + gens-d-7: 100px 69px 50px 69px; + gens-d-8: 150px 69px 50px 69px; + gens-d-9: 200px 69px 50px 69px; + gens-d-10: 0px 138px 50px 69px; + gens-d-11: 50px 138px 50px 69px; + gens-d-12: 100px 138px 50px 69px; + gens-d-13: 150px 138px 50px 69px; +} +@spritesheet gens-v-sheet +{ + src: "../../../Gens_mark_V_new.tga"; + gens-v-0: 0px 0px 50px 69px; + gens-v-1: 50px 0px 50px 69px; + gens-v-2: 100px 0px 50px 69px; + gens-v-3: 150px 0px 50px 69px; + gens-v-4: 200px 0px 50px 69px; + gens-v-5: 0px 69px 50px 69px; + gens-v-6: 50px 69px 50px 69px; + gens-v-7: 100px 69px 50px 69px; + gens-v-8: 150px 69px 50px 69px; + gens-v-9: 200px 69px 50px 69px; + gens-v-10: 0px 138px 50px 69px; + gens-v-11: 50px 138px 50px 69px; + gens-v-12: 100px 138px 50px 69px; + gens-v-13: 150px 138px 50px 69px; +} +@spritesheet gr-rank-back-sheet { src: "../../../newui_gens_rankback.tga"; gr-rank-back: 0px 0px 170px 88px; } +@spritesheet gr-text-back-sheet { src: "../../../newui_cha_textbox02.tga"; gr-text-back: 0px 0px 170px 21px; } +@spritesheet gr-edge-top-sheet { src: "../../../newui_item_table03(Up).tga"; gr-edge-top: 0px 0px 1px 14px; } +@spritesheet gr-edge-bottom-sheet { src: "../../../newui_item_table03(Dw).tga"; gr-edge-bottom: 0px 0px 1px 14px; } +@spritesheet gr-edge-left-sheet { src: "../../../newui_item_table03(L).tga"; gr-edge-left: 0px 0px 14px 1px; } +@spritesheet gr-edge-right-sheet { src: "../../../newui_item_table03(R).tga"; gr-edge-right: 0px 0px 14px 1px; } + +.frame-top { decorator: image(docked-bg-top-a); } +#panel { pointer-events: none; } + +#rank_back { position: absolute; left: 13px; top: 60px; width: 170px; height: 88px; decorator: image(gr-rank-back); } +#mark { position: absolute; left: 30.5px; top: 69.5px; width: 50px; height: 69px; } +#mark.gens-d-0 { decorator: image(gens-d-0); } +#mark.gens-d-1 { decorator: image(gens-d-1); } +#mark.gens-d-2 { decorator: image(gens-d-2); } +#mark.gens-d-3 { decorator: image(gens-d-3); } +#mark.gens-d-4 { decorator: image(gens-d-4); } +#mark.gens-d-5 { decorator: image(gens-d-5); } +#mark.gens-d-6 { decorator: image(gens-d-6); } +#mark.gens-d-7 { decorator: image(gens-d-7); } +#mark.gens-d-8 { decorator: image(gens-d-8); } +#mark.gens-d-9 { decorator: image(gens-d-9); } +#mark.gens-d-10 { decorator: image(gens-d-10); } +#mark.gens-d-11 { decorator: image(gens-d-11); } +#mark.gens-d-12 { decorator: image(gens-d-12); } +#mark.gens-d-13 { decorator: image(gens-d-13); } +#mark.gens-v-0 { decorator: image(gens-v-0); } +#mark.gens-v-1 { decorator: image(gens-v-1); } +#mark.gens-v-2 { decorator: image(gens-v-2); } +#mark.gens-v-3 { decorator: image(gens-v-3); } +#mark.gens-v-4 { decorator: image(gens-v-4); } +#mark.gens-v-5 { decorator: image(gens-v-5); } +#mark.gens-v-6 { decorator: image(gens-v-6); } +#mark.gens-v-7 { decorator: image(gens-v-7); } +#mark.gens-v-8 { decorator: image(gens-v-8); } +#mark.gens-v-9 { decorator: image(gens-v-9); } +#mark.gens-v-10 { decorator: image(gens-v-10); } +#mark.gens-v-11 { decorator: image(gens-v-11); } +#mark.gens-v-12 { decorator: image(gens-v-12); } +#mark.gens-v-13 { decorator: image(gens-v-13); } +.text-back { position: absolute; left: 13px; width: 170px; height: 21px; decorator: image(gr-text-back); } + +.fill { position: absolute; background-color: rgba(0, 0, 0, 153); } +.t-edge-top, .t-edge-bottom, .t-edge-left, .t-edge-right, .t-corner { position: absolute; } +.t-edge-top { height: 14px; decorator: image(gr-edge-top); } +.t-edge-bottom { height: 14px; decorator: image(gr-edge-bottom); } +.t-edge-left { width: 14px; decorator: image(gr-edge-left); } +.t-edge-right { width: 14px; decorator: image(gr-edge-right); } +.t-corner { width: 14px; height: 14px; } +.t-tl { decorator: image(docked-corner-tl); } +.t-tr { decorator: image(docked-corner-tr); } +.t-bl { decorator: image(docked-corner-bl); } +.t-br { decorator: image(docked-corner-br); } + +.sharp-text { display: block; position: absolute; white-space: nowrap; text-align: left; pointer-events: none; } +#btn_exit { pointer-events: auto; } + +/* The rank strip and the description box, piece by piece. */ +.fill-strip { left: 16px; top: 252px; width: 52px; height: 20px; } +.fill-desc { left: 16px; top: 272px; width: 161px; height: 113px; } +.corner-strip-tl { left: 13px; top: 250px; } +.corner-strip-tr { left: 59px; top: 250px; } +.corner-desc-tr { left: 167px; top: 270px; } +.corner-bl { left: 13px; top: 376px; } +.corner-br { left: 167px; top: 376px; } +.edge-strip-top { left: 19px; top: 250px; width: 48px; } +.edge-strip-right { left: 59px; top: 256px; height: 14px; } +.edge-desc-top { left: 68px; top: 270px; width: 102px; } +.edge-desc-right { left: 167px; top: 276px; height: 106px; } +.edge-bottom { left: 19px; top: 376px; width: 156px; } +.edge-left { left: 13px; top: 256px; height: 126px; } +.text-back-level { top: 151px; } +.text-back-rank { top: 175px; } + +/* The window's own lines. */ +.gr-line, .gr-promo-line { position: absolute; } +#gr_title { left: 0; top: 15px; text-align: center; font-weight: bold; } +#gr_gens_label { left: 102px; top: 90px; font-weight: bold; } +#gr_gens_name { left: 102px; top: 110px; } +#gr_level_label { left: 100px; top: 134px; } +#gr_title_name { left: 66px; top: 134px; text-align: center; } +#gr_rank_label { left: 13px; top: 157px; text-align: center; font-weight: bold; } +#gr_rank_value { left: 0; top: 157px; text-align: right; } +#gr_contrib_label { left: 13px; top: 180px; text-align: center; font-weight: bold; } +#gr_contrib_value { left: 0; top: 180px; text-align: right; } +#gr_desc_label { left: 13px; top: 258px; text-align: center; font-weight: bold; } + +/* The promotion note: up to NUM_LINE_CMB rows 15 units apart from y 200. */ +.gr-promo { position: static; } +.gr-promo-line { left: 20px; } +.gr-promo-line:nth-child(1) { top: 200px; } +.gr-promo-line:nth-child(2) { top: 215px; } +.gr-promo-line:nth-child(3) { top: 230px; } +.gr-promo-line:nth-child(4) { top: 245px; } +.gr-promo-line:nth-child(5) { top: 260px; } +.gr-promo-line:nth-child(6) { top: 275px; } +.gr-promo-line:nth-child(7) { top: 290px; } + +/* The frame's bottom edge starts at y=376. The pane counters the panel's scale, + so its scroll geometry and scrollbar use physical pixels. */ +.gr-desc { position: absolute; left: 20px; top: 280px; transform-origin: left top; overflow: hidden scroll; clip: always; pointer-events: auto; } +.gr-desc-line { position: relative; display: block; } +.gr-desc-text { position: absolute; display: block; left: 0; top: 0; white-space: nowrap; pointer-events: none; } + +.gr-line, .gr-promo-line, .gr-desc-text { color: #ffffff; } +#gr_gens_label { color: rgb(246, 209, 73); } +#gr_rank_label, #gr_contrib_label, #gr_desc_label { color: rgb(230, 230, 0); } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#gr_title { width: calc(190px * var(--root-scale)); } +#gr_gens_label { width: calc(190px * var(--root-scale)); } +#gr_gens_name { width: calc(190px * var(--root-scale)); } +#gr_level_label { width: calc(190px * var(--root-scale)); } +#gr_title_name { width: calc(174px * var(--root-scale)); } +#gr_rank_label { width: calc(74px * var(--root-scale)); } +#gr_rank_value { width: calc(170px * var(--root-scale)); } +#gr_contrib_label { width: calc(74px * var(--root-scale)); } +#gr_contrib_value { width: calc(170px * var(--root-scale)); } +#gr_desc_label { width: calc(58px * var(--root-scale)); } +.gr-promo-line { width: calc(180px * var(--root-scale)); } +.gr-desc.scroll-pane { width: calc(165px * var(--root-scale)); height: calc(96px * var(--root-scale)); } +/* CTextBox's row pitch: a line height + 2. */ +.gr-desc-line { width: calc(150px * var(--root-scale)); height: calc((var(--line-height) + 2px) * var(--root-scale)); } +.gr-desc-text { width: calc(150px * var(--root-scale)); } + +/* The data-for template row has no step of its own; it inherits this one. */ +.gr-desc { --line-height: 0px; } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet gr-classic-box-sheet { src: ../../../Classic/Level_box.jpg; gr-classic-box: 0px 0px 75px 21px; } +#rank_back { decorator: none; box-sizing: border-box; border-width: 1px; border-color: rgb(230, 230, 153); } +.text-back { decorator: image(gr-classic-box fill); } +.t-corner, .t-edge-top, .t-edge-bottom, .t-edge-left, .t-edge-right, .fill-strip { display: none; } +.fill-desc { left: 13px; top: 250px; width: 170px; height: 140px; background-color: transparent; + box-sizing: border-box; border-width: 1px; border-color: rgb(230, 230, 153); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/gold_bowman.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/gold_bowman.rcss new file mode 100644 index 0000000000..78c89b3c28 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/gold_bowman.rcss @@ -0,0 +1,42 @@ +/* Classic Golden Archer windows (CGoldBowmanWindow, CGoldBowmanLena), over event_item_entry.rcss. + The current client's look (Main.dll GoldenArcher.cpp, which replaced 0.97's Lucky Number window; + ): the 0.97 frame, the title in + its 120 box at (35, 12), texts in (255, 230, 210), Message_box plates 120x22 as buttons (lit + (0.8, 0.6, 0.4) under the mouse, darkened 0.4 while locked) and the 0.97 Close at (25, 395). + Each document's _rows.rcss places its own lines and buttons. */ + +@spritesheet gb-classic-plate-sheet { src: ../../../Classic/Message_box.jpg; gb-classic-plate: 0px 0px 213px 64px; } +@spritesheet gb-classic-exit-sheet { src: ../../../Classic/Exit_01.jpg; gb-classic-exit: 0px 0px 24px 24px; } +@spritesheet gb-classic-exit2-sheet { src: ../../../Classic/Exit_02.jpg; gb-classic-exit-pressed: 0px 0px 24px 24px; } +@spritesheet gb-classic-money-sheet { src: ../../../Classic/Item_money.jpg; gb-classic-money: 0px 0px 113px 18px; } +@spritesheet gb-classic-box-sheet { src: ../../../Classic/Level_box.jpg; gb-classic-box: 0px 0px 75px 21px; } + +.frame-top { decorator: image(docked-bg-top-a); } +.entry-text .sharp-text { white-space: pre; } +.entry-label { color: #ffffff; } +.entry-btn.locked .entry-label { color: #808080; } + +/* The register plate and the exit plate (the first and second buttons in both documents). */ +.entry-btn:nth-child(1) { left: 35px; width: 120px; height: 22px; decorator: image(gb-classic-plate); } +.entry-btn:nth-child(1):hover, .entry-btn:nth-child(1):active { image-color: #ffd9b3; } +.entry-btn:nth-child(1).locked, .entry-btn:nth-child(1).locked:hover, .entry-btn:nth-child(1).locked:active { image-color: #666666; } +.entry-btn:nth-child(2) { left: 25px; top: 395px; width: 24px; height: 24px; decorator: image(gb-classic-exit); } +.entry-btn:nth-child(2):active { decorator: image(gb-classic-exit-pressed); } +.entry-btn:nth-child(2) .entry-label { display: none; } + +/* The lucky number field on the Item_Money bar. */ +#serial_back { position: absolute; left: 40px; top: 190px; width: 113px; height: 18px; decorator: image(gb-classic-money); } +#serial_field { + text-align: left; + left: 48px; + top: 192px; + padding: 0; + border-width: 0; + border-radius: 0; + background-color: transparent; + color: rgb(255, 230, 210); + pointer-events: auto; + width: calc(100px * var(--root-scale)); + height: calc(14px * var(--root-scale)); + line-height: calc(14px * var(--root-scale)); +} diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/gold_bowman_lena_rows.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/gold_bowman_lena_rows.rcss new file mode 100644 index 0000000000..f8aac8bfe1 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/gold_bowman_lena_rows.rcss @@ -0,0 +1,30 @@ +/* Classic rows of the Golden Archer's Rena window, after the current client's Rena page: the + title in its box, the explanation from y 50, "Collected" and "Registered" each on a Level_box + (75x21, the second mirrored) at y 115 with their counts under them (the registered one in + (204, 153, 0)), Register at y 165 and the closing notice from y 215. */ + +.entry-text:nth-child(1) { left: 35px; top: 12px; width: 120px; color: #e6e6e6; font-weight: bold; } +.entry-text:nth-child(2) { left: 0px; top: 50px; color: rgb(255, 230, 210); } +.entry-text:nth-child(3) { left: 0px; top: 65px; color: rgb(255, 230, 210); } +.entry-text:nth-child(4) { left: 0px; top: 80px; color: rgb(255, 230, 210); } +.entry-text:nth-child(5) { left: 13px; top: 115px; width: 75px; height: 21px; decorator: image(gb-classic-box); color: rgb(255, 230, 210); } +.entry-text:nth-child(6) { left: 13px; top: 140px; width: 75px; color: #ffffff; } +.entry-text:nth-child(7) { left: 102px; top: 115px; width: 75px; height: 21px; decorator: image(gb-classic-box flip-horizontal); color: rgb(255, 230, 210); } +.entry-text:nth-child(8) { left: 102px; top: 140px; width: 75px; color: rgb(204, 153, 0); } +.entry-text:nth-child(9) { left: 0px; top: 215px; color: rgb(255, 230, 210); } +.entry-text:nth-child(10) { left: 0px; top: 230px; color: rgb(255, 230, 210); } + +.entry-btn:nth-child(1) { top: 165px; } + +/* The captions are the current client's (texts 884 / 885, centred on the box). MuMain's own + captions ("Number of Rena you have", ...) are far wider than the 75-unit boxes and run into + each other, so they are hidden and the short ones drawn on the plates instead. */ +.entry-text:nth-child(5) .sharp-text, .entry-text:nth-child(7) .sharp-text { visibility: hidden; } +.entry-text:nth-child(5) { font-size: 8px; decorator: text("Collected Renas" #ffe6d2 center center), image(gb-classic-box); } +.entry-text:nth-child(7) { font-size: 8px; decorator: text("Registered Renas" #ffe6d2 center center), image(gb-classic-box flip-horizontal); } + +/* Where C++ draws the live 3D Rena (legacy's .entry-item-box, which this copy predated): 20x20, + just left of each count's "X". */ +.entry-item-box { position: absolute; width: 20px; height: 20px; pointer-events: none; } +#entry_item_box_1 { left: 22px; top: 136px; } +#entry_item_box_2 { left: 111px; top: 136px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/gold_bowman_rows.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/gold_bowman_rows.rcss new file mode 100644 index 0000000000..cb8d838591 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/gold_bowman_rows.rcss @@ -0,0 +1,16 @@ +/* Classic rows of the Golden Archer's lucky number window: the title in its box, the explanation + from y 50, the example from y 120 (the number green), the field at y 190, Register at y 220 and + the registered gift's name at y 260. */ + +.entry-text:nth-child(1) { left: 35px; top: 12px; width: 120px; color: #e6e6e6; font-weight: bold; } +.entry-text:nth-child(2) { left: 0px; top: 50px; color: rgb(255, 230, 210); } +.entry-text:nth-child(3) { left: 0px; top: 65px; color: rgb(255, 230, 210); } +.entry-text:nth-child(4) { left: 0px; top: 80px; color: rgb(255, 230, 210); } +.entry-text:nth-child(5) { left: 0px; top: 95px; color: rgb(255, 230, 210); } +.entry-text:nth-child(6) { left: 0px; top: 120px; color: rgb(255, 230, 210); } +.entry-text:nth-child(7) { left: 0px; top: 135px; color: rgb(0, 255, 24); } +.entry-text:nth-child(8) { left: 0px; top: 150px; color: rgb(255, 230, 210); } +.entry-text:nth-child(9) { left: 0px; top: 165px; color: rgb(255, 230, 210); } +.entry-text:nth-child(10) { left: 0px; top: 260px; color: rgb(0, 210, 255); } + +.entry-btn:nth-child(1) { top: 220px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/guard_window.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/guard_window.rcss new file mode 100644 index 0000000000..40ffaad7eb --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/guard_window.rcss @@ -0,0 +1,217 @@ +/* Classic theme for the guardsman (CGuardWindow, the siege registration). 0.97 has no Castle Siege; + the Season 1 client's (00615570, docked at x 450): the 0.97 frame, the title bold white + at y 15, the castle's owners bold white at 56 and 71; Season 1's tab strip: three win_button tabs + 54 wide at x 15, 69 and 123 from y 90 (the chosen one 2 taller and white, the others 0.6 grey + with a 1-unit (146, 144, 141) line under them at y 105), labels bold; the pages' lines as + legacy's; the guild list on a black 40% box (158 x 237 at (15, 124)) with no frame, its headings + at y 113 in the normal font, its rows (230, 220, 200), a chosen row on white at 50% with black + text, the classic docked scroll bar (win_scrollbar); the buttons Season 1's win_button 50 x 18 at + x 70 (Proclaim 115, Register 199, Give up 367), grey 0.8 at rest, white under the mouse, 0.6 + pressed, red (1, 0.4, 0.4) locked, labelled (230, 220, 200); the 0.97 Close at (25, 395). + Legacy's rules first, then the classic ones. */ + +/* Legacy theme for CGuardWindow, reproducing its RenderFrame(), tabs and pages: the + docked_panel_frame.rcss frame (linked first; newui_item_back01 top), the three newui_guild_tab04 + tabs (56 x 22, one unit apart from (12, 84); the selected one on its second row, its label white, + the others (181, 181, 181)), the texts in their bound fonts and colours, the List tab's + newui_item_table03 edges, the backdrops and lines' boxes in their bound colours, the scroll track + (newui_scrollbar_up / m / down) and newui_scroll_on thumb (tinted (200, 200, 200) while dragged), + the 53 x 23 newui_btn_empty_very_small buttons at x 68 (locked ones tinted (100, 100, 100) with a + grey label, never hovered), the exit button at (13, 391). Reference px inside #panel. */ + +@spritesheet gd-tab-sheet +{ + src: "../../../newui_guild_tab04.tga"; + gd-tab-up: 0px 0px 56px 22px; + gd-tab-down: 0px 22px 56px 22px; +} +@spritesheet gd-btn-sheet +{ + src: "../../../newui_btn_empty_very_small.tga"; + gd-btn-up: 0px 0px 53px 23px; + gd-btn-over: 0px 23px 53px 23px; + gd-btn-down: 0px 46px 53px 23px; +} +@spritesheet gd-edge-top-sheet { src: "../../../newui_item_table03(Up).tga"; gd-edge-top: 0px 0px 1px 14px; } +@spritesheet gd-edge-bottom-sheet { src: "../../../newui_item_table03(Dw).tga"; gd-edge-bottom: 0px 0px 1px 14px; } +@spritesheet gd-edge-left-sheet { src: "../../../newui_item_table03(L).tga"; gd-edge-left: 0px 0px 14px 1px; } +@spritesheet gd-edge-right-sheet { src: "../../../newui_item_table03(R).tga"; gd-edge-right: 0px 0px 14px 1px; } + +.frame-top { decorator: image(docked-bg-top-b); } +/* RmlUi handles tab clicks; the panel leaves world clicks alone elsewhere. */ +#panel { pointer-events: none; } + +.gd-tabs { position: static; } +.gd-tab { position: absolute; top: 84px; width: 56px; height: 22px; pointer-events: auto; decorator: image(gd-tab-up); } +.gd-tab:nth-child(1) { left: 12px; } +.gd-tab:nth-child(2) { left: 69px; } +.gd-tab:nth-child(3) { left: 126px; } +.gd-tab.selected { decorator: image(gd-tab-down); } +.gd-tab .gd-tab-label { left: 0; text-align: center; color: #b5b5b5; } +.gd-tab.selected .gd-tab-label { color: #ffffff; } + +.t-edge-top, .t-edge-bottom, .t-edge-left, .t-edge-right { position: absolute; } +.t-edge-top { width: 161px; height: 14px; decorator: image(gd-edge-top); } +.t-edge-bottom { width: 161px; height: 14px; decorator: image(gd-edge-bottom); } +.t-edge-left { width: 14px; decorator: image(gd-edge-left); } +.t-edge-right { width: 14px; decorator: image(gd-edge-right); } + +.sharp-text { display: block; position: absolute; white-space: nowrap; text-align: left; pointer-events: none; } + +/* RenderFrame() and the pages drew every one of these in (220, 220, 220). */ +.gd-heading, .gd-owner, .gd-line { color: #dcdcdc; } + +/* The window's own text. Each line is named, so the theme decides where it sits, what colour it + is and how it is aligned; only its font size stays bound. Its width is reference px times --root-scale. */ +.gd-heading, .gd-owner, .gd-line { left: 0; text-align: center; } +.gd-heading { left: 15px; top: 13px; font-weight: bold; } +.gd-owner { font-weight: bold; } +#owner_master { top: 50px; } +#owner_guild { top: 65px; } + +.gd-page { position: static; } +#status_start { top: 125px; } +#status_end { top: 139px; } +#status_period { top: 153px; } +#status_expected_label { top: 188px; } +#status_expected_time { top: 202px; } +#status_next_stage { top: 237px; } +#register_message { top: 125px; } +#register_message2 { top: 139px; } +#register_acquired { top: 155px; } +#register_registered { top: 169px; } +/* The List tab's own message kept the headers' bold font. */ +#list_message { top: 125px; font-weight: bold; } +.gd-line.bold { font-weight: bold; } + +#btn_proclaim { top: 120px; } +#btn_register { top: 200px; } +#btn_give_up { top: 370px; } + +.gd-btn { display: block; position: absolute; left: 68px; width: 53px; height: 23px; decorator: image(gd-btn-up); pointer-events: auto; } +.gd-btn:hover { decorator: image(gd-btn-over); } +.gd-btn:active { decorator: image(gd-btn-down); } +.gd-btn.locked, .gd-btn.locked:hover, .gd-btn.locked:active { decorator: image(gd-btn-up); image-color: #646464; } +.gd-label { left: 0; text-align: center; color: #ffffff; } +.gd-btn.locked .gd-label { color: #646464; } + +#btn_exit { top: 391px; pointer-events: auto; } + +/* The guild list's frame, placed here rather than inline in the shared RML. The main box is + shorter when the summary row is present, which is what `.with-footer` says. */ +.gd-list-frame { position: static; } +.gd-list-edge-left { left: 11px; top: 111px; height: 255px; } +.gd-list-edge-right { left: 166px; top: 111px; height: 255px; } +.gd-list-edge-top { left: 14px; top: 111px; } +.gd-list-edge-bottom { left: 14px; top: 357px; } +.with-footer .gd-list-edge-left, +.with-footer .gd-list-edge-right { height: 215px; } +.with-footer .gd-list-edge-bottom { top: 317px; } +.gd-foot-edge-left { left: 11px; top: 345px; height: 25px; } +.gd-foot-edge-right { left: 166px; top: 345px; height: 25px; } +.gd-foot-edge-top { left: 14px; top: 345px; } +.gd-foot-edge-bottom { left: 14px; top: 362px; } + +/* Guild rows flow inside counter-scaled scroll panes. */ +.gd-list { position: static; } +.gd-header, .gd-cell { position: absolute; } +.gd-header { top: 117px; font-weight: bold; } +.hdr-name { left: 20px; } +.hdr-mark-count { left: 65px; } +.hdr-state { left: 113px; } +.hdr-order { left: 138px; } +.hdr-side { left: 95px; } +.hdr-involvement { left: 135px; } + +.gd-scroll-pane { position: absolute; left: 15px; top: 129px; transform-origin: left top; overflow: hidden scroll; } +.gd-row { display: block; position: relative; pointer-events: auto; } +.gd-row-back { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; } +.gd-row .gd-cell { position: absolute; top: 23.0769%; white-space: nowrap; pointer-events: none; } +.cell-name { left: 4.0541%; } +.cell-mark-count { right: 50%; text-align: right; } +.cell-state { right: 16.2162%; text-align: right; } +.cell-order { right: 2.7027%; text-align: right; } +.cell-side { right: 29.7297%; text-align: right; } +.cell-involvement { right: 4.7297%; text-align: right; } + +.score-label { left: 33px; top: 354px; } +.score-value { left: 75px; top: 354px; } + +/* RenderInterface()'s own boxes: the list's backdrop and the summary row's two halves, all at the + colour its SetLineColor() left set. */ +.gd-list-back { position: absolute; left: 14px; top: 128px; width: 161px; height: 237px; background-color: rgba(0, 0, 0, 102); } +.with-footer .gd-list-back { height: 197px; } +.gd-foot-back-label { position: absolute; left: 14px; top: 348px; width: 61px; height: 20px; background-color: rgba(146, 134, 121, 102); } +.gd-foot-back-value { position: absolute; left: 75px; top: 348px; width: 100px; height: 20px; background-color: rgba(0, 0, 0, 102); } + +.gd-header { color: #dcdcdc; } +.gd-cell { color: rgb(230, 220, 200); } +/* RenderDataLine(): a selected row, and a defending guild's row, carry the same backdrop; only a + selected row's text turns black against it. */ +.gd-row.selected .gd-row-back, .gd-row.defending .gd-row-back { background-color: rgba(0, 0, 0, 102); } +.gd-row.selected .gd-cell { color: #000000; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#heading { width: calc(160px * var(--root-scale)); } +#owner_master { width: calc(190px * var(--root-scale)); } +#owner_guild { width: calc(190px * var(--root-scale)); } +.gd-tab-label { width: calc(56px * var(--root-scale)); } +#status_start { width: calc(190px * var(--root-scale)); } +#status_end { width: calc(190px * var(--root-scale)); } +#status_period { width: calc(190px * var(--root-scale)); } +#status_expected_label { width: calc(190px * var(--root-scale)); } +#status_expected_time { width: calc(190px * var(--root-scale)); } +#status_next_stage { width: calc(190px * var(--root-scale)); } +#register_message { width: calc(190px * var(--root-scale)); } +#register_message2 { width: calc(190px * var(--root-scale)); } +#register_acquired { width: calc(190px * var(--root-scale)); } +#register_registered { width: calc(190px * var(--root-scale)); } +#list_message { width: calc(190px * var(--root-scale)); } +#guard_declare_list { width: calc(160px * var(--root-scale)); height: calc(235px * var(--root-scale)); } +.gd-row { width: calc(148px * var(--root-scale)); height: calc(13px * var(--root-scale)); } +#guard_siege_list { width: calc(160px * var(--root-scale)); height: calc(195px * var(--root-scale)); } +.gd-label { width: calc(53px * var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet gd-classic-btn-sheet { src: "../../../win_button.tga"; gd-classic-btn: 0px 0px 49px 16px; } +.gd-heading { top: 15px; color: #ffffff; } +.gd-owner { color: #ffffff; } +#owner_master { top: 56px; } +#owner_guild { top: 71px; } + +.gd-tab, .gd-tab.selected { top: 90px; width: 54px; height: 16px; decorator: image(gd-classic-btn fill); image-color: #999999; + box-sizing: border-box; border-bottom: 1px rgb(146, 144, 141); } +.gd-tab:nth-child(1) { left: 15px; } +.gd-tab:nth-child(2) { left: 69px; } +.gd-tab:nth-child(3) { left: 123px; } +.gd-tab.selected { top: 88px; height: 18px; image-color: #ffffff; border-bottom-width: 0; } +.gd-tab .gd-tab-label, .gd-tab.selected .gd-tab-label { font-weight: bold; color: #e6dcc8; } +.gd-tab-label { width: calc(54px * var(--root-scale)); } + +.t-edge-top, .t-edge-bottom, .t-edge-left, .t-edge-right { display: none; } +.gd-list-back { left: 15px; top: 124px; width: 158px; height: 237px; } +.with-footer .gd-list-back { height: 197px; } +.gd-header { top: 113px; font-weight: normal; } +.gd-list-declare .hdr-name { left: 21px; } +.hdr-mark-count { left: 79px; } +.hdr-state { left: 114px; } +.hdr-order { left: 139px; } +.gd-list-siege .hdr-name { left: 21px; } +.hdr-side { left: 96px; } +.hdr-involvement { left: 136px; } +.gd-scroll-pane { left: 16px; top: 125px; } +#guard_declare_list { width: calc(157px * var(--root-scale)); height: calc(235px * var(--root-scale)); } +#guard_siege_list { width: calc(157px * var(--root-scale)); height: calc(195px * var(--root-scale)); } +.gd-row.selected .gd-row-back { background-color: rgba(255, 255, 255, 128); } + +.gd-btn, .gd-btn:hover, .gd-btn:active { left: 70px; width: 50px; height: 18px; decorator: image(gd-classic-btn fill); image-color: #cccccc; } +.gd-btn:hover { image-color: #ffffff; } +.gd-btn:active { image-color: #999999; } +.gd-btn.locked, .gd-btn.locked:hover, .gd-btn.locked:active { decorator: image(gd-classic-btn fill); image-color: #ff6666; } +.gd-label, .gd-btn.locked .gd-label { color: #e6dcc8; } +.gd-btn:active .gd-label { margin-left: calc(1px * var(--root-scale)); margin-top: calc(1px * var(--root-scale)); } +.gd-label { width: calc(50px * var(--root-scale)); } +#btn_proclaim { top: 115px; } +#btn_register { top: 199px; } +#btn_give_up { top: 367px; } +#btn_exit { top: 395px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/guild_info.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/guild_info.rcss new file mode 100644 index 0000000000..640c3090f6 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/guild_info.rcss @@ -0,0 +1,383 @@ +/* Classic theme for CGuildInfoWindow. A theme's stylesheet replaces its base's whole file, so this is + legacy's guild_info.rcss (its layout, with legacy's comments) followed by the classic parts at the + end. Every tab, figure, list and button stays: 0.97 has one guild window (the notice over the + member list, 004f0810), and the window here keeps MuMain's Guild, Members and Alliance pages, + dressed in the classic pieces -- Season 1's win_button tabs (dimmed, the current one lit and taller, + as in its pet window), tables drawn as single lines in the classic social windows' colour, 0.97's + text colours and plates for the buttons, and the Season 1 scrollbar. */ + +@spritesheet gi-tab-list-sheet { src: "../../../newui_guild_tab01.tga"; gi-tab-list: 0px 0px 166px 22px; } +@spritesheet gi-tab-point-sheet { src: "../../../newui_guild_tab02.tga"; gi-tab-point: 0px 0px 56px 22px; } +@spritesheet gi-tab-head-sheet { src: "../../../newui_guild_tab03.tga"; gi-tab-head: 0px 0px 63px 26px; } +@spritesheet gi-edge-top-sheet { src: "../../../newui_item_table03(Up).tga"; gi-edge-top: 0px 0px 1px 14px; } +@spritesheet gi-edge-bottom-sheet { src: "../../../newui_item_table03(Dw).tga"; gi-edge-bottom: 0px 0px 1px 14px; } +@spritesheet gi-edge-left-sheet { src: "../../../newui_item_table03(L).tga"; gi-edge-left: 0px 0px 14px 1px; } +@spritesheet gi-edge-right-sheet { src: "../../../newui_item_table03(R).tga"; gi-edge-right: 0px 0px 14px 1px; } +@spritesheet gi-scroll-top-sheet { src: "../../../newui_scrollbar_up.tga"; gi-scroll-top: 0px 0px 7px 3px; } +@spritesheet gi-scroll-mid-sheet { src: "../../../newui_scrollbar_m.tga"; gi-scroll-mid: 0px 0px 7px 15px; } +@spritesheet gi-scroll-bottom-sheet { src: "../../../newui_scrollbar_down.tga"; gi-scroll-bottom: 0px 0px 7px 3px; } +@spritesheet gi-thumb-sheet { src: "../../../newui_scroll_on.tga"; gi-thumb: 0px 0px 15px 30px; } +@spritesheet gi-btn-sheet +{ + src: "../../../newui_btn_empty_small.tga"; + gi-btn-up: 0px 0px 64px 29px; + gi-btn-over: 0px 29px 64px 29px; + gi-btn-down: 0px 58px 64px 29px; +} + +.frame-top { decorator: image(docked-bg-top-b); } +/* The tabs, the list lines and the scroll thumbs are hit-tested natively. */ +#panel { pointer-events: none; } + +#tab_list { position: absolute; left: 12px; top: 68px; width: 166px; height: 22px; decorator: image(gi-tab-list); } +#tab_point { position: absolute; top: 68px; width: 56px; height: 22px; decorator: image(gi-tab-point); } +#tab_point.tab-0 { left: 12px; } +#tab_point.tab-1 { left: 68px; } +#tab_point.tab-2 { left: 124px; } +#tab_head { position: absolute; left: 11px; top: 237px; width: 63px; height: 25px; decorator: image(gi-tab-head); } + +.t-edge-top, .t-edge-bottom, .t-edge-left, .t-edge-right, .t-corner { position: absolute; } +.t-edge-top { height: 14px; decorator: image(gi-edge-top); } +.t-edge-bottom { height: 14px; decorator: image(gi-edge-bottom); } +.t-edge-left { width: 14px; decorator: image(gi-edge-left); } +.t-edge-right { width: 14px; decorator: image(gi-edge-right); } +.t-corner { width: 14px; height: 14px; } +.t-tl { decorator: image(docked-corner-tl); } +.t-tr { decorator: image(docked-corner-tr); } +.t-bl { decorator: image(docked-corner-bl); } +.t-br { decorator: image(docked-corner-br); } +.fill { position: absolute; } + +#guild_mark { position: absolute; left: 74px; top: 106px; width: 39px; height: 39px; } +.mark-cell { float: left; width: 4.875px; height: 4.875px; } +.line-mark { position: absolute; width: calc(8px * var(--root-scale)); height: calc(8px * var(--root-scale)); } +.line-mark-cell { float: left; width: 1px; height: 1px; } + +.s-top, .s-mid, .s-bottom { position: absolute; width: 7px; } +.s-top { height: 3px; decorator: image(gi-scroll-top); } +.s-mid { height: 15px; decorator: image(gi-scroll-mid); } +.s-bottom { height: 3px; decorator: image(gi-scroll-bottom); } +.thumb { position: absolute; width: 15px; height: 30px; decorator: image(gi-thumb); } + +/* The original drew these boxes (officer rows, the selected row) without setting a colour, so they + took whatever the frame left: in practice the scroll bar's rgb(106, 97, 88), sometimes white, + which hid the member text. The grey-brown it normally shows, always (an original defect fixed). */ +/* A row's backdrop: the selected line, and a member holding an office. */ +.gi-row.selected .gi-row-back, .gi-row.officer .gi-row-back { background-color: rgb(106, 97, 88); } + +.sharp-text { display: block; position: absolute; white-space: nowrap; text-align: left; pointer-events: none; } + +.gi-btn { + display: block; + position: absolute; + width: 64px; + height: 29px; + decorator: image(gi-btn-up); + pointer-events: auto; +} +.gi-btn:hover { decorator: image(gi-btn-over); } +.gi-btn:active { decorator: image(gi-btn-down); } +.gi-label { left: 0; text-align: center; color: #ffffff; } + +/* Every piece below came out of a style attribute in the shared RML, which the inline-property + rule made un-overridable. The geometry is the original's own Render_*() walk. */ +.gi-page { position: static; } +.gi-line, .gi-note, .gi-figure, .gi-header { position: absolute; } +.gi-line { text-align: center; } + +#gi_hint_title { left: 0; top: 15px; font-weight: bold; } +#gi_hint_1 { left: 25px; top: 46px; } +#gi_hint_2 { left: 25px; top: 61px; } +#gi_hint_3 { left: 25px; top: 76px; } + +#gi_title { left: 0; top: 12px; } +#gi_name { left: 35px; top: 48px; } +/* The three tab labels, one TAB_WIDTH apart from TAB_START_X + 1. */ +.gi-tab-label { top: 76px; } +#gi_tab_info { left: 13px; } +#gi_tab_members { left: 69px; } +#gi_tab_union { left: 125px; } + +#gi_notice_label { left: 22px; top: 249px; } +#gi_created { left: 22px; top: 169px; } +#gi_score { left: 22px; top: 182px; } +#gi_member_count { left: 22px; top: 195px; } +#gi_rival { left: 22px; top: 208px; } + +#gi_hdr_name { left: 24px; top: 112px; } +#gi_hdr_position { left: 89px; top: 112px; } +#gi_hdr_server { left: 126px; top: 112px; } +#gi_hdr_union_name { left: 34px; top: 115px; } +#gi_hdr_union_members { left: 140px; top: 115px; } + +/* The guild mark's own table. */ +.mark-edge-top { left: 73px; top: 104px; width: 42px; } +.mark-edge-bottom { left: 73px; top: 138px; width: 42px; } +.mark-edge-left { left: 70px; top: 104px; height: 42px; } +.mark-edge-right { left: 105px; top: 104px; height: 42px; } +.mark-corner-tl { left: 70px; top: 104px; } +.mark-corner-tr { left: 105px; top: 104px; } +.mark-corner-bl { left: 70px; top: 138px; } +.mark-corner-br { left: 105px; top: 138px; } + +/* The figures table, and the announcement box under it. */ +.figures-edge-top { left: 12px; top: 159px; width: 166px; } +.figures-edge-bottom { left: 12px; top: 215px; width: 166px; } +.figures-edge-left { left: 10px; top: 159px; height: 65px; } +.figures-edge-right { left: 167px; top: 159px; height: 65px; } +.figures-corner-tl { left: 10px; top: 159px; } +.figures-corner-tr { left: 167px; top: 159px; } +.figures-corner-bl { left: 10px; top: 215px; } +.figures-corner-br { left: 167px; top: 215px; } +.notice-fill { left: 11px; top: 260px; width: 165px; height: 84px; } +.notice-edge-top { left: 12px; top: 260px; width: 165px; } +.notice-edge-bottom { left: 12px; top: 334px; width: 165px; } +.notice-edge-left { left: 10px; top: 260px; height: 82px; } +.notice-edge-right { left: 167px; top: 260px; height: 82px; } +.notice-corner-tr { left: 167px; top: 260px; } +.notice-corner-bl { left: 10px; top: 334px; } +.notice-corner-br { left: 167px; top: 334px; } + +/* The member list's table. */ +.members-fill { left: 12px; top: 125px; width: 165px; height: 232px; } +.members-head-fill { left: 12px; top: 105px; width: 165px; height: 20px; } +.members-edge-top { left: 12px; top: 105px; width: 165px; } +.members-edge-bottom { left: 12px; top: 347px; width: 165px; } +.members-edge-left { left: 8px; top: 105px; height: 251px; } +.members-edge-right { left: 168px; top: 105px; height: 251px; } +.members-corner-tl { left: 8px; top: 105px; } +.members-corner-tr { left: 168px; top: 105px; } +.members-corner-bl { left: 8px; top: 347px; } +.members-corner-br { left: 168px; top: 347px; } + +/* The alliance list's table. */ +.union-fill { left: 12px; top: 125px; width: 165px; height: 85px; } +.union-head-fill { left: 12px; top: 110px; width: 165px; height: 15px; } +.union-edge-top { left: 12px; top: 109px; width: 166px; } +.union-edge-bottom { left: 12px; top: 201px; width: 166px; } +.union-edge-left { left: 10px; top: 109px; height: 100px; } +.union-edge-right { left: 167px; top: 109px; height: 100px; } +.union-corner-tl { left: 10px; top: 109px; } +.union-corner-tr { left: 167px; top: 109px; } +.union-corner-bl { left: 10px; top: 201px; } +.union-corner-br { left: 167px; top: 201px; } + +/* Each tab's scroll track. Its own top was bound although both are constants; only the thumb's + offset inside it still is. */ +.gi-scroll { position: absolute; } +.gi-scroll > div { position: absolute; } + +/* A list row. Its own top follows the native list box's scroll position; everything else about it + is placed here. A backgrounded element with children paints an unclosed box in this build, so + the backdrop is a childless leaf (engine-findings.md). */ +.gi-rows { position: static; } +.gi-row { position: absolute; width: 148px; height: 13px; } +.gi-row-back { position: absolute; left: 0; top: 0; width: 148px; height: 13px; } +.gi-cell { position: absolute; top: 3px; } + +/* The alliance explanation's own rows: the original advanced its y by 15, 25 or 20 per line. */ +.gi-alliance-note { position: static; } +.gi-alliance-line { position: absolute; left: 25px; } +.gi-alliance-line:nth-child(1) { top: 106px; } +.gi-alliance-line:nth-child(2) { top: 121px; } +.gi-alliance-line:nth-child(3) { top: 136px; } +.gi-alliance-line:nth-child(4) { top: 151px; } +.gi-alliance-line:nth-child(5) { top: 166px; } +.gi-alliance-line:nth-child(6) { top: 191px; } +.gi-alliance-line:nth-child(7) { top: 206px; } +.gi-alliance-line:nth-child(8) { top: 221px; } +.gi-alliance-line:nth-child(9) { top: 241px; } +.gi-alliance-line:nth-child(10) { top: 256px; } +.gi-alliance-line:nth-child(11) { top: 271px; } + +#btn_guild_out { left: 100px; top: 350px; } +#btn_get_position { left: 3px; top: 360px; } +#btn_free_position { left: 64px; top: 360px; } +#btn_get_out { left: 125px; top: 360px; } +#btn_union_create { left: 30px; top: 230px; } +#btn_union_out { left: 100px; top: 230px; } + +.gi-line, .gi-note, .gi-figure, .gi-header, .gi-cell { color: #ffffff; } +/* Render_Text()'s own colours. */ +#gi_name { color: rgb(200, 255, 100); } +#gi_notice_label { color: rgb(255, 185, 1); } +.gi-cell { color: rgb(230, 220, 200); } +.cell-member-server { color: rgb(255, 196, 0); } +.gi-row.selected .gi-cell { color: #000000; } +.notice-fill { background-color: #000000; } +.members-fill, .union-fill { background-color: rgba(21, 21, 21, 150); } +.members-head-fill, .union-head-fill { background-color: rgba(59, 59, 59, 150); } + +/* The announcement list: base.rcss's .scroll-pane, counter-scaled out of #panel's transform so + its net render transform is identity and the text inside stays at the native renderer's own + physical size. The scrollbar therefore keeps .scroll-pane's dp width rather than a + reference-px one, same as every other pane consumer (component-catalog.md). */ +#gi_notice_list { + position: absolute; + left: 15px; + top: 264px; + transform-origin: left top; + /* Native drew the announcement's track at every list length, also when every line fits. */ + overflow: hidden scroll; +} + +/* display: block is explicit, not incidental: a data-for
is inline without it in this + build and every row then lands on the same line. */ +.gi-pane-row { position: relative; display: block; } +.gi-pane-cell { position: absolute; left: 2.740%; top: 0; white-space: nowrap; } + +/* The member list, same .scroll-pane recipe as the announcement: 18 rows of 13 units, which is + the native box's own m_iNumRenderLine times its line step. Cell positions are percentages of + the row's bound width, so they need no binding of their own and hold at every scale. */ +#gi_member_list { + position: absolute; + left: 13px; + top: 123px; + transform-origin: left top; + overflow: hidden scroll; +} + +.gi-member-row { pointer-events: auto; } +.gi-pane-row-back { position: absolute; left: 0; top: 0; width: 100%; height: 100%; } +.gi-member-row.selected .gi-pane-row-back, +.gi-member-row.officer .gi-pane-row-back { background-color: rgb(106, 97, 88); } +.gi-member-row.selected .gi-pane-cell { color: #000000; } + +.cell-member-name { left: 5.369%; } +.cell-member-role { left: 59.060%; transform: translateX(-50%); } +.cell-member-server { right: 12.752%; text-align: right; } + +/* The alliance list: 6 rows of 13 units, the native box's own m_iNumRenderLine times its line + step. Its mark is art rather than text, so the cells are eighths of a bound 8-unit box and + keep scaling with the panel, unlike the glyphs beside them. */ +#gi_union_list { + position: absolute; + left: 15px; + top: 130px; + transform-origin: left top; + overflow: hidden scroll; +} + +.gi-union-row { pointer-events: auto; } +.gi-union-row.selected .gi-pane-row-back { background-color: rgb(106, 97, 88); } +.gi-union-row.selected .gi-pane-cell { color: #000000; } + +.gi-union-row .line-mark { position: absolute; left: 2.721%; top: 0; } +.gi-union-row .line-mark-cell { float: left; width: 12.5%; height: 12.5%; } + +.cell-union-name { left: 10.884%; } +.cell-union-count { right: 3.401%; text-align: right; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#gi_hint_title { width: calc(100% * var(--root-scale)); } +#gi_title { width: calc(100% * var(--root-scale)); } +#gi_name { width: calc(120px * var(--root-scale)); } +#gi_tab_info { width: calc(56px * var(--root-scale)); } +#gi_tab_members { width: calc(56px * var(--root-scale)); } +#gi_tab_union { width: calc(56px * var(--root-scale)); } +#gi_notice_label { width: calc(40px * var(--root-scale)); } +#gi_created { width: calc(40px * var(--root-scale)); } +#gi_score { width: calc(80px * var(--root-scale)); } +#gi_member_count { width: calc(80px * var(--root-scale)); } +#gi_notice_list { width: calc(161px * var(--root-scale)); height: calc(80px * var(--root-scale)); } +.gi-pane-row { width: calc(146px * var(--root-scale)); height: calc(13px * var(--root-scale)); } +.gi-label { width: calc(64px * var(--root-scale)); } +#gi_hdr_name { width: calc(40px * var(--root-scale)); } +#gi_hdr_position { width: calc(40px * var(--root-scale)); } +#gi_hdr_server { width: calc(40px * var(--root-scale)); } +#gi_member_list { width: calc(164px * var(--root-scale)); height: calc(234px * var(--root-scale)); } +.gi-pane-row.gi-member-row { width: calc(149px * var(--root-scale)); height: calc(13px * var(--root-scale)); } +#gi_hdr_union_name { width: calc(40px * var(--root-scale)); } +#gi_hdr_union_members { width: calc(40px * var(--root-scale)); } +#gi_union_list { width: calc(162px * var(--root-scale)); height: calc(78px * var(--root-scale)); } +.gi-pane-row.gi-union-row { width: calc(147px * var(--root-scale)); height: calc(13px * var(--root-scale)); } + +/* The tabs' hit areas (guild_info_tab): the original's columns, 56 wide from x 12, over the top 90. */ +.gi-tab-hit { position: absolute; top: 0; width: 56px; height: 90px; pointer-events: auto; cursor: pointer; } +#gi_tab_hit_0 { left: 12px; } +#gi_tab_hit_1 { left: 68px; } +#gi_tab_hit_2 { left: 124px; } + +/* ---- Classic parts ------------------------------------------------------------------------- */ + +@spritesheet gi-classic-tab-sheet { src: "../../../win_button.tga"; gi-classic-tab: 0px 0px 49px 16px; } +@spritesheet gi-classic-btn-sheet { src: ../../../Classic/s1/text_button.jpg; gi-classic-btn: 0px 0px 56px 24px; } +@spritesheet gi-classic-scroll-sheet +{ + src: "../../../win_scrollbar.jpg"; + gi-classic-scroll-thumb: 0px 1px 11px 1px; + gi-classic-scroll-up: 0px 3px 13px 13px; + gi-classic-scroll-down: 0px 16px 13px 13px; +} + +/* The tabs: each tab's hit area is drawn as a dimmed win_button plate, 54 wide in its 56 column, + and the current tab's marker as the same plate lit and 4 taller, over the dimmed one and under + the label (Season 1's pet window draws its tabs this way). */ +#tab_list { decorator: none; } +.gi-tab-hit { + top: 72px; + width: 54px; + height: 16px; + image-color: rgb(153, 153, 153); + decorator: image(gi-classic-tab fill); +} +#gi_tab_hit_0 { left: 13px; } +#gi_tab_hit_1 { left: 69px; } +#gi_tab_hit_2 { left: 125px; } +#tab_point { top: 68px; width: 54px; height: 20px; z-index: 1; decorator: image(gi-classic-tab fill); } +#tab_point.tab-0 { left: 13px; } +#tab_point.tab-1 { left: 69px; } +#tab_point.tab-2 { left: 125px; } +.gi-tab-label { top: 75px; z-index: 2; color: rgb(230, 220, 200); } + +/* The tables: one line in the classic social windows' colour around each list and the notice, in + place of the Season 6 item-table edges and corners. */ +.t-edge-top, .t-edge-bottom, .t-edge-left, .t-edge-right, .t-corner { decorator: none; } +.members-fill, .union-fill, .notice-fill { border-width: 1px; border-color: rgb(146, 134, 121); } +.members-head-fill, .union-head-fill { border-width: 1px 1px 0 1px; border-color: rgb(146, 134, 121); } +.notice-fill { background-color: rgba(0, 0, 0, 150); } + +/* The notice's head: its label alone, as 0.97 writes its headings (the Season 6 tab art goes). */ +#tab_head { decorator: none; } + +/* 0.97's colours: the title as its title box, the guild's name and notice in its pale green, the + members in pale blue with the server in orange, an officer's row on 0.97's dark blue. */ +#gi_title, #gi_hint_title { color: #dcdcdc; font-weight: bold; } +#gi_name { color: rgb(100, 255, 200); } +#gi_notice_label { color: #ffffff; } +.gi-figure, .gi-header { color: rgb(230, 220, 200); } +.gi-note { color: #e6e6e6; } +#gi_notice_list .gi-pane-cell { color: rgb(100, 255, 200); } +.gi-member-row .gi-pane-cell, .gi-union-row .gi-pane-cell { color: rgb(210, 230, 255); } +.gi-member-row .cell-member-server { color: rgb(255, 196, 0); } +.gi-member-row.officer .gi-pane-row-back { background-color: #282896; } +.gi-member-row.officer .cell-member-name { color: #ffffff; } +.gi-member-row.selected .gi-pane-row-back, +.gi-union-row.selected .gi-pane-row-back { background-color: rgb(106, 97, 88); } +.gi-member-row.selected .gi-pane-cell, +.gi-union-row.selected .gi-pane-cell { color: #000000; } + +/* The buttons: Season 1's text_button (56x24, its labelled buttons' art, as the classic MU Helper's), + centred where legacy's 64x29 buttons were; brighter under the mouse, one unit down while pressed. + The member tab's three sit in the three tab columns, inside the frame (legacy's 64-wide art had + transparent margins; this one has none). */ +.gi-btn, .gi-btn:hover, .gi-btn:active { width: 56px; height: 24px; margin-top: 2px; margin-left: 4px; decorator: image(gi-classic-btn fill); } +.gi-btn:hover { filter: brightness(1.3); } +.gi-btn:active { margin-top: 3px; } +.gi-label { width: calc(56px * var(--root-scale)); } +#btn_get_position { left: 8px; } +#btn_free_position { left: 64px; } +#btn_get_out { left: 120px; } + +/* The lists scroll with the Season 1 client's win_scrollbar (as the classic social windows): 13x13 + arrows at both ends, the track between two 106,97,88 lines, a grey thumb. */ +.scroll-pane scrollbarvertical { width: 13dp; margin: 0; } +.scroll-pane scrollbarvertical slidertrack { decorator: none; box-sizing: border-box; border-left: 1dp rgb(106, 97, 88); border-right: 1dp rgb(106, 97, 88); } +.scroll-pane scrollbarvertical sliderbar { height: auto; min-height: 6dp; margin: 0 1dp; decorator: image(gi-classic-scroll-thumb fill); } +.scroll-pane scrollbarvertical sliderbar:active { filter: none; } +.scroll-pane scrollbarvertical sliderarrowdec, +.scroll-pane scrollbarvertical sliderarrowinc { width: 100%; height: 13dp; pointer-events: auto; } +.scroll-pane scrollbarvertical sliderarrowdec { decorator: image(gi-classic-scroll-up); } +.scroll-pane scrollbarvertical sliderarrowinc { decorator: image(gi-classic-scroll-down); } +.scroll-pane scrollbarvertical sliderarrowdec:active, +.scroll-pane scrollbarvertical sliderarrowinc:active { filter: brightness(0.7); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/guild_make.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/guild_make.rcss new file mode 100644 index 0000000000..4af88c00b4 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/guild_make.rcss @@ -0,0 +1,221 @@ +/* Legacy theme for CGuildMakeWindow, reproducing its Render(): the docked_panel_frame.rcss frame + (linked first; newui_item_back01 top), "Guild" (255, 176, 73) centred at y 15; page 0: the + question white at y 50, Create Guild (newui_btn_empty, 108 x 29) at (41, 100), the exit button; + page 1: "NAME" at (10, 66), the name box (newui_guildmakeeditbox, 108 x 23) at (45, 60) and the + field at (50, 66) (200 x 14, black at alpha 25, text (255, 255, 230) at alpha 210), the gold + rectangle round the mark, RenderGuildColor()'s cells (InventoryBox2 behind a colour inset 1; + the empty colour black with a grey cross), the two hints (230, 230, 230); page 2: the finished + mark 48 x 48 at (72, 74) in its gold rectangle and the name at y 140; Back / Next + (newui_btn_empty_small, 64 x 29) at (15, 379) and (110, 379). Reference px inside #panel. */ + +@spritesheet gm-big-btn-sheet +{ + src: "../../../newui_btn_empty.tga"; + gm-big-up: 0px 0px 108px 29px; + gm-big-over: 0px 29px 108px 29px; + gm-big-down: 0px 58px 108px 29px; +} +@spritesheet gm-small-btn-sheet +{ + src: "../../../newui_btn_empty_small.tga"; + gm-small-up: 0px 0px 64px 29px; + gm-small-over: 0px 29px 64px 29px; + gm-small-down: 0px 58px 64px 29px; +} +@spritesheet gm-name-back-sheet { src: "../../../newui_guildmakeeditbox.tga"; gm-name-back: 0px 0px 108px 23px; } +@spritesheet gm-cell-back-sheet +{ + src: "../../../InventoryBox2.jpg"; + gm-cell-back-13: 0px 0px 13px 14px; + gm-cell-back-18: 0px 0px 18px 19px; + gm-cell-back-23: 0px 0px 23px 25px; +} +@spritesheet gm-gold-h-sheet { src: "../../../Trading_line.jpg"; gm-gold-h: 7px 3px 126px 2px; } +@spritesheet gm-gold-v-sheet { src: "../../../Item_Back01.jpg"; gm-gold-v: 1px 80px 2px 125px; } + +.frame-top { decorator: image(docked-bg-top-b); } +/* The grid and palette leave the pointer to the window's native hit tests. */ +#panel { pointer-events: none; } + +.sharp-text { display: block; position: absolute; white-space: nowrap; pointer-events: none; } +.gm-centred { left: 0; text-align: center; } +#title { top: 15px; color: #ffb049; } +#info { top: 50px; color: #ffffff; } +#result { top: 140px; color: #ffb049; } +#name_label { left: 10px; top: 66px; color: #ffb049; } +.gm-hint { left: 50px; color: #e6e6e6; } + +.gm-btn { display: block; position: absolute; pointer-events: auto; } +.gm-btn-big { left: 41px; top: 100px; width: 108px; height: 29px; decorator: image(gm-big-up); } +.gm-btn-big:hover { decorator: image(gm-big-over); } +.gm-btn-big:active { decorator: image(gm-big-down); } +.gm-btn-small { top: 379px; width: 64px; height: 29px; decorator: image(gm-small-up); } +.gm-btn-small:hover { decorator: image(gm-small-over); } +.gm-btn-small:active { decorator: image(gm-small-down); } +#btn_back { left: 15px; } +#btn_next { left: 110px; } +.gm-label { left: 0; text-align: center; color: #ffffff; } +#btn_exit { pointer-events: auto; } + +#name_back { position: absolute; left: 45px; top: 60px; width: 108px; height: 23px; decorator: image(gm-name-back); } +#name_field { + display: none; + left: 50px; + top: 66px; + padding: 0; + border-width: 0; + border-radius: 0; + background-color: rgba(0, 0, 0, 25); + color: rgba(255, 255, 230, 210); + pointer-events: auto; +} +#name_field.shown { display: block; } + +.gold-rect { position: absolute; pointer-events: none; } +#mark_rect { left: 45px; top: 95px; width: 130px; height: 130px; } +#result_rect { left: 72px; top: 70px; width: 53px; height: 53px; } +.gold-h { position: absolute; left: 0; top: 0; width: 100%; height: 2px; decorator: image(gm-gold-h); } +.gold-h-end { top: 100%; margin-left: 0; width: 100%; padding-right: 1px; } +.gold-v { position: absolute; left: 0; top: 0; width: 2px; height: 100%; decorator: image(gm-gold-v); } +.gold-v-end { left: 100%; } + +.gm-cell { position: absolute; pointer-events: none; } +.gm-cell-13 { width: 15px; height: 15px; decorator: image(gm-cell-back-13); } +.gm-cell-18 { width: 20px; height: 20px; decorator: image(gm-cell-back-18); } +.gm-cell-23 { width: 25px; height: 25px; decorator: image(gm-cell-back-23); } +.gm-fill { position: absolute; left: 1px; top: 1px; } +.gm-cell-13 .gm-fill { width: 13px; height: 13px; } +.gm-cell-18 .gm-fill { width: 18px; height: 18px; } +.gm-cell-23 .gm-fill { width: 23px; height: 23px; } +.gm-cross { position: absolute; height: 2px; background-color: #808080; transform-origin: center; } +.gm-cell-13 .gm-cross { left: -2.69px; top: 5.5px; width: 18.38px; } +.gm-cell-18 .gm-cross { left: -3.73px; top: 8px; width: 25.46px; } +.gm-cell-23 .gm-cross { left: -4.76px; top: 10.5px; width: 32.53px; } +.gm-cross-a { transform: rotate(45deg); } +.gm-cross-b { transform: rotate(-45deg); } + +#result_mark { position: absolute; left: 72px; top: 74px; width: 48px; height: 48px; pointer-events: none; } +.mark-cell { float: left; width: 6px; height: 6px; } + +/* RenderEditGuildMark()'s own layout: the 8 x 8 mark grid of 15-unit cells from (50, 100), the + palette's two rows of 20-unit cells from (15, 260), and the selected colour's swatch. */ +.gm-grid, .gm-palette { position: static; } +#selected_swatch { left: 15px; top: 230px; } +.gm-hint-1 { top: 230px; } +.gm-hint-2 { top: 245px; } +.gm-grid .gm-cell:nth-child(1) { left: 50px; top: 100px; } +.gm-grid .gm-cell:nth-child(2) { left: 65px; top: 100px; } +.gm-grid .gm-cell:nth-child(3) { left: 80px; top: 100px; } +.gm-grid .gm-cell:nth-child(4) { left: 95px; top: 100px; } +.gm-grid .gm-cell:nth-child(5) { left: 110px; top: 100px; } +.gm-grid .gm-cell:nth-child(6) { left: 125px; top: 100px; } +.gm-grid .gm-cell:nth-child(7) { left: 140px; top: 100px; } +.gm-grid .gm-cell:nth-child(8) { left: 155px; top: 100px; } +.gm-grid .gm-cell:nth-child(9) { left: 50px; top: 115px; } +.gm-grid .gm-cell:nth-child(10) { left: 65px; top: 115px; } +.gm-grid .gm-cell:nth-child(11) { left: 80px; top: 115px; } +.gm-grid .gm-cell:nth-child(12) { left: 95px; top: 115px; } +.gm-grid .gm-cell:nth-child(13) { left: 110px; top: 115px; } +.gm-grid .gm-cell:nth-child(14) { left: 125px; top: 115px; } +.gm-grid .gm-cell:nth-child(15) { left: 140px; top: 115px; } +.gm-grid .gm-cell:nth-child(16) { left: 155px; top: 115px; } +.gm-grid .gm-cell:nth-child(17) { left: 50px; top: 130px; } +.gm-grid .gm-cell:nth-child(18) { left: 65px; top: 130px; } +.gm-grid .gm-cell:nth-child(19) { left: 80px; top: 130px; } +.gm-grid .gm-cell:nth-child(20) { left: 95px; top: 130px; } +.gm-grid .gm-cell:nth-child(21) { left: 110px; top: 130px; } +.gm-grid .gm-cell:nth-child(22) { left: 125px; top: 130px; } +.gm-grid .gm-cell:nth-child(23) { left: 140px; top: 130px; } +.gm-grid .gm-cell:nth-child(24) { left: 155px; top: 130px; } +.gm-grid .gm-cell:nth-child(25) { left: 50px; top: 145px; } +.gm-grid .gm-cell:nth-child(26) { left: 65px; top: 145px; } +.gm-grid .gm-cell:nth-child(27) { left: 80px; top: 145px; } +.gm-grid .gm-cell:nth-child(28) { left: 95px; top: 145px; } +.gm-grid .gm-cell:nth-child(29) { left: 110px; top: 145px; } +.gm-grid .gm-cell:nth-child(30) { left: 125px; top: 145px; } +.gm-grid .gm-cell:nth-child(31) { left: 140px; top: 145px; } +.gm-grid .gm-cell:nth-child(32) { left: 155px; top: 145px; } +.gm-grid .gm-cell:nth-child(33) { left: 50px; top: 160px; } +.gm-grid .gm-cell:nth-child(34) { left: 65px; top: 160px; } +.gm-grid .gm-cell:nth-child(35) { left: 80px; top: 160px; } +.gm-grid .gm-cell:nth-child(36) { left: 95px; top: 160px; } +.gm-grid .gm-cell:nth-child(37) { left: 110px; top: 160px; } +.gm-grid .gm-cell:nth-child(38) { left: 125px; top: 160px; } +.gm-grid .gm-cell:nth-child(39) { left: 140px; top: 160px; } +.gm-grid .gm-cell:nth-child(40) { left: 155px; top: 160px; } +.gm-grid .gm-cell:nth-child(41) { left: 50px; top: 175px; } +.gm-grid .gm-cell:nth-child(42) { left: 65px; top: 175px; } +.gm-grid .gm-cell:nth-child(43) { left: 80px; top: 175px; } +.gm-grid .gm-cell:nth-child(44) { left: 95px; top: 175px; } +.gm-grid .gm-cell:nth-child(45) { left: 110px; top: 175px; } +.gm-grid .gm-cell:nth-child(46) { left: 125px; top: 175px; } +.gm-grid .gm-cell:nth-child(47) { left: 140px; top: 175px; } +.gm-grid .gm-cell:nth-child(48) { left: 155px; top: 175px; } +.gm-grid .gm-cell:nth-child(49) { left: 50px; top: 190px; } +.gm-grid .gm-cell:nth-child(50) { left: 65px; top: 190px; } +.gm-grid .gm-cell:nth-child(51) { left: 80px; top: 190px; } +.gm-grid .gm-cell:nth-child(52) { left: 95px; top: 190px; } +.gm-grid .gm-cell:nth-child(53) { left: 110px; top: 190px; } +.gm-grid .gm-cell:nth-child(54) { left: 125px; top: 190px; } +.gm-grid .gm-cell:nth-child(55) { left: 140px; top: 190px; } +.gm-grid .gm-cell:nth-child(56) { left: 155px; top: 190px; } +.gm-grid .gm-cell:nth-child(57) { left: 50px; top: 205px; } +.gm-grid .gm-cell:nth-child(58) { left: 65px; top: 205px; } +.gm-grid .gm-cell:nth-child(59) { left: 80px; top: 205px; } +.gm-grid .gm-cell:nth-child(60) { left: 95px; top: 205px; } +.gm-grid .gm-cell:nth-child(61) { left: 110px; top: 205px; } +.gm-grid .gm-cell:nth-child(62) { left: 125px; top: 205px; } +.gm-grid .gm-cell:nth-child(63) { left: 140px; top: 205px; } +.gm-grid .gm-cell:nth-child(64) { left: 155px; top: 205px; } +.gm-palette .gm-cell:nth-child(1) { left: 15px; top: 260px; } +.gm-palette .gm-cell:nth-child(2) { left: 35px; top: 260px; } +.gm-palette .gm-cell:nth-child(3) { left: 55px; top: 260px; } +.gm-palette .gm-cell:nth-child(4) { left: 75px; top: 260px; } +.gm-palette .gm-cell:nth-child(5) { left: 95px; top: 260px; } +.gm-palette .gm-cell:nth-child(6) { left: 115px; top: 260px; } +.gm-palette .gm-cell:nth-child(7) { left: 135px; top: 260px; } +.gm-palette .gm-cell:nth-child(8) { left: 155px; top: 260px; } +.gm-palette .gm-cell:nth-child(9) { left: 15px; top: 280px; } +.gm-palette .gm-cell:nth-child(10) { left: 35px; top: 280px; } +.gm-palette .gm-cell:nth-child(11) { left: 55px; top: 280px; } +.gm-palette .gm-cell:nth-child(12) { left: 75px; top: 280px; } +.gm-palette .gm-cell:nth-child(13) { left: 95px; top: 280px; } +.gm-palette .gm-cell:nth-child(14) { left: 115px; top: 280px; } +.gm-palette .gm-cell:nth-child(15) { left: 135px; top: 280px; } +.gm-palette .gm-cell:nth-child(16) { left: 155px; top: 280px; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#title { width: calc(100% * var(--root-scale)); } +#info { width: calc(100% * var(--root-scale)); } +.gm-label { width: calc(64px * var(--root-scale)); } +#result { width: calc(100% * var(--root-scale)); } +#name_field { width: calc(200px * var(--root-scale)); height: calc(14px * var(--root-scale)); line-height: calc(14px * var(--root-scale)); } + +/* The mark grid's and the palette's cells take the pointer (guild_mark_paint, guild_mark_color). */ +.gm-grid .gm-cell, .gm-palette .gm-cell { pointer-events: auto; cursor: pointer; } + +/* ===== Classic (0.97) ===================================================== + 0.97's guild creation window (004f0480 and the buttons in 004f5820): "Guild" in its box at the top; page 0 "Do you wish + to be the guild master?" at (20, 50); page 1 "Name" at (17, 62) beside the Item_Money bar at + (55, 60), the 8x8 mark grid at (50, 100), the colour at (15, 230), the hints at (50, 230 / 245) + and the palette from (15, 260) -- already legacy's places; OK (ok.jpg, ok2 under the mouse) at + (20, 350) and Cancel (cancel.jpg) at (100, 350), 70x21. MuMain's Create Guild (page 0) and Next + take the OK plate, Back the Cancel plate; their art is lettered, so the labels are hidden. */ +@spritesheet gm-classic-ok-sheet { src: ../../../Classic/Ok.jpg; gm-classic-ok: 0px 0px 70px 21px; } +@spritesheet gm-classic-ok2-sheet { src: ../../../Classic/Ok2.jpg; gm-classic-ok-hover: 0px 0px 70px 21px; } +@spritesheet gm-classic-cancel-sheet { src: ../../../Classic/Cancel.jpg; gm-classic-cancel: 0px 0px 70px 21px; } +@spritesheet gm-classic-cancel2-sheet { src: ../../../Classic/Cancel2.jpg; gm-classic-cancel-hover: 0px 0px 70px 21px; } +@spritesheet gm-classic-money-sheet { src: ../../../Classic/Item_money.jpg; gm-classic-money: 0px 0px 113px 18px; } + +#title { left: 35px; top: 12px; width: calc(120px * var(--root-scale)); color: #dcdcdc; font-weight: bold; } +#info { left: 20px; top: 50px; text-align: left; color: #e6e6e6; } +#name_label { left: 17px; top: 62px; color: #e6e6e6; } +#name_back { left: 55px; top: 60px; width: 113px; height: 18px; decorator: image(gm-classic-money); } +#name_field { left: 60px; top: 62px; width: calc(100px * var(--root-scale)); background-color: transparent; } + +.gm-btn-big, .gm-btn-small { width: 70px; height: 21px; } +#btn_make, #btn_next { left: 20px; top: 350px; decorator: image(gm-classic-ok); } +#btn_make:hover, #btn_next:hover, #btn_make:active, #btn_next:active { decorator: image(gm-classic-ok-hover); } +#btn_back { left: 100px; top: 350px; decorator: image(gm-classic-cancel); } +#btn_back:hover, #btn_back:active { decorator: image(gm-classic-cancel-hover); } +.gm-btn .gm-label { display: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/hud_status.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/hud_status.rcss new file mode 100644 index 0000000000..3ae8fc80be --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/hud_status.rcss @@ -0,0 +1,35 @@ +/* Classic theme for the HUD status texts. The 0.97 client's RenderTimes() (004bf090) + draws "Macro Time" and its bar as legacy does (y 392 / 404, centred on the free area), but the + event's entry countdown at (10, 372), left-aligned, in the same (128, 128, 255) on a black 50% box + (legacy centres it at 410). The crown switch lines (Castle Siege, no 0.97 counterpart) stay + legacy's. Legacy's rules first, then the classic ones. */ + +/* Legacy theme for the HUD status texts (see hud_status.rml), reproducing the original's native + draws: RenderSwichState()'s crown switch lines centred at 480 - 85 and 15 below it in white; + RenderTimes()'s "Macro Time" at 480 - 48 - 40 over RenderBar()'s 50 x 2 bar (frame 54 x 6, its + half-black shadow one pixel down and right), centred on the uncovered world; CSBaseMatch::RenderTime()'s + countdown centred at 480 - 70 in (128, 128, 255) on a half-black box. Reference px on the HUD + board. */ + +#screen { + pointer-events: none; + font-family: "token(font-body)"; +} + +.status-line { position: absolute; left: 0; width: 640px; height: 0; } +.status-line .sharp-text { position: absolute; top: 0; white-space: nowrap; color: #ffffff; } +#switch_first { top: 395px; } +#switch_second { top: 410px; } +#countdown { top: 410px; } +.countdown-text { color: rgb(128, 128, 255); background-color: rgba(0, 0, 0, 128); } + +#macro { position: absolute; margin-left: -25px; top: 392px; width: 55px; height: 19px; } +.macro-label { position: absolute; left: 0; top: 0; white-space: nowrap; color: #ffffff; } +.macro-shadow { position: absolute; left: 1px; top: 13px; width: 54px; height: 6px; background-color: rgba(0, 0, 0, 128); } +.macro-bar { position: absolute; left: 0; top: 12px; width: 54px; height: 6px; background-color: rgb(0, 51, 51); } +.macro-track { position: absolute; left: 2px; top: 2px; width: 50px; height: 2px; background-color: rgb(0, 50, 50); } +.macro-fill { position: absolute; left: 0; top: 0; height: 2px; background-color: rgb(0, 200, 50); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +#countdown { top: 372px; } +#countdown .sharp-text { left: 10px; width: auto; margin-left: 0; text-align: left; transform-origin: left top; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/igs_common.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/igs_common.rcss new file mode 100644 index 0000000000..8082bc7437 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/igs_common.rcss @@ -0,0 +1,34 @@ +/* Classic theme for what the cash shop's documents share (legacy's, below): the button is the + Season 2 client's Buy (Classic/s2 buy0, buy1 under the mouse, buy2 pressed; 72 x 30, which the + S6 Ingame_Bt03 resamples), at the S6 button's size. */ + +/* What the cash shop's documents share (in_game_shop.rml and its igs_* dialogs): the + Ingame_Bt03 button with its label, the dimmed screen behind a dialog, and the counter-scaled + text layer. */ + +.sharp-text { display: block; position: absolute; white-space: nowrap; text-align: left; pointer-events: none; } + +/* CMessageBoxBase::RenderMsgBackColor(): black at half alpha over the whole screen. It also takes + the clicks the shop under the dialog would otherwise get. */ +.igs-dim { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 128); pointer-events: auto; } + +/* Up, over and pressed frames; the label drops a unit while pressed. A disabled button is greyed + and its label dim (CMessageBoxButton::Render()). */ +@spritesheet igs-btn-sheet { src: "../../../InGameShop/Ingame_Bt03.tga"; igs-btn-up: 0px 0px 52px 26px; igs-btn-over: 0px 26px 52px 26px; igs-btn-down: 0px 52px 52px 26px; } +.igs-btn { position: absolute; width: 52px; height: 26px; decorator: image(igs-btn-up); pointer-events: auto; } +.igs-btn:hover { decorator: image(igs-btn-over); } +.igs-btn:active { decorator: image(igs-btn-down); } +.igs-btn-label { color: #ffffff; margin-top: -1px; } +/* A centred label sits at margin-left -1000px (base.rcss's .sharp-centre); a unit right is -999px. */ +.igs-btn:active .igs-btn-label { margin-left: -999px; margin-top: 0; } +.igs-btn.disabled, .igs-btn.disabled:hover { decorator: image(igs-btn-up); image-color: rgba(204, 204, 204, 230); pointer-events: none; } +.igs-btn.disabled .igs-btn-label { color: #808080; } + +/* --- Classic: the Season 2 button -------------------------------------------------------------- */ +@spritesheet igs-classic-buy0-sheet { src: ../../../Classic/s2/buy0.tga; igs-classic-btn-up: 0px 0px 72px 30px; } +@spritesheet igs-classic-buy1-sheet { src: ../../../Classic/s2/buy1.tga; igs-classic-btn-over: 0px 0px 72px 30px; } +@spritesheet igs-classic-buy2-sheet { src: ../../../Classic/s2/buy2.tga; igs-classic-btn-down: 0px 0px 72px 30px; } +.igs-btn { decorator: image(igs-classic-btn-up fill); } +.igs-btn:hover { decorator: image(igs-classic-btn-over fill); } +.igs-btn:active { decorator: image(igs-classic-btn-down fill); } +.igs-btn.disabled, .igs-btn.disabled:hover { decorator: image(igs-classic-btn-up fill); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/in_game_shop.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/in_game_shop.rcss new file mode 100644 index 0000000000..90cb92ea96 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/in_game_shop.rcss @@ -0,0 +1,221 @@ +/* Classic theme for the cash shop (CInGameShop). 0.97 has none; the Season 2 client has, and the + S6 shop is its layout at 80% (800x600 -> 640x480: the right column 204 -> 164, the shelf 596 -> + 476), its backdrop (Ingame_shopback) the Season 2 back panels and ItemBackPanel boxes flattened at + that scale, and most of its pieces the Season 2 ones resampled. So the classic shop keeps the + layout and backdrop and puts back the Season 2 originals (Classic/s2, from the Season 2 client's + Interface\LeftBt, ShopDisplay and RightBt): the zone tabs (TopMenuTabBT0, TopMenuTabBT1 + selected), the category buttons (LeftMenuBT0, LeftMenuBT1 selected), the categories' ornament + (Deco4), the page arrows (page0-2 left, page3-5 right: up, over, down; S6 drew hearts) and Close + (Return0-2 for up, over, down; S6 drew its own exit). The Buy / Use button is igs_common.rcss's. + The gift, charge and refresh icons have no Season 2 counterpart and stay. Legacy's rules first, + then the classic ones. */ + +/* The cash shop as CInGameShop drew it: Ingame_shopback.jpg, the zone tabs, category buttons and + their decoration, the 3x3 package boxes, the player's balances and buttons, the banner, and the + storage / gift list. Reference px under the window's root transform; text counter-scales out of + it (.sharp-text) so it rasterises at the native renderer's size. */ + +#panel { + position: absolute; + transform-origin: left top; + width: 640px; + height: 429px; + font-family: "token(font-body)"; + pointer-events: none; +} + +@spritesheet igs-bg-back-sheet { src: "../../../InGameShop/Ingame_shopback.jpg"; igs-bg-back: 0px 0px 640px 429px; } +@spritesheet igs-zone-sheet { src: "../../../InGameShop/Ingame_Tab_Up.tga"; igs-zone-up: 0px 0px 76px 23px; igs-zone-down: 0px 23px 76px 23px; } +@spritesheet igs-category-sheet { src: "../../../InGameShop/Ingame_Bt01.tga"; igs-category-up: 0px 0px 73px 27px; igs-category-down: 0px 54px 73px 27px; } +@spritesheet igs-deco-middle-sheet { src: "../../../InGameShop/Ingame_Deco_Center.tga"; igs-deco-middle: 0px 0px 4px 8px; } +@spritesheet igs-deco-down-sheet { src: "../../../InGameShop/Ingame_Deco_Dn.tga"; igs-deco-down: 0px 0px 47px 100px; } +@spritesheet igs-tab-left-sheet { src: "../../../InGameShop/ingame_Tab01.tga"; igs-tab-left: 0px 0px 49px 20px; } +@spritesheet igs-tab-right-sheet { src: "../../../InGameShop/ingame_Tab02.tga"; igs-tab-right: 0px 0px 49px 20px; } +@spritesheet igs-logo-sheet { src: "../../../InGameShop/Ingame_Itembox_logo.tga"; igs-logo: 0px 0px 57px 57px; } +@spritesheet igs-gift-sheet { src: "../../../InGameShop/Ingame_Bt_Gift.tga"; igs-gift-up: 0px 0px 25px 25px; igs-gift-over: 0px 25px 25px 25px; igs-gift-down: 0px 50px 25px 25px; } +@spritesheet igs-charge-sheet { src: "../../../InGameShop/Ingame_Bt_Cash.tga"; igs-charge-up: 0px 0px 25px 25px; igs-charge-over: 0px 25px 25px 25px; igs-charge-down: 0px 50px 25px 25px; } +@spritesheet igs-refresh-sheet { src: "../../../InGameShop/Ingame_Bt_Reset.tga"; igs-refresh-up: 0px 0px 25px 25px; igs-refresh-over: 0px 25px 25px 25px; igs-refresh-down: 0px 50px 25px 25px; } +@spritesheet igs-page-left-sheet { src: "../../../InGameShop/ingame_Bt_page_L.tga"; igs-page-left-up: 0px 0px 20px 23px; igs-page-left-over: 0px 23px 20px 23px; igs-page-left-down: 0px 46px 20px 23px; } +@spritesheet igs-page-right-sheet { src: "../../../InGameShop/ingame_Bt_page_R.tga"; igs-page-right-up: 0px 0px 20px 23px; igs-page-right-over: 0px 23px 20px 23px; igs-page-right-down: 0px 46px 20px 23px; } +@spritesheet igs-storage-page-sheet { src: "../../../InGameShop/IGS_Storage_Page.tga"; igs-storage-page: 0px 0px 80px 30px; } +@spritesheet igs-storage-left-sheet { src: "../../../InGameShop/IGS_Storage_Page_Left.tga"; igs-storage-left-up: 0px 0px 20px 22px; igs-storage-left-over: 0px 22px 20px 22px; igs-storage-left-down: 0px 44px 20px 22px; } +@spritesheet igs-storage-right-sheet { src: "../../../InGameShop/IGS_Storage_Page_Right.tga"; igs-storage-right-up: 0px 0px 20px 22px; igs-storage-right-over: 0px 22px 20px 22px; igs-storage-right-down: 0px 44px 20px 22px; } +@spritesheet igs-exit-sheet { src: "../../../newui_exit_00.tga"; igs-exit-up: 0px 0px 36px 29px; igs-exit-down: 0px 29px 36px 29px; } + +.bg-back { position: absolute; left: 0; top: 0; width: 640px; height: 429px; decorator: image(igs-bg-back); } +#igs_items { position: absolute; left: 0; top: 0; width: 640px; height: 429px; pointer-events: none; } + +/* Radio labels: grey, white when selected (CRadioButton::ChangeFrame()). */ +.igs-zone-label, .igs-category-label, .igs-storage-tab-label { color: #b5b5b5; } +.selected .igs-zone-label, .selected .igs-category-label, .selected .igs-storage-tab-label { color: #ffffff; } +.igs-zone-label, .igs-category-label { font-weight: bold; } + +/* The zones: 76 x 23 tabs a unit apart from (95, 0). */ +#igs_zones { position: absolute; left: 95px; top: 0; display: flex; pointer-events: none; } +.igs-zone { position: relative; flex: 0 0 76px; width: 76px; height: 23px; margin-right: 1px; decorator: image(igs-zone-up); pointer-events: auto; } +.igs-zone.selected { decorator: image(igs-zone-down); } + +/* The categories: 73 x 27 buttons 6 apart from (13, 31), the 4 x 8 link under each but the last + at its centre, and the 47 x 100 ornament from the panel's left edge 10 above the last's top. */ +#igs_categories { position: absolute; left: 13px; top: 31px; width: 73px; pointer-events: none; } +.igs-category { position: relative; display: block; width: 73px; height: 27px; margin-bottom: 6px; decorator: image(igs-category-up); pointer-events: auto; } +.igs-category.selected { decorator: image(igs-category-down); } +.igs-category.selected .igs-category-label { margin-left: -999px; margin-top: 1px; } +.igs-category-deco { position: absolute; left: 34px; top: 26px; width: 4px; height: 8px; decorator: image(igs-deco-middle); } +.igs-category.last .igs-category-deco { display: none; } +.igs-categories-end { position: relative; display: block; left: -13px; margin-top: -43px; width: 47px; height: 100px; decorator: image(igs-deco-down); } + +/* The packages: 122 x 121 cells from the panel's corner; in each the name and price across 104 from + (105, 40) and (105, 113), the Buy button at (162, 126), or the empty box's logo at (128, 52). */ +#igs_packages { position: absolute; left: 0; top: 0; width: 366px; display: flex; flex-wrap: wrap; pointer-events: none; } +.igs-package { position: relative; flex: 0 0 122px; width: 122px; height: 121px; } +/* Where C++ draws the package's live 3D item (the original's 108x58 at 102,51 of each box). */ +.igs-package-item { position: absolute; left: 102px; top: 51px; width: 108px; height: 58px; pointer-events: none; } +/* The box itself is the backdrop's art. */ +.igs-package-card { display: none; } +.igs-package-logo { display: none; position: absolute; left: 128px; top: 52px; width: 57px; height: 57px; decorator: image(igs-logo); } +.igs-package.empty .igs-package-logo { display: block; } +.igs-package-name, .igs-package-price { position: absolute; left: 105px; width: 104px; height: 1px; } +.igs-package-name { top: 40px; color: #ffffff; } +.igs-package-price { top: 113px; color: #ffeea1; } +.igs-buy { left: 162px; top: 126px; } + +.igs-page-btn { position: absolute; top: 397px; width: 20px; height: 23px; pointer-events: auto; } +#igs_page_prev { left: 231px; decorator: image(igs-page-left-up); } +#igs_page_prev:hover { decorator: image(igs-page-left-over); } +#igs_page_prev:active { decorator: image(igs-page-left-down); } +#igs_page_next { left: 307px; decorator: image(igs-page-right-up); } +#igs_page_next:hover { decorator: image(igs-page-right-over); } +#igs_page_next:active { decorator: image(igs-page-right-down); } + +/* "current / total" in bold: the current page right-aligned to the slash, the total after it. */ +.igs-page-numbers { position: absolute; left: 0; width: 640px; height: 1px; color: #ffffff; font-weight: bold; } +.igs-page-numbers .sharp-right { transform-origin: right top; } +#igs_page { top: 404px; } +#igs_page .igs-page-current { right: 369px; } +#igs_page .igs-page-slash { left: 277px; } +#igs_page .igs-page-total { left: 287px; } +#igs_storage_page { top: 376px; } +#igs_storage_page .igs-page-current { right: 90px; } +#igs_storage_page .igs-page-slash { left: 556px; } +#igs_storage_page .igs-page-total { left: 566px; } + +/* The player: the name in bold centred over 122 from (498, 23), then three balance rows from + (498, 50) 15 apart, each value right-aligned to 622. */ +#igs_character { position: absolute; left: 498px; top: 23px; width: 122px; height: 1px; color: #ffffff; font-weight: bold; } +#igs_wallet { position: absolute; left: 0; top: 50px; width: 640px; } +.igs-wallet-row { position: relative; display: block; height: 15px; color: #ffeea1; } +.igs-wallet-label { left: 498px; } +.igs-wallet-value { right: 18px; transform-origin: right top; } + +.igs-icon-btn { position: absolute; top: 94px; width: 25px; height: 25px; pointer-events: auto; } +#igs_gift { left: 519px; decorator: image(igs-gift-up); } +#igs_gift:hover { decorator: image(igs-gift-over); } +#igs_gift:active { decorator: image(igs-gift-down); } +#igs_charge { left: 546px; decorator: image(igs-charge-up); } +#igs_charge:hover { decorator: image(igs-charge-over); } +#igs_charge:active { decorator: image(igs-charge-down); } +#igs_refresh { left: 573px; decorator: image(igs-refresh-up); } +#igs_refresh:hover { decorator: image(igs-refresh-over); } +#igs_refresh:active { decorator: image(igs-refresh-down); } + +#igs_banner { position: absolute; left: 482px; top: 133px; width: 153px; height: 63px; pointer-events: none; } +#igs_banner.linked { pointer-events: auto; } + +/* The storage and gift tabs: 49 x 20 from (486, 208), overlapping by 2; only the selected one has + art (Ingame_Tab01 for the storage, Ingame_Tab02 for the gift box). */ +#igs_storage_tabs { position: absolute; left: 486px; top: 208px; display: flex; pointer-events: none; } +.igs-storage-tab { position: relative; flex: 0 0 49px; width: 49px; height: 20px; margin-right: -2px; pointer-events: auto; } +.igs-storage-tab.selected { decorator: image(igs-tab-left); } +.igs-storage-tab.selected.gift { decorator: image(igs-tab-right); } + +.igs-storage-header { position: absolute; top: 233px; height: 1px; color: #ffffff; font-weight: bold; } +#igs_storage_header_name { left: 492px; width: 96px; } +#igs_storage_header_period { left: 592px; width: 34px; } + +/* Native put the box at (490, 360) in left-down coordinates, 146 x 115 -- so its top edge is + 360 - 115. The height here is the 9 rows it actually drew. */ +#igs_storage_list { + position: absolute; + left: 490px; + top: 245px; + transform-origin: left top; + /* Native drew the track at every list length. */ + overflow: hidden scroll; + pointer-events: auto; +} +/* display: block is explicit: a data-for
is inline without it in this build and every row + lands on the same line. */ +.igs-row { position: relative; display: block; pointer-events: auto; } +.igs-row-back { position: absolute; left: 0; top: 0; width: 100%; height: 100%; } +.igs-row.selected .igs-row-back { background-color: rgb(106, 97, 88); } +.igs-cell { position: absolute; top: 0; white-space: nowrap; } +/* CUIInGameShopListBox::RenderDataLine(): the name in 98 units from the row's left, the period + right-aligned at +102 across 33. As fractions of the row's own bound width they need no + binding and hold at every scale. */ +.igs-cell-name { left: 0; width: 74.809%; } +.igs-cell-period { right: 0; width: 25.191%; text-align: right; } + +#igs_storage_page_back { position: absolute; left: 518px; top: 366px; width: 80px; height: 30px; decorator: image(igs-storage-page); } +.igs-storage-page-btn { position: absolute; top: 369px; width: 20px; height: 22px; pointer-events: auto; } +#igs_storage_prev { left: 500px; decorator: image(igs-storage-left-up); } +#igs_storage_prev:hover { decorator: image(igs-storage-left-over); } +#igs_storage_prev:active { decorator: image(igs-storage-left-down); } +#igs_storage_next { left: 596px; decorator: image(igs-storage-right-up); } +#igs_storage_next:hover { decorator: image(igs-storage-right-over); } +#igs_storage_next:active { decorator: image(igs-storage-right-down); } +#igs_use { left: 572px; top: 396px; } + +/* newui_exit_00: up, and the pressed frame while held. */ +#igs_close { position: absolute; left: 484px; top: 392px; width: 36px; height: 29px; decorator: image(igs-exit-up); pointer-events: auto; } +#igs_close:active { decorator: image(igs-exit-down); } + +#igs_versions { position: absolute; left: 12px; top: 396px; color: rgb(210, 180, 230); } +#igs_versions .igs-version-banner { top: 12px; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#igs_storage_list { width: calc(146px * var(--root-scale)); height: calc(117px * var(--root-scale)); } +.igs-row { width: calc(131px * var(--root-scale)); height: calc(13px * var(--root-scale)); } + +/* --- Classic: the Season 2 pieces ------------------------------------------------------------- */ +@spritesheet igs-classic-tab0-sheet { src: ../../../Classic/s2/topmenutabbt0.tga; igs-classic-tab-up: 0px 0px 86px 33px; } +@spritesheet igs-classic-tab1-sheet { src: ../../../Classic/s2/topmenutabbt1.tga; igs-classic-tab-down: 0px 0px 86px 33px; } +@spritesheet igs-classic-cat0-sheet { src: ../../../Classic/s2/leftmenubt0.tga; igs-classic-cat-up: 0px 0px 88px 30px; } +@spritesheet igs-classic-cat1-sheet { src: ../../../Classic/s2/leftmenubt1.tga; igs-classic-cat-down: 0px 0px 88px 30px; } +@spritesheet igs-classic-deco-sheet { src: ../../../Classic/s2/deco4.tga; igs-classic-deco: 0px 0px 58px 125px; } +@spritesheet igs-classic-pl0-sheet { src: ../../../Classic/s2/page0.tga; igs-classic-left-up: 0px 0px 23px 23px; } +@spritesheet igs-classic-pl1-sheet { src: ../../../Classic/s2/page1.tga; igs-classic-left-over: 0px 0px 23px 23px; } +@spritesheet igs-classic-pl2-sheet { src: ../../../Classic/s2/page2.tga; igs-classic-left-down: 0px 0px 23px 23px; } +@spritesheet igs-classic-pr0-sheet { src: ../../../Classic/s2/page3.tga; igs-classic-right-up: 0px 0px 23px 23px; } +@spritesheet igs-classic-pr1-sheet { src: ../../../Classic/s2/page4.tga; igs-classic-right-over: 0px 0px 23px 23px; } +@spritesheet igs-classic-pr2-sheet { src: ../../../Classic/s2/page5.tga; igs-classic-right-down: 0px 0px 23px 23px; } +@spritesheet igs-classic-ret0-sheet { src: ../../../Classic/s2/return0.tga; igs-classic-return-up: 0px 0px 34px 30px; } +@spritesheet igs-classic-ret1-sheet { src: ../../../Classic/s2/return1.tga; igs-classic-return-over: 0px 0px 34px 30px; } +@spritesheet igs-classic-ret2-sheet { src: ../../../Classic/s2/return2.tga; igs-classic-return-down: 0px 0px 34px 30px; } + +.igs-zone { decorator: image(igs-classic-tab-up fill); } +.igs-zone.selected { decorator: image(igs-classic-tab-down fill); } +.igs-category { decorator: image(igs-classic-cat-up fill); } +.igs-category.selected { decorator: image(igs-classic-cat-down fill); } +.igs-categories-end { decorator: image(igs-classic-deco fill); } + +/* The arrows at the Season 2 size (23 x 23), centred on the S6 places. */ +.igs-page-btn { top: 397px; width: 23px; height: 23px; } +#igs_page_prev { left: 229px; decorator: image(igs-classic-left-up); } +#igs_page_prev:hover { decorator: image(igs-classic-left-over); } +#igs_page_prev:active { decorator: image(igs-classic-left-down); } +#igs_page_next { left: 305px; decorator: image(igs-classic-right-up); } +#igs_page_next:hover { decorator: image(igs-classic-right-over); } +#igs_page_next:active { decorator: image(igs-classic-right-down); } +.igs-storage-page-btn { top: 368px; width: 23px; height: 23px; } +#igs_storage_prev { left: 498px; decorator: image(igs-classic-left-up); } +#igs_storage_prev:hover { decorator: image(igs-classic-left-over); } +#igs_storage_prev:active { decorator: image(igs-classic-left-down); } +#igs_storage_next { left: 594px; decorator: image(igs-classic-right-up); } +#igs_storage_next:hover { decorator: image(igs-classic-right-over); } +#igs_storage_next:active { decorator: image(igs-classic-right-down); } + +/* Close: Return at its own size, on the S6 exit's place. */ +#igs_close { left: 485px; top: 392px; width: 34px; height: 30px; decorator: image(igs-classic-return-up); } +#igs_close:hover { decorator: image(igs-classic-return-over); } +#igs_close:active { decorator: image(igs-classic-return-down); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/inventory_extension.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/inventory_extension.rcss new file mode 100644 index 0000000000..766000c6d6 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/inventory_extension.rcss @@ -0,0 +1,140 @@ +/* Classic theme for the extended inventory. 0.97 has none; it takes the 0.97 inventory's parts: the + inventory frame (Item_Back01 over Item_Back02), the white bold title, 0.97's Close at (20, 395), + and for a locked page a dark box in the window line colour with 0.97's padlock (Lock_02) in + place of S6's table and numbered lock. Legacy's layout and comments below. */ + +/* Legacy theme for CInventoryExtension's chrome (frame/title/exit button). The workspace places + #panel (its slot's left/top/scale), so coordinates below are plain reference px, not dp. */ + +#panel { + position: absolute; + transform-origin: left top; + width: 190px; + height: 429px; + font-family: "token(font-body)"; +} + +#title { + position: absolute; + left: 0; + top: 12px; + width: calc(100% * var(--root-scale)); + text-align: center; + color: token(text-primary); + font-weight: bold; + font-size: 1em; +} + +@spritesheet ext-btn-exit-sheet { src: "../../../newui_exit_00.tga"; ext-btn-exit: 0px 0px 36px 29px; } +.ext-btn { + position: absolute; + left: 13px; + top: 391px; + width: 36px; + height: 29px; + cursor: pointer; + pointer-events: auto; + decorator: image(ext-btn-exit); +} +.ext-btn:hover { filter: brightness(1.25); } + +/* Locked-page numbered lock glyph -- one file per number (not a packed atlas), each sheet is the + whole 25x28 source image, at the original's 85,71 (74,29 within its page). */ +@spritesheet ext-lock-1-sheet { src: "../../../newui_item_add_marking_no01.tga"; ext-lock-1: 0px 0px 25px 28px; } +@spritesheet ext-lock-2-sheet { src: "../../../newui_item_add_marking_no02.tga"; ext-lock-2: 0px 0px 25px 28px; } +@spritesheet ext-lock-3-sheet { src: "../../../newui_item_add_marking_no03.tga"; ext-lock-3: 0px 0px 25px 28px; } +@spritesheet ext-lock-4-sheet { src: "../../../newui_item_add_marking_no04.tga"; ext-lock-4: 0px 0px 25px 28px; } + +/* A locked page's table and empty-slot art: the original's 173x87 and 161x81 from each image's + top-left. */ +@spritesheet ext-table-sheet { src: "../../../newui_item_add_table.tga"; ext-table: 0px 0px 173px 87px; } +@spritesheet ext-empty-sheet { src: "../../../newui_item_add_marking_non.jpg"; ext-empty: 0px 0px 161px 81px; } +.ext-locked-empty { + position: absolute; + left: 4px; + top: 3px; + width: 161px; + height: 81px; + pointer-events: none; + decorator: image(ext-empty); +} + +.ext-locked-page { + position: absolute; + left: 11px; + width: 173px; + height: 87px; + pointer-events: none; + decorator: image(ext-table); +} +.ext-locked-icon { + position: absolute; + left: 74px; + top: 29px; + width: 25px; + height: 28px; + pointer-events: none; + /* decorator set per-instance via data-style-decorator (inventory_extension.rml). */ +} + +/* Each locked page's own row (42 + 87 per page) and its marking. The pages shown are + sparse, so a row is identified by which page it is rather than by its place in the list. */ +.ext-locked-page.page-1 { top: 42px; } +.ext-locked-page.page-2 { top: 129px; } +.ext-locked-page.page-3 { top: 216px; } +.ext-locked-page.page-4 { top: 303px; } +.page-1 .ext-locked-icon { decorator: image(ext-lock-1); } +.page-2 .ext-locked-icon { decorator: image(ext-lock-2); } +.page-3 .ext-locked-icon { decorator: image(ext-lock-3); } +.page-4 .ext-locked-icon { decorator: image(ext-lock-4); } + +/* Native item grids: the first cell's top-left, in #panel's units. */ +.native-anchor { position: absolute; pointer-events: none; } +#item_grid_1, #item_grid_1_counts { left: 15px; top: 45px; width: calc(8 * var(--item-cell)); height: calc(4 * var(--item-cell)); } +#item_grid_2, #item_grid_2_counts { left: 15px; top: 132px; width: calc(8 * var(--item-cell)); height: calc(4 * var(--item-cell)); } +#item_grid_3, #item_grid_3_counts { left: 15px; top: 219px; width: calc(8 * var(--item-cell)); height: calc(4 * var(--item-cell)); } +#item_grid_4, #item_grid_4_counts { left: 15px; top: 306px; width: calc(8 * var(--item-cell)); height: calc(4 * var(--item-cell)); } + +/* The frame. */ +@spritesheet ext-bg-fill-sheet { src: "../../../newui_msgbox_back.jpg"; ext-bg-fill: 0px 0px 190px 429px; } +@spritesheet ext-bg-top-sheet { src: "../../../newui_item_back04.tga"; ext-bg-top: 0px 0px 190px 64px; } +@spritesheet ext-bg-left-sheet { src: "../../../newui_item_back02-L.tga"; ext-bg-left: 0px 0px 21px 320px; } +@spritesheet ext-bg-right-sheet { src: "../../../newui_item_back02-R.tga"; ext-bg-right: 0px 0px 21px 320px; } +@spritesheet ext-bg-bottom-sheet { src: "../../../newui_item_back03.tga"; ext-bg-bottom: 0px 0px 190px 45px; } + +.bg-fill, .bg-top, .bg-left, .bg-right, .bg-bottom { + position: absolute; + pointer-events: none; +} + +.bg-fill { left: 0; top: 0; width: 190px; height: 429px; decorator: image(ext-bg-fill); } +.bg-top { left: 0; top: 0; width: 190px; height: 64px; decorator: image(ext-bg-top); } +.bg-left { left: 0; top: 64px; width: 21px; height: 320px; decorator: image(ext-bg-left); } +.bg-right { left: 169px; top: 64px; width: 21px; height: 320px; decorator: image(ext-bg-right); } +.bg-bottom { left: 0; top: 384px; width: 190px; height: 45px; decorator: image(ext-bg-bottom); } + +/* The grid's clicks are native (CInventoryCtrl), so the placed panel takes no pointer events; its + controls take their own. */ +#panel.slot-placed { pointer-events: none; } +#panel { font-size: calc(var(--text-px, 12px) / var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet classic-iext-back1-sheet { src: ../../../Classic/Item_back01.jpg; classic-iext-back1: 0px 0px 190px 256px; } +@spritesheet classic-iext-back2-sheet { src: ../../../Classic/Item_Back02.jpg; classic-iext-back2: 0px 0px 190px 177px; } +@spritesheet classic-iext-exit-sheet { src: ../../../Classic/Exit_01.jpg; classic-iext-exit: 0px 0px 24px 24px; } +@spritesheet classic-iext-exit2-sheet { src: ../../../Classic/Exit_02.jpg; classic-iext-exit-pressed: 0px 0px 24px 24px; } +#panel { height: 433px; } +.bg-fill { top: 256px; height: 177px; decorator: image(classic-iext-back2); } +.bg-top { height: 256px; decorator: image(classic-iext-back1); } +.bg-left, .bg-right, .bg-bottom { display: none; } +#frame_corner_close { display: none; } +.ext-btn { left: 20px; top: 395px; width: 24px; height: 24px; decorator: image(classic-iext-exit); } +.ext-btn:hover { filter: none; } +.ext-btn:active { decorator: image(classic-iext-exit-pressed); } +@spritesheet classic-iext-lock-sheet { src: ../../../Classic/Lock_02.jpg; classic-iext-lock: 0px 0px 24px 24px; } +#title { color: #ffffff; } +.ext-locked-page { decorator: none; box-sizing: border-box; border: 1px rgb(146, 134, 121); background-color: rgba(0, 0, 0, 150); } +.ext-locked-empty { display: none; } +.ext-locked-icon, .page-1 .ext-locked-icon, .page-2 .ext-locked-icon, .page-3 .ext-locked-icon, .page-4 .ext-locked-icon { + left: 74px; top: 31px; width: 24px; height: 24px; decorator: image(classic-iext-lock); +} diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/item_endurance.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/item_endurance.rcss new file mode 100644 index 0000000000..5dd371fea5 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/item_endurance.rcss @@ -0,0 +1,129 @@ +/* Classic (0.97) item endurance HUD (CItemEnduranceInfo). From the 0.97 client: + - the pet's (Guardian Angel, Imp, Uniria, Dinorant) life in the top-right corner (004bec00): + its name ending at x 625, y 4, and the 0.97 bar at (575, 16) -- a half-black shadow, the dark + teal frame 54x6 and the green fill 50x2 for the life; + - the arrow / bolt count (004bf540) at the top right, x 550, y 4; + - the worn gear's warning icons as legacy draws them (0.97 also flags them top right). + The pets' layer is the screen's stretch of the 640x480 frame, as in legacy, so every place below + is in the original's units. */ + +@spritesheet endurance-pet-back-sheet { src: "../../../newui_Pet_Back.tga"; endurance-pet-back: 0px 0px 57px 23px; } +@spritesheet endurance-boots-sheet { src: "../../../newui_durable_boots.tga"; endurance-boots: 0px 0px 23px 23px; } +@spritesheet endurance-cap-sheet { src: "../../../newui_durable_cap.tga"; endurance-cap: 0px 0px 23px 23px; } +@spritesheet endurance-gloves-sheet { src: "../../../newui_durable_gloves.tga"; endurance-gloves: 0px 0px 23px 23px; } +@spritesheet endurance-lower-sheet { src: "../../../newui_durable_lower.tga"; endurance-lower: 0px 0px 23px 23px; } +@spritesheet endurance-necklace-sheet { src: "../../../newui_durable_necklace.tga"; endurance-necklace: 0px 0px 23px 23px; } +@spritesheet endurance-ring-sheet { src: "../../../newui_durable_ring.tga"; endurance-ring: 0px 0px 23px 23px; } +@spritesheet endurance-shield-sheet { src: "../../../newui_durable_shield.tga"; endurance-shield: 0px 0px 23px 23px; } +@spritesheet endurance-upper-sheet { src: "../../../newui_durable_upper.tga"; endurance-upper: 0px 0px 23px 23px; } +@spritesheet endurance-weapon-sheet { src: "../../../newui_durable_weapon.tga"; endurance-weapon: 0px 0px 23px 23px; } +@spritesheet endurance-wing-sheet { src: "../../../newui_durable_wing.tga"; endurance-wing: 0px 0px 23px 23px; } + +body { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + pointer-events: none; + font-family: "token(font-body)"; +} + +#pets, #icons { position: absolute; width: 0; height: 0; transform-origin: left top; pointer-events: none; } +#pets { + left: 0; + top: 0; + transform: scale(var(--overlay-scale-x, 1), var(--overlay-scale-y, 1)); + --root-scale: var(--overlay-scale-x, 1); + --root-scale-y: var(--overlay-scale-y, 1); +} +/* 0.97 places the pet's life and the arrow count from the right edge of the area its open windows + leave free (004cb520: 640, 450 or 260), 50 further left in a party so they stay clear of the + party list (004bec00, 004bf540). The column follows --world-right in the frame's units, so the + places below stay the ones 0.97 uses with no window open. */ +#pet_column { position: absolute; left: calc(var(--world-right, 640px) / var(--overlay-scale-x, 1) - 640px); top: 0; } +#pets.in-party #pet_column { left: calc(var(--world-right, 640px) / var(--overlay-scale-x, 1) - 690px); } +/* The icons on the dock: the column's first cell two dock units clear of the uncovered world's + right edge, 140 below the dock's top (the bottom HUD's top less the dock's 432 units). */ +#icons { + left: calc(var(--world-right, 100%) - 25px * var(--dock-scale, 1)); + top: calc(100% - 51px * var(--hud-scale, 1) - 292px * var(--dock-scale, 1)); + transform: scale(var(--dock-scale, 1)); +} + + +/* The arrow count at (550, 4), white on half black. */ +#arrows_row { position: absolute; left: 550px; top: 4px; height: 11px; white-space: nowrap; pointer-events: none; } +#arrows { + display: inline-block; + white-space: nowrap; + color: #ffffff; + background-color: rgba(0, 0, 0, 128); + transform-origin: left top; +} + +/* The pet's bar at (575, 16): the shadow (1, 1 below-right), then the frame and its inside, one + dark teal, and the fill C++ sizes to the life (49 of the S6 bar's units), painted flat. */ +.pet { position: absolute; left: 575px; top: 16px; width: 54px; height: 6px; } +.pet-fill { position: absolute; left: 1px; top: 1px; width: 54px; height: 6px; background-color: rgba(0, 0, 0, 128); } +.pet-frame { position: absolute; left: 0; top: 0; width: 54px; height: 6px; background-color: rgb(0, 51, 51); } +.pet-bar { position: absolute; left: 2px; top: 2px; height: 2px; background-color: rgb(0, 200, 50); image-color: rgba(255, 255, 255, 0); } + +/* The name ends at x 625, y 4: a box from x 525 to 625, the name right-aligned in it. */ +.pet-name-box { position: absolute; left: -50px; top: -12px; width: 100px; height: 0; } +.pet-name { + position: absolute; + right: 0; + top: 0; + white-space: nowrap; + color: #ffffff; + background-color: rgba(0, 0, 0, 128); + transform-origin: right top; +} + +.text-row { position: absolute; width: 600px; text-align: center; white-space: nowrap; pointer-events: none; } + +.icon { position: absolute; width: 23px; height: 23px; } +.icon-art { position: absolute; left: 0; top: 0; width: 23px; height: 23px; } +.icon-art--boots { decorator: image(endurance-boots); } +.icon-art--cap { decorator: image(endurance-cap); } +.icon-art--gloves { decorator: image(endurance-gloves); } +.icon-art--lower { decorator: image(endurance-lower); } +.icon-art--necklace { decorator: image(endurance-necklace); } +.icon-art--ring { decorator: image(endurance-ring); } +.icon-art--shield { decorator: image(endurance-shield); } +.icon-art--upper { decorator: image(endurance-upper); } +.icon-art--weapon { decorator: image(endurance-weapon); } +.icon-art--wing { decorator: image(endurance-wing); } +.icon-tint { position: absolute; top: 0; height: 23px; } +.icon-tint--half { background-color: rgba(255, 255, 0, 128); } +.icon-tint--third { background-color: rgba(255, 128, 0, 128); } +.icon-tint--fifth { background-color: rgba(255, 51, 0, 128); } +.icon-tint--zero { background-color: rgba(255, 0, 0, 128); } + +.durability-tip { display: inline-block; white-space: nowrap; font-weight: bold; background-color: rgba(0, 0, 0, 128); } +.durability-tip--half { color: rgb(255, 255, 0); } +.durability-tip--third { color: rgb(255, 168, 0); } +.durability-tip--fifth { color: rgb(255, 83, 0); } +.durability-tip--zero { color: rgb(255, 0, 0); } + +/* The icon column: two cells per column, filling downwards then leftwards, as the original's own + counter stepped them. */ +#icon_column { position: absolute; left: 0; top: 0; } +.icon.cell-0 { left: 0px; top: 0px; } +.icon.cell-1 { left: 0px; top: 25px; } +.icon.cell-2 { left: -25px; top: 0px; } +.icon.cell-3 { left: -25px; top: 25px; } +.icon.cell-4 { left: -50px; top: 0px; } +.icon.cell-5 { left: -50px; top: 25px; } +.icon.cell-6 { left: -75px; top: 0px; } +.icon.cell-7 { left: -75px; top: 25px; } +.icon.cell-8 { left: -100px; top: 0px; } +.icon.cell-9 { left: -100px; top: 25px; } +.icon.cell-10 { left: -125px; top: 0px; } +.icon.cell-11 { left: -125px; top: 25px; } + +/* Whole icon, or one half each when both rings warn at once (the original halved 23 to 11). */ +.icon-tint { left: 0; width: 23px; } +.icon-tint.half-left { left: 0; width: 11px; } +.icon-tint.half-right { left: 11px; width: 11px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/item_grid.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/item_grid.rcss new file mode 100644 index 0000000000..367ca854cc --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/item_grid.rcss @@ -0,0 +1,52 @@ +/* Classic (0.97) item grids: inventory, storage, trade, shop and Chaos Machine all drew their + cells the same way in 0.97: + an empty cell is Interface\Item_box (32x32 shrunk to the 20-unit pitch), a cell under an item is + Interface\InventoryBox2 (its 20x21 corner) tinted by the item's state, and there is no frame + around the grid. The items, the drop preview and the stack counts are as in legacy. + CInventoryCtrl::FollowGrid() reads --item-cell back for the hit tests. */ + +@spritesheet classic-item-cell-sheet { src: ../../../Classic/Item_box.jpg; classic-item-cell: 0px 0px 32px 32px; } +@spritesheet classic-item-cell-used-sheet { src: ../../../Classic/InventoryBox2.jpg; classic-item-cell-used: 0px 0px 20px 21px; } + +body { --item-cell: 20px; } + +.item-grid, .item-grid-counts { position: absolute; pointer-events: none; } +.item-grid-cells, .item-grid-counts { display: flex; flex-wrap: wrap; } +.item-grid-cells { position: absolute; left: 0; top: 0; width: 100%; height: 100%; } + +.item-cell, .item-count { position: relative; flex: 0 0 var(--item-cell); width: var(--item-cell); height: var(--item-cell); } +.item-cell-art { position: absolute; left: 0; top: 0; width: var(--item-cell); height: var(--item-cell); decorator: image(classic-item-cell); } + +/* Under an item: the darker square, white, or the 0.97 wear colours (0.8 0.7 0, 0.8 0.5 0, + 0.8 0.3 0.3, then red); an untradeable item takes 0.97's red-orange. */ +.item-cell.tint-normal .item-cell-art, +.item-cell.tint-durability-50 .item-cell-art, +.item-cell.tint-durability-70 .item-cell-art, +.item-cell.tint-durability-80 .item-cell-art, +.item-cell.tint-durability-100 .item-cell-art, +.item-cell.tint-untradeable .item-cell-art { decorator: image(classic-item-cell-used); } +.item-cell.tint-durability-50 .item-cell-art { image-color: #ccb300; } +.item-cell.tint-durability-70 .item-cell-art { image-color: #cc8000; } +.item-cell.tint-durability-80 .item-cell-art { image-color: #cc4d4d; } +.item-cell.tint-durability-100 .item-cell-art { image-color: #ff0000; } +.item-cell.tint-untradeable .item-cell-art { image-color: #ff331a; } + +.item-cell-drop { position: absolute; left: 0; top: 0; width: 100%; height: 100%; } +.item-cell.drop-free .item-cell-drop { background-color: rgba(26, 102, 204, 102); } +.item-cell.drop-blocked .item-cell-drop, .item-cell.drop-invalid .item-cell-drop { background-color: rgba(255, 51, 51, 102); } +.item-cell.drop-valid .item-cell-drop { background-color: rgba(51, 102, 51, 102); } + +.item-grid-frame { display: none; } + +.item-count-text { + position: absolute; + right: 0; + top: 1px; + transform-origin: right top; + white-space: nowrap; + font-weight: bold; + color: #ffffff; + font-effect: outline(1px #000000); +} + +.item-view { position: absolute; left: -20px; top: -20px; width: 230px; height: 469px; pointer-events: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/kanturu_enter.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/kanturu_enter.rcss new file mode 100644 index 0000000000..96d722f866 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/kanturu_enter.rcss @@ -0,0 +1,70 @@ +/* Classic theme for CKanturu2ndEnterNpc. 0.97 has no Kanturu; the Season 2 client's entry window + (00430482 places it, 0043119e draws the frame, 004312ed the texts, 00475c3e the + buttons) is a 0.97 message box 213 x 250 at (213, 15): a Message_box2 edge (213 x 5) at the top + and the bottom (y 245), six Message_box1 stones (213 x 40) between them from y 5. The texts as + legacy's, from y 20: the subject in (255, 176, 73), the state texts 20 lower, the first green + (145, 241, 97), the others (255, 238, 193), 12 apart and 15 between two. The buttons are Season 1's + win_button stretched to 50 x 16 at y 215: Enter at x 12, Refresh at 82, Close at 152, labelled in + (230, 220, 200); grey (0.8) at rest, white under the mouse, darker (0.6) and one unit in while + pressed, red (1, 0.4, 0.4) while locked. Reference px inside #panel. */ + +@spritesheet kanturu-classic-stone-sheet { src: ../../../Classic/Message_box1.jpg; kanturu-classic-stone: 0px 0px 213px 40px; } +@spritesheet kanturu-classic-edge-sheet { src: ../../../Classic/Message_box2.jpg; kanturu-classic-edge: 0px 0px 213px 5px; } +@spritesheet kanturu-classic-btn-sheet { src: "../../../win_button.tga"; kanturu-classic-btn: 0px 0px 49px 16px; } + +#panel { + position: absolute; + transform-origin: left top; + width: 213px; + height: 250px; + font-family: "token(font-body)"; + pointer-events: auto; +} + +/* The stones: #back and the first five middle tiles, 40 apart from y 5; the edges: the top and the + bottom pieces. */ +#back { position: absolute; left: 0; top: 5px; width: 213px; height: 40px; decorator: image(kanturu-classic-stone); } +#frame_top { position: absolute; left: 0; top: 0; width: 213px; height: 5px; decorator: image(kanturu-classic-edge); } +.frame-middle { position: absolute; left: 0; width: 213px; height: 40px; decorator: image(kanturu-classic-stone); } +#frame_bottom { position: absolute; left: 0; top: 245px; width: 213px; height: 5px; decorator: image(kanturu-classic-edge); } + +.sharp-text { display: block; position: absolute; white-space: nowrap; text-align: center; pointer-events: none; } +#kanturu_lines { left: 0; top: 20px; --flow-w: 213px; } +.kanturu-line { display: block; height: calc(12px * var(--root-scale)); white-space: nowrap; color: #ffb049; } +.kanturu-line.tone-state.group-start { margin-top: calc(20px * var(--root-scale)); } +.kanturu-line.tone-note.group-start { margin-top: calc(15px * var(--root-scale)); } +.kanturu-line.tone-subject { font-weight: bold; } +.kanturu-line.tone-state { color: #91f161; } +.kanturu-line.tone-note { color: #ffeec1; } + +.kanturu-btn { + display: block; + position: absolute; + top: 215px; + width: 50px; + height: 16px; + decorator: image(kanturu-classic-btn fill); + image-color: #cccccc; + pointer-events: auto; +} +.kanturu-btn:hover { image-color: #ffffff; } +.kanturu-btn:active { image-color: #999999; } +.kanturu-btn.locked, .kanturu-btn.locked:hover, .kanturu-btn.locked:active { image-color: #ff6666; } +#btn_enter { left: 12px; } +#btn_refresh { left: 82px; } +#btn_close { left: 152px; } +.kanturu-label { left: 0; color: #e6dcc8; } +.kanturu-btn:active .kanturu-label { margin-left: calc(1px * var(--root-scale)); margin-top: calc(1px * var(--root-scale)); } +.kanturu-btn.locked:active .kanturu-label { margin-left: 0; margin-top: 0; } + +/* Five of the ten middle tiles finish the stones; the rest are not drawn. */ +.frame-middles { position: static; } +.frame-middles .frame-middle:nth-child(1) { top: 45px; } +.frame-middles .frame-middle:nth-child(2) { top: 85px; } +.frame-middles .frame-middle:nth-child(3) { top: 125px; } +.frame-middles .frame-middle:nth-child(4) { top: 165px; } +.frame-middles .frame-middle:nth-child(5) { top: 205px; } +.frame-middles .frame-middle:nth-child(n+6) { display: none; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +.kanturu-label { width: calc(50px * var(--root-scale)); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/kanturu_info.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/kanturu_info.rcss new file mode 100644 index 0000000000..4173458f8c --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/kanturu_info.rcss @@ -0,0 +1,92 @@ +/* Classic theme for CKanturuInfoWindow (kanturu_info.rml is forked here). 0.97 has no Kanturu; the + Season 2 client draws its boss-battle HUD in two pieces: + - the count box (004399f4): MonsterCount (86x80) at (0, 300), the characters at (10, 321) and the + monsters (or the boss) at (10, 343), yellow; + - the hourglass timer (00414514, placed at (243, 400) by 004db3f0): hourglass (154x23 drawn + 154x30) at (238, 405), the minutes centred on x 301 and the seconds on x 332 at y 414 in + Interface\FontTest digits 14x14, 9.8 apart, orange (1, 0.6, 0.3) over a black copy one unit + down and right, and between them the dot (3x9) at (314, 416), blinking. + The classic workspace puts the window's top-left at (0, 300) of the event frame; the rest is + placed from there. Reference px, under .screen's W/640 x H/480 stretch. */ + +@spritesheet kanturu-classic-count-sheet { src: "../../../MonsterCount.tga"; kanturu-classic-count: 0px 0px 86px 80px; } +@spritesheet kanturu-classic-glass-sheet { src: "../../../hourglass.tga"; kanturu-classic-glass: 0px 0px 154px 23px; } +@spritesheet kanturu-classic-dot-sheet { src: "../../../dot.tga"; kanturu-classic-dot: 0px 0px 3px 9px; } +@spritesheet kanturu-classic-digits-sheet +{ + src: ../../../Classic/Fonttest.tga; + kanturu-classic-d0: 0px 0px 16px 16px; + kanturu-classic-d1: 16px 0px 16px 16px; + kanturu-classic-d2: 32px 0px 16px 16px; + kanturu-classic-d3: 48px 0px 16px 16px; + kanturu-classic-d4: 64px 0px 16px 16px; + kanturu-classic-d5: 80px 0px 16px 16px; + kanturu-classic-d6: 96px 0px 16px 16px; + kanturu-classic-d7: 112px 0px 16px 16px; + kanturu-classic-d8: 128px 0px 16px 16px; + kanturu-classic-d9: 144px 0px 16px 16px; +} + +body { pointer-events: none; } + +.screen { + position: absolute; + left: 0; + top: 0; + width: 640px; + height: 480px; + transform-origin: left top; + pointer-events: none; +} + +#panel { position: absolute; width: 86px; height: 80px; font-family: "token(font-body)"; } +#back { position: absolute; left: 0; top: 0; width: 86px; height: 80px; decorator: image(kanturu-classic-count); } +#hourglass { position: absolute; left: 238px; top: 105px; width: 154px; height: 30px; decorator: image(kanturu-classic-glass); } + +.info-text { + display: block; + position: absolute; + transform-origin: left top; + white-space: nowrap; + font-weight: bold; + color: #ffff00; +} +#users { left: 10px; top: 21px; } +#monsters { left: 10px; top: 43px; } + +/* The blinking dot in place of the colon's text. */ +#colon { + left: 314px; + top: 116px; + width: calc(3px * var(--root-scale, 1)); + height: calc(9px * var(--root-scale, 1)); + color: transparent; + decorator: image(kanturu-classic-dot); + image-color: rgb(255, 153, 77); +} + +.digit { position: absolute; top: 114px; width: 14px; height: 14px; image-color: rgb(255, 153, 77); } +.shadow .digit { top: 115px; image-color: #000000; } +.digit.blank { visibility: hidden; } +.digit.d0 { decorator: image(kanturu-classic-d0); } +.digit.d1 { decorator: image(kanturu-classic-d1); } +.digit.d2 { decorator: image(kanturu-classic-d2); } +.digit.d3 { decorator: image(kanturu-classic-d3); } +.digit.d4 { decorator: image(kanturu-classic-d4); } +.digit.d5 { decorator: image(kanturu-classic-d5); } +.digit.d6 { decorator: image(kanturu-classic-d6); } +.digit.d7 { decorator: image(kanturu-classic-d7); } +.digit.d8 { decorator: image(kanturu-classic-d8); } +.digit.d9 { decorator: image(kanturu-classic-d9); } +/* RenderNumber(): the run starts half its digits' width left of its x, each digit 0.7 of its width + after the last. */ +#minutes .digit { left: calc(301px - var(--n) * 7px + var(--i) * 9.8px); } +#seconds .digit { left: calc(332px - var(--n) * 7px + var(--i) * 9.8px); } +#minutes_shadow .digit { left: calc(302px - var(--n) * 7px + var(--i) * 9.8px); } +#seconds_shadow .digit { left: calc(333px - var(--n) * 7px + var(--i) * 9.8px); } + +/* The HUD takes no pointer events where it is placed (base.rcss gives a placed panel them). */ +#panel.slot-placed { pointer-events: none; } + +/* The data-for template row has no index of its own; it inherits this one. */ +.run { --i: 0; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/kanturu_info.rml b/src/bin/Data/Interface/RmlUi/themes/classic/kanturu_info.rml new file mode 100644 index 0000000000..345b37d8bd --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/kanturu_info.rml @@ -0,0 +1,51 @@ + + + Kanturu info (CKanturuInfoWindow) + + + + + +
+
+
+
+ {{users_text}} + {{monsters_text}} + : +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/letter_read.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/letter_read.rcss new file mode 100644 index 0000000000..bffe910a9c --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/letter_read.rcss @@ -0,0 +1,151 @@ +/* Classic theme for a letter being read: the Season 1 client's window (CUILetterReadWindow, the code + this client's own native window ran before its RmlUi port; same frame and palette as + friend_shell.rcss, which says where they come from). 0.97 has no letters. Inside the frame: + - a black band 14 high with "Sender: name date time" at (3, 3), closed by a 106,97,88 line; + - the letter's text below it, the sender's portrait in a 119-wide column at the right from y 15 + down to the bottom; + - a 106,97,88 line 20 above the bottom and a black foot 19 high left of the portrait, with + Reply / Delete (50x14 at x 2, 53), Previous / Next (40x14 at 104, 145) and Close (50x14 at 186), + 16 above the bottom. + Season 1: 370x182 with the portrait; 420 here, the buttons wider, for longer captions. + 1dp is one of the window's units. font-size 1rem, never dp: the theme sizes text natively. */ + +@spritesheet lr-titlebar-sheet { src: "../../../win_titlebar.jpg"; lr-titlebar: 0px 0px 4px 15px; } +@spritesheet lr-size-sheet { src: "../../../win_size.jpg"; lr-minimize: 0px 0px 9px 9px; lr-close: 0px 9px 9px 9px; } +@spritesheet lr-button-sheet { src: "../../../win_button.tga"; lr-button: 0px 0px 49px 16px; } +@spritesheet lr-scroll-sheet +{ + src: "../../../win_scrollbar.jpg"; + lr-scroll-thumb: 0px 1px 11px 1px; + lr-scroll-up: 0px 3px 13px 13px; + lr-scroll-down: 0px 16px 13px 13px; +} + +#panel { transform: none; } +#panel { width: 420dp; height: 182dp; min-width: 400dp; min-height: 182dp; max-width: 100%; max-height: 100%; font-family: "token(font-body)"; font-size: 1rem; color: rgb(230, 220, 200); } + +/* Season 1's frame (friend_shell.rcss): body black at 179, the 5-unit outline drawn in + CUIBaseWindow::DrawOutLine()'s order (the inner lines crossing into the corners), a dot in all + four corners (the window doesn't resize, so the bottom-right one is drawn too; the footer + anchor, unused here, carries the bottom two), and the title bar. */ +.window-shell-sprite-back { + left: 0; + right: 0; + top: 5dp; + bottom: 5dp; + background-color: rgba(0, 0, 0, 179); + decorator: linear-gradient(to right, transparent 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, transparent 4dp), + linear-gradient(to left, transparent 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, transparent 4dp); +} +.window-shell-sprite-top { + left: 0; + right: 0; + top: 0; + bottom: 0; + height: auto; + decorator: linear-gradient(to bottom, rgb(146, 134, 121) 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp), + linear-gradient(to top, rgb(146, 134, 121) 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp); +} +.window-shell-sprite-middle { + left: 0; + right: 0; + top: 1dp; + bottom: 1dp; + decorator: linear-gradient(to right, rgb(146, 134, 121) 1dp, transparent 1dp, transparent 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp), + linear-gradient(to left, rgb(146, 134, 121) 1dp, transparent 1dp, transparent 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp); +} +.window-shell-sprite-bottom { + left: 2dp; + right: 2dp; + top: 2dp; + bottom: auto; + height: 1dp; + decorator: linear-gradient(to right, rgb(173, 167, 150) 1dp, transparent 1dp), + linear-gradient(to left, rgb(173, 167, 150) 1dp, transparent 1dp); +} +#window_shell_footer { + left: 2dp; + right: 2dp; + top: auto; + bottom: 2dp; + height: 1dp; + decorator: linear-gradient(to right, rgb(173, 167, 150) 1dp, transparent 1dp), + linear-gradient(to left, rgb(173, 167, 150) 1dp, transparent 1dp); +} +.window-shell-header-rail { + left: 5dp; + right: 5dp; + top: 5dp; + height: 16dp; + box-sizing: border-box; + border-left: 1dp rgb(136, 138, 147); + border-right: 1dp rgb(0, 0, 8); + border-bottom: 1dp rgb(106, 97, 88); + decorator: image(lr-titlebar fill); +} +.window-shell-header-title { left: 9dp; right: 40dp; top: 8dp; text-align: left; white-space: nowrap; overflow: hidden; color: rgb(230, 220, 200); } +/* This frame needs no extra fill. Only the title bar drags: the strip reaches back out of the + client area over it. */ +#frame_fill { display: none; } +#drag_strip { position: absolute; left: -5dp; right: -5dp; top: -21dp; height: 21dp; pointer-events: auto; } + +/* The client area: 5 units in from the sides and the bottom, 21 down. Each interactive part opts + back into pointer events. */ +.window-shell-content, .window-shell-content.has-title +{ + left: 5dp; + right: 5dp; + top: 21dp; + bottom: 5dp; + padding: 0; + display: block; + pointer-events: none; +} + +div { display: block; } +button { font-family: "token(font-body)"; font-size: 1rem; color: rgb(230, 220, 200); cursor: pointer; pointer-events: auto; } + +/* Minimize and close at w-27 and w-16, y 8 (no maximize). */ +#window_controls { position: absolute; right: 2dp; top: -13dp; z-index: 10; pointer-events: auto; white-space: nowrap; } +#window_controls button { display: inline-block; width: 9dp; height: 9dp; margin-left: 2dp; padding: 0; box-sizing: border-box; } +#btn_minimize { decorator: image(lr-minimize); } +#btn_close_x { decorator: image(lr-close); } + +/* win_button stretched whole, pressed one unit in. */ +.btn { position: relative; display: inline-block; box-sizing: border-box; width: auto; height: 14dp; padding: 0 2dp; line-height: 14dp; vertical-align: top; text-align: center; overflow: hidden; pointer-events: auto; decorator: image(lr-button fill); } +/* base.rcss's .btn:hover / :active swap in legacy's button art; these keep win_button. */ +.btn:hover, .btn:active { decorator: image(lr-button fill); } +.btn:active { padding-top: 1dp; padding-left: 3dp; } + +/* The sender's well, which #photo_image fills: the right column, 119 wide. */ +#photo_image { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; } +#photo_slot.webzen #photo_image { left: 50%; top: 50%; width: 80dp; height: 62dp; margin-left: -40dp; margin-top: -31dp; } +/* The "?" in the well's bottom-left corner, a pixel smaller and inset while its help is open. */ +@spritesheet photo-help-sheet { src: "../../../win_question.tga"; photo-help: 0px 0px 16px 16px; photo-help-pressed: 0px 0px 15px 15px; } +#photo_help { position: absolute; left: 1dp; bottom: 1dp; width: 16dp; height: 16dp; pointer-events: auto; cursor: pointer; decorator: image(photo-help); } +#photo_help.active { left: 2dp; width: 15dp; height: 15dp; decorator: image(photo-help-pressed); } +#photo_slot.webzen #photo_help { display: none; } + +.text-field { background-color: transparent; border-width: 0; color: rgb(230, 220, 200); } + +#header { position: absolute; left: 0; right: 0; top: 0; height: 15dp; line-height: 14dp; padding: 0 3dp; box-sizing: border-box; white-space: nowrap; overflow: hidden; pointer-events: auto; border-bottom: 1dp rgb(106, 97, 88); background-color: rgb(0, 0, 0); } + +#body_pane { position: absolute; left: 0; right: 120dp; top: 15dp; bottom: 20dp; overflow: hidden scroll; background-color: transparent; pointer-events: auto; } +.line { padding: 0 4dp; min-height: 13dp; line-height: 13dp; } + +#photo_slot { position: absolute; right: 0; width: 119dp; top: 15dp; bottom: 0; background-color: transparent; pointer-events: auto; cursor: move; } + +#footer { position: absolute; left: 0; right: 120dp; bottom: 0; height: 20dp; padding: 3dp 0 0 2dp; box-sizing: border-box; white-space: nowrap; border-top: 1dp rgb(106, 97, 88); border-right: 1dp rgb(106, 97, 88); background-color: rgb(0, 0, 0); } +#footer .btn { width: 60dp; margin-right: 1dp; } +#footer .btn.narrow { width: 50dp; } + +/* win_scrollbar, as the friend window's lists. */ +.scroll-pane scrollbarvertical { width: 13dp; margin: 0; } +.scroll-pane scrollbarvertical slidertrack { decorator: none; box-sizing: border-box; border-left: 1dp rgb(106, 97, 88); border-right: 1dp rgb(106, 97, 88); } +.scroll-pane scrollbarvertical sliderbar { height: auto; min-height: 6dp; margin: 0 1dp; decorator: image(lr-scroll-thumb fill); } +.scroll-pane scrollbarvertical sliderarrowdec, +.scroll-pane scrollbarvertical sliderarrowinc { width: 100%; height: 13dp; pointer-events: auto; } +.scroll-pane scrollbarvertical sliderarrowdec { decorator: image(lr-scroll-up); } +.scroll-pane scrollbarvertical sliderarrowinc { decorator: image(lr-scroll-down); } +.scroll-pane scrollbarvertical sliderarrowdec:active, +.scroll-pane scrollbarvertical sliderarrowinc:active { filter: brightness(0.7); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/letter_write.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/letter_write.rcss new file mode 100644 index 0000000000..09723ceb92 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/letter_write.rcss @@ -0,0 +1,149 @@ +/* Classic theme for a letter being written: the Season 1 client's window (CUILetterWriteWindow, the + code this client's own native window ran before its RmlUi port; same frame and palette as + friend_shell.rcss, which says where they come from). 0.97 has no letters. Inside the frame: + - a black band 29 high: "Receiver" and "Title" right-aligned at x 3, y 3 and 18, their fields + after them, 106,97,88 lines at y 14 and 29; + - the text from (5, 33) down to the foot, the sender's portrait in a 119-wide column at the right + from y 30; + - a 106,97,88 line 19 above the bottom and a black foot: Send and Close (50x14 at x 12, 63), the + previous / next pose buttons (50x14 at 250, 301, under the portrait), 16 above the bottom. + Season 1: 370x216 with the portrait; 420 here, the buttons wider, for longer captions. + 1dp is one of the window's units. font-size 1rem, never dp: the theme sizes text natively. */ + +@spritesheet lw-titlebar-sheet { src: "../../../win_titlebar.jpg"; lw-titlebar: 0px 0px 4px 15px; } +@spritesheet lw-size-sheet { src: "../../../win_size.jpg"; lw-minimize: 0px 0px 9px 9px; lw-close: 0px 9px 9px 9px; } +@spritesheet lw-button-sheet { src: "../../../win_button.tga"; lw-button: 0px 0px 49px 16px; } + +#panel { transform: none; } +#panel { width: 420dp; height: 216dp; min-width: 400dp; min-height: 150dp; max-width: 100%; max-height: 100%; font-family: "token(font-body)"; font-size: 1rem; color: rgb(230, 220, 200); } + +/* Season 1's frame (friend_shell.rcss): body black at 179, the 5-unit outline drawn in + CUIBaseWindow::DrawOutLine()'s order (the inner lines crossing into the corners), a dot in all + four corners (the window doesn't resize, so the bottom-right one is drawn too; the footer + anchor, unused here, carries the bottom two), and the title bar. */ +.window-shell-sprite-back { + left: 0; + right: 0; + top: 5dp; + bottom: 5dp; + background-color: rgba(0, 0, 0, 179); + decorator: linear-gradient(to right, transparent 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, transparent 4dp), + linear-gradient(to left, transparent 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, transparent 4dp); +} +.window-shell-sprite-top { + left: 0; + right: 0; + top: 0; + bottom: 0; + height: auto; + decorator: linear-gradient(to bottom, rgb(146, 134, 121) 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp), + linear-gradient(to top, rgb(146, 134, 121) 1dp, rgb(37, 37, 37) 1dp, rgb(37, 37, 37) 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp); +} +.window-shell-sprite-middle { + left: 0; + right: 0; + top: 1dp; + bottom: 1dp; + decorator: linear-gradient(to right, rgb(146, 134, 121) 1dp, transparent 1dp, transparent 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp), + linear-gradient(to left, rgb(146, 134, 121) 1dp, transparent 1dp, transparent 4dp, rgb(106, 97, 88) 4dp, rgb(106, 97, 88) 5dp, transparent 5dp); +} +.window-shell-sprite-bottom { + left: 2dp; + right: 2dp; + top: 2dp; + bottom: auto; + height: 1dp; + decorator: linear-gradient(to right, rgb(173, 167, 150) 1dp, transparent 1dp), + linear-gradient(to left, rgb(173, 167, 150) 1dp, transparent 1dp); +} +#window_shell_footer { + left: 2dp; + right: 2dp; + top: auto; + bottom: 2dp; + height: 1dp; + decorator: linear-gradient(to right, rgb(173, 167, 150) 1dp, transparent 1dp), + linear-gradient(to left, rgb(173, 167, 150) 1dp, transparent 1dp); +} +.window-shell-header-rail { + left: 5dp; + right: 5dp; + top: 5dp; + height: 16dp; + box-sizing: border-box; + border-left: 1dp rgb(136, 138, 147); + border-right: 1dp rgb(0, 0, 8); + border-bottom: 1dp rgb(106, 97, 88); + decorator: image(lw-titlebar fill); +} +.window-shell-header-title { left: 9dp; right: 40dp; top: 8dp; text-align: left; white-space: nowrap; overflow: hidden; color: rgb(230, 220, 200); } +/* This frame needs no extra fill. Only the title bar drags: the strip reaches back out of the + client area over it. */ +#frame_fill { display: none; } +#drag_strip { position: absolute; left: -5dp; right: -5dp; top: -21dp; height: 21dp; pointer-events: auto; } + +/* The client area: 5 units in from the sides and the bottom, 21 down. Each interactive part opts + back into pointer events. */ +.window-shell-content, .window-shell-content.has-title +{ + left: 5dp; + right: 5dp; + top: 21dp; + bottom: 5dp; + padding: 0; + display: block; + pointer-events: none; +} + +div { display: block; } +button { font-family: "token(font-body)"; font-size: 1rem; color: rgb(230, 220, 200); cursor: pointer; pointer-events: auto; } + +/* Minimize and close at w-27 and w-16, y 8 (no maximize). */ +#window_controls { position: absolute; right: 2dp; top: -13dp; z-index: 10; pointer-events: auto; white-space: nowrap; } +#window_controls button { display: inline-block; width: 9dp; height: 9dp; margin-left: 2dp; padding: 0; box-sizing: border-box; } +#btn_minimize { decorator: image(lw-minimize); } +#btn_close_x { decorator: image(lw-close); } + +/* win_button stretched whole, pressed one unit in. */ +.btn { position: relative; display: inline-block; box-sizing: border-box; width: auto; height: 14dp; padding: 0 2dp; line-height: 14dp; vertical-align: top; text-align: center; overflow: hidden; pointer-events: auto; decorator: image(lw-button fill); } +/* base.rcss's .btn:hover / :active swap in legacy's button art; these keep win_button. */ +.btn:hover, .btn:active { decorator: image(lw-button fill); } +.btn:active { padding-top: 1dp; padding-left: 3dp; } + +/* The sender's well, which #photo_image fills: the right column, 119 wide. */ +#photo_image { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; } +#photo_slot.webzen #photo_image { left: 50%; top: 50%; width: 80dp; height: 62dp; margin-left: -40dp; margin-top: -31dp; } +/* The "?" in the well's bottom-left corner, a pixel smaller and inset while its help is open. */ +@spritesheet photo-help-sheet { src: "../../../win_question.tga"; photo-help: 0px 0px 16px 16px; photo-help-pressed: 0px 0px 15px 15px; } +#photo_help { position: absolute; left: 1dp; bottom: 1dp; width: 16dp; height: 16dp; pointer-events: auto; cursor: pointer; decorator: image(photo-help); } +#photo_help.active { left: 2dp; width: 15dp; height: 15dp; decorator: image(photo-help-pressed); } +#photo_slot.webzen #photo_help { display: none; } + +.text-field { background-color: transparent; border-width: 0; color: rgb(230, 220, 200); } +.btn.disabled { pointer-events: none; image-color: rgba(255, 255, 255, 120); } + +#rows { + position: absolute; + left: 0; + right: 0; + top: 0; + height: 30dp; + padding-right: 120dp; + box-sizing: border-box; + pointer-events: auto; + decorator: linear-gradient(to bottom, rgb(0, 0, 0) 14dp, rgb(106, 97, 88) 14dp, rgb(106, 97, 88) 15dp, rgb(0, 0, 0) 15dp, rgb(0, 0, 0) 29dp, rgb(106, 97, 88) 29dp); +} +.row { display: flex; height: 15dp; padding-top: 1dp; box-sizing: border-box; white-space: nowrap; } +.row .label { flex: 0 0 60dp; height: 13dp; line-height: 13dp; padding: 0 4dp 0 3dp; box-sizing: border-box; text-align: right; overflow: hidden; } +.row .text-field { flex: 1 1 auto; box-sizing: border-box; width: auto; height: 13dp; pointer-events: auto; } + +#body_wrap { position: absolute; left: 5dp; right: 120dp; top: 33dp; bottom: 20dp; } +#body_field { width: 100%; height: 100%; box-sizing: border-box; pointer-events: auto; } + +#photo_slot { position: absolute; right: 0; width: 119dp; top: 30dp; bottom: 20dp; background-color: transparent; pointer-events: auto; cursor: move; } + +#footer { position: absolute; left: 0; right: 0; bottom: 0; height: 20dp; padding: 3dp 0 0 12dp; box-sizing: border-box; white-space: nowrap; border-top: 1dp rgb(106, 97, 88); background-color: rgb(0, 0, 0); } +#footer .btn { width: 60dp; margin-right: 1dp; } +/* The pose buttons under the portrait, at the right. */ +#footer .btn.pose { position: absolute; top: 3dp; right: 60dp; width: 58dp; margin: 0; } +#footer .btn.pose:last-child { right: 1dp; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/login.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/login.rcss new file mode 100644 index 0000000000..53ec3a54ab --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/login.rcss @@ -0,0 +1,160 @@ +/* Classic (0.97) login box. Positions, sizes and colours from the 0.97 client: + - 0Account_new (250x216) centred horizontally, resting at y=266 of 480 with its bottom 2 px + below the screen, sliding up when it appears; + - the Connect and Exit plates are part of the background art; the button art only lights up + under the mouse (0On_Botton / 0On_Botton2); + - text colour (255, 230, 210). + 1 original pixel = 1/480 of the screen height, as the 0.97 client scales its 2D art. The text + does not stretch with it: 0.97 drew its font at screen pixels, so the labels, fields and buttons + are "native-text" (login.rml), the native text size (RmlNativeText.h). */ + +@spritesheet classic-login-sheet +{ + src: ../../../../Logo/Classic/0account_new.tga; + classic-login-back: 0px 0px 250px 216px; +} + +@spritesheet classic-login-ok-sheet +{ + src: ../../../../Logo/Classic/0on_botton.jpg; + classic-login-ok-hover: 0px 0px 70px 19px; +} + +@spritesheet classic-login-exit-sheet +{ + src: ../../../../Logo/Classic/0on_botton2.jpg; + classic-login-exit-hover: 0px 0px 70px 20px; +} + +@keyframes classic-login-rise +{ + from { transform: translateY(100%); } + to { transform: translateY(0%); } +} + +body { + width: 100%; + height: 100%; + margin: 0; + pointer-events: none; + --px: calc(100vh / 480); +} + +/* LoginWin.cpp still moves this one; the classic box is placed by the stylesheet instead. */ +#panel { + position: absolute; + width: 0; + height: 0; +} + +#classic_box { + position: absolute; + left: 50%; + bottom: calc(-2 * var(--px)); + width: calc(250 * var(--px)); + height: calc(216 * var(--px)); + margin-left: calc(-125 * var(--px)); + font-family: "token(font-body)"; + color: #ffe6d2; + decorator: image(classic-login-back); + pointer-events: auto; + animation: 0.45s cubic-out 1 classic-login-rise; +} + +.label { + position: absolute; + left: calc(32 * var(--px)); + white-space: nowrap; +} +.label-account { top: calc(50 * var(--px)); } +.label-password { top: calc(72 * var(--px)); } + +.login-field { + position: absolute; + left: calc(100 * var(--px)); + width: calc(119 * var(--px)); + height: calc(16 * var(--px)); + padding: 0; + color: #ffe6d2; + background-color: transparent; + border-width: 0; + box-shadow: none; + decorator: none; +} +.login-field-account { top: calc(48 * var(--px)); } +.login-field-password { top: calc(70 * var(--px)); } + +.btn { + position: absolute; + width: calc(70 * var(--px)); + text-align: center; + cursor: pointer; + pointer-events: auto; + decorator: none; +} +.btn-text { + color: #ffffff; +} +.btn-ok { + left: calc(128 * var(--px)); + top: calc(95 * var(--px)); + height: calc(19 * var(--px)); + line-height: calc(19 * var(--px)); +} +.btn-ok:hover { + decorator: image(classic-login-ok-hover); +} +.btn-cancel { + left: calc(90 * var(--px)); + top: calc(180 * var(--px)); + height: calc(20 * var(--px)); + line-height: calc(20 * var(--px)); +} +.btn-cancel:hover { + decorator: image(classic-login-exit-hover); +} + +/* The "remember me" / "save password" options, which neither 0.97 nor Season 1 (the same box) has: + on the two blank plates of the box's second row (x 52 and 129, y 118, 69x19), each with the + classic social windows' check box (a 7x7 box, win_check's mark). */ +@spritesheet classic-login-check-sheet { src: ../../../win_check.tga; classic-login-check: 0px 0px 5px 5px; } + +#classic_box .checkbox-row { + position: absolute; + top: calc(118 * var(--px)); + width: calc(69 * var(--px)); + height: calc(19 * var(--px)); + line-height: calc(19 * var(--px)); + text-align: center; + white-space: nowrap; + cursor: pointer; + pointer-events: auto; +} +#classic_box .checkbox-remember-me { left: calc(52 * var(--px)); } +#classic_box .checkbox-save-password { left: calc(129 * var(--px)); } +#classic_box .checkbox-box { + display: inline-block; + width: calc(7 * var(--px)); + height: calc(7 * var(--px)); + margin-right: calc(3 * var(--px)); + vertical-align: middle; + box-sizing: border-box; + background-color: rgb(106, 97, 88); + border: 1px rgb(146, 134, 121); + decorator: none; +} +#classic_box .checkbox-box.checked { decorator: image(classic-login-check); } +/* The labels are sized with the box, not at the native text size, which would run past the plate + at most sizes (the plate shrinks with the screen faster than the native text does). They break + into two lines at their space ("Remember / Password", German's "Benutzernamen / merken", the + longest word), beside the check box. */ +#classic_box .checkbox-label { + position: static; + display: inline-block; + max-width: calc(54 * var(--px)); + vertical-align: middle; + white-space: normal; + text-align: left; + font-size: calc(6.5 * var(--px)); + line-height: calc(7.5 * var(--px)); +} diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/login.rml b/src/bin/Data/Interface/RmlUi/themes/classic/login.rml new file mode 100644 index 0000000000..201929dd31 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/login.rml @@ -0,0 +1,38 @@ + + + Login + + + + + +
+
+ + {{password_label}} + + + + + +
+
+ {{remember_me_label}} +
+
+
+ {{save_password_label}} +
+ +
{{ok_label}}
+
{{cancel_label}}
+
+ +
diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/login_main.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/login_main.rcss new file mode 100644 index 0000000000..b7630d4c72 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/login_main.rcss @@ -0,0 +1,4 @@ +/* Classic (0.97) login: the 0.97 login scene has no Menu / Credits buttons (CLoginMainWin), so the + bar is hidden. Esc still opens the system menu (SceneUICoordinator). */ + +#panel { display: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/lucky_coin_exchange_rows.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/lucky_coin_exchange_rows.rcss new file mode 100644 index 0000000000..eef21a43e0 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/lucky_coin_exchange_rows.rcss @@ -0,0 +1,60 @@ +/* Classic rows for Delgado's lucky coin exchange (CExchangeLuckyCoin). 0.97 has no lucky coin; the window takes the + classic Golden Archer's parts (gold_bowman.rcss): the 0.97 frame, each action on a 0.97 text plate + (Message_box, 120 x 22, centred on the S6 button's row) lit warm under the mouse and darkened + while locked, and the 0.97 Close (Exit_01, Exit_02 pressed) at (25, 395) in place of the Close + text button. Legacy's rows first, then the classic rules. */ + +/* Where lucky_coin_exchange.rml's own lines and buttons sit. CExchangeLuckyCoin's RenderTexts(): the title and Exchange bold, the warning bold yellow at y 80, the notice two and three lines (14 units) below it. The three exchange buttons from y 220, EXCHANGE_BTN_VAL apart; Close at y 360. + The look they share is event_item_entry.rcss; only the rows are this document's. */ + +.entry-text:nth-child(1) { left: 0px; top: 25px; color: #ffffff; font-weight: bold; } +.entry-text:nth-child(2) { left: 0px; top: 200px; color: #ffffff; font-weight: bold; } +.entry-text:nth-child(3) { left: 0px; top: 80px; color: rgb(255, 255, 0); font-weight: bold; } +.entry-text:nth-child(4) { left: 0px; top: 108px; color: #ffffff; } +.entry-text:nth-child(5) { left: 0px; top: 122px; color: #ffffff; } + +.entry-btn:nth-child(1) { left: 41px; top: 220px; width: 108px; height: 29px; } +.entry-btn:nth-child(1) .entry-label { font-weight: bold; } +.entry-btn:nth-child(1) { decorator: image(coin-btn-wide-up); } +.entry-btn:nth-child(1):hover { decorator: image(coin-btn-wide-over); } +.entry-btn:nth-child(1):active { decorator: image(coin-btn-wide-down); } +.entry-btn:nth-child(1).locked, .entry-btn:nth-child(1).locked:hover, .entry-btn:nth-child(1).locked:active { decorator: image(coin-btn-wide-up); image-color: #ffffff; } + +.entry-btn:nth-child(2) { left: 41px; top: 253px; width: 108px; height: 29px; } +.entry-btn:nth-child(2) .entry-label { font-weight: bold; } +.entry-btn:nth-child(2) { decorator: image(coin-btn-wide-up); } +.entry-btn:nth-child(2):hover { decorator: image(coin-btn-wide-over); } +.entry-btn:nth-child(2):active { decorator: image(coin-btn-wide-down); } +.entry-btn:nth-child(2).locked, .entry-btn:nth-child(2).locked:hover, .entry-btn:nth-child(2).locked:active { decorator: image(coin-btn-wide-up); image-color: #ffffff; } + +.entry-btn:nth-child(3) { left: 41px; top: 286px; width: 108px; height: 29px; } +.entry-btn:nth-child(3) .entry-label { font-weight: bold; } +.entry-btn:nth-child(3) { decorator: image(coin-btn-wide-up); } +.entry-btn:nth-child(3):hover { decorator: image(coin-btn-wide-over); } +.entry-btn:nth-child(3):active { decorator: image(coin-btn-wide-down); } +.entry-btn:nth-child(3).locked, .entry-btn:nth-child(3).locked:hover, .entry-btn:nth-child(3).locked:active { decorator: image(coin-btn-wide-up); image-color: #ffffff; } + +.entry-btn:nth-child(4) { left: 63px; top: 360px; width: 64px; height: 29px; } +.entry-btn:nth-child(4) { decorator: image(coin-btn-small-up); } +.entry-btn:nth-child(4):hover { decorator: image(coin-btn-small-over); } +.entry-btn:nth-child(4):active { decorator: image(coin-btn-small-down); } +.entry-btn:nth-child(4).locked, .entry-btn:nth-child(4).locked:hover, .entry-btn:nth-child(4).locked:active { decorator: image(coin-btn-small-up); image-color: #ffffff; } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet lce-classic-plate-sheet { src: ../../../Classic/Message_box.jpg; lce-classic-plate: 0px 0px 213px 64px; } +@spritesheet lce-classic-exit-sheet { src: ../../../Classic/Exit_01.jpg; lce-classic-exit: 0px 0px 24px 24px; } +@spritesheet lce-classic-exit2-sheet { src: ../../../Classic/Exit_02.jpg; lce-classic-exit-pressed: 0px 0px 24px 24px; } +.entry-btn:nth-child(1) { left: 35px; top: 224px; width: 120px; height: 22px; decorator: image(lce-classic-plate fill); image-color: #ffffff; } +.entry-btn:nth-child(1):hover, .entry-btn:nth-child(1):active { decorator: image(lce-classic-plate fill); image-color: #ffd9b3; } +.entry-btn:nth-child(1).locked, .entry-btn:nth-child(1).locked:hover, .entry-btn:nth-child(1).locked:active { decorator: image(lce-classic-plate fill); image-color: #666666; } +.entry-btn:nth-child(2) { left: 35px; top: 257px; width: 120px; height: 22px; decorator: image(lce-classic-plate fill); image-color: #ffffff; } +.entry-btn:nth-child(2):hover, .entry-btn:nth-child(2):active { decorator: image(lce-classic-plate fill); image-color: #ffd9b3; } +.entry-btn:nth-child(2).locked, .entry-btn:nth-child(2).locked:hover, .entry-btn:nth-child(2).locked:active { decorator: image(lce-classic-plate fill); image-color: #666666; } +.entry-btn:nth-child(3) { left: 35px; top: 290px; width: 120px; height: 22px; decorator: image(lce-classic-plate fill); image-color: #ffffff; } +.entry-btn:nth-child(3):hover, .entry-btn:nth-child(3):active { decorator: image(lce-classic-plate fill); image-color: #ffd9b3; } +.entry-btn:nth-child(3).locked, .entry-btn:nth-child(3).locked:hover, .entry-btn:nth-child(3).locked:active { decorator: image(lce-classic-plate fill); image-color: #666666; } +.entry-btn:nth-child(4) { left: 25px; top: 395px; width: 24px; height: 24px; decorator: image(lce-classic-exit); } +.entry-btn:nth-child(4):hover { decorator: image(lce-classic-exit); } +.entry-btn:nth-child(4):active { decorator: image(lce-classic-exit-pressed); } +.entry-btn:nth-child(4).locked, .entry-btn:nth-child(4).locked:hover, .entry-btn:nth-child(4).locked:active { decorator: image(lce-classic-exit); image-color: #666666; } +.entry-btn:nth-child(4) .entry-label { display: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/lucky_coin_registration_rows.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/lucky_coin_registration_rows.rcss new file mode 100644 index 0000000000..039d3b4974 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/lucky_coin_registration_rows.rcss @@ -0,0 +1,48 @@ +/* Classic rows for Delgado's lucky coin registration (CRegistrationLuckyCoin). 0.97 has no lucky coin; the window takes the + classic Golden Archer's parts (gold_bowman.rcss): the 0.97 frame, each action on a 0.97 text plate + (Message_box, 120 x 22, centred on the S6 button's row) lit warm under the mouse and darkened + while locked, and the 0.97 Close (Exit_01, Exit_02 pressed) at (25, 395) in place of the Close + text button. Legacy's rows first, then the classic rules. */ + +/* Where lucky_coin_registration.rml's own lines and buttons sit. CRegistrationLuckyCoin's RenderTexts(): white, centred on the 190-unit panel from y 25. Register at the panel's height - 220, Close at y 360. + The look they share is event_item_entry.rcss; only the rows are this document's. */ + +.entry-text:nth-child(1) { left: 0px; top: 25px; color: #ffffff; font-weight: bold; } +.entry-text:nth-child(2) { left: 0px; top: 65px; color: #ffffff; } +.entry-text:nth-child(3) { left: 0px; top: 85px; color: #ffffff; } +.entry-text:nth-child(4) { left: 0px; top: 105px; color: #ffffff; } +.entry-text:nth-child(5) { left: 0px; top: 125px; color: #ffffff; } +.entry-text:nth-child(6) { left: 0px; top: 145px; color: #ffffff; font-weight: bold; } +.entry-text:nth-child(7) { left: 24px; top: 175px; color: #ffffff; font-weight: bold; } + +.entry-btn:nth-child(1) { left: 63px; top: 209px; width: 64px; height: 29px; } +.entry-btn:nth-child(1) .entry-label { font-weight: bold; } +.entry-btn:nth-child(1) { decorator: image(coin-btn-small-up); } +.entry-btn:nth-child(1):hover { decorator: image(coin-btn-small-over); } +.entry-btn:nth-child(1):active { decorator: image(coin-btn-small-down); } +.entry-btn:nth-child(1).locked, .entry-btn:nth-child(1).locked:hover, .entry-btn:nth-child(1).locked:active { decorator: image(coin-btn-small-up); image-color: #ffffff; } + +.entry-btn:nth-child(2) { left: 63px; top: 360px; width: 64px; height: 29px; } +.entry-btn:nth-child(2) .entry-label { font-weight: bold; } +.entry-btn:nth-child(2) { decorator: image(coin-btn-small-up); } +.entry-btn:nth-child(2):hover { decorator: image(coin-btn-small-over); } +.entry-btn:nth-child(2):active { decorator: image(coin-btn-small-down); } +.entry-btn:nth-child(2).locked, .entry-btn:nth-child(2).locked:hover, .entry-btn:nth-child(2).locked:active { decorator: image(coin-btn-small-up); image-color: #ffffff; } + +/* Where C++ draws the live 3D preview: the original's place and size. */ +.entry-item-box { position: absolute; left: -20px; top: 50px; width: 190px; height: 429px; pointer-events: none; } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet lcr-classic-plate-sheet { src: ../../../Classic/Message_box.jpg; lcr-classic-plate: 0px 0px 213px 64px; } +@spritesheet lcr-classic-exit-sheet { src: ../../../Classic/Exit_01.jpg; lcr-classic-exit: 0px 0px 24px 24px; } +@spritesheet lcr-classic-exit2-sheet { src: ../../../Classic/Exit_02.jpg; lcr-classic-exit-pressed: 0px 0px 24px 24px; } +.entry-btn:nth-child(1) { left: 35px; top: 212px; width: 120px; height: 22px; decorator: image(lcr-classic-plate fill); image-color: #ffffff; } +.entry-btn:nth-child(1):hover, .entry-btn:nth-child(1):active { decorator: image(lcr-classic-plate fill); image-color: #ffd9b3; } +.entry-btn:nth-child(1).locked, .entry-btn:nth-child(1).locked:hover, .entry-btn:nth-child(1).locked:active { decorator: image(lcr-classic-plate fill); image-color: #666666; } +.entry-btn:nth-child(2) { left: 25px; top: 395px; width: 24px; height: 24px; decorator: image(lcr-classic-exit); } +.entry-btn:nth-child(2):hover { decorator: image(lcr-classic-exit); } +.entry-btn:nth-child(2):active { decorator: image(lcr-classic-exit-pressed); } +.entry-btn:nth-child(2).locked, .entry-btn:nth-child(2).locked:hover, .entry-btn:nth-child(2).locked:active { decorator: image(lcr-classic-exit); image-color: #666666; } +.entry-btn:nth-child(2) .entry-label { display: none; } +/* The web-page notice runs past the frame in longer languages: it wraps inside it (the next row is empty). */ +.entry-text:nth-child(5) .sharp-text { left: 8px; width: calc(174px * var(--root-scale)); margin-left: 0; white-space: normal; transform-origin: left top; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/lucky_item.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/lucky_item.rcss new file mode 100644 index 0000000000..ff6c14c129 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/lucky_item.rcss @@ -0,0 +1,122 @@ +/* Classic theme for the Lucky Item window (a mix window: the lucky item's exchange and refining). + 0.97 has none; it takes the classic Chaos Machine's parts: the 0.97 inventory frame (Item_Back01 + over Item_Back02), the light grey bold title in the top band, 0.97's Mix_button1 (Mix_button2 + pressed) at the legacy place; the corner close stays (the window has no other), as the Chaos + Machine's. Legacy's layout and comments below. */ + +/* Legacy theme for CLuckyItemWnd's chrome (frame/title/mix button). C++ supplies position + and scale; the theme owns width and height. Coordinates below are reference px, not dp. */ + +#panel { + position: absolute; + transform-origin: left top; + width: 190px; + height: 429px; + font-family: "token(font-body)"; +} + +/* left:0/right:0 (not a fixed width) so the title stays centered across #panel's runtime width. + top:11px matches storage_ext.rcss's own subject-text offset -- both windows' native RenderText + call used the same `m_Pos.y + 18` baseline offset. */ +#title { + position: absolute; + left: 0; + right: 0; + top: 11px; + text-align: center; + color: token(text-primary); + font-weight: bold; + font-size: 1em; +} + +/* Centered via left:50%/negative margin-left (half of the button's own 44px width) rather than + width-dependent centering math, so it stays centered regardless of #panel's runtime width -- + same technique base.rcss's .modern-joint-px uses. top:380px matches the native + `m_ptPos.y + 380` offset exactly (LuckyItemWnd.cpp's old ChangeButtonInfo() call), a fixed + distance from the panel's TOP, not scaled with height. */ +@spritesheet lucky-mix-btn-sheet { src: "../../../newui_bt_mix.tga"; lucky-mix-btn: 0px 0px 44px 35px; } +.mix-btn { + position: absolute; + left: 50%; + margin-left: -22px; + top: 380px; + width: 44px; + height: 35px; + cursor: pointer; + pointer-events: auto; + decorator: image(lucky-mix-btn); +} +.mix-btn:hover { filter: brightness(1.25); } +.mix-btn.hidden { display: none; } + + +/* Former Render_Frame()'s m_sText[]/AddText() text loop. left:10/right:10 (rather than a fixed + width) follows #panel's theme width minus 20px. top:208px matches the native `m_ptPos.y + 18 + 190` baseline. Each line + is a fixed 11px-tall block (matching the native loop's `11.0f * i` per-slot spacing) so blank + spacer entries (empty text) still preserve the original's vertical rhythm. */ +#text_lines { + position: absolute; + left: 10px; + right: 10px; + top: 208px; +} +/* #text_lines is a text layer (lucky_item.rml): 11px rows via its bound line height. */ +.lucky-line { + display: block; + overflow: hidden; + white-space: nowrap; + color: token(text-primary); + font-size: 1em; + text-align: center; +} + +/* Native item grid: the first cell's top-left, in #panel's units. */ +.native-anchor { position: absolute; pointer-events: none; } +#item_grid, #item_grid_counts { left: 15px; top: 110px; width: calc(8 * var(--item-cell)); height: calc(4 * var(--item-cell)); } + +/* The frame. */ +@spritesheet lucky-bg-fill-sheet { src: "../../../newui_msgbox_back.jpg"; lucky-bg-fill: 0px 0px 190px 429px; } +@spritesheet lucky-bg-top-sheet { src: "../../../newui_item_back04.tga"; lucky-bg-top: 0px 0px 190px 64px; } +@spritesheet lucky-bg-left-sheet { src: "../../../newui_item_back02-L.tga"; lucky-bg-left: 0px 0px 21px 320px; } +@spritesheet lucky-bg-right-sheet { src: "../../../newui_item_back02-R.tga"; lucky-bg-right: 0px 0px 21px 320px; } +@spritesheet lucky-bg-bottom-sheet { src: "../../../newui_item_back03.tga"; lucky-bg-bottom: 0px 0px 190px 45px; } + +.bg-fill, .bg-top, .bg-left, .bg-right, .bg-bottom { + position: absolute; + pointer-events: none; +} + +/* All five pieces stretch to fill their own box regardless of the spritesheet rect above (RmlUi's + `image` decorator always fills the element's box) -- the same stretch behavior the native + RenderImage() calls always had, just driven by CSS now instead of C++ math. left/right have no + explicit height: with both `top` and `bottom` set, they stretch to whatever's left between the + fixed-height top/bottom pieces, tracking #panel's own runtime height. top/bottom have no + explicit width for the same reason (`left`+`right` stretch), tracking runtime width. */ +.bg-fill { left: 0; top: 0; right: 0; bottom: 0; decorator: image(lucky-bg-fill); } +.bg-top { left: 0; top: 0; right: 0; height: 64px; decorator: image(lucky-bg-top); } +.bg-left { left: 0; top: 64px; bottom: 45px; width: 21px; decorator: image(lucky-bg-left); } +.bg-right { right: 0; top: 64px; bottom: 45px; width: 21px; decorator: image(lucky-bg-right); } +.bg-bottom { left: 0; bottom: 0; right: 0; height: 45px; decorator: image(lucky-bg-bottom); } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#title { width: calc(100% * var(--root-scale)); } +#text_lines { width: calc((100% - 20px) * var(--root-scale)); line-height: calc(11px * var(--root-scale)); } + +/* The grid's clicks are native (CInventoryCtrl), so the placed panel takes no pointer events; its + controls take their own. */ +#panel.slot-placed { pointer-events: none; } +#panel { font-size: calc(var(--text-px, 12px) / var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet lucky-classic-back1-sheet { src: ../../../Classic/Item_back01.jpg; lucky-classic-back1: 0px 0px 190px 256px; } +@spritesheet lucky-classic-back2-sheet { src: ../../../Classic/Item_Back02.jpg; lucky-classic-back2: 0px 0px 190px 177px; } +@spritesheet lucky-classic-btn1-sheet { src: ../../../Classic/Mix_button1.jpg; lucky-classic-btn: 0px 0px 44px 32px; } +@spritesheet lucky-classic-btn2-sheet { src: ../../../Classic/Mix_button2.jpg; lucky-classic-btn-pressed: 0px 0px 44px 32px; } +#panel { height: 433px; } +.bg-top { right: auto; width: 190px; height: 256px; decorator: image(lucky-classic-back1); } +.bg-fill { top: 256px; right: auto; bottom: auto; width: 190px; height: 177px; decorator: image(lucky-classic-back2); } +.bg-left, .bg-right, .bg-bottom { display: none; } +#title { top: 12px; color: #dcdcdc; } +.mix-btn { height: 32px; decorator: image(lucky-classic-btn); } +.mix-btn:hover { filter: none; } +.mix-btn:active { decorator: image(lucky-classic-btn-pressed); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/main_frame.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/main_frame.rcss new file mode 100644 index 0000000000..348a5573ee --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/main_frame.rcss @@ -0,0 +1,291 @@ +/* Classic HUD: the 640x48 bar at the bottom, the two dragons over its ends (Menu04, the right one + mirrored), the life and mana orbs filling from the bottom, the AG column, the experience line and + the Party / Character / Inventory / Guild buttons, as the 0.97 client draws them, with what the + Season 1 and 2 clients add to it: the command window and friend buttons in the bar's top boxes and + the SD column. The bar is 0.97's middle third (Menu02) between Season 2's left third + (s2/menu01_new: 0.97's Menu01_new with the command window button's box at the top left and a + recess for the SD column at x 73) and Season 1's right third (s1/Menu03_new: 0.97's Menu03_new + with the friend button's box at the top right). From the 0.97 client: + 1dp is one unit of its 640x480 frame, and every part sits at its 0.97 place, x from the bar's + left end and y from the bar's top (480 - 48 = 432 in the 0.97 frame). The bar keeps its + proportions and stays centred on wide screens; the world shows beside it. */ + +@spritesheet classic-hud-bar-left-sheet { src: ../../../Classic/s2/menu01_new.jpg; classic-hud-bar-left: 0px 0px 256px 48px; } +@spritesheet classic-hud-bar-middle-sheet { src: ../../../Classic/Menu02.jpg; classic-hud-bar-middle: 0px 0px 128px 48px; } +@spritesheet classic-hud-bar-right-sheet { src: ../../../Classic/s1/Menu03_new.jpg; classic-hud-bar-right: 0px 0px 256px 48px; } +@spritesheet classic-hud-dragon-sheet { src: ../../../Classic/Menu04.tga; classic-hud-dragon: 0px 0px 108px 45px; } +@spritesheet classic-hud-red-sheet { src: ../../../Classic/Menu_red.jpg; classic-hud-life: 0px 0px 53px 48px; } +@spritesheet classic-hud-green-sheet { src: ../../../Classic/Menu_green.jpg; classic-hud-life-poisoned: 0px 0px 53px 48px; } +@spritesheet classic-hud-blue-sheet { src: ../../../Classic/Menu_blue.jpg; classic-hud-mana: 0px 0px 53px 48px; } +@spritesheet classic-hud-ag-sheet { src: ../../../Classic/Menu03_new_ag.jpg; classic-hud-ag: 0px 0px 15px 36px; } +@spritesheet classic-hud-sd-sheet { src: ../../../Classic/s2/menu01_new2_sd.jpg; classic-hud-sd: 0px 0px 15px 36px; } +@spritesheet classic-hud-party-sheet { src: ../../../Classic/Menu_party.jpg; classic-hud-party-open: 0px 0px 24px 24px; } +@spritesheet classic-hud-character-sheet { src: ../../../Classic/Menu_character.jpg; classic-hud-character-open: 0px 0px 24px 24px; } +@spritesheet classic-hud-inventory-sheet { src: ../../../Classic/Menu_inventory.jpg; classic-hud-inventory-open: 0px 0px 24px 24px; } +@spritesheet classic-hud-guild-sheet { src: ../../../Classic/Guild.jpg; classic-hud-guild-open: 0px 0px 52px 18px; } +@spritesheet classic-hud-command-sheet { src: ../../../Classic/s1/menu01_new2.jpg; classic-hud-command-open: 0px 0px 53px 19px; } +@spritesheet classic-hud-friend-sheet { src: ../../../Classic/s1/win_push.jpg; classic-hud-friend-open: 0px 0px 52px 18px; } +@spritesheet classic-hud-letter-sheet { src: ../../../Classic/s1/win_letter.jpg; classic-hud-letter: 0px 0px 15px 9px; } + +/* What the classic bar does not have: the S6 flat fills, the cash shop and menu buttons (Esc opens + the menu), the fourth item hotkey, the five-slot skill row and its + highlight, the EXP frame art (the line is drawn on the bar's own art) and the readouts' + current/max variant. */ +#gauge_fill_left, #gauge_fill_right, #item_band_fill, #skill_band_fill, #gauge_frame, +#btn_cshop, #btn_window, .alert-dot, .btn-icon-label, +#item_slot_3, .slot-hotkey-label, +#skill_slot_0, #skill_slot_1, #skill_slot_2, #skill_slot_3, #skill_slot_4, #skill_list_highlight, +.exp-frame, .gauge-num.value-full, .gauge-fill-horizontal { + display: none; +} + +#hud_layout { position: absolute; left: 50%; bottom: 0; margin-left: -320dp; + width: 640dp; height: 48dp; overflow: visible; pointer-events: none; } +#hud_layout.workspace-placed { margin-left: 0; bottom: auto; transform-origin: left top; } +.hud-part { + position: absolute; + font-family: "token(font-body)"; + font-size: 9dp; +} + +/* The bar and its dragons (0.97: bar at y 432, dragons 108x45 at x 0 and 532, y 387). The bar + takes the pointer so clicks on it don't reach the world; the dragons don't. A window docked on a + side covers that side's dragon, as in 0.97: the theme stacks the HUD under the windows + (theme.ini [Stacking]). + On a wide screen the bar is centred and the windows dock at the screen's edge, so a docked + window would cover only part of the right dragon. The right dragon therefore hides whole while + the windows docked on the right (--world-right, the uncovered world's right edge in screen + pixels) reach past the bar's right end (50vw + 320dp: the bar is centred and one px here is + one screen px): its width is 108dp, minus that overlap magnified a thousand times, clamped to + 0..108dp, i.e. all or nothing. The left side has no docked windows. */ +#hud_strip { left: 0dp; top: 0dp; width: 640dp; height: 48dp; pointer-events: auto; } +.frame-art { position: absolute; top: 0dp; height: 48dp; pointer-events: none; } +#frame_left { left: 0dp; width: 256dp; decorator: image(classic-hud-bar-left); } +#frame_middle { left: 256dp; width: 128dp; decorator: image(classic-hud-bar-middle); } +#frame_right { left: 384dp; width: 256dp; decorator: image(classic-hud-bar-right); } +#dragon_left { left: 0dp; top: -45dp; width: 108dp; height: 45dp; decorator: image(classic-hud-dragon); } +#dragon_right { + left: 532dp; + top: -45dp; + width: clamp(0dp, calc(108dp + (var(--world-right, 100vw) - 50vw - 320dp) * 1000), 108dp); + height: 45dp; + decorator: image(classic-hud-dragon flip-horizontal); +} + +/* Life (x 97), mana (x 489) and AG (x 551, 15x36 standing on y 473). Each fills from the bottom: + the box is the filled height and the art keeps its size, cropped from the top, as 0.97 moved + the quad's top and its texture rows together. The SD column is the Season 2 client's + (FUN_005eb880): 15x36 at x 73 standing on y 474, in the bar's recess left of the life orb, + filled the same way. */ +#gauges_left { left: 97dp; top: 0dp; width: 53dp; height: 48dp; } +#gauges_right { left: 489dp; top: 0dp; width: 77dp; height: 48dp; } +.gauge-slot { position: absolute; pointer-events: auto; } +#bar_hp { left: 0dp; top: 0dp; width: 53dp; height: 48dp; } +#bar_mp { left: 0dp; top: 0dp; width: 53dp; height: 48dp; } +#bar_ag { left: 62dp; top: 5dp; width: 15dp; height: 36dp; } +#bar_sd { left: -24dp; top: 6dp; width: 15dp; height: 36dp; } +.gauge-fill { position: absolute; left: 0; bottom: 0; width: 100%; } +.gauge-fill-hp { decorator: image(classic-hud-life cover left bottom); } +.gauge-fill-hp.poisoned { decorator: image(classic-hud-life-poisoned cover left bottom); } +.gauge-fill-mp { decorator: image(classic-hud-mana cover left bottom); } +.gauge-fill-ag { decorator: image(classic-hud-ag cover left bottom); } +.gauge-fill-sd { decorator: image(classic-hud-sd cover left bottom); } + +/* The current values, centred under each gauge at y 467 (0.97 drew sprite digits 9x10 from + Interface\FontTest; plain bold text here): mana at 540 (528 here, below), AG at 571; the Season 2 + client's SD at 98 and life at 140 (0.97, without the SD column: life at 100). */ +.gauge-num { + position: absolute; + z-index: 1; + top: 35dp; + width: 60dp; + font-size: 10dp; + line-height: 10dp; + text-align: center; + color: #ffffff; + font-weight: bold; + font-effect: outline(1px #000000); + white-space: nowrap; + pointer-events: none; +} +#bar_hp .gauge-num { left: 13dp; } +#bar_sd .gauge-num { left: -5dp; top: 29dp; } +/* Mana 12 left of 0.97's 540 (at 528, still over the orb): the AG value is centred only 31 to its + right, and with five-digit mana and four-digit AG (high-level characters) 0.97's own numbers run + into each other. The AG cannot move right (the Guild button starts at 582). */ +#bar_mp .gauge-num { left: 9dp; } +#bar_ag .gauge-num { left: -10dp; top: 30dp; } + +/* The hero's coordinates in the box at the left end, centred at x 24 and 48, y 462. */ +#coords { left: 0dp; top: 30dp; width: 72dp; height: 9dp; } +.coord { + position: absolute; + top: 0dp; + width: 30dp; + font-size: 9dp; + line-height: 9dp; + text-align: center; + color: #ffffff; + font-weight: bold; + font-effect: outline(1px #000000); + white-space: nowrap; + pointer-events: none; +} +#coord_x { left: 9dp; } +#coord_y { left: 33dp; } + +/* Party, Character and Inventory (24x24 at x 348, 379 and 410, y 452) and Guild (52x18 at 582, + 459). The buttons are part of the bar's art; an open window shows the button pressed. */ +#buttons { left: 348dp; top: 20dp; width: 286dp; height: 25dp; } +.frame-btn { position: absolute; top: 0dp; width: 24dp; height: 24dp; cursor: pointer; pointer-events: auto; } +#btn_party { left: 0dp; } +#btn_chainfo { left: 31dp; } +#btn_myinven { left: 62dp; } +#btn_guild { left: 234dp; top: 7dp; width: 52dp; height: 18dp; } +#btn_party.open { decorator: image(classic-hud-party-open); } +#btn_chainfo.open { decorator: image(classic-hud-character-open); } +#btn_myinven.open { decorator: image(classic-hud-inventory-open); } +#btn_guild.open { decorator: image(classic-hud-guild-open); } + +/* The Season 1 client's command window button (Season 2's FUN_0040af9e): the bar's top-left box, + 53x19 at (6, 435), drawn lit (menu01_new2) while the command window is open, its hint under the + mouse. */ +#btn_command { left: -342dp; top: -17dp; width: 53dp; height: 19dp; } +#btn_command.open { decorator: image(classic-hud-command-open); } + +/* The Season 1 client's friend button (00493930): the bar's top-right box, 52x18 at (582, 435), + drawn pressed (win_push) while the friend window is open. A new letter or chat blinks Season 1's + letter (win_letter, 15x9) at 33, 5 in it (36, 7 pressed); Season 1 blinks a figure (win_man) for + a chat, which the HUD's one alert flag cannot tell apart. */ +#btn_friend { left: 234dp; top: -17dp; width: 52dp; height: 18dp; } +#btn_friend.open { decorator: image(classic-hud-friend-open); } +#btn_friend .alert-dot { display: block; position: absolute; left: 33dp; top: 5dp; width: 15dp; height: 9dp; decorator: image(classic-hud-letter); } +#btn_friend.open .alert-dot { left: 36dp; top: 7dp; } +#btn_friend .alert-dot.hidden { display: none; } + +/* Experience: a 4-unit line at (221, 439), 198 long for one tenth of the level, with the tenth + (0-9) at x 425, y 434. The part is the hint area (219-421 x 439-445). */ +#exp { left: 219dp; top: 7dp; width: 202dp; height: 6dp; pointer-events: auto; } +#exp_track { position: absolute; left: 2dp; top: 0dp; width: 198dp; height: 4dp; } +#exp_fill { position: absolute; left: 0; top: 0; height: 100%; background-color: #ebcc57; } +#exp_digit { + position: absolute; + left: 196dp; + top: -5dp; + width: 20dp; + font-size: 10dp; + line-height: 10dp; + text-align: center; + color: #e8cf99; + font-weight: bold; + font-effect: outline(1px #000000); + pointer-events: none; +} + +/* Item hotkeys Q, W, E: the item's 3D icon in a 20x20 box at x 208 + 31i, y 454 (the letters are + in the bar's art). */ +#item_slots { left: 208dp; top: 22dp; width: 82dp; height: 20dp; } +#item_slot_0 { position: absolute; left: 0dp; top: 0dp; width: 20dp; height: 20dp; } +#item_slot_1 { position: absolute; left: 31dp; top: 0dp; width: 20dp; height: 20dp; } +#item_slot_2 { position: absolute; left: 62dp; top: 0dp; width: 20dp; height: 20dp; } +.item-icon { position: absolute; left: 0; top: 0; width: 20dp; height: 20dp; pointer-events: none; } +/* The stack count in the bar's oval right of each slot: 0.97 draws it with RenderNumber (005122f0, + 9x10 digits, 6.3 apart) at x 226 + 31i, y 447 (004be48b), which puts a two- or three-digit + count's middle about x 17 from the slot and its digits from y 447 to 457. */ +.item-stack-label { + position: absolute; + left: 17dp; + top: -7dp; + transform: translateX(-50%); + color: #ffffff; + font-weight: bold; + font-effect: outline(1px #000000); + font-size: 11dp; + line-height: 10dp; + white-space: nowrap; + pointer-events: none; +} +#item_slot_0, #item_slot_1, #item_slot_2, #current_skill_slot { + pointer-events: auto; + cursor: pointer; +} + +/* Skills (0.97): the current skill sits in the ring at x 304, y 444 (32x36, tinted (1, 0.9, 0.8)); + a click opens the list: every learned skill in one row of 32x36 cells centred on x 320 at y 370 + (each cell takes the pointer down to y 412), the current one tinted like the ring, the rest + (0.6, 0.7, 0.8). Each cell carries its hotkey digit centred at x + 4, y + 26. The icons are + legacy's (skill_icons.rcss, 20x28, centred in the cell): the classic clients' Skill.jpg has no + icon for the skills added later, and 0.97 drew its 32x36 icons with their own stone frame. */ +#skill_slots { left: 304dp; top: 12dp; width: 32dp; height: 36dp; } +#current_skill_slot { position: absolute; left: 0dp; top: 0dp; width: 32dp; height: 36dp; } +.skill-icon { + position: absolute; + left: 6dp; + top: 4dp; + width: 20dp; + height: 28dp; + pointer-events: none; + image-color: #b3c0cc; +} +#current_skill_slot .skill-icon, .skill-cell.selected .skill-icon { image-color: #ffe6cc; } +.cooldown-wipe { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + background-color: rgba(255, 128, 128, 128); + pointer-events: none; +} +.skill-hotkey-label { + position: absolute; + left: -6dp; + top: 26dp; + width: 20dp; + text-align: center; + color: #ffffff; + font-weight: bold; + font-effect: outline(1px #000000); + font-size: 10dp; + line-height: 10dp; + white-space: nowrap; + pointer-events: none; +} + +#skill_list { left: 0dp; top: -62dp; width: 640dp; height: 42dp; } +#skill_grid { + position: absolute; + left: 0; + top: 0; + width: 640dp; + height: 42dp; + display: flex; + flex-direction: row; + justify-content: center; + pointer-events: none; +} +/* The id rule above outranks base.rcss's .hidden: closing the list needs its own rule. */ +#skill_grid.hidden { display: none; } +.skill-cell { + position: relative; + flex: 0 0 auto; + width: 32dp; + height: 42dp; + pointer-events: auto; + cursor: pointer; +} +.skill-cell .cooldown-wipe { bottom: auto; top: 0; max-height: 36dp; } +/* The Dark Lord's pet commands (0.97 has no Dark Lord): their own row of the same cells, centred + just above the skill row, while the list is open. */ +#pet_skill_row { + position: absolute; + left: 0; + top: -42dp; + width: 640dp; + height: 42dp; + display: flex; + flex-direction: row; + justify-content: center; + pointer-events: none; +} +#pet_skill_row.hidden { display: none; } + diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/main_frame.rml b/src/bin/Data/Interface/RmlUi/themes/classic/main_frame.rml new file mode 100644 index 0000000000..2af589fa49 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/main_frame.rml @@ -0,0 +1,169 @@ + + + + Main Frame + + + + + + + + +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+ {{hp_current_text}} + {{hp_text}} +
+
+
+
+ {{sd_current_text}} + {{sd_text}} +
+
+
+
+
+
+ {{ag_current_text}} + {{ag_text}} +
+
+
+
+ {{mp_current_text}} + {{mp_text}} +
+
+ + +
+ +
+
+
+
+ SHOP +
+
+ CHAR +
+
+
+ INV +
+
+ FRIEND +
+
+
+ MENU +
+
+ + +
+ {{coord_x}} + {{coord_y}} +
+ + +
+
+
+
+
+
+
+ {{exp_digit}} +
+ + +
+
Q{{item_slot_0_count}}
+
W{{item_slot_1_count}}
+
E{{item_slot_2_count}}
+
R{{item_slot_3_count}}
+
+ +
+
+
{{skill_slot_0_hotkey}}
+
{{skill_slot_1_hotkey}}
+
{{skill_slot_2_hotkey}}
+
{{skill_slot_3_hotkey}}
+
{{skill_slot_4_hotkey}}
+
{{current_skill_hotkey}}
+
+ + +
+
+ +
+
+ {{cell.hotkey}} +
+
+
+
+
+
+ {{cell.hotkey}} +
+
+
+
+
+ +
diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/map_name.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/map_name.rcss new file mode 100644 index 0000000000..e1492b67d1 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/map_name.rcss @@ -0,0 +1,3 @@ +/* Classic (0.97): 0.97 shows no map title when the hero enters a map, so the banner is hidden. */ + +#banner { display: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/master_level.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/master_level.rcss new file mode 100644 index 0000000000..630dc792cf --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/master_level.rcss @@ -0,0 +1,142 @@ +/* Classic theme for the master skill tree (CMasterLevel). 0.97 and the Season 1/2 clients have no + Master Level: a black ground edged by a 1-unit line + (230, 230, 153) with the three columns between such lines, as the classic pet window's (Season 1) + frames of lines, each skill on a 0.97 item cell (Item_box) behind its icon, and the 0.97 Close + (Exit_01, Exit_02 pressed) at the top-right; the tree's arrows keep the Season 3 art. Legacy's + rules first, then the classic ones. */ + +/* Legacy theme for CMasterLevel -- the master skill tree, reproducing the original's Render(): + the two background textures, per node the box, the lit or grey icon, the arrow and the level, + the close button and the header text. Every coordinate is the original's, in reference px + (#panel carries the HUD board's scale, see master_level.rml). Sprite rectangles are texels + of the power-of-two textures the engine loads (a 50x38 box inside a 64x64 texture): each covers + exactly the UV rectangle the original drew. Icons come from master_skill_icons.rcss. */ + +@spritesheet master-back-left-sheet { src: "../../../new_Master_back01.jpg"; master-back-left: 0px 0px 512px 428px; } +@spritesheet master-back-right-sheet { src: "../../../new_Master_back02.jpg"; master-back-right: 0px 0px 128px 428px; } +@spritesheet master-box-sheet { src: "../../../new_Master_box.tga"; master-box: 0px 0px 50px 38px; } +@spritesheet master-exit-sheet +{ + src: "../../../new_Master_exit.jpg"; + master-exit-up: 0px 0px 13px 14px; + master-exit-down: 0px 14px 13px 14px; +} +@spritesheet master-arrow-1-sheet { src: "../../../new_Master_arrow01.tga"; master-arrow-1: 0px 0px 28px 7px; } +@spritesheet master-arrow-2-sheet { src: "../../../new_Master_arrow02.tga"; master-arrow-2: 0px 0px 28px 7px; } +@spritesheet master-arrow-3-sheet { src: "../../../new_Master_arrow03.tga"; master-arrow-3: 0px 0px 7px 12px; } +/* The original draws only the top 48 texels of this 7x52 arrow (UV 12/16 of its 8x64 texture), + stretched over 52 units. */ +@spritesheet master-arrow-4-sheet { src: "../../../new_Master_arrow04.tga"; master-arrow-4: 0px 0px 7px 48px; } +@spritesheet master-arrow-5-sheet { src: "../../../new_Master_arrow05.tga"; master-arrow-5: 0px 0px 42px 31px; } +@spritesheet master-arrow-6-sheet { src: "../../../new_Master_arrow06.tga"; master-arrow-6: 0px 0px 42px 31px; } +@spritesheet master-arrow-7-sheet { src: "../../../new_Master_arrow07.tga"; master-arrow-7: 0px 0px 40px 28px; } +@spritesheet master-arrow-8-sheet { src: "../../../new_Master_arrow08.tga"; master-arrow-8: 0px 0px 40px 28px; } + +/* The whole 640x428 tree claims the cursor, as the original's UpdateMouseEvent() did. */ +#panel { + position: absolute; + left: 0; + top: 0; + width: 640px; + height: 428px; + font-family: "token(font-body)"; + pointer-events: auto; +} + +#back_left, #back_right { position: absolute; top: 0; height: 428px; } +#back_left { left: 0; width: 512px; decorator: image(master-back-left); } +#back_right { left: 512px; width: 128px; decorator: image(master-back-right); } + +.node { position: absolute; width: 50px; height: 38px; } +.node-box { position: absolute; left: 0; top: 0; width: 50px; height: 38px; decorator: image(master-box); } +.node-icon { position: absolute; left: 8px; top: 5px; width: 20px; height: 28px; } + +/* Arrow offsets from the node box, as RenderIcon() placed each direction. */ +.node-arrow { position: absolute; pointer-events: none; } +.arrow-1 { left: 30px; top: 14px; width: 28px; height: 7px; decorator: image(master-arrow-1); } +.arrow-2 { left: 30px; top: 14px; width: 28px; height: 7px; decorator: image(master-arrow-2); } +.arrow-3 { left: 14.5px; top: 35px; width: 7px; height: 12px; decorator: image(master-arrow-3); } +.arrow-4 { left: 14.5px; top: 35px; width: 7px; height: 52px; decorator: image(master-arrow-4); } +.arrow-5 { left: 0; top: 0; width: 42px; height: 31px; decorator: image(master-arrow-5); } +.arrow-6 { left: 0; top: 0; width: 42px; height: 31px; decorator: image(master-arrow-6); } +.arrow-7 { left: 16.5px; top: 36px; width: 40px; height: 28px; decorator: image(master-arrow-7); } +.arrow-8 { left: 0; top: 0; width: 40px; height: 28px; decorator: image(master-arrow-8); } + +/* Text leaves: native left-aligned RenderText() at a reference point, on the black box the + original's SetBgColor(0, 0, 0, 1) leaves behind every text of this window (the level texts + inherit it from the previous frame). Spaces are kept: the EXP value is %6.2f, space-padded. */ +.text { + display: block; + position: absolute; + transform-origin: left top; + white-space: pre; + background-color: #000000; + pointer-events: none; +} + +/* The level, RenderText(CalcX + 38, CalcY + 23): white on a node that can be raised, else + RGBA(120, 120, 120). */ +.node-level { left: 38px; top: 23px; color: #ffffff; } +.node.locked .node-level { color: #787878; } + +/* The close button, native CButton at (611, 9) 13x14: the pressed frame is the texture's lower + half. */ +#close { + position: absolute; + left: 611px; + top: 9px; + width: 13px; + height: 14px; + decorator: image(master-exit-up); + cursor: pointer; +} +#close:active { decorator: image(master-exit-down); } + +/* Header line: SetTextColor(255, 255, 255). */ +.head-text { top: 11px; color: #ffffff; } +#class_name { left: 154px; } +#master_level { left: 275px; } +#level_point { left: 372px; } +#experience { left: 466px; } +#experience_area { position: absolute; left: 458px; top: 11px; width: 81px; height: 10px; } + +/* Column totals: SetTextColor(255, 155, 0). Native asked for RT3_SORT_CENTER without a box, which + the text renderer draws left-aligned at the point. */ +.column-text { top: 40px; color: #ff9b00; } +#column_0 { left: 92px; } +#column_1 { left: 302px; } +#column_2 { left: 513px; } + +/* The tree's own grid, which the original computed per node: a group's column, 49 units a slot + across it, and 55 plus 41 units a rank down. A rank past the screen was off the tree natively + too, so the table stops where the 480-unit screen does. */ +.node.column-0 { left: 11px; } +.node.column-1 { left: 221px; } +.node.column-2 { left: 431px; } +.node.slot-0 { margin-left: 0; } +.node.slot-1 { margin-left: 49px; } +.node.slot-2 { margin-left: 98px; } +.node.slot-3 { margin-left: 147px; } +.node.rank-1 { top: 55px; } +.node.rank-2 { top: 96px; } +.node.rank-3 { top: 137px; } +.node.rank-4 { top: 178px; } +.node.rank-5 { top: 219px; } +.node.rank-6 { top: 260px; } +.node.rank-7 { top: 301px; } +.node.rank-8 { top: 342px; } +.node.rank-9 { top: 383px; } +.node.rank-10 { top: 424px; } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet ml-classic-cell-sheet { src: ../../../Classic/Item_box.jpg; ml-classic-cell: 0px 0px 32px 32px; } +@spritesheet ml-classic-exit-sheet { src: ../../../Classic/Exit_01.jpg; ml-classic-exit: 0px 0px 24px 24px; } +@spritesheet ml-classic-exit2-sheet { src: ../../../Classic/Exit_02.jpg; ml-classic-exit-pressed: 0px 0px 24px 24px; } +#back_left { left: 0; width: 640px; decorator: none; background-color: #000000; + box-sizing: border-box; border: 1px rgb(230, 230, 153); } +/* The middle column's two edges. */ +#back_right { left: 214px; top: 32px; width: 212px; height: 392px; decorator: none; box-sizing: border-box; + border-left: 1px rgb(230, 230, 153); border-right: 1px rgb(230, 230, 153); } +.node-box { left: 6px; top: 3px; width: 24px; height: 32px; decorator: image(ml-classic-cell fill); } +#close { left: 610px; top: 4px; width: 24px; height: 24px; decorator: image(ml-classic-exit); } +#close:active { decorator: image(ml-classic-exit-pressed); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/match_status.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/match_status.rcss new file mode 100644 index 0000000000..13fd9e5009 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/match_status.rcss @@ -0,0 +1,73 @@ +/* Classic theme for a guild war's or battle soccer's time and result (match_status.rml is forked + here). The 0.97 client (004bc220) draws the time with the score at the top of the + area the open windows leave free: "Time" at (centre + 80, 4) and the minutes:seconds under it at + 17, (255, 200, 150) in the normal font on a black 50% box. Here the bound text carries its own + label, so it is one line at (centre + 80, 4). 0.97 has no result panel: the classic + one is the 0.97 box (Message_box1 stones between Message_box2 edges) with legacy's layout and + 0.97's OK. Legacy's rules first, then the classic ones. */ + +/* Legacy theme for a guild war's or battle soccer's time and result (see match_status.rml), + reproducing the original's RenderTournamentInterface(): the big countdown at 350 on the + uncovered world's centre, red -- yellow in its last minute or before the start -- with a white + copy one pixel down and right; the result panel (300 x 210 at 170, 120) with the big title, + "VS" in yellow, the team names right-aligned under it at 50, their scores at (45, 75) and + (215, 75), and the big outcome at (47, 115) and (218, 115) or the tie centred, and ok.jpg's + 70 x 20 button (ok2.jpg under the pointer) at (115, 160). The original's frame textures were + never loaded, so the panel is a dark fill here; the winner reads yellow and the loser red where + the original coloured by side and all but hid the left one. Reference px. */ + +@spritesheet ms-ok-sheet { src: "../../../ok.jpg"; ms-ok: 0px 0px 70px 20px; } +@spritesheet ms-ok-over-sheet { src: "../../../ok2.jpg"; ms-ok-over: 0px 0px 70px 20px; } + +body { pointer-events: none; } +#hud, #stage { pointer-events: none; font-family: "token(font-body)"; } + +#countdown { position: absolute; top: 350px; width: 0; height: 0; } +#countdown .sharp-text { position: absolute; top: 0; white-space: nowrap; } +.countdown-shadow { color: rgb(255, 10, 10); } +#countdown.soon .countdown-shadow { color: rgb(255, 255, 10); } +.countdown-face { margin-top: 1px; padding-left: 2px; color: #ffffff; } + +#result { position: absolute; left: 170px; top: 120px; width: 300px; height: 210px; } +#result_back { position: absolute; left: 0; top: 0; width: 300px; height: 210px; background-color: rgba(0, 0, 0, 200); border: 1px rgb(90, 80, 60); } +#result .sharp-text { position: absolute; top: 0; white-space: nowrap; color: #ffffff; } +.result-line { position: absolute; left: 0; width: 300px; height: 0; } +.result-cell { position: absolute; height: 0; } +#result_title { top: 20px; } +#result_title .sharp-text { color: rgb(200, 240, 255); } +#result_vs { top: 50px; } +#result_vs .sharp-text { color: rgb(255, 255, 10); } +#result_team1 { left: 0; top: 50px; width: 65px; } +#result_team2 { left: 170px; top: 50px; width: 65px; } +#result_team1 .sharp-right, #result_team2 .sharp-right { right: 0; } +#result_score1 { left: 45px; top: 75px; } +#result_score2 { left: 215px; top: 75px; } +#result_outcome1 { left: 47px; top: 115px; } +#result_outcome2 { left: 218px; top: 115px; } +#result_outcome1 .sharp-text, #result_outcome2 .sharp-text { color: rgb(255, 10, 10); } +#result_outcome1.win .sharp-text, #result_outcome2.win .sharp-text { color: rgb(255, 255, 10); } +#result_tie { top: 115px; } +#result_tie .sharp-text { color: rgb(255, 255, 10); } + +#result_ok { position: absolute; left: 115px; top: 160px; width: 70px; height: 20px; decorator: image(ms-ok); pointer-events: auto; cursor: pointer; } +#result_ok:hover { decorator: image(ms-ok-over); } +.ok-label { display: none; } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet ms-classic-stone-sheet { src: ../../../Classic/Message_box1.jpg; ms-classic-stone: 0px 0px 213px 40px; } +@spritesheet ms-classic-edge-sheet { src: ../../../Classic/Message_box2.jpg; ms-classic-edge: 0px 0px 213px 5px; } +#countdown { top: 4px; margin-left: 80px; } +#countdown .sharp-text, #countdown.soon .sharp-text { color: rgb(255, 200, 150); background-color: rgba(0, 0, 0, 128); padding: 0; margin: 0; } +/* Five stones, each stretched to the box's width (as Season 2 stretched them for wider boxes), so + both side borders show; 5 + 5 * 40 + 5 = 210. */ +#result_back { display: none; } +.result-stones { position: static; } +.result-stone { position: absolute; left: 0; width: 300px; height: 40px; decorator: image(ms-classic-stone fill); } +.result-stone:nth-child(1) { top: 5px; } +.result-stone:nth-child(2) { top: 45px; } +.result-stone:nth-child(3) { top: 85px; } +.result-stone:nth-child(4) { top: 125px; } +.result-stone:nth-child(5) { top: 165px; } +.result-edge { position: absolute; left: 0; width: 300px; height: 5px; decorator: image(ms-classic-edge fill); } +#result_edge_top { top: 0; } +#result_edge_bottom { top: 205px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/match_status.rml b/src/bin/Data/Interface/RmlUi/themes/classic/match_status.rml new file mode 100644 index 0000000000..f4118a4898 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/match_status.rml @@ -0,0 +1,65 @@ + + + + Match Status + + + + + +
+ +
+
{{countdown}}
+
+
+ +
+
+
+
+
+
+
+ {{title}} +
+
+ {{vs}} +
+
+ {{team1}} +
+
+ {{team2}} +
+
+ ({{score1}}) +
+
+ ({{score2}}) +
+
+ {{outcome1}} +
+
+ {{outcome2}} +
+
+ {{tie_text}} +
+
+ OK +
+
+
+ +
diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/message_box_view.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/message_box_view.rcss new file mode 100644 index 0000000000..17a787fd57 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/message_box_view.rcss @@ -0,0 +1,224 @@ +/* Classic (0.97) look for a native message box drawn by MessageBoxView: 0.97's tall box from + RenderMessageBox (0051af50) -- Message_box2 (213x5) as the top and bottom edges, Message_box1 + (213x40, the stone with its golden sides) stacked between them, 213 wide and centred (x 213..426 + of the 640x480 frame), its top at y 60 for the server and event texts and at y 100 for the + confirmations -- and 0.97's OK plate, Ok / Ok2 (70x21, the second image under the mouse), + centred at x 284. + Two of the kinds are 0.97 boxes, placed as 0.97 placed them: + - "blood-castle-result" (opened by 0051da80, drawn by 0051db00): four strips (213x170) at y 60, + the outcome on two lines at y 70 and 86, the experience at 106 and the zen at 130, OK at + (284, 190); + - "devil-square-rank" (opened by 0051d9e0, drawn by 0051ddf0): seven strips (213x290) at y 60, + the title at (229, 70) and the "your bravery" line at (229, 86), the column headers at y 110, + the rows from 126, 16 apart, OK at (284, 320). + The others ("progress", "gem-disjoint", "chaos-castle-result", "guild-appoint") have no 0.97 + counterpart: they keep legacy's S6 frame heights (the 67 cap, 15 per strip, the 50 foot), lines + and buttons, at y 100 like legacy, only narrowed to 0.97's 213 -- every x that legacy centred on + its 230 box is 8.5 less, so it stays centred on this one. + The box is the original 213 wide, so its edges are the original Message_box2: legacy's 230 (and + the derived Message_box2_230) is not needed. + + Copied from legacy's message_box_view.rcss (a theme sheet replaces the whole file). Reference px + inside #panel, on the 640x480 .stage; text at the native size in the counter-scaled #lines, as + legacy. What 0.97 does not have (the jewel list, the table's rules, the labelled buttons) keeps + legacy's rules, the labelled buttons on 0.97's Bar plate; the progress bar is Season 1's. */ + +@spritesheet classic-box-edge-sheet { src: ../../../Classic/Message_box2.jpg; classic-box-edge: 0px 0px 213px 5px; } +@spritesheet classic-box-stone-sheet { src: ../../../Classic/Message_box1.jpg; classic-box-stone: 0px 0px 213px 40px; } +@spritesheet classic-box-btn-sheet { src: ../../../Classic/Bar.jpg; classic-box-btn: 0px 0px 40px 18px; } +@spritesheet classic-box-ok-sheet { src: ../../../Classic/Ok.jpg; classic-box-ok: 0px 0px 70px 21px; } +@spritesheet classic-box-ok2-sheet { src: ../../../Classic/Ok2.jpg; classic-box-ok-hover: 0px 0px 70px 21px; } + +@spritesheet box-separator-sheet { src: "../../../newui_separate_line.jpg"; box-separator: 0px 0px 205px 2px; } +@spritesheet box-progress-back-sheet { src: ../../../Classic/Progress_back.jpg; box-progress-back: 0px 0px 200px 16px; } +@spritesheet box-progress-bar-sheet { src: ../../../Classic/Progress_add.tga; box-progress-bar: 0px 0px 200px 16px; } + +/* 0.97's boxes: centred on the 640x480 stage (x 213), the top at 100 (the confirmations), at 60 + for the event results 0.97 has (the Blood Castle result and the Devil Square ranking). */ +#stage { pointer-events: none; } +#panel { position: absolute; left: 213px; top: 100px; width: 213px; font-family: "token(font-body)"; pointer-events: auto; } +#panel[data-kind="blood-castle-result"], #panel[data-kind="devil-square-rank"] { top: 60px; } +/* The stone between the two edges: Message_box1 stretched over the box's height (0.97 stacked + whole 40-unit strips; its gold sides are vertical, so stretching keeps them). The box is on the + .stage, whose transform already scales it: a decorator drawn at the image's own size + (scale-none, repeat) would be scaled twice and spill past the box, so every piece of art here + fits its element's box. Legacy's newui_msgbox_back fill (222 wide, from y 2 to 8 above the + bottom) is dropped: 0.97's stone is opaque and has no backing. */ +#back { position: absolute; left: 0; top: 5px; bottom: 5px; width: 213px; decorator: image(classic-box-stone fill); } +/* The frame stacks by flow: the cap, then one element per strip C++ reported, then the foot. Their + heights are the box's height and live only here -- C++ used to add them up itself. Legacy's + heights (the cap 67, the strips 15, the foot 50) stay, since the S6 boxes' lines and buttons are + placed by them; the stone shows through them, the top edge rides the cap and the bottom edge the + frame's own bottom, each fitted to the box's width (contain). Legacy's newui_msgbox_top / middle + / bottom art is dropped for 0.97's. */ +#frame { position: relative; display: block; width: 213px; decorator: image(classic-box-edge contain left bottom); } +#box_top { display: block; width: 213px; height: 67px; decorator: image(classic-box-edge contain left top); } +#box_bottom { display: block; width: 213px; height: 50px; } +.box-strip { display: block; } +.box-strip--middle { width: 213px; height: 15px; } +/* Legacy's newui_Message_Line after the Devil Square ranking's 11th strip is dropped: 0.97's + ranking is plain stone, and its fixed 290 (below) leaves that strip's place mid-table. The + strip keeps its height. */ +.box-strip--divider { width: 213px; height: 21px; } +/* The two 0.97 boxes are 0.97's height, whatever C++ reports for the S6 frame: 5 + 40 * N + 5. + The strips inside are art-less spacers, so the part past this height shows nothing; they take + no mouse either (C++ reports 6 strips for the Blood Castle result and 11 + the divider + 3 for + the ranking, 37 and 58 past the box), so a click under the box reaches the world. */ +#panel[data-kind="blood-castle-result"] #frame { height: 170px; } +#panel[data-kind="devil-square-rank"] #frame { height: 290px; } +#panel[data-kind="blood-castle-result"] #frame div, #panel[data-kind="devil-square-rank"] #frame div { pointer-events: none; } +/* Legacy's rules, inside the stone's golden sides (x 0-5 and 207-212). */ +.box-separator { display: none; position: absolute; left: 6px; width: 201px; height: 2px; decorator: image(box-separator); } + +/* CProgressMsgBox's bar as the Season 1 client's message box draws its progress (RE\mains1 + castle_siege_ui.md 0.4, render 00625a20): Progress_back (150x12) centred, and the 0.97 fill + (Progress, an orange line Season 1 adds over it; Progress_add carries that as alpha) over the + same place, as wide as the elapsed fraction of 150. Legacy's height above the bottom edge. */ +#progress_back { position: absolute; left: 31.5px; bottom: 35px; width: 150px; height: 12px; decorator: image(box-progress-back fill); } +#progress_bar { position: absolute; left: 31.5px; bottom: 35px; height: 12px; decorator: image(box-progress-bar fill); } + +.sharp-text { display: block; position: absolute; white-space: nowrap; pointer-events: none; } +/* pre: RenderText() keeps leading and repeated spaces (the result tables' padded numbers). */ + +/* A labelled button: 0.97's Bar plate (40x18) stretched to the button's box, lighter under the + mouse and darker while pressed (0.97's own buttons are lettered art; it has no plain plate with + states). */ +.box-btn { display: block; position: absolute; decorator: image(classic-box-btn); pointer-events: auto; } +.box-btn:hover { image-color: #ffe6b4; } +.box-btn:active { image-color: #b4b4b4; } +.box-btn.disabled, .box-btn.disabled:hover, .box-btn.disabled:active { decorator: image(classic-box-btn); image-color: #99999999; } +.box-label { color: #ffffff; } +.box-btn.disabled .box-label { color: #808080; } + +/* The lettered OK: 0.97's Ok, Ok2 under the mouse (0.97 has no pressed image), untinted -- the + plate's hover / press tint above is not 0.97's; the art is lettered, so the label is hidden. */ +.box-btn.ok-art { decorator: image(classic-box-ok); image-color: #ffffff; } +.box-btn.ok-art:hover { decorator: image(classic-box-ok-hover); image-color: #ffffff; } +.box-btn.ok-art:active { decorator: image(classic-box-ok-hover); image-color: #ffffff; } +.box-btn.ok-art .box-label { display: none; } + +/* The jewel list keeps native text metrics while RmlUi handles scrolling. */ +#list_box { position: absolute; left: 15.5px; top: 64.5px; width: 181px; height: 111px; pointer-events: none; background-color: rgba(0, 0, 0, 102); } +#list { position: absolute; left: 16.5px; top: 65.5px; transform-origin: left top; overflow: hidden scroll; } +.list-row { display: block; position: relative; pointer-events: auto; } +.list-row-back { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; } +.list-row.selected .list-row-back { background-color: rgb(106, 97, 88); } +.list-row-text { position: absolute; left: 3.5714%; top: 23.0769%; white-space: pre; pointer-events: none; color: #e6dcc8; } +.list-row.selected .list-row-text { color: #000000; } + + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#list { width: calc(180px * var(--root-scale)); height: calc(109px * var(--root-scale)); } +.list-row { width: calc(168px * var(--root-scale)); height: calc(13px * var(--root-scale)); } + +/* The lines, in one counter-scaled flow from the box's text top, centred on the box. The progress + notices, the jewel dissolve box and the guild appointment stack each line one native line height + + 4 apart (RenderTexts()); the event results space theirs as below. */ +#lines { left: 0; top: 40px; --flow-w: 213px; text-align: center; } +.box-line { display: block; white-space: pre; } +.box-cell { white-space: pre; } +.box-cell.bold { font-weight: bold; } +#panel[data-kind="progress"] #lines { top: 35px; } +#panel[data-kind="gem-disjoint"] #lines { top: 17px; } +#panel[data-kind="guild-appoint"] #lines { top: 97px; } +#panel[data-kind="progress"] .box-line, #panel[data-kind="gem-disjoint"] .box-line, +#panel[data-kind="guild-appoint"] .box-line { height: calc((var(--line-height, 0px) + 4px) * var(--root-scale)); } +#panel[data-kind="progress"] .box-line.bold, #panel[data-kind="gem-disjoint"] .box-line.bold, +#panel[data-kind="guild-appoint"] .box-line.bold { height: calc((var(--bold-line-height, 0px) + 4px) * var(--root-scale)); } + +/* The Chaos Castle result (S6 only, legacy's RenderMatchResult() spacing): the message 16 apart + from 40, the rewards 30 below it, 20 apart. */ +#panel[data-kind="chaos-castle-result"] .box-line { height: calc(16px * var(--root-scale)); } +#panel[data-kind="chaos-castle-result"] .box-line--message + .box-line--reward { margin-top: calc(14px * var(--root-scale)); } +#panel[data-kind="chaos-castle-result"] .box-line--reward { height: calc(20px * var(--root-scale)); } + +/* The Blood Castle result (0051db00): the outcome from 10 (y 70), 16 apart, the rewards 20 below + the outcome's last line (y 106), 24 apart (y 130). The outcome is one translated sentence, + wrapped to the box's text width -- legacy's 10 clear of each side -- each line 16 apart. */ +#panel[data-kind="blood-castle-result"] #lines { top: 10px; } +#panel[data-kind="blood-castle-result"] .box-line { height: calc(16px * var(--root-scale)); } +#panel[data-kind="blood-castle-result"] .box-line--message + .box-line--reward { margin-top: calc(4px * var(--root-scale)); } +#panel[data-kind="blood-castle-result"] .box-line--reward { height: calc(24px * var(--root-scale)); } +#panel[data-kind="blood-castle-result"] .box-line--message { height: auto; white-space: normal; width: calc(193px * var(--root-scale)); + margin: 0 auto; line-height: calc(16px * var(--root-scale)); } +#panel[data-kind="blood-castle-result"] .box-line--message .box-cell { white-space: normal; } + +/* The Devil Square ranking (0051ddf0): the two message lines from (16, 10), 16 apart; the headers + at 50 over the rank, point, experience and reward columns; the rows from 66, 16 apart, the rank + and the name first. 0.97's column x are not known: the columns keep legacy's place on the screen + (legacy's x 8 less, the box being 8 further right), which fits them inside the golden sides. + "My info" and its row (S6's section) follow the table's ten rows at its pitch, at 226 and 242, + above 0.97's OK at 260. */ +#panel[data-kind="devil-square-rank"] #lines { top: 10px; } +#panel[data-kind="devil-square-rank"] .box-line--message { + height: calc(16px * var(--root-scale)); + padding-left: calc(16px * var(--root-scale)); + text-align: left; +} +#panel[data-kind="devil-square-rank"] .box-line--header { position: relative; margin-top: calc(8px * var(--root-scale)); height: calc(16px * var(--root-scale)); } +#panel[data-kind="devil-square-rank"] .box-line--row { position: relative; height: calc(16px * var(--root-scale)); } +#panel[data-kind="devil-square-rank"] .box-line--my-info { position: absolute; left: 0; width: 100%; top: calc(216px * var(--root-scale)); } +#panel[data-kind="devil-square-rank"] .box-line--my-row { position: absolute; left: 0; width: 100%; top: calc(232px * var(--root-scale)); height: calc(16px * var(--root-scale)); } +#panel[data-kind="devil-square-rank"] .box-line--header .box-cell, +#panel[data-kind="devil-square-rank"] .box-line--row .box-cell, +#panel[data-kind="devil-square-rank"] .box-line--my-row .box-cell { position: absolute; top: 0; } +#panel[data-kind="devil-square-rank"] .box-line--header .box-cell:nth-child(1) { left: calc(22px * var(--root-scale)); } +#panel[data-kind="devil-square-rank"] .box-line--header .box-cell:nth-child(2) { left: calc(82px * var(--root-scale)); } +#panel[data-kind="devil-square-rank"] .box-line--header .box-cell:nth-child(3) { left: calc(132px * var(--root-scale)); } +#panel[data-kind="devil-square-rank"] .box-line--header .box-cell:nth-child(4) { left: calc(170px * var(--root-scale)); } +#panel[data-kind="devil-square-rank"] .box-line--row .box-cell:nth-child(1), +#panel[data-kind="devil-square-rank"] .box-line--my-row .box-cell:nth-child(1) { left: calc(7px * var(--root-scale)); } +#panel[data-kind="devil-square-rank"] .box-line--row .box-cell:nth-child(2), +#panel[data-kind="devil-square-rank"] .box-line--my-row .box-cell:nth-child(2) { left: calc(22px * var(--root-scale)); } +#panel[data-kind="devil-square-rank"] .box-line--row .box-cell:nth-child(3), +#panel[data-kind="devil-square-rank"] .box-line--my-row .box-cell:nth-child(3) { left: calc(82px * var(--root-scale)); } +#panel[data-kind="devil-square-rank"] .box-line--row .box-cell:nth-child(4), +#panel[data-kind="devil-square-rank"] .box-line--my-row .box-cell:nth-child(4) { left: calc(132px * var(--root-scale)); } +#panel[data-kind="devil-square-rank"] .box-line--row .box-cell:nth-child(5), +#panel[data-kind="devil-square-rank"] .box-line--my-row .box-cell:nth-child(5) { left: calc(170px * var(--root-scale)); } +/* Legacy's rules over and under the headers, 4 above them and 3 above the rows. Its two rules + around "my info" are dropped: 0.97's 16 pitch leaves no room between the table, "my info", its + row and the OK. */ +#panel[data-kind="devil-square-rank"] .box-separator:nth-child(1) { display: block; top: 46px; } +#panel[data-kind="devil-square-rank"] .box-separator:nth-child(2) { display: block; top: 63px; } + +/* The buttons. The 0.97 results' OK: centred (x 284), at 130 in the Blood Castle box (y 190) and + at 260 in the Devil Square one (y 320); the Chaos Castle result's 20 above the bottom edge, as + legacy. The S6 boxes' buttons as legacy's SetButtonInfo() placed them, 8.5 left for the + narrower box: the jewel dissolve box's Close and Dissolve centred, 21 and 56 above the bottom + edge; the guild appointment's two appointments 114 wide at (48.5, 30) and (48.5, 57), OK and + Close 64 wide at (39.5, 127) and (103.5, 127). */ +#panel[data-kind="blood-castle-result"] .box-btn, #panel[data-kind="chaos-castle-result"] .box-btn, +#panel[data-kind="devil-square-rank"] .box-btn { left: 71px; width: 70px; height: 21px; } +#panel[data-kind="blood-castle-result"] .box-btn { top: 130px; } +#panel[data-kind="devil-square-rank"] .box-btn { top: 260px; } +#panel[data-kind="chaos-castle-result"] .box-btn { bottom: 20px; } +#panel[data-kind="gem-disjoint"] .box-btn { left: 74.5px; width: 64px; height: 29px; } +#panel[data-kind="gem-disjoint"] .box-btn:nth-child(1) { bottom: 21px; } +#panel[data-kind="gem-disjoint"] .box-btn:nth-child(2) { bottom: 56px; } +#panel[data-kind="guild-appoint"] .box-btn { width: 64px; height: 29px; } +#panel[data-kind="guild-appoint"] .box-btn:nth-child(1) { left: 48.5px; top: 30px; width: 114px; } +#panel[data-kind="guild-appoint"] .box-btn:nth-child(2) { left: 48.5px; top: 57px; width: 114px; } +#panel[data-kind="guild-appoint"] .box-btn:nth-child(3) { left: 39.5px; top: 127px; } +#panel[data-kind="guild-appoint"] .box-btn:nth-child(4) { left: 103.5px; top: 127px; } + +/* Scrolling lists: the Season 1 client's win_scrollbar (as the classic social windows'), in place of + base.rcss's S6 track and knob: 13x13 arrows at both ends, the track between two 106,97,88 lines, + a grey thumb sized to the list. */ +@spritesheet mbv-scroll-sheet +{ + src: "../../../win_scrollbar.jpg"; + mbv-scroll-thumb: 0px 1px 11px 1px; + mbv-scroll-up: 0px 3px 13px 13px; + mbv-scroll-down: 0px 16px 13px 13px; +} +.scroll-pane scrollbarvertical { width: 13dp; margin: 0; } +.scroll-pane scrollbarvertical slidertrack { decorator: none; box-sizing: border-box; border-left: 1dp rgb(106, 97, 88); border-right: 1dp rgb(106, 97, 88); } +.scroll-pane scrollbarvertical sliderbar { height: auto; min-height: 6dp; margin: 0 1dp; decorator: image(mbv-scroll-thumb fill); } +.scroll-pane scrollbarvertical sliderbar:active { filter: none; } +.scroll-pane scrollbarvertical sliderarrowdec, +.scroll-pane scrollbarvertical sliderarrowinc { width: 100%; height: 13dp; pointer-events: auto; } +.scroll-pane scrollbarvertical sliderarrowdec { decorator: image(mbv-scroll-up); } +.scroll-pane scrollbarvertical sliderarrowinc { decorator: image(mbv-scroll-down); } +.scroll-pane scrollbarvertical sliderarrowdec:active, +.scroll-pane scrollbarvertical sliderarrowinc:active { filter: brightness(0.7); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/mix_inventory.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/mix_inventory.rcss new file mode 100644 index 0000000000..09f944bde3 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/mix_inventory.rcss @@ -0,0 +1,236 @@ +/* Classic (0.97) Chaos Machine (CMixInventory), from the 0.97 client's 004f27f0: Item_Back01 over Item_Back02 and the Mix + button 0.97 drew -- mix_button1 (44x32, mix_button2 while pressed), lowered from 0.97's (75, 300) + to legacy's y 380 (see .mix-btn). MuMain's recipe texts keep their S6 places, which are 0.97's + in the main: success rate and zen from y 49, the 8x4 grid at (15, 110), the lists from 203. + The rest is legacy's. */ + +#panel { + position: absolute; + transform-origin: left top; + width: 190px; + height: 433px; + font-family: "token(font-body)"; +} + +/* Native RenderFrame() draws every text line bold, the title and tax rate in (220,220,220). */ +#title { + position: absolute; + /* 0.97: a 120-wide box at x 35, y 12, centred. */ + left: 35px; + top: 12px; + width: calc(120px * var(--root-scale)); + text-align: center; + color: #dcdcdc; + font-weight: bold; + font-size: 1em; +} +#title.low { top: 12px; } + +/* Native shrinks the tax line to its 160 box (tax_rate_fit, a transform) rather than wrapping it. */ +/* 0.97 has no tax line. */ +.mix-tax-rate.sharp-text { display: none; } +.mix-tax-rate { + position: absolute; + left: 15px; + top: 25px; + width: calc(160px * var(--root-scale)); + white-space: nowrap; + text-align: center; + color: #dcdcdc; + font-weight: bold; + font-size: 1em; +} +/* The tax line and the descriptions are text layers (.sharp-text, mix_inventory.rml); inside them + .mix-fit shrinks the line to its box around the box's centre (left edge when left-aligned). */ +.mix-fit { display: block; transform-origin: center top; } +.mix-description.left .mix-fit { transform-origin: left top; } + +/* Recipe name (two 10px rows, the second kept even when empty), then success rate and required + zen (20px each, when shown) -- left-aligned at native's fPos_x, over a translucent band. */ +.mix-head { + position: absolute; + left: 15px; + top: 49px; + width: calc(160px * var(--root-scale)); +} +/* .mix-head is a text layer: its row heights are physical (end of file). */ +.mix-row { + display: block; + white-space: nowrap; + font-weight: bold; + font-size: 1em; + color: #d2e6ff; +} +.mix-row.hidden { display: none; } +.mix-text { background-color: rgba(40, 40, 40, 128); } + +/* Prediction / source checklist / status (fixed top 203, 15px rows -- 10 in the socket mixes --, + wrapping like native's CutStr() at ~156px), then the advice after one + blank row. */ +.mix-list { + position: absolute; + left: 15px; + top: 203px; + width: calc(156px * var(--root-scale)); + line-height: calc(15px * var(--root-scale)); +} +.mix-list.socket-prompt { line-height: calc(10px * var(--root-scale)); } +.mix-list.hidden, .mix-head.hidden, .mix-descriptions.hidden { display: none; } +.mix-list-line { + display: block; + font-weight: bold; + font-size: 1em; + color: #dcdcdc; +} +.mix-list-line.hidden { display: none; } +/* The lists are at the native text size, which does not shrink with the window: per unit of the + window it is 7.5 at a dp ratio of 2 but 9.6 at 1.25 and 11.7 at 0.94 (800x600, or 1280x720 at + 75%). There the long recipes (seed extraction) wrapped into more lines and ran down under the + Mix button; on these small canvases the lists' lines are drawn smaller, back to about 8.7 units + (on the lines: the list itself takes C++'s native size inline). */ +@media (max-resolution: 1.3x) { .mix-list .mix-list-line { font-size: 0.85em; } } +@media (max-resolution: 1x) { .mix-list .mix-list-line { font-size: 0.75em; } } +/* Native cuts only the prediction and source lines (CutStr); status and advice run on. */ +/* One native line each, cut at the frame's inner edge (x 182): + nothing covers what native runs on past its frame. */ +.mix-unwrapped { white-space: nowrap; overflow: hidden; } +.mix-advice { display: block; margin-top: calc(15px * var(--root-scale)); } +.mix-advice.socket-prompt { margin-top: calc(10px * var(--root-scale)); } + +/* RenderMixDescriptions(): each line at its own native top (d.top), centred in 160px at x=15 or + left-aligned from x=5, no band, shrunk to fit its box like native (d.fit, as a transform on + .mix-fit: a continuous scale, where font-size steps would be coarse). Native's left box is 200 + wide and runs past the window; here it stays inside it (180). A line still too long at the + minimum size is cut at its box, as native's window cuts it. */ +.mix-descriptions { + position: absolute; + left: 0; + top: 0; + width: 190px; +} +.mix-description { + position: absolute; + left: 5px; /* native's 160 box at x=15, widened to the frame around the same centre (95): */ + width: calc(180px * var(--root-scale)); /* the fit still targets 160 (MixInventory.cpp), the cut is at the frame */ + text-align: center; + white-space: nowrap; + overflow: hidden; + font-weight: bold; + font-size: 1em; +} +.mix-description.left { left: 5px; width: calc(180px * var(--root-scale)); text-align: left; } + +.mix-socket-prompt { + position: absolute; + left: 15px; + top: 280px; + width: calc(160px * var(--root-scale)); + text-align: center; + color: #c8c8c8; + font-weight: bold; + font-size: 1em; +} +.mix-socket-prompt.hidden { display: none; } +/* The socket pane counter-scales so scrollbar input uses physical pixels. */ +.socket-list-box { position: absolute; left: 14px; top: 294px; width: 161px; height: 67px; background-color: rgba(0, 0, 0, 102); } +#socket_list { position: absolute; left: 15px; top: 295px; transform-origin: left top; overflow: hidden scroll; } +.socket-row { position: relative; display: block; pointer-events: auto; } +.socket-row-back { position: absolute; left: 0; top: 0; width: 100%; height: 100%; } +.socket-row.selected .socket-row-back { background-color: rgba(0, 0, 0, 102); } +.socket-line-text { position: absolute; left: 5.4%; top: 0; white-space: nowrap; color: #e6dcc8; } +.socket-row.selected .socket-line-text { color: #000000; } + +/* 44x35 crop of the top-left ("up") frame of the native 2-frame vertical button sheet + (CMixInventory::Create()'s former ChangeButtonInfo(..., 44.f, 35.f)) -- hover uses a CSS + brightness filter instead of the sheet's own "down"/"over" frames, same convention as every + other migrated inv-btn/ext-btn. Centered: (190-44)/2 = 73, top matches the native + `m_Pos.y + 380`. */ +@spritesheet mix-classic-btn1-sheet { src: ../../../Classic/Mix_button1.jpg; mix-classic-btn: 0px 0px 44px 32px; } +@spritesheet mix-classic-btn2-sheet { src: ../../../Classic/Mix_button2.jpg; mix-classic-btn-pressed: 0px 0px 44px 32px; } +/* 0.97 drew it at (75, 300), where its short texts ended; MuMain's lists (from 203, up to about + nine 15-unit lines) and descriptions (to 367) run past that, so it sits at legacy's y 380, under + them, keeping 0.97's x (the Close at (25, 395) is left of it). */ +.mix-btn { + position: absolute; + left: 75px; + top: 380px; + width: 44px; + height: 32px; + cursor: pointer; + pointer-events: auto; + decorator: image(mix-classic-btn); +} +.mix-btn:active { decorator: image(mix-classic-btn-pressed); } +.mix-btn.hidden { display: none; } +.mix-btn.locked { pointer-events: none; image-color: #808080; } + + +/* What each line is telling the player -- the colours native RenderMixDescriptions() and the + source list set, now the theme's. */ +.mix-recipe { color: rgb(255, 48, 48); } +.mix-recipe.ready { color: rgb(255, 255, 48); } +.mix-success { color: rgb(210, 230, 255); } +.mix-success.boosted { color: rgb(255, 255, 48); } +/* Native left the recipe colour set for the zen line unless a success line reset it. */ +.mix-zen { color: rgb(255, 48, 48); } +.mix-zen.ready { color: rgb(255, 255, 48); } +.mix-zen.after-success { color: rgb(210, 230, 255); } +.mix-kind.missing { color: rgb(255, 50, 20); } +.mix-kind.partial { color: rgb(210, 230, 255); } +.mix-kind.ready { color: rgb(255, 255, 48); } +.mix-kind.normal { color: #ffffff; } +.mix-kind.warning { color: rgb(255, 40, 20); } +.mix-kind.loss { color: rgb(255, 0, 0); } +.mix-kind.dim { color: rgb(200, 200, 200); } + +/* RenderMixDescriptions()'s own block: 13-unit rows from y 250, a row lower for castle senior. */ +.mix-description.row-0 { top: 250px; } +.mix-description.row-1 { top: 263px; } +.mix-description.row-2 { top: 276px; } +.mix-description.row-3 { top: 289px; } +.mix-description.row-4 { top: 302px; } +.mix-description.row-5 { top: 315px; } +.mix-description.row-6 { top: 328px; } +.mix-description.row-7 { top: 341px; } +.mix-description.row-8 { top: 354px; } +.mix-descriptions.lowered .mix-description.row-0 { top: 270px; } +.mix-descriptions.lowered .mix-description.row-1 { top: 283px; } +.mix-descriptions.lowered .mix-description.row-2 { top: 296px; } +.mix-descriptions.lowered .mix-description.row-3 { top: 309px; } +.mix-descriptions.lowered .mix-description.row-4 { top: 322px; } +.mix-descriptions.lowered .mix-description.row-5 { top: 335px; } +.mix-descriptions.lowered .mix-description.row-6 { top: 348px; } +.mix-descriptions.lowered .mix-description.row-7 { top: 361px; } +.mix-descriptions.lowered .mix-description.row-8 { top: 374px; } + +/* Native item grid: the first cell's top-left, in #panel's units. */ +.native-anchor { position: absolute; pointer-events: none; } +#item_view { height: 473px; } +#item_grid, #item_grid_counts { left: 15px; top: 110px; width: calc(8 * var(--item-cell)); height: calc(4 * var(--item-cell)); } + +/* The frame. */ + +.bg-fill, .bg-top, .bg-left, .bg-right, .bg-bottom { + position: absolute; + pointer-events: none; +} + +@spritesheet mix-classic-back1-sheet { src: ../../../Classic/Item_back01.jpg; mix-classic-back1: 0px 0px 190px 256px; } +@spritesheet mix-classic-back2-sheet { src: ../../../Classic/Item_Back02.jpg; mix-classic-back2: 0px 0px 190px 177px; } +.bg-top { left: 0; top: 0; width: 190px; height: 256px; decorator: image(mix-classic-back1); } +.bg-fill { left: 0; top: 256px; width: 190px; height: 177px; decorator: image(mix-classic-back2); } +.bg-left, .bg-right, .bg-bottom { display: none; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +.mix-row { height: calc(10px * var(--root-scale)); } +.mix-row.mix-row-wide { height: calc(20px * var(--root-scale)); } +.mix-row.mix-row-wide.mix-required-zen { height: calc(20px * var(--root-scale)); } +.mix-list-line.mix-unwrapped { width: calc(167px * var(--root-scale)); } +#socket_list { width: calc(160px * var(--root-scale)); height: calc(65px * var(--root-scale)); } +.socket-row { width: calc(148px * var(--root-scale)); height: calc(13px * var(--root-scale)); } + +/* The grid's clicks are native (CInventoryCtrl), so the placed panel takes no pointer events; its + controls take their own. (Legacy's rule, which this copy predated.) */ +#panel.slot-placed { pointer-events: none; } +/* Legacy's #panel font-size (calc(var(--text-px) / var(--root-scale))) is left out: the lists' + lines are sized in em above, placed at 0.97's y 203, and that rule moves them 4 units down. */ diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/move_command.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/move_command.rcss new file mode 100644 index 0000000000..fa4bfe50b8 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/move_command.rcss @@ -0,0 +1,170 @@ +/* Classic theme for CMoveCommandWindow: the Season 1 client's warp list (00438c20; 0.97 has none, + its warps are the /move command). Season 1 drew what legacy reproduces (S6 kept it): black at + 0.8 at the top left, "Move" in bold (255, 204, 26), the headers (127, 178, 255), the rows, a + (0.6, 0, 0) bar for Close. It differs in three columns, map, level and zen, centred at 45, 105 + and 155 of its 190-wide box (640x480; no strife column, which came with Gens), and in its + scrollbar art (win_scrollbar, as the classic social windows'). The rest is legacy's (its + comments explain it). */ + +/* The dock's height less its top unit (the original's window started at y 1). */ +#panel { + position: absolute; + transform-origin: left top; + width: 230px; + height: 431px; + /* RenderFrame()'s window fill, 0xCC000000. */ + background-color: rgba(0, 0, 0, 204); + font-family: "token(font-body)"; + /* The panel itself must claim the cursor: native's UpdateMouseEvent() consumed every event + inside its own rectangle, so a click on the list never reached the world underneath. */ + pointer-events: auto; +} + +/* g_hFontBold, SetTextColor(255, 204, 26). Centred on the panel's own midpoint (115) -- the + width/margin pair in the RML plus transform-origin: center top is what keeps that midpoint + fixed once the leaf counter-scales itself out of #panel. */ +#title { + display: block; + position: absolute; + left: 0; + top: 4px; + text-align: center; + transform-origin: center top; + color: rgb(255, 204, 26); + font-weight: bold; +} + +/* Column headers, SetTextColor(127, 178, 255), one native text height below the title's baseline + (RenderFrame() draws them at m_StartUISubjectName.y + 20). */ +#head { + position: absolute; + left: 2px; + top: 24px; + transform-origin: left top; + color: rgb(127, 178, 255); +} + +/* The scrollbar keeps .scroll-pane's own dp width rather than a reference-px one. #list's net + render transform is identity (#panel's scale times #list's counter-scale), so everything inside + it is already laid out in real pixels -- a scrollbar sized in reference units would be the one + part of this window that grew with the panel while its neighbours did not. It follows the + player's UI-scale setting instead, same as every other .scroll-pane consumer. */ +/* Between the header (native's kListOffsetY) and the close bar. */ +#list_box { + position: absolute; + left: 2px; + right: 3px; + top: 38px; + bottom: 22px; +} +#list { + position: absolute; + left: 0; + top: 0; + transform-origin: left top; + /* Native drew the track at every list length, also when every row fits (large windows). */ + overflow: hidden scroll; +} + +/* With nothing to scroll native drew the disabled thumb (newui_scroll_off) at the track's top. */ +@spritesheet mc-thumb-off-sheet +{ + src: "../../../newui_scroll_off.tga"; + mc-thumb-off: 0px 0px 15px 30px; + mc-thumb-off-inner: 0px 14px 15px 2px; +} +#list.no-scroll scrollbarvertical sliderbar { + decorator: ninepatch(mc-thumb-off, mc-thumb-off-inner); +} + +/* Native gives each row's text the TOP of its slot (RenderText(x, itemY)), so the row carries a + height and the cells sit at its top -- a line-height would split the slack above and below + instead, the same distinction character_info.rcss's .attr-lines already records. */ +.mc-row { + position: relative; + /* Explicit, not incidental: a data-for
is inline without it in this build, and every row + then lands on the same line. .quest-row/.party-row/.chat-line all declare it for the same + reason. */ + display: block; + color: rgb(164, 39, 17); + pointer-events: auto; +} +/* A row is its text's line height plus 2 reference px, as native's rows were. */ +.mc-strut { display: inline; } +.mc-row.can-move { color: rgb(255, 255, 255); } + +/* Each cell reproduces RT3_WRITE_CENTER exactly: native passed no box width, so the text renderer + centred the MEASURED width on the given x. A zero-offset percentage plus translateX(-50%) is + the same thing -- centred on a point, natural width, no box to overflow. The four points are + native's own 20/62/119/159 relative to the panel, restated against the row's own left edge + (panel + 2) and expressed as a fraction of row_width so they need no per-frame binding. */ +.col { + position: absolute; + top: 0; + white-space: nowrap; + transform: translateX(-50%); +} +.col-strife { left: 8.654%; } +.col-map { left: 28.846%; } +.col-level { left: 56.250%; } +.col-zen { left: 75.481%; } + +/* Only a reachable destination highlights, matching native's own `if (_bCanMove)` guard around + setting _bSelected. Native painted this quad AFTER the row text (so the tint sat over the + glyphs); as a background it sits behind them, which reads the same but cleaner. 0x99CCCC1A. */ +.mc-row.can-move:hover { + background-color: rgba(204, 204, 26, 153); +} + +/* An unmet requirement brightens only the cell that is unmet, and only on a row that is already + unreachable -- native's SetTextColor(255, 51, 26) inside the !_bCanMove branch. */ +.mc-row .col.unmet { color: rgb(255, 51, 26); } +.mc-row.can-move .col.unmet { color: rgb(255, 255, 255); } + +/* RenderFrame()'s second fill, 0xFF990000, with the label one unit down (closeTop + 1). */ +#close_bar { + position: absolute; + left: 2px; + right: 3px; + bottom: 6px; + height: 16px; + background-color: rgb(153, 0, 0); + pointer-events: auto; + cursor: pointer; +} +#close_label { position: absolute; white-space: nowrap; color: rgb(255, 255, 255); } + +/* A theme's data-fit="fill" slot sizes #panel (class fill-placement), its border included. */ +#panel.fill-placement { box-sizing: border-box; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. The rows + leave 17 reference px at the pane's right for the scrollbar; #head spans the rows' width. */ +#title { width: calc(100% * var(--root-scale)); margin-left: calc(50% - 50% * var(--root-scale)); } +#head { width: calc(100% * var(--root-scale) - 22px * var(--root-scale)); } +#list { width: calc(100% * var(--root-scale)); height: calc(100% * var(--root-scale)); } +.mc-row { width: calc(100% - 17px * var(--root-scale)); padding-bottom: calc(2px * var(--root-scale)); } + +/* Season 1's three columns: no strife column, the others centred where Season 1 put them (45, + 105 and 155 of 190), as fractions of the row. */ +.col-strife { display: none; } +.col-map { left: 23.7%; } +.col-level { left: 55.3%; } +.col-zen { left: 81.6%; } + +/* win_scrollbar: the arrows at both ends, the track between two 106,97,88 lines, the grey thumb. */ +@spritesheet mc-scroll-sheet +{ + src: "../../../win_scrollbar.jpg"; + mc-scroll-thumb: 0px 1px 11px 1px; + mc-scroll-up: 0px 3px 13px 13px; + mc-scroll-down: 0px 16px 13px 13px; +} +#list scrollbarvertical { width: 13dp; margin: 0; } +#list scrollbarvertical slidertrack { decorator: none; box-sizing: border-box; border-left: 1dp rgb(106, 97, 88); border-right: 1dp rgb(106, 97, 88); } +#list scrollbarvertical sliderbar, #list.no-scroll scrollbarvertical sliderbar { height: auto; min-height: 6dp; margin: 0 1dp; decorator: image(mc-scroll-thumb fill); } +#list scrollbarvertical sliderarrowdec, +#list scrollbarvertical sliderarrowinc { width: 100%; height: 13dp; pointer-events: auto; } +#list scrollbarvertical sliderarrowdec { decorator: image(mc-scroll-up); } +#list scrollbarvertical sliderarrowinc { decorator: image(mc-scroll-down); } +#list scrollbarvertical sliderarrowdec:active, +#list scrollbarvertical sliderarrowinc:active { filter: brightness(0.7); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/msg_win.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/msg_win.rcss new file mode 100644 index 0000000000..767286ff99 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/msg_win.rcss @@ -0,0 +1,93 @@ +/* Classic (0.97) message box of the login and character scenes (CMsgWin): Message_box (213x64) at + the top centre (y 60 of the 640x480 frame), one line centred at y 75 or two at 69 and 81, and + the 0.97 OK / Cancel plates (70x21, the second image under the mouse) -- OK alone at (284, 98), + OK and Cancel at (234, 98) and (334, 98), the narrow pair (40 wide) at (323, 98) and (373, 98) + beside an input. From the 0.97 client's RenderMessageBox (0051af50). Positions below are the + box's own, in 1/480 of the screen height. The text does not stretch with the box: 0.97 drew its + font at screen pixels, so it is 1rem, the native text size (msg_win.rml's body is "native-text", + RmlNativeText.h). */ + +@spritesheet classic-msgwin-back-sheet { src: ../../../Classic/Message_box.jpg; classic-msgwin-back: 0px 0px 213px 64px; } +@spritesheet classic-msgwin-ok-sheet { src: ../../../Classic/Ok.jpg; classic-msgwin-ok: 0px 0px 70px 21px; } +@spritesheet classic-msgwin-ok2-sheet { src: ../../../Classic/Ok2.jpg; classic-msgwin-ok-hover: 0px 0px 70px 21px; } +@spritesheet classic-msgwin-cancel-sheet { src: ../../../Classic/Cancel.jpg; classic-msgwin-cancel: 0px 0px 70px 21px; } +@spritesheet classic-msgwin-cancel2-sheet { src: ../../../Classic/Cancel2.jpg; classic-msgwin-cancel-hover: 0px 0px 70px 21px; } + +body { --px: calc(100vh / 480); } + +#panel { + position: absolute; + left: 50%; + top: calc(60 * var(--px)); + transform: none; + width: calc(213 * var(--px)); + height: calc(64 * var(--px)); + margin-left: calc(-106.5 * var(--px)); + font-family: "token(font-body)"; + font-size: 1rem; + decorator: image(classic-msgwin-back); +} + +#msg_line1, #msg_line2 { + position: absolute; + left: 0; + right: 0; + text-align: center; + color: #ffffff; + white-space: nowrap; + pointer-events: none; +} +#msg_line1 { top: calc(15 * var(--px)); } +#msg_line1.multi-line { top: calc(9 * var(--px)); } +#msg_line2 { top: calc(21 * var(--px)); } +#msg_line2.hidden { display: none; } +.no-buttons #msg_line1 { top: calc(24 * var(--px)); } +.no-buttons #msg_line1.multi-line { top: calc(18 * var(--px)); } +.no-buttons #msg_line2 { top: calc(30 * var(--px)); } + +/* The personal number field (deleting a character), left of the narrow buttons. */ +#input_frame { + display: none; + position: absolute; + left: calc(12 * var(--px)); + top: calc(38 * var(--px)); + width: calc(95 * var(--px)); + height: calc(21 * var(--px)); + background-color: rgba(0, 0, 0, 160); + pointer-events: none; +} +.mode-input #input_frame { display: block; } +.msgwin-input-field { + position: absolute; + left: calc(16 * var(--px)); + top: calc(41 * var(--px)); + width: calc(87 * var(--px)); + height: calc(15 * var(--px)); + padding: 0; + color: #ffe6d2; + background-color: transparent; + border-width: 0; + box-shadow: none; + decorator: none; +} + +.btn { + display: none; + position: absolute; + top: calc(38 * var(--px)); + width: calc(70 * var(--px)); + height: calc(21 * var(--px)); + cursor: pointer; + pointer-events: auto; + color: transparent; +} +#btn_ok { left: calc(71 * var(--px)); decorator: image(classic-msgwin-ok); } +#btn_ok:hover { decorator: image(classic-msgwin-ok-hover); } +#btn_cancel { left: calc(71 * var(--px)); decorator: image(classic-msgwin-cancel); } +#btn_cancel:hover { decorator: image(classic-msgwin-cancel-hover); } +.mode-ok-only #btn_ok, .mode-both #btn_ok, .mode-input #btn_ok, +.mode-cancel-only #btn_cancel, .mode-both #btn_cancel, .mode-input #btn_cancel { display: block; } +.mode-both #btn_ok { left: calc(21 * var(--px)); } +.mode-both #btn_cancel { left: calc(121 * var(--px)); } +.mode-input #btn_ok { left: calc(110 * var(--px)); width: calc(40 * var(--px)); } +.mode-input #btn_cancel { left: calc(160 * var(--px)); width: calc(40 * var(--px)); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/mu_helper_bar.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/mu_helper_bar.rcss new file mode 100644 index 0000000000..d5d3f6c6f4 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/mu_helper_bar.rcss @@ -0,0 +1,131 @@ +/* Classic theme for the MU Helper bar (CMuHelperBar). 0.97 has neither the helper nor this box, and + its bar already shows the hero's coordinates: the classic bar keeps only the helper's two buttons + (setup and start / stop, their own icons) at the top-left corner, without the map and position + readout or its S6 frame. Legacy's rules first, then the + classic ones. */ + +/* Legacy theme for the "Official MU Helper" mini control bar + hero position readout + (CMuHelperBar) -- fixed 207x25dp layout, anchored top-left via base.rcss's .anchor-top-left. */ + +@spritesheet muhelper-seg-a-sheet +{ + src: "../../../Minimap_positionA.tga"; + muhelper-seg-a-image: 0px 0px 22px 25px; +} +@spritesheet muhelper-seg-b-sheet +{ + src: "../../../Minimap_positionB.tga"; + muhelper-seg-b-image: 3px 0px 19px 25px; +} +@spritesheet muhelper-seg-c-sheet +{ + src: "../../../MacroUI/Minimap_positionC.tga"; + muhelper-seg-c-image: 0px 0px 73px 20px; +} +@spritesheet muhelper-config-sheet +{ + src: "../../../MacroUI/MacroUI_Setup.tga"; + muhelper-config-image: 0px 0px 18px 13px; + muhelper-config-hover: 0px 13px 18px 13px; +} +@spritesheet muhelper-start-sheet +{ + src: "../../../MacroUI/MacroUI_Start.tga"; + muhelper-start-image: 0px 0px 18px 13px; + muhelper-start-hover: 0px 13px 18px 13px; +} +@spritesheet muhelper-stop-sheet +{ + src: "../../../MacroUI/MacroUI_Stop.tga"; + muhelper-stop-image: 0px 0px 18px 13px; + muhelper-stop-hover: 0px 13px 18px 13px; +} + +#panel.workspace-placed { transform-origin: left top; } +#panel { + position: absolute; + width: 207dp; + height: 25dp; + font-family: "token(font-body)"; + font-size: 1rem; +} + +#seg_a { + position: absolute; + left: 0dp; + top: 0dp; + width: 22dp; + height: 25dp; + decorator: image(muhelper-seg-a-image); + pointer-events: none; +} +#seg_b { + position: absolute; + left: 22dp; + top: 0dp; + width: 112dp; + height: 25dp; + decorator: image(muhelper-seg-b-image); + pointer-events: none; +} +#seg_c { + position: absolute; + left: 134dp; + top: 0dp; + width: 73dp; + height: 20dp; + decorator: image(muhelper-seg-c-image); + pointer-events: none; +} + +/* The original normal-font readout: 1rem is the native text size (RmlNativeText.h); this panel has + no scale transform, so it rasterizes at the displayed size directly. */ +#text { + position: absolute; + font-family: "token(font-body)"; + font-size: 1rem; + line-height: 9dp; + left: 10dp; + top: 5dp; + width: 132dp; + height: 9dp; + text-align: center; + color: token(text-primary); + white-space: nowrap; + pointer-events: none; +} + +.mu-btn { + position: absolute; + top: 0dp; + width: 18dp; + height: 13dp; + cursor: pointer; + pointer-events: auto; +} +#btn_config { + left: 153dp; + decorator: image(muhelper-config-image); +} +#btn_start { + left: 171dp; + decorator: image(muhelper-start-image); +} +#btn_stop { + left: 171dp; + decorator: image(muhelper-stop-image); +} +/* Native SetButtonInfo(..., overflg 1, ...): the sheet's second 13px frame while hovered. */ +#btn_config:hover { decorator: image(muhelper-config-hover); } +#btn_start:hover { decorator: image(muhelper-start-hover); } +#btn_stop:hover { decorator: image(muhelper-stop-hover); } + +.dot { + display: none; +} + +/* --- Classic ---------------------------------------------------------------------------------- */ +#seg_a, #seg_b, #seg_c, #text { display: none; } +#panel { width: 40dp; height: 15dp; } +#btn_config { left: 2dp; top: 2dp; } +#btn_start, #btn_stop { left: 22dp; top: 2dp; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/mu_helper_common.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/mu_helper_common.rcss new file mode 100644 index 0000000000..25958c8978 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/mu_helper_common.rcss @@ -0,0 +1,295 @@ +/* Classic theme for the MU Helper's shared pieces (config window and detail panel). 0.97 and + Season 1 have no MU Helper; it takes the parts the classic theme's Season 1 windows wear, over + legacy's layout (whose comments follow): its panes and group boxes as Season 1's frames of lines + (0.9, 0.9, 0.6, the pet window's) on the translucent fills, the classic social windows' check + boxes, win_button tabs (the selected one raised and bright), text_button buttons, black fields + edged in the window line colour, and plain boxes for the skill slots (the classic clients have + no skill box art). The range steppers and digits stay legacy's. */ + +/* Legacy pieces the MU Helper config window and its detail panel share -- each one a straight + reading of the native draw call it replaces. Link + after docked_panel_frame.rcss: #panel, the frame sprites, the group-box corners and the exit + button come from there. Plain reference px throughout; #panel carries transform: scale(root_scale). + + Text leaves are .sharp-text layers counter-scaled out of #panel in the RML, so this file never + sets a text font-size -- see character_info.rml's header comment for the technique. */ + +.frame-top { decorator: image(docked-bg-top-b); } + +/* The docked family's exit sits at (13, 392); the MU Helper's at (20, 388). */ +#btn_exit { left: 20px; top: 388px; } + +.mh-text { + display: block; + position: absolute; + white-space: nowrap; + color: token(text-primary); + pointer-events: none; +} +/* .mh-text's display:block has the same specificity as base.rcss's .hidden and comes later, so a + data-class-hidden page header or tab label would stay on screen over its sibling. */ +.mh-text.hidden { display: none; } +.mh-text.mh-center { text-align: center; } +.mh-text.mh-bold { font-weight: bold; } + +/* A page title: bold, centred on the panel's own 190 units, 13 down. */ +.mh-title { left: 0; top: 13px; } + +/* --- Tabbed pane ------------------------------------------------------------------------------ + RenderBackPane(): a 65-wide header tab sitting on a 165-wide box, drawn as two translucent fills + (0x66000000) under the table sprites -- 14x14 corners, and the 1px edge sprites stretched across + each edge, which is exactly what native's crop of a 1px texture with GL_CLAMP draws. Every piece + is its own childless sibling: a decorated leaf with children can render an incomplete box in this + build. Offsets are relative to the pane; .mh-pane-h70 is the one taller variant (the elf party + page's heal-support pane). */ +@spritesheet mh-edge-top-sheet { src: "../../../newui_item_table03(Up).tga"; mh-edge-top: 0px 0px 1px 14px; } +@spritesheet mh-edge-bottom-sheet { src: "../../../newui_item_table03(Dw).tga"; mh-edge-bottom: 0px 0px 1px 14px; } +@spritesheet mh-edge-left-sheet { src: "../../../newui_item_table03(L).tga"; mh-edge-left: 0px 0px 14px 1px; } +@spritesheet mh-edge-right-sheet { src: "../../../newui_item_table03(R).tga"; mh-edge-right: 0px 0px 14px 1px; } + +.mh-pane { position: absolute; width: 165px; pointer-events: none; } +.mh-pane .p { position: absolute; pointer-events: none; } + +.mh-pane .p-fill-tab { left: 3px; top: 2px; width: 58px; height: 18px; background-color: rgba(0, 0, 0, 102); } +.mh-pane .p-fill-body { left: 3px; top: 20px; width: 158px; height: 38px; background-color: rgba(0, 0, 0, 102); } + +.mh-pane .p-tab-tl { left: 0; top: 0; width: 14px; height: 14px; decorator: image(docked-corner-tl); } +.mh-pane .p-tab-tr { left: 51px; top: 0; width: 14px; height: 14px; decorator: image(docked-corner-tr); } +.mh-pane .p-tab-top { left: 6px; top: 0; width: 53px; height: 14px; decorator: image(mh-edge-top); } +.mh-pane .p-tab-right { left: 51px; top: 6px; width: 14px; height: 14px; decorator: image(mh-edge-right); } + +.mh-pane .p-box-tr { left: 151px; top: 18px; width: 14px; height: 14px; decorator: image(docked-corner-tr); } +.mh-pane .p-box-bl { left: 0; top: 49px; width: 14px; height: 14px; decorator: image(docked-corner-bl); } +.mh-pane .p-box-br { left: 151px; top: 49px; width: 14px; height: 14px; decorator: image(docked-corner-br); } +.mh-pane .p-box-top { left: 2px; top: 18px; width: 153px; height: 14px; decorator: image(mh-edge-top); } +.mh-pane .p-box-right { left: 151px; top: 24px; width: 14px; height: 31px; decorator: image(mh-edge-right); } +.mh-pane .p-box-bottom { left: 6px; top: 49px; width: 153px; height: 14px; decorator: image(mh-edge-bottom); } +.mh-pane .p-left { left: 0; top: 6px; width: 14px; height: 45px; decorator: image(mh-edge-left); } + +.mh-pane .mh-text { left: 10px; top: 6px; } + +.mh-pane-h70 .p-fill-body { height: 63px; } +.mh-pane-h70 .p-box-bl, +.mh-pane-h70 .p-box-br, +.mh-pane-h70 .p-box-bottom { top: 74px; } +.mh-pane-h70 .p-box-right { height: 56px; } +.mh-pane-h70 .p-left { height: 70px; } + +/* --- Threshold gauge --------------------------------------------------------------------------- + base.rcss's .level-gauge at RenderHpLevel()'s size. Native's hit rectangle began 7 units before + the rail and ended 1 unit after it. */ +.mh-gauge { position: absolute; width: 124px; height: 16px; } +.mh-gauge-hit { left: -7px; right: -1px; } +.mh-gauge-fill { height: 16px; } + +/* --- Checkbox / radio -------------------------------------------------------------------------- + CCheckBox: a 15x15 box from a two-frame 15x30 sheet -- frame 0 (top) is CHECKED, frame 1 the + empty box (SetNowFrame(State ? 0 : 1)), the reverse of base.rcss's own checkbox sheet -- with its + label 16 across and 4 down in the normal font. Only the box takes the click, as natively. The + radio-behaving ones (the conditions, the Dark Raven modes) use the MacroUI option-button art. */ +@spritesheet mh-check-sheet { src: "../../../newui_option_check.tga"; mh-check-on: 0px 0px 15px 15px; mh-check-off: 0px 15px 15px 15px; } +@spritesheet mh-radio-sheet { src: "../../../MacroUI/MacroUI_OptionButton.tga"; mh-radio-on: 0px 0px 15px 15px; mh-radio-off: 0px 15px 15px 15px; } + +.mh-check .checkbox-box { + position: absolute; + width: 15px; + height: 15px; + cursor: pointer; + pointer-events: auto; + decorator: image(mh-check-off); +} +.mh-check .checkbox-box.checked { decorator: image(mh-check-on); } +.mh-check .checkbox-label { left: 16px; top: 4px; } +.mh-check.mh-radio .checkbox-box { decorator: image(mh-radio-off); } +.mh-check.mh-radio .checkbox-box.checked { decorator: image(mh-radio-on); } + +/* --- Footer buttons ---------------------------------------------------------------------------- + The in-game-shop button art, three 52x26 frames: up, over, down (ChangeButtonImgState with + overflg set). The label is a sibling laid over the button, not a child of it -- see the pane note + above -- and lets the mouse through to it. */ +@spritesheet mh-igs-sheet +{ + src: "../../../InGameShop/Ingame_Bt03.tga"; + mh-igs-up: 0px 0px 52px 26px; + mh-igs-over: 0px 26px 52px 26px; + mh-igs-down: 0px 52px 52px 26px; +} +.mh-btn-igs { + position: absolute; + width: 52px; + height: 26px; + cursor: pointer; + pointer-events: auto; + decorator: image(mh-igs-up); +} +.mh-btn-igs:hover { decorator: image(mh-igs-over); } +.mh-btn-igs:active { decorator: image(mh-igs-down); } +/* Every labelled native button here set MoveTextPos(0, -1). */ +.mh-btn-label { margin-top: -1px; } + +/* --- Numeric field ----------------------------------------------------------------------------- + MacroUI_InputNumber is 28 wide but native drew it into a 20-wide box -- a crop, like the gauge. + The field on top is black text on that plate (native's CUITextInputBox colours), with no chrome of + its own; the config window's item-name field sits on the wider MacroUI_InputString plate the same + way. */ +@spritesheet mh-number-plate-sheet { src: "../../../MacroUI/MacroUI_InputNumber.tga"; mh-number-plate: 0px 0px 20px 15px; } +.mh-number-plate { position: absolute; width: 20px; height: 15px; decorator: image(mh-number-plate); pointer-events: none; } + +.mh-field { + position: absolute; + color: #000000; + background-color: transparent; + border-width: 0; + border-radius: 0; + padding: 0; +} + +@spritesheet mh-string-plate-sheet { src: "../../../MacroUI/MacroUI_InputString.tga"; mh-string-plate: 0px 0px 93px 15px; } +.mh-string-plate { position: absolute; width: 94px; height: 15px; decorator: image(mh-string-plate); pointer-events: none; } + +/* --- Plain group box (config window) ----------------------------------------------------------- + RenderBack(): a translucent fill inset 3/2 and 4/5, the four 14x14 corners, then the four 1px edge + sprites stretched over them -- in that order, so the edges paint over the corners as natively. The + pieces anchor to the box's own edges, so only each box's rectangle is per-instance. */ +.mh-box { position: absolute; pointer-events: none; } +.mh-box .b { position: absolute; pointer-events: none; } +.mh-box .b-fill { left: 3px; top: 2px; right: 4px; bottom: 5px; background-color: rgba(0, 0, 0, 102); } +.mh-box .b-tl { left: 0; top: 0; width: 14px; height: 14px; decorator: image(docked-corner-tl); } +.mh-box .b-tr { right: 0; top: 0; width: 14px; height: 14px; decorator: image(docked-corner-tr); } +.mh-box .b-bl { left: 0; bottom: 0; width: 14px; height: 14px; decorator: image(docked-corner-bl); } +.mh-box .b-br { right: 0; bottom: 0; width: 14px; height: 14px; decorator: image(docked-corner-br); } +.mh-box .b-top { left: 6px; right: 6px; top: 0; height: 14px; decorator: image(mh-edge-top); } +.mh-box .b-bottom { left: 6px; right: 6px; bottom: 0; height: 14px; decorator: image(mh-edge-bottom); } +.mh-box .b-left { left: 0; top: 6px; bottom: 8px; width: 14px; decorator: image(mh-edge-left); } +.mh-box .b-right { right: 0; top: 6px; bottom: 8px; width: 14px; decorator: image(mh-edge-right); } + +/* --- Tabs -------------------------------------------------------------------------------------- + Native pointed its tab group at IMAGE_GUILDINFO_TAB_BUTTON, a slot nothing ever loads, so the + tabs drew from an empty texture. newui_guild_tab04 is two 56x22 frames -- exactly this tab's size + -- and is the art that slot was evidently meant to hold: up on top, selected below. Label grey + while up, white when selected (CRadioButton::ChangeFrame). */ +@spritesheet mh-tab-sheet { src: "../../../newui_guild_tab04.tga"; mh-tab-up: 0px 0px 56px 22px; mh-tab-on: 0px 22px 56px 22px; } +.mh-tab { position: absolute; top: 48px; width: 56px; height: 22px; cursor: pointer; pointer-events: auto; decorator: image(mh-tab-up); } +.mh-tab.active { decorator: image(mh-tab-on); } +.mh-tab-label { top: 48px; color: token(text-muted); } +.mh-tab-label.active { color: token(text-primary); } +#tab_0, #tab_0_label { left: 10px; } +#tab_1, #tab_1_label { left: 66px; } +#tab_2, #tab_2_label { left: 122px; } + +/* --- Config window buttons --------------------------------------------------------------------- + The range steppers are the character window's level-up "+" and MacroUI's "-", each two 16x15 + frames with no hover (overflg off: up, then pressed). "Setting", "Add" and "Delete" are the + illusion-temple clearness button, three 38x24 frames: up, over, down. */ +@spritesheet mh-plus-sheet { src: "../../../newui_chainfo_btn_level.tga"; mh-plus-up: 0px 0px 16px 15px; mh-plus-down: 0px 15px 16px 15px; } +@spritesheet mh-minus-sheet { src: "../../../MacroUI/MacroUI_RangeMinus.tga"; mh-minus-up: 0px 0px 16px 15px; mh-minus-down: 0px 15px 16px 15px; } +@spritesheet mh-setting-sheet +{ + src: "../../../newui_Bt_clearness_illusion.jpg"; + mh-setting-up: 0px 0px 38px 24px; + mh-setting-over: 0px 24px 38px 24px; + mh-setting-down: 0px 48px 38px 24px; +} +.mh-btn-plus, .mh-btn-minus { position: absolute; width: 16px; height: 15px; cursor: pointer; pointer-events: auto; } +.mh-btn-plus { decorator: image(mh-plus-up); } +.mh-btn-plus:active { decorator: image(mh-plus-down); } +.mh-btn-minus { decorator: image(mh-minus-up); } +.mh-btn-minus:active { decorator: image(mh-minus-down); } +.mh-btn-setting { position: absolute; width: 38px; height: 24px; cursor: pointer; pointer-events: auto; decorator: image(mh-setting-up); } +.mh-btn-setting:hover { decorator: image(mh-setting-over); } +.mh-btn-setting:active { decorator: image(mh-setting-down); } + +/* --- Range digit ------------------------------------------------------------------------------- + One CryWolf rank-number texture per value (icon_Rank_N.tga), native's 15x19 crop of each. */ +@spritesheet mh-range-0-sheet { src: "../../../icon_Rank_0.tga"; mh-range-0: 0px 0px 15px 19px; } +@spritesheet mh-range-1-sheet { src: "../../../icon_Rank_1.tga"; mh-range-1: 0px 0px 15px 19px; } +@spritesheet mh-range-2-sheet { src: "../../../icon_Rank_2.tga"; mh-range-2: 0px 0px 15px 19px; } +@spritesheet mh-range-3-sheet { src: "../../../icon_Rank_3.tga"; mh-range-3: 0px 0px 15px 19px; } +@spritesheet mh-range-4-sheet { src: "../../../icon_Rank_4.tga"; mh-range-4: 0px 0px 15px 19px; } +@spritesheet mh-range-5-sheet { src: "../../../icon_Rank_5.tga"; mh-range-5: 0px 0px 15px 19px; } +@spritesheet mh-range-6-sheet { src: "../../../icon_Rank_6.tga"; mh-range-6: 0px 0px 15px 19px; } +@spritesheet mh-range-7-sheet { src: "../../../icon_Rank_7.tga"; mh-range-7: 0px 0px 15px 19px; } +@spritesheet mh-range-8-sheet { src: "../../../icon_Rank_8.tga"; mh-range-8: 0px 0px 15px 19px; } +.mh-range-digit { position: absolute; width: 15px; height: 19px; pointer-events: none; } + +/* --- Skill slot -------------------------------------------------------------------------------- + newui_skillbox with the skill's 20x28 icon 6 in and 6 down (RenderIconList()). */ +@spritesheet mh-slot-sheet { src: "../../../newui_skillbox.jpg"; mh-slot-box: 0px 0px 32px 38px; } +.mh-slot { position: absolute; width: 32px; height: 38px; cursor: pointer; pointer-events: auto; decorator: image(mh-slot-box); } +.mh-slot-icon { position: absolute; left: 6px; top: 6px; width: 20px; height: 28px; pointer-events: none; } + +/* The extension-function note under the second and third tabs, 0xFF00B4FF in the engine's + A|B|G|R packing -- orange, not blue. */ +.mh-orange { color: rgb(255, 180, 0); } + +/* --- Extra-item list --------------------------------------------------------------------------- + Native's rows: 13 units tall, text 8 in and 3 down, in a pale text colour. The selected + row is a solid bar in whatever colour GL was left at -- native set none, so white -- with black + text on it. */ +.mh-extra-row { + display: block; + box-sizing: border-box; + width: 100%; + white-space: nowrap; + color: rgb(230, 220, 200); + cursor: pointer; + pointer-events: auto; +} +.mh-extra-row.selected { background-color: rgb(255, 255, 255); color: #000000; } + +/* --- Classic overrides ------------------------------------------------------------------------ */ +@spritesheet mh-classic-check-sheet { src: "../../../win_check.tga"; mh-classic-check: 0px 0px 5px 5px; } +@spritesheet mh-classic-tab-sheet { src: "../../../win_button.tga"; mh-classic-tab: 0px 0px 49px 16px; } + +/* Panes and boxes: no S6 sprites; each corner and edge piece draws the line along its outer side. */ +.mh-pane .p-tab-tl, .mh-pane .p-tab-tr, .mh-pane .p-tab-top, .mh-pane .p-tab-right, +.mh-pane .p-box-tr, .mh-pane .p-box-bl, .mh-pane .p-box-br, .mh-pane .p-box-top, .mh-pane .p-box-right, +.mh-pane .p-box-bottom, .mh-pane .p-left, +.mh-box .b-tl, .mh-box .b-tr, .mh-box .b-bl, .mh-box .b-br, +.mh-box .b-top, .mh-box .b-bottom, .mh-box .b-left, .mh-box .b-right { + decorator: none; + box-sizing: border-box; + border-color: rgb(230, 230, 153); +} +.mh-pane .p-tab-tl, .mh-box .b-tl { border-top-width: 1px; border-left-width: 1px; } +.mh-pane .p-tab-tr, .mh-pane .p-box-tr, .mh-box .b-tr { border-top-width: 1px; border-right-width: 1px; } +.mh-pane .p-box-bl, .mh-box .b-bl { border-bottom-width: 1px; border-left-width: 1px; } +.mh-pane .p-box-br, .mh-box .b-br { border-bottom-width: 1px; border-right-width: 1px; } +.mh-pane .p-tab-top, .mh-pane .p-box-top, .mh-box .b-top { border-top-width: 1px; } +.mh-pane .p-tab-right, .mh-pane .p-box-right, .mh-box .b-right { border-right-width: 1px; } +.mh-pane .p-box-bottom, .mh-box .b-bottom { border-bottom-width: 1px; } +.mh-pane .p-left, .mh-box .b-left { border-left-width: 1px; } + +/* Check boxes and option buttons: 106,97,88 inside a 146,134,121 line, win_check when set. */ +.mh-check .checkbox-box, .mh-check.mh-radio .checkbox-box { + width: 11px; + height: 11px; + margin: 2px 0 0 2px; + box-sizing: border-box; + border: 1px rgb(146, 134, 121); + background-color: rgb(37, 37, 37); + decorator: none; +} +.mh-check .checkbox-box.checked, .mh-check.mh-radio .checkbox-box.checked { background-color: rgb(106, 97, 88); decorator: image(mh-classic-check fill); } + +/* Labelled buttons: Season 1's text_button (56x24, its labelled buttons' art, the personal shop's), + at legacy's 24 / 26 high, which its art fits; brighter under the mouse, one unit down while + pressed. */ +@spritesheet mh-classic-btn-sheet { src: ../../../Classic/s1/text_button.jpg; mh-classic-btn: 0px 0px 56px 24px; } +.mh-btn-igs, .mh-btn-igs:hover, .mh-btn-igs:active, +.mh-btn-setting, .mh-btn-setting:hover, .mh-btn-setting:active { decorator: image(mh-classic-btn fill); } +.mh-btn-igs:hover, .mh-btn-setting:hover { filter: brightness(1.3); } +.mh-btn-setting:active, .mh-btn-igs:active { margin-top: 1px; } + +/* Fields: black, edged in the window line colour, with the window's text colour. */ +.mh-number-plate, .mh-string-plate { decorator: none; box-sizing: border-box; border: 1px rgb(146, 134, 121); background-color: rgb(0, 0, 0); } +.mh-field { color: rgb(230, 220, 200); } + +/* Tabs: win_button, the others 18 high from y 52 and darkened, the selected one 22 high at y 48. */ +.mh-tab { top: 52px; height: 18px; image-color: rgb(153, 153, 153); decorator: image(mh-classic-tab fill); } +.mh-tab.active { top: 48px; height: 22px; z-index: 1; image-color: #ffffff; decorator: image(mh-classic-tab fill); } +.mh-tab-label { top: 52px; color: rgb(200, 190, 170); z-index: 2; } +.mh-tab-label.active { top: 50px; color: #ffffff; } + +/* Skill slots: a plain box; 0.97's icons carry their own frame. */ +.mh-slot { decorator: none; box-sizing: border-box; border: 1px rgb(146, 134, 121); background-color: rgba(0, 0, 0, 150); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/mu_helper_skill_picker.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/mu_helper_skill_picker.rcss new file mode 100644 index 0000000000..c505b93b7a --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/mu_helper_skill_picker.rcss @@ -0,0 +1,80 @@ +/* Classic theme for CMuHelperSkillPicker: legacy's (below), its skill boxes plain boxes edged in the + window line colour, as the MU Helper's slots (the classic clients have no skill box art). */ + +/* Legacy theme for CMuHelperSkillPicker. Native drew each entry as newui_skillbox (32x38) with the + skill's 20x28 icon centred in it -- (32 - 20) / 2 = 6 across, (38 - 28) / 2 = 5 down. Plain + reference px throughout: #panel carries the config window's scale. */ + +/* Above the docked MU Helper documents by the stacking table (5.2 over 3.4). The flyout overlaps + the detail window's column, and RmlUi hit-tests documents independently of CManager -- below + them, a click on an icon could also land on a control underneath. */ +body { + position: absolute; +} + +@spritesheet mhsp-box-sheet { src: "../../../newui_skillbox.jpg"; mhsp-box: 0px 0px 32px 38px; } + +#panel { + position: absolute; + transform-origin: left top; + pointer-events: none; +} + +.mhsp-entry { + position: absolute; + width: 32px; + height: 38px; + decorator: image(mhsp-box); + /* Takes the pointer: RmlUi's hit test stops here (see body above), and a click picks the skill. */ + pointer-events: auto; +} + +.mhsp-icon { + position: absolute; + left: 6px; + top: 5px; + width: 20px; + height: 28px; +} + +/* Native's fan-out: columns right to left from just outside the config window's left edge, and + in a column the entries alternate above and below the row of the slot that opened the flyout + (y 171 for an attack slot, ten to a column; 293 for a buff slot, five to a column). The + attack rules follow and win: every buff rule is matched by an attack rule of more weight. */ +#panel .mhsp-entry:nth-child(5n+1) { top: 293px; } +#panel .mhsp-entry:nth-child(5n+2) { top: 331px; } +#panel .mhsp-entry:nth-child(5n+3) { top: 255px; } +#panel .mhsp-entry:nth-child(5n+4) { top: 369px; } +#panel .mhsp-entry:nth-child(5n+5) { top: 217px; } +#panel .mhsp-entry:nth-child(n+1):nth-child(-n+5) { left: -32px; } +#panel .mhsp-entry:nth-child(n+6):nth-child(-n+10) { left: -64px; } +#panel .mhsp-entry:nth-child(n+11):nth-child(-n+15) { left: -96px; } +#panel .mhsp-entry:nth-child(n+16):nth-child(-n+20) { left: -128px; } +#panel .mhsp-entry:nth-child(n+21):nth-child(-n+25) { left: -160px; } +#panel .mhsp-entry:nth-child(n+26):nth-child(-n+30) { left: -192px; } +#panel .mhsp-entry:nth-child(n+31):nth-child(-n+35) { left: -224px; } +#panel .mhsp-entry:nth-child(n+36):nth-child(-n+40) { left: -256px; } +#panel .mhsp-entry:nth-child(n+41):nth-child(-n+45) { left: -288px; } +#panel .mhsp-entry:nth-child(n+46):nth-child(-n+50) { left: -320px; } +#panel .mhsp-entry:nth-child(n+51):nth-child(-n+55) { left: -352px; } +#panel .mhsp-entry:nth-child(n+56):nth-child(-n+60) { left: -384px; } +#panel.attack .mhsp-entry:nth-child(10n+1) { top: 171px; } +#panel.attack .mhsp-entry:nth-child(10n+2) { top: 209px; } +#panel.attack .mhsp-entry:nth-child(10n+3) { top: 133px; } +#panel.attack .mhsp-entry:nth-child(10n+4) { top: 247px; } +#panel.attack .mhsp-entry:nth-child(10n+5) { top: 95px; } +#panel.attack .mhsp-entry:nth-child(10n+6) { top: 285px; } +#panel.attack .mhsp-entry:nth-child(10n+7) { top: 57px; } +#panel.attack .mhsp-entry:nth-child(10n+8) { top: 323px; } +#panel.attack .mhsp-entry:nth-child(10n+9) { top: 19px; } +#panel.attack .mhsp-entry:nth-child(10n+10) { top: 361px; } +#panel.attack .mhsp-entry:nth-child(n+1):nth-child(-n+10) { left: -32px; } +#panel.attack .mhsp-entry:nth-child(n+11):nth-child(-n+20) { left: -64px; } +#panel.attack .mhsp-entry:nth-child(n+21):nth-child(-n+30) { left: -96px; } +#panel.attack .mhsp-entry:nth-child(n+31):nth-child(-n+40) { left: -128px; } +#panel.attack .mhsp-entry:nth-child(n+41):nth-child(-n+50) { left: -160px; } +#panel.attack .mhsp-entry:nth-child(n+51):nth-child(-n+60) { left: -192px; } +#panel.attack .mhsp-entry:nth-child(n+61):nth-child(-n+70) { left: -224px; } +#panel.attack .mhsp-entry:nth-child(n+71):nth-child(-n+80) { left: -256px; } + +.mhsp-entry { decorator: none; box-sizing: border-box; border: 1px rgb(146, 134, 121); background-color: rgba(0, 0, 0, 150); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/my_inventory.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/my_inventory.rcss new file mode 100644 index 0000000000..08cc2c2d1e --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/my_inventory.rcss @@ -0,0 +1,162 @@ +/* Classic (0.97) inventory: Item_Back01 (190x256) over Item_Back02 (190x177), the equipment slots + on the 0.97 art at their 0.97 places, the 8x8 grid at (15, 200), the Zen bar and the Close / + Repair buttons. From the 0.97 client; positions are the window's own units (#panel's + left/top/scale come from C++). CMyInventory reads the slot and grid boxes back for its hit tests, + so moving a box here moves where it is clicked. */ + +@spritesheet classic-inv-back1-sheet { src: ../../../Classic/Item_back01.jpg; classic-inv-back1: 0px 0px 190px 256px; } +@spritesheet classic-inv-back2-sheet { src: ../../../Classic/Item_Back02.jpg; classic-inv-back2: 0px 0px 190px 177px; } + +#panel { + position: absolute; + transform-origin: left top; + width: 190px; + height: 433px; + font-family: "token(font-body)"; +} + +.bg-fill, .bg-top, .bg-left, .bg-right, .bg-bottom { position: absolute; pointer-events: none; } +.bg-top { left: 0; top: 0; width: 190px; height: 256px; decorator: image(classic-inv-back1); } +.bg-fill { left: 0; top: 256px; width: 190px; height: 177px; decorator: image(classic-inv-back2); } +.bg-left, .bg-right { display: none; } + +.native-text { white-space: nowrap; pointer-events: none; } + +/* The title, centred in the dark band at the top (0.97: a 120-wide box at x 35, y 12). */ +#title { + position: absolute; + left: 0; + top: 12px; + width: 190px; + height: 15px; + cursor: move; +} +.title-text { + display: block; + width: 190px; + text-align: center; + transform-origin: center top; + color: #ffffff; + font-weight: bold; +} + +/* 0.97 has no set / socket options. */ +.option-labels, .option-hover { display: none; } + +/* Zen: the label at (20, 371) on its dark box (drawn by .bg-bottom, which the 0.97 frame does not + need), the bar Item_Money (113x18) at (50, 368) and the amount at (60, 371), coloured by size: + pale yellow, green from 100 000, orange from 1 000 000, red from 10 000 000. */ +@spritesheet classic-inv-money-sheet { src: ../../../Classic/Item_money.jpg; classic-inv-money: 0px 0px 113px 18px; } +.bg-bottom { + left: 20px; + top: 370px; + width: 22px; + height: 13px; + background-color: #282828; + font-size: 11px; + font-weight: bold; + decorator: text("Zen" #ffdc96 center center); +} +#gold_bg { + position: absolute; + left: 50px; + top: 368px; + width: 113px; + height: 18px; + decorator: image(classic-inv-money); + pointer-events: none; +} +#gold_text { + position: absolute; + left: 60px; + top: 371px; + transform-origin: left top; + font-weight: bold; + color: #ffdc96; +} +#gold_text.gold-hundred-thousand { color: #00c918; } +#gold_text.gold-million { color: #ff9600; } +#gold_text.gold-ten-million { color: #ff0000; } + +/* Close and Repair, 24x24 at (20, 395) and (48, 395), where the Season 1 client draws them beside + its personal shop button (0.97, without it: 25 and 60); the second image while pressed. */ +@spritesheet classic-inv-exit-sheet { src: ../../../Classic/Exit_01.jpg; classic-inv-exit: 0px 0px 24px 24px; } +@spritesheet classic-inv-exit2-sheet { src: ../../../Classic/Exit_02.jpg; classic-inv-exit-pressed: 0px 0px 24px 24px; } +@spritesheet classic-inv-repair-sheet { src: ../../../Classic/Repair_01.jpg; classic-inv-repair: 0px 0px 24px 24px; } +@spritesheet classic-inv-repair2-sheet { src: ../../../Classic/Repair_02.jpg; classic-inv-repair-pressed: 0px 0px 24px 24px; } +.inv-btn { + position: absolute; + top: 395px; + width: 24px; + height: 24px; + cursor: pointer; + pointer-events: auto; +} +.inv-btn.hidden { display: none; } +.inv-btn-exit { left: 20px; decorator: image(classic-inv-exit); } +.inv-btn-exit:active { decorator: image(classic-inv-exit-pressed); } +.inv-btn-repair { left: 48px; decorator: image(classic-inv-repair); } +.inv-btn-repair:active { decorator: image(classic-inv-repair-pressed); } + +/* The Season 1 client's personal shop button (005c76d0): btn_pshop (24x24) at (76, 395), + btn_pshop2 while the shop is open. Dimmed while it cannot be used. */ +@spritesheet classic-inv-pshop-sheet { src: ../../../Classic/s1/btn_pshop.jpg; classic-inv-pshop: 0px 0px 24px 24px; } +@spritesheet classic-inv-pshop2-sheet { src: ../../../Classic/s1/btn_pshop2.jpg; classic-inv-pshop-open: 0px 0px 24px 24px; } +#btn_myshop { left: 76px; decorator: image(classic-inv-pshop); } +#btn_myshop.close-mode { decorator: image(classic-inv-pshop-open); } +#btn_myshop.locked { filter: brightness(0.6); } + +/* The extended inventory's button has no 0.97 or Season 1 counterpart: it keeps legacy's own art + (newui_expansion_btn, 36x29) after the Season 1 buttons, on the row's centre, until the classic + theme has art for it. */ +@spritesheet classic-inv-expand-sheet { src: "../../../newui_expansion_btn.tga"; classic-inv-expand: 0px 0px 36px 29px; } +#btn_expand { display: block; left: 108px; top: 393px; width: 36px; height: 29px; decorator: image(classic-inv-expand); } +#btn_expand:hover { filter: brightness(1.25); } + +/* Equipment: each slot is its 0.97 background at its 0.97 place (the box is also where the slot + is clicked and the item drawn). */ +@spritesheet classic-slot-fairy-sheet { src: ../../../Classic/Item_fairy.jpg; classic-slot-fairy: 0px 0px 40px 40px; } +@spritesheet classic-slot-cap-sheet { src: ../../../Classic/Item_cap.jpg; classic-slot-cap: 0px 0px 40px 40px; } +@spritesheet classic-slot-wing-sheet { src: ../../../Classic/Item_wing.jpg; classic-slot-wing: 0px 0px 60px 40px; } +@spritesheet classic-slot-weapon1-sheet { src: ../../../Classic/Item_weapon01.jpg; classic-slot-weapon1: 0px 0px 40px 60px; } +@spritesheet classic-slot-upper-sheet { src: ../../../Classic/Item_upper.jpg; classic-slot-upper: 0px 0px 40px 60px; } +@spritesheet classic-slot-weapon2-sheet { src: ../../../Classic/Item_weapon02.jpg; classic-slot-weapon2: 0px 0px 40px 60px; } +@spritesheet classic-slot-gloves-sheet { src: ../../../Classic/Item_gloves.jpg; classic-slot-gloves: 0px 0px 40px 40px; } +@spritesheet classic-slot-lower-sheet { src: ../../../Classic/Item_lower.jpg; classic-slot-lower: 0px 0px 40px 40px; } +@spritesheet classic-slot-boots-sheet { src: ../../../Classic/Item_boots.jpg; classic-slot-boots: 0px 0px 40px 40px; } +@spritesheet classic-slot-necklace-sheet { src: ../../../Classic/Item_necklace.jpg; classic-slot-necklace: 0px 0px 20px 20px; } +@spritesheet classic-slot-ring-sheet { src: ../../../Classic/Item_ring.jpg; classic-slot-ring: 0px 0px 20px 20px; } + +.native-anchor { position: absolute; pointer-events: none; } +#slot_helper { left: 15px; top: 46px; width: 40px; height: 40px; decorator: image(classic-slot-fairy); } +#slot_helm { left: 75px; top: 46px; width: 40px; height: 40px; decorator: image(classic-slot-cap); } +#slot_wing { left: 115px; top: 46px; width: 60px; height: 40px; decorator: image(classic-slot-wing); } +#slot_weapon_right { left: 15px; top: 89px; width: 40px; height: 60px; decorator: image(classic-slot-weapon1); } +#slot_armor { left: 75px; top: 89px; width: 40px; height: 60px; decorator: image(classic-slot-upper); } +#slot_weapon_left { left: 134px; top: 89px; width: 40px; height: 60px; decorator: image(classic-slot-weapon2); } +#slot_amulet { left: 55px; top: 89px; width: 20px; height: 20px; decorator: image(classic-slot-necklace); } +#slot_gloves { left: 15px; top: 152px; width: 40px; height: 40px; decorator: image(classic-slot-gloves); } +#slot_pants { left: 75px; top: 152px; width: 40px; height: 40px; decorator: image(classic-slot-lower); } +#slot_boots { left: 134px; top: 152px; width: 40px; height: 40px; decorator: image(classic-slot-boots); } +#slot_ring_right { left: 55px; top: 152px; width: 20px; height: 20px; decorator: image(classic-slot-ring); } +#slot_ring_left { left: 115px; top: 152px; width: 20px; height: 20px; decorator: image(classic-slot-ring); } + +/* A slot's state tints its background as 0.97 did: wear 0.8 0.7 0 / 0.8 0.5 0 / 0.8 0.3 0.3, red + when broken, red-orange when the hero cannot use the item; while the item on the cursor cannot + go in, the S6 red wash. No art where the class wears nothing (Magic Gladiator's helm). */ +.equip-slot.no-art { decorator: none; } +.equip-slot.durability-50 { image-color: #ccb300; } +.equip-slot.durability-30 { image-color: #cc8000; } +.equip-slot.durability-20 { image-color: #cc4d4d; } +.equip-slot.broken { image-color: #ff0000; } +.equip-slot.unequipable { image-color: #ff331a; } +.equip-slot-item { position: absolute; left: 0; top: 0; right: 0; bottom: 0; } +.equip-slot.refused .equip-slot-item { background-color: rgba(230, 26, 26, 102); } + +#item_grid, #item_grid_counts { left: 15px; top: 200px; width: calc(8 * var(--item-cell)); height: calc(8 * var(--item-cell)); } +#item_view { height: 473px; } +#option_tooltip_anchor { left: 95px; top: 40px; } + +/* The grid's clicks are native (CInventoryCtrl), so the placed panel takes no pointer events; its + controls take their own. (Legacy's rule, which this copy predated.) */ +#panel.slot-placed { pointer-events: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/my_quest_info.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/my_quest_info.rcss new file mode 100644 index 0000000000..1976b07f8a --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/my_quest_info.rcss @@ -0,0 +1,273 @@ +/* Classic theme for CNewUIMyQuestInfoWindow (T). 0.97 has no quest window; the Season 1 client's + quest views (00418f90, 00419b60) use 0.97's parts: Trading_line (190x10) as the divider, and + win_button tabs (49 wide), the selected one raised and bright, the others darkened (0.6), as its + pet window's. Legacy's layout and comments below. Open takes Season 1's quest book (Quest1, Quest2 + pressed), beside Close; Give-up keeps legacy's icon (0.97 and Season 1 have none). */ + +/* Legacy theme for CMyQuestInfoWindow, retiring its last CUIControl-family pieces + (CUICurQuestListBox, CUIQuestContentsListBox, CButton x3). #panel/frame sprites/exit button + are shared with character_info/pet_info/party_info via docked_panel_frame.rcss + (linked in my_quest_info.rml before this file) -- only window-specific content lives here now. + Coordinates below are plain reference px, not dp. + + Content-area layout (quest list / divider / contents) reinterprets the original's intent rather + than porting CUICurQuestListBox/CUIQuestContentsListBox's own pixel math. Tab-row/button + positions are carried over exactly from SetPos()/SetButtonInfo()/RenderTabBtn(). */ +.frame-top { decorator: image(docked-bg-top-b); } + +@spritesheet myquest-line-sheet { src: ../../../Classic/Trading_line.jpg; myquest-line: 0px 0px 190px 10px; } +@spritesheet myquest-btn-open-sheet { src: "../../../Quest_Bt_open.tga"; myquest-btn-open: 0px 0px 36px 29px; } +@spritesheet myquest-btn-giveup-sheet { src: "../../../Quest_Bt_cast.tga"; myquest-btn-giveup: 0px 0px 36px 29px; } +@spritesheet myquest-tab-back-sheet { src: "../../../Quest_tab01.tga"; myquest-tab-back: 0px 0px 166px 22px; } +@spritesheet myquest-tab-small-sheet { src: "../../../Quest_tab02.tga"; myquest-tab-small: 0px 0px 48px 22px; } +@spritesheet myquest-tab-big-sheet { src: "../../../Quest_tab03.tga"; myquest-tab-big: 0px 0px 72px 22px; } + +#title { + position: absolute; + left: 0; + top: 12px; + width: calc(190px * var(--root-scale)); + text-align: center; + color: token(text-title); + font-weight: bold; + font-size: 1em; +} + +.tab-row { + position: absolute; + left: 10px; + top: 27px; + width: 166px; + height: 22px; + decorator: image(myquest-tab-back); +} +.tab-btn { + position: absolute; + top: 0; + height: 22px; + text-align: center; + line-height: 22px; + font-size: 1em; + color: token(text-muted); + cursor: pointer; + pointer-events: auto; + white-space: nowrap; + overflow: hidden; +} +.tab-btn.active { color: token(text-primary); } +.tab-btn-quest { left: 0; width: 48px; } +.tab-btn-jobchange { left: 48px; width: 48px; } +.tab-btn-castletemple { left: 96px; width: 72px; } +.tab-btn-quest.active { decorator: image(myquest-tab-small); } +.tab-btn-jobchange.active { decorator: image(myquest-tab-small); } +.tab-btn-castletemple.active { decorator: image(myquest-tab-big); } + +.quest-tab, .jobchange-tab, .castletemple-tab { + position: absolute; + left: 9px; + top: 60px; + width: 172px; + height: 320px; +} + +/* display:block is load-bearing on every non-absolutely-positioned element below -- unstyled + elements default to `display:inline`, which ignores width/height and won't stack in its own + row. */ +.quest-empty-msg { + position: absolute; + left: 14px; + top: 32px; /* native glyph tops at y+96, 18 apart; tab at y+60 */ + /* To the panel's inner edge (x 180, like .party-empty-msg), not native's 140 wrap width: the + original draws its line past 140 when the text grows (800x600, 1280x720). The text is one + line (MyQuestInfoWindow.cpp) and wraps here only when it would leave the frame. */ + width: calc(157px * var(--root-scale)); + color: token(text-heading); + font-weight: bold; + font-size: 1em; + text-align: left; +} +.quest-empty-msg span { display: block; } + +.quest-list { + position: absolute; + left: 0; + top: 0; + width: calc(172px * var(--root-scale)); + height: calc(100px * var(--root-scale)); + overflow: auto hidden; +} +/* Inside the .quest-list text layer: lengths are physical (end of file). */ +.quest-row { + display: block; + width: 100%; + color: token(text-primary); + font-size: 1em; + cursor: pointer; + pointer-events: auto; + white-space: nowrap; +} +.quest-row:hover { color: token(text-hover); } +.quest-row.selected { color: token(text-selected); font-weight: bold; } + +/* Native CNewUIMyQuestInfoWindow draws its divider (newui_myquest_Line) at y+160 on the quest tab, + y+182 on the job-change tab and y+210 on the castle/temple tab; the tabs start at y+60. */ +.quest-divider { + position: absolute; + left: 0; + top: 100px; + width: 172px; + height: 21px; + decorator: image(myquest-line); +} + +.quest-contents { + position: absolute; + left: 0; + top: 121px; + width: calc(172px * var(--root-scale)); + height: calc(199px * var(--root-scale)); + overflow: auto hidden; +} + +/* #reward_popup_anchor (my_quest_info.rml) marks where MyQuestInfoWindow.cpp's still-native + reward-item info-tooltip popup anchors -- panel-relative (a sibling of .quest-tab, not nested + inside it, matching that div's own comment), same left/top the popup's old hardcoded + m_Pos+95,+230 offset resolved to. */ +.quest-popup-anchor { + position: absolute; + width: 0; + height: 0; + pointer-events: none; +} +#reward_popup_anchor { left: 95px; top: 230px; } +.quest-content-row { + display: block; + width: 100%; + font-size: 1em; + color: token(text-info); +} +.quest-content-row.row-heading { font-weight: bold; } +/* A clickable row keeps its colour on hover, as the original list box does. */ +.quest-content-row.clickable { cursor: pointer; pointer-events: auto; } + +/* Open/Give-up only -- Exit is fully shared now (docked_panel_frame.rcss's #btn_exit). */ +.quest-btn { + position: absolute; + top: 392px; + width: 36px; + height: 29px; + cursor: pointer; + pointer-events: auto; +} +.quest-btn:hover { filter: brightness(1.25); } +/* No pointer-events:none -- RmlClickOpen()/RmlClickGiveUp() already guard on + openEnabled/giveupEnabled, so a locked click is already a safe no-op; dimming alone is + enough. */ +.quest-btn.locked { filter: brightness(0.6); } +.quest-btn-open { left: 50px; decorator: image(myquest-btn-open); } +.quest-btn-giveup { left: 87px; decorator: image(myquest-btn-giveup); } + +/* Exit is a common close button -- legacy's sprite already has its own "X" baked in, so the + shared label span is redundant. */ +.btn-exit-label { display: none; } + +.jobchange-title { + display: block; + text-align: center; + width: calc(172px * var(--root-scale)); + color: token(accent-teal); + font-weight: bold; + font-size: 1em; + /* Text layers: native title at y+58, contents from + y+76 in 16px rows; the tab starts at y+60. */ + position: absolute; + top: -3px; +} +.jobchange-contents, .jobchange-state { + display: block; + text-align: center; + width: 172px; + color: token(text-primary); + font-size: 1em; +} +.jobchange-contents { position: absolute; top: 15px; } +.jobchange-contents span { display: block; } +/* Native: status rows left-aligned at x+23 from y+283, 18 apart. */ +.jobchange-state { + position: absolute; + top: 220px; + left: 14px; + text-align: left; + color: token(text-heading); + font-weight: bold; +} +.jobchange-state span { display: block; } +.jobchange-divider { top: 122px; } +.castletemple-divider { top: 150px; } + +/* Native: Blood Castle at y+105 with lines at +125/+145, Illusion Temple at y+285 with lines at + +305/+325 (text tops; 20px rows, bound on the text layers in my_quest_info.rml, put the glyphs + there; the tab starts at y+60). */ +.castle-block, .temple-block { position: absolute; left: 0; text-align: center; } +.castle-block { top: 40px; } +.temple-block { top: 220px; } +.castle-title, .temple-title { + display: block; + color: token(text-heading); + font-weight: bold; + font-size: 1em; +} +.castle-line, .temple-line { + display: block; + color: token(text-primary); + font-size: 1em; +} + +/* Requirement/reward rows by kind (UI::Quests::RewardModel::RowStyle; the RML toggles + .row-). The original client's colors. */ +.quest-content-row.row-subject { color: #ffb90a; } +.quest-content-row.row-summary { color: #ffe6d2; } +.quest-content-row.row-heading { color: #b3e64d; } +.quest-content-row.row-requirement { color: #dfbf67; } +.quest-content-row.row-requirement-unmet { color: #ff1e1e; } +.quest-content-row.row-reward { color: #dfbf67; } +.quest-content-row.row-random-reward { color: #6767df; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#tab_quest { width: calc(48px * var(--root-scale)); height: calc(22px * var(--root-scale)); line-height: calc(22px * var(--root-scale)); } +#tab_jobchange { width: calc(48px * var(--root-scale)); height: calc(22px * var(--root-scale)); line-height: calc(22px * var(--root-scale)); } +#tab_castletemple { width: calc(72px * var(--root-scale)); height: calc(22px * var(--root-scale)); line-height: calc(22px * var(--root-scale)); } +.quest-empty-msg { line-height: calc(18px * var(--root-scale)); } +.quest-row { height: calc(18px * var(--root-scale)); line-height: calc(18px * var(--root-scale)); padding-left: calc(4px * var(--root-scale)); } +.quest-content-row { padding: calc(1px * var(--root-scale)) calc(4px * var(--root-scale)); } +.jobchange-title { line-height: calc(16px * var(--root-scale)); } +.jobchange-contents { width: calc(172px * var(--root-scale)); line-height: calc(16px * var(--root-scale)); } +.jobchange-state { width: calc(158px * var(--root-scale)); line-height: calc(18px * var(--root-scale)); } +.castle-block { width: calc(172px * var(--root-scale)); line-height: calc(20px * var(--root-scale)); } +.temple-block { width: calc(172px * var(--root-scale)); line-height: calc(20px * var(--root-scale)); } + +/* The native text size, counter-scaled out of the panel's scale. */ +#panel { font-size: calc(var(--text-px) / var(--root-scale)); } + +/* Season 1's tabs: win_button stretched to each tab, 16 high and darkened, the selected one 20 high + (raised 4) and bright; no S6 tab strip. The divider: Trading_line in proportion. */ +@spritesheet myquest-classic-tab-sheet { src: "../../../win_button.tga"; myquest-classic-tab: 0px 0px 49px 16px; } +.tab-row { decorator: none; } +.tab-btn { + top: 4px; + height: 16px; + line-height: 16px; + color: rgb(230, 220, 200); + image-color: rgb(153, 153, 153); + decorator: image(myquest-classic-tab fill); +} +.tab-btn.active { top: 0; height: 20px; line-height: 20px; z-index: 1; color: #ffffff; image-color: #ffffff; decorator: image(myquest-classic-tab fill); } +.quest-divider { decorator: image(myquest-line contain); } + +/* Open: Season 1's quest book, 24x24 at (55, 395) beside the 0.97 Close, as in the character window. + Give-up: legacy's icon after it. */ +@spritesheet myquest-classic-open-sheet { src: ../../../Classic/s1/Quest1.jpg; myquest-classic-open: 0px 0px 24px 24px; } +@spritesheet myquest-classic-open2-sheet { src: ../../../Classic/s1/Quest2.jpg; myquest-classic-open-pressed: 0px 0px 24px 24px; } +.quest-btn-open { left: 55px; top: 395px; width: 24px; height: 24px; decorator: image(myquest-classic-open); } +.quest-btn-open:active { decorator: image(myquest-classic-open-pressed); } +.quest-btn-giveup { left: 85px; top: 393px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/my_shop.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/my_shop.rcss new file mode 100644 index 0000000000..8155b962a1 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/my_shop.rcss @@ -0,0 +1,135 @@ +/* Classic theme for CMyShopInventory, the personal shop. 0.97 has none; the Season 1 client's + (005c8330) sits on the 0.97 inventory frame (Item_Back01 over Item_Back02) with its title in the + top band and the shop's name on Item_Money (150x24 at 20, 65). Its Open and Close are text + buttons; MuMain's are icon buttons, so the classic theme gives them Season 1's own icons, in the + row Season 1's inventory draws: Close at 20, open (btn_pshop) at 48, close shop (btn_pshop2) at 76, + y 395, 24x24. Legacy's layout and comments below. */ + +/* Legacy theme for CMyShopInventory's chrome (frame/title/shop-name field/Open-Close-Exit buttons). + The workspace places #panel (its slot's left/top/scale), so coordinates below are plain + reference px, not dp. */ + +#panel { + position: absolute; + transform-origin: left top; + width: 190px; + height: 429px; + font-family: "token(font-body)"; +} + +/* Between the frame's top corners, clear of the close button; a longer title ends in ".." and + scrolls on hover (base.rcss .marquee). */ +#title { + position: absolute; + left: 28px; + top: 15px; + width: calc(134px * var(--root-scale)); + text-align: center; + /* Native draws it in the normal font, 0xFF49B0FF -- an ABGR DWORD, i.e. (255,176,73). */ + color: #ffb049; + font-size: 1em; +} + +/* Shop-name field: only placement/size plus this window's own bespoke strip art -- every other + visual comes from base.rcss's shared .text-field. Box is the exact 169x26 @ (12,49) the + newui_Box_openTitle strip occupied as #edit_bg; padding-left puts the first glyph at x=50, the + same place the native CUITextInputBox drew it (SetPosition(m_Pos.x + 50, m_Pos.y + 55)), clearing + the label baked into the left of that sprite. Text colour matches the old + SetTextColor(255, 255, 230, 210). */ +@spritesheet shop-edit-bg-sheet { src: "../../../newui_Box_openTitle.tga"; shop-edit-bg: 0px 0px 169px 26px; } +.my-shop-title-field { + position: absolute; + left: 12px; + top: 49px; + width: 169px; + height: 26px; + padding: 6px 6px 0 38px; + font-size: 1em; + color: token(text-narrative); + background-color: transparent; + border-width: 0; + decorator: image(shop-edit-bg); +} + +/* Buttons: same 36x29 reference-pixel boxes ChangeButtonInfo() used to place them at. */ +@spritesheet shop-btn-exit-sheet { src: "../../../newui_exit_00.tga"; shop-btn-exit: 0px 0px 36px 29px; } +@spritesheet shop-btn-open-sheet { src: "../../../newui_Bt_openshop.tga"; shop-btn-open: 0px 0px 36px 29px; } +@spritesheet shop-btn-close-sheet { src: "../../../newui_Bt_closeshop.tga"; shop-btn-close: 0px 0px 36px 29px; } + +.shop-btn { + position: absolute; + top: 391px; + width: 36px; + height: 29px; + cursor: pointer; + pointer-events: auto; +} +.shop-btn:hover { filter: brightness(1.25); } +/* A locked CNewUIButton still shows its hint on hover; it only takes no click (MyShopInventory.cpp). */ +.shop-btn.locked, +.shop-btn.locked:hover { cursor: default; filter: brightness(0.6); } + +.shop-btn-exit { left: 13px; decorator: image(shop-btn-exit); } +.shop-btn-open { left: 53px; decorator: image(shop-btn-open); } +.shop-btn-close { left: 93px; decorator: image(shop-btn-close); } + +/* Former RenderTextInfo()'s colours; shop_notice.rcss lays the notice out. */ +.myshop-line-still-opening { color: #d78a00; } +.myshop-line-warning { color: #ff2d2f; } +.myshop-line-info { color: token(text-notice); } + +/* Native item grid: the first cell's top-left, in #panel's units. */ +.native-anchor { position: absolute; pointer-events: none; } +#item_grid, #item_grid_counts { left: 16px; top: 90px; width: calc(8 * var(--item-cell)); height: calc(4 * var(--item-cell)); } + +/* The frame. */ +@spritesheet shop-bg-fill-sheet { src: "../../../newui_msgbox_back.jpg"; shop-bg-fill: 0px 0px 190px 429px; } +@spritesheet shop-bg-top-sheet { src: "../../../newui_item_back01.tga"; shop-bg-top: 0px 0px 190px 64px; } +@spritesheet shop-bg-left-sheet { src: "../../../newui_item_back02-L.tga"; shop-bg-left: 0px 0px 21px 320px; } +@spritesheet shop-bg-right-sheet { src: "../../../newui_item_back02-R.tga"; shop-bg-right: 0px 0px 21px 320px; } +@spritesheet shop-bg-bottom-sheet { src: "../../../newui_item_back03.tga"; shop-bg-bottom: 0px 0px 190px 45px; } + +.bg-fill, .bg-top, .bg-left, .bg-right, .bg-bottom { + position: absolute; + pointer-events: none; +} + +.bg-fill { left: 0; top: 0; width: 190px; height: 429px; decorator: image(shop-bg-fill); } +.bg-top { left: 0; top: 0; width: 190px; height: 64px; decorator: image(shop-bg-top); } +.bg-left { left: 0; top: 64px; width: 21px; height: 320px; decorator: image(shop-bg-left); } +.bg-right { left: 169px; top: 64px; width: 21px; height: 320px; decorator: image(shop-bg-right); } +.bg-bottom { left: 0; top: 384px; width: 190px; height: 45px; decorator: image(shop-bg-bottom); } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#shop_title { width: calc(169px * var(--root-scale)); height: calc(26px * var(--root-scale)); padding: calc(6px * var(--root-scale)) calc(6px * var(--root-scale)) 0 calc(38px * var(--root-scale)); } + +/* The grid's clicks are native (CInventoryCtrl), so the placed panel takes no pointer events; its + controls take their own. */ +#panel.slot-placed { pointer-events: none; } +#panel { font-size: calc(var(--text-px, 12px) / var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet classic-shop-back1-sheet { src: ../../../Classic/Item_back01.jpg; classic-shop-back1: 0px 0px 190px 256px; } +@spritesheet classic-shop-back2-sheet { src: ../../../Classic/Item_Back02.jpg; classic-shop-back2: 0px 0px 190px 177px; } +@spritesheet classic-shop-money-sheet { src: ../../../Classic/Item_money.jpg; classic-shop-money: 0px 0px 113px 18px; } +@spritesheet classic-shop-exit-sheet { src: ../../../Classic/Exit_01.jpg; classic-shop-exit: 0px 0px 24px 24px; } +@spritesheet classic-shop-exit2-sheet { src: ../../../Classic/Exit_02.jpg; classic-shop-exit-pressed: 0px 0px 24px 24px; } +@spritesheet classic-shop-open-sheet { src: ../../../Classic/s1/btn_pshop.jpg; classic-shop-open: 0px 0px 24px 24px; } +@spritesheet classic-shop-close-sheet { src: ../../../Classic/s1/btn_pshop2.jpg; classic-shop-close: 0px 0px 24px 24px; } + +.bg-fill { top: 256px; height: 177px; decorator: image(classic-shop-back2); } +.bg-top { height: 256px; decorator: image(classic-shop-back1); } +.bg-left, .bg-right, .bg-bottom { display: none; } +#panel { height: 433px; } + +#title { left: 0; top: 12px; width: calc(190px * var(--root-scale)); color: #dcdcdc; font-weight: bold; } + +.my-shop-title-field { left: 20px; top: 50px; width: 150px; height: 24px; padding: 5px 6px 0 6px; decorator: image(classic-shop-money fill); } +#shop_title { width: calc(150px * var(--root-scale)); height: calc(24px * var(--root-scale)); padding: calc(5px * var(--root-scale)) calc(6px * var(--root-scale)) 0 calc(6px * var(--root-scale)); } + +.shop-btn { top: 395px; width: 24px; height: 24px; } +.shop-btn-exit { left: 20px; decorator: image(classic-shop-exit); } +.shop-btn-exit:active { decorator: image(classic-shop-exit-pressed); } +.shop-btn-open { left: 48px; decorator: image(classic-shop-open); } +.shop-btn-close { left: 76px; decorator: image(classic-shop-close); } +#frame_corner_close { display: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/npc_dialogue.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/npc_dialogue.rcss new file mode 100644 index 0000000000..3a4f453d7a --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/npc_dialogue.rcss @@ -0,0 +1,119 @@ +/* Classic theme for the NPC dialogue window (CNPCDialogue). 0.97 has no such window; it keeps + legacy's look on the classic docked frame, whose header (Item_Back01's dark band, y 5-30) is + shorter than legacy's: the Gens contribution banner moves under it. Legacy's layout and comments + below. */ + +/* Legacy theme for CNPCDialogue -- #panel/frame sprites/exit button come from + docked_panel_frame.rcss (linked before this file), same family as character_info/my_quest_info/ + pet_info/party_info/quest_progress. Coordinates below are plain reference px, not dp. + + L/R pager sprites duplicate quest_progress.rcss's own qp-btn-l/r defs (same Quest_bt_L/R.tga + asset, reused by both windows) rather than cross-linking that unrelated stylesheet -- this + window's layout (dual pagination, contribute banner, quest-list-mode text) isn't a "near-identical + sibling" the way CQuestProgress/CQuestProgressByEtc are to each other, so it gets its own files + (same "duplicate a small shared sprite def" choice quest_progress.rcss's own modern fork already + made for this exact asset). */ +.frame-top { decorator: image(docked-bg-top-a); } + +@spritesheet nd-btn-l-sheet { src: "../../../Quest_bt_L.tga"; nd-btn-l: 0px 0px 17px 18px; } +@spritesheet nd-btn-r-sheet { src: "../../../Quest_bt_R.tga"; nd-btn-r: 0px 0px 17px 18px; } +@spritesheet nd-line-sheet { src: "../../../newui_myquest_Line.tga"; nd-line-img: 0px 0px 188px 21px; } +@spritesheet nd-contribute-sheet { src: "../../../Gens_point.tga"; nd-contribute-img: 0px 0px 168px 18px; } + +/* Text layers: .sharp-text, base.rcss. */ + +/* NPC name doubles as this window's title -- dynamic (g_QuestMng.GetNPCName()), unlike the other + docked windows' own static #title text. */ +#title { + position: absolute; + left: 0; + top: 12px; + width: calc(100% * var(--root-scale)); + text-align: center; + color: token(accent-cyan); + font-weight: bold; +} + +/* Gens contribute-point banner (NPC 543/544 only) -- see RenderContributePoint()'s own gate, + preserved verbatim in SyncRmlModel(). No explicit display here -- base.rcss's + .hidden{display:none} (toggled by this element's own data-class-hidden="!show_contribute") must + win the cascade uncontested, same convention every data-class-hidden target in + my_quest_info.rcss already follows. */ +.nd-contribute { + position: absolute; + left: 11px; + top: 27px; + width: 168px; + height: 18px; + text-align: center; + color: token(text-narrative); + decorator: image(nd-contribute-img); +} + +.nd-npc-lines { + position: absolute; + left: 15.5px; /* native 13 + the native renderer's own glyph inset */ + top: 56.5px; /* native 59 is the glyph top; our rows centre the glyphs in the 15px gap */ + width: 160px; /* native DivideStringByPixel budget (wrap width, see NPCDialogue.cpp) */ +} +.nd-line { + display: block; + color: token(text-narrative); + white-space: nowrap; +} + +.nd-divider { + position: absolute; + left: 1px; + top: 181px; + width: 188px; + height: 21px; + decorator: image(nd-line-img); +} + +.nd-btn-l, .nd-btn-r { + position: absolute; + width: 17px; + height: 18px; + cursor: pointer; + pointer-events: auto; +} +.nd-btn-l { left: 131px; decorator: image(nd-btn-l); } +.nd-btn-r { left: 153px; decorator: image(nd-btn-r); } +.nd-btn-npc { top: 165px; } +.nd-btn-ans { top: 372px; } +.nd-btn-l:hover, .nd-btn-r:hover { filter: brightness(1.25); } +/* Native renders a locked pager button not at all (Render() skips IsLock() buttons), so a page + arrow only shows while there is another page that way. */ +.nd-btn-l.locked, .nd-btn-r.locked { display: none; } + +.nd-answers { + position: absolute; + left: 15.5px; + top: 204.5px; /* native 207, as .nd-npc-lines */ + width: 160px; +} +.nd-answer-row { + display: block; + color: token(text-narrative); + white-space: pre-line; + cursor: pointer; + pointer-events: auto; +} +.nd-answer-row:hover { background-color: token(surface-hover); } + +/* Exit is a common close button -- legacy's sprite already has its own "X" baked in, so the shared + label span is redundant (same convention quest_progress.rcss's own .btn-exit-label uses). */ +.btn-exit-label { display: none; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +.nd-contribute { width: calc(168px * var(--root-scale)); line-height: calc(18px * var(--root-scale)); } +#npc_lines_container { width: calc(160px * var(--root-scale)); line-height: calc(15px * var(--root-scale)); } +#answers_container { width: calc(160px * var(--root-scale)); line-height: calc(15px * var(--root-scale)); } + +/* The native text size, counter-scaled out of the placed root's scale. */ +#panel { font-size: calc(var(--text-px) / var(--root-scale)); } + +/* The Gens contribution banner under the classic header's ornament (y 31-39) instead of on it, + just clear of the NPC's lines (glyphs from y 59). */ +.nd-contribute { top: 40px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/npc_quest.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/npc_quest.rcss new file mode 100644 index 0000000000..83c6a42031 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/npc_quest.rcss @@ -0,0 +1,210 @@ +/* Classic theme for the NPC quest window (CNewUINPCQuest). 0.97 has no quest window; the Season 1 + client's quest views use 0.97's parts: Trading_line (190x10) as the divider, a 0.97 text plate + (Message_box) as the button, lit warm under the mouse, and 0.97's zen box (Item_money). Legacy's + layout and comments below. */ + +/* CNPCQuest (npc_quest.rml). docked_panel_frame.rcss (linked first) supplies #panel/.frame-piece/ + #btn_exit/.tooltip; #panel is the frame inside #content_root, the document's positioning root. + Coordinates below are plain reference px, not dp. + + Divider/Complete-button sprites duplicate assets other sibling windows this session already use + (newui_myquest_Line.tga, newui_btn_empty.tga -- the same texture quest_progress.rcss's own + qp-btn-complete-idle/hover spritesheet uses) rather than cross-linking those unrelated + stylesheets -- same "duplicate a small shared sprite def" choice made for every sibling this + session. */ +.frame-top { decorator: image(docked-bg-top-a); } + +/* The positioning root, unpainted: #panel inside it is the frame. It carries the font-family + docked_panel_frame.rcss's #panel gives every sibling, which the texts here would otherwise lack. */ +#content_root { + position: absolute; + transform-origin: left top; + width: 190px; + height: 429px; + font-family: "token(font-body)"; +} + +/* The frame, at #content_root's own place; the item preview over it, under the rows. */ +#content_root > #panel { left: 0; top: 0; pointer-events: none; } +.nq-item { position: absolute; left: 0; top: 0; width: 190px; height: 429px; pointer-events: none; } + +@spritesheet nq-line-sheet { src: ../../../Classic/Trading_line.jpg; nq-line-img: 0px 0px 190px 10px; } +@spritesheet nq-btn-complete-sheet { + src: "../../../newui_btn_empty.tga"; + nq-btn-complete-idle: 0px 0px 108px 29px; + nq-btn-complete-hover: 0px 29px 108px 29px; +} +@spritesheet nq-zen-sheet { src: ../../../Classic/Item_money.jpg; nq-zen-img: 0px 0px 113px 18px; } + +/* NPC name doubles as this window's title -- dynamic (g_csQuest.GetNPCName()), same convention + npc_dialogue.rcss's own #title uses. */ +#title { + position: absolute; + left: 0; + top: 16px; + width: calc(190px * var(--root-scale)); + text-align: center; + color: token(accent-cyan); /* native g_hFont, not bold */ + font-size: 1em; +} + +/* Suppressed for Dark Lord/Dark/RageFighter-class NPCs (bCheckNPC gate) -- see SyncRmlModel()'s own + comment. No explicit display here -- base.rcss's .hidden must win the cascade uncontested (this + session's own overlap bugfix established why an explicit display:block here would always beat + it, regardless of show_quest_title). */ +.nq-quest-title { + position: absolute; + left: 0; + top: 29px; + width: calc(190px * var(--root-scale)); + text-align: center; + color: #c8dcff; + font-size: 1em; +} + +.nq-divider { + position: absolute; + left: 1px; + top: 325px; + width: 188px; + height: 21px; + decorator: image(nq-line-img); +} + +/* The always-present divider (npc_quest_bg.rml) under the dialogue text. */ +.nq-divider-dialogue { top: 220px; } + +/* No explicit display -- same reasoning as .nq-quest-title above. */ +.nq-conditions { + position: absolute; + left: 52px; + top: 244px; + width: 128px; +} +/* Rows inside text layers (npc_quest.rml) take the layer's bound line height as their pitch. */ +.nq-condition-row { + display: block; + font-weight: bold; + font-size: 1em; + white-space: nowrap; +} + +.nq-btn-complete { + position: absolute; + left: 41px; + top: 355px; + width: 108px; + height: 29px; + text-align: center; + vertical-align: middle; + line-height: 29px; + color: token(text-narrative); + font-size: 1em; + cursor: pointer; + pointer-events: auto; + decorator: image(nq-btn-complete-idle); +} +.nq-btn-complete:hover { decorator: image(nq-btn-complete-hover); } +.nq-btn-complete.disabled { + color: token(text-inactive); + pointer-events: none; + cursor: default; + filter: brightness(0.6); +} + +/* No explicit display -- same reasoning as .nq-quest-title above. */ +.nq-cost { + position: absolute; + left: 11px; + top: 361px; + width: 170px; + height: 24px; + decorator: image(nq-zen-img); +} +/* Native draws the label at x+20 and the amount right-aligned to x+170 (window coordinates), both + bold at y+368; .nq-cost itself starts at x+11. */ +.nq-cost-label { + display: block; + position: absolute; + left: 9px; + top: 7px; + color: token(text-hint); + font-weight: bold; + font-size: 1em; +} +.nq-cost-amount { + display: block; + position: absolute; + left: 9px; + top: 7px; + width: 150px; + text-align: right; + font-weight: bold; + font-size: 1em; +} + +/* Native centred the message and answer lines on a band of NUM_LINE_CMB (7) lines from 66, 18 + apart. With no quest in progress it drew the answers at 250 instead, but still centred the + messages as if the answers followed them: the padding keeps that room. */ +#nq_dialogue { + position: absolute; + left: 0; + top: 66px; + --flow-w: 190px; + --flow-h: 126px; + box-sizing: border-box; + text-align: center; +} +#nq_dialogue.answers-anchored { padding-bottom: calc(var(--answer-lines, 0) * 18px * var(--root-scale)); } +#nq_dialogue.answers-anchored .nq-answers { + position: absolute; + left: 0; + top: calc(184px * var(--root-scale)); + width: 100%; +} +/* Native advances every message and answer line 18 reference px and never wraps them. */ +.nq-message-line { + display: block; + white-space: nowrap; + color: token(text-narrative); + font-size: 1em; +} +.nq-answer-row { + display: block; + white-space: nowrap; + color: #dfbf67; + font-weight: bold; + font-size: 1em; + cursor: pointer; + pointer-events: auto; +} +/* Native highlighted the hovered answer by swapping its text color to red, not a background + highlight -- preserved exactly, not replaced with the translucent-quad style other sibling + answer lists use, since that's genuinely how this window's own RenderText() colored it. */ +.nq-answer-row:hover { color: #ff0000; } + +/* Exit is a common close button -- legacy's sprite already has its own "X" baked in, so the shared + label span is redundant (same convention every sibling this session uses). */ +.btn-exit-label { display: none; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#conditions_anchor { width: calc(128px * var(--root-scale)); line-height: calc(32px * var(--root-scale)); } +#btn_complete { width: calc(108px * var(--root-scale)); height: calc(29px * var(--root-scale)); line-height: calc(29px * var(--root-scale)); } +.nq-cost-amount.gold-amount { width: calc(150px * var(--root-scale)); } +#nq_dialogue { line-height: calc(18px * var(--root-scale)); } + +/* The native text size, counter-scaled out of the placed root's scale. */ +#content_root { font-size: calc(var(--text-px) / var(--root-scale)); } + +@spritesheet nq-classic-plate-sheet { src: ../../../Classic/Message_box.jpg; nq-classic-plate: 0px 0px 213px 64px; } +.nq-divider { decorator: image(nq-line-img contain); } +.nq-btn-complete, .nq-btn-complete:hover, .nq-btn-complete.disabled { decorator: image(nq-classic-plate fill); } +.nq-btn-complete:hover { image-color: #ffe3c6; filter: brightness(1.7); } +.nq-cost { decorator: image(nq-zen-img fill); } + +/* The name and the quest title in Item_Back01's dark band (y 5-30), shorter than legacy's header, + whose quest title line (y 29) fell on the band's ornament; the name alone (a Dark Lord or Magic + Gladiator at Marlon) where the other classic windows put their title. */ +#title { top: 12px; } +#title.with-quest-title { top: 8px; } +.nq-quest-title { top: 19px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/npc_shop.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/npc_shop.rcss new file mode 100644 index 0000000000..3391425c54 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/npc_shop.rcss @@ -0,0 +1,86 @@ +/* Classic (0.97) NPC shop (CNPCShop), from the 0.97 client's 004f1f50: Item_Back01 over Item_Back02, the title at the top, + the 8x15 grid at (15, 50), Repair and Repair all (repair_01, 24x24, the second image while + pressed) at (85, 365) and (115, 365), and the repair cost: "Repair all" at (20, 398) on its dark + box and the bar (Item_Money) at (55, 395). 0.97's Buy / Sell mode buttons (25 and 55) have no + MuMain counterpart (buying and selling are by click and drag). No tax line (not in 0.97). + #panel's left/top/scale come from C++; everything below is the window's own units. */ + +@spritesheet shop-classic-back1-sheet { src: ../../../Classic/Item_back01.jpg; shop-classic-back1: 0px 0px 190px 256px; } +@spritesheet shop-classic-back2-sheet { src: ../../../Classic/Item_Back02.jpg; shop-classic-back2: 0px 0px 190px 177px; } + +#panel { + position: absolute; + transform-origin: left top; + width: 190px; + height: 433px; + font-family: "token(font-body)"; +} + +.bg-fill, .bg-top, .bg-left, .bg-right, .bg-bottom { position: absolute; pointer-events: none; } +.bg-top { left: 0; top: 0; width: 190px; height: 256px; decorator: image(shop-classic-back1); } +.bg-fill { left: 0; top: 256px; width: 190px; height: 177px; decorator: image(shop-classic-back2); } +.bg-left, .bg-right, .bg-bottom { display: none; } + +#title { + position: absolute; + /* 0.97: a 120-wide box at x 35, centred. */ + left: 35px; + top: 12px; + width: calc(120px * var(--root-scale)); + text-align: center; + color: #dcdcdc; + font-weight: bold; + font-size: 1em; +} +#tax_rate { display: none; } + +@spritesheet shop-classic-repair1-sheet { src: ../../../Classic/Repair_01.jpg; shop-classic-repair: 0px 0px 24px 24px; } +@spritesheet shop-classic-repair2-sheet { src: ../../../Classic/Repair_02.jpg; shop-classic-repair-pressed: 0px 0px 24px 24px; } +.shop-btn { + position: absolute; + top: 365px; + width: 24px; + height: 24px; + cursor: pointer; + pointer-events: auto; + decorator: image(shop-classic-repair); +} +.shop-btn:active { decorator: image(shop-classic-repair-pressed); } +.shop-btn.hidden { display: none; } +.shop-btn-repair { left: 85px; } +.shop-btn-repair-all { left: 115px; } + +@spritesheet shop-classic-money-sheet { src: ../../../Classic/Item_money.jpg; shop-classic-money: 0px 0px 113px 18px; } +.repair-money { + position: absolute; + left: 55px; + top: 395px; + width: 113px; + height: 18px; + pointer-events: none; + decorator: image(shop-classic-money); +} +.repair-money.hidden { display: none; } +.repair-money-label, .repair-money-value { + position: absolute; + top: 398px; + font-weight: bold; + font-size: 1em; + white-space: nowrap; + pointer-events: none; +} +.repair-money-label { left: 20px; color: #ffdc96; background-color: #282828; } +.repair-money-value { left: 65px; color: #ffdc96; } +.repair-money-value.gold-hundred-thousand { color: #00c918; } +.repair-money-value.gold-million { color: #ff9600; } +.repair-money-value.gold-ten-million { color: #ff0000; } +.repair-money-label.hidden, .repair-money-value.hidden { display: none; } + +.native-anchor { position: absolute; pointer-events: none; } +#item_grid, #item_grid_counts { left: 15px; top: 50px; width: calc(8 * var(--item-cell)); height: calc(15 * var(--item-cell)); } +#item_view { height: 473px; } + +/* The grid's clicks are native (CInventoryCtrl), so the placed panel takes no pointer events; its + controls take their own. (Legacy's rules, which this copy predated.) */ +#panel.slot-placed { pointer-events: none; } +#panel { font-size: calc(var(--text-px, 12px) / var(--root-scale)); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/option_window.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/option_window.rcss new file mode 100644 index 0000000000..ac8354bcb1 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/option_window.rcss @@ -0,0 +1,626 @@ +/* Classic (0.97) theme for the settings window. A theme's stylesheet replaces its base's whole file, + so this is legacy's option_window.rcss (its layout, scrolling settings area and tuning rows, with + legacy's comments) followed by the classic parts at the end. + + 0.97 has no settings window: its Esc menu's "Options" opens a box in the Esc menu's own style + (0051af50): the title "Options" centred at y 35, then 0.97 text plates (Message_box, 120x22) at + y 60, 90 and 120 for "Automatic Attack: On/Off", "Sound on Whisper: On/Off" and "Close", lit warm + under the mouse. MuMain's window has more to set (five tabs and the tuning of each Enhanced + feature), so it takes 0.97's parts rather than its layout: the dialog stone of 0.97's boxes + (Message_box1, edged by Message_box2), the title centred at the top, the tabs and the tuning's + Reset buttons as text plates lit like 0.97's, and the check boxes, scrollbar and close cross of + the classic social windows. The gauges and sliders are legacy's. */ + +#panel { + width: 440dp; + height: 310dp; + max-height: 96%; + font-family: "token(font-body)"; + font-size: 1rem; + color: token(text-input); +} + +/* window_shell.rcss draws the msgbox caps with image(), which only fits its 230dp art. Here the same + sprites are ninepatches (the slices chat_room.rcss uses), so the corners and border thickness keep + their size at this width, and the back fill repeats its texture instead of stretching it. Scoped + to this document. */ +@spritesheet option-cap-top-sheet { src: "../../../newui_msgbox_top.tga"; option-cap-top: 0px 0px 230px 67px; option-cap-top-inner: 12px 12px 206px 43px; } +@spritesheet option-cap-middle-sheet { src: "../../../newui_msgbox_middle.tga"; option-cap-middle: 0px 0px 230px 15px; option-cap-middle-inner: 12px 4px 206px 7px; } +@spritesheet option-cap-bottom-sheet { src: "../../../newui_msgbox_bottom.tga"; option-cap-bottom: 0px 0px 230px 50px; option-cap-bottom-inner: 12px 12px 206px 26px; } +@spritesheet option-back-sheet { src: "../../../newui_msgbox_back.jpg"; option-back: 0px 0px 222px 250px; } +.window-shell-sprite-back { decorator: image(option-back repeat left top); } +.window-shell-sprite-top { decorator: ninepatch(option-cap-top, option-cap-top-inner); } +.window-shell-sprite-middle { decorator: ninepatch(option-cap-middle, option-cap-middle-inner); } +.window-shell-sprite-bottom { decorator: ninepatch(option-cap-bottom, option-cap-bottom-inner); } + +/* The content well: the tab row at its top and the settings area below it + (.option-tab-scroll). An ID selector, so it wins over window_shell.rcss's own + .window-shell-content insets regardless of link order. */ +#content { + left: 18dp; + right: 18dp; + top: 30dp; + bottom: 18dp; + display: block; +} + +/* One row of tab buttons -- reuses my_quest_info.rcss's own tab sprite family + (Quest_tab01/02.tga) rather than a hand-rolled boxed-button look, per that window already being + the established "tabbed legacy window" reference. Not a pixel-for-pixel port though: + my_quest_info.rcss's own .tab-row/.tab-btn are fixed reference-px position:absolute with + 3 unequal-width tabs (48/48/72px) hand-placed to match its own fixed 190px frame -- this window + has 6 equal-width tabs across a differently-sized flex/dp row, needing each sprite resized to a + box different from its own native pixel size. `decorator: image(...)` does NOT stretch a sprite + to a mismatched box in this RmlUi build (most of the box stays unpainted instead of the art + scaling); `ninepatch(...)` does, correctly, in both directions, same fix already used for + .gmd-btn.cols-2/.server-row's own resized reuse of a fixed-size sprite. Inner rects below are a + conservative uniform inset (not pixel-verified against the source art, unlike legacy-btn-idle's + own inner rect) -- revisit if the stretched edges show visible seams/artifacts. Redeclared + spritesheets (RmlUi spritesheets are per-document, can't share my_quest_info.rcss's own). */ +@spritesheet option-tab-back-sheet { src: "../../../Quest_tab01.tga"; option-tab-back: 0px 0px 166px 22px; option-tab-back-inner: 6px 4px 154px 14px; } +@spritesheet option-tab-active-sheet { src: "../../../Quest_tab02.tga"; option-tab-active: 0px 0px 48px 22px; option-tab-active-inner: 4px 4px 40px 14px; } +.option-tab-row { + position: absolute; + left: 0; + right: 0; + top: 0; + display: flex; + height: 22dp; + decorator: ninepatch(option-tab-back, option-tab-back-inner); +} +/* Sized by their labels (not equal cells): "Gameplay" and "Graphics" need more room than + "UI", and equal cells cut them off. */ +.option-tab-btn { + flex: 1 1 auto; + padding: 0 4dp; + height: 22dp; + line-height: 22dp; + text-align: center; + font-size: 1rem; + white-space: nowrap; + overflow: hidden; + cursor: pointer; + pointer-events: auto; + color: token(text-muted); +} +.option-tab-btn:hover { + color: token(text-input); +} +.option-tab-btn.active-tab { + color: token(text-primary); + decorator: ninepatch(option-tab-active, option-tab-active-inner); +} + +/* The settings of the active tab, below the tab row. It scrolls with the chat log's scrollbar + (base.rcss's .scroll-pane) when its rows don't fit; the tabs and the close cross stay where they + are. A tab's last dropdown opens its list upwards (.option-opens-up), so it stays inside this area. */ +.option-tab-scroll { + position: absolute; + left: 0; + right: 0; + top: 30dp; + bottom: 0; +} + +/* One tab's rows, top to bottom. The .hidden override is needed because this display:flex would + otherwise tie with base.rcss's .hidden{display:none} and win by load order. */ +.option-tab-panel { + display: flex; + flex-direction: column; + padding: 2dp 10dp 0 4dp; +} +.option-tab-panel.hidden { + display: none; +} + +/* A label column and a control column. A row is as tall as its label, which wraps when a + translation or a larger font needs a second line, and at least as tall as its control. */ +.option-row { + position: relative; + display: flex; + align-items: center; + flex-shrink: 0; + min-height: 20dp; + margin-bottom: 6dp; +} +/* A part of the row above it: indented under its label, its control still in the column. */ +.option-sub-row .option-row-label { + margin-right: -12dp; + padding-left: 12dp; +} + +/* A heading over a group of rows. */ +.option-section { + flex-shrink: 0; + margin: 6dp 0 6dp; + padding-bottom: 2dp; + border-bottom: 1dp #5a4a2a; + color: token(text-primary); +} +.option-section:first-child { + margin-top: 0; +} +.option-checkbox-row { + cursor: pointer; + pointer-events: auto; +} +/* Not base.rcss's own .checkbox-label -- that's position:absolute, glyph-first (built for + login.rml's standalone checkboxes), which doesn't line up with a column of sibling rows. This + row uses .option-row-label (below) instead, label-first in the markup, same as every other row + type -- see option_window.rml's own comment. */ +.checkbox-box { + flex-shrink: 0; +} +/* Tick is baked into the checked-state sprite art (base.rcss's .checkbox-box.checked), same as + login.rcss's own legacy checkbox -- .checkbox-tick draws nothing here. */ +.checkbox-tick { + display: none; +} + +/* The label column: 44% of the row, the controls start where it ends in every row. */ +.option-row-label { + width: 44%; + flex-shrink: 0; + padding-right: 8dp; + white-space: normal; + line-height: 1.3em; + color: token(text-input); +} + +/* Volume and effect-limit gauges: base.rcss's .level-gauge at native's sizes (the volume bars + 124x16, the effect bar drawn 70x15), beside their labels. Native's volume hit area began 8 + units before the bar. */ +.option-gauge { + position: relative; + flex-shrink: 0; + width: 124dp; + height: 14dp; +} +.option-gauge.effect-gauge { + width: 70dp; + height: 15dp; +} +.option-gauge .level-gauge-fill { + left: 0; + top: 0; + bottom: 0; +} +.option-gauge-hit { + left: -8dp; + right: 0; +} + +/* Custom dropdown -- NOT RmlUi's native (WidgetDropDown.cpp) sets this same 1 on its generated + selectbox for the identical reason -- this is the custom-dropdown equivalent of that. */ +.option-dropdown-list { + display: block; + position: absolute; + left: 0; + top: 100%; + box-sizing: border-box; + width: 100%; + max-height: 90dp; + overflow-y: auto; + z-index: 1; + background-color: token(surface-control); + border-width: 1dp; + border-color: token(border-control); + pointer-events: auto; +} +.option-dropdown-list.hidden { + display: none; +} +/* Explicit scrollbar sizing, same reasoning generic_confirm_dialog.rcss's own .gcd-text-col + comment already gives for its own overflow:auto well -- an unstyled scrollbarvertical isn't + just visually wrong, its own (also unstyled) hit-test area can cover most/all of the option + row's width instead of a slim strip at the edge, silently swallowing clicks meant for the + option text beneath it as a scrollbar drag instead. Arrow buttons collapsed to 0, same + drag/click-only affordance as every other scrollbar in this codebase. */ +.option-dropdown-list scrollbarvertical { + width: 6dp; + margin: 0; +} +.option-dropdown-list scrollbarvertical slidertrack { + background-color: token(surface-recessed); +} +.option-dropdown-list scrollbarvertical sliderbar { + background-color: token(control-thumb); +} +.option-dropdown-list scrollbarvertical sliderbar:hover, +.option-dropdown-list scrollbarvertical sliderbar:active { + background-color: token(control-thumb-hover); +} +.option-dropdown-list scrollbarvertical sliderarrowdec, +.option-dropdown-list scrollbarvertical sliderarrowinc { + width: 0; + height: 0; +} +.option-dropdown-option { + display: block; + width: 100%; + padding: 2dp 4dp; + white-space: nowrap; + cursor: pointer; + pointer-events: auto; + color: token(text-input); +} +.option-dropdown-option:hover { + color: token(text-primary); + background-color: token(border-control); +} +.option-dropdown-option.selected { + color: token(text-primary); + background-color: #8f6922; +} + +/* A row with a hint (data-hint) takes the pointer itself, so the hint shows anywhere on the row: + body's pointer-events: none would leave only its control hoverable. */ +.option-row-tipped { + pointer-events: auto; +} +/* A tab's last dropdown opens its list upwards, over the rows above. */ +.option-opens-up .option-dropdown-list { + top: auto; + bottom: 100%; +} + +/* Close is the window-control cross the friend and chat windows use, in the frame's top-right corner + (#content's top-right, pulled out over its inset). Drawn larger than its 9px art, in proportion to + this wider frame: a ninepatch whose inner rect is the whole sprite scales it evenly, where image() + would not stretch it. */ +@spritesheet option-close-sheet { src: "../../../win_size.jpg"; option-close: 0px 9px 9px 9px; option-close-inner: 0px 9px 9px 9px; } +.option-close-btn { + position: absolute; + right: -5dp; + top: -18dp; + width: 14dp; + height: 14dp; + cursor: pointer; + pointer-events: auto; + decorator: ninepatch(option-close, option-close-inner); +} +.option-close-btn:hover { + image-color: rgba(255, 255, 255, 220); +} + +/* The original's options window has no title banner, only the plain top cap: the shell's title + (bound to "Option" for the modern theme) is not shown here. It used to be invisible by accident + (its font was an unsubstituted token in window_shell.rcss). */ +.window-shell-header-rail, +.window-shell-header-title { display: none; } + +/* A setting another one already covers (OptionWindow.h's OptionRmlModel): shown ticked, dimmed, and + not clickable. */ +.option-checkbox-row.locked { + opacity: 0.45; + cursor: default; +} + +/* The player's tuning of each Enhanced feature (OptionWindow.h's tuning rows), under the feature's + row. The feature's label and chevron expand its sliders; only the checkbox switches the feature. + A locked feature dims its checkbox, not its label, which still expands the tuning. */ +.option-tuning-group-row { + cursor: default; +} +.option-tuning-group-row.locked { + opacity: 1; +} +.option-tuning-group-row.locked .checkbox-box { + opacity: 0.45; +} +.option-tuning-group-row .checkbox-box { + cursor: pointer; +} +.option-tuning-group-label { + cursor: pointer; +} +.option-tuning-group-label:hover { + color: token(text-primary); +} +/* A small arrow before the label: pointing right while collapsed, down while expanded. */ +.option-tuning-chevron { + display: inline-block; + width: 5dp; + height: 5dp; + margin: 0 6dp 1dp -10dp; + border-right: 1dp token(text-secondary); + border-bottom: 1dp token(text-secondary); + transform: rotate(-45deg); +} +.option-tuning-chevron.expanded { + transform: rotate(45deg); +} +/* .hidden ties with these rules' display at equal specificity, so it is restated. */ +.option-tuning-group, +.option-tuning-more, +.option-tuning-rows { + display: block; + flex-shrink: 0; +} +.option-tuning-group { + margin: -2dp 0 8dp 12dp; + padding-left: 6dp; + border-left: 1dp #5a4a2a; +} +.option-tuning-group.hidden, +.option-tuning-more.hidden, +.option-tuning-reason.hidden, +.option-tuning-error.hidden { + display: none; +} +.option-tuning-reason { + display: block; + margin-bottom: 4dp; + color: token(semantic-warning); +} +.option-tuning-row { + display: block; + margin-bottom: 6dp; +} +.option-tuning-head { + display: flex; + align-items: center; +} +.option-tuning-label { + flex: 1 1 auto; + color: token(text-input); +} +.option-tuning-value { + flex: 0 0 auto; + margin-left: 6dp; + color: token(text-primary); +} +.option-tuning-state { + flex: 0 0 auto; + margin-left: 6dp; + color: token(text-muted); +} +.option-tuning-state.custom { + color: token(accent-gold); +} +.option-tuning-state.unsaved { + color: token(semantic-warning); +} +.option-tuning-reset { + flex: 0 0 auto; + margin-left: 6dp; + padding: 0 4dp; + cursor: pointer; + pointer-events: auto; + color: token(text-muted); + border-width: 1dp; + border-color: token(border-control); + background-color: token(surface-control); +} +.option-tuning-reset:hover { + color: token(text-primary); +} +.option-tuning-track { + display: flex; + align-items: center; + margin-top: 2dp; +} +.option-tuning-bound { + flex: 0 0 auto; + width: 52dp; + white-space: nowrap; + color: token(text-muted); +} +.option-tuning-track .option-tuning-bound:last-child { + text-align: right; +} +/* The volume gauge's art: its rail, and its full fill at its own size, cut off at the value as + native draws it (scale-none crops the image to the fill's width). */ +.option-tuning-slider { + margin: 0 6dp; +} +.option-tuning-fill { + decorator: image(level-gauge-fill-10 scale-none left center); +} +.option-tuning-hit { + left: -6dp; + right: -6dp; + top: -5dp; + bottom: -5dp; +} +.option-tuning-hit:focus { + border-width: 1dp; + border-color: token(accent-gold); +} +.option-tuning-group.locked .option-tuning-track { + opacity: 0.45; +} +.option-tuning-group.locked .option-tuning-hit { + cursor: default; +} +.option-tuning-more-head { + display: block; + margin: 2dp 0 6dp; + cursor: pointer; + pointer-events: auto; + color: token(text-secondary); +} +.option-tuning-more-head .option-tuning-chevron { + margin-left: 0; +} +.option-tuning-more-head:hover { + color: token(text-primary); +} +.option-tuning-actions { + display: flex; + flex-shrink: 0; + justify-content: flex-end; + margin-bottom: 4dp; +} +.option-tuning-all { + margin: 0 0 8dp; +} +.option-tuning-error { + display: block; + flex-shrink: 0; + margin-bottom: 8dp; + color: token(semantic-danger); +} + +/* ---- Classic (0.97) parts ------------------------------------------------------------------- */ + +@spritesheet classic-opt-stone-sheet { src: ../../../Classic/Message_box1_440x300.jpg; classic-opt-stone: 0px 0px 440px 300px; } +@spritesheet classic-opt-edge-sheet { src: ../../../Classic/Message_box2_440.jpg; classic-opt-edge: 0px 0px 440px 5px; } +@spritesheet classic-opt-plate-sheet { src: ../../../Classic/Message_box.jpg; classic-opt-plate: 0px 0px 213px 64px; } +@spritesheet classic-opt-check-sheet { src: "../../../win_check.tga"; classic-opt-check: 0px 0px 5px 5px; } +@spritesheet classic-opt-scroll-sheet +{ + src: "../../../win_scrollbar.jpg"; + classic-opt-scroll-thumb: 0px 1px 11px 1px; + classic-opt-scroll-up: 0px 3px 13px 13px; + classic-opt-scroll-down: 0px 16px 13px 13px; +} + +#panel { + color: rgb(230, 220, 200); +} +/* Room above the tabs for the title. */ +#content { + top: 34dp; +} + +/* The box, in place of legacy's message box caps: 0.97's dialog stone (Message_box1, 213x40) in + rows between two edge strips (Message_box2, 213x5). Stretched to this 440 width, their 5-texel + sides blurred into wide bands, so both come widened ahead of time + (tools/classic_theme/make_classic_derived_textures.py): the sides keep their width and only the + stone between them stretches, in proportion, in rows down to the 300 between the edges. */ +.window-shell-sprite-back { + left: 0; + right: 0; + top: 5dp; + bottom: 5dp; + height: auto; + decorator: image(classic-opt-stone fill); +} +.window-shell-sprite-middle { decorator: none; } +.window-shell-sprite-top { left: 0; right: 0; top: 0; height: 5dp; decorator: image(classic-opt-edge fill); } +.window-shell-sprite-bottom { left: 0; right: 0; bottom: 0; height: 5dp; decorator: image(classic-opt-edge fill); } + +/* The title, centred near the top as 0.97's "Options" (its rail art is not 0.97's). */ +.window-shell-header-title { display: block; top: 12dp; color: #ffffff; } +.window-shell-header-title.hidden { display: none; } + +/* The tabs: one row of 0.97 text plates, each sized by its label, the active one and the one under + the mouse lit as 0.97 lit its plates (additive 0.8, 0.6, 0.4: brightened and warmed). */ +.option-tab-row { decorator: none; } +.option-tab-btn { + margin-right: 1dp; + padding: 0 3dp; + color: rgb(200, 190, 170); + decorator: image(classic-opt-plate fill); +} +.option-tab-btn:last-child { margin-right: 0; } +.option-tab-btn:hover, +.option-tab-btn.active-tab { color: #ffffff; image-color: #ffe3c6; filter: brightness(1.7); decorator: image(classic-opt-plate fill); } + +/* Text on 0.97's colours; headings and the tuning's guide line on the classic line colour. */ +.option-row-label, +.option-tuning-label { color: rgb(230, 220, 200); } +.option-section { color: #ffffff; border-bottom-color: rgb(106, 97, 88); } +.option-tuning-group { border-left-color: rgb(106, 97, 88); } +.option-tuning-value { color: #ffffff; } +.option-tuning-group-label:hover, +.option-tuning-more-head:hover { color: #ffffff; } +.option-tuning-more-head { color: rgb(200, 190, 170); } +.option-tuning-chevron { border-right-color: rgb(146, 134, 121); border-bottom-color: rgb(146, 134, 121); } +.option-tuning-group-label:hover .option-tuning-chevron, +.option-tuning-more-head:hover .option-tuning-chevron { border-right-color: #ffffff; border-bottom-color: #ffffff; } + +/* The classic social windows' check box: 106,97,88 inside a 146,134,121 line, the win_check mark + when set (themes/classic/friend_shell.rcss). */ +.option-checkbox-row .checkbox-box { + width: 11dp; + height: 11dp; + box-sizing: border-box; + border: 1dp rgb(146, 134, 121); + background-color: rgb(37, 37, 37); + decorator: none; +} +.option-checkbox-row .checkbox-box.checked { decorator: image(classic-opt-check fill); background-color: rgb(106, 97, 88); } +.option-checkbox-row:hover .option-row-label { color: #ffffff; } + +/* The lists on 0.97's text colours, on black with the classic line colour. */ +.option-dropdown-value, .option-dropdown-list { background-color: rgba(0, 0, 0, 200); border-color: rgb(146, 134, 121); color: rgb(230, 220, 200); } +.option-dropdown-option { color: rgb(230, 220, 200); } +.option-dropdown-option:hover { color: #ffffff; background-color: rgb(106, 97, 88); } +.option-dropdown-option.selected { color: #000000; background-color: rgb(146, 134, 121); } + +/* Reset (a setting, or a whole feature): small 0.97 text plates, lit under the mouse. */ +.option-tuning-reset { + height: 16dp; + line-height: 16dp; + padding: 0 8dp; + border-width: 0; + background-color: transparent; + color: rgb(230, 220, 200); + decorator: image(classic-opt-plate fill); +} +.option-tuning-reset:hover { color: #ffffff; image-color: #ffe3c6; filter: brightness(1.7); } +.option-tuning-hit:focus { border-color: rgb(146, 134, 121); } + +/* The settings area scrolls with the Season 1 client's win_scrollbar (as the classic social windows + and dialogs): 13x13 arrows at both ends, the track between two 106,97,88 lines, a grey thumb. */ +.scroll-pane scrollbarvertical { width: 13dp; margin: 0; } +.scroll-pane scrollbarvertical slidertrack { decorator: none; box-sizing: border-box; border-left: 1dp rgb(106, 97, 88); border-right: 1dp rgb(106, 97, 88); } +.scroll-pane scrollbarvertical sliderbar { height: auto; min-height: 6dp; margin: 0 1dp; decorator: image(classic-opt-scroll-thumb fill); } +.scroll-pane scrollbarvertical sliderbar:active { filter: none; } +.scroll-pane scrollbarvertical sliderarrowdec, +.scroll-pane scrollbarvertical sliderarrowinc { width: 100%; height: 13dp; pointer-events: auto; } +.scroll-pane scrollbarvertical sliderarrowdec { decorator: image(classic-opt-scroll-up); } +.scroll-pane scrollbarvertical sliderarrowinc { decorator: image(classic-opt-scroll-down); } +.scroll-pane scrollbarvertical sliderarrowdec:active, +.scroll-pane scrollbarvertical sliderarrowinc:active { filter: brightness(0.7); } + +/* Close: legacy's cross (win_size, the classic social windows' close), in the stone's top-right + corner below the edge strip. */ +.option-close-btn { top: -26dp; right: -10dp; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/party_info.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/party_info.rcss new file mode 100644 index 0000000000..d6a80b9da9 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/party_info.rcss @@ -0,0 +1,111 @@ +/* Classic (0.97) party window (P), from the 0.97 client's 004ef160: the title on its dark box at the top, the seven help + lines from y 50 while there is no party, and one 35-unit row per member from y 50 -- the name + (white on dark blue for the leader, pale blue for the others), the map and the coordinates in + pale orange, the health bar (a 92x5 dark red back, a 90x3 red fill) and "health / max" under + it. No group boxes and no leader flag. The frame and Close come from docked_panel_frame.rcss. + Text leaves are counter-scaled (base.rcss): widths inside them are times --root-scale. */ + +.frame-top { decorator: image(docked-bg-top-b); } + +#title { + position: absolute; + left: 35px; + top: 12px; + width: calc(120px * var(--root-scale)); + text-align: center; + color: #dcdcdc; + font-weight: bold; + font-size: 1em; + pointer-events: none; +} + +.party-empty-msg { + position: absolute; + left: 20px; + top: 50px; + width: calc(160px * var(--root-scale)); + color: #e6e6e6; + font-size: 1em; + text-align: left; +} +.party-empty-msg span { display: block; } +.party-empty-msg span.paragraph { margin-top: calc(5px * var(--root-scale)); } +.party-empty-msg { line-height: calc(15px * var(--root-scale)); } + +.party-list { position: absolute; left: 0; top: 50px; width: 190px; } +.party-row { position: relative; display: block; width: 190px; height: 35px; } + +.gbox-title-fill, .gbox-content-fill, .gbox-corner, .gbox-edge, .party-flag { display: none; } + +.party-name { + display: block; + position: absolute; + left: 20px; + top: 2px; + white-space: nowrap; + font-size: 1em; + color: rgb(210, 230, 255); + pointer-events: none; +} +.party-name.leader { color: #ffffff; background-color: #282896; } + +.party-map, .party-coord { + display: block; + position: absolute; + top: 10px; + white-space: nowrap; + font-size: 1em; + color: rgb(255, 230, 210); + pointer-events: none; +} +.party-map { left: 40px; } +.party-coord { left: 90px; } + +.party-hp-bar { + position: absolute; + left: 39px; + top: 19px; + width: 92px; + height: 5px; + background-color: rgb(51, 0, 0); + pointer-events: none; +} +.party-hp-fill { + position: absolute; + left: 1px; + top: 1px; + width: 0%; + max-width: 90px; + height: 3px; + background-color: rgb(225, 15, 0); + pointer-events: none; +} +.party-hp-text { + display: block; + position: absolute; + left: 65px; + top: 27px; + white-space: nowrap; + font-size: 1em; + color: #ffffff; + pointer-events: none; +} + +/* The leader's kick / a member's leave: the 0.97 Close plate (exit_01, 24x24) at x 140. */ +@spritesheet party-classic-kick-sheet { src: ../../../Classic/Exit_01.jpg; party-classic-kick: 0px 0px 24px 24px; } +@spritesheet party-classic-kick2-sheet { src: ../../../Classic/Exit_02.jpg; party-classic-kick-pressed: 0px 0px 24px 24px; } +.party-kick-btn { + position: absolute; + left: 140px; + top: 5px; + width: 24px; + height: 24px; + decorator: image(party-classic-kick); + cursor: pointer; + pointer-events: auto; +} +.party-kick-btn:active { decorator: image(party-classic-kick-pressed); } + +/* The native text size, counter-scaled out of the panel's scale. (Legacy's rule, which this copy + predated.) */ +#panel { font-size: calc(var(--text-px) / var(--root-scale)); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/party_list.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/party_list.rcss new file mode 100644 index 0000000000..066d8ea7c0 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/party_list.rcss @@ -0,0 +1,55 @@ +/* Classic (0.97) party list beside the right-hand windows, from the 0.97 client's 004ef160: one 50x19 box per member, no gap, + dark (0.1 grey at 70%), lighter under the mouse; the health bar 43x4 dark red with up to ten + red steps (here one bar, the steps' 40 units); the name in white; a member away in red, a + defence buff in blue. No card art, leader flag or leave button (0.97 leaves from the window). + #panel (77 wide) sits left of the docked windows, like 0.97's list, which followed the edge of + the area its open windows left free (004cb520: x 590, 400 or 210); the boxes keep to its right + edge, as 0.97 kept them 3 units left of the windows. Placed as legacy places it. */ + +#panel { + position: absolute; + transform-origin: left top; + width: 77px; + font-family: "token(font-body)"; + pointer-events: none; + left: calc(var(--world-right, 100%) - 79px * var(--dock-scale, 1)); + top: max(calc(var(--workspace-top, 0px) + 14px * var(--dock-scale, 1)), calc(var(--workspace-bottom, 100%) - 418px * var(--dock-scale, 1))); + transform: scale(var(--dock-scale, 1)); + --root-scale: var(--dock-scale, 1); +} +/* A box takes the pointer: its hover is the skill target, and a click on it never walks. */ +.card { pointer-events: auto; } + +.card { display: block; position: relative; width: 50px; height: 19px; margin-left: 24px; } + +.card-fill, .card-tint, .card-select { position: absolute; left: 0; top: 0; width: 50px; height: 19px; } +.card-fill { background-color: rgba(26, 26, 26, 179); } +.card-tint, .card-select { display: none; } +.card.selected .card-select { display: block; background-color: rgba(128, 128, 128, 204); } +.card.absent .card-tint { display: block; background-color: rgba(77, 0, 0, 128); } +.card.defense .card-tint { display: block; background-color: rgba(51, 51, 255, 51); } + +.card-flag, .card-leave { display: none; } + +.card-name { + display: block; + position: absolute; + left: 3px; + top: 1px; + white-space: nowrap; + color: #ffffff; +} +.card.absent .card-name { color: #808080; } + +/* The bar's back (.card-back, the S6 card art's element), then the fill: C++ sizes the fill for + the S6 69-unit bar, so it is scaled to 0.97's 40. */ +.card-back { position: absolute; left: 3px; top: 12px; width: 43px; height: 4px; background-color: rgb(50, 10, 0); } +.card-health { + position: absolute; + left: 4px; + top: 13px; + height: 2px; + background-color: rgb(250, 10, 0); + transform: scale(0.58, 1); + transform-origin: left top; +} diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/pet_info.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/pet_info.rcss new file mode 100644 index 0000000000..4d50174ea5 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/pet_info.rcss @@ -0,0 +1,347 @@ +/* Classic theme for CNewUIPetInfoWindow, the Dark Lord's pet window. 0.97 has no Dark Lord; this is + the Season 1 client's window (00421e40) over legacy's (whose comments explain the rest): on the + 0.97 frame, two win_button tabs 49 wide every 45 from x 15, the selected one at y 63 (49x20), + the other at y 67 (49x16) darkened to 0.6; Trading_line (190x10) at y 80 and 380; a frame of + lines (0.9, 0.9, 0.6) from (12, 90) to (178, 380); no S6 group boxes. The window's otherwise + hidden frame pieces carry the lines. Without a pet, the red message in the middle of the frame. */ + +/* Legacy theme for CPetInfoWindow -- #panel/frame sprites/exit button/group-box + corner-and-fill shape are shared with character_info/my_quest_info/party_info via + docked_panel_frame.rcss (linked in pet_info.rml before this file) -- only window-specific content + lives here now. Coordinates below are plain reference px, matching that shared convention. */ +.frame-top { decorator: image(docked-bg-top-a); } + +/* CRadioGroupButton's own tab sprite -- 2 stacked 56x22 frames (idle then selected); verify frame + order live, swap the y-offsets below if it renders backwards. */ +@spritesheet petinfo-tab-idle-sheet { src: "../../../newui_guild_tab04.tga"; petinfo-tab-idle: 0px 0px 56px 22px; } +@spritesheet petinfo-tab-active-sheet { src: "../../../newui_guild_tab04.tga"; petinfo-tab-active: 0px 22px 56px 22px; } + +@spritesheet petinfo-lifebar-back-sheet { src: "../../../newui_pet_lifebar01.jpg"; petinfo-lifebar-back: 0px 0px 151px 12px; } +@spritesheet petinfo-lifebar-fill-sheet { src: "../../../newui_pet_lifebar02.jpg"; petinfo-lifebar-fill: 0px 0px 1px 8px; } + +@spritesheet petinfo-skillbox-sheet { src: "../../../newui_skillbox.jpg"; petinfo-skillbox: 0px 0px 32px 38px; } +/* newui_command.jpg command-icon sheet (CSkillList::IMAGE_COMMAND) -- 4 fixed 19x27 icons at the + same u-offsets RenderDarkSpiritInfo() used (1/21/41/61), y=0. */ +@spritesheet petinfo-skillicon-0-sheet { src: "../../../newui_command.jpg"; petinfo-skillicon-0: 1px 0px 19px 27px; } +@spritesheet petinfo-skillicon-1-sheet { src: "../../../newui_command.jpg"; petinfo-skillicon-1: 21px 0px 19px 27px; } +@spritesheet petinfo-skillicon-2-sheet { src: "../../../newui_command.jpg"; petinfo-skillicon-2: 41px 0px 19px 27px; } +@spritesheet petinfo-skillicon-3-sheet { src: "../../../newui_command.jpg"; petinfo-skillicon-3: 61px 0px 19px 27px; } + +#title { + position: absolute; + left: 0; + top: 13px; + width: calc(100% * var(--root-scale)); + text-align: center; + color: token(text-primary); + font-weight: bold; + font-size: 1em; + pointer-events: none; +} + +.tab-row { position: absolute; left: 12px; top: 48px; width: 112px; height: 22px; } +.tab-btn { + position: absolute; + top: 0; + width: 56px; + height: 22px; + text-align: center; + line-height: 22px; + font-size: 1em; + color: token(text-muted); + cursor: pointer; + pointer-events: auto; + white-space: nowrap; + overflow: hidden; + decorator: image(petinfo-tab-idle); +} +.tab-btn.active { color: token(text-primary); decorator: image(petinfo-tab-active); } +.tab-btn-darkhorse { left: 0; } +.tab-btn-darkspirit { left: 56px; } + +.pet-tab { position: absolute; left: 0; top: 0; right: 0; bottom: 0; } + +/* Native draws it bold in 0xFF0000FF -- an ABGR DWORD, i.e. red -- into a 160x30 text box at + (15,100) whose background shows as a dark translucent band (the renderer's background colour is + still set when it draws). */ +.pet-no-pet-msg { + display: block; + position: absolute; + left: 15px; + top: 96px; + width: calc((100% - 30px) * var(--root-scale)); + height: calc(27px * var(--root-scale)); + padding-top: calc(3px * var(--root-scale)); + color: #ff0000; + background-color: rgba(0, 28, 48, 150); + font-weight: bold; + font-size: 1em; + text-align: center; +} +/* display: block above would otherwise outrank base.rcss's .hidden (equal specificity, later + rule) and keep the message up while a pet is equipped. */ +.pet-no-pet-msg.hidden { display: none; } + +.pet-subtitle { + display: block; + position: absolute; + left: 0; + top: 25px; + width: calc(100% * var(--root-scale)); + text-align: center; + font-size: 1em; + color: token(text-primary); + pointer-events: none; +} + +/* Group-box shape (.gbox-corner/.gbox-title-fill/.gbox-content-fill/.gbox-title-text) comes from + docked_panel_frame.rcss -- only per-instance position + which corner sprite stays here. */ +.gbox-dh-corner-tl { left: 12px; top: 75px; decorator: image(docked-corner-tl); } +.gbox-dh-corner-tr { right: 10px; top: 75px; decorator: image(docked-corner-tr); } +.gbox-dh-corner-bl { left: 12px; top: 166px; decorator: image(docked-corner-bl); } +.gbox-dh-corner-br { right: 10px; top: 166px; decorator: image(docked-corner-br); } +.gbox-dh-title-fill { left: 15px; top: 77px; width: 52px; height: 20px; } +.gbox-dh-content-fill { left: 15px; top: 97px; right: 14px; height: 78px; } +.gbox-dh-title-text { left: 14px; top: 83px; width: 56px; } + +.gbox-ds1-corner-tl { left: 12px; top: 75px; decorator: image(docked-corner-tl); } +.gbox-ds1-corner-tr { right: 10px; top: 75px; decorator: image(docked-corner-tr); } +.gbox-ds1-corner-bl { left: 12px; top: 182px; decorator: image(docked-corner-bl); } +.gbox-ds1-corner-br { right: 10px; top: 182px; decorator: image(docked-corner-br); } +.gbox-ds1-title-fill { left: 15px; top: 77px; width: 52px; height: 20px; } +.gbox-ds1-content-fill { left: 15px; top: 97px; right: 14px; height: 94px; } +.gbox-ds1-title-text { left: 14px; top: 83px; width: 56px; } + +.gbox-ds2-corner-tl { left: 12px; top: 196px; decorator: image(docked-corner-tl); } +.gbox-ds2-corner-tr { right: 10px; top: 196px; decorator: image(docked-corner-tr); } +.gbox-ds2-corner-bl { left: 12px; top: 377px; decorator: image(docked-corner-bl); } +.gbox-ds2-corner-br { right: 10px; top: 377px; decorator: image(docked-corner-br); } +.gbox-ds2-title-fill { left: 15px; top: 198px; width: 52px; height: 20px; } +.gbox-ds2-content-fill { left: 15px; top: 218px; right: 14px; height: 168px; } +.gbox-ds2-title-text { left: 14px; top: 204px; width: 56px; } + +.pet-stat-text { + display: block; + position: absolute; + left: 22px; + font-size: 1em; + color: token(text-primary); + white-space: nowrap; + pointer-events: none; +} +.pet-dh-life-text { top: 103px; } +.pet-dh-exp-text { top: 134px; } +.pet-dh-dmg-text { top: 147px; } +.pet-dh-atkspeed-text { top: 160px; } +.pet-ds-life-text { top: 103px; } +.pet-ds-exp-text { top: 134px; } +.pet-ds-dmg-text { top: 147px; } +.pet-ds-atkspeed-text { top: 160px; } +.pet-ds-charisma-text { top: 173px; } + +/* HP bar: background sprite + a fill whose width is bound as a percentage of its own 147px max + (matches RenderDarkHorseInfo/RenderDarkSpiritInfo's own `iHP = min(life,255)*147/255`). */ +.hp-bar { + position: absolute; + left: 19px; + width: 151px; + height: 12px; + decorator: image(petinfo-lifebar-back); + pointer-events: none; +} +.hp-bar-dh { top: 115px; } +.hp-bar-ds { top: 115px; } +.hp-bar-fill { + position: absolute; + left: 2px; + top: 2px; + width: 0%; + max-width: 147px; + height: 8px; + decorator: image(petinfo-lifebar-fill); + pointer-events: none; +} + +.skill-slot { + position: absolute; + left: 22px; + width: 32px; + height: 38px; + decorator: image(petinfo-skillbox); + pointer-events: none; +} +.skill-slot-0 { top: 224px; } +.skill-slot-1 { top: 264px; } +.skill-slot-2 { top: 304px; } +.skill-slot-3 { top: 344px; } + +.skill-icon { + position: absolute; + left: 29px; + width: 19px; + height: 27px; + pointer-events: none; +} +.skill-icon-0 { top: 230px; decorator: image(petinfo-skillicon-0); } +.skill-icon-1 { top: 270px; decorator: image(petinfo-skillicon-1); } +.skill-icon-2 { top: 310px; decorator: image(petinfo-skillicon-2); } +.skill-icon-3 { top: 350px; decorator: image(petinfo-skillicon-3); } + +.skill-label { + display: block; + position: absolute; + left: 14px; + width: 100px; + text-align: center; + font-size: 1em; + color: token(text-primary); + pointer-events: none; +} +.skill-label-0 { top: 241px; } +.skill-label-1 { top: 281px; } +.skill-label-2 { top: 321px; } +.skill-label-3 { top: 361px; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +.tab-btn.tab-btn-darkhorse { width: calc(56px * var(--root-scale)); height: calc(22px * var(--root-scale)); line-height: calc(22px * var(--root-scale)); } +.tab-btn.tab-btn-darkspirit { width: calc(56px * var(--root-scale)); height: calc(22px * var(--root-scale)); line-height: calc(22px * var(--root-scale)); } +.gbox-title-text.gbox-dh-title-text { width: calc(56px * var(--root-scale)); } +.pet-stat-text.pet-dh-life-text { width: calc(150px * var(--root-scale)); } +.pet-stat-text.pet-dh-exp-text { width: calc(150px * var(--root-scale)); } +.pet-stat-text.pet-dh-dmg-text { width: calc(150px * var(--root-scale)); } +.pet-stat-text.pet-dh-atkspeed-text { width: calc(150px * var(--root-scale)); } +.gbox-title-text.gbox-ds1-title-text { width: calc(56px * var(--root-scale)); } +.pet-stat-text.pet-ds-life-text { width: calc(150px * var(--root-scale)); } +.pet-stat-text.pet-ds-exp-text { width: calc(150px * var(--root-scale)); } +.pet-stat-text.pet-ds-dmg-text { width: calc(150px * var(--root-scale)); } +.pet-stat-text.pet-ds-atkspeed-text { width: calc(150px * var(--root-scale)); } +.pet-stat-text.pet-ds-charisma-text { width: calc(150px * var(--root-scale)); } +.gbox-title-text.gbox-ds2-title-text { width: calc(56px * var(--root-scale)); } +.skill-label.skill-label-0 { width: calc(100px * var(--root-scale)); } +.skill-label.skill-label-1 { width: calc(100px * var(--root-scale)); } +.skill-label.skill-label-2 { width: calc(100px * var(--root-scale)); } +.skill-label.skill-label-3 { width: calc(100px * var(--root-scale)); } + +/* The native text size, counter-scaled out of the panel's scale. */ +#panel { font-size: calc(var(--text-px) / var(--root-scale)); } + +@spritesheet petinfo-classic-tab-sheet { src: "../../../win_button.tga"; petinfo-classic-tab: 0px 0px 49px 16px; } +@spritesheet petinfo-classic-line-sheet { src: ../../../Classic/Trading_line.jpg; petinfo-classic-line: 0px 0px 190px 10px; } + +/* The tabs are sharp text (counter-scaled), so their own sizes are reference px times the panel's + --root-scale, and they take the two-class selectors of legacy's sizes above, which would + otherwise win over a plain .tab-btn rule. Their places (left, top) stay in the panel's px. + Season 1's tabs are 49 wide every 45, for its short labels; here they are 78 wide side by side + across the frame, so "Dark Horse" and "Dark Raven" fit. */ +.tab-row { left: 15px; top: 63px; width: 159px; height: 20px; } +.tab-btn { + top: 4px; + color: rgb(230, 220, 200); + image-color: rgb(153, 153, 153); + decorator: image(petinfo-classic-tab fill); +} +.tab-btn.tab-btn-darkhorse, +.tab-btn.tab-btn-darkspirit { width: calc(78px * var(--root-scale)); height: calc(16px * var(--root-scale)); line-height: calc(16px * var(--root-scale)); } +.tab-btn.active { top: 0; z-index: 1; color: #ffffff; image-color: #ffffff; decorator: image(petinfo-classic-tab fill); } +.tab-btn.active.tab-btn-darkhorse, +.tab-btn.active.tab-btn-darkspirit { height: calc(20px * var(--root-scale)); line-height: calc(20px * var(--root-scale)); } +.tab-btn-darkhorse { left: 0; } +.tab-btn-darkspirit { left: 81px; } + +/* No pet: Season 1 writes the message in red (220, 60, 60) over a black copy one pixel down and + right, centred in the frame at y 220, with no band behind it. */ +.pet-no-pet-msg { + top: 213px; + height: auto; + padding-top: 0; + color: rgb(220, 60, 60); + background-color: transparent; + font-effect: shadow(1px 1px black); +} + +/* Season 1 has one title; the tab already names the pet, so legacy's subtitle under it goes. */ +.pet-subtitle { display: none; } + +/* The two Trading_lines (80 and 380) on one piece, the frame of lines on the other. */ +.frame-right { + display: block; + left: 0; + top: 80px; + width: 190px; + height: 310px; + decorator: image(petinfo-classic-line contain left top), image(petinfo-classic-line contain left bottom); +} +.frame-bottom { + display: block; + left: 12px; + top: 90px; + width: 167px; + height: 291px; + box-sizing: border-box; + border-width: 1px; + border-color: rgb(230, 230, 153); +} + +/* No S6 group boxes. */ +.gbox-corner, .gbox-title-fill, .gbox-content-fill { display: none; } + +/* The pet's level and stats as Season 1 draws them (00412bb0, called from 004222d0 with the window's + left edge), in the window's units: + - the level in a Level_box (75x21) at (13, 96), gold (223, 191, 103), centred in the 70 from 14, + its text top at 100; + - the life line at (24, 120), then the bar at (24, 135): a 145x8 back in (0.2, 0, 0) and the + life, life * 143 / 255 wide and 6 high, in (0.882, 0.059, 0) one in from its top-left -- no + texture; + - the other lines 15 apart from 150 at x 24, all (230, 230, 230) over a band of black at 50%, + 145 wide. */ +@spritesheet petinfo-classic-level-sheet { src: ../../../Classic/Level_box.jpg; petinfo-classic-level: 0px 0px 75px 21px; } + +.gbox-title-fill.gbox-dh-title-fill, +.gbox-title-fill.gbox-ds1-title-fill { + display: block; + left: 13px; + top: 96px; + width: 75px; + height: 21px; + background-color: transparent; + decorator: image(petinfo-classic-level); +} +.gbox-title-text.gbox-dh-title-text, +.gbox-title-text.gbox-ds1-title-text { + left: 14px; + top: 99px; + width: calc(70px * var(--root-scale)); + color: rgb(223, 191, 103); +} + +.pet-stat-text.pet-dh-life-text, .pet-stat-text.pet-dh-exp-text, .pet-stat-text.pet-dh-dmg-text, +.pet-stat-text.pet-dh-atkspeed-text, +.pet-stat-text.pet-ds-life-text, .pet-stat-text.pet-ds-exp-text, .pet-stat-text.pet-ds-dmg-text, +.pet-stat-text.pet-ds-atkspeed-text, .pet-stat-text.pet-ds-charisma-text { + left: 24px; + width: calc(145px * var(--root-scale)); + color: rgb(230, 230, 230); + background-color: rgba(0, 0, 0, 128); +} +.pet-dh-life-text, .pet-ds-life-text { top: 119px; } +.pet-dh-exp-text, .pet-ds-exp-text { top: 149px; } +.pet-dh-dmg-text, .pet-ds-dmg-text { top: 164px; } +.pet-dh-atkspeed-text, .pet-ds-atkspeed-text { top: 179px; } +.pet-ds-charisma-text { top: 194px; } + +.hp-bar { + left: 24px; + width: 145px; + height: 8px; + background-color: rgb(51, 0, 0); + decorator: none; +} +.hp-bar-dh, .hp-bar-ds { top: 135px; } +.hp-bar-fill { + left: 1px; + top: 1px; + max-width: 143px; + height: 6px; + background-color: rgb(225, 15, 0); + decorator: none; +} diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/purchase_shop.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/purchase_shop.rcss new file mode 100644 index 0000000000..cce61ca5ca --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/purchase_shop.rcss @@ -0,0 +1,116 @@ +/* Classic theme for CPurchaseShopInventory, another player's personal shop. 0.97 has none; it + takes the classic personal shop's parts: the 0.97 inventory frame (Item_Back01 over Item_Back02), + the owner's name on Item_Money, 0.97's Close at (20, 395). Legacy's layout and comments below. */ + +/* Legacy theme for CPurchaseShopInventory's chrome (frame/title/subtitle-strip/warning-text/exit + button). #panel's left/top/scale come live from C++ (SyncRmlModel()), so coordinates below are + plain reference px, not dp. */ + +#panel { + position: absolute; + transform-origin: left top; + width: 190px; + height: 429px; + font-family: "token(font-body)"; +} + +/* Between the frame's top corners, clear of the close button; a longer title ends in ".." and + scrolls on hover (base.rcss .marquee). */ +#title { + position: absolute; + left: 28px; + top: 15px; + width: calc(134px * var(--root-scale)); + text-align: center; + /* Native draws it in the normal font, 0xFF49B0FF -- an ABGR DWORD, i.e. (255,176,73). */ + color: #ffb049; + font-size: 1em; +} + +/* Same sprite as CMyShopInventory's own subject-box background (newui_Box_openTitle.tga) -- + purely decorative here, behind a read-only shop-owner name instead of a live text field. */ +@spritesheet pshop-title-strip-sheet { src: "../../../newui_Box_openTitle.tga"; pshop-title-strip: 0px 0px 169px 26px; } +.shop-title-strip { + position: absolute; + left: 12px; + top: 49px; + width: 169px; + height: 26px; + pointer-events: none; + decorator: image(pshop-title-strip); +} +#shop_owner_text { + position: absolute; + left: 0; + top: 58px; + width: calc(100% * var(--root-scale)); + text-align: center; + color: #00ff00; + font-weight: bold; + font-size: 1em; + pointer-events: none; +} + +/* The old RenderTextInfo()'s colours; shop_notice.rcss lays the notice out. */ +.warning-label { color: #ff2d2f; } +.warning-line { color: token(text-notice); } + +@spritesheet pshop-btn-exit-sheet { src: "../../../newui_exit_00.tga"; pshop-btn-exit: 0px 0px 36px 29px; } +.shop-btn-exit { + position: absolute; + left: 13px; + top: 391px; + width: 36px; + height: 29px; + cursor: pointer; + pointer-events: auto; + decorator: image(pshop-btn-exit); +} +.shop-btn-exit:hover { filter: brightness(1.25); } + +/* Native item grid: the first cell's top-left, in #panel's units. */ +.native-anchor { position: absolute; pointer-events: none; } +#item_grid, #item_grid_counts { left: 16px; top: 90px; width: calc(8 * var(--item-cell)); height: calc(4 * var(--item-cell)); } + +/* The frame. */ +@spritesheet pshop-bg-fill-sheet { src: "../../../newui_msgbox_back.jpg"; pshop-bg-fill: 0px 0px 190px 429px; } +@spritesheet pshop-bg-top-sheet { src: "../../../newui_item_back01.tga"; pshop-bg-top: 0px 0px 190px 64px; } +@spritesheet pshop-bg-left-sheet { src: "../../../newui_item_back02-L.tga"; pshop-bg-left: 0px 0px 21px 320px; } +@spritesheet pshop-bg-right-sheet { src: "../../../newui_item_back02-R.tga"; pshop-bg-right: 0px 0px 21px 320px; } +@spritesheet pshop-bg-bottom-sheet { src: "../../../newui_item_back03.tga"; pshop-bg-bottom: 0px 0px 190px 45px; } + +.bg-fill, .bg-top, .bg-left, .bg-right, .bg-bottom { + position: absolute; + pointer-events: none; +} + +.bg-fill { left: 0; top: 0; width: 190px; height: 429px; decorator: image(pshop-bg-fill); } +.bg-top { left: 0; top: 0; width: 190px; height: 64px; decorator: image(pshop-bg-top); } +.bg-left { left: 0; top: 64px; width: 21px; height: 320px; decorator: image(pshop-bg-left); } +.bg-right { left: 169px; top: 64px; width: 21px; height: 320px; decorator: image(pshop-bg-right); } +.bg-bottom { left: 0; top: 384px; width: 190px; height: 45px; decorator: image(pshop-bg-bottom); } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ + +/* The grid's clicks are native (CInventoryCtrl), so the placed panel takes no pointer events; its + controls take their own. */ +#panel.slot-placed { pointer-events: none; } +#panel { font-size: calc(var(--text-px, 12px) / var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet classic-pshop-back1-sheet { src: ../../../Classic/Item_back01.jpg; classic-pshop-back1: 0px 0px 190px 256px; } +@spritesheet classic-pshop-back2-sheet { src: ../../../Classic/Item_Back02.jpg; classic-pshop-back2: 0px 0px 190px 177px; } +@spritesheet classic-pshop-exit-sheet { src: ../../../Classic/Exit_01.jpg; classic-pshop-exit: 0px 0px 24px 24px; } +@spritesheet classic-pshop-exit2-sheet { src: ../../../Classic/Exit_02.jpg; classic-pshop-exit-pressed: 0px 0px 24px 24px; } +#panel { height: 433px; } +.bg-fill { top: 256px; height: 177px; decorator: image(classic-pshop-back2); } +.bg-top { height: 256px; decorator: image(classic-pshop-back1); } +.bg-left, .bg-right, .bg-bottom { display: none; } +#frame_corner_close { display: none; } +.shop-btn-exit { left: 20px; top: 395px; width: 24px; height: 24px; decorator: image(classic-pshop-exit); } +.shop-btn-exit:hover { filter: none; } +.shop-btn-exit:active { decorator: image(classic-pshop-exit-pressed); } +@spritesheet classic-pshop-money-sheet { src: ../../../Classic/Item_money.jpg; classic-pshop-money: 0px 0px 113px 18px; } +#title { left: 0; top: 12px; width: calc(190px * var(--root-scale)); color: #dcdcdc; font-weight: bold; } +.shop-title-strip { left: 20px; top: 50px; width: 150px; height: 24px; decorator: image(classic-pshop-money fill); } +#shop_owner_text { top: 56px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/quest_progress.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/quest_progress.rcss new file mode 100644 index 0000000000..ff8bb8946e --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/quest_progress.rcss @@ -0,0 +1,227 @@ +/* Classic theme for the quest progress windows (CQuestProgress, CQuestProgressByEtc). 0.97 has no + such window; it keeps legacy's look on the classic docked frame, whose header (Item_Back01's dark + band, y 5-30) is shorter than legacy's: the title and the quest's subject close up inside it. + Legacy's layout and comments below. */ + +/* Legacy theme for CQuestProgress/CQuestProgressByEtc -- shared by both windows' own documents + (quest_progress.rml/quest_progress_etc.rml, see either file's header comment for why two .rml + files link one .rcss). #panel/frame sprites/exit button come from + docked_panel_frame.rcss (linked before this file), same family as character_info/my_quest_info/ + pet_info/party_info. Coordinates below are plain reference px, not dp. + + `#panel.qp-etc` overrides mark the handful of values that genuinely differ between the two + windows (confirmed by reading both native classes in full): CQuestProgressByEtc's NPC-line/ + button top offsets sit 3-7px higher, and its answers list starts right where CQuestProgress's own + player-name/player-words preamble would otherwise occupy, since that preamble doesn't exist in + quest_progress_etc.rml at all. Everything else here is byte-identical between the two windows. */ +.frame-top { decorator: image(docked-bg-top-a); } + +@spritesheet qp-btn-l-sheet { src: "../../../Quest_bt_L.tga"; qp-btn-l: 0px 0px 17px 18px; } +@spritesheet qp-btn-r-sheet { src: "../../../Quest_bt_R.tga"; qp-btn-r: 0px 0px 17px 18px; } +@spritesheet qp-btn-complete-sheet { + src: "../../../newui_btn_empty.tga"; + qp-btn-complete-idle: 0px 0px 108px 29px; + qp-btn-complete-hover: 0px 29px 108px 29px; +} + +#title { + position: absolute; + left: 0; + top: 12px; + width: calc(190px * var(--root-scale)); + text-align: center; + color: token(text-title); + font-weight: bold; + font-size: 1em; +} + +.qp-subject { + display: block; + position: absolute; + left: 0; + top: 27px; + width: calc(190px * var(--root-scale)); + text-align: center; + color: token(accent-teal); + font-weight: bold; /* native g_hFontBold, like the title, NPC and player names */ + font-size: 1em; +} + +.qp-npc-name { + display: block; + position: absolute; + left: 13px; + top: 51px; + color: #ffff0a; + font-weight: bold; + font-size: 1em; +} + +.qp-npc-lines { + position: absolute; + left: 13px; + top: 66px; + width: calc(164px * var(--root-scale)); +} +#panel.qp-etc .qp-npc-lines { top: 59px; } +.qp-line { + display: block; + color: token(text-narrative); + font-size: 1em; + white-space: nowrap; +} + +/* Native 188x21 sprite at fixed size -- its own element rather than a stretched decorator, same + reasoning my_quest_info.rcss's own .quest-divider comment gives. */ +@spritesheet qp-line-sheet { src: "../../../newui_myquest_Line.tga"; qp-line-img: 0px 0px 188px 21px; } +.qp-divider { + position: absolute; + left: 1px; + top: 181px; + width: 188px; + height: 21px; + decorator: image(qp-line-img); +} + +.qp-btn-l, .qp-btn-r { + position: absolute; + top: 168px; + width: 17px; + height: 18px; + cursor: pointer; + pointer-events: auto; +} +#panel.qp-etc .qp-btn-l, #panel.qp-etc .qp-btn-r { top: 165px; } +.qp-btn-l { left: 131px; decorator: image(qp-btn-l); } +.qp-btn-r { left: 153px; decorator: image(qp-btn-r); } +.qp-btn-l:hover, .qp-btn-r:hover { filter: brightness(1.25); } +/* Native CNewUIQuestProgress(ByEtc)::Render() skips a locked pager button entirely, so a page + arrow only shows while there is another page that way. */ +.qp-btn-l.locked, .qp-btn-r.locked { display: none; } + +/* Player-name label -- CQuestProgress's own document only (quest_progress_etc.rml has no such + element at all). Shown for active_view 0 and 1, hidden only in reward view (2). + No explicit display here -- base.rcss's .hidden{display:none} (toggled by this element's own + data-class-hidden="active_view == 2") must win the cascade uncontested, same convention every + data-class-hidden target in my_quest_info.rcss already follows (an explicit display:block here, + linked after base.rcss, would otherwise always beat it regardless of active_view). */ +.qp-player-name { + position: absolute; + left: 13px; + top: 207px; + color: #ffb90a; + font-weight: bold; + font-size: 1em; +} + +.qp-answers { + position: absolute; + left: 13px; + top: 222px; + width: calc(164px * var(--root-scale)); +} +#panel.qp-etc .qp-answers { top: 207px; } +.qp-player-words { + display: block; + color: token(text-narrative); + font-size: 1em; + /* margin-bottom 15px, bound (the .qp-answers text layer is in physical px) */ +} +.qp-answer-row { + display: block; + color: token(text-narrative); + font-size: 1em; + cursor: pointer; + pointer-events: auto; +} +.qp-answer-row:hover { background-color: token(surface-hover); } + +.qp-reward { + position: absolute; + left: 0; + top: 0; + width: 190px; + height: 429px; +} +.qp-reward-list { + position: absolute; + left: 9px; + top: 205px; + width: calc(174px * var(--root-scale)); + height: calc(150px * var(--root-scale)); + overflow: auto hidden; +} + +/* #reward_popup_anchor (quest_progress.rml/quest_progress_etc.rml) marks where + QuestProgress.cpp/QuestProgressByEtc.cpp's still-native reward-item info-tooltip popup anchors -- + same left/top the popup's old hardcoded m_Pos+95,+360 offset resolved to (.qp-reward itself has + zero left/top, so this is panel-relative). */ +.qp-popup-anchor { + position: absolute; + width: 0; + height: 0; + pointer-events: none; +} +#reward_popup_anchor { left: 95px; top: 360px; } +.qp-reward-row { + display: block; + width: 100%; + text-align: center; /* padding 1px 4px, bound (text layer) */ + font-size: 1em; + color: token(text-primary); +} +.qp-reward-row.row-heading { font-weight: bold; } +/* A clickable row keeps its colour on hover, as the original list box does. */ +.qp-reward-row.clickable { cursor: pointer; pointer-events: auto; } + +.qp-btn-complete { + position: absolute; + left: 41px; + top: 362px; + width: 108px; + height: 29px; + text-align: center; + vertical-align: middle; + line-height: 29px; + color: token(text-narrative); + font-size: 1em; + cursor: pointer; + pointer-events: auto; + decorator: image(qp-btn-complete-idle); +} +.qp-btn-complete:hover { decorator: image(qp-btn-complete-hover); } +.qp-btn-complete.disabled { + color: token(text-inactive); + pointer-events: none; + cursor: default; + filter: brightness(0.6); +} + +/* Exit is a common close button -- legacy's sprite already has its own "X" baked in, so the shared + label span is redundant (same convention my_quest_info.rcss's own .btn-exit-label uses). */ +.btn-exit-label { display: none; } + +/* Requirement/reward rows by kind (UI::Quests::RewardModel::RowStyle; the RML toggles + .row-). The original client's colors. */ +.qp-reward-row.row-heading { color: #b3e64d; } +.qp-reward-row.row-requirement { color: #dfbf67; } +.qp-reward-row.row-requirement-unmet { color: #ff1e1e; } +.qp-reward-row.row-reward { color: #dfbf67; } +.qp-reward-row.row-random-reward { color: #6767df; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +.qp-npc-name { width: calc(164px * var(--root-scale)); } +.qp-npc-lines { line-height: calc(15px * var(--root-scale)); } +.qp-player-name { width: calc(164px * var(--root-scale)); } +.qp-answers { line-height: calc(15px * var(--root-scale)); } +.qp-player-words { margin-bottom: calc(15px * var(--root-scale)); } +.qp-reward-row { padding: calc(1px * var(--root-scale)) calc(4px * var(--root-scale)); } +#btn_complete { width: calc(108px * var(--root-scale)); height: calc(29px * var(--root-scale)); line-height: calc(29px * var(--root-scale)); } + +/* The native text size, counter-scaled out of the panel's scale. */ +#panel { font-size: calc(var(--text-px) / var(--root-scale)); } + +/* The title and the subject in the classic header's dark band, where legacy's subject line (y 27) + fell on the band's ornament. */ +#title { top: 8px; } +.qp-subject { top: 19px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/quick_command.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/quick_command.rcss new file mode 100644 index 0000000000..da5fcbc0cc --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/quick_command.rcss @@ -0,0 +1,69 @@ +/* Classic (0.97) theme for CQuickCommandWindow, the menu opened on a player. 0.97 has none (its + player commands are chat commands), so this is legacy's menu in 0.97's parts, as the classic + command window (D) is: the box 0.97 drew its hints and item boxes in (black at 0.8 inside a + 1-unit black frame, 004c2420), the player's name in bold green, and each action on a 0.97 text + plate (Message_box, 213x64, squashed to the row) lit warm under the mouse as 0.97 lit its plates. + The S6 frame pieces, lines and arrows are not drawn. Reference px relative to the menu's + top-left (#panel is placed at the UI scale). */ + +@spritesheet classic-qcmd-plate-sheet { src: ../../../Classic/Message_box.jpg; classic-qcmd-plate: 0px 0px 213px 64px; } + +#panel { + position: absolute; + transform-origin: left top; + width: 112px; + height: 140px; + font-family: "token(font-body)"; +} + +#back { + position: absolute; + left: 0; + top: 0; + width: 112px; + height: 140px; + box-sizing: border-box; + border-width: 1px; + border-color: #000000; + background-color: rgba(0, 0, 0, 204); +} +#frame_up, .frame-middle, #frame_down, .line, .arrow { display: none; } + +/* The name centred near the top: bold, (0, 255, 0), as legacy's. */ +#name { + display: block; + position: absolute; + left: 0; + top: 14px; + text-align: center; + white-space: nowrap; + color: #00ff00; + font-weight: bold; +} + +/* The rows from y 42, a plate 96x17 every 19, the label centred on it; white, yellow under the + mouse as legacy's. */ +#rows { position: absolute; left: 0; top: 42px; width: 112px; } +.quick-row { + display: block; + position: relative; + width: 96px; + height: 17px; + margin: 0 0 2px 8px; + decorator: image(classic-qcmd-plate fill); +} +.quick-row:hover { image-color: #ffe3c6; filter: brightness(1.7); } +.quick-label { + display: block; + position: absolute; + left: 0; + top: 1px; + text-align: center; + white-space: nowrap; + color: #ffffff; +} +.quick-row:hover .quick-label { color: #ffff00; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#name { width: calc(112px * var(--root-scale)); } +.quick-label { width: calc(96px * var(--root-scale)); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/reconnect_dialog.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/reconnect_dialog.rcss new file mode 100644 index 0000000000..03453ba85c --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/reconnect_dialog.rcss @@ -0,0 +1,76 @@ +/* Classic theme for the reconnect dialog (a MuMain feature: no original). It takes the 0.97 box and + the progress bar of the Season 1 client's message box (00625a20): a 0.97 box 213 x 130 + (Message_box1 stones between Message_box2 edges) under the dim, the three lines (230, 220, 200) + centred at y 14 / 32 / 50, Progress_back (150 x 12) at (31, 70) with the fill over the same + rectangle (the two textures are drawn to overlay; its additive draw carried by the derived + Progress_add), and 0.97's Cancel (70 x 21, Cancel2 under the mouse) at (71, 99). The stones + are two elements stretched to the box (this document is in px under the C++ scale, where a + repeated sprite takes a larger natural size and cuts the box's right border). Legacy's rules first, then the classic ones. */ + +/* Legacy theme for the reconnect dialog, reproducing UI::Reconnect's native drawing: a black dim + over the whole screen (its alpha bound), then a 230 x 122 message-box panel -- newui_msgbox_back + (222 x 112 from y 2), newui_msgbox_top (67), one newui_msgbox_middle strip stretched to 5, + newui_msgbox_bottom (50) --, the newui_Bar_switch01 gauge (160 x 18 at 35, 66) with its + newui_Bar_switch02 fill (inset 5, up to 150 x 8), the newui_button_cancel button (54 x 30 at + 88, 86; its hover row 30 below) and the lines in (230, 220, 200). Above every other document, + the tooltip included: the original drew it after the whole frame. Reference px inside #panel. */ + +@spritesheet rc-back-sheet { src: "../../../newui_msgbox_back.jpg"; rc-back: 0px 0px 222px 242px; } +@spritesheet rc-top-sheet { src: "../../../newui_msgbox_top.tga"; rc-top: 0px 0px 230px 67px; } +@spritesheet rc-middle-sheet { src: "../../../newui_msgbox_middle.tga"; rc-middle: 0px 0px 230px 15px; } +@spritesheet rc-bottom-sheet { src: "../../../newui_msgbox_bottom.tga"; rc-bottom: 0px 0px 230px 50px; } +@spritesheet rc-progress-back-sheet { src: "../../../newui_Bar_switch01.jpg"; rc-progress-back: 0px 0px 160px 18px; } +@spritesheet rc-progress-bar-sheet { src: "../../../newui_Bar_switch02.jpg"; rc-progress-bar: 0px 0px 150px 8px; } +@spritesheet rc-cancel-sheet +{ + src: "../../../newui_button_cancel.tga"; + rc-cancel: 0px 0px 54px 30px; + rc-cancel-over: 0px 30px 54px 30px; +} + +body { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; font-family: "token(font-body)"; } +#dim { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: #000000; pointer-events: none; } +#panel { position: absolute; transform-origin: left top; width: 230px; height: 122px; pointer-events: none; } +#back { position: absolute; left: 0; top: 2px; width: 222px; height: 112px; decorator: image(rc-back); } +#box_top { position: absolute; left: 0; top: 0; width: 230px; height: 67px; decorator: image(rc-top); } +#box_middle { position: absolute; left: 0; top: 67px; width: 230px; height: 5px; decorator: image(rc-middle); } +#box_bottom { position: absolute; left: 0; top: 72px; width: 230px; height: 50px; decorator: image(rc-bottom); } +#progress_back { position: absolute; left: 35px; top: 66px; width: 160px; height: 18px; decorator: image(rc-progress-back); } +#progress_bar { position: absolute; left: 40px; top: 71px; height: 8px; decorator: image(rc-progress-bar); } +#cancel { position: absolute; left: 88px; top: 86px; width: 54px; height: 30px; decorator: image(rc-cancel); pointer-events: auto; } +#cancel:hover { decorator: image(rc-cancel-over); } + +.sharp-text { display: block; position: absolute; white-space: nowrap; pointer-events: none; } +.line { color: rgb(230, 220, 200); } + +/* The status lines' own rows (PANEL_Y + 12 / 30 / 48) and the panel-wide centring box. */ +.line { left: 0; text-align: center; } +#rc_title { top: 12px; font-weight: bold; } +#rc_step { top: 30px; } +#rc_countdown { top: 48px; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#rc_title { width: calc(230px * var(--root-scale)); } +#rc_step { width: calc(230px * var(--root-scale)); } +#rc_countdown { width: calc(230px * var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet rc-classic-stone-sheet { src: ../../../Classic/Message_box1.jpg; rc-classic-stone: 0px 0px 213px 40px; } +@spritesheet rc-classic-edge-sheet { src: ../../../Classic/Message_box2.jpg; rc-classic-edge: 0px 0px 213px 5px; } +@spritesheet rc-classic-pback-sheet { src: ../../../Classic/Progress_back.jpg; rc-classic-pback: 0px 0px 200px 16px; } +@spritesheet rc-classic-pfill-sheet { src: ../../../Classic/Progress_add.tga; rc-classic-pfill: 0px 0px 200px 16px; } +@spritesheet rc-classic-cancel-sheet { src: ../../../Classic/Cancel.jpg; rc-classic-cancel: 0px 0px 70px 21px; } +@spritesheet rc-classic-cancel2-sheet { src: ../../../Classic/Cancel2.jpg; rc-classic-cancel-over: 0px 0px 70px 21px; } +#panel { width: 213px; height: 130px; } +#back { left: 0; top: 5px; width: 213px; height: 60px; decorator: image(rc-classic-stone fill); } +#box_top { left: 0; top: 0; width: 213px; height: 5px; decorator: image(rc-classic-edge fill); } +#box_middle { left: 0; top: 65px; width: 213px; height: 60px; decorator: image(rc-classic-stone fill); } +#box_bottom { left: 0; top: 125px; width: 213px; height: 5px; decorator: image(rc-classic-edge fill); } +#progress_back { left: 31px; top: 70px; width: 150px; height: 12px; decorator: image(rc-classic-pback fill); } +#progress_bar { left: 31px; top: 70px; height: 12px; decorator: image(rc-classic-pfill fill); } +#cancel { left: 71px; top: 99px; width: 70px; height: 21px; decorator: image(rc-classic-cancel fill); } +#cancel:hover { decorator: image(rc-classic-cancel-over fill); } +#rc_title { top: 14px; } +#rc_step { top: 32px; } +#rc_countdown { top: 50px; } +#rc_title, #rc_step, #rc_countdown { width: calc(213px * var(--root-scale)); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/remember_password_prompt.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/remember_password_prompt.rcss new file mode 100644 index 0000000000..17edaff739 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/remember_password_prompt.rcss @@ -0,0 +1,66 @@ +/* Classic (0.97) look for the login's "save password" warning (RememberPasswordPrompt). 0.97 has no + such option; the warning takes the classic confirmation's parts (generic_confirm_dialog.rcss): + 0.97's dialog stone (Message_box1) between two edge strips (Message_box2), 213 wide, the title + bold over the text, both centred, and the two buttons on 0.97's Bar plate with their labels, + lighter under the mouse and darker while pressed (0.97's lettered OK / Cancel plates are English + art, and these labels are translated). Legacy's flat 340 panel, palette and dp sizes are + replaced; .center-both still centres the panel. */ + +@spritesheet classic-rpp-edge-sheet { src: ../../../Classic/Message_box2.jpg; classic-rpp-edge: 0px 0px 213px 5px; } +@spritesheet classic-rpp-stone-sheet { src: ../../../Classic/Message_box1.jpg; classic-rpp-stone: 0px 0px 213px 40px; } +@spritesheet classic-rpp-plate-sheet { src: ../../../Classic/Bar.jpg; classic-rpp-plate: 0px 0px 40px 18px; } + +/* The edges on the panel (the strips fitted to its width, at the top and the bottom), the stone + between them on the panel's art-free child. */ +#panel { + width: 213dp; + height: 200dp; + font-family: "token(font-body)"; + font-size: 1rem; + color: #ffffff; + decorator: image(classic-rpp-edge contain left top), image(classic-rpp-edge contain left bottom); +} +.frame-accent { + position: absolute; + left: 0; + right: 0; + top: 5dp; + bottom: 5dp; + decorator: image(classic-rpp-stone fill); +} + +.prompt-title { + position: absolute; + left: 10dp; + top: 15dp; + width: 193dp; + text-align: center; + color: #ffffff; + font-weight: bold; +} + +.prompt-body { + position: absolute; + left: 10dp; + top: 38dp; + width: 193dp; + text-align: center; + line-height: 15dp; + color: #ffffff; + white-space: normal; +} + +.btn-ok, .btn-cancel { + top: auto; + bottom: 19dp; + width: 70dp; + height: 21dp; + line-height: 21dp; + text-align: center; + color: #ffffff; + decorator: image(classic-rpp-plate fill); +} +.btn-ok:hover, .btn-cancel:hover { decorator: image(classic-rpp-plate fill); image-color: #ffe6b4; } +.btn-ok:active, .btn-cancel:active { decorator: image(classic-rpp-plate fill); image-color: #b4b4b4; } +.btn-ok { left: 31dp; } +.btn-cancel { left: 112dp; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/server_msg.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/server_msg.rcss new file mode 100644 index 0000000000..e51e656059 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/server_msg.rcss @@ -0,0 +1,48 @@ +/* Classic theme for the character list's server message (CServerMsgWin). Its frame is the Season 2 + login's art (server_ex*), which the classic theme does not bring (it keeps 0.97's login + and server list), and 0.97 has no such window: the message keeps its translucent black centre and takes + the 0.97 box's edges (Message_box2, stretched to the 512 width) at the top and the bottom, no + sides. Legacy's rules first, then the classic ones. */ + +/* Legacy theme for CServerMsgWin, reproducing its five sprites and Render(): the centre + (server_ex03, flat black at alpha 143) inset 3 px, the 512 x 6 top and bottom strips + (server_ex01, rows 0-5 and 6-11), the 3 px side pieces (server_ex02 columns 0-2 and 3-5) + stretched to the line count, the lines white in the fixed font (Cousine) at (11, 12 + 20 i). + Real pixels inside #panel. */ + +@spritesheet server-msg-strip-sheet +{ + src: "../../../server_ex01.tga"; + server-msg-top: 0px 0px 512px 6px; + server-msg-bottom: 0px 6px 512px 6px; +} +@spritesheet server-msg-side-sheet +{ + src: "../../../server_ex02.jpg"; + server-msg-left: 0px 0px 3px 4px; + server-msg-right: 3px 0px 3px 4px; +} + +#panel { position: absolute; transform-origin: left top; width: 512px; pointer-events: none; } +#centre { position: absolute; left: 3px; top: 3px; width: 506px; background-color: rgba(0, 0, 0, 143); } +#top { position: absolute; left: 0; top: 0; width: 512px; height: 6px; decorator: image(server-msg-top); } +#bottom { position: absolute; left: 0; width: 512px; height: 6px; decorator: image(server-msg-bottom); } +#left { position: absolute; left: 0; top: 6px; width: 3px; decorator: image(server-msg-left); } +#right { position: absolute; left: 509px; top: 6px; width: 3px; decorator: image(server-msg-right); } + +.sharp-text { display: block; position: absolute; white-space: pre; pointer-events: none; } +.server-line { left: 11px; font-family: Cousine; color: #ffffff; } + +/* RenderContents()'s own rows: the message lines 20 units apart from y 12, up to + SMW_MSG_LINE_MAX of them. */ +.server-lines { position: static; } +.server-line:nth-child(1) { top: 12px; } +.server-line:nth-child(2) { top: 32px; } +.server-line:nth-child(3) { top: 52px; } +.server-line:nth-child(4) { top: 72px; } +.server-line:nth-child(5) { top: 92px; } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet server-msg-classic-edge-sheet { src: ../../../Classic/Message_box2.jpg; server-msg-classic-edge: 0px 0px 213px 5px; } +#top, #bottom { height: 5px; decorator: image(server-msg-classic-edge fill); } +#left, #right { display: none; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/server_select.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/server_select.rcss new file mode 100644 index 0000000000..05b5aaf300 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/server_select.rcss @@ -0,0 +1,152 @@ +/* Classic (0.97) server list. From the 0.97 client's art and layout: + - group buttons 70x16 (0Box squashed) in a column centred on the screen, from y=220 of 480, + dimmed to 0.8 and lit (and pushed 10 px right) when selected; + - the selected group's servers 134x20 (0Box squashed) at x=365 of 640 (centre + 45), each with + its load bar under the name: cyan -> white -> red; + - Non-PvP servers yellowish, closed ones orange; text white. + Differences from the original, for want of data in a stylesheet: the server rows start level + with the group column instead of centred on the selected group, and the load bar is one strip + instead of 20 squares. + 1 original pixel = 1/480 of the screen height, as the 0.97 client scales its 2D art. The text + does not stretch with it: 0.97 drew its font at screen pixels, so it is 13rem, 13 px growing + like the native text (server_select.rml's body is "scene-window-scale", RmlNativeText.h). */ + +@spritesheet classic-server-box-sheet +{ + src: ../../../../Logo/Classic/0box.jpg; + classic-server-box: 0px 0px 134px 30px; +} + +body { + --px: calc(100vh / 480); +} + +#panel { + left: 0; + top: 0; + width: 100%; + height: 100%; + padding: 0; + transform: none; + font-family: "token(font-body)"; + font-size: 13rem; + color: #ffffff; +} + +#columns { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + display: block; +} + +#group_col { + position: absolute; + left: 50%; + top: calc(220 * var(--px)); + margin-left: calc(-35 * var(--px)); + width: calc(80 * var(--px)); + display: block; +} + +.group-btn { + display: block; + width: calc(70 * var(--px)); + height: calc(16 * var(--px)); + line-height: calc(16 * var(--px)); + text-align: center; + white-space: nowrap; + cursor: pointer; + pointer-events: auto; + decorator: image(classic-server-box); + filter: brightness(0.8); +} +.group-btn.checked { + margin-left: calc(10 * var(--px)); + filter: brightness(1.0); +} + +#server_col { + position: absolute; + left: 50%; + top: calc(218 * var(--px)); + margin-left: calc(45 * var(--px)); + width: calc(134 * var(--px)); + display: block; +} +#server_col.hidden { + display: none; +} + +.server-row { + position: relative; + display: block; + width: calc(134 * var(--px)); + height: calc(20 * var(--px)); + padding: 0; + padding-top: calc(1 * var(--px)); + text-align: center; + line-height: calc(12 * var(--px)); + white-space: nowrap; + cursor: pointer; + pointer-events: auto; + decorator: image(classic-server-box); + filter: brightness(0.8); + color: #ffffb3; +} +.server-row:hover { + filter: brightness(1.0); +} +.server-row.gray { + color: #ffffff; +} +.server-row.orange { + color: #ffb27f; +} + +/* base.rcss gives the server list's buttons (.server-group-btn / .server-option-btn) the legacy + sprites and colours for each state (the selected group red): these keep the 0.97 plate and + colours when selected, hovered and pressed. */ +.group-btn:hover, .group-btn:active, .group-btn.checked, .group-btn.checked:hover, .group-btn.checked:active, +.server-row:hover, .server-row:active { + decorator: image(classic-server-box); +} +.group-btn, .group-btn:hover, .group-btn:active, +.group-btn.checked, .group-btn.checked:hover, .group-btn.checked:active { color: #ffffff; } +.server-row:hover, .server-row:active { color: #ffffb3; } +.server-row.gray:hover, .server-row.gray:active { color: #ffffff; } +.server-row.orange:hover, .server-row.orange:active { color: #ffb27f; } + +.server-gauge-slot { + position: absolute; + left: calc(18 * var(--px)); + top: calc(14 * var(--px)); + width: calc(98 * var(--px)); + height: calc(3 * var(--px)); + margin: 0; + background-color: #1a1a1a; +} +.server-gauge-fill { + display: block; + height: 100%; + decorator: linear-gradient(to right, #00ffff, #ffffff, #ff0000); +} + +/* Test-server warning: two lines in red, left of the list (x=150 of 640). */ +#pvp_notice { + position: absolute; + left: 50%; + top: calc(174 * var(--px)); + margin-left: calc(-170 * var(--px)); + color: #ff3319; +} +#pvp_notice.hidden { + display: none; +} + +/* The 0.97 list has no description panel. */ +#desc_panel { + display: none; +} diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/siege_warfare.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/siege_warfare.rcss new file mode 100644 index 0000000000..d872cb8845 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/siege_warfare.rcss @@ -0,0 +1,195 @@ +/* Classic theme for the castle siege HUD (CSiegeWarfare). 0.97 has no Castle Siege; the Season 1 + client's (0040dc00 / 0040f8d0, 00411f60), on the 640x480 board: + - the mini map: frame.tga (151 x 173) at (489, 259) over the 128 x 128 map at (512, 304); the + zoom button b_zoomout01 (24 x 22) at (616, 272); the transparency in % at (514, 291), the click + on it (494..532, 287..303); + - the commander's column: seven groups 17 apart from (494, 291) (19 x 18, b_group02 under the + chosen one), their numbers orange (1, 0.6, 0.3), the chosen one white; the three commands + beside the chosen group from x 511, 5 above its row (18 and 36 above for the 6th and 7th), + 18 apart: b_command01 (b_command02 under the mouse, 30 x 18) with i_attack at (8, 2), i_defense + at (7, 2), i_wait at (10, 3); a command on the map 11 x 11 at -8; + - the time on the hourglass (154 x 23 drawn 154 x 30) at (238, 405), orange (1, 0.6, 0.3). + The map stays where the C++ projects the dots (25, 28 from #siege_hud), so #siege_hud is at + (487, 276) and everything else is placed from it. The battle-skill frame (Season 1 draws none) + keeps legacy's art, above the frame. Legacy's rules first, then the classic ones. */ + +/* Legacy theme for CSiegeWarfare, reproducing the original CSiegeWarBase::Render() and its + variants' OnRender(): from the frame's top-left (486, 234) the 128 x 128 map at (25, 28), the + 154 x 162 frame over it, the 134 x 37 time frame at (20, 158) with the big-font time centred + 10 below its top, the transparency button (38 x 23, up / over / down rows) at (58, 4) with its + value centred in bold, and the 3 x 3 hero dot (255, 255, 0). The other characters' dots are the + colour the original's RenderColor() inherited from the previous native draw, measured on the + original client: (106, 97, 88). A command on the map: its team number in bold at (-12, -5) + and its icon (the image's first (w - 1) x (h - 1) texels, as RenderColorBitmap()'s power-of-two + UVs cut it) drawn 11 x 11 at (-7, -7). The commander's team buttons (26 x 22) and command + buttons (30 x 22, icons at (8, 5), (8, 3) and (10, 5)); the chosen command follows the pointer + (number at (-13, -6), icon at (-8, -8)). The battle-skill frame (128 x 53) sits at (26, + -53): the skill's 20 x 28 cell at (26, 21), the kills at (78, 28) and (97, 28) in the big + font, the scroll buttons (15 x 13) at (48, 21) and (48, 36). Reference px on .screen's + HUD board (see siege_warfare.rml). */ + +@spritesheet sw-frame-sheet { src: "../../../newui_SW_Minimap_Frame.tga"; sw-frame: 0px 0px 154px 162px; } +@spritesheet sw-time-sheet { src: "../../../newui_SW_Time_Frame.tga"; sw-time: 0px 0px 134px 37px; } +@spritesheet sw-alpha-sheet { + src: "../../../newui_SW_MiniMap_Bt_clearness.jpg"; + sw-alpha-up: 0px 0px 38px 23px; + sw-alpha-over: 0px 23px 38px 23px; + sw-alpha-down: 0px 46px 38px 23px; +} +@spritesheet sw-team-sheet { + src: "../../../newui_SW_Minimap_Bt_group.tga"; + sw-team-up: 0px 0px 26px 22px; + sw-team-over: 0px 22px 26px 22px; + sw-team-down: 0px 44px 26px 22px; +} +@spritesheet sw-order-sheet { + src: "../../../newui_SW_Minimap_Bt_Command.tga"; + sw-order-up: 0px 0px 30px 22px; + sw-order-over: 0px 22px 30px 22px; + sw-order-down: 0px 44px 30px 22px; +} +@spritesheet sw-attack-sheet { src: "../../../i_attack.tga"; sw-attack: 0px 0px 13px 13px; } +@spritesheet sw-defence-sheet { src: "../../../i_defense.tga"; sw-defence: 0px 0px 18px 15px; } +@spritesheet sw-wait-sheet { src: "../../../i_wait.tga"; sw-wait: 0px 0px 11px 12px; } +@spritesheet sw-skill-sheet { src: "../../../newui_SW_BattleSkill_Frame.tga"; sw-skill: 0px 0px 128px 53px; } +@spritesheet sw-scroll-up-sheet { + src: "../../../newui_Bt_skill_scroll_up.jpg"; + sw-scroll-up-up: 0px 0px 15px 13px; + sw-scroll-up-over: 0px 13px 15px 13px; + sw-scroll-up-down: 0px 26px 15px 13px; +} +@spritesheet sw-scroll-down-sheet { + src: "../../../newui_Bt_skill_scroll_dn.jpg"; + sw-scroll-down-up: 0px 0px 15px 13px; + sw-scroll-down-over: 0px 13px 15px 13px; + sw-scroll-down-down: 0px 26px 15px 13px; +} + +body { pointer-events: none; } + +.screen { + pointer-events: none; + font-family: "token(font-body)"; +} + +.text { + display: block; + position: absolute; + transform-origin: left top; + white-space: nowrap; + color: #ffffff; +} +.text.bold { font-weight: bold; } +.button-label { left: 0; top: 0; text-align: center; } + +/* The frame's top-left on the HUD board: right of the HUD's centre, above the bar. */ +#siege_hud { position: absolute; left: 486px; top: 234px; width: 0; height: 0; } +#frame { position: absolute; left: 0; top: 0; width: 154px; height: 162px; } +#map { position: absolute; left: 25px; top: 28px; width: 128px; height: 128px; } +#frame_art { position: absolute; left: 0; top: 0; width: 154px; height: 162px; decorator: image(sw-frame); } +#time_frame { position: absolute; left: 20px; top: 158px; width: 134px; height: 37px; decorator: image(sw-time); } +#time { left: 20px; top: 168px; text-align: center; } + +.dot { position: absolute; width: 3px; height: 3px; background-color: rgb(106, 97, 88); } +#hero { position: absolute; width: 3px; height: 3px; background-color: #ffff00; } + +.command { position: absolute; width: 0; height: 0; } +.command-team { left: -12px; top: -5px; } +.command-icon { position: absolute; left: -7px; top: -7px; width: 11px; height: 11px; } + +.cursor { position: absolute; width: 0; height: 0; } +.cursor-team { left: -13px; top: -6px; } +.cursor-icon { position: absolute; left: -8px; top: -8px; } +.cursor-icon.attack { width: 13px; height: 13px; } +.cursor-icon.defence { width: 18px; height: 15px; } +.cursor-icon.wait { width: 11px; height: 12px; } + +/* The original's RenderCmdBtn(): the team column at (0, 5), 22 apart, and the command column beside + it from the chosen team's row; teams 6 and 7 share team 5's row. */ +#teams { position: absolute; left: 0; top: 5px; } +#orders { position: absolute; left: 26px; top: 5px; } +#orders.chosen-1 { top: 27px; } +#orders.chosen-2 { top: 49px; } +#orders.chosen-3 { top: 71px; } +#orders.chosen-4, #orders.chosen-5, #orders.chosen-6 { top: 93px; } +.team { position: relative; display: block; width: 26px; height: 22px; decorator: image(sw-team-up); } +.team:hover { decorator: image(sw-team-over); } +.team:active, .team.selected { decorator: image(sw-team-down); } + +.order { position: relative; display: block; width: 30px; height: 22px; } +.order-button { position: absolute; left: 0; top: 0; width: 30px; height: 22px; decorator: image(sw-order-up); } +.order-button:hover { decorator: image(sw-order-over); } +.order-button:active { decorator: image(sw-order-down); } +.order-icon { position: absolute; } +.order-icon.attack { left: 8px; top: 5px; width: 13px; height: 13px; decorator: image(sw-attack); } +.order-icon.defence { left: 8px; top: 3px; width: 18px; height: 15px; decorator: image(sw-defence); } +.order-icon.wait { left: 10px; top: 5px; width: 11px; height: 12px; decorator: image(sw-wait); } + +#skill { position: absolute; left: 26px; top: -53px; width: 128px; height: 53px; } +#skill_frame { position: absolute; left: 0; top: 0; width: 128px; height: 53px; decorator: image(sw-skill); } +#skill_icon { position: absolute; left: 26px; top: 21px; width: 20px; height: 28px; } +.kills-needed { left: 78px; top: 28px; } +.kills-now { left: 97px; top: 28px; } +.scroll { position: absolute; left: 48px; width: 15px; height: 13px; } +.scroll-up { top: 21px; decorator: image(sw-scroll-up-up); } +.scroll-up:hover { decorator: image(sw-scroll-up-over); } +.scroll-up:active { decorator: image(sw-scroll-up-down); } +.scroll-down { top: 36px; decorator: image(sw-scroll-down-up); } +.scroll-down:hover { decorator: image(sw-scroll-down-over); } +.scroll-down:active { decorator: image(sw-scroll-down-down); } + +#alpha_button { position: absolute; left: 58px; top: 4px; width: 38px; height: 23px; decorator: image(sw-alpha-up); } +#alpha_button:hover { decorator: image(sw-alpha-over); } +#alpha_button:active { decorator: image(sw-alpha-down); } + +/* The battle skill's icon: reddened until the hero has the kills it needs. */ +#skill_icon { image-color: #ffffff; } +#skill_icon.unaffordable { image-color: rgb(255, 127, 127); } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#time { width: calc(134px * var(--root-scale)); } +.team .button-label { width: calc(26px * var(--root-scale)); line-height: calc(22px * var(--root-scale)); } +#alpha_button .button-label { width: calc(38px * var(--root-scale)); line-height: calc(23px * var(--root-scale)); } + +/* The buttons take the pointer: a click on one is the HUD's, never the world's. The map's zoom + button is the frame art's own, so it draws nothing of its own. */ +.team, .order-button, .scroll, #alpha_button, #scale_button { pointer-events: auto; cursor: pointer; } +#scale_button { position: absolute; left: 134px; top: 7px; width: 13px; height: 12px; } + +/* --- Classic: the Season 1 HUD ---------------------------------------------------------------- */ +@spritesheet sw-classic-frame-sheet { src: "../../../frame.tga"; sw-classic-frame: 0px 0px 151px 173px; } +@spritesheet sw-classic-zoom-sheet { src: "../../../b_zoomout01.jpg"; sw-classic-zoom: 0px 0px 24px 22px; } +@spritesheet sw-classic-group-sheet { src: "../../../b_group02.jpg"; sw-classic-group: 0px 0px 19px 18px; } +@spritesheet sw-classic-cmd1-sheet { src: "../../../b_command01.jpg"; sw-classic-cmd: 0px 0px 30px 18px; } +@spritesheet sw-classic-cmd2-sheet { src: "../../../b_command02.jpg"; sw-classic-cmd-over: 0px 0px 30px 18px; } +@spritesheet sw-classic-glass-sheet { src: "../../../hourglass.tga"; sw-classic-glass: 0px 0px 154px 23px; } + +#siege_hud { left: 487px; top: 276px; } +#frame_art { left: 2px; top: -17px; width: 151px; height: 173px; decorator: image(sw-classic-frame); } +#time_frame { left: -249px; top: 129px; width: 154px; height: 30px; decorator: image(sw-classic-glass); } +#time { left: -249px; top: 136px; color: rgb(255, 153, 77); font-effect: shadow(1px 1px black); } +#time { width: calc(154px * var(--root-scale)); } +#scale_button { left: 129px; top: -4px; width: 24px; height: 22px; decorator: image(sw-classic-zoom); } +#alpha_button, #alpha_button:hover, #alpha_button:active { left: 7px; top: 11px; width: 38px; height: 16px; decorator: none; } +#alpha_button .button-label { width: calc(38px * var(--root-scale)); line-height: calc(16px * var(--root-scale)); } + +#teams { left: 5px; top: 32px; } +.team, .team:hover, .team:active { width: 19px; height: 17px; decorator: none; } +.team.selected { decorator: image(sw-classic-group); height: 17px; } +.team .button-label { color: rgb(255, 153, 77); width: calc(19px * var(--root-scale)); line-height: calc(18px * var(--root-scale)); } +.team.selected .button-label { color: #ffffff; } +#orders { left: 24px; top: 27px; } +#orders.chosen-1 { top: 44px; } +#orders.chosen-2 { top: 61px; } +#orders.chosen-3 { top: 78px; } +#orders.chosen-4 { top: 95px; } +#orders.chosen-5 { top: 94px; } +#orders.chosen-6 { top: 93px; } +.order { height: 18px; } +.order-button, .order-button:active { height: 18px; decorator: image(sw-classic-cmd); } +.order-button:hover { decorator: image(sw-classic-cmd-over); } +.order-icon.attack { left: 8px; top: 2px; } +.order-icon.defence { left: 7px; top: 2px; } +.order-icon.wait { left: 10px; top: 3px; } +.command-icon { left: -8px; top: -8px; } +#skill { top: -70px; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/storage.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/storage.rcss new file mode 100644 index 0000000000..5b6f0926c8 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/storage.rcss @@ -0,0 +1,125 @@ +/* Classic (0.97) storage (CStorageInventory), from the 0.97 client's 004f3170: Item_Back01 over Item_Back02, the title at + the top, the 8x15 grid at (15, 50), the Zen bar (Item_Money) at (50, 353) with "Zen" and the + amount, the storage cost line at y 374, and Deposit / Withdraw / Lock (24x24, the second image + while pressed) at x 26, 76 and 126, y 390. No expansion (not in 0.97). #panel's left/top/scale + come from C++; everything below is the window's own units. */ + +@spritesheet stor-classic-back1-sheet { src: ../../../Classic/Item_back01.jpg; stor-classic-back1: 0px 0px 190px 256px; } +@spritesheet stor-classic-back2-sheet { src: ../../../Classic/Item_Back02.jpg; stor-classic-back2: 0px 0px 190px 177px; } + +#panel { + position: absolute; + transform-origin: left top; + width: 190px; + height: 433px; + font-family: "token(font-body)"; +} + +.bg-fill, .bg-top, .bg-left, .bg-right, .bg-bottom { position: absolute; pointer-events: none; } +.bg-top { left: 0; top: 0; width: 190px; height: 256px; decorator: image(stor-classic-back1); } +.bg-fill { left: 0; top: 256px; width: 190px; height: 177px; decorator: image(stor-classic-back2); } +.bg-right, .bg-bottom { display: none; } +/* "Zen" left of the bar, on its dark box (the frame piece 0.97 does not need). */ +.bg-left { + left: 20px; + top: 355px; + width: 22px; + height: 13px; + background-color: #282828; + font-size: 11px; + font-weight: bold; + decorator: text("Zen" #ffdc96 center center); +} + +#title { + position: absolute; + /* 0.97: a 120-wide box at x 35, centred. */ + left: 35px; + top: 12px; + width: calc(120px * var(--root-scale)); + text-align: center; + color: #dcdcdc; + font-weight: bold; + font-size: 1em; +} +#title.locked { color: rgb(240, 32, 32); } + +@spritesheet stor-classic-money-sheet { src: ../../../Classic/Item_money.jpg; stor-classic-money: 0px 0px 113px 18px; } +#money_bg { + position: absolute; + left: 50px; + top: 353px; + width: 113px; + height: 18px; + decorator: image(stor-classic-money); + pointer-events: none; +} +#zen_text { + position: absolute; + right: 32px; + top: 356px; + color: #ffdc96; + font-weight: bold; + font-size: 1em; + white-space: nowrap; + pointer-events: none; +} +#zen_text.gold-hundred-thousand { color: #00c918; } +#zen_text.gold-million { color: #ff9600; } +#zen_text.gold-ten-million { color: #ff0000; } +#fee_label { + position: absolute; + left: 50px; + top: 374px; + color: #ff0000; + background-color: #282828; + font-weight: bold; + font-size: 1em; + white-space: nowrap; + pointer-events: none; +} +#fee_value { + position: absolute; + right: 22px; + top: 374px; + color: #ffdc96; + background-color: #282828; + font-weight: bold; + font-size: 1em; + white-space: nowrap; + pointer-events: none; +} + +@spritesheet stor-classic-money1-sheet { src: ../../../Classic/Money_01.jpg; stor-classic-money-btn: 0px 0px 24px 24px; } +@spritesheet stor-classic-money2-sheet { src: ../../../Classic/Money_02.jpg; stor-classic-money-btn-pressed: 0px 0px 24px 24px; } +@spritesheet stor-classic-lock1-sheet { src: ../../../Classic/Lock_01.jpg; stor-classic-lock: 0px 0px 24px 24px; } +@spritesheet stor-classic-lock2-sheet { src: ../../../Classic/Lock_02.jpg; stor-classic-lock-pressed: 0px 0px 24px 24px; } +@spritesheet stor-classic-lock3-sheet { src: ../../../Classic/Lock_03.jpg; stor-classic-locked: 0px 0px 24px 24px; } +@spritesheet stor-classic-lock4-sheet { src: ../../../Classic/Lock_04.jpg; stor-classic-locked-pressed: 0px 0px 24px 24px; } + +.stor-btn { + position: absolute; + top: 390px; + width: 24px; + height: 24px; + cursor: pointer; + pointer-events: auto; +} +.stor-btn.hidden { display: none; } +.stor-btn-insert { left: 26px; decorator: image(stor-classic-money-btn); } +.stor-btn-take { left: 76px; decorator: image(stor-classic-money-btn); } +.stor-btn-insert:active, .stor-btn-take:active { decorator: image(stor-classic-money-btn-pressed); } +.stor-btn-lock { left: 126px; decorator: image(stor-classic-lock); } +.stor-btn-lock:active { decorator: image(stor-classic-lock-pressed); } +.stor-btn-lock.locked-mode { decorator: image(stor-classic-locked); } +.stor-btn-lock.locked-mode:active { decorator: image(stor-classic-locked-pressed); } +.stor-btn-expand { display: none; } + +.native-anchor { position: absolute; pointer-events: none; } +#item_grid, #item_grid_counts { left: 15px; top: 50px; width: calc(8 * var(--item-cell)); height: calc(15 * var(--item-cell)); } +#item_view { height: 473px; } + +/* The grid's clicks are native (CInventoryCtrl), so the placed panel takes no pointer events; its + controls take their own. (Legacy's rules, which this copy predated.) */ +#panel.slot-placed { pointer-events: none; } +#panel { font-size: calc(var(--text-px, 12px) / var(--root-scale)); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/storage_ext.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/storage_ext.rcss new file mode 100644 index 0000000000..065c719c8b --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/storage_ext.rcss @@ -0,0 +1,84 @@ +/* Classic theme for the extended storage. 0.97 has none; it takes the 0.97 storage's parts: the + inventory frame (Item_Back01 over Item_Back02), the white bold title, 0.97's Close at (20, 395). + Legacy's layout and comments below. */ + +/* Legacy theme for CStorageInventoryExt's chrome (frame/title/exit button). #panel's left/top/ + scale come live from C++ (SyncRmlModel()), so coordinates below are plain reference px, not dp. */ + +#panel { + position: absolute; + transform-origin: left top; + width: 190px; + height: 429px; + font-family: "token(font-body)"; +} + +#title { + position: absolute; + left: 0; + top: 11px; + width: calc(100% * var(--root-scale)); + text-align: center; + color: token(text-primary); + font-weight: bold; + font-size: 1em; +} + +@spritesheet ext-btn-exit-sheet { src: "../../../newui_exit_00.tga"; ext-btn-exit: 0px 0px 36px 29px; } +.ext-btn { + position: absolute; + left: 13px; + top: 391px; + width: 36px; + height: 29px; + cursor: pointer; + pointer-events: auto; + decorator: image(ext-btn-exit); +} +.ext-btn:hover { filter: brightness(1.25); } + +/* Native item grid: the first cell's top-left, in #panel's units. */ +.native-anchor { position: absolute; pointer-events: none; } +#item_grid, #item_grid_counts { left: 15px; top: 36px; width: calc(8 * var(--item-cell)); height: calc(15 * var(--item-cell)); } + +/* The frame. */ +@spritesheet ext-bg-fill-sheet { src: "../../../newui_msgbox_back.jpg"; ext-bg-fill: 0px 0px 190px 429px; } +@spritesheet ext-bg-top-sheet { src: "../../../newui_item_back01.tga"; ext-bg-top: 0px 0px 190px 64px; } +@spritesheet ext-bg-left-sheet { src: "../../../newui_item_back02-L.tga"; ext-bg-left: 0px 0px 21px 320px; } +@spritesheet ext-bg-right-sheet { src: "../../../newui_item_back02-R.tga"; ext-bg-right: 0px 0px 21px 320px; } +@spritesheet ext-bg-bottom-sheet { src: "../../../newui_item_back03.tga"; ext-bg-bottom: 0px 0px 190px 45px; } + +.bg-fill, .bg-top, .bg-left, .bg-right, .bg-bottom { + position: absolute; + pointer-events: none; +} + +.bg-fill { left: 0; top: 0; width: 190px; height: 429px; decorator: image(ext-bg-fill); } +.bg-top { left: 0; top: 0; width: 190px; height: 64px; decorator: image(ext-bg-top); } +.bg-left { left: 0; top: 64px; width: 21px; height: 320px; decorator: image(ext-bg-left); } +.bg-right { left: 169px; top: 64px; width: 21px; height: 320px; decorator: image(ext-bg-right); } +.bg-bottom { left: 0; top: 384px; width: 190px; height: 45px; decorator: image(ext-bg-bottom); } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#title { margin-left: calc(50% - 50% * var(--root-scale)); } + +/* The grid's clicks are native (CInventoryCtrl), so the placed panel takes no pointer events; its + controls take their own. */ +#panel.slot-placed { pointer-events: none; } +#panel { font-size: calc(var(--text-px, 12px) / var(--root-scale)); } + +/* --- Classic ---------------------------------------------------------------------------------- */ +@spritesheet classic-sext-back1-sheet { src: ../../../Classic/Item_back01.jpg; classic-sext-back1: 0px 0px 190px 256px; } +@spritesheet classic-sext-back2-sheet { src: ../../../Classic/Item_Back02.jpg; classic-sext-back2: 0px 0px 190px 177px; } +@spritesheet classic-sext-exit-sheet { src: ../../../Classic/Exit_01.jpg; classic-sext-exit: 0px 0px 24px 24px; } +@spritesheet classic-sext-exit2-sheet { src: ../../../Classic/Exit_02.jpg; classic-sext-exit-pressed: 0px 0px 24px 24px; } +#panel { height: 433px; } +.bg-fill { top: 256px; height: 177px; decorator: image(classic-sext-back2); } +.bg-top { height: 256px; decorator: image(classic-sext-back1); } +.bg-left, .bg-right, .bg-bottom { display: none; } +#frame_corner_close { display: none; } +.ext-btn { left: 20px; top: 395px; width: 24px; height: 24px; decorator: image(classic-sext-exit); } +.ext-btn:hover { filter: none; } +.ext-btn:active { decorator: image(classic-sext-exit-pressed); } +/* Centred as the extended inventory's: legacy's margin shifts this sharp-text title out of the window. */ +#title { color: #ffffff; margin-left: 0; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/sys_menu.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/sys_menu.rcss new file mode 100644 index 0000000000..d43409012e --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/sys_menu.rcss @@ -0,0 +1,81 @@ +/* Classic (0.97) system menu of the login and character scenes (CSysMenuWin): Esc opens a column + of Message_box plates (213x64 squashed to 120x22) at x 260, y 60 + 30*i of the 640x480 frame, + with no panel, frame or darkening behind them; the plate under the mouse is drawn again in + additive blend tinted (0.8, 0.6, 0.4); each label is centred on x 320 at the plate's y + 5, + white. Login shows Exit game / Options / Cancel (3 plates), the character scene Exit game / + Select server / Options / Cancel (4 plates; C++ hides #btn_select_server where it does not + apply, which also sets .compact). From the 0.97 client's RenderMessageBox (0051af50), message + 0x6e. Positions below are the column's own, in 1/480 of the screen height, as msg_win.rcss. + The labels keep legacy's size, the native text size C++ sets on #panel ("native-text", + RmlNativeText.h): 0.97 drew its font at screen pixels, and 1rem here is one original pixel, + not the text size (sys_menu.rml's body is "scene-window-scale"). + + Dropped from legacy: the op1_back1 cap sprite and the .panel-cap-top / .panel-cap-bottom / + .panel-middle art sizes (0.97 draws nothing behind the plates, so those three art elements + are hidden below; they are art, not controls), and the 213x187rem panel and 108x30rem button + geometry, replaced by the plates'. The modal #backdrop stays (base.rcss: full screen, takes + the pointer) but shows nothing. */ + +@spritesheet classic-sysmenu-plate-sheet { src: ../../../Classic/Message_box.jpg; classic-sysmenu-plate: 0px 0px 213px 64px; } + +body { --px: calc(100vh / 480); } + +/* 0.97 darkens nothing behind the menu: the catcher keeps the clicks, not the dim. */ +#backdrop { + background-color: transparent; +} + +/* The column: 120 wide, centred on x 320, from y 60; 4 plates reach y 112 (3 reach 82). */ +#panel { + position: absolute; + left: 50%; + top: calc(60 * var(--px)); + transform: none; + width: calc(120 * var(--px)); + height: calc(112 * var(--px)); + margin-left: calc(-60 * var(--px)); + font-family: "token(font-body)"; + color: white; +} +#panel.compact { + height: calc(82 * var(--px)); +} + +/* The S6 panel art (caps and stone middle): 0.97 has no panel behind the plates. */ +#panel .panel-cap-top, +#panel .panel-cap-bottom, +#panel .panel-middle { + display: none; +} + +/* The plates: Message_box squashed to 120x22, one every 30, the label on one line centred on the + plate (a label wider than the plate stays centred: 0.97 centred it on x 320 whatever its + width; vertically the 22-high line box centres it, where 0.97 put its top at plate y + 5, + about the same for the native text size). Under the mouse 0.97 adds the plate to itself + tinted (0.8, 0.6, 0.4), a brightening RCSS cannot express; image-color keeps that tint's hue + (1.8 : 1.6 : 1.4 with the brightest channel left at full) on hover and while pressed (0.97 + has no pressed state). */ +#panel .btn { + left: 0; + width: calc(120 * var(--px)); + height: calc(22 * var(--px)); + line-height: calc(22 * var(--px)); + white-space: nowrap; + decorator: image(classic-sysmenu-plate); +} +#panel .btn:hover, +#panel .btn:active { + decorator: image(classic-sysmenu-plate); + image-color: #ffe3c6; + filter: brightness(1.8); +} + +#btn_exit_game { top: 0; } +#btn_select_server { top: calc(30 * var(--px)); } +#btn_option { top: calc(60 * var(--px)); } +#btn_close { top: calc(90 * var(--px)); } + +/* Login (.compact, #btn_select_server hidden by C++): Options and Cancel close up to the 3-plate + column. */ +#panel.compact #btn_option { top: calc(30 * var(--px)); } +#panel.compact #btn_close { top: calc(60 * var(--px)); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/theme.ini b/src/bin/Data/Interface/RmlUi/themes/classic/theme.ini new file mode 100644 index 0000000000..76a0c8a920 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/theme.ini @@ -0,0 +1,24 @@ +; The classic 0.97 interface. It builds on legacy (ThemeInheritance.h): a window this theme does +; not restyle keeps legacy's look, so the theme ships only what it changes. Its art is the 0.97 +; client's, in Data/Interface/Classic (interface) and Data/Logo/Classic (login box and character select). +[Theme] +Base=legacy + +; 0.97 draws its windows over the bar's ends, where the dragons stand, so the HUD goes under every +; window (the lowest is quick_command.rml, 2.0) and stays over the event HUDs and the buff strip +; (up to 1.92): a window docked on a side, or dragged there, covers that side's dragon. +; 0.97 draws the chat's input box over the bar (its foot on the bar's top), so it goes over the +; windows and the HUD and under the tooltips (10.69). +[Stacking] +main_frame.rml=1.95 +chat_input.rml=10.65 + +; The classic client font, Verdana, taken from the player's Windows (it may not be shipped); +; tokens.ini names it, and the bundled face stands in where the file is missing +; (UI/RmlBridge/ThemeFonts.h, one file per key). +[Fonts] +Verdana=%WINDIR%\Fonts\verdana.ttf +VerdanaBold=%WINDIR%\Fonts\verdanab.ttf + +[Meta] +DisplayName=Classic (0.97) diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/tokens.ini b/src/bin/Data/Interface/RmlUi/themes/classic/tokens.ini new file mode 100644 index 0000000000..a39f6ffba7 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/tokens.ini @@ -0,0 +1,6 @@ +; Classic (0.97) tokens: only what differs from legacy (ThemeInheritance.h resolves the rest). +; The current client draws its text in Verdana 13 px (Main.dll Font.cpp); theme.ini's [Fonts] +; loads it from the system. Where it is missing RmlUi falls back to the bundled face. +[Tokens] +font-title=Verdana +font-body=Verdana diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/tooltip.rml b/src/bin/Data/Interface/RmlUi/themes/classic/tooltip.rml new file mode 100644 index 0000000000..ea067a98ff --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/tooltip.rml @@ -0,0 +1,40 @@ + + + + Tooltip + + + + + +
+
{{line.text}}
+
+ +
diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/trade.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/trade.rcss new file mode 100644 index 0000000000..b84a13f695 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/trade.rcss @@ -0,0 +1,172 @@ +/* Classic (0.97) trade window (CTrade), from the 0.97 client's 004f1270: Item_Back01 over Item_Back02, the title at the top; + the partner -- name at (20, 45), level at (140, 45), the 8x4 grid at (15, 70), "Zen" and the bar + at (20, 162) / (50, 160), the accept mark (accept_box) at (140, 185); the warning lines from + (20, 185); then mine -- name at (20, 250), the grid at (15, 270), Zen at (20, 362) / (50, 360); + and Zen trade (money_01), OK (accept_box) and Cancel (exit_01), 24x24 at x 26, 97 and 137, + y 390, the second image while pressed. #panel's left/top/scale come from C++. */ + +@spritesheet trade-classic-back1-sheet { src: ../../../Classic/Item_back01.jpg; trade-classic-back1: 0px 0px 190px 256px; } +@spritesheet trade-classic-back2-sheet { src: ../../../Classic/Item_Back02.jpg; trade-classic-back2: 0px 0px 190px 177px; } + +#panel { + position: absolute; + transform-origin: left top; + width: 190px; + height: 433px; + font-family: "token(font-body)"; +} + +.bg-fill, .bg-top, .bg-left, .bg-right, .bg-bottom { position: absolute; pointer-events: none; } +.bg-top { left: 0; top: 0; width: 190px; height: 256px; decorator: image(trade-classic-back1); } +.bg-fill { left: 0; top: 256px; width: 190px; height: 177px; decorator: image(trade-classic-back2); } +.bg-bottom { display: none; } +/* "Zen" beside both bars, on their dark boxes (frame pieces 0.97 does not need). */ +.bg-left, .bg-right { + left: 20px; + width: 22px; + height: 13px; + background-color: rgba(40, 40, 40, 128); + font-size: 11px; + font-weight: bold; + decorator: text("Zen" #ffdc96 center center); +} +.bg-left { top: 162px; } +.bg-right { top: 362px; } + +#title { + position: absolute; + /* 0.97: a 120-wide box at x 35, centred. */ + left: 35px; + top: 12px; + width: calc(120px * var(--root-scale)); + text-align: center; + color: #dcdcdc; + font-weight: bold; + font-size: 1em; + pointer-events: none; +} + +.nick-bg, #divider { display: none; } + +.id-text { position: absolute; color: rgb(210, 230, 255); white-space: nowrap; pointer-events: none; font-weight: bold; } +.id-text-your { left: 20px; top: 45px; } +.id-text-my { left: 20px; top: 250px; font-size: 1em; } + +.guild-name { + position: absolute; + left: 20px; + top: 30px; + color: #dcdcdc; + font-weight: bold; + font-size: 1em; + white-space: nowrap; + pointer-events: none; +} + +.level-text { + position: absolute; + left: 140px; + top: 45px; + font-weight: bold; + font-size: 1em; + white-space: nowrap; + pointer-events: none; +} +.level-text.level-bucket-10 { color: #ff0000; } +.level-text.level-bucket-50 { color: #ff9600; } +.level-text.level-bucket-100 { color: #00c918; } +.level-text.level-bucket-200 { color: #d2e6ff; } +.level-text.level-bucket-300 { color: #ff99ff; } +.level-text.level-bucket-400 { color: #ff9999; } + +@spritesheet trade-classic-money-sheet { src: ../../../Classic/Item_money.jpg; trade-classic-money: 0px 0px 113px 18px; } +.gold-bg { position: absolute; left: 50px; width: 113px; height: 18px; decorator: image(trade-classic-money); pointer-events: none; } +.gold-bg-your { top: 160px; } +.gold-bg-my { top: 360px; } + +.gold-text { + position: absolute; + left: 60px; + text-align: left; + color: #ffdc96; + font-weight: bold; + font-size: 1em; + white-space: nowrap; + pointer-events: none; +} +.gold-text-your { top: 162px; } +.gold-text-my { top: 362px; } +.gold-text.gold-hundred-thousand { color: #00c918; } +.gold-text.gold-million { color: #ff9600; } +.gold-text.gold-ten-million { color: #ff0000; } +#your_gold_text, #my_gold_text { width: auto; } + +@spritesheet trade-classic-accept1-sheet { src: ../../../Classic/Accept_box01.jpg; trade-classic-accept: 0px 0px 24px 24px; } +@spritesheet trade-classic-accept2-sheet { src: ../../../Classic/Accept_box02.jpg; trade-classic-accepted: 0px 0px 24px 24px; } +.checkbox-row { position: absolute; width: 24px; height: 24px; } +.checkbox-box { width: 24px; height: 24px; decorator: image(trade-classic-accept); } +.checkbox-box.checked { decorator: image(trade-classic-accepted); } +.confirm-your { left: 140px; top: 185px; cursor: default; pointer-events: none; } +.confirm-my { left: 97px; top: 390px; cursor: pointer; pointer-events: auto; } +.confirm-my.waiting .checkbox-box { image-color: rgb(255, 0, 0); } + +@spritesheet trade-classic-exit1-sheet { src: ../../../Classic/Exit_01.jpg; trade-classic-exit: 0px 0px 24px 24px; } +@spritesheet trade-classic-exit2-sheet { src: ../../../Classic/Exit_02.jpg; trade-classic-exit-pressed: 0px 0px 24px 24px; } +@spritesheet trade-classic-zen1-sheet { src: ../../../Classic/Money_01.jpg; trade-classic-zen: 0px 0px 24px 24px; } +@spritesheet trade-classic-zen2-sheet { src: ../../../Classic/Money_02.jpg; trade-classic-zen-pressed: 0px 0px 24px 24px; } +.trade-btn { + position: absolute; + top: 390px; + width: 24px; + height: 24px; + cursor: pointer; + pointer-events: auto; +} +.trade-btn-exit { left: 137px; decorator: image(trade-classic-exit); } +.trade-btn-exit:active { decorator: image(trade-classic-exit-pressed); } +.trade-btn-zen { left: 26px; decorator: image(trade-classic-zen); } +.trade-btn-zen:active { decorator: image(trade-classic-zen-pressed); } + +.warning-label { + position: absolute; + left: 20px; + top: 185px; + color: #d20000; + font-weight: bold; + font-size: 1em; + white-space: nowrap; + pointer-events: none; +} +.notice-line { + position: absolute; + left: 20px; + color: rgb(255, 230, 210); + font-weight: bold; + font-size: 1em; + white-space: nowrap; + pointer-events: none; +} +.notice-line1 { left: 45px; top: 185px; } +.notice-line2 { top: 200px; } +.notice-line3 { top: 215px; } + +.item-warning-badge { + position: absolute; + background-color: rgba(210, 0, 0, 255); + color: #ffffff; + font-weight: bold; + font-size: 1em; + text-align: center; + white-space: nowrap; + pointer-events: none; +} + +.native-anchor { position: absolute; pointer-events: none; } +#partner_grid, #partner_grid_counts { left: 15px; top: 70px; width: calc(8 * var(--item-cell)); height: calc(4 * var(--item-cell)); } +#item_grid, #item_grid_counts { left: 15px; top: 270px; width: calc(8 * var(--item-cell)); height: calc(4 * var(--item-cell)); } +#item_view { height: 473px; } + +/* The grid's clicks are native (CInventoryCtrl), so the placed panel takes no pointer events; its + controls take their own. (Legacy's rules, which this copy predated.) */ +#panel.slot-placed { pointer-events: none; } +#panel { font-size: calc(var(--text-px, 12px) / var(--root-scale)); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/united_market_place.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/united_market_place.rcss new file mode 100644 index 0000000000..102f489723 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/united_market_place.rcss @@ -0,0 +1,53 @@ +/* Classic theme for Julia's market warp (CUnitedMarketPlaceWindow). 0.97 has no market; the window + takes the classic NPC entries' parts (event_entry.rcss): the 0.97 inventory frame + (docked_panel_frame.rcss, Item_Back01 over Item_Back02, 0.97's Close), the title in light grey + bold at the top, the description in white, centred every 20 from y 60, and Warp as one 0.97 text + plate (Message_box, 140x35 at x 25 like the Blood Castle's and Devil Square's) tinted + (0.9, 0.8, 0.7) and lit white under the mouse, its label white and bold; while locked the plate is + darkened (0.4, 0.4, 0.5) and its label grey. Coordinates are reference px inside #panel. */ + +@spritesheet market-classic-plate-sheet { src: ../../../Classic/Message_box.jpg; market-classic-plate: 0px 0px 213px 64px; } + +.frame-top { decorator: image(docked-bg-top-b); } +#panel { pointer-events: auto; } + +#title, .market-line, #warp_label { + display: block; + position: absolute; + white-space: nowrap; + text-align: center; + pointer-events: none; +} +#title { left: 15px; top: 12px; font-weight: bold; color: #dcdcdc; } +.market-line { left: 0; color: #ffffff; } + +#warp { + display: block; + position: absolute; + left: 25px; + top: 225px; + width: 140px; + height: 35px; + decorator: image(market-classic-plate fill); + image-color: #e6ccb3; + pointer-events: auto; +} +#warp:hover, #warp:active { image-color: #ffffff; } +#warp.locked, #warp.locked:hover, #warp.locked:active { image-color: #66667f; } +#warp_label { left: 0; color: #ffffff; font-weight: bold; } +#warp.locked #warp_label { color: #808080; } + +/* The description's own rows: every 20 units from y 60. */ +.market-lines { position: static; } +.market-line:nth-child(1) { top: 60px; } +.market-line:nth-child(2) { top: 80px; } +.market-line:nth-child(3) { top: 100px; } +.market-line:nth-child(4) { top: 120px; } +.market-line:nth-child(5) { top: 140px; } +.market-line:nth-child(6) { top: 160px; } +.market-line:nth-child(7) { top: 180px; } + +/* Lengths inside counter-scaled layers: reference px times the panel's --root-scale. */ +#title { width: calc(160px * var(--root-scale)); } +.market-line { width: calc(190px * var(--root-scale)); } +#warp_label { width: calc(140px * var(--root-scale)); } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/window_menu.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/window_menu.rcss new file mode 100644 index 0000000000..2f3ac67577 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/window_menu.rcss @@ -0,0 +1,62 @@ +/* Classic (0.97) theme for CWindowMenu (U). 0.97 has no window menu, so this is legacy's in 0.97's + parts, as the classic quick command menu: the box 0.97 drew its hints and item boxes in (black at + 0.8 inside a 1-unit black frame, 004c2420) and each entry on a 0.97 text plate (Message_box, + 213x64, squashed to the row) lit warm under the mouse as 0.97 lit its plates. The S6 frame + pieces, lines and arrows are not drawn. Reference px relative to the menu's top-left, at the + original's (528, 284) on the HUD board (window_menu.rml). */ + +@spritesheet classic-wmenu-plate-sheet { src: ../../../Classic/Message_box.jpg; classic-wmenu-plate: 0px 0px 213px 64px; } + +#screen { pointer-events: none; } + +#panel { + position: absolute; + left: 528px; + top: 284px; + width: 112px; + height: 146px; + font-family: "token(font-body)"; + pointer-events: auto; +} + +#back { + position: absolute; + left: 0; + top: 0; + width: 112px; + height: 146px; + box-sizing: border-box; + border-width: 1px; + border-color: #000000; + background-color: rgba(0, 0, 0, 204); +} +#frame_up, .frame-middle, #frame_down, .line, .arrow { display: none; } +.frame-middles, .lines { position: static; } + +/* Six plates 96x18 from y 13, every 20, the label centred on each; white, yellow under the mouse + as legacy's. */ +#rows { position: absolute; left: 0; top: 13px; width: 112px; } +.menu-row { + display: block; + position: relative; + width: 96px; + height: 18px; + margin: 0 0 2px 8px; + pointer-events: auto; + cursor: pointer; + decorator: image(classic-wmenu-plate fill); +} +.menu-row:hover { image-color: #ffe3c6; filter: brightness(1.7); } +.menu-label { + display: block; + position: absolute; + left: 0; + top: 1px; + width: calc(96px * var(--root-scale)); + transform-origin: left top; + text-align: center; + white-space: nowrap; + color: #ffffff; + pointer-events: none; +} +.menu-row:hover .menu-label { color: #ffff00; } diff --git a/src/bin/Data/Interface/RmlUi/themes/classic/workspace.rcss b/src/bin/Data/Interface/RmlUi/themes/classic/workspace.rcss new file mode 100644 index 0000000000..9cf45c7593 --- /dev/null +++ b/src/bin/Data/Interface/RmlUi/themes/classic/workspace.rcss @@ -0,0 +1,135 @@ +/* Window placement for the classic theme (a copy of legacy's; only the chat and the system log differ). The game reads where each open slot lands; nothing here is drawn. */ + +body { + width: 100%; + height: 100%; + margin: 0; + visibility: hidden; + pointer-events: none; +} + +#workspace_shell { position: relative; width: 100%; height: 100%; display: flex; flex-direction: column; } +#shell_middle { position: relative; display: flex; flex-direction: row; flex: 1 1 0; min-height: 0; } +#safe_area { position: relative; flex: 1 1 0; min-width: 0; min-height: 0; } +.region.shell-region { position: relative; display: flex; flex: 0 0 auto; } +#shell_header { align-items: flex-start; } +#shell_header .slot[data-window="top_bar"] { margin-left: auto; } +#shell_footer { justify-content: center; } +#shell_left, #shell_right { flex-direction: column; } +.shell-region[data-participation="overlay"] { position: absolute; } +#shell_header[data-participation="overlay"] { top: 0; left: 0; right: 0; } +#shell_footer[data-participation="overlay"] { bottom: 0; left: 0; right: 0; } +#shell_left[data-participation="overlay"] { left: 0; top: 0; bottom: 0; } +#shell_right[data-participation="overlay"] { right: 0; top: 0; bottom: 0; } + +.region { + position: absolute; +} + +/* The original's docked columns: open windows pack from the right edge, sitting on the HUD. */ +.dock-right { + left: 0; + right: 0; + bottom: 0; + display: flex; + flex-direction: row-reverse; + align-items: flex-start; +} + +.slot { + display: none; + flex: 0 0 auto; +} + +.slot.open { + display: block; +} + +/* The original's left-docked warp list, sitting on the HUD. */ +.dock-left { + left: 0; + right: 0; + bottom: 0; + display: flex; + flex-direction: row; + align-items: flex-start; +} + +/* Classic (0.97): the messages at the top-left corner of the screen, with no window (0.97 drew + six lines from y 13), and the input box centred over the bar, 268 wide, at 0.97's y 415-444: + its foot lies on the bar's top edge and is drawn over it (chat_input is raised over the HUD). + The region's bottom is 18 units above the bar, hence -29. */ +.chat-stack { + left: 0; + top: 0; + right: 0; + bottom: 0; +} +.chat-stack .slot[data-window="chat_log"] { position: absolute; left: 0; top: 0; } +.chat-stack .slot[data-window="chat_input"] { position: absolute; left: 50%; bottom: -29dp; margin-left: -134dp; } + +/* The event HUDs: the original's 640x480 frame standing on the HUD, in its units (one unit is + --hud-scale px), its top 429 units above the HUD, each at the original's place in it. Classic: + centred on the area the open windows leave free, as 0.97 centred its event scores and timers on + it (004cb520, 004bc220, 004bf090), so they move aside with the windows. The spectator list's + slot is its bottom-left corner; the list grows upwards. */ +.event-hud { + left: calc((var(--world-left, 0px) + var(--world-right, 100%)) / 2); + margin-left: calc(-320px * var(--hud-scale)); + bottom: 0; + width: calc(640px * var(--hud-scale)); + height: calc(429px * var(--hud-scale)); +} +.event-hud .slot { position: absolute; } +.event-hud .slot[data-window="blood_castle_time"], +.event-hud .slot[data-window="chaos_castle_time"], +.event-hud .slot[data-window="empire_guardian_timer"] { left: calc(513px * var(--hud-scale)); top: calc(348px * var(--hud-scale)); } +/* The guild war / battle soccer score: the 0.97 client's, at the top, 20 left of the centre. */ +.event-hud .slot[data-window="battle_soccer"] { left: calc(300px * var(--hud-scale)); top: 0; } +/* The duel score: the Season 1 client's band at the top centre (duel_window.rcss). */ +.event-hud .slot[data-window="duel"] { left: calc(170px * var(--hud-scale)); top: calc(20px * var(--hud-scale)); } +/* Kanturu: the Season 2 client's count box at (0, 300); its hourglass timer is placed from there + (kanturu_info.rcss). */ +.event-hud .slot[data-window="kanturu_info"] { left: 0; top: calc(300px * var(--hud-scale)); } +/* Doppelganger: the event's own frame, raised clear of the 0.97 HUD's right dragon (its bottom at + y 380). */ +.event-hud .slot[data-window="doppelganger_frame"] { left: calc(413px * var(--hud-scale)); top: calc(293px * var(--hud-scale)); } +.event-hud .slot[data-window="duel_watch_users"] { left: calc(583px * var(--hud-scale)); top: calc(429px * var(--hud-scale)); } + +/* Where a free window (the friend list) first opens: the bottom-right corner above the HUD. */ +.free-bottom-right { + right: 0; + bottom: 0; +} + +/* The original's centred NPC panels: a 640x480 stage in the screen's centre (1dp is one of its + units at the panel scale), each panel centred across it at the original's height. */ +.panel-stage { + left: 50%; + top: 50%; + width: 640dp; + height: 480dp; + margin-left: -320dp; + margin-top: -240dp; + display: flex; + flex-direction: column; + align-items: center; +} +/* Kanturu: the Season 2 client's entry box at y 15. */ +.panel-stage .slot[data-window="kanturu_entry"] { margin-top: 15dp; } +.panel-stage .slot[data-window="cursed_temple_entry"] { margin-top: 80dp; } +.panel-stage .slot[data-window="cursed_temple_result"] { margin-top: 120dp; } +.panel-stage .slot[data-window="in_game_shop"] { margin-top: 0; } + +/* The six-line message area; it never collapses between messages. */ +.system-log-stack { + left: 4dp; + /* Classic: under the chat's six lines at the top-left corner (the chat region starts under the + top bar, so its sixth line ends near 133). */ + top: 136dp; + display: flex; + flex-direction: column; + align-items: flex-start; +} +/* The performance overlays start at the top-left corner, over the HUD's corner widgets. */ +.diagnostics-corner { left: 0; top: 0; } diff --git a/src/bin/Data/Logo/Classic/0account_new.ozt b/src/bin/Data/Logo/Classic/0account_new.ozt new file mode 100644 index 0000000000..889807008f Binary files /dev/null and b/src/bin/Data/Logo/Classic/0account_new.ozt differ diff --git a/src/bin/Data/Logo/Classic/0box.ozj b/src/bin/Data/Logo/Classic/0box.ozj new file mode 100644 index 0000000000..7e083b833d Binary files /dev/null and b/src/bin/Data/Logo/Classic/0box.ozj differ diff --git a/src/bin/Data/Logo/Classic/0on_botton.ozj b/src/bin/Data/Logo/Classic/0on_botton.ozj new file mode 100644 index 0000000000..ca0398d9e0 Binary files /dev/null and b/src/bin/Data/Logo/Classic/0on_botton.ozj differ diff --git a/src/bin/Data/Logo/Classic/0on_botton2.ozj b/src/bin/Data/Logo/Classic/0on_botton2.ozj new file mode 100644 index 0000000000..66d155add9 Binary files /dev/null and b/src/bin/Data/Logo/Classic/0on_botton2.ozj differ diff --git a/src/bin/Data/Logo/Classic/Delete01.ozt b/src/bin/Data/Logo/Classic/Delete01.ozt new file mode 100644 index 0000000000..89e644a140 Binary files /dev/null and b/src/bin/Data/Logo/Classic/Delete01.ozt differ diff --git a/src/bin/Data/Logo/Classic/Delete02.ozj b/src/bin/Data/Logo/Classic/Delete02.ozj new file mode 100644 index 0000000000..ef887248d2 Binary files /dev/null and b/src/bin/Data/Logo/Classic/Delete02.ozj differ diff --git a/src/bin/Data/Logo/Classic/Interface01.ozt b/src/bin/Data/Logo/Classic/Interface01.ozt new file mode 100644 index 0000000000..eec9abc93b Binary files /dev/null and b/src/bin/Data/Logo/Classic/Interface01.ozt differ diff --git a/src/bin/Data/Logo/Classic/Interface02.ozt b/src/bin/Data/Logo/Classic/Interface02.ozt new file mode 100644 index 0000000000..0425c15d76 Binary files /dev/null and b/src/bin/Data/Logo/Classic/Interface02.ozt differ diff --git a/src/bin/Data/Logo/Classic/Interface03.ozt b/src/bin/Data/Logo/Classic/Interface03.ozt new file mode 100644 index 0000000000..db5aa45850 Binary files /dev/null and b/src/bin/Data/Logo/Classic/Interface03.ozt differ diff --git a/src/bin/Data/Logo/Classic/Interface04.ozt b/src/bin/Data/Logo/Classic/Interface04.ozt new file mode 100644 index 0000000000..7efd81f9bd Binary files /dev/null and b/src/bin/Data/Logo/Classic/Interface04.ozt differ diff --git a/src/bin/Data/Logo/Classic/New_character001.ozj b/src/bin/Data/Logo/Classic/New_character001.ozj new file mode 100644 index 0000000000..8a6ad6a7bb Binary files /dev/null and b/src/bin/Data/Logo/Classic/New_character001.ozj differ diff --git a/src/bin/Data/Logo/Classic/New_character002.ozj b/src/bin/Data/Logo/Classic/New_character002.ozj new file mode 100644 index 0000000000..6849a5bca7 Binary files /dev/null and b/src/bin/Data/Logo/Classic/New_character002.ozj differ diff --git a/src/bin/Data/Logo/Classic/New_character003.ozj b/src/bin/Data/Logo/Classic/New_character003.ozj new file mode 100644 index 0000000000..025b744c0f Binary files /dev/null and b/src/bin/Data/Logo/Classic/New_character003.ozj differ diff --git a/src/bin/Data/Logo/Classic/New_character004.ozj b/src/bin/Data/Logo/Classic/New_character004.ozj new file mode 100644 index 0000000000..9ccdd18006 Binary files /dev/null and b/src/bin/Data/Logo/Classic/New_character004.ozj differ diff --git a/src/bin/Data/Logo/Classic/New_character01.ozt b/src/bin/Data/Logo/Classic/New_character01.ozt new file mode 100644 index 0000000000..b63d5d1f94 Binary files /dev/null and b/src/bin/Data/Logo/Classic/New_character01.ozt differ diff --git a/src/bin/Data/Logo/Classic/New_character02.ozt b/src/bin/Data/Logo/Classic/New_character02.ozt new file mode 100644 index 0000000000..6deccabcf1 Binary files /dev/null and b/src/bin/Data/Logo/Classic/New_character02.ozt differ diff --git a/src/bin/Data/Logo/Classic/New_character201.ozt b/src/bin/Data/Logo/Classic/New_character201.ozt new file mode 100644 index 0000000000..6bc385cfce Binary files /dev/null and b/src/bin/Data/Logo/Classic/New_character201.ozt differ diff --git a/src/bin/Data/Logo/Classic/New_character202.ozj b/src/bin/Data/Logo/Classic/New_character202.ozj new file mode 100644 index 0000000000..5686d24e13 Binary files /dev/null and b/src/bin/Data/Logo/Classic/New_character202.ozj differ diff --git a/src/bin/Data/Logo/Classic/New_character_cancel.ozj b/src/bin/Data/Logo/Classic/New_character_cancel.ozj new file mode 100644 index 0000000000..ab3a3ba584 Binary files /dev/null and b/src/bin/Data/Logo/Classic/New_character_cancel.ozj differ diff --git a/src/bin/Data/Logo/Classic/New_character_ok.ozj b/src/bin/Data/Logo/Classic/New_character_ok.ozj new file mode 100644 index 0000000000..a768deca6b Binary files /dev/null and b/src/bin/Data/Logo/Classic/New_character_ok.ozj differ diff --git a/src/bin/Data/Logo/Classic/Ok01.ozt b/src/bin/Data/Logo/Classic/Ok01.ozt new file mode 100644 index 0000000000..87a594988c Binary files /dev/null and b/src/bin/Data/Logo/Classic/Ok01.ozt differ diff --git a/src/bin/Data/Logo/Classic/Ok02.ozj b/src/bin/Data/Logo/Classic/Ok02.ozj new file mode 100644 index 0000000000..72206d9716 Binary files /dev/null and b/src/bin/Data/Logo/Classic/Ok02.ozj differ diff --git a/src/source/Character/CharMakeWin.cpp b/src/source/Character/CharMakeWin.cpp index b848abacf5..61fb75e573 100644 --- a/src/source/Character/CharMakeWin.cpp +++ b/src/source/Character/CharMakeWin.cpp @@ -20,6 +20,7 @@ #include "App/Platform/Windows/Local.h" #include "CharacterManager.h" +#include "ClassStep.h" #include #include @@ -194,6 +195,8 @@ void CCharMakeWin::BindRmlModel(Rml::DataModelConstructor& c, CharMakeRmlModel& c.RegisterArray>(); c.Bind("jobs", &model.jobs); + c.Bind("job_previous", &model.jobPrevious); + c.Bind("job_next", &model.jobNext); c.Bind("dark_lord_extra", &model.darkLordExtra); c.Bind("stat_label0", &model.statLabel0); c.Bind("stat_label1", &model.statLabel1); @@ -455,6 +458,7 @@ void CCharMakeWin::SyncRmlModel() auto& model = m_RmlView.GetModel(); auto& jobs = model.jobs; bool jobsDirty = false; + std::array enabled{}; for (int classIndex = 0; classIndex < MAX_CLASS; ++classIndex) { JobButtonEntry& entry = jobs[classIndex]; @@ -462,6 +466,7 @@ void CCharMakeWin::SyncRmlModel() const bool disabled = !m_aJobState[classIndex].enabled; if (entry.checked != checked) { entry.checked = checked; jobsDirty = true; } if (entry.disabled != disabled) { entry.disabled = disabled; jobsDirty = true; } + enabled[classIndex] = !disabled; const std::string label = StringUtils::WideToNarrow(I18N::Game::Lookup(kClassButtonTextIds[classIndex])); if (entry.label != label) { entry.label = label; jobsDirty = true; } @@ -469,6 +474,19 @@ void CCharMakeWin::SyncRmlModel() if (jobsDirty) m_RmlView.MarkDirty("jobs"); + const int jobPrevious = UI::CharacterCreation::StepToEnabledClass(enabled, m_nSelJob, -1); + const int jobNext = UI::CharacterCreation::StepToEnabledClass(enabled, m_nSelJob, +1); + if (model.jobPrevious != jobPrevious) + { + model.jobPrevious = jobPrevious; + m_RmlView.MarkDirty("job_previous"); + } + if (model.jobNext != jobNext) + { + model.jobNext = jobNext; + m_RmlView.MarkDirty("job_next"); + } + const bool isDarkLord = (m_nSelJob == CLASS_DARK_LORD); if (model.darkLordExtra != isDarkLord) { diff --git a/src/source/Character/CharMakeWin.h b/src/source/Character/CharMakeWin.h index 224c081c3c..36102793f2 100644 --- a/src/source/Character/CharMakeWin.h +++ b/src/source/Character/CharMakeWin.h @@ -126,6 +126,10 @@ class CCharMakeWin : public mu::ui::window::CObject struct CharMakeRmlModel { std::vector jobs; + // The enabled classes before and after the selected one (-1: none), for a theme that steps + // through the classes with arrows (UI::CharacterCreation::StepToEnabledClass()). + int jobPrevious = -1; + int jobNext = -1; bool darkLordExtra = false; Rml::String statLabel0, statLabel1, statLabel2, statLabel3, statLabel4; diff --git a/src/source/Character/ClassStep.h b/src/source/Character/ClassStep.h new file mode 100644 index 0000000000..def87d0221 --- /dev/null +++ b/src/source/Character/ClassStep.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace UI::CharacterCreation +{ +// For a creation window that steps through the classes with arrows instead of a button per class: +// the nearest enabled class from `current` in `step`'s direction (-1 / +1), or -1 when there is none +// that way. `enabled` is in CLASS_* order. +constexpr int StepToEnabledClass(std::span enabled, int current, int step) +{ + for (int index = current + step; index >= 0 && index < static_cast(enabled.size()); index += step) + { + if (enabled[index]) + return index; + } + return -1; +} +} // namespace UI::CharacterCreation diff --git a/src/source/UI/HUD/MainFrameExtras.cpp b/src/source/UI/HUD/MainFrameExtras.cpp new file mode 100644 index 0000000000..de2c5c1159 --- /dev/null +++ b/src/source/UI/HUD/MainFrameExtras.cpp @@ -0,0 +1,132 @@ +#include "stdafx.h" +#include "MainFrameExtras.h" + +#include "Audio/DSPlaySound.h" +#include "Core/Utilities/StringUtils.h" +#include "Engine/Object/ZzzCharacter.h" +#include "I18N/All.h" +#include "UI/Core/WindowSystem.h" +#include "Engine/Object/ZzzInventory.h" +#include "World/MapInfra/MapManager.h" + +#include + +#include +#include + +namespace UI::Hud::MainFrameExtras +{ +namespace +{ +// A bound text and the source it was made from, so a frame whose source has not changed costs a +// comparison instead of a conversion. +struct WideText +{ + std::wstring source; + Rml::String text; +}; + +struct Model +{ + Rml::String coordX; + Rml::String coordY; + bool partyOpen = false; + bool guildOpen = false; + bool commandOpen = false; + WideText partyTooltip; + WideText guildTooltip; + WideText commandTooltip; + int heroX = -1; + int heroY = -1; +}; + +Model s_model; +Rml::DataModelHandle s_handle; + +void Toggle(mu::ui::window::INTERFACE_LIST window) +{ + g_pNewUISystem->Toggle(window); + PlayBuffer(SOUND_CLICK01); +} + +// The command window, under the D key's rules (HotKey.cpp): nothing in Chaos Castle, a notice in a +// battle zone. +void ToggleCommandWindow() +{ + if (gMapManager.InChaosCastle()) + return; + if (::IsStrifeMap(gMapManager.WorldActive)) + { + if (g_pSystemLogBox->CheckChatRedundancy(I18N::Game::TheCommandWindowCannotBeActivatedInBattleZone) == FALSE) + g_pSystemLogBox->AddText(I18N::Game::TheCommandWindowCannotBeActivatedInBattleZone, mu::ui::window::TYPE_SYSTEM_MESSAGE); + return; + } + Toggle(mu::ui::window::INTERFACE_COMMAND); +} + +void SyncText(Rml::String& field, const char* name, Rml::String value) +{ + if (field == value) + return; + field = std::move(value); + s_handle.DirtyVariable(name); +} + +void SyncWide(WideText& field, const char* name, const wchar_t* source) +{ + if (source == nullptr || std::wcscmp(field.source.c_str(), source) == 0) + return; + field.source = source; + field.text = StringUtils::WideToNarrow(source); + s_handle.DirtyVariable(name); +} + +void SyncBool(bool& field, const char* name, bool value) +{ + if (field == value) + return; + field = value; + s_handle.DirtyVariable(name); +} +} // namespace + +void BindModel(Rml::DataModelConstructor& constructor) +{ + constructor.Bind("coord_x", &s_model.coordX); + constructor.Bind("coord_y", &s_model.coordY); + constructor.Bind("party_open", &s_model.partyOpen); + constructor.Bind("guild_open", &s_model.guildOpen); + constructor.Bind("command_open", &s_model.commandOpen); + constructor.Bind("party_tooltip", &s_model.partyTooltip.text); + constructor.Bind("guild_tooltip", &s_model.guildTooltip.text); + constructor.Bind("command_tooltip", &s_model.commandTooltip.text); + constructor.BindEventCallback("mainframe_command_click", + [](Rml::DataModelHandle, Rml::Event&, const Rml::VariantList&) { ToggleCommandWindow(); }); + constructor.BindEventCallback("mainframe_party_click", + [](Rml::DataModelHandle, Rml::Event&, const Rml::VariantList&) { Toggle(mu::ui::window::INTERFACE_PARTY); }); + constructor.BindEventCallback("mainframe_guild_click", + [](Rml::DataModelHandle, Rml::Event&, const Rml::VariantList&) { Toggle(mu::ui::window::INTERFACE_GUILDINFO); }); + s_handle = constructor.GetModelHandle(); +} + +void SyncModel() +{ + if (!s_handle) + return; + + // The coordinates are formatted only when the hero moves to another tile. + if (Hero != nullptr && (Hero->PositionX != s_model.heroX || Hero->PositionY != s_model.heroY)) + { + s_model.heroX = Hero->PositionX; + s_model.heroY = Hero->PositionY; + SyncText(s_model.coordX, "coord_x", std::to_string(s_model.heroX)); + SyncText(s_model.coordY, "coord_y", std::to_string(s_model.heroY)); + } + SyncBool(s_model.partyOpen, "party_open", g_pNewUISystem->IsVisible(mu::ui::window::INTERFACE_PARTY)); + SyncBool(s_model.guildOpen, "guild_open", g_pNewUISystem->IsVisible(mu::ui::window::INTERFACE_GUILDINFO)); + SyncBool(s_model.commandOpen, "command_open", g_pNewUISystem->IsVisible(mu::ui::window::INTERFACE_COMMAND)); + SyncWide(s_model.partyTooltip, "party_tooltip", I18N::Game::PartyP); + SyncWide(s_model.guildTooltip, "guild_tooltip", I18N::Game::GuildG); + SyncWide(s_model.commandTooltip, "command_tooltip", I18N::Game::CommandD); +} +} // namespace UI::Hud::MainFrameExtras diff --git a/src/source/UI/HUD/MainFrameExtras.h b/src/source/UI/HUD/MainFrameExtras.h new file mode 100644 index 0000000000..b30957f48c --- /dev/null +++ b/src/source/UI/HUD/MainFrameExtras.h @@ -0,0 +1,19 @@ +#pragma once + +namespace Rml +{ +class DataModelConstructor; +} + +// What the classic HUD shows and the S6 one does not, added to CMainFrameWindow's data model +// ("main_frame"): the Party and Guild buttons on the bar (0.97) and the command window button +// (Season 1 / 2) (open state, click, hint), and the hero's coordinates in its left box. Only the +// classic theme's main_frame.rml uses them; a theme that does not pays nothing. +namespace UI::Hud::MainFrameExtras +{ +// Adds the bindings, while CMainFrameWindow builds its model. +void BindModel(Rml::DataModelConstructor& constructor); + +// Per-frame update, from CMainFrameWindow's own model sync. +void SyncModel(); +} // namespace UI::Hud::MainFrameExtras diff --git a/src/source/UI/HUD/MainFrameWindow.cpp b/src/source/UI/HUD/MainFrameWindow.cpp index 24abada43a..5e68ae1d1d 100644 --- a/src/source/UI/HUD/MainFrameWindow.cpp +++ b/src/source/UI/HUD/MainFrameWindow.cpp @@ -38,6 +38,7 @@ #include "UI/RmlBridge/RmlDocumentVisibility.h" #include "UI/RmlBridge/RmlTheme.h" #include "UI/RmlBridge/RmlWorkspaceParticipant.h" +#include "UI/HUD/MainFrameExtras.h" #include "UI/Placement/WindowPlacement.h" #include "UI/RmlBridge/RmlTooltip.h" #include "Core/Utilities/StringUtils.h" @@ -278,6 +279,7 @@ void mu::ui::window::CMainFrameWindow::BindRmlModel(Rml::DataModelConstructor& c [this](Rml::DataModelHandle, Rml::Event&, const Rml::VariantList&) { RmlClickFriend(); }); c.BindEventCallback("mainframe_window_click", [this](Rml::DataModelHandle, Rml::Event&, const Rml::VariantList&) { RmlClickWindow(); }); + UI::Hud::MainFrameExtras::BindModel(c); } void mu::ui::window::CMainFrameWindow::OnRmlReloaded() @@ -487,6 +489,7 @@ void mu::ui::window::CMainFrameWindow::SyncRmlModel() }; m_ItemHotKey.SyncSlotIcons(m_RmlView.Document()); + UI::Hud::MainFrameExtras::SyncModel(); // HP/MP -- legacy RenderLifeMana(). fLife/fMana there are the EMPTY fraction; store filled. DWORD wLifeMax, wLife, wManaMax, wMana; diff --git a/src/source/UI/Inventory/ItemEnduranceInfo.cpp b/src/source/UI/Inventory/ItemEnduranceInfo.cpp index 3551259d74..eaf976e3d4 100644 --- a/src/source/UI/Inventory/ItemEnduranceInfo.cpp +++ b/src/source/UI/Inventory/ItemEnduranceInfo.cpp @@ -17,6 +17,7 @@ #include "UI/RmlBridge/RmlDocumentVisibility.h" #include "UI/RmlBridge/RmlTheme.h" #include "Render/Text/CUIRenderText.h" +#include "Engine/Object/ZzzInventory.h" #include @@ -342,6 +343,7 @@ void mu::ui::window::CItemEnduranceInfo::BindRmlModel(Rml::DataModelConstructor& c.Bind("bold_text_px", &model.boldTextPx); c.Bind("bold_line_height_px", &model.boldLineHeightPx); c.Bind("arrows", &model.arrows); + c.Bind("in_party", &model.inParty); auto pet = c.RegisterStruct(); pet.RegisterMember("bar_width", &PetFrameEntry::barWidth); @@ -401,6 +403,7 @@ void mu::ui::window::CItemEnduranceInfo::SyncLeftColumn() arrows = StringUtils::WideToNarrow(szText); } SyncItemEnduranceField(m_RmlView.Binder(), &ItemEnduranceRmlModel::arrows, "arrows", std::move(arrows)); + SyncItemEnduranceField(m_RmlView.Binder(), &ItemEnduranceRmlModel::inParty, "in_party", PartyNumber > 0); std::vector pets; const auto addFrame = [&](const wchar_t* name, int life, int maxLife) diff --git a/src/source/UI/Inventory/ItemEnduranceRmlModel.h b/src/source/UI/Inventory/ItemEnduranceRmlModel.h index e5ad056bb6..fc9426fbd8 100644 --- a/src/source/UI/Inventory/ItemEnduranceRmlModel.h +++ b/src/source/UI/Inventory/ItemEnduranceRmlModel.h @@ -47,6 +47,9 @@ struct ItemEnduranceRmlModel // The elf's arrow / bolt count line; empty when none is shown. Rml::String arrows; + // Whether the hero is in a party, so a theme can keep the column clear of the party list. + bool inParty = false; + std::vector pets; std::vector icons; diff --git a/src/source/UI/RmlBridge/RmlTheme.cpp b/src/source/UI/RmlBridge/RmlTheme.cpp index 7004059263..b1aba982a7 100644 --- a/src/source/UI/RmlBridge/RmlTheme.cpp +++ b/src/source/UI/RmlBridge/RmlTheme.cpp @@ -275,12 +275,38 @@ namespace UI::RmlBridge return doc; } + std::optional ThemedStackingDepth(const ThemeInheritance& theme, std::string_view documentName) + { + const auto setting = theme.GetSetting("Stacking", std::string(documentName)); + if (!setting) + return StackingDepthForDocument(documentName); + + char* end = nullptr; + const float depth = std::strtof(setting->value.c_str(), &end); + if (end == setting->value.c_str() || *end != '\0') + { + g_ErrorReport.Write(L"> [RmlTheme] Bad [Stacking] depth '%hs' for '%hs'.\r\n", setting->value.c_str(), + std::string(documentName).c_str()); + return StackingDepthForDocument(documentName); + } + return depth; + } + + namespace + { + std::optional ActiveThemeStackingDepth(const std::string& documentName) + { + const ThemeInheritance theme(std::filesystem::path("Data/Interface/RmlUi/themes") / GetActiveThemeName()); + return ThemedStackingDepth(theme, documentName); + } + } // namespace + void ApplyStackingDepth(Rml::ElementDocument* document, const std::string& documentName) { if (document == nullptr) return; - const std::optional depth = StackingDepthForDocument(documentName); + const std::optional depth = ActiveThemeStackingDepth(documentName); if (!depth) { g_ErrorReport.Write(L"> [RmlTheme] No stacking depth for '%hs'.\r\n", documentName.c_str()); @@ -295,7 +321,7 @@ namespace UI::RmlBridge return; if (SceneForDocument(documentName) == DocumentScene::Main) document->SetAttribute(MainSceneDocumentAttribute, true); - const std::optional mainDepth = StackingDepthForDocument(documentName); + const std::optional mainDepth = ActiveThemeStackingDepth(documentName); if (const std::optional otherDepth = StackingDepthOutsideMainScene(documentName); otherDepth && mainDepth) { document->SetAttribute(MainSceneDepthAttribute, *mainDepth); diff --git a/src/source/UI/RmlBridge/RmlTheme.h b/src/source/UI/RmlBridge/RmlTheme.h index 45132928d7..2958bd9d88 100644 --- a/src/source/UI/RmlBridge/RmlTheme.h +++ b/src/source/UI/RmlBridge/RmlTheme.h @@ -1,7 +1,9 @@ #pragma once #include +#include #include +#include #include namespace Rml @@ -104,6 +106,12 @@ namespace UI::RmlBridge // document loaded some other way. void ApplyStackingDepth(Rml::ElementDocument* document, const std::string& documentName); + class ThemeInheritance; + // `documentName`'s depth under `theme`: the theme's own, when its theme.ini lists the document + // under [Stacking] (inherited like any setting; e.g. `chat_input.rml=10.65` for an input box + // drawn over the HUD), else the stacking table's. None when neither knows the document. + std::optional ThemedStackingDepth(const ThemeInheritance& theme, std::string_view documentName); + // Scene gate (RmlStackingOrder.h, DocumentScene). The original drew CNewUIManager's windows // only while the main scene ran; the main-scene windows sync their documents from their own // Update(), which stops with the main scene, so a document open at logout kept rendering over diff --git a/tests/ui/CMakeLists.txt b/tests/ui/CMakeLists.txt index eaa25adc70..e0fae59d2b 100644 --- a/tests/ui/CMakeLists.txt +++ b/tests/ui/CMakeLists.txt @@ -124,6 +124,11 @@ target_compile_definitions(rml_stacking_order_tests PRIVATE MU_CLIENT_SOURCE_DIR="${CMAKE_SOURCE_DIR}/src/source" ) +mu_add_test( + NAME character_class_step_tests + SOURCES test_character_class_step.cpp +) + mu_add_test( NAME party_list_layout_tests SOURCES diff --git a/tests/ui/test_character_class_step.cpp b/tests/ui/test_character_class_step.cpp new file mode 100644 index 0000000000..6ccab95bec --- /dev/null +++ b/tests/ui/test_character_class_step.cpp @@ -0,0 +1,35 @@ +#include + +#include "Character/ClassStep.h" + +#include + +using UI::CharacterCreation::StepToEnabledClass; + +namespace +{ +// DW, DK, Elf, MG, DL, Summoner, RF, with MG and Summoner locked. +constexpr std::array Enabled{true, true, true, false, true, false, true}; +} // namespace + +TEST_CASE("class arrows step over locked classes [ui][char-make]") +{ + CHECK(StepToEnabledClass(Enabled, 2, +1) == 4); + CHECK(StepToEnabledClass(Enabled, 4, -1) == 2); + CHECK(StepToEnabledClass(Enabled, 4, +1) == 6); + CHECK(StepToEnabledClass(Enabled, 0, -1) == -1); + CHECK(StepToEnabledClass(Enabled, 6, +1) == -1); +} + +TEST_CASE("class arrows reach every enabled class, whatever the theme shows [ui][char-make]") +{ + int reached = 0; + for (int index = 0; index >= 0; index = StepToEnabledClass(Enabled, index, +1)) + ++reached; + CHECK(reached == 5); + + reached = 0; + for (int index = 6; index >= 0; index = StepToEnabledClass(Enabled, index, -1)) + ++reached; + CHECK(reached == 5); +} diff --git a/tests/ui/test_theme_inheritance.cpp b/tests/ui/test_theme_inheritance.cpp index 94943594c2..c6f8089438 100644 --- a/tests/ui/test_theme_inheritance.cpp +++ b/tests/ui/test_theme_inheritance.cpp @@ -1,12 +1,16 @@ #include #include "stdafx.h" #include "UI/RmlBridge/ThemeInheritance.h" +#include "UI/RmlBridge/RmlStackingOrder.h" +#include "UI/RmlBridge/RmlTheme.h" #include #include using UI::RmlBridge::ThemeInheritance; using UI::RmlBridge::ResolveThemeResource; +using UI::RmlBridge::StackingDepthForDocument; +using UI::RmlBridge::ThemedStackingDepth; namespace { @@ -83,3 +87,33 @@ TEST_CASE("inherited images resolve container files but keep logical extensions CHECK(ResolveThemeResource(virtualImage.generic_string(), true) == virtualImage.generic_string()); CHECK(ResolveThemeResource("Data/Interface/ordinary.tga", true) == "Data/Interface/ordinary.tga"); } + +TEST_CASE("a theme restacks documents through [Stacking], inherited like any setting [ui][rml-theme]") +{ + ThemeFiles files; + files.Write("base/theme.ini", "[Stacking]\nchat_input.rml=10.65\nchat_log.rml=over\n"); + files.Write("child/theme.ini", "[Theme]\nBase=base\n"); + const ThemeInheritance theme(files.root / "child"); + REQUIRE(theme.IsValid()); + const auto input = ThemedStackingDepth(theme, "chat_input.rml"); + REQUIRE(input); + CHECK(*input == doctest::Approx(10.65f)); + // Not listed, or not a number: the stacking table's depth. + CHECK(ThemedStackingDepth(theme, "main_frame.rml") == StackingDepthForDocument("main_frame.rml")); + CHECK(ThemedStackingDepth(theme, "chat_log.rml") == StackingDepthForDocument("chat_log.rml")); + CHECK_FALSE(ThemedStackingDepth(theme, "no_such_document.rml")); +} + +TEST_CASE("the classic theme stacks its chat input over the HUD and under the tooltips [ui][rml-theme]") +{ + const ThemeInheritance classic(std::filesystem::path(MU_RMLUI_DIR) / "themes/classic"); + REQUIRE(classic.IsValid()); + const auto input = ThemedStackingDepth(classic, "chat_input.rml"); + REQUIRE(input); + CHECK(*input > *StackingDepthForDocument("main_frame.rml")); + CHECK(*input < *StackingDepthForDocument("tooltip.rml")); + + const ThemeInheritance legacy(std::filesystem::path(MU_RMLUI_DIR) / "themes/legacy"); + REQUIRE(legacy.IsValid()); + CHECK(ThemedStackingDepth(legacy, "chat_input.rml") == StackingDepthForDocument("chat_input.rml")); +} diff --git a/tools/classic_theme/make_classic_derived_textures.py b/tools/classic_theme/make_classic_derived_textures.py new file mode 100644 index 0000000000..618f4c4799 --- /dev/null +++ b/tools/classic_theme/make_classic_derived_textures.py @@ -0,0 +1,132 @@ +"""Builds the classic theme's derived textures from the original 0.97 ones. + +Where 0.97 tiles or stretches a texture over a box of known size, the +theme ships the result instead, drawn unscaled: + + Nis_vframe_tall.ozj nis_vframe (5x40) stacked 12 times: the chat window's sides. + Message_box2_268.ozj Message_box2 (213x5) stretched to 268: the chat window's top edge. + Message_box2_230.ozj the same stretched to 230: the in-game message box's edges. + Message_box1_60x5.ozj Message_box1 (213x40) stretched to 60 and stacked 5 times: the Season 2 + Chaos Goblin menu's stone (213x300). + Message_box1_40x6.ozj Message_box1 (213x40) stacked 6 times, unscaled: the Season 2 trainer's + and Lahap's stones (213x200 and 213x240, cut from it). + Message_box1_440x300.ozj Message_box1 widened to 440 for the settings window: its 5-texel sides + kept at their width, the stone between them stretched in proportion, in + rows down to 300. + Message_box2_440.ozj Message_box2 widened to 440 the same way: the settings window's edges. + s1/DuelWindow_add.ozt Season 1's duel crest (a JPEG on black), which Season 1 drew additively: + as a TGA whose alpha is each texel's brightest channel and colour that + channel scaled back up, so plain alpha blending lands close to the + additive draw and the black square disappears. + Progress_add.ozt 0.97's progress fill (an orange line on black), which Season 1's message + box drew additively over Progress_back: the same treatment. + +Usage: python tools/classic_theme/make_classic_derived_textures.py +""" +import io +import pathlib + +from PIL import Image + +TEXTURES = pathlib.Path(__file__).resolve().parents[2] / "src/bin/Data/Interface/Classic" +# An OZJ is a 24-byte prefix followed by the JPEG. +OZJ_PREFIX = 24 + + +def read_ozj(name): + raw = (TEXTURES / name).read_bytes() + return raw[:OZJ_PREFIX], Image.open(io.BytesIO(raw[OZJ_PREFIX:])).convert("RGB") + + +def write_ozj(name, prefix, image): + out = io.BytesIO() + image.save(out, "JPEG", quality=95, subsampling=0) + (TEXTURES / name).write_bytes(prefix + out.getvalue()) + print(f"{name}: {image.width}x{image.height}") + + +# An OZT is a 4-byte prefix followed by an uncompressed TGA. +OZT_PREFIX = bytes([0, 0, 2, 0]) + + +def write_ozt_rgba(name, image): + header = (bytes([0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + image.width.to_bytes(2, "little") + + image.height.to_bytes(2, "little") + bytes([32, 8])) + pixels = bytearray() + for y in range(image.height - 1, -1, -1): # bottom-up, as the originals + for x in range(image.width): + r, g, b, a = image.getpixel((x, y)) + pixels += bytes([b, g, r, a]) + (TEXTURES / name).write_bytes(OZT_PREFIX + header + bytes(pixels)) + print(f"{name}: {image.width}x{image.height}") + + +def additive_to_alpha(image): + out = Image.new("RGBA", image.size) + for y in range(image.height): + for x in range(image.width): + r, g, b = image.getpixel((x, y)) + a = max(r, g, b) + if a == 0: + out.putpixel((x, y), (0, 0, 0, 0)) + else: + out.putpixel((x, y), (min(255, r * 255 // a), min(255, g * 255 // a), min(255, b * 255 // a), a)) + return out + + +def widen_box_part(part, width, height): + """Widens a 0.97 box part (213 wide, 5-texel sides) to width without widening its sides: the + sides keep their width and the middle stretches, both scaled in height by the middle's factor, + and the result stacked in rows down to height.""" + side = 5 + middle = part.crop((side, 0, part.width - side, part.height)) + row_height = round(part.height * (width - 2 * side) / middle.width) + row = Image.new("RGB", (width, row_height)) + row.paste(part.crop((0, 0, side, part.height)).resize((side, row_height), Image.BILINEAR), (0, 0)) + row.paste(middle.resize((width - 2 * side, row_height), Image.BILINEAR), (side, 0)) + row.paste(part.crop((part.width - side, 0, part.width, part.height)).resize((side, row_height), Image.BILINEAR), + (width - side, 0)) + if height == part.height: + return row.resize((width, height), Image.BILINEAR) + out = Image.new("RGB", (width, height)) + for y in range(0, height, row_height): + out.paste(row, (0, y)) + return out + + +def main(): + prefix, side = read_ozj("Nis_vframe.ozj") + tall = Image.new("RGB", (side.width, side.height * 12)) + for i in range(12): + tall.paste(side, (0, i * side.height)) + write_ozj("Nis_vframe_tall.ozj", prefix, tall) + + prefix, top = read_ozj("Message_box2.ozj") + for width in (268, 230): + write_ozj(f"Message_box2_{width}.ozj", prefix, top.resize((width, top.height), Image.BILINEAR)) + + prefix, stone = read_ozj("Message_box1.ozj") + strip = stone.resize((stone.width, 60), Image.BILINEAR) + stack = Image.new("RGB", (strip.width, strip.height * 5)) + for i in range(5): + stack.paste(strip, (0, i * strip.height)) + write_ozj("Message_box1_60x5.ozj", prefix, stack) + + rows = Image.new("RGB", (stone.width, stone.height * 6)) + for i in range(6): + rows.paste(stone, (0, i * stone.height)) + write_ozj("Message_box1_40x6.ozj", prefix, rows) + + write_ozj("Message_box1_440x300.ozj", prefix, widen_box_part(stone, 440, 300)) + prefix, edge = read_ozj("Message_box2.ozj") + write_ozj("Message_box2_440.ozj", prefix, widen_box_part(edge, 440, edge.height)) + + _, crest = read_ozj("s1/DuelWindow.OZJ") + write_ozt_rgba("s1/DuelWindow_add.ozt", additive_to_alpha(crest)) + + _, fill = read_ozj("Progress.ozj") + write_ozt_rgba("Progress_add.ozt", additive_to_alpha(fill)) + + +if __name__ == "__main__": + main() diff --git a/tools/classic_theme/oz_texture_sizes.py b/tools/classic_theme/oz_texture_sizes.py new file mode 100644 index 0000000000..f91275ce46 --- /dev/null +++ b/tools/classic_theme/oz_texture_sizes.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +"""List the real pixel size of MU's .OZJ/.OZT textures. + +The engine pads every texture to a power of two when it loads it, so a theme that uses an image +whose size is not a power of two needs an @spritesheet with the real size (see +docs/rmlui-ui-system/theming-and-modding.md). This prints that size for every texture in a folder. + +.OZJ is a JPEG behind a 24-byte header; .OZT is a TGA behind a 4-byte header. + +Usage: oz_texture_sizes.py [--recursive] +Output: tab-separated path format width height power_of_two +""" +import argparse +import pathlib +import struct +import sys + + +def jpeg_size(data: bytes): + i = 2 # skip SOI + while i + 9 < len(data): + if data[i] != 0xFF: + i += 1 + continue + marker = data[i + 1] + if marker in (0xD8, 0x01) or 0xD0 <= marker <= 0xD7: + i += 2 + continue + length = struct.unpack(">H", data[i + 2:i + 4])[0] + if 0xC0 <= marker <= 0xCF and marker not in (0xC4, 0xC8, 0xCC): + height, width = struct.unpack(">HH", data[i + 5:i + 9]) + return width, height + i += 2 + length + return None + + +def texture_size(path: pathlib.Path): + data = path.read_bytes() + suffix = path.suffix.lower() + if suffix == ".ozj": + start = data.find(b"\xff\xd8", 24) + return ("ozj", jpeg_size(data[start:])) if start >= 0 else ("ozj", None) + if suffix == ".ozt": + if len(data) < 4 + 18: + return "ozt", None + width, height = struct.unpack(" bool: + return value > 0 and value & (value - 1) == 0 + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("folder", type=pathlib.Path) + parser.add_argument("--recursive", action="store_true") + args = parser.parse_args() + + files = args.folder.rglob("*") if args.recursive else args.folder.iterdir() + print("path\tformat\twidth\theight\tpower_of_two") + for path in sorted(p for p in files if p.is_file()): + fmt, size = texture_size(path) + if fmt is None: + continue + relative = path.relative_to(args.folder).as_posix() + if size is None: + print(f"{relative}\t{fmt}\t?\t?\t?") + continue + width, height = size + pot = "yes" if is_power_of_two(width) and is_power_of_two(height) else "no" + print(f"{relative}\t{fmt}\t{width}\t{height}\t{pot}") + return 0 + + +if __name__ == "__main__": + sys.exit(main())