十字军之王3
ParaWikis
Notice
: Undefined index: HTTP_ACCEPT_LANGUAGE in
/data/wwwroot/www.parawikis.com/skins/Liberty/LibertyTemplate.php
on line
185
最新百科
都市天际线2百科
英雄无敌3百科
维多利亚3百科
奇妙探险队2百科
罪恶帝国百科
英白拉多:罗马百科
热门百科
群星百科
欧陆风云4百科
十字军之王2百科
十字军之王3百科
钢铁雄心4百科
维多利亚2百科
ParaWikis
申请建站
ParaWikis
ParaCommons
最近更改
随机页面
加入QQ群
工具
链入页面
相关更改
特殊页面
页面信息
页面值
帮助
译名手册
字词转换
编辑指南
编辑规范
练手沙盒
资助我们
×
欢迎访问十字军之王3百科!
注册一个账号
,一起参与编写吧!这里是
当前的工程
。
全站已采用新UI,任何使用上的问题请点击
这里
。欢迎所有对百科感兴趣的同学加入QQ群:
497888338
。
阅读
编辑
编辑源代码
查看历史
讨论
编辑“
界面
”
咯咯炀
(
讨论
|
贡献
)
2020年10月29日 (四) 13:52的版本
(创建页面,内容为“{{Version|timeless}} CK3's user interface (UI) is highly moddable, but for this reason UI mods disable achievements, since a player could cheat with them. The game…”)
(差异) ←上一版本 |
最后版本
(
差异
) |
下一版本→
(
差异
)
警告:您正在编辑的是本页面的旧版本。
如果您发布该更改,该版本后的所有更改都会丢失。
警告:
您没有登录。如果您做出任意编辑,您的IP地址将会公开可见。如果您
登录
或
创建
一个账户,您的编辑将归属于您的用户名,且将享受其他好处。
反垃圾检查。
不要
加入这个!
{{Version|timeless}} CK3's user interface (UI) is highly moddable, but for this reason UI mods disable achievements, since a player could cheat with them. The game also includes a GUI editor, which allows to inspect UI elements and edit them in the game. Modders can: * change the visual style of the interface * make windows movable and resizable * change and remove elements * add new buttons * show more information from the code * add new windows (with a workaround) Modders can’t: * add new hotkeys (only reuse the existing ones) * display information from one window in another, unless developers included that possibility. == Basics == The interface in CK3 is created through .gui files in the game/gui folder, which are somewhat similar to html files. As such, you can edit them with any text editor, like [[Modding#Tips_.26_guidelines | VS Code, Sublime or Atom]]. Choose Python or Perl 6 for syntax highlighting, they fit well. CK3 uses .dds files for textures, which are saved inside the game/gfx/ folder. To edit or save .dds files use either Photoshop with [https://software.intel.com/en-us/articles/intel-texture-works-plugin Intel plugin] or GIMP with [https://code.google.com/archive/p/gimp-dds/downloads this plugin]. To reload gui files in the game and use the GUI editor, add -debug_mode and -develop launch options: * right-click the game on Steam, choose Properties, Set Launch Options, add "-debug_mode -develop" You can use the following console commands: * reload gui - reloads all gui files to display any changes in the game * reload texture - reloads all texture files * gui_editor - opens the GUI editor * tweak gui.debug - allows to enable highlighting of UI elements. The tooltips will display their name, size and position. * DumpDataTypes - will create a data_types.log in your log folder (Documents/Paradox Interactive/Crusader Kings III/logs) listing all available GUI functions for each window/game object Other tips: * always have the error log open to see if there is a mistake in the code (it's in the same log folder) * enable the error tracker in the game by clicking "Toggle Release Mode" below the console, to see if your changes craeted any new errors * mute the game when using "reload gui" command, as it triggers the intro sound every time * use [https://steamcommunity.com/sharedfiles/filedetails/?id=2269399705 Reload GUI mod] that adds a button to reload gui (with a hotkey) and closes the Settings window when you reload * add the gui folder to your text editor, so it uses it for autocompletion * you can use test_gui.gui in gui/debug for testing. To show this window, open the console and click Test Window. * fold code so it's easier to see its structure. Usual hotkeys are Ctrl+K, Ctrl+1 (where 1 is the level at which to fold the code). == Creating a GUI mod == 1. Start the game launcher, go to Mods, Mod Tools and fill in all the fields, including tags. Clicking Create will create a new folder and a .mod file in <code>Documents/Paradox Interactive/Crusader Kings III/mod</code>. 2. Next, create a "gui" folder inside your mod and copy the files you want to mod there from game/gui. * If you don’t know which file is needed, use the GUI editor and inspect it in the game. == GUI Editor == GUI Editor is a developer tool for editing the UI in the game. To use it you need to launch the game with debug_mode and -developer options. To open the editor, either: * press Ctrl+F8 * open the console with the ` key (below Esc), click GUI Editor * open the console, run gui_editor command === Features === By default the editor starts with the Edit mode enabled. You can disable it in the top window, called Outliner. Hotkey "E". * The edit mode is similar to the Inspect mode in browsers. While it’s enabled you can’t interact with the game, but it allows you to select parts of the UI and change them in the Properties window below. * Scroll with your mouse wheel to change what element the editor should focus on, since hud.gui tends to get on top of other windows. * Yellow border indicated the selected element. To hide other borders, uncheck "Show Hierarchy" in the Outliner (Hotkey "L"). * Holding the right mouse button allows to move the selected element. * To undo anything, press Ctrl+Z or the undo button in the Outliner. Redo is next to it, Ctrl+Y. * Red stars * in the Outliner indicate unsaved changes. Press Ctrl+S or the save button at the top to save them. Make sure the gui files you're editing are in your mod, otherwise it will write the changes to the game folder. (To reset them, verify integrity from Steam's properties window) * You can move any dev windows by dragging them and resize them by dragging the edges. * You can drag UI elements in the Outliner's hierarchy to reorder them. Right-click to show the context menu. * You can change or add new properties (by clicking the plus symbol) in the Properties window. By clicking "Window" in the Outliner, you can open two more windows: UI components and Registered Data Types. * UI Components is like a palette from which you can drag new elements to the UI. gui/shared/standard.gui and gui/defaults.gui contain the most common things, like buttons, icons and text. * Registered Data Types may be used to look up what functions are available to display data from the game. * Clicking the top right button in the Data Types will dump this data to your log folder (Documents/Paradox Interactive/CK3/logs). You can also use "DumpDataTypes" console command. Note: it is often easy to select a template by mistake, changing which will affect ''all'' instances of it in the UI. Pay attention to what file you have selected in the outliner. If you see in the Properties window a blue header that starts with "type:", it is a template, so be careful not to edit this part (unless you intend to). == UI code == CK3’s UI is composed of containers and objects inside them. Most windows, for example, are created using a "window" container, while map icons use a widget or an hbox. The order in the file determines the order on the screen: what's lower in the code will appear on a higher layer. Most elements can also contain others, for example, there can be a textbox inside an icon inside a button. Nested elemenets, aka children, will will be moved with their parent. Position is set relative to the top left corner (either of the screen or the parent). This can be changed with <code>parentanchor</code> property. The available options are: left, right, top, bottom, hcenter (horizontal center) and vcenter (vertical center). They can be combined with a | like this: <code>parentanchor = right|vcenter</code>. Every element is opened and closed with curly brackets, like this: <code>container = { }</code>. The common code style is to open and close the block on the same level, while indenting the contents with one tab: widget = { size = { 50 50 } alpha = 0.5 } This helps you see the structure of the code better, notice any missing or extra brackets, and is needed for some editors to correctly fold the blocks of code. === UI Components === Window * The only movable container. To enable movement, add <code>movable = yes</code> property. * Can be fixed size or resized by its children. * In the game the background is set using templates, like <code>using = Window_Background</code> and <code>using = Window_Decoration</code>. * If a child is outside of a window, it won't be clickable and won't show a tooltip. Use <code>allow_outside = yes</code> to change this. Widget * A static container. Similar to a window in other regards. Margin_widget * Similar to a widget, but can be resized with margins. (This allows us to make windows that resize to screens of different size, by setting height to 100% and margins to ~50 to show the hud) Container * Does not have a fixed size (but you can set maximumsize). * Resizes automatically to fit all its children, including invisible ones. Use <code>ignoreinvisible = yes</code> to ignore them. * Often used to group multiple elements to move them together. Flowcontainer * Arranges all its children in a horizontal row. Use <code>direction = vertical</code> to make it vertical. * Doesn't ignore invisible children by default. Use <code>ignoreinvisible = yes</code> to change it. * Does not have a fixed size. * Its children cannot have positions, as they are set automatically. * If you need to adjust position of its child, you can put it inside a container or a widget and then change position relative to this parent. Hbox/Vbox * Arranges all its children in a horizontal row and spreads them along its width. Vbox is the same but vertical. * Cannot have a fixed size, but instead takes the width of its parent as its own (ignoring the parent's margins). Vbox takes the height. ** If its parent can't have a fixed size (like flowcontainer), this may crash the game. * Can be limited by minimumsize/maximumsize and margins. * Ignores invisible children by default. Use <code>ignoreinvisible = no</code> to change this. * An hbox inside another hbox will have 0 size and won't spread its children. Use <code>layoutpolicy_horizontal = expanding</code> to resize it (or <code>layoutpolicy_vertical = expanding</code> in a vbox) * Accepts datamodels (to create lists from game data). Dynamicgridbox * Is only used with datamodels. * Arranges all the items vertically. Use <code>flipdirection = yes</code> to make it horizontal. * Doesn't ignore invisible items by default. Use <code>ignoreinvisible = yes</code> to change it. * Can be fixed size, resized by the content and limited by minimumsize and maximumsize. * Items can be of different size. * Can become laggy with very long lists. Fixedgridbox * Similar to a dynamic box but all its itmes are of fixed size (it's essentially a table). * Is only used with datamodels. * Arranges all its items vertically. Use <code>flipdirection = yes</code> to make it horizontal. * Cannot ignore invisible items. * Can be fixed size, resized by the content and limited by minimumsize and maximumsize. * Much better for performance with long lists. Overlappingitembox * Is only used with datamodels. * Arranges all its items horizontally and overlaps them if the list is longer that the size of the box. Use <code>flipdirection = yes</code> to make it horizontal. * Can be fixed size or autoresized. Scrollarea * A widget with scrollbars that appear if the content is bigger than its size. * Scrollbars can be disabled with <code>scrollbarpolicy_horizontal = always_off</code> and <code>scrollbarpolicy_vertical = always_off</code>. ** A scrollarea with no scrollbars can be used to crop lists or images. * Can be fixed size, resized by the content and limited by minimumsize and maximumsize. Button * A clickable object. Accepts <code>onclick</code> and <code>onrightclick</code>. ** When adding a right click function, include <code>button_ignore = none</code>. * Doesn't have a texture by default. * Can be fixed size or resized by its children. ** A 0x0 button can be used to add invisible hotkeys. Icon * Displays a texture. * Can be used as a widget to store children. * Can be flipped with <code>mirror = horizontal</code> or <code>mirror = vertical</code>. Textbox * Shows text. * Can be fixed size or autoresized. * Use <code>elide = right</code> or <code>elide = left</code> to cut off text that is too long * Can be a single line or multiple, with <code>multiline = yes</code>. * Game files often use templates set in gui/shared/text.gui, like <code>text_single</code>. Use them to keep visual consistency and to type less code every time. === Promotes and Functions === Each window has a predefined set of commands - promotes and functions - available for it. These can be found in the data_types.log file in <code>Documents/Paradox Interactive/Crusader Kings III/logs/</code> after you use the "DumpDataTypes" console command. They are used to display all data from the game, like your name, gold, children, and to set button actions. A promote returns a scope, i.e a game object, like Character or Province, while a function returns a number, a string or a boolean (true/false) value, etc. Global commands can be used anywhere, like GetPlayer (returns the player character) or GetCurrentDate. Other commands can only be used in their window/object, for example, GetParents can only be used in the character window and must be started with <code>CharacterWindow.GetParents</code>. Commands can be chained like this: <code>CharacterWindow.GetCharacter.GetPrimaryTitle.GetHeir.GetPrimarySpouse.GetFather</code> Children can inherit the scope from their parent, meaning we wouldn't need to retype the line above to show information about this character. Instead we can set <code>datacontext</code> of a widget to this line and then every textbox in it will use <code>"[Character.GetNameNoTooltip]"</code>, <code>"[Character.GetGold]"</code>, etc. The same applies to items in gridboxes. === Templates === Templates are named blocks of code which can be used multiple times throughout the code, which helps maintain the same style and reduce the amount of code we write. Editing the template will edit all instances of it! Templates are global and can be defined in any file. Most of the game templates are stored in gui/shared. A local version, local_template, has to be defined within the same file. Templates can store the contents of an entire window or just one line, like this one: <pre> template Window_Size_Sidebar { size = { 610 100% } } </pre> This template can be used inside another element with "using = Window_Size_Sidebar", which will, essentially, replace the "using" line with the contents of the template. ==== Types ==== If templates can contain just a few properties, types are always whole elements, like a button or a widget. text_single and text_multi are types of a textbox with many properties already defined for them, so we don't need to retype them every time and instead simply write: <pre> text_single = { text = "my text" } </pre> Types are defined in a slightly different way, by creating a named group of types first: <pre> types Standard_Types { type text_single = textbox { ... } } </pre> ==== Blockoverride ==== Templates and types can have named override blocks, which allow us to edit a part of an instance without changing the whole template. For example, a template may have a default block of text: <pre> block "text" { text = "default_text" } </pre> To replace it, we add a blockoverride with the same name in our instance: <pre> blockoverride "text" { text = "actual text" } </pre> We can also remove it from our instance like this: <code>blockoverride "text" {}</code> == Scripted GUIs == Scripted guis are, essentially, hidden events triggered from the UI. The are stored as .txt files in game/common/scripted_guis and cannot be reloaded from the game, unlike the .gui files. The basic structure of a scripted gui is: <pre> gui_name = { scope = character # the root scope, i.e. the target of the effects saved_scopes = {} # any additional targets is_shown = {} # is it visible on the UI? ai_is_valid = {} # is the AI allowed to use it? Disabled by default. is_valid = {} # can the player use it? effect = { # what it does custom_tooltip = "" # adds a tooltip } } </pre> Not all of the blocks are necessary. Sometimes a scripted gui may only contain the scope and is_shown or effect. In the .gui file we use the following: <pre> datacontext = "[GetScriptedGui('gui_name')]" onclick = "[ScriptedGui.Execute( GuiScope.SetRoot( GetPlayer.MakeScope ).End)]" visible = "[ScriptedGui.IsShown( GuiScope.SetRoot( GetPlayer.MakeScope ).End)]" enabled = "[ScriptedGui.IsValid( GuiScope.SetRoot( GetPlayer.MakeScope ).End)]" tooltip = "[ScriptedGui.BuildTooltip( GuiScope.SetRoot( GetPlayer.MakeScope ).End)]" </pre> datacontext is necessary to link the element to the scripted gui. Other commands won't work without it. In this example the scripted gui is scoped to the player with a global function <code>GetPlayer.MakeScope</code>. It can be changed to someone in the character window, e.g. <code>CharacterWindow.GetCharacter.MakeScope</code>, or if the scope was a province, <code>HoldingView.GetProvince.MakeScope</code>. ScriptedGui.Execute is used with buttons and will execute everything listed in the <code>effect</code> block in the scripted gui. IsShown and IsValid check for conditions in is_shown and is_valid blocks. BuildTooltip can also be used with a textbox to display custom text in the UI. To save another scope to our scripted gui, we use AddScope like this: "[ScriptedGui.Execute( GuiScope.SetRoot( GetPlayer.MakeScope ).AddScope('target', CharacterWindow.GetCharacter.MakeScope ).End )]" And then we use the same name in the scripted gui: saved_scope = { target } Multiple scopes can be saved this way. It is important to not put any spaces before the dots or opening parentheses! <code>Execute(</code> is correct, <code>Execute (</code> is not. Other spaces can be omitted, but they help with readability. === Displaying a variable or script value === Variables and script values can be shown on the UI like this: variable: <code>text = "[GetPlayer.MakeScope.Var('test_var').GetValue|1]"</code> svalue: <code>text = "[GuiScope.SetRoot( GetPlayer.MakeScope ).ScriptValue('test_value')|0]"</code> In this example the variable is stored in the player character and is called test_var. Any other scope can be used, just remember to add MakeScope. |1 at the end is optional and will cut off all decimals save for one, so instead of 1.573 you will see 1.5. Note that it does not round the value. You can set this at any number, add % to convert to a percentage, add = or + to color the value if it's positive or negative. When using localization to display values in events, we use this: <code>event_var: "[ROOT.GetCharacter.MakeScope.Var('test_var').GetValue|0]"</code> <code>event_value: "[SCOPE.ScriptValue('test_value')|0]"</code> If you have a saved scope (named "target" here), it changes to this: <code>event_var: "[target.MakeScope.Var('test_var').GetValue|0]"</code> <code>event_value: "[GuiScope.SetRoot( target.MakeScope ).ScriptValue('test_value')|0]"</code> === Displaying data lists === We can create custom lists of characters, for example, to make societies. To do this, first, we need to add them to a variable list. This can be done though an event or a scripted gui, like this: <pre> effect = { every_living_character = { limit = { has_trait = paranoid } root = { add_to_variable_list = { name = secret_society target = prev } } } } </pre> If we fire this effect for the player, they will be the <code>root</code>, so the list will be stored in them. Then we use any list box (vbox, dynamicgridbox, fixedgridbox) with the datamodel set to our list: <pre> dynamicgridbox = { datamodel = "[GetPlayer.MakeScope.GetList('secret_society')]" item = { flowcontainer = { datacontext = "[Scope.GetCharacter]" portrait_head_small = {} text_single = { text = "[Character.GetNameNoTooltip]" } } } } </pre> == New windows and toggles == There isn't a simple way to create a new window and make your mod compatible with others. We have to either overwrite the hud or other windows. The usual way is to add the new window to hud.gui inside of ingame_topbar widget and then add a button to show/hide it. The alternative is to rewrite one of the unused windows, like test_gui and add a button with the console command that shows it. === Toggles with PdxGuiWidget === PdxGuiWidget is a simple function used to hide or reveal named elements. In this example we have a container with a hidden submenu, one button that shows it and another that hides it. # when clicked, the first button goes back to its parent, searches in it for the submenu and the other button, reveals them and hides itself # the second button searches for the element and the button, reveals them and hides itself <pre> container = { button = { name = "show submenu" onclick = "[PdxGuiWidget.AccessParent.FindChild('submnenu').Show]" onclick = "[PdxGuiWidget.AccessParent.FindChild('hide submenu').Show]" onclick = "[PdxGuiWidget.Hide]" } button = { name = "hide submenu" visible = no onclick = "[PdxGuiWidget.AccessParent.FindChild('submnenu').Hide]" onclick = "[PdxGuiWidget.AccessParent.FindChild('show submenu').Show]" onclick = "[PdxGuiWidget.Hide]" } widget = { name = "submenu" visible = no } } </pre> If the elements are separated by more parents/children, we can repeat AccessParent like this: onclick = "[PdxGuiWidget.AccessParent.AccessParent.AccessParent.AccessParent.FindChild('submnenu').Show]" Each button can hide or reveal multiple elements of any type. You only need to provide the name. Pros: * easy to edit on the fly as any changes can be reloaded with the "reload gui" command Cons: * the toggles will reset any time the game is restarted * If you want to hide multiple things or toggles, the code will get very bloated and hard to manage * trying to hide entries in a data list (like a dynamicgridbox) will only hide the first instance === Toggles with animation === We can set up animations that are triggered by buttons (or conditions) to hide/show elements or to even move them. This way we don't need to count how many parents separate the button and the window and we can trigger many things at once with just one onclick. The previous example would look like this and work the same way. The first button triggers "show_submenu", which hides the button and shows the rest, while the second button triggers "hide_submenu", which hides this button and the widget and shows the first button. <pre> container = { button = { state = { # this is an animation name = show_submenu on_start = "[PdxGuiWidget.Hide]" } state = { name = hide_submenu on_start = "[PdxGuiWidget.Show]" } onclick = "[PdxGuiTriggerAllAnimations('show_submenu')]" } button = { visible = no state = { name = show_submenu on_start = "[PdxGuiWidget.Show]" } state = { name = hide_submenu on_start = "[PdxGuiWidget.Hide]" } onclick = "[PdxGuiTriggerAllAnimations('hide_submenu')]" } widget = { visible = no state = { name = show_submenu on_start = "[PdxGuiWidget.Show]" } state = { name = hide_submenu on_start = "[PdxGuiWidget.Hide]" } } } </pre> it is longer, but animations can be saved as templates and reused with one line, like <code>using = hide_animation</code>. Fullscreen Barbershop uses animations extensively, if you want a better example. Pros: * can also be edited on the fly, with "reload gui" command * easier to link many things together, and even open a different window and trigger an animation in it Cons: * animation blocks can be quite lengthy * all toggles will reset when the game is restarted === Toggles with Scripted GUIs === Scripted guis allows us to use script to toggle visibility. They make it easier to manage multiple things but can impact performance when used in big numbers. For a scripted toggle we need to create a .txt file in common/scripted_guis/. The name of the file can be anything. A basic toggle in this file would looks like this: <pre> gui_toggle = { scope = character is_shown = { has_variable = gui_toggle } effect = { if = { limit = { has_variable = gui_toggle } remove_variable = gui_toggle } else = { set_variable = gui_toggle } } } </pre> When clicked, it adds a variable to the scoped character and removes it when clicked again. Then, if the variable is present, our window will be visible. If it's not, it's hidden. This is how the gui file would look like. We can use just one button as its function will change with each click. <pre> container = { button = { datacontext = "[GetScriptedGui('gui_toggle')]" onclick = "[ScriptedGui.Execute( GuiScope.SetRoot( GetPlayer.MakeScope ).End )]" } widget = { datacontext = "[GetScriptedGui('gui_toggle')]" visible = "[ScriptedGui.IsShown( GuiScope.SetRoot( GetPlayer.MakeScope ).End )]" } } </pre> "GetPlayer" is a global promote and returns the player character. "Player.MakeScope" makes our player the scope of the scripted gui, meaning this is where we store the variable in. Two buttons can be used if you want different tooltips for them. In this case, copy the 'visible' property to both buttons, but add 'Not' to one of them, so it's hidden by default: visible = "[Not(ScriptedGui.IsShown( GuiScope.SetRoot( GetPlayer.MakeScope ).End ))]" Pros: * the toggles are saved in the character and won't reset unless they die or you start a new game * easier to link many things, even in different windows The downsides: * you need to restart the game to update scripted guis * it's a little harder to remember the syntax (copy the code from here to reduce the chance of mistakes) {{Modding navbox}} [[Category:Modding]] [[en:Interface]]
摘要:
请注意您对十字军之王3百科的所有贡献都被认为是在知识共享署名-非商业性使用-相同方式共享下发布,请查看在
十字军之王3百科:版权
的细节。如果您不希望您的文字被任意修改和再散布,请不要提交。
您同时也要向我们保证您所提交的内容是您自己所作,或得自一个不受版权保护或相似自由的来源。
未经许可,请勿提交受版权保护的作品!
为防止机器编辑,请完成下方验证
取消
编辑帮助
(在新窗口中打开)
本页使用的模板:
Template:Clear
(
编辑
)
Template:Hover box
(
编辑
)
Template:Modding navbox
(
编辑
)
Template:Navbox
(
查看源代码
)(受保护)
Template:Navboxgroup
(
编辑
)
Template:Version
(
查看源代码
)(受保护)
Template:悬停
(
编辑
)
×
登录
密码
记住登录
加入十字军之王3百科
忘记密码?
其他方式登录