Удаление мода Recipe Book

Для сборщика электроники нужны фиол. манипуляторы (AKMF) #62
Обновление версии zzzparanoidal #65
This commit is contained in:
Aleksei-bird 2024-05-11 19:58:53 +03:00
parent 43137ef5f1
commit de9cea6cbf
97 changed files with 6 additions and 10398 deletions

View File

@ -1,33 +0,0 @@
# Recipe Book
A [Factorio](https://factorio.com) mod for looking up information about recipes, materials, machines, and technologies, and seeing how they interact with one another. Greatly assists in figuring out complex production cycles, especially in large modpacks.
## Download
Download on the [Factorio mod portal](https://mods.factorio.com/mod/RecipeBook), either on the website or in-game.
## Screenshots
![](screenshots/shortcut.png)
![](screenshots/search.png)
![](screenshots/search-filter.png)
![](screenshots/crafter.png)
![](screenshots/fluid.png)
![](screenshots/item.png)
![](screenshots/mining-drill.png)
![](screenshots/recipe.png)
![](screenshots/technology.png)
![](screenshots/settings.png)
![](screenshots/quick-ref.png)
![](screenshots/multi-window.png)

View File

@ -1,702 +0,0 @@
---------------------------------------------------------------------------------------------------
Version: 3.5.7
Date: 2023-11-24
Changes:
- Show entities as available from the start if they are placed by items whose recipes are available at start. (#145)
Bugfixes:
- Fixed crashes when table content elements somehow get invalidated. (#136)
- Fixed labs not being shown as a placed result. (#145)
- Fixed potential issues when recursively unlocking rocket launch products. (#144)
---------------------------------------------------------------------------------------------------
Version: 3.5.6
Date: 2023-08-21
Bugfixes:
- [Reverse factory] Fixed that recycling recipes would cause many items to incorrectly show as researched (#133)
---------------------------------------------------------------------------------------------------
Version: 3.5.5
Date: 2023-07-01
Bugfixes:
- Fixed a crash on load when a force is invalidated (#131)
---------------------------------------------------------------------------------------------------
Version: 3.5.4
Date: 2023-06-11
Bugfixes:
- Fixed a crash when calling `/rb-print-object` with no parameters (#128)
---------------------------------------------------------------------------------------------------
Version: 3.5.3
Date: 2023-04-29
Bugfixes:
- Fixed a crash when migrating from before version 3.0
- Fixed that characters were not showing as being able to craft recipes
---------------------------------------------------------------------------------------------------
Version: 3.5.2
Date: 2023-01-16
Optimizations:
- Massively reduced save loading time with large numbers of modules or fluids (credit to Rseding)
---------------------------------------------------------------------------------------------------
Version: 3.5.1
Date: 2022-12-06
Changes:
- Updated to Factorio 1.1.74 and flib 0.12.0
- Dictionary translations are performed 10x faster in singleplayer
---------------------------------------------------------------------------------------------------
Version: 3.5.0
Date: 2022-10-30
Features:
- Added new page contents:
- Number of module slots will be shown on all entities that support modules (https://todo.sr.ht/~raiguard/factorio-mods/57)
- [Recipe] Catalyst amounts are shown in ingredient and product tooltips (https://todo.sr.ht/~raiguard/factorio-mods/59)
Bugfixes:
- [Burning] Fixed can burn list on entities that have a fluid filter on their energy source
- [Recipe] Fixed that recipes were counting fluids when testing crafter ingredient limits
- [Resource] Fixed that fluid resource products would not show temperature (https://todo.sr.ht/~raiguard/factorio-mods/60)
---------------------------------------------------------------------------------------------------
Version: 3.4.5
Date: 2022-06-12
Bugfixes:
- Fixed a crash when a mining tool is used in a recipe (https://todo.sr.ht/~raiguard/factorio-mods/29)
---------------------------------------------------------------------------------------------------
Version: 3.4.4
Date: 2022-06-12
Bugfixes:
- Fixed a crash when a character has no crafting categories
- Fixed a crash when the GUI tried to display the dummy-steel-axe item (https://todo.sr.ht/~raiguard/factorio-mods/28)
---------------------------------------------------------------------------------------------------
Version: 3.4.3
Date: 2022-05-22
Bugfixes:
- Fixed a crash when a technology has no research ingredients (#117)
---------------------------------------------------------------------------------------------------
Version: 3.4.2
Date: 2022-05-22
Bugfixes:
- Fixed a crash when an entity is mineable, but has no mineable products (#118)
---------------------------------------------------------------------------------------------------
Version: 3.4.1
Date: 2022-05-21
Changes:
- Updated Korean locale (by x2605) (#115)
- Updated Russian locale (by astorin) (#116)
Bugfixes:
- Fixed flib dependency (#114)
---------------------------------------------------------------------------------------------------
Version: 3.4.0
Date: 2022-05-21
Features:
- Added new categories:
- Entity type
- Item type
- Science pack: Uncheck a science pack to hide all objects that it unlocks (#89)
- Added new interactions:
- [Entity] Shift + click to get a blueprint (not just on the recipe screen) (#98)
- Added new page contents:
- [Entity] Entity type, expected resources
- [Item] Affects recipes (for modules), Gathered from, item type
- [Recipe] Pollution multiplier (#113)
- Added new pages:
- Entity type: All entities of the given type
- Item type: All items of the given type
Changes:
- Category lists will be hidden when that category is disabled
---------------------------------------------------------------------------------------------------
Version: 3.3.4
Date: 2022-04-20
Bugfixes:
- Fixed a crash when upgrading from 3.1 or earlier
---------------------------------------------------------------------------------------------------
Version: 3.3.3
Date: 2022-04-14
Bugfixes:
- Fixed a crash when refreshing contents with an invalid info or quick ref GUI (#110)
- Fixed that certain entities had a "get blueprint" action when they weren't blueprintable (#111)
---------------------------------------------------------------------------------------------------
Version: 3.3.2
Date: 2022-03-20
Bugfixes:
- Fixed a crash when a favorites entry was removed from the game (#107)
- Fixed that using Control + F to focus search did not work
---------------------------------------------------------------------------------------------------
Version: 3.3.1
Date: 2022-03-12
Changes:
- Updated Korean locale (by x2605) (#101)
- Updated Russian locale (by Astorin) (#103)
Bugfixes:
- Fixed a crash when the first item group has no visible members in visual search (#102)
- Fixed a crash when using navigation hotkeys before opening an info GUI (#105)
---------------------------------------------------------------------------------------------------
Version: 3.3.0
Date: 2022-03-01
Features:
- Added new properties:
- [NEW] Beacon: size, effect area, distribution effectivity, module slots, accepted modules, unlocked by, placed by
- Equipment: buffer capacity, placed in
- Fluid: fuel pollution
- [NEW] Generator: fluid consumption, minimum / maximum temperatures, max power production, base pollution, can burn, unlocked by, and placeable by
- Added Korean locale (by x2605) (#97)
- Added visual mode to the search GUI, providing a more vanilla-like search interface
- This interface can only show items and fluids
Changes:
- Any blueprintable entity may be shift+clicked to get a blueprint of it, regardless of whether or not it has a recipe (#91)
- Category and group table items are hidden by default
- Consolidated all machines into a single "entity" type
- Fluid temperature variants are now sorted and placed adjacent to their base fluid in search results
- Refactored all GUI code to improve modularity and significantly cleaned up the codebase
- Technology unlocks equipment, unlocks fluids, unlocks items, and unlocks machines are hidden by default
- Using the inspect hotkey while holding a selection tool will do nothing (#95)
Bugfixes:
- Fixed a crash when a mod prototype was removed without the mod versions changing
- Fixed "can mine" table header being unlocalised
- Fixed recipe output percentages not being rounded
---------------------------------------------------------------------------------------------------
Version: 3.2.3
Date: 2022-01-08
Bugfixes:
- Fixed a rare crash during migrations (#90)
- Fixed a crash when a mod creates a force before the recipe book can be built (#94)
---------------------------------------------------------------------------------------------------
Version: 3.2.2
Date: 2021-12-06
Changes:
- "--- categories" lists are hidden by default
- Improved some of the list header names
Bugfixes:
- Fixed that quick ref windows would not open when the info GUI is docked (#87)
---------------------------------------------------------------------------------------------------
Version: 3.2.1
Date: 2021-11-09
Changes:
- Updated Russian locale (by Astorin)
Bugfixes:
- Added missing migration for GUI data from 3.2.0
---------------------------------------------------------------------------------------------------
Version: 3.2.0
Date: 2021-11-07
Features:
- Added new pages:
- Equipment category: All equipment and items belonging to each category
- Equipment: Size, take result, equipment properties, compatible fuels, fuel categories, equipment categories, and unlocked by for each equipment
- Added compatible equipment and equipment categories to the item page
- Added fuel categories to burner machine page
- Shift + click on a recipe with one product to view the product's page
- Using the inspect hotkey will attempt to open the info page relative to the currently open GUI
- Only works on vanilla GUIs (custom mod GUIs do not support relative anchoring)
- This can be disabled in the mod settings
Changes:
- Changed default inspect hotkey to alt+click
- Changed default search hotkey to Control + B
- Renamed 'burner machine' to 'machine'
Bugfixes:
- Fixed a crash if a prototype (somehow) doesn't have a stored translation (#80)
- Fixed a crash when another mod adds a force before RB has a chance to load
- Fixed a crash when using the search hotkey in the equipment grid GUI (#82)
- Fixed some edge-cases with the focus search hotkey logic
- Fixed that mining drills were not being processed for technology unlocks
---------------------------------------------------------------------------------------------------
Version: 3.1.5
Date: 2021-09-19
Changes:
- Added Brazillian Portuguese translation (by BM123499)
- Quick reference windows now open next to their parent window
Bugfixes:
- Fixed that dragging a quick reference window would reset its position for a frame
- Fixed that settings wouldn't be preserved if they were falsey
---------------------------------------------------------------------------------------------------
Version: 3.1.4
Date: 2021-09-02
Bugfixes:
- Fixed a crash when using the navigation hotkeys with a non-custom GUI open
- Fixed a crash when using the search hotkey in some windows
---------------------------------------------------------------------------------------------------
Version: 3.1.3
Date: 2021-08-18
Bugfixes:
- Fixed a crash when an item has a place result that isn't in the Recipe Book
- Fixed navigation hotkeys not working if search was open
- Fixed the toggle quick ref button wouldn't be updated if it was in the stickied info GUI
---------------------------------------------------------------------------------------------------
Version: 3.1.2
Date: 2021-08-17
Bugfixes:
- Fixed a crash when a mod unlocks a research during config changed before Recipe Book does its own configuration changes
- Fixed a crash when clicking the Factory Planner dimmer frame while an info GUI is stuck to search
- Fixed that the search GUI would not be brought to the front when clicking the FP dimmer frame
---------------------------------------------------------------------------------------------------
Version: 3.1.1
Date: 2021-08-16
Bugfixes:
- Fixed a crash when joining a multiplayer game without changing your language
---------------------------------------------------------------------------------------------------
Version: 3.1.0
Date: 2021-08-16
Features:
- Added "compatible modules" to the crafter page (hidden by default, must be enabled in the page settings)
- Added "burner machine" page
- Burner machines are machines that consume fuel and aren't a crafter, lab, mining drill, or offshore pump
- Some of these machines might get their own pages someday if enough relevant information is available for display
- Added "burnt result" and "burnt result of" to the item page
Gui:
- When clicking a search result in the search GUI with the left mouse button, the info GUI will be "stickied" to the search GUI
- A "detach" button will appear in the titlebar of the sticky window, allowing you to detach it
- Middle-clicking something will open it in a standalone info GUI
- This brings back a 2.0-esque experience for those who preferred it
- This can be disabled in the mod settings
- Added the ability to collapse components of an info page
- Some components (categories, compatible modules) default to collapsed to save space
- Default state can be overridden in the settings
- Added search GUI location setting, choose between top-left and center
- Added page content settings
- Each "section" of a page can be enabled or disabled, and have the following settings based on type:
- All:
- Default state (normal, collapsed, hidden)
- Table (with absolute rows):
- Row visibility
- List box:
- Max rows
Changes:
- Machines that have exactly one item to place them will inherit the item's hidden & enabled statuses
- Machines that have no items to place them will be marked as disabled
- Renamed "rocket launch payloads" to "rocket launch product of"
- Search GUI now opens below the mod_gui button frame, instead of all the way in the corner
- Search GUI now takes "opened" focus again
- The pin button has returned as well, allowing you to keep it open while viewing other GUIs
Bugfixes:
- Fixed that class filters in search used the internal names instead of the localised names
- Fixed that fluidboxes were not being considered for compatible recipes on crafters
- Fixed that the "shift + click to get a blueprint" interaction help wouldn't be shown in certain conditions
---------------------------------------------------------------------------------------------------
Version: 3.0.3
Date: 2021-08-14
Changes:
- Updated Russian locale by Astorin
- The search GUI now supports locale-specific widths
Bugfixes:
- Fixed a crash when an item has a resource as its place result
- Fixed a crash when a resource has no products when mined
---------------------------------------------------------------------------------------------------
Version: 3.0.2
Date: 2021-08-10
Changes:
- Removed `/RecipeBook` command, replaced with `/rb-refresh-all`
- Updated to flib 0.8.2
Bugfixes:
- Fixed a crash when a mod added or removed pretty much anything to/from an existing save
- Fixed that a new search GUI would be created every time the player joined a multiplayer game
---------------------------------------------------------------------------------------------------
Version: 3.0.1
Date: 2021-08-09
Changes:
- Updated to flib 0.8.1
---------------------------------------------------------------------------------------------------
Version: 3.0.0
Date: 2021-08-09
Features:
- Added new pages:
- Fuel category: fluids and items belonging to each category
- Group: fluids, items, and recipes belonging to each group
- Lab: research speed, compatible science packs, compatible fuels, fuel categories, unlocked by, placeable by, size
- Mining drill: mining speed, mining area, compatible resources, resource categories, compatible fuels, fuel categories, unlocked by, placeable by, size
- Offshore pump: pumping speed, output fluid, unlocked by, placeable by, size
- Recipe category: fluids, items, and recipes belonging to each recipe category
- Resource: resource category, required fluid, mining time, products, compatible mining drills
- Resource category: resources and mining drills belonging to that category
- Added numerous properties that were previously confined to tooltips, and new properties:
- Crafter: Crafting speed, ingredient limit, size, compatible fuels, fuel categories
- Fluid: Fuel value, default temperature, group
- Item: Stack size, fuel value, fuel pollution, vehicle acceleration, vehicle top speed, group, place result (if the place result has RB data), module effects
- Recipe: Recipe category, group, compatible modules
- Added settings to toggle fuel category, group, and resource category member visibility
- Added text search to information pages
- Alt-clicking an ingredient or product in a quick ref window will mark it green
- Middle-clicking an object will open that object in a new window
- Search and information have been separated into separate GUIs
- You can open as many information windows as you want simultaneously
Changes:
- "Empty X barrel" recipes will no longer unlock the fluid that they empty
- Recipe time-to-craft is now displayed in a generic info table, rather than as a fake ingredient
- Renamed "placeable by" to "placed by"
- Split the universal "search" hotkey into separate search and open selected object hotkeys
- Unresearched objects are shown by default
Optimizations:
- Reduced network traffic taken up by translation requests by a ridiculous amount
- Reduced the mod's script data footprint by more than 10x
- Significantly reduced the amount of time translating takes
Bugfixes:
- Fixed that recipe "made in" didn't account for ingredient count limits on assemblers
- Fixed that rocket launch products were always marked as their own payload
- Fixed that rocket launch products weren't being shown in many places due to invalid recipe categories
---------------------------------------------------------------------------------------------------
Version: 2.7.1
Date: 2021-05-03
Bugfixes:
- Fixed a crash when a new force was created
---------------------------------------------------------------------------------------------------
Version: 2.7.0
Date: 2021-05-03
Features:
- Added an option to show disabled recipes and technologies
- Added indicators for when a recipe or technology is disabled
- Added researched state for labs and offshore pumps
Changes:
- Disabled recipes and technologies are hidden by default
- When a fluid has multiple temperatures, the default temperature will be displayed for fluid products that usually have no temperature
Bugfixes:
- Fixed a crash when using the hotkey on a science lab
- Fixed fluids not being enabled at start even if their offshore pump was
- Fixed fluid temperature variants not copying recipe categories from their parents
- Fixed fluid variant ingredient in lists being completely wrong in most cases
- Fixed several inconsistencies with fluid temperature variation researched status
---------------------------------------------------------------------------------------------------
Version: 2.6.0
Date: 2021-04-05
Features:
- Added generic object opening support
- Hovering over any crafter, fluid, item, recipe, or technology anywhere in the game and using the Recipe Book hotkey will open that object's page
- Added fuel pollution, vehicle acceleration, and vehicle top speed multipliers to item tooltips
- Added tooltips to close buttons
Bugfixes:
- Fixed a crash if another mod updated a new technology in on_configuration_changed before Recipe Book refreshed its data
- Fixed a crash when a required fluid for mining was unresearched and "show unresearched objects" was off
- Fixed a crash when using "%" in search in some situations
- Fixed that changes to object availability would not apply when opening the GUI while preserve session is enabled (credit to kubiix)
---------------------------------------------------------------------------------------------------
Version: 2.5.2
Date: 2021-02-17
Bugfixes:
- Fixed a crash when an infinite technology only has one level (#44)
- Fixed a crash when researching a previously-disabled technology (#44)
---------------------------------------------------------------------------------------------------
Version: 2.5.1
Date: 2021-02-17
Bugfixes:
- Fixed a crash when a character entity had an item to place it (#43)
---------------------------------------------------------------------------------------------------
Version: 2.5.0
Date: 2021-02-17
Features:
- Added controls for navigating the session history, bound by default to the back and forward buttons on the mouse
- Added default recipe category excludes for Creative Mod and the PySuite
- Added fluid temperature support (thanks kubiix!)
- When searching, temperatures and temperature ranges for each fluid will be shown as well
- Each temperature and temperature range has a separate fluid page listing the properties specific to that temperature or range
- Each fluid still has a non-temperature page that shows all properties for that fluid
- Added highlight on the last selected item (configurable)
- Added "made in" to the recipe quick reference panel
- Added required fluid to resource tooltip
- Added "placeable by" and "unlocked by" to the crafter page
- Added help message when viewing a blank page
- Added technology page and search category (credit to kubiix)
Changes:
- Adjusted glyph sizing to fix alignment
- Adjusted titlebar styling to match the base game
- Moderatly increased the size of the main GUI
- Improved interaction help formatting
- Put the settings gear icon on a diet
- Recipes and materials that are available at the beginning of the game are now treated as such
- Separated fluid and item search categories
- Significantly refactored the data processor to improve code quality, simplify some things, and support fluid temperatures
- Removed "burnable in" and "compatible fuels" sections, as they were inconsistent and only worked with crafters
Bugfixes:
- Fixed a crash with certain modded burner entities
- Fixed a crash when upgrading from a pre-2.0 version of the mod
- Fixed a long-standing bug that materials would be marked as available when usable as an ingredient, even if it was not obtainable
- Fixed crafter labels showing interaction helps
- Fixed that even if a page was already open, it would be added again to the session history and re-opened
- Fixed that hand-minable resource items would be marked as unavailable if no available recipes produced it
- Fixed the session history active line not lining up with the other lines
- Fixed that the GUIs would not update when a research was finished (credit to kubiix)
---------------------------------------------------------------------------------------------------
Version: 2.4.1
Date: 2021-01-02
Features:
- Added compatibility with Factory Planner's dimmer frame - RB will now stay in front of it if both GUIs are open at once
Bugfixes:
- Fixed RB GUI not coming to the front when opened
- Fixed that closing RB while pinned would also close whatever GUI happened to be marked as `opened` at the time
---------------------------------------------------------------------------------------------------
Version: 2.4.0
Date: 2021-01-02
Features:
- Added crafter page, listing the recipes compatible with that crafter and the fuels it is compatible with
- Added search by crafter
- Added `burnable in` to material page, listing the crafters where it can be used as fuel
- Added descriptions to object tooltips
- Added fuel values to material tooltips
- Added session history listing to the navigation button tooltips
- Pressing enter while in the search textfield will switch search categories
- When opening the GUI, the home page will be shown instead of the last viewed page (optional)
Changes:
- Updated the mod to the new flib `gui-beta` module
- Removed per-player settings from the mod settings menu - use the mod's built-in settings GUI instead
Bugfixes:
- Fixed a crash when an object was added to the favorites list, then removed from the game on configuration changed
- Fixed that quick reference windows would not update their contents when settings were changed
---------------------------------------------------------------------------------------------------
Version: 2.3.3
Date: 2020-12-06
Changes:
- Clicking a crafter to give a blueprint of it will use the blueprint clipboard intead of a one-off item
---------------------------------------------------------------------------------------------------
Version: 2.3.2
Date: 2020-11-23
Changes:
- Updated to Factorio 1.1
---------------------------------------------------------------------------------------------------
Version: 2.3.1
Date: 2020-11-15
Changes:
- Updated deprecated require path for flib data-util module
- Updated German translation (by Moonsilence)
---------------------------------------------------------------------------------------------------
Version: 2.3.0
Date: 2020-09-02
Features:
- Added setting to disable the "alternate name" in object tooltips
- Added `usable in` list to the material page, listing the labs that that science pack is usable in
- Added crafting speed and crafting categories to crafter tooltips
- Added category, crafting time, ingredients, and products to recipe tooltips
Changes:
- Characters are now properly detected and included as crafters, instead of being hard-coded
---------------------------------------------------------------------------------------------------
Version: 2.2.0
Date: 2020-08-30
Features:
- Added stack size to item tooltips
- Added `pumped by` to material page, which lists offshore pumps that produce that fluid
- Added `rocket launch payloads` and `rocket launch products` to material page
- Added rocket silos as crafters
- Rocket silo crafters will display their required amount of rocket parts in their label and tooltip
- Added fixed recipe to crafter tooltip if it has one
- Shift + clicking a crafter with a fixed recipe will open that recipe's page
- Added `purge-memoizer-cache` argument to the `/RecipeBook` command
Changes:
- Known "meta-recipes" (such as transport drones recipes used for requests) will no longer affect object availability
- If there is a mod whose meta-recipes are not excluded, please let me know so I can exclude it
---------------------------------------------------------------------------------------------------
Version: 2.1.1
Date: 2020-08-15
Changes:
- Updated to Factorio 1.0
Bugfixes:
- Fixed a crash due to improper checking of force availability data for crafters
---------------------------------------------------------------------------------------------------
Version: 2.1.0
Date: 2020-08-10
Features:
- Added base crafting speed to recipe pages
- Added character to "made in" list for recipes that are hand-craftable
- Added brief interaction helps to all object tooltips
Changes:
- All recipe ingredients and products will always be shown despite object visibility settings
- Renamed "machine" back to "crafter" as the reason for the name change is moot at this point
Bugfixes:
- Fixed a crash when a mod would be removed while translations were running, but before those translations translated all of that mod's strings
- Fixed a crash when opening a quick reference panel for a hidden recipe, when show hidden objects is turned off
- Fixed a desync related to a player's connected status in multiplayer during a mod change
---------------------------------------------------------------------------------------------------
Version: 2.0.4
Date: 2020-07-27
Features:
- Enabling "use internal names" will change search to use internal names as well
Changes:
- Renamed "show internal names" to "use internal names" and moved to search settings
Bugfixes:
- Fixed a desync related to player.connnected being unreliable during on_configuration_changed in multiplayer
- Fixed a potential crash if a GUI handler was removed between versions
---------------------------------------------------------------------------------------------------
Version: 2.0.3
Date: 2020-07-25
Bugfixes:
- Fixed that the search history would not be purged on configuration change, leading to crashes with non-existent items
- Reverted the session history "fix" from v2.0.2 that was actually being caused by the above issue, and didn't actually fix anything
- Fixed a crash with the listbox item clicked regex when an item name has brackets in it
- Fixed a crash when attempting to get a machine blueprint for a crafter that had the "non-blueprintable" flag set
- Fixed that temporary machine blueprints of machines with a side that was an even number of tiles would be placed one tile off from where the preview was
---------------------------------------------------------------------------------------------------
Version: 2.0.2
Date: 2020-07-25
Features:
- Clicking a machine on the recipe screen will give you a blueprint of that machine with the recipe set
- Right-clicking the search textfield will clear it
Bugfixes:
- Fixed that the session history would sometimes get a duplicated home entry, causing a crash when trying to format the back button
---------------------------------------------------------------------------------------------------
Version: 2.0.1
Date: 2020-07-20
Changes:
- Improved performance of "add to favorites" button
- Remote interface:
- Consolidated check_obj_valid into open_page, having it separate wasn't really necessary
---------------------------------------------------------------------------------------------------
Version: 2.0.0
Date: 2020-07-19
Features:
- Added the ability to "pin" the GUI to the screen, so it can exist alongside other windows
- Added the ability to "favorite" an object for easy access later
- Added browse-able search history, keeping track of the last 20 searches
- Added setting to display internal prototype names instead of translations
- Added object type glyphs
- Added settings for toggling specific recipe categories
- Added an in-game settings screen for on-the-fly changes
- Added German translation by LuziferSenpai
Changes:
- Completely rewrote the mod from scratch to improve code quality, efficiency, and structure
- Search and information are now combined into one window
- Information listboxes are significantly wider and are arranged in a single column
- Absolutely all recipes are now included in the Recipe Book data
- The GUI will remain open when clicking on a technology
- Remote Interface:
- Added check_obj_valid function
- Renamed open_gui to open_page and changed argument formatting (see docs)
- Removed tie-ins to the back button and associated events (reopen_source_event)
Bugfixes:
- Fixed several crashes related to GUI buttons and multiplayer latency
---------------------------------------------------------------------------------------------------
Version: 1.3.6
Date: 2020-06-24
Bugfixes:
- Fixed a crash related to GUI style changes in Factorio 0.18.33
- Fixed typos in changelog
---------------------------------------------------------------------------------------------------
Version: 1.3.5
Date: 2020-06-19
Features:
- Added /RecipeBook command for diagnosing / fixing issues, use /help RecipeBook to see possible options
---------------------------------------------------------------------------------------------------
Version: 1.3.4
Date: 2020-06-11
Bugfixes:
- Fixed a crash when re-joining a multiplayer game for the second time after a mod configuration change
- Fixed that loading certain scenarios would cause translations to be duplicated
---------------------------------------------------------------------------------------------------
Version: 1.3.3
Date: 2020-05-31
Changes:
- Deep Storage Unit (DSU) recipes are now hidden from the Recipe Book
- The log is no longer spammed with recipe book data unless the debug adapter is hooked
Bugfixes:
- Fixed a crash when two players were searching at the same time
---------------------------------------------------------------------------------------------------
Version: 1.3.2
Date: 2020-05-26
Bugfixes:
- Fixed that object availability would not be updated when migrating
---------------------------------------------------------------------------------------------------
Version: 1.3.1
Date: 2020-05-26
Bugfixes:
- Fixed a crash when joining a multiplayer game for not the first time
---------------------------------------------------------------------------------------------------
Version: 1.3.0
Date: 2020-05-26
Features:
- Added keyboard shortcuts for changing categories in the search GUI
- The shortcut button properly toggles the search GUI open/closed, instead of just opening it
- Hidden objects are now indicated with an [H] moniker
- Unavailable (unresearched) objects are colored red
- Added an option to hide unavailable objects
Changes:
- Refactored mod structure to improve performance and simplicity
- Switched from RaiLuaLib to FLib
- Search is now spread out over multiple ticks to save performance and allow the addition of more complex features
- Changing search categories will no longer reset the textfield to blank
- Removed crafters as a searchable category and info screen, the utility offered by them was minimal
- Transport drones recipes are now excluded from the Recipe Book
- Recipes that have no ingredients are excluded from the Recipe Book
- Updated GUI styles for Factorio 0.18.27
---------------------------------------------------------------------------------------------------
Version: 1.2.3
Date: 2020-04-12
Changes:
- Converted all strings to double quotes
- Removed search button from next to close button (it will come back as an ACTUAL search button later)
- Translations are no longer performed on every join. If you change languages, simply use the /retranslate-all-dictionaries command to retranslate your dictionaries
Bugfixes:
- Fixed crash when using RaiLuaLib 0.2.4
---------------------------------------------------------------------------------------------------
Version: 1.2.2
Date: 2020-04-09
Changes:
- Updated to RaiLuaLib 0.2.3
---------------------------------------------------------------------------------------------------
Version: 1.2.1
Date: 2020-04-03
Features:
- Added fuzzy search option
Changes:
- Marked Death Markers as incompatible, because it somehow causes this mod to desync in multiplayer
Bugfixes:
- Added an error catch for a common error that I cannot reproduce. It gives instructions on how to report the error, and prints several helpful things to a file.
---------------------------------------------------------------------------------------------------
Version: 1.2.0
Date: 2020-04-01
Features:
- You can now open multiple recipe quick reference windows simultaneously
- Using the search hotkey while holding an item will open that item's material page, if one exists
- Fluid searching with the hotkey now supports infinity pipes
Changes:
- Recipe quick reference windows are now draggable
- Remote Interface:
- open_info_gui -> open_gui
- object_name -> object
- 'object' is now specified as a table when opening a material GUI, the first entry being the material type, and the second the name
- Recipe Quick Reference windows may be opened using the 'recipe-quick-reference` gui_type
- source_data is not supported when opening this GUI type
Bugfixes:
- Fixed that items and fluids with identical names would conflict
---------------------------------------------------------------------------------------------------
Version: 1.1.5
Date: 2020-03-20
Changes:
- Materials that aren't used in any recipes are excluded from the Recipe Book
- Significantly optimized GUI construction and update logic (it is now over 4x faster!)
- Removed mod GUI button, it is replaced by a shortcut
- Replaced the chef hat book icon with a proper "search recipe book" icon
- Refactored search loop to make adding more features easier
- Removed lualib and made it a separate mod, RaiLuaLib, that this mod now depends on
Bugfixes:
- Fixed crash when a clicking an object with rich text in the name (Krastorio 2)
- Fixed GUI alignment issues caused by style changes in 0.18.13
- Fixed potential issues with conditionally registered handlers losing their correlations with custom mod events when configuration changes
---------------------------------------------------------------------------------------------------
Version: 1.1.4
Date: 2020-03-08
Features:
- Added a function to the remote interface to return the current API version
---------------------------------------------------------------------------------------------------
Version: 1.1.3
Date: 2020-02-15
Bugfixes:
- Fixed a crash when opening a material from the recipe page (bad pattern matching)
---------------------------------------------------------------------------------------------------
Version: 1.1.2
Date: 2020-02-12
Bugfixes:
- Fixed incompatibilities with Quick Item Search
---------------------------------------------------------------------------------------------------
Version: 1.1.1
Date: 2020-02-12
Changes:
- Recipe amounts and crafting times are now shown in a slightly bold font
Bugfixes:
- Fixed a crash when reading a product with a variable amount of materials
---------------------------------------------------------------------------------------------------
Version: 1.1.0
Date: 2020-02-11
Features:
- Added support for the /retranslate-all-dictionaries command, which will retranslate all of your dictionaries
- Added support for variable probability results in recipes
- Using the hotkey while hovering over a pipe, pump, storage tank, or fluid wagon will open its fluid's material page
Bugfixes:
- Fixed a crash when confirming the search textfield when the results listbox was empty
- Fixed a crash when a recipe's product didn't have an amount specified
- Fixed a crash when there was more than one player on the map in some cases
- Fixed the translation module doing extraneous translating
- Fixed the translation module would never stop translating if the previous translation finished before you restarted it
---------------------------------------------------------------------------------------------------
Version: 1.0.0
Date: 2020-02-09
Features:
- Initial release

File diff suppressed because it is too large Load Diff

View File

@ -1,569 +0,0 @@
local dictionary = require("__flib__.dictionary-lite")
local gui = require("__flib__.gui")
local migration = require("__flib__.migration")
local on_tick_n = require("__flib__.on-tick-n")
local table = require("__flib__.table")
local constants = require("constants")
local database = require("scripts.database")
local formatter = require("scripts.formatter")
local global_data = require("scripts.global-data")
local migrations = require("scripts.migrations")
local player_data = require("scripts.player-data")
local remote_interface = require("scripts.remote-interface")
local util = require("scripts.util")
-- -----------------------------------------------------------------------------
-- GLOBALS
INFO_GUI = require("scripts.gui.info.index")
QUICK_REF_GUI = require("scripts.gui.quick-ref.index")
SEARCH_GUI = require("scripts.gui.search.index")
SETTINGS_GUI = require("scripts.gui.settings.index")
--- Open the given page.
--- @param player LuaPlayer
--- @param player_table PlayerTable
--- @param context Context
--- @param options table?
function OPEN_PAGE(player, player_table, context, options)
options = options or {}
--- @type InfoGui?
local Gui
if options.id then
Gui = util.get_gui(player.index, "info", options.id)
else
_, Gui = next(INFO_GUI.find_open_context(player_table, context))
end
if Gui and Gui.refs.root.visible then
Gui:update_contents({ new_context = context })
else
INFO_GUI.build(player, player_table, context, options)
end
end
--- Refresh the contents of all Recipe Book GUIs.
--- @param player LuaPlayer
--- @param player_table PlayerTable
--- @param skip_memoizer_purge boolean?
function REFRESH_CONTENTS(player, player_table, skip_memoizer_purge)
if not skip_memoizer_purge then
formatter.create_cache(player.index)
end
--- @type table<number|string, InfoGui>
local info_guis = player_table.guis.info
for id, InfoGui in pairs(info_guis) do
if not constants.ignored_info_ids[id] and InfoGui.refs.window.valid then
InfoGui:update_contents({ refresh = true })
end
end
--- @type table<string, QuickRefGui>
local quick_ref_guis = player_table.guis.quick_ref
for _, QuickRefGui in pairs(quick_ref_guis) do
if QuickRefGui.refs.window.valid then
QuickRefGui:update_contents()
end
end
--- @type SearchGui?
local SearchGui = util.get_gui(player.index, "search")
if SearchGui then
SearchGui:dispatch("update_favorites")
SearchGui:dispatch("update_history")
if SearchGui.state.search_type == "textual" then
SearchGui:dispatch("update_search_results")
elseif SearchGui.state.search_type == "visual" then
if SearchGui.refs.window.visible then
SearchGui:update_visual_contents()
else
SearchGui.state.needs_visual_update = true
end
end
end
end
-- -----------------------------------------------------------------------------
-- COMMANDS
-- User commands
commands.add_command("rb-refresh-all", { "command-help.rb-refresh-all" }, function(e)
local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
if not player.admin then
player.print({ "cant-run-command-not-admin", "rb-refresh-all" })
return
end
game.print("[color=red]REFRESHING RECIPE BOOK[/color]")
game.print("Get comfortable, this could take a while!")
on_tick_n.add(game.tick + 1, { action = "refresh_all" })
end)
-- Debug commands
commands.add_command("rb-print-object", nil, function(e)
if not e.parameter then
return
end
local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
if not player.admin then
player.print({ "cant-run-command-not-admin", "rb-dump-data" })
return
end
local class, name = string.match(e.parameter, "^(.+) (.+)$")
if not class or not name then
player.print("Invalid arguments format")
return
end
local obj = database[class] and database[class][name]
if not obj then
player.print("Not a valid object")
return
end
if __DebugAdapter then
__DebugAdapter.print(obj)
player.print("Object data has been printed to the debug console.")
else
log(game.table_to_json(obj))
player.print("Object data has been printed to the log file.")
end
end)
commands.add_command("rb-count-objects", nil, function(e)
local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
if not player.admin then
player.print({ "cant-run-command-not-admin", "rb-dump-data" })
return
end
for name, tbl in pairs(database) do
if type(tbl) == "table" then
local output = name .. ": " .. table_size(tbl)
player.print(output)
log(output)
end
end
end)
commands.add_command("rb-dump-database", nil, function(e)
local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
if not player.admin then
player.print({ "cant-run-command-not-admin", "rb-dump-data" })
return
end
if __DebugAdapter and (not e.parameter or #e.parameter == 0) then
__DebugAdapter.print(database)
game.print("Database has been dumped to the debug console.")
else
game.print("[color=red]DUMPING RECIPE BOOK DATABASE[/color]")
game.print("Get comfortable, this could take a while!")
on_tick_n.add(
game.tick + 1,
{ action = "dump_database", player_index = e.player_index, raw = e.parameter == "raw" }
)
end
end)
-- -----------------------------------------------------------------------------
-- EVENT HANDLERS
-- BOOTSTRAP
script.on_init(function()
dictionary.on_init()
on_tick_n.init()
global_data.init()
global_data.update_sync_data()
global_data.build_prototypes()
database.build()
database.check_forces()
for i, player in pairs(game.players) do
player_data.init(i)
player_data.refresh(player, global.players[i])
end
end)
script.on_load(function()
formatter.create_all_caches()
-- When mod configuration changes, don't bother to build anything because it'll have to be built again anyway
if global_data.check_should_load() then
database.build()
database.check_forces()
end
-- Load GUIs
for _, player_table in pairs(global.players) do
local guis = player_table.guis
if guis then
for _, Gui in pairs(guis.quick_ref or {}) do
QUICK_REF_GUI.load(Gui)
end
for id, Gui in pairs(guis.info or {}) do
if not constants.ignored_info_ids[id] then
INFO_GUI.load(Gui)
end
end
if guis.search then
SEARCH_GUI.load(guis.search)
end
if guis.settings then
SETTINGS_GUI.load(guis.settings)
end
end
end
end)
migration.handle_on_configuration_changed(migrations, function()
dictionary.on_configuration_changed()
global_data.update_sync_data()
global_data.build_prototypes()
database.build()
database.check_forces()
for i, player in pairs(game.players) do
player_data.refresh(player, global.players[i])
end
end)
-- DICTIONARIES
dictionary.handle_events()
script.on_event(dictionary.on_player_dictionaries_ready, function(e)
local player = game.get_player(e.player_index) --[[@as LuaPlayer]] --[[@as LuaPlayer]]
local player_table = global.players[e.player_index]
player_table.translations = dictionary.get_all(e.player_index)
if player_table.flags.can_open_gui then
REFRESH_CONTENTS(player, player_table)
else
-- Show message if needed
if player_table.flags.show_message_after_translation then
player.print({ "message.rb-can-open-gui" })
player_table.flags.show_message_after_translation = false
end
-- Create GUI
SEARCH_GUI.build(player, player_table)
-- Update flags
player_table.flags.can_open_gui = true
-- Enable shortcut
player.set_shortcut_available("rb-search", true)
end
end)
-- FORCE
script.on_event(defines.events.on_force_created, function(e)
if not global.forces or not database.generated then
return
end
global_data.add_force(e.force)
database.check_force(e.force)
end)
script.on_event({ defines.events.on_research_finished, defines.events.on_research_reversed }, function(e)
-- This can be called by other mods before we get a chance to load
if not global.players or not database.generated then
return
end
if not database[constants.classes[1]] then
return
end
database.handle_research_updated(e.research, e.name == defines.events.on_research_finished and true or nil)
-- Refresh all GUIs to reflect finished research
for _, player in pairs(e.research.force.players) do
local player_table = global.players[player.index]
if player_table and player_table.flags.can_open_gui then
REFRESH_CONTENTS(player, player_table, true)
end
end
end)
-- GUI
local function handle_gui_action(msg, e)
local Gui = util.get_gui(e.player_index, msg.gui, msg.id)
if Gui then
Gui:dispatch(msg, e)
end
end
local function read_gui_action(e)
local msg = gui.read_action(e)
if msg then
handle_gui_action(msg, e)
return true
end
return false
end
gui.hook_events(read_gui_action)
script.on_event(defines.events.on_gui_click, function(e)
-- If clicking on the Factory Planner dimmer frame
if not read_gui_action(e) and e.element.style.name == "fp_frame_semitransparent" then
-- Bring all GUIs to the front
local player_table = global.players[e.player_index]
if player_table.flags.can_open_gui then
util.dispatch_all(e.player_index, "info", "bring_to_front")
util.dispatch_all(e.player_index, "quick_ref", "bring_to_front")
--- @type SearchGui?
local SearchGui = util.get_gui(e.player_index, "search")
if SearchGui and SearchGui.refs.window.visible then
SearchGui:bring_to_front()
end
end
end
end)
script.on_event(defines.events.on_gui_closed, function(e)
if not read_gui_action(e) then
local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
local player_table = global.players[e.player_index]
if player_table.flags.technology_gui_open then
player_table.flags.technology_gui_open = false
local gui_data = player_table.guis.search
if not gui_data.state.pinned then
player.opened = gui_data.refs.window
end
elseif player_table.guis.info._relative_id then
--- @type InfoGui?
local InfoGui = util.get_gui(e.player_index, "info", player_table.guis.info._relative_id)
if InfoGui then
InfoGui:dispatch("close")
end
end
end
end)
-- INTERACTION
script.on_event(defines.events.on_lua_shortcut, function(e)
if e.prototype_name == "rb-search" then
local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
local player_table = global.players[e.player_index]
local cursor_stack = player.cursor_stack
if cursor_stack and cursor_stack.valid_for_read then
local data = database.item[cursor_stack.name]
if data then
OPEN_PAGE(player, player_table, { class = "item", name = cursor_stack.name })
else
-- If we're here, the selected object has no page in RB
player.create_local_flying_text({
text = { "message.rb-object-has-no-page" },
create_at_cursor = true,
})
player.play_sound({ path = "utility/cannot_build" })
end
return
end
-- Open search GUI
--- @type SearchGui?
local SearchGui = util.get_gui(e.player_index, "search")
if SearchGui then
SearchGui:toggle()
end
end
end)
local entity_type_to_gui_type = {
["infinity-container"] = defines.relative_gui_type.container_gui,
["linked-container"] = defines.relative_gui_type.container_gui,
["logistic-container"] = defines.relative_gui_type.container_gui,
}
local function get_opened_relative_gui_type(player)
local gui_type = player.opened_gui_type
local opened = player.opened
-- Attempt 1: Some GUIs can be converted straight from their gui_type
local straight_conversion = defines.relative_gui_type[table.find(defines.gui_type, gui_type) .. "_gui"]
if straight_conversion then
return { gui = straight_conversion }
end
-- Attempt 2: Specific logic
if gui_type == defines.gui_type.entity and opened.valid then
local gui = defines.relative_gui_type[string.gsub(opened.type or "", "%-", "_") .. "_gui"]
or entity_type_to_gui_type[opened.type]
if gui then
return { gui = gui, type = opened.type, name = opened.name }
end
end
if gui_type == defines.gui_type.item and opened and opened.valid then -- Sometimes items don't show up!?
if opened.object_name == "LuaEquipmentGrid" then
return { gui = defines.relative_gui_type.equipment_grid_gui }
else
local gui = defines.relative_gui_type[string.gsub(opened.type, "%-", "_") .. "_gui"]
or defines.relative_gui_type.item_with_inventory_gui
if gui then
return { gui = gui, type = opened.type, name = opened.name }
end
end
end
end
script.on_event({ "rb-search", "rb-open-selected" }, function(e)
local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
local player_table = global.players[e.player_index]
if player_table.flags.can_open_gui then
if e.input_name == "rb-open-selected" then
-- Open the selected prototype
local selected_prototype = e.selected_prototype
if selected_prototype then
-- Special case: Don't open selection tools if we're holding them
if
constants.ignored_cursor_inspection_types[selected_prototype.derived_type]
and player.cursor_stack
and player.cursor_stack.valid_for_read
and player.cursor_stack.name == selected_prototype.name
then
return
end
local class = constants.type_to_class[selected_prototype.derived_type]
or constants.type_to_class[selected_prototype.base_type]
-- Not everything will have a Recipe Book entry
if class then
local name = selected_prototype.name
local obj_data = database[class][name]
if obj_data then
local options
if player_table.settings.general.interface.open_info_relative_to_gui then
local id = player_table.guis.info._relative_id
if id then
options = { id = id }
else
-- Get the context of the current opened GUI
local anchor = get_opened_relative_gui_type(player)
if anchor then
anchor.position = defines.relative_gui_position.right
options = { parent = player.gui.relative, anchor = anchor }
end
end
end
local context = { class = class, name = name }
OPEN_PAGE(player, player_table, context, options)
return
end
end
-- If we're here, the selected object has no page in RB
player.create_local_flying_text({
text = { "message.rb-object-has-no-page" },
create_at_cursor = true,
})
player.play_sound({ path = "utility/cannot_build" })
return
end
else
--- @type SearchGui?
local SearchGui = util.get_gui(e.player_index, "search")
if SearchGui then
SearchGui:toggle()
end
end
else
player.print({ "message.rb-cannot-open-gui" })
player_table.flags.show_message_after_translation = true
end
end)
script.on_event(
{ "rb-navigate-backward", "rb-navigate-forward", "rb-return-to-home", "rb-jump-to-front", "rb-linked-focus-search" },
function(e)
local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
local player_table = global.players[e.player_index]
local opened = player.opened
if
player_table.flags.can_open_gui
and player.opened_gui_type == defines.gui_type.custom
and (not opened or (opened.valid and player.opened.name == "rb_search_window"))
then
local active_id = player_table.guis.info._active_id
if active_id then
--- @type InfoGui?
local InfoGui = util.get_gui(e.player_index, "info", active_id)
if InfoGui then
if e.input_name == "rb-linked-focus-search" then
InfoGui:dispatch({ action = "toggle_search" })
else
local event_properties = constants.nav_event_properties[e.input_name]
InfoGui:dispatch(
{ action = "navigate", delta = event_properties.delta },
{ player_index = e.player_index, shift = event_properties.shift }
)
end
end
end
end
end
)
-- PLAYER
script.on_event(defines.events.on_player_created, function(e)
player_data.init(e.player_index)
local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
local player_table = global.players[e.player_index]
player_data.refresh(player, player_table)
formatter.create_cache(e.player_index)
end)
script.on_event(defines.events.on_player_removed, function(e)
player_data.remove(e.player_index)
end)
-- TICK
script.on_event(defines.events.on_tick, function(e)
dictionary.on_tick()
local actions = on_tick_n.retrieve(e.tick)
if actions then
for _, msg in pairs(actions) do
if msg.gui then
handle_gui_action(msg, { player_index = msg.player_index })
elseif msg.action == "dump_database" then
-- game.table_to_json() does not like functions
local output = {}
for key, value in pairs(database) do
if type(value) ~= "function" then
output[key] = value
end
end
local func = msg.raw and serpent.dump or game.table_to_json
game.write_file("rb-dump", func(output), false, msg.player_index)
game.print("[color=green]Dumped database to script-output/rb-dump[/color]")
elseif msg.action == "refresh_all" then
dictionary.on_init()
database.build()
database.check_forces()
for player_index, player in pairs(game.players) do
local player_table = global.players[player_index]
player_data.refresh(player, player_table)
player_table.flags.show_message_after_translation = true
end
game.print("[color=green]Database refresh complete, retranslating dictionaries...[/color]")
end
end
end
end)
-- -----------------------------------------------------------------------------
-- REMOTE INTERFACE
remote.add_interface("RecipeBook", remote_interface)

View File

@ -1,5 +0,0 @@
require("prototypes.custom-input")
require("prototypes.font")
require("prototypes.shortcut")
require("prototypes.sprite")
require("prototypes.style")

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,15 +0,0 @@
{
"name": "RecipeBook",
"version": "3.5.7",
"title": "Recipe Book",
"author": "raiguard",
"description": "Search for information about entities, fluids, items, recipes, and technologies in a clean, easy-to-use interface. Similar to FNEI and What is it Really Used For.",
"contact": "https://github.com/raiguard/RecipeBook",
"homepage": "https://github.com/raiguard/RecipeBook",
"factorio_version": "1.1",
"dependencies": ["base >= 1.1.80", "flib >= 0.12.9"],
"package": {
"git_publish_branch": "master",
"ignore": ["imgui.ini", "resources", "screenshots"]
}
}

View File

@ -1,382 +0,0 @@
[command-help]
rb-refresh-all= - Reprocess the Recipe Book data, recreate all GUIs, and retranslate all dictionaries.
[controls]
rb-jump-to-front=Jump to front
rb-navigate-backward=Navigate backward
rb-navigate-forward=Navigate forward
rb-open-selected=Open selected object in Recipe Book
rb-return-to-home=Return to home
rb-search=Search Recipe Book
[entity-type]
accumulator=Accumulator
ammo-turret=Ammo turret
arithmetic-combinator=Arithmetic combinator
arrow=Arrow
artillery-flare=Artillery flare
artillery-projectile=Artillery projectile
artillery-turret=Artillery turret
artillery-wagon=Artillery wagon
assembling-machine=Assembling machine
beacon=Beacon
beam=Beam
boiler=Boiler
burner-generator=Burner generator
car=Car
cargo-wagon=Cargo wagon
character=Character
character-corpse=Character corpse
cliff=Cliff
combat-robot=Combat robot
constant-combinator=Constant combinator
construction-robot=Construction robot
container=Container
corpse=Corpse
curved-rail=Curved rail
decider-combinator=Decider combinator
deconstructible-tile-proxy=Deconstructible tile proxy
electric-energy-interface=Electric energy interface
electric-pole=Electric pole
electric-turret=Electric turret
entity-ghost=Entity ghost
explosion=Explosion
fire=Fire
fish=Fish
flame-thrower-explosion=Flame thrower explosion
fluid-turret=Fluid turret
fluid-wagon=Fluid wagon
flying-text=Flying text
furnace=Furnace
gate=Gate
generator=Generator
heat-interface=Heat interface
heat-pipe=Heat pipe
highlight-box=Highlight box
infinity-container=Infinity container
infinity-pipe=Infinity pipe
inserter=Inserter
item-entity=Item entity
item-request-proxy=Item request proxy
lab=Lab
lamp=Lamp
land-mine=Land mine
linked-belt=Linked belt
linked-container=Linked container
loader=Loader
loader-1x1=Loader (1x1)
locomotive=Locomotive
logistic-container=Logistic container
logistic-robot=Logistic robot
market=Market
mining-drill=Mining drill
offshore-pump=Offshore pump
particle-source=Particle source
pipe=Pipe
pipe-to-ground=Pipe to ground
player-port=Player port
power-switch=Power switch
programmable-speaker=Programmable speaker
projectile=Projectile
pump=Pump
radar=Radar
rail-chain-signal=Rail chain signal
rail-remnants=Rail remnants
rail-signal=Rail signal
reactor=Reactor
resource=Resource
roboport=Roboport
rocket-silo=Rocket silo
rocket-silo-rocket=Rocket silo rocket
rocket-silo-rocket-shadow=Rocket silo rocket shadow
simple-entity=Simple entity
simple-entity-with-force=Simple entity with force
simple-entity-with-owner=Simple entity with owner
smoke-with-trigger=Smoke with trigger
solar-panel=Solar panel
speech-bubble=Speech bubble
spider-leg=Spider leg
spider-vehicle=Spider vehicle
splitter=Splitter
sticker=Sticker
storage-tank=Storage tank
straight-rail=Straight rail
stream=Stream
tile-ghost=Tile ghost
train-stop=Train stop
transport-belt=Transport belt
tree=Tree
turret=Turret
underground-belt=Underground belt
unit=Unit
unit-spawner=Unit spawner
wall=Wall
[fuel-category-name]
burnable-fluid=Burnable fluid
[gui]
rb-accepted-equipment=Accepted equipment
rb-accepted-modules=Accepted modules
rb-add-to-favorites=Add to favorites
rb-affects-recipes=Affects recipes
rb-alt-click=Alt + click
rb-attach-search-results-description=If enabled, clicking a search result will open an info page attached to the search GUI. Furthermore, clicking another search result will open it in that same page.\nYou can use the middle mouse button to open a detached info window at any time.
rb-attach-search-results=Open search results in an attached info GUI
rb-base-pollution=Base pollution
rb-base-pollution-desc=The actual pollution rate may vary depending on the fluid burned.
rb-beacon=Beacon
rb-buffer-capacity=Buffer capacity
rb-burned-in=Burned in
rb-burnt-result=Burnt result
rb-burnt-result-of=Burnt result of
rb-can-burn=Can burn
rb-can-craft=Can craft
rb-can-mine=Can mine
rb-captions=Captions
rb-catalyst-abbrev=(C)
rb-catalyst-amount=Catalyst amount
rb-categories=Categories
rb-categories-description=Uncheck a category to hide its objects from search and information pages.\n[font=default-semibold]NOTE:[/font] Some objects will be shown regardless of these settings (i.e. recipe ingredients and products).
rb-category=Category
rb-change-search-type=Change search type
rb-charging-energy=Charging energy
rb-click=Click
rb-close-quick-ref-window=Close quick reference window
rb-close-search-gui-after-selection=Close search GUI after selection
rb-collapse=Collapse
rb-collapsed=Collapsed
rb-construction-radius=Construction radius
rb-content=Content
rb-control-click=Control + click
rb-crafter=Crafter
rb-crafting-time=Crafting time
rb-crafting-time-desc=How long it takes to make this recipe in a crafter with a crafting speed of 1.
rb-default-gui-type=Default GUI Type
rb-default-gui-type-description=[font=default-semibold]Textual:[/font] The standard Recipe Book search interface, geared towards compactness and searching by name. This search interface can show all object types.\n[font=default-semibold]Visual:[/font] A more "standard" search interface, prioritizing visual selection and icons. This search interface only shows items and fluids.\nThis is merely the default, you can swap between the two in the search GUI itself.
rb-default-gui-type-textual=Textual
rb-default-gui-type-visual=Visual
rb-default-state=Default state
rb-default-temperature=Default temperature
rb-delete-favorites=Delete favorites
rb-delete-history=Delete history
rb-detach-instruction=Detach information window
rb-disabled-abbrev=(D)
rb-distribution-effectivity=Distribution effectivity
rb-effect-area=Effect area
rb-energy-consumption=Energy consumption
rb-energy-per-shield-point=Energy per shield point
rb-energy-production=Energy production
rb-entities=Entities
rb-entity=Entity
rb-entity-type=Entity type
rb-equipment-categories=Equipment categories
rb-equipment-category=Equipment category
rb-equipment=Equipment
rb-equipment-properties=Equipment properties
rb-expand=Expand
rb-expected-resources=Expected resources
rb-favorites=Favorites
rb-fixed-recipe=Fixed recipe
rb-fluid-consumption=Fluid consumption
rb-fluid=Fluid
rb-fluids=Fluids
rb-format-amount=__1__ ×
rb-format-area=__1__×__2__
rb-format-seconds-parenthesis=(__1__ s)
rb-fuel-categories=Fuel categories
rb-fuel-category=Fuel category
rb-fuzzy-search-description=More lenient pattern matching for searches.\n[font=default-semibold]NOTE:[/font] After changing this setting, you will need to search again in order for the change to take effect.
rb-fuzzy-search=Fuzzy search
rb-gathered-from=Gathered from
rb-general=General
rb-generator=Generator
rb-get-blueprint=Get blueprint
rb-go-backward=Go backward
rb-go-forward=Go forward
rb-go-to-the-back=Go to the back
rb-go-to-the-front=Go to the front
rb-group=Group
rb-hidden-abbrev=(H)
rb-hidden=Hidden
rb-history=History
rb-ingredient-in=Ingredient in
rb-ingredient-limit=Ingredient limit
rb-ingredients=Ingredients
rb-inputs=Inputs
rb-interface=Interface
rb-item=Item
rb-items=Items
rb-item-type=Item type
rb-jump-to-back=Jump to the back
rb-jump-to-the-front=Jump to the front
rb-lab=Lab
rb-list-box-label=__1__ (__2__)
rb-logistic-radius=Logistic radius
rb-made-in=Made in
rb-max-energy-production=Max energy production
rb-maximum-temperature=Maximum temperature
rb-max-rows=Max rows
rb-middle-click=Middle click
rb-mined-by=Mined by
rb-mined-from=Mined from
rb-minimum-temperature=Minimum temperature
rb-mining-area=Mining area
rb-mining-drill=Mining drill
rb-mining-drills=Mining drills
rb-mining-speed=Mining speed
rb-mining-time=Mining time
rb-module-effects=Module effects
rb-module-slots=Module slots
rb-modules=Modules
rb-no-content-warning=[img=warning-white] Nothing to show based on current settings.
rb-no-results=[img=warning-white] No results.
rb-normal=Normal
rb-offshore-pump=Offshore pump
rb-open-info-relative-to-gui-description=When enabled, using the inspect hotkey on an object will show that object's info page relative to the currently open GUI. If no GUI is open, or the opened GUI does not support relative anchoring, it will open as a standalone window in the middle of the screen.
rb-open-info-relative-to-gui=Open info page relative to current GUI
rb-open-in-technology-window=Open in technology window
rb-open-list-in-new-window=Open this list in a new window.
rb-open-quick-ref-window=Open quick reference window
rb-pages=Pages
rb-per-second-suffix=/ s
rb-pin-instruction=Keep open
rb-place-as-equipment-result=Place as equipment result
rb-placed-by=Placed by
rb-placed-in=Placed in
rb-place-result=Place result
rb-pollution-multiplier=Pollution multiplier
rb-prerequisite-of=Prerequisite of
rb-prerequisites=Prerequisites
rb-product-of=Product of
rb-products=Products
rb-pumped-by=Pumped by
rb-recipe-categories=Recipe categories
rb-recipe-category=Recipe category
rb-recipe=Recipe
rb-recipes=Recipes
rb-remove-from-favorites=Remove from favorites
rb-required-fluid=Required fluid
rb-required-units=Required units
rb-researched-in=Researched in
rb-research-ingredients-per-unit=Research ingredients per unit
rb-researching-speed=Researching speed
rb-research-speed-desc=The lab's base research speed. Does not include force bonuses.
rb-resource-categories=Resource categories
rb-resource-category=Resource category
rb-resource=Resource
rb-resources=Resources
rb-right-click=Right click
rb-robot-limit=Robot limit
rb-rocket-launch-product-of=Rocket launch product of
rb-rocket-launch-products=Rocket launch products
rb-rocket-parts-required=Rocket parts required
rb-science-pack=Science pack
rb-search-filter=Search filters
rb-search-gui-location-center=Center
rb-search-gui-location-description=All GUIs in Recipe Book are draggable - this is just the default location. You can reset the location to default by middle-clicking the titlebar.
rb-search-gui-location=Search GUI location
rb-search-gui-location-top-left=Top-left
rb-search-instruction=Search (__CONTROL__focus-search__)
rb-search=Search
rb-search-title=Recipe Book
rb-search-type-both=Both
rb-search-type-description=[font=default-semibold]Localised:[/font] An object's translated name will be matched for search.\n[font=default-semibold]Internal:[/font] An object's internal prototype name will be matched for search.\n[font=default-semibold]Both:[/font] An object's prototype name and translated name will both be matched for search.
rb-search-type-internal=Internal
rb-search-type-localised=Localised
rb-search-type=Search type
rb-session-history=Session history
rb-settings-instruction=Settings
rb-settings=Recipe Book settings
rb-shield-points=Shield points
rb-shift-click=Shift + click
rb-show-alternate-name-description=Show the object's "alternate" name in its tooltip. By default, this will be the object's prototype name. If `show internal names` is enabled, this will be the object's translated name.
rb-show-alternate-name=Show alternate name
rb-show-descriptions=Show descriptions
rb-show-detailed-tooltips-description=Show various info about an object in its tooltip, sort of like a mini info page. Disable this to significantly improve overall performance.
rb-show-detailed-tooltips=Show detailed tooltips
rb-show-disabled-description="Disabled" objects are objects that exist, but are not selectable in-game under any circumstance.
rb-show-disabled=Show disabled objects
rb-show-fluid-temperatures-absolute-only=Absolute only
rb-show-fluid-temperatures-all=All
rb-show-fluid-temperatures-description=[font=default-semibold]Off:[/font] Fluid temperature variants will not be shown in search.\n[font=default-semibold]Absolute only:[/font] Only "absolute" (non-range) temperature variants will be shown in search.\n[font=default-semibold]All:[/font] All temperature variants will be shown in search.
rb-show-fluid-temperatures-off=Off
rb-show-fluid-temperatures=Show fluid temperatures
rb-show-glyphs=Show glyphs
rb-show-hidden-description="Hidden" objects are objects that will not show up in regular selection lists, but can still be interacted with in other ways.\n[font=default-semibold]NOTE:[/font] Some hidden objects will be shown regardless of this setting (i.e. recipe ingredients and products).
rb-show-hidden=Show hidden objects
rb-show-interaction-helps=Show interaction helps
rb-show-internal-names-description=Show an object's internal prototype name instead of its translated name.\nIf `show alternate name` is enabled, the object's translated name will be shown in its tooltip.
rb-show-internal-names=Show internal names
rb-show-made-in-in-quick-ref=Show "made in" in quick reference GUI
rb-show-unresearched=Show unresearched objects
rb-size=Size
rb-stack-size=Stack size
rb-take-result=Take result
rb-tech-level-desc=The level of this infinite technology to show data for.
rb-tech-level=Level
rb-technology=Technology
rb-temperatures=Temperature variants
rb-time-per-unit-desc=How long it takes to research one unit in a lab with a research speed of 1.
rb-time-per-unit=Time per unit
rb-toggle-completed=Toggle completed
rb-tooltips=Tooltips
rb-unlocked-by=Unlocked by
rb-unlocks-entities=Unlocks entities
rb-unlocks-equipment=Unlocks equipment
rb-unlocks-fluids=Unlocks fluids
rb-unlocks-items=Unlocks items
rb-unlocks-recipes=Unlocks recipes
rb-unresearched=Unresearched
rb-view-base-fluid=View base fluid
rb-view-details-in-new-window=View details in new window
rb-view-details=View details
rb-view-fixed-recipe=View fixed recipe
rb-view-fluid=View fluid
rb-view-ingredient-in=View ingredient in
rb-view-product-details=View product details
rb-view-product-of=View product of
rb-view-required-fluid=View required fluid
[item-name]
rb-crafter-blueprint=Temporary crafter blueprint
[item-type]
ammo=Ammo
armor=Armor
blueprint=Blueprint
blueprint-book=Blueprint book
capsule=Capsule
copy-paste-tool=Copy paste tool
deconstruction-item=Deconstruction item
gun=Gun
item=Item
item-with-entity-data=Item with entity data
item-with-inventory=Item with inventory
item-with-label=Item with label
item-with-tags=Item with tags
mining-tool=Mining tool (migration only)
module=Module
rail-planner=Rail planner
repair-tool=Repair tool
selection-tool=Selection tool
spidertron-remote=Spidertron remote
tool=Tool
upgrade-item=Upgrade item
[message]
rb-cannot-create-blueprint=Cannot create blueprint.
rb-cannot-open-gui=Cannot open Recipe Book yet, please wait. If this persists for more than a few minutes, run the [color=128, 206, 240]/rb-refresh-all[/color] command.
rb-can-open-gui=Recipe Book is now available!
rb-invalid-command=Invalid command, type [color=128, 206, 240]/help RecipeBook[/color] to see available commands.
rb-memoizer-cache-cleared=Memoizer cache cleared.
rb-object-has-no-page=Object has no page in the Recipe Book
[mod-description]
RecipeBook=Search for information about entities, fluids, items, recipes, and technologies in a clean, easy-to-use interface. Similar to FNEI and What is it Really Used For.
[mod-name]
RecipeBook=Recipe Book
[shortcut-name]
rb-search=Search Recipe Book

View File

@ -1,6 +0,0 @@
{
"language-name": "English",
"font": {
"RecipeBook": ["__RecipeBook__/fonts/RecipeBook.ttf"]
}
}

View File

@ -1,384 +0,0 @@
[command-help]
rb-refresh-all=- Заново обработать данные Книги рецептов, пересоздать все интерфейсы и перевести словари.
[controls]
rb-jump-to-front=Перейти в начало
rb-navigate-backward=Назад
rb-navigate-forward=Вперёд
rb-open-selected=Открыть выбранный объект в Книге рецептов
rb-return-to-home=Домой
rb-search=Поиск в Книге рецептов
[entity-type]
accumulator=Аккумулятор
ammo-turret=Турель с боеприпасами
arithmetic-combinator=Арифметический комбинатор
arrow=Стрелка
artillery-flare=Артиллерийская вспышка
artillery-projectile=Артиллерийский снаряд
artillery-turret=Артиллерийская установка
artillery-wagon=Артиллерийский вагон
assembling-machine=Сборочный автомат
beacon=Маяк
beam=Луч
boiler=Бойлер
burner-generator=Твердотопливный генератор
car=Автомобиль
cargo-wagon=Грузовой вагон
character=Персонаж
character-corpse=Труп персонажа
cliff=Скала
combat-robot=Боевой дрон
constant-combinator=Постоянный комбинатор
construction-robot=Строительный дрон
container=Контейнер
corpse=Труп
curved-rail=Изогнутые рельсы
decider-combinator=Сравнивающий комбинатор
deconstructible-tile-proxy=Представление разбираемого тайла
electric-energy-interface=Интерфейс электроэнергии
electric-pole=Опора ЛЭП
electric-turret=Электрическая турель
entity-ghost=Призрак объекта
explosion=Взрыв
fire=Огонь
fish=Рыба
flame-thrower-explosion=Огнемётный взрыв
fluid-turret=Жидкостная турель
fluid-wagon=Вагон-цистерна
flying-text=Летающий текст
furnace=Печь
gate=Ворота
generator=Генератор
heat-interface=Тепловой интерфейс
heat-pipe=Тепловая трубка
highlight-box=Прямоугольник выделения
infinity-container=Бесконечный контейнер
infinity-pipe=Бесконечная труба
inserter=Манипулятор
item-entity=Сущность предмета
item-request-proxy=Представление запроса предметов
lab=Лаборатория
lamp=Лампа
land-mine=Мина
linked-belt=Связанный конвейер
linked-container=Связанный контейнер
loader=Погрузчик
loader-1x1=Погрузчик (1х1)
locomotive=Локомотив
logistic-container=Логистический контейнер
logistic-robot=Транспортный дрон
market=Рынок
mining-drill=Бур
offshore-pump=Прибрежный насос
particle-source=Источник частиц
pipe=Труба
pipe-to-ground=Подземная труба
player-port=Порт игрока
power-switch=Выключатель
programmable-speaker=Программируемый динамик
projectile=Снаряд
pump=Помпа
radar=Радар
rail-chain-signal=Проходной светофор
rail-remnants=Обломки рельсов
rail-signal=Светофор
reactor=Реактор
resource=Ресурс
roboport=Дронстанция
rocket-silo=Ракетная шахта
rocket-silo-rocket=Ракета в ракетной шахте
rocket-silo-rocket-shadow=Тень ракеты в ракетной шахте
simple-entity=Простая сущность
simple-entity-with-force=Простая сущность, принадлежащая команде (силе)
simple-entity-with-owner=Простая сущность, имеющая владельца
smoke-with-trigger=Дым с триггером
solar-panel=Солнечная панель
speech-bubble=Пузырь с текстом
spider-leg=Нога паука
spider-vehicle=Транспорт паука
splitter=Разделитель
sticker=Наклейка
storage-tank=Резервуар
straight-rail=Прямые рельсы
stream=Поток
tile-ghost=Призрак тайла
train-stop=Железнодорожная станция
transport-belt=Конвейер
tree=Дерево
turret=Турель
underground-belt=Подземный конвейер
unit=Юнит
unit-spawner=Породитель юнитов
wall=Стена
[fuel-category-name]
burnable-fluid=Сжигаемая жидкость
[gui]
rb-accepted-equipment=Подходящее оборудование
rb-accepted-modules=Подходящие модули
rb-add-to-favorites=Добавить в избранное
rb-affects-recipes=Влияет на рецепты
rb-alt-click=Alt + щелчок
rb-attach-search-results-description=Если включено, то при нажатии на результат поиска откроется информационная страница, прикреплённая к окну поиска. Более того, щёлкнув другой результат поиска, вы откроете его на той же странице.\nВы можете использовать среднюю кнопку мыши, чтобы открыть отдельное информационное окно в любое время.
rb-attach-search-results=Открыть результаты поиска в прикреплённом окне интерфейса
rb-base-pollution=Базовое загрязнение
rb-base-pollution-desc=Актуальный уровень загрязнения может сильно различаться в зависимости от сжигаемой жидкости.
rb-beacon=Маяк
rb-buffer-capacity=Ёмкость буфера
rb-burned-in=Сжигается в
rb-burnt-result=Результат сжигания
rb-burnt-result-of=Результат сжигания
rb-can-burn=Можно сжигать
rb-can-craft=Можно создавать
rb-can-mine=Можно добывать
rb-captions=Заголовки
rb-catalyst-abbrev=(К)
rb-catalyst-amount=Количество катализатора
rb-categories=Категории
rb-categories-description=Снимите отметку с категории, чтобы скрыть её объекты с поисковых и информационных страниц.\n[font=default-semibold]ПРИМЕЧАНИЕ:[/font] Некоторые объекты будут отображаться независимо от этих настроек (например, ингредиенты рецепта и продукты).
rb-category=Категория
rb-change-search-type=Изменить тип поиска
rb-charging-energy=Энергия зарядки
rb-click=Щелчок
rb-close-quick-ref-window=Закрыть окно краткой информации
rb-close-search-gui-after-selection=Закрыть интерфейс поиска после выбора
rb-collapse=Свернуть
rb-collapsed=Свёрнуто
rb-construction-radius=Радиус строительства
rb-content=Содержимое
rb-control-click=Control + щелчок
rb-crafter=Сборщик
rb-crafting-time=Время создания
rb-crafting-time-desc=Сколько времени нужно, чтобы приготовить этот рецепт в сборщике со скоростью изготовления 1.
rb-default-gui-type=Тип интерфейса по умолчанию
rb-default-gui-type-description=[font=default-semibold]Текстовый:[/font] Стандартный интерфейс Книги рецептов, настроенный на компактность и поиск по имени. Этот интерфейс поиска может отображать все типы объектов.\n[font=default-semibold]Визуальный:[/font] Более "обычный" интерфейс поиска, основанный на визуальном выборе и значках. Этот интерфейс поиска показывает только предметы и жидкости.\nЭто всего лишь значение по умолчанию, вы можете переключаться между ними в самом графическом интерфейсе поиска.
rb-default-gui-type-textual=Текстовый
rb-default-gui-type-visual=Визуальный
rb-default-state=Состояние по умолчанию
rb-default-temperature=Температура по умолчанию
rb-delete-favorites=Удалить избранное
rb-delete-history=Удалить историю
rb-detach-instruction=Открепить информационное окно
rb-disabled-abbrev=(О)
rb-distribution-effectivity=Эффективность распределения
rb-effect-area=Область эффекта
rb-energy-consumption=Энергопотребление
rb-energy-per-shield-point=Энергии на единицу щита
rb-energy-production=Производство энергии
rb-entities=Сущности
rb-entity=Сущность
rb-entity-type=Тип сущности
rb-equipment-categories=Категории оборудования
rb-equipment-category=Категория оборудования
rb-equipment=Оборудование
rb-equipment-properties=Параметры оборудования
rb-expand=Развернуть
rb-expected-resources=Ожидаемые ресурсы
rb-favorites=Избранное
rb-fixed-recipe=Исправленный рецепт
rb-fluid-consumption=Потребление жидкости
rb-fluid=Жидкость
rb-fluids=Жидкости
rb-format-amount=__1__ ×
rb-format-area=__1__×__2__
rb-format-seconds-parenthesis=(__1__ с)
rb-fuel-categories=Категории топлива
rb-fuel-category=Категория топлива
rb-fuzzy-search-description=Более мягкое сопоставление с шаблоном для поиска.\n[font=default-semibold]ПРИМЕЧАНИЕ:[/font] После изменения этого параметра вам нужно будет снова выполнить поиск, чтобы изменение вступило в силу.
rb-fuzzy-search=Нечёткий поиск
rb-gathered-from=Добывается из
rb-general=Основное
rb-generator=Генератор
rb-get-blueprint=Получить чертёж
rb-go-backward=Назад
rb-go-forward=Вперёд
rb-go-to-the-back=Перейти назад
rb-go-to-the-front=Перейти вперёд
rb-group=Группа
rb-hidden-abbrev=(С)
rb-hidden=Скрыто
rb-history=История
rb-ingredient-in=Ингредиент в
rb-ingredient-limit=Предел ингредиента
rb-ingredients=Ингредиенты
rb-inputs=Входы
rb-interface=Интерфейс
rb-item=Предмет
rb-items=Предметы
rb-item-type=Тип предмета
rb-jump-to-back=Перейти в конец
rb-jump-to-the-front=Перейти в начало
rb-lab=Лаборатория
rb-list-box-label=__1__ (__2__)
rb-logistic-radius=Радиус логистики
rb-made-in=Создаётся в
rb-max-energy-production=Макс. производство электроэнергии
rb-maximum-temperature=Макс. температура
rb-max-rows=Макс. строк
rb-middle-click=СКМ
rb-mined-by=Добывается с помощью
rb-mined-from=Добывается из
rb-minimum-temperature=Мин. температура
rb-mining-area=Область добычи
rb-mining-drill=Бур
rb-mining-drills=Буры
rb-mining-speed=Скорость добычи
rb-mining-time=Время добычи
rb-module-effects=Эффекты модулей
rb-module-slots=Ячейки модулей
rb-modules=Модули
rb-no-content-warning=[img=warning-white] Нечего показывать при текущих настройках.
rb-no-results=[img=warning-white] Нет результатов.
rb-normal=Обычный
rb-offshore-pump=Прибрежный насос
rb-open-info-relative-to-gui-description=Если этот параметр включен, использование горячей клавиши "Проверка" на объекте будет отображать информационную страницу этого объекта относительно текущего открытого графического интерфейса. Если графический интерфейс не открыт или открытый графический интерфейс не поддерживает относительную привязку, он откроется как отдельное окно в середине экрана.
rb-open-info-relative-to-gui=Открыть информационную страницу относительно текущего графического интерфейса
rb-open-in-technology-window=Открыть в окне технологий
rb-open-list-in-new-window=Открыть этот список в новом окне.
rb-open-quick-ref-window=Открыть окно краткой информации
rb-pages=Страницы
rb-per-second-suffix=/ с
rb-pin-instruction=Держать открытым
rb-place-as-equipment-result=Разместить как итоговое оборудование
rb-placed-by=Чем размещается
rb-placed-in=Размещается в
rb-place-result=Результат размещения
rb-pollution-multiplier=Множитель загрязнения
rb-prerequisite-of=Предварительно для
rb-prerequisites=Предварительные
rb-product-of=Продукция по
rb-products=Продукция
rb-pumped-by=Чем перекачивается
rb-recipe-categories=Категории рецепта
rb-recipe-category=Категория рецепта
rb-recipe=Рецепт
rb-recipes=Рецепты
rb-remove-from-favorites=Удалить из избранного
rb-required-fluid=Требуемая жидкость
rb-required-units=Требуемые предметы
rb-researched-in=Исследуется в
rb-research-ingredients-per-unit=Исследовательских ингредиентов на предмет
rb-researching-speed=Скорость исследования
rb-research-speed-desc=Базовая скорость исследования лабораторий. Не включает бонусы ускорения.
rb-resource-categories=Категории ресурса
rb-resource-category=Категория ресурса
rb-resource=Ресурс
rb-resources=Ресурсы
rb-right-click=ПКМ
rb-robot-limit=Лимит дронов
rb-rocket-launch-product-of=Результат запуска ракеты с
rb-rocket-launch-products=Результат запуска ракеты
rb-rocket-parts-required=Требуется частей ракеты
rb-science-pack=Исследовательский пакет
rb-search-filter=Фильтры поиска
rb-search-gui-location-center=Центр
rb-search-gui-location-description=Все окна мода можно перетаскивать - это просто расположение по умолчанию. Вы можете восстановить местоположение по умолчанию, щелкнув средней кнопкой мыши по строке заголовка.
rb-search-gui-location=Расположение окна поиска
rb-search-gui-location-top-left=Наверху слева
rb-search-instruction=Поиск (__CONTROL__focus-search__)
rb-search=Поиск
rb-search-title=Книга рецептов
rb-search-type-both=Оба
rb-search-type-description=[font=default-semibold]Локализованное:[/font] Переведённое название объекта будет использовано для поиска.\n[font=default-semibold]Внутреннее: [/font] Внутреннее название прототипа объекта будет использовано для поиска.\n[font=default-semibold]Оба:[/font] Название прототипа объекта и переведённое название будут использованы для поиска.
rb-search-type-internal=Внутреннее
rb-search-type-localised=Локализованное
rb-search-type=Тип поиска
rb-session-history=История сессии
rb-settings-instruction=Настройки
rb-settings=Настройки Recipe Book
rb-shield-points=Единицы щита
rb-shift-click=Shift + щелчок
rb-show-alternate-name-description=Показывать "альтернативное" название объекта во всплывающей подсказке. По умолчанию это будет название прототипа объекта. Если включен параметр "показывать внутренние названия", это будет переведённое название объекта.
rb-show-alternate-name=Показывать альтернативное название
rb-show-descriptions=Показывать описания
rb-show-detailed-tooltips-description=Показывать различную информацию об объекте во всплывающей подсказке, вроде мини-информационной страницы. Отключите это, чтобы значительно улучшить общую производительность.
rb-show-detailed-tooltips=Показывать подробные подсказки
rb-show-disabled-description="Отключённые" объекты - это объекты, которые существуют, но не могут быть выбраны в игре ни при каких обстоятельствах.
rb-show-disabled=Показывать отключённые объекты
rb-show-fluid-temperatures-absolute-only=Только абсолютные
rb-show-fluid-temperatures-all=Все
rb-show-fluid-temperatures-description=[font=default-semibold]Выключено:[/font] Варианты температуры жидкости не будут отображаться в поиске.\n[font=default-semibold]Только абсолютные:[/font] Только «абсолютные» (не диапазоны) варианты температуры будут отображаться в поиске.\n[font=default-semibold]Все:[/font] Все варианты температуры будут показаны в поиске.
rb-show-fluid-temperatures-off=Выключено
rb-show-fluid-temperatures=Показывать температуры жидкости
rb-show-glyphs=Показывать иконки
rb-show-hidden-description="Скрытые" объекты - это объекты, которые не будут отображаться в обычных списках выбора, но с ними можно взаимодействовать другими способами.\n[font=default-semibold]ПРИМЕЧАНИЕ:[/font] Некоторые скрытые объекты будут отображаться независимо от этой настройки (например, ингредиенты и продукция рецепта).
rb-show-hidden=Показывать скрытые объекты
rb-show-interaction-helps=Показывать интерактивные подсказки
rb-show-internal-names-description=Показывать внутреннее название прототипа объекта вместо его переведённого названия.\nЕсли включен параметр "Показывать альтернативное название", переведённое имя объекта будет отображаться во всплывающей подсказке.
rb-show-internal-names=Показывать внутреннее название
rb-show-made-in-in-quick-ref=Показывать "создаётся в" в окне краткой информации
rb-show-unresearched=Показывать неисследованные объекты
rb-size=Размер
rb-stack-size=Размер пачки
rb-take-result=Взять результат
rb-tech-level-desc=Уровень этой бесконечной технологии, для которой нужно показать данные.
rb-tech-level=Уровень
rb-technology=Технология
rb-temperatures=Варианты температуры
rb-time-per-unit-desc=Сколько времени нужно на исследование единицы в лаборатории со скоростью исследования 1.
rb-time-per-unit=Времени на единицу
rb-toggle-completed=Переключить завершённое
rb-tooltips=Подсказки
rb-unlocked-by=Разблокируется этим
rb-unlocks-entities=Разблокирует сущности
rb-unlocks-equipment=Разблокирует оборудование
rb-unlocks-fluids=Разблокирует жидкости
rb-unlocks-items=Разблокирует предметы
rb-unlocks-recipes=Разблокирует рецепты
rb-unresearched=Неисследовано
rb-view-base-fluid=Посмотреть основную жидкость
rb-view-details-in-new-window=Посмотреть подробности в новом окне
rb-view-details=Посмотреть подробности
rb-view-fixed-recipe=Посмотреть исправленный рецепт
rb-view-fluid=Посмотреть жидкость
rb-view-ingredient-in=Посмотреть ингредиент в
rb-view-product-details=Просмотр сведений о продукте
rb-view-product-of=Посмотреть продукцию из
rb-view-required-fluid=Посмотреть требуемую жидкость
[item-name]
rb-crafter-blueprint=Временный чертёж сборщика
[item-type]
ammo=Боеприпасы
armor=Броня
blueprint=Чертёж
blueprint-book=Книга чертежей
capsule=Капсула
copy-paste-tool=Средство копирования/вставки
deconstruction-item=Предмет разборки
gun=Оружие
item=Предмет
item-with-entity-data=Предмет с данными сущности
item-with-inventory=Предмет с инвентарём
item-with-label=Предмет с ярлыком
item-with-tags=Предмет с тэгами
mining-tool=Инструмент добычи (только миграция)
module=Модуль
rail-planner=Планировщик рельсов
repair-tool=Средство ремонта
selection-tool=Средство выбора
spidertron-remote=Пульт управления паукотроном
tool=Средство
upgrade-item=Предмет улучшения
[message]
rb-cannot-create-blueprint=Невозможно создать чертёж.
rb-cannot-open-gui=Невозможно открыть Книгу рецептов, подождите. Если так продолжается более нескольких минут, запустите команду [color=128, 206, 240]/rb-refresh-all[/color].
rb-can-open-gui=Книга рецептов теперь доступна!
rb-invalid-command=Неверная команда, наберите [color=128, 206, 240]/help RecipeBook[/color] для просмотра доступных команд.
rb-memoizer-cache-cleared=Кэш memoizer очищен.
rb-object-has-no-page=У объекта нет страницы в Книге рецептов
[mod-description]
RecipeBook=Ищите информацию о сущностях, жидкостях, предметах, рецептах и технологиях в понятном и лёгком в использовании интерфейсе. Похож на FNEI и What is it Really Used For.
[mod-name]
RecipeBook=Recipe Book (Книга рецептов)
[shortcut-name]
rb-search=Поиск в Книге рецептов

View File

@ -1,6 +0,0 @@
{
"language-name": "Russian",
"font": {
"RecipeBook": ["__RecipeBook__/fonts/RecipeBook.ttf"]
}
}

View File

@ -1,51 +0,0 @@
[command-help]
[controls]
[entity-type]
artillery-turret=Артилерійська вежа
artillery-wagon=Артилерійський вагон
container=Контейнер
loader=Навантажувач
pipe=Труба
radar=Радар
rocket-silo=Ракетна шахта
unit=Одиниця
[fuel-category-name]
[gui]
rb-entity=Сутність
rb-fluid=Рідина
rb-group=Група
rb-hidden=Прихований
rb-history=Історія
rb-item=Товар
rb-items=Предмети
rb-list-box-label=__1__ (__2__)
rb-modules=Модулі
rb-pin-instruction=Тримати відкритим
rb-recipe=Рецепт
rb-resources=Ресурси
rb-search-type-both=Обидва
rb-search-type-internal=Внутрішній
rb-settings-instruction=Налаштування
rb-show-fluid-temperatures-all=Всі
rb-show-fluid-temperatures-off=Вим
rb-tech-level=Рівень
[item-name]
[item-type]
item=Товар
module=Модуль
[message]
[mod-description]
[mod-name]
[shortcut-name]

View File

@ -1,40 +0,0 @@
data:extend({
{
type = "custom-input",
name = "rb-open-selected",
key_sequence = "ALT + mouse-button-1",
include_selected_prototype = true,
},
{
type = "custom-input",
name = "rb-search",
key_sequence = "CONTROL + B",
include_selected_prototype = true,
},
{
type = "custom-input",
name = "rb-navigate-backward",
key_sequence = "mouse-button-4",
},
{
type = "custom-input",
name = "rb-navigate-forward",
key_sequence = "mouse-button-5",
},
{
type = "custom-input",
name = "rb-return-to-home",
key_sequence = "SHIFT + mouse-button-4",
},
{
type = "custom-input",
name = "rb-jump-to-front",
key_sequence = "SHIFT + mouse-button-5",
},
{
type = "custom-input",
name = "rb-linked-focus-search",
key_sequence = "",
linked_game_control = "focus-search",
},
})

View File

@ -1,9 +0,0 @@
data:extend({
{
type = "font",
name = "RecipeBook",
from = "RecipeBook",
size = 12,
filtered = true,
},
})

View File

@ -1,15 +0,0 @@
local data_util = require("__flib__.data-util")
data:extend({
{
type = "shortcut",
name = "rb-search",
action = "lua",
icon = data_util.build_sprite(nil, { 0, 0 }, "__RecipeBook__/graphics/shortcut.png", 32, 2),
small_icon = data_util.build_sprite(nil, { 0, 32 }, "__RecipeBook__/graphics/shortcut.png", 24, 2),
disabled_icon = data_util.build_sprite(nil, { 48, 0 }, "__RecipeBook__/graphics/shortcut.png", 32, 2),
disabled_small_icon = data_util.build_sprite(nil, { 36, 32 }, "__RecipeBook__/graphics/shortcut.png", 24, 2),
toggleable = true,
associated_control_input = "rb-search",
},
})

View File

@ -1,40 +0,0 @@
local data_util = require("__flib__.data-util")
local frame_action_icons = "__RecipeBook__/graphics/frame-action-icons.png"
local tool_icons = "__RecipeBook__/graphics/tool-icons.png"
local small_tool_icons = "__RecipeBook__/graphics/small-tool-icons.png"
data:extend({
-- Frame action icons
data_util.build_sprite("rb_nav_backward_black", { 0, 0 }, frame_action_icons, 32),
data_util.build_sprite("rb_nav_backward_white", { 32, 0 }, frame_action_icons, 32),
data_util.build_sprite("rb_nav_backward_disabled", { 64, 0 }, frame_action_icons, 32),
data_util.build_sprite("rb_nav_forward_black", { 0, 32 }, frame_action_icons, 32),
data_util.build_sprite("rb_nav_forward_white", { 32, 32 }, frame_action_icons, 32),
data_util.build_sprite("rb_nav_forward_disabled", { 64, 32 }, frame_action_icons, 32),
data_util.build_sprite("rb_pin_black", { 0, 64 }, frame_action_icons, 32),
data_util.build_sprite("rb_pin_white", { 32, 64 }, frame_action_icons, 32),
data_util.build_sprite("rb_settings_black", { 0, 96 }, frame_action_icons, 32),
data_util.build_sprite("rb_settings_white", { 32, 96 }, frame_action_icons, 32),
data_util.build_sprite("rb_expand_black", { 0, 128 }, frame_action_icons, 32),
data_util.build_sprite("rb_expand_white", { 32, 128 }, frame_action_icons, 32),
data_util.build_sprite("rb_detach_black", { 0, 160 }, frame_action_icons, 32),
data_util.build_sprite("rb_detach_white", { 32, 160 }, frame_action_icons, 32),
-- Tool icons
data_util.build_sprite("rb_favorite_black", { 0, 0 }, tool_icons, 32, 2),
data_util.build_sprite("rb_clipboard_black", { 0, 32 }, tool_icons, 32, 2),
data_util.build_sprite("rb_fluid_black", { 0, 64 }, tool_icons, 32, 2),
data_util.build_sprite("rb_technology_gui_black", { 0, 96 }, tool_icons, 32, 2),
data_util.build_sprite("rb_list_nav_backward_black", { 0, 128 }, tool_icons, 32, 2),
data_util.build_sprite("rb_list_nav_forward_black", { 0, 160 }, tool_icons, 32, 2),
data_util.build_sprite("rb_export_black", { 0, 192 }, tool_icons, 32, 2),
data_util.build_sprite("rb_collapsed", { 0, 224 }, tool_icons, 32, 2),
data_util.build_sprite("rb_expanded", { 0, 256 }, tool_icons, 32, 2),
data_util.build_sprite("rb_filter", { 0, 288 }, tool_icons, 32, 2),
data_util.build_sprite("rb_swap", { 0, 320 }, tool_icons, 32, 2),
-- Small tool icons
data_util.build_sprite("rb_plus_black", { 0, 0 }, small_tool_icons, 16, 2),
data_util.build_sprite("rb_minus_black", { 0, 16 }, small_tool_icons, 16, 2),
-- Slot button icons
data_util.build_sprite("rb_favorite_slot", { 0, 0 }, "__RecipeBook__/graphics/favorite-slot-button-icon.png", 32, 1),
})

View File

@ -1,364 +0,0 @@
local constants = require("constants")
local styles = data.raw["gui-style"].default
styles.rb_list_box_item = {
type = "button_style",
parent = "list_box_item",
left_padding = 4,
right_padding = 4,
horizontally_squashable = "on",
horizontally_stretchable = "on",
disabled_graphical_set = styles.list_box_item.default_graphical_set,
disabled_font_color = styles.list_box_item.default_font_color,
}
styles.rb_last_selected_list_box_item = {
type = "button_style",
parent = "rb_list_box_item",
default_font_color = constants.colors.yellow.tbl,
disabled_font_color = constants.colors.yellow.tbl,
}
styles.rb_unresearched_list_box_item = {
type = "button_style",
parent = "rb_list_box_item",
default_font_color = constants.colors.unresearched.tbl,
disabled_font_color = constants.colors.unresearched.tbl,
}
styles.rb_table_button = {
type = "button_style",
parent = "rb_list_box_item",
horizontally_stretchable = "off",
horizontally_squashable = "off",
top_margin = -3,
right_margin = -8,
bottom_margin = -5,
left_margin = -8,
}
styles.rb_filter_group_button_tab = {
type = "button_style",
parent = "filter_group_button_tab",
width = 0,
horizontally_stretchable = "on",
disabled_graphical_set = styles.button.selected_graphical_set,
}
styles.rb_disabled_filter_group_button_tab = {
type = "button_style",
parent = "filter_group_button_tab",
width = 0,
horizontally_stretchable = "on",
draw_grayscale_picture = true,
default_graphical_set = styles.filter_group_button_tab.disabled_graphical_set,
hovered_graphical_set = styles.filter_group_button_tab.disabled_graphical_set,
clicked_graphical_set = styles.filter_group_button_tab.disabled_graphical_set,
}
-- FLOW STYLES
styles.rb_main_frame_flow = {
type = "horizontal_flow_style",
horizontal_spacing = 12,
}
styles.rb_main_info_pane_flow = {
type = "vertical_flow_style",
vertical_spacing = 8,
}
styles.rb_quick_ref_content_flow = {
type = "vertical_flow_style",
bottom_padding = 12,
left_padding = 12,
right_padding = 0,
top_padding = 6,
}
styles.rb_search_content_flow = {
type = "vertical_flow_style",
padding = 12,
top_padding = 8,
vertical_spacing = 10,
}
styles.rb_warning_flow = {
type = "vertical_flow_style",
padding = 12,
horizontal_align = "center",
vertical_align = "center",
vertical_spacing = 8,
horizontally_stretchable = "on",
vertically_stretchable = "on",
}
-- FRAME STYLES
styles.rb_main_info_frame = {
type = "frame_style",
parent = "inside_shallow_frame",
width = 450,
}
styles.rb_search_results_frame = {
type = "frame_style",
parent = "deep_frame_in_shallow_frame",
height = 28 * 18,
width = 250,
horizontally_stretchable = "on",
}
styles.rb_search_results_subheader_frame = {
type = "frame_style",
parent = "subheader_frame",
height = 28,
horizontally_stretchable = "on",
horizontal_flow_style = {
type = "horizontal_flow_style",
horizontal_align = "center",
},
}
styles.rb_subheader_frame = {
type = "frame_style",
parent = "subheader_frame",
height = 0, -- Negate the height requirement
minimal_height = 36,
}
styles.rb_quick_ref_content_frame = {
type = "frame_style",
parent = "inside_shallow_frame",
width = 224,
}
styles.rb_slot_table_frame = {
type = "frame_style",
parent = "slot_button_deep_frame",
maximal_height = 200,
natural_height = 40,
width = 40 * 5,
}
styles.rb_settings_category_frame = {
type = "frame_style",
parent = "bordered_frame",
horizontally_stretchable = "on",
right_padding = 8,
}
styles.rb_inside_warning_frame = {
type = "frame_style",
parent = "inside_shallow_frame",
graphical_set = {
base = {
position = { 17, 0 },
corner_size = 8,
center = { position = { 411, 25 }, size = { 1, 1 } },
draw_type = "outer",
},
shadow = default_inner_shadow,
},
}
styles.rb_warning_frame_in_shallow_frame = {
type = "frame_style",
parent = "deep_frame_in_shallow_frame",
graphical_set = {
base = {
position = { 85, 0 },
corner_size = 8,
center = { position = { 411, 25 }, size = { 1, 1 } },
draw_type = "outer",
},
shadow = default_inner_shadow,
},
}
styles.rb_inside_deep_frame_under_tabs = {
type = "frame_style",
parent = "invisible_frame",
graphical_set = {
base = {
center = { position = { 42, 8 }, size = { 1, 1 } },
top = { position = { 93, 0 }, size = { 1, 8 } },
draw_type = "outer",
},
shadow = {
top = { position = { 191, 128 }, size = { 1, 8 } },
tint = hard_shadow_color,
scale = 0.5,
draw_type = "inner",
},
},
}
styles.rb_filter_frame = {
type = "frame_style",
parent = "filter_frame",
horizontally_stretchable = "on",
bottom_padding = 8,
top_padding = 8,
left_padding = 13,
width = 426,
}
-- LABEL STYLES
styles.rb_hyperlink_label = {
type = "label_style",
-- parent = "hyperlink_label",
font_color = { 110, 179, 255 },
hovered_font_color = { 154, 250, 255 },
}
styles.rb_table_label = {
type = "label_style",
font = "default-semibold",
horizontally_stretchable = "on",
}
styles.rb_toolbar_label = {
type = "label_style",
parent = "subheader_caption_label",
-- left_padding = 4,
horizontally_squashable = "on",
}
styles.rb_unresearched_toolbar_label = {
type = "label_style",
parent = "rb_toolbar_label",
font_color = constants.colors.unresearched.tbl,
}
styles.rb_slot_label = {
type = "label_style",
parent = "count_label",
height = 36,
width = 35,
vertical_align = "bottom",
horizontal_align = "right",
right_padding = 3,
}
styles.rb_slot_label_top = {
type = "label_style",
parent = "rb_slot_label",
vertical_align = "top",
top_padding = 3,
}
styles.rb_list_box_label = {
type = "label_style",
parent = "bold_label",
bottom_padding = 2,
}
-- LINE STYLES
styles.rb_dark_line = {
type = "line_style",
horizontally_stretchable = "on",
left_margin = -8,
right_margin = -8,
top_margin = -2,
bottom_margin = -2,
border = {
border_width = 8,
horizontal_line = { filename = "__RecipeBook__/graphics/dark-line.png", size = { 1, 8 } },
},
}
-- SCROLL PANE STYLES
styles.rb_list_box_scroll_pane = {
type = "scroll_pane_style",
parent = "list_box_scroll_pane",
graphical_set = {
shadow = default_inner_shadow,
},
vertical_flow_style = {
type = "vertical_flow_style",
vertical_spacing = 0,
horizontally_stretchable = "on",
},
}
styles.rb_page_scroll_pane = {
type = "scroll_pane_style",
parent = "flib_naked_scroll_pane_no_padding",
vertical_flow_style = {
type = "vertical_flow_style",
padding = 12,
top_padding = 8,
vertical_spacing = 8,
},
}
styles.rb_search_results_scroll_pane = {
type = "scroll_pane_style",
parent = "rb_list_box_scroll_pane",
vertically_stretchable = "on",
minimal_height = 28 * constants.search_results_visible_items,
}
styles.rb_filter_scroll_pane = {
type = "scroll_pane_style",
parent = "flib_naked_scroll_pane_no_padding",
background_graphical_set = {
position = { 282, 17 },
corner_size = 8,
overall_tiling_vertical_size = 32,
overall_tiling_vertical_spacing = 8,
overall_tiling_vertical_padding = 4,
overall_tiling_horizontal_size = 32,
overall_tiling_horizontal_spacing = 8,
overall_tiling_horizontal_padding = 4,
},
vertically_stretchable = "on",
vertical_flow_style = {
type = "vertical_flow_style",
vertical_spacing = 0,
width = 40 * 10,
},
}
-- styles.rb_settings_content_scroll_pane = {
-- type = "scroll_pane_style",
-- parent = "rb_naked_scroll_pane",
-- vertical_flow_style = {
-- type = "vertical_flow_style",
-- padding = 4
-- }
-- }
-- TABLE STYLES
styles.rb_info_table = {
type = "table_style",
parent = "mods_table",
top_margin = -6, -- To hide the strange first row styling
bottom_margin = 1,
top_cell_padding = 1,
bottom_cell_padding = 3,
column_alignments = {
{ column = 1, alignment = "middle-left" },
{ column = 2, alignment = "middle-right" },
},
}
-- TEXTFIELD STYLES
styles.rb_search_textfield = {
type = "textbox_style",
parent = "flib_widthless_textfield",
horizontally_stretchable = "on",
}
styles.rb_search_invalid_textfield = {
type = "textbox_style",
parent = "flib_widthless_invalid_textfield",
horizontally_stretchable = "on",
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 B

View File

@ -1,17 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="96.000000pt" height="96.000000pt" viewBox="0 0 96.000000 96.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,96.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M425 855 c-16 -15 -25 -36 -25 -55 0 -19 9 -40 25 -55 49 -50 135
-15 135 55 0 41 -39 80 -80 80 -19 0 -40 -9 -55 -25z"/>
<path d="M345 655 c-24 -24 -25 -28 -25 -180 0 -148 1 -155 20 -155 19 0 20
-7 20 -120 l0 -120 40 0 40 0 0 120 0 120 40 0 40 0 0 -120 0 -120 40 0 40 0
0 120 c0 113 1 120 20 120 19 0 20 7 20 155 0 152 -1 156 -25 180 -23 24 -31
25 -135 25 -104 0 -112 -1 -135 -25z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,21 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="96.000000pt" height="96.000000pt" viewBox="0 0 96.000000 96.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,96.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M320 800 c0 -33 3 -40 20 -40 19 0 20 -7 20 -100 l0 -100 -120 -167
c-130 -182 -139 -205 -95 -248 l24 -25 311 0 311 0 24 25 c44 43 35 66 -95
248 l-120 167 0 100 c0 93 1 100 20 100 17 0 20 7 20 40 l0 40 -160 0 -160 0
0 -40z m200 -120 l0 -80 -40 0 -40 0 0 80 0 80 40 0 40 0 0 -80z m127 -322
l113 -158 -280 0 -280 0 91 128 c153 213 133 193 192 190 l51 -3 113 -157z"/>
<path d="M490 425 c-15 -18 -10 -45 13 -59 34 -22 73 27 47 59 -16 19 -44 19
-60 0z"/>
<path d="M380 340 c-11 -11 -20 -29 -20 -40 0 -11 9 -29 20 -40 11 -11 29 -20
40 -20 26 0 60 34 60 60 0 11 -9 29 -20 40 -11 11 -29 20 -40 20 -11 0 -29 -9
-40 -20z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 720 B

View File

@ -1,16 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="96.000000pt" height="96.000000pt" viewBox="0 0 96.000000 96.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,96.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M193 813 c-11 -16 -31 -49 -46 -75 l-27 -47 0 -261 0 -261 25 -24 24
-25 311 0 311 0 24 25 25 24 0 263 0 263 -43 70 -42 70 -272 3 -271 2 -19 -27z
m537 -93 l20 -40 -270 0 -270 0 20 40 20 40 230 0 230 0 20 -40z m30 -320 l0
-200 -280 0 -280 0 0 200 0 200 280 0 280 0 0 -200z"/>
<path d="M360 480 l0 -40 120 0 120 0 0 40 0 40 -120 0 -120 0 0 -40z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 786 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,23 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="96.000000pt" height="96.000000pt" viewBox="0 0 96.000000 96.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,96.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M223 864 c-58 -21 -108 -80 -129 -151 -31 -106 -3 -281 71 -449 20
-44 21 -54 9 -75 -7 -13 -13 -43 -14 -66 l0 -43 360 0 360 0 0 40 c0 27 -13
67 -40 120 l-40 80 0 160 c0 153 1 160 20 160 17 0 20 7 20 40 0 33 -3 40 -20
40 -13 0 -20 7 -20 20 0 17 -7 20 -40 20 -33 0 -40 -3 -40 -20 0 -18 -7 -20
-55 -20 -54 0 -56 1 -118 64 -50 51 -74 67 -117 80 -66 20 -151 19 -207 0z
m212 -88 c22 -14 23 -19 13 -36 -10 -16 -24 -20 -70 -20 -51 0 -58 2 -58 20 0
17 -7 20 -40 20 -33 0 -40 -3 -40 -20 0 -13 -7 -20 -20 -20 -17 0 -20 -7 -20
-40 0 -33 3 -40 20 -40 19 0 20 -6 19 -167 l0 -168 -19 41 c-27 62 -60 202
-60 258 0 144 53 200 182 193 40 -3 78 -11 93 -21z m5 -186 c0 -39 4 -53 20
-62 11 -7 20 -21 20 -30 0 -14 8 -18 40 -18 32 0 40 4 40 18 0 9 9 23 20 30
16 9 20 23 20 62 l0 50 60 0 60 0 0 -160 0 -160 -200 0 -200 0 0 160 0 160 60
0 60 0 0 -50z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 920 B

View File

@ -1,19 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="96.000000pt" height="96.000000pt" viewBox="0 0 96.000000 96.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,96.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M275 871 c-11 -5 -31 -21 -45 -36 l-25 -27 -3 -244 -3 -244 -61 0
-60 0 3 -85 c4 -80 6 -86 37 -117 l32 -33 250 0 250 0 32 33 33 32 3 245 3
245 81 0 80 0 -3 85 c-4 80 -6 86 -37 117 l-32 33 -258 2 c-141 1 -266 -2
-277 -6z m365 -382 c-5 -283 -7 -313 -22 -323 -13 -8 -23 -8 -35 0 -14 9 -19
28 -21 83 l-3 71 -139 0 -140 0 0 228 c0 164 3 231 12 240 8 8 63 12 183 12
l170 0 -5 -311z m148 299 c7 -7 12 -25 12 -40 0 -26 -3 -28 -40 -28 -37 0 -40
2 -40 28 0 31 16 52 40 52 9 0 21 -5 28 -12z m-306 -588 l4 -40 -151 0 c-163
0 -175 4 -175 52 l0 28 159 0 159 0 4 -40z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 996 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,27 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="96.000000pt" height="96.000000pt" viewBox="0 0 96.000000 96.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.16, written by Peter Selinger 2001-2019
</metadata>
<g transform="translate(0.000000,96.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M500 850 c-67 -26 -83 -28 -151 -23 -75 6 -76 5 -114 -28 -21 -19
-56 -56 -77 -83 -39 -49 -39 -50 -37 -131 2 -69 0 -87 -19 -117 -20 -32 -21
-46 -18 -162 3 -149 2 -147 116 -192 91 -35 145 -36 221 -2 31 14 103 34 160
43 123 20 150 31 208 83 39 34 44 44 49 90 3 36 -1 67 -13 98 -15 39 -15 50
-4 70 10 20 10 34 1 72 -7 26 -11 69 -10 96 1 27 -2 51 -7 53 -6 2 -24 12 -42
23 -25 15 -32 27 -35 56 -7 81 -102 103 -228 54z m136 -117 c5 -27 7 -68 6
-93 -5 -137 -8 -170 -18 -180 -7 -7 -40 -22 -75 -34 -61 -22 -65 -26 -91 -79
-27 -56 -28 -57 -71 -57 -23 0 -52 -7 -65 -15 -12 -9 -37 -22 -56 -30 -31 -13
-36 -13 -59 5 -20 16 -25 31 -30 91 -5 62 -3 76 13 100 16 22 20 44 20 109 0
81 0 83 40 130 l40 48 92 4 c65 4 107 11 138 26 25 11 59 21 77 21 30 1 32 -1
39 -46z"/>
<path d="M451 658 c-52 -30 -53 -32 -46 -67 3 -20 7 -52 8 -71 2 -28 6 -36 25
-38 13 -2 31 3 40 11 9 8 32 22 50 31 28 14 32 22 32 56 0 21 -4 42 -10 45 -5
3 -10 17 -10 30 0 17 -20 39 -33 34 -1 0 -26 -14 -56 -31z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,22 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="90.000000pt" height="90.000000pt" viewBox="0 0 90.000000 90.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.16, written by Peter Selinger 2001-2019
</metadata>
<g transform="translate(0.000000,90.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M213 702 c-193 -97 -213 -109 -213 -132 0 -23 20 -35 215 -133 118
-59 224 -107 235 -107 11 0 117 48 235 107 195 98 215 110 215 133 0 23 -20
35 -215 133 -118 59 -225 107 -238 106 -12 0 -118 -48 -234 -107z"/>
<path d="M833 458 c-22 -11 -23 -16 -23 -143 0 -106 -3 -135 -15 -145 -23 -19
-18 -78 10 -127 14 -23 30 -43 35 -43 5 0 21 20 35 43 28 49 33 108 10 127
-12 10 -15 41 -15 156 0 79 -3 144 -7 143 -5 0 -18 -5 -30 -11z"/>
<path d="M180 314 l0 -87 40 -38 c51 -49 118 -69 230 -69 112 0 179 20 230 69
l40 38 0 87 0 86 -120 -60 c-67 -34 -133 -60 -150 -60 -17 0 -83 26 -150 60
l-120 60 0 -86z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

View File

@ -1,161 +0,0 @@
local constants = require("constants")
local util = require("scripts.util")
local beacon = require("scripts.database.beacon")
local burning = require("scripts.database.burning")
local crafter = require("scripts.database.crafter")
local entity = require("scripts.database.entity")
local entity_state = require("scripts.database.entity-state")
local entity_type = require("scripts.database.entity-type")
local equipment_category = require("scripts.database.equipment-category")
local equipment = require("scripts.database.equipment")
local fluid = require("scripts.database.fluid")
local fuel_category = require("scripts.database.fuel-category")
local generator = require("scripts.database.generator")
local group = require("scripts.database.group")
local item = require("scripts.database.item")
local item_type = require("scripts.database.item-type")
local lab = require("scripts.database.lab")
local mining_drill = require("scripts.database.mining-drill")
local offshore_pump = require("scripts.database.offshore-pump")
local recipe_category = require("scripts.database.recipe-category")
local recipe = require("scripts.database.recipe")
local resource_category = require("scripts.database.resource-category")
local resource = require("scripts.database.resource")
local science_pack = require("scripts.database.science-pack")
local technology = require("scripts.database.technology")
local database = {}
function database.build()
-- Create class tables
for _, class in pairs(constants.classes) do
database[class] = {}
end
-- Create dictionaries
for _, class in pairs(constants.classes) do
util.new_dictionary(class)
util.new_dictionary(class .. "_description")
end
util.new_dictionary("gui", constants.gui_strings)
-- Data that is needed for generation but will not be saved
local metadata = {}
entity_type(database)
equipment_category(database)
fuel_category(database)
group(database)
item_type(database)
recipe_category(database)
resource_category(database)
science_pack(database)
equipment(database)
beacon(database, metadata)
crafter(database, metadata)
generator(database)
entity(database, metadata)
mining_drill(database)
fluid(database, metadata)
lab(database)
offshore_pump(database) -- requires fluids
item(database, metadata) -- requires all entities
recipe(database, metadata)
resource(database)
technology(database, metadata)
offshore_pump.check_enabled_at_start(database)
fluid.process_temperatures(database, metadata)
mining_drill.add_resources(database)
fuel_category.check_fake_category(database)
lab.process_researched_in(database)
burning(database)
entity_state(database)
database.generated = true
end
local function update_launch_products(launch_products, force_index, to_value)
for _, launch_product in pairs(launch_products) do
local product_data = database.item[launch_product.name]
if product_data.researched_forces then
product_data.researched_forces[force_index] = to_value
end
update_launch_products(product_data.rocket_launch_products, force_index, to_value)
end
end
function database.handle_research_updated(technology, to_value)
local force_index = technology.force.index
-- Technology
local technology_data = database.technology[technology.name]
-- Other mods can update technologies during on_configuration_changed before RB gets a chance to config change
if not technology_data then
return
end
technology_data.researched_forces[force_index] = to_value
for _, objects in pairs({
technology_data.unlocks_equipment,
technology_data.unlocks_fluids,
technology_data.unlocks_items,
technology_data.unlocks_entities,
technology_data.unlocks_recipes,
}) do
for _, obj_ident in ipairs(objects) do
local class = obj_ident.class
local obj_data = database[class][obj_ident.name]
-- Unlock this object
if obj_data.researched_forces then
obj_data.researched_forces[force_index] = to_value
end
if class == "fluid" and obj_data.temperature_ident then
-- Unlock base fluid
local base_fluid_data = database.fluid[obj_data.prototype_name]
if base_fluid_data.researched_forces then
base_fluid_data.researched_forces[force_index] = to_value
end
elseif class == "item" then
-- Unlock rocket launch products
update_launch_products(obj_data.rocket_launch_products, force_index, to_value)
elseif class == "offshore_pump" then
-- Unlock pumped fluid
local fluid = obj_data.fluid
local fluid_data = database.fluid[fluid.name]
if fluid_data.researched_forces then
fluid_data.researched_forces[force_index] = to_value
end
end
end
end
end
function database.check_force(force)
if not force.valid then
return
end
for _, technology in pairs(force.technologies) do
if technology.enabled and technology.researched then
database.handle_research_updated(technology, true)
end
end
end
function database.check_forces()
for _, force in pairs(global.forces) do
database.check_force(force)
end
end
return database

View File

@ -1,35 +0,0 @@
local util = require("scripts.util")
return function(database, metadata)
metadata.beacon_allowed_effects = {}
for name, prototype in pairs(global.prototypes.beacon) do
local size = util.get_size(prototype) --[[@as DisplayResolution]]
database.entity[name] = {
accepted_modules = {},
blueprintable = util.is_blueprintable(prototype),
class = "entity",
distribution_effectivity = prototype.distribution_effectivity,
effect_area = {
height = size.height + (prototype.supply_area_distance * 2),
width = size.width + (prototype.supply_area_distance * 2),
},
energy_usage = prototype.energy_usage,
entity_type = { class = "entity_type", name = prototype.type },
module_slots = prototype.module_inventory_size
and prototype.module_inventory_size > 0
and prototype.module_inventory_size
or nil,
placed_by = util.process_placed_by(prototype),
prototype_name = name,
science_packs = {},
size = size,
unlocked_by = {},
}
util.add_to_dictionary("entity", name, prototype.localised_name)
util.add_to_dictionary("entity_description", name, prototype.localised_description)
metadata.beacon_allowed_effects[name] = prototype.allowed_effects
end
end

View File

@ -1,51 +0,0 @@
local table = require("__flib__.table")
local constants = require("constants")
return function(database)
-- Compatible fuels / burned in
for _, class in pairs(constants.burner_classes) do
for name, data in pairs(database[class]) do
local can_burn = data.can_burn
if can_burn then
-- Generators might have a fluid defined here already
for _, fuel_ident in pairs(can_burn) do
local fuel_data = database[fuel_ident.class][fuel_ident.name]
fuel_data.burned_in[#fuel_data.burned_in + 1] = { class = class, name = name }
end
local fuel_filter = data.fuel_filter
if fuel_filter then
data.can_burn = { fuel_filter }
data.fuel_filter = nil
local fuel_data = database[fuel_filter.class][fuel_filter.name]
fuel_data.burned_in[#fuel_data.burned_in + 1] = { class = class, name = name }
end
for i, category_ident in pairs(data.fuel_categories or {}) do
local category_data = database.fuel_category[category_ident.name]
if category_data then
-- Add fluids and items to the compatible fuels, and add the object to the material's burned in table
for _, objects in pairs({ category_data.fluids, category_data.items }) do
for _, obj_ident in pairs(objects) do
local obj_data = database[obj_ident.class][obj_ident.name]
obj_data.burned_in[#obj_data.burned_in + 1] = { class = class, name = name }
can_burn[#can_burn + 1] = table.shallow_copy(obj_ident)
end
end
else
-- Remove this category from the entity
table.remove(data.fuel_categories, i)
end
end
end
end
end
-- Burnt results
for item_name, item_data in pairs(database.item) do
local burnt_result = item_data.burnt_result
if burnt_result then
local result_data = database.item[burnt_result.name]
result_data.burnt_result_of[#result_data.burnt_result_of + 1] = { class = "item", name = item_name }
end
end
end

View File

@ -1,108 +0,0 @@
local util = require("scripts.util")
return function(database, metadata)
-- Characters as crafters
for name, prototype in pairs(global.prototypes.character) do
local ingredient_limit = prototype.ingredient_count
if ingredient_limit == 255 then
ingredient_limit = nil
end
database.entity[name] = {
accepted_modules = {}, -- Always empty
blueprintable = false,
can_burn = {}, -- Always empty
can_craft = {},
class = "entity",
crafting_speed = 1,
enabled = true,
entity_type = { class = "entity_type", name = prototype.type },
hidden = false,
ingredient_limit = ingredient_limit,
is_character = true,
placed_by = util.process_placed_by(prototype),
prototype_name = name,
recipe_categories_lookup = prototype.crafting_categories or {},
recipe_categories = util.convert_categories(prototype.crafting_categories or {}, "recipe_category"),
science_packs = {},
unlocked_by = {},
}
util.add_to_dictionary("entity", name, prototype.localised_name)
util.add_to_dictionary("entity_description", name, prototype.localised_description)
end
-- Actual crafters
metadata.allowed_effects = {}
metadata.crafter_fluidbox_counts = {}
metadata.fixed_recipes = {}
local rocket_silo_categories = util.unique_obj_array()
for name, prototype in pairs(global.prototypes.crafter) do
-- Fixed recipe
local fixed_recipe
if prototype.fixed_recipe then
metadata.fixed_recipes[prototype.fixed_recipe] = true
fixed_recipe = { class = "recipe", name = prototype.fixed_recipe }
end
-- Rocket silo categories
if prototype.rocket_parts_required then
for category in pairs(prototype.crafting_categories) do
table.insert(rocket_silo_categories, { class = "recipe_category", name = category })
end
end
local ingredient_limit = prototype.ingredient_count
if ingredient_limit == 255 then
ingredient_limit = nil
end
metadata.allowed_effects[name] = prototype.allowed_effects
local fluidboxes = prototype.fluidbox_prototypes
if fluidboxes then
local fluidbox_counts = { inputs = 0, outputs = 0 }
for _, fluidbox in pairs(fluidboxes) do
local type = fluidbox.production_type
if string.find(type, "input") then
fluidbox_counts.inputs = fluidbox_counts.inputs + 1
end
if string.find(type, "output") then
fluidbox_counts.outputs = fluidbox_counts.outputs + 1
end
end
metadata.crafter_fluidbox_counts[name] = fluidbox_counts
end
local is_hidden = prototype.has_flag("hidden")
local fuel_categories, fuel_filter = util.process_energy_source(prototype)
database.entity[name] = {
accepted_modules = {},
blueprintable = util.is_blueprintable(prototype),
can_burn = {},
can_craft = {},
class = "entity",
crafting_speed = prototype.crafting_speed,
entity_type = { class = "entity_type", name = prototype.type },
fixed_recipe = fixed_recipe,
fuel_categories = fuel_categories,
fuel_filter = fuel_filter,
hidden = is_hidden,
ingredient_limit = ingredient_limit,
module_slots = prototype.module_inventory_size
and prototype.module_inventory_size > 0
and prototype.module_inventory_size
or nil,
placed_by = util.process_placed_by(prototype),
prototype_name = name,
recipe_categories_lookup = prototype.crafting_categories or {},
recipe_categories = util.convert_categories(prototype.crafting_categories or {}, "recipe_category"),
rocket_parts_required = prototype.rocket_parts_required,
science_packs = {},
size = util.get_size(prototype),
unlocked_by = {},
}
util.add_to_dictionary("entity", name, prototype.localised_name)
util.add_to_dictionary("entity_description", name, prototype.localised_description)
end
metadata.rocket_silo_categories = rocket_silo_categories
end

View File

@ -1,17 +0,0 @@
return function(database)
for _, entity_data in pairs(database.entity) do
-- Hidden / disabled for entities
if not entity_data.is_character then
local placed_by_len = #(entity_data.placed_by or {})
if placed_by_len == 0 and not entity_data.expected_resources then
entity_data.enabled = false
elseif placed_by_len == 1 then
local item_ident = entity_data.placed_by[1]
local item_data = database.item[item_ident.name]
if item_data.hidden then
entity_data.hidden = true
end
end
end
end
end

View File

@ -1,26 +0,0 @@
local constants = require("constants")
local util = require("scripts.util")
return function(database)
for class in pairs(constants.prototypes.filtered_entities) do
if class ~= "resource" then
for name, prototype in pairs(global.prototypes[class]) do
local type = prototype.type
local type_data = database.entity_type[type]
if not type_data then
type_data = {
class = "entity_type",
entities = {},
prototype_name = type,
}
database.entity_type[type] = type_data
util.add_to_dictionary("entity_type", type, { "entity-type." .. type })
util.add_to_dictionary("entity_type_description", type, { "entity-type-description." .. type })
end
table.insert(type_data.entities, { class = "entity", name = name })
end
end
end
end

View File

@ -1,70 +0,0 @@
local table = require("__flib__.table")
local util = require("scripts.util")
return function(database, metadata)
metadata.gathered_from = {}
--- @type table<string, LuaEntityPrototype>
local prototypes = global.prototypes.entity
for name, prototype in pairs(prototypes) do
local equipment_categories = util.unique_obj_array()
local equipment = util.unique_obj_array()
local equipment_grid = prototype.grid_prototype
if equipment_grid then
for _, equipment_category in pairs(equipment_grid.equipment_categories) do
table.insert(equipment_categories, { class = "equipment_category", name = equipment_category })
local category_data = database.equipment_category[equipment_category]
if category_data then
for _, equipment_name in pairs(category_data.equipment) do
table.insert(equipment, equipment_name)
end
end
end
end
local fuel_categories, fuel_filter = util.process_energy_source(prototype)
local expected_resources
local mineable = prototype.mineable_properties
if
mineable
and mineable.minable
and mineable.products
and #mineable.products > 0
and mineable.products[1].name ~= name
then
expected_resources = table.map(mineable.products, function(product)
if not metadata.gathered_from[product.name] then
metadata.gathered_from[product.name] = {}
end
table.insert(metadata.gathered_from[product.name], { class = "entity", name = name })
return { class = product.type, name = product.name, amount_ident = util.build_amount_ident(product) }
end)
end
database.entity[name] = {
accepted_equipment = equipment,
blueprintable = util.is_blueprintable(prototype),
can_burn = {},
class = "entity",
enabled_at_start = expected_resources and true or false, -- FIXME: This is inaccurate
entity_type = { class = "entity_type", name = prototype.type },
equipment_categories = equipment_categories,
expected_resources = expected_resources,
fuel_categories = fuel_categories,
fuel_filter = fuel_filter,
module_slots = prototype.module_inventory_size
and prototype.module_inventory_size > 0
and prototype.module_inventory_size
or nil,
placed_by = util.process_placed_by(prototype),
prototype_name = name,
science_packs = {},
unlocked_by = {},
}
util.add_to_dictionary("entity", name, prototype.localised_name)
util.add_to_dictionary("entity_description", name, prototype.localised_description)
end
end

View File

@ -1,25 +0,0 @@
local util = require("scripts.util")
local equipment_category_proc = {}
function equipment_category_proc.build(database)
for name, prototype in pairs(global.prototypes.equipment_category) do
database.equipment_category[name] = {
class = "equipment_category",
enabled_at_start = true,
equipment = {},
prototype_name = name,
}
util.add_to_dictionary("equipment_category", name, prototype.localised_name)
util.add_to_dictionary("equipment_category_description", name, prototype.localised_description)
end
end
-- When calling the module directly, call equipment_category_proc.build
setmetatable(equipment_category_proc, {
__call = function(_, ...)
return equipment_category_proc.build(...)
end,
})
return equipment_category_proc

View File

@ -1,87 +0,0 @@
local table = require("__flib__.table")
local util = require("scripts.util")
local properties_by_type = {
["active-defense-equipment"] = { { "energy_consumption", "energy" } },
["battery-equipment"] = {},
["belt-immunity-equipment"] = { { "energy_consumption", "energy" } },
["energy-shield-equipment"] = {
{ "energy_consumption", "energy" },
{ "shield", "number", "shield_points" },
{ "energy_per_shield", "energy", "energy_per_shield_point" },
},
["generator-equipment"] = { { "energy_production", "energy" } },
["movement-bonus-equipment"] = { { "energy_consumption", "energy" }, { "movement_bonus", "percent" } },
["night-vision-equipment"] = { { "energy_consumption", "energy" } },
["roboport-equipment"] = { { "energy_consumption", "energy" } },
["solar-panel-equipment"] = { { "energy_production", "energy" } },
}
local function get_equipment_property(properties, source, name, formatter, label)
local value = source[name]
if value and value > 0 then
table.insert(properties, {
type = "plain",
label = label or name,
value = value,
formatter = formatter,
})
end
end
return function(database)
--- @type table<string, LuaEquipmentPrototype>
local prototypes = global.prototypes.equipment
for name, prototype in pairs(prototypes) do
local fuel_categories
local burner = prototype.burner_prototype
if burner then
fuel_categories = util.convert_categories(burner.fuel_categories, "fuel_category")
end
for _, category in pairs(prototype.equipment_categories) do
local category_data = database.equipment_category[category]
category_data.equipment[#category_data.equipment + 1] = { class = "equipment", name = name }
end
local equipment_type = prototype.type
local properties = {}
for _, property in pairs(properties_by_type[equipment_type]) do
get_equipment_property(properties, prototype, property[1], property[2], property[3])
end
local energy_source = prototype.energy_source
if energy_source then
get_equipment_property(properties, energy_source, "buffer_capacity", "energy_storage")
end
if equipment_type == "roboport-equipment" then
local logistic_parameters = prototype.logistic_parameters
get_equipment_property(properties, logistic_parameters, "logistic_radius", "number")
get_equipment_property(properties, logistic_parameters, "construction_radius", "number")
get_equipment_property(properties, logistic_parameters, "robot_limit", "number")
get_equipment_property(properties, logistic_parameters, "charging_energy", "energy")
end
database.equipment[name] = {
can_burn = {},
class = "equipment",
enabled = true,
equipment_categories = table.map(prototype.equipment_categories, function(category)
return { class = "equipment_category", name = category }
end),
equipment_properties = properties,
fuel_categories = fuel_categories,
hidden = false,
placed_in = util.unique_obj_array(),
prototype_name = name,
science_packs = {},
size = prototype.shape and prototype.shape.width or nil, -- Equipments can have irregular shapes
take_result = prototype.take_result and { class = "item", name = prototype.take_result.name } or nil,
unlocked_by = {},
}
util.add_to_dictionary("equipment", name, prototype.localised_name)
util.add_to_dictionary("equipment_description", name, prototype.localised_description)
end
end

View File

@ -1,238 +0,0 @@
local table = require("__flib__.table")
local constants = require("constants")
local util = require("scripts.util")
local fluid_proc = {}
function fluid_proc.build(database, metadata)
local localised_fluids = {}
for name, prototype in pairs(global.prototypes.fluid) do
-- Group
local group = prototype.group
local group_data = database.group[group.name]
group_data.fluids[#group_data.fluids + 1] = { class = "fluid", name = name }
-- Fake fuel category
local fuel_category
if prototype.fuel_value > 0 then
fuel_category = { class = "fuel_category", name = constants.fake_fluid_fuel_category }
local fluids = database.fuel_category[constants.fake_fluid_fuel_category].fluids
fluids[#fluids + 1] = { class = "fluid", name = name }
end
-- Save to recipe book
database.fluid[name] = {
burned_in = {},
class = "fluid",
default_temperature = prototype.default_temperature,
fuel_category = fuel_category,
fuel_pollution = prototype.fuel_value > 0
and prototype.emissions_multiplier ~= 1
and prototype.emissions_multiplier
or nil,
fuel_value = prototype.fuel_value > 0 and prototype.fuel_value or nil,
group = { class = "group", name = group.name },
hidden = prototype.hidden,
ingredient_in = {},
mined_from = {},
product_of = {},
prototype_name = name,
pumped_by = {},
recipe_categories = util.unique_obj_array(),
science_packs = {},
subgroup = { class = "group", name = prototype.subgroup.name },
temperatures = {},
unlocked_by = util.unique_obj_array(),
}
-- Don't add strings yet - they will be added in process_temperatures() to improve the ordering
localised_fluids[name] = { name = prototype.localised_name, description = prototype.localised_description }
end
metadata.localised_fluids = localised_fluids
end
-- Adds a fluid temperature definition if one doesn't exist yet
function fluid_proc.add_temperature(fluid_data, temperature_ident)
local temperature_string = temperature_ident.string
local temperatures = fluid_data.temperatures
if not temperatures[temperature_string] then
temperatures[temperature_string] = {
base_fluid = { class = "fluid", name = fluid_data.prototype_name },
class = "fluid",
default_temperature = fluid_data.default_temperature,
fuel_pollution = fluid_data.fuel_pollution,
fuel_value = fluid_data.fuel_value,
group = fluid_data.group,
hidden = fluid_data.hidden,
ingredient_in = {},
mined_from = {},
name = fluid_data.prototype_name .. "." .. temperature_string,
product_of = {},
prototype_name = fluid_data.prototype_name,
recipe_categories = util.unique_obj_array(),
science_packs = {},
subgroup = fluid_data.subgroup,
temperature_ident = temperature_ident,
unlocked_by = util.unique_obj_array(),
}
end
end
-- Returns true if `comp` is within `base`
function fluid_proc.is_within_range(base, comp, flip)
if flip then
return base.min >= comp.min and base.max <= comp.max
else
return base.min <= comp.min and base.max >= comp.max
end
end
function fluid_proc.process_temperatures(database, metadata)
-- Create a new fluids table so insertion order will neatly organize the temperature variants
local new_fluid_table = {}
for fluid_name, fluid_data in pairs(database.fluid) do
new_fluid_table[fluid_name] = fluid_data
local localised = metadata.localised_fluids[fluid_name]
util.add_to_dictionary("fluid", fluid_name, localised.name)
util.add_to_dictionary("fluid_description", fluid_name, localised.description)
local temperatures = fluid_data.temperatures
if temperatures and next(temperatures) then
-- Step 1: Add a variant for the default temperature if one does not exist
local default_temperature = fluid_data.default_temperature
local default_temperature_ident = util.build_temperature_ident({ temperature = default_temperature })
if not temperatures[default_temperature_ident.string] then
fluid_proc.add_temperature(fluid_data, default_temperature_ident)
end
-- Step 2: Sort the temperature variants
local temp = {}
for _, temperature_data in pairs(temperatures) do
table.insert(temp, temperature_data)
end
table.sort(temp, function(temp_a, temp_b)
return util.get_sorting_number(temp_a.temperature_ident) < util.get_sorting_number(temp_b.temperature_ident)
end)
-- Create a new table and insert in order
temperatures = {}
for _, temperature_data in pairs(temp) do
temperatures[temperature_data.name] = temperature_data
-- Add to database and add translation
new_fluid_table[temperature_data.name] = temperature_data
util.add_to_dictionary("fluid", temperature_data.name, {
"",
localised.name,
" (",
{ "format-degrees-c-compact", temperature_data.temperature_ident.string },
")",
})
end
fluid_data.temperatures = temperatures
-- Step 3: Add researched properties to temperature variants
for _, temperature_data in pairs(temperatures) do
temperature_data.enabled_at_start = fluid_data.enabled_at_start
if fluid_data.researched_forces then
temperature_data.researched_forces = {}
end
end
-- Step 4: Add properties from base fluid to temperature variants
-- TODO: This is an idiotic way to do this
for fluid_tbl_name, obj_table_name in pairs({
ingredient_in = "ingredients",
product_of = "products",
mined_from = "products",
}) do
for _, obj_ident in pairs(fluid_data[fluid_tbl_name]) do
local obj_data = database[obj_ident.class][obj_ident.name]
-- Get the matching fluid
local fluid_ident
-- This is kind of a slow way to do it, but I don't really care
for _, material_ident in pairs(obj_data[obj_table_name]) do
if material_ident.name == fluid_name then
fluid_ident = material_ident
break
end
end
-- Get the temperature identifier from the material table
local temperature_ident = fluid_ident.temperature_ident
if temperature_ident then
-- Change the name of the material and remove the identifier
fluid_ident.name = fluid_ident.name .. "." .. temperature_ident.string
fluid_ident.temperature_ident = nil
elseif obj_table_name == "products" then
-- Change the name of the material to the default temperature
fluid_ident.name = fluid_ident.name .. "." .. default_temperature_ident.string
fluid_ident.temperature_ident = nil
-- Use the default temperature for matching
temperature_ident = default_temperature_ident
end
-- Iterate over all temperature variants and compare their constraints
for _, temperature_data in pairs(temperatures) do
if
not temperature_ident
or fluid_proc.is_within_range(
temperature_data.temperature_ident,
temperature_ident,
fluid_tbl_name == "ingredient_in"
)
then
-- Add to recipes table
temperature_data[fluid_tbl_name][#temperature_data[fluid_tbl_name] + 1] = obj_ident
-- Recipe-specific logic
if obj_ident.class == "recipe" then
-- Add recipe category
local recipe_categories = temperature_data.recipe_categories
recipe_categories[#recipe_categories + 1] = table.shallow_copy(obj_data.recipe_category)
-- If in product_of, append to unlocked_by
-- Also add this fluid to that tech's `unlocks fluids` table
-- This is to avoid variants being "unlocked" when you can't actually get them
-- If this is an "empty X barrel" recipe, ignore it
if fluid_tbl_name == "product_of" and not string.find(obj_ident.name, "^empty%-.+%-barrel$") then
local temp_unlocked_by = temperature_data.unlocked_by
for _, technology_ident in pairs(obj_data.unlocked_by) do
temp_unlocked_by[#temp_unlocked_by + 1] = technology_ident
local technology_data = database.technology[technology_ident.name]
-- Don't use fluid_ident becuase it has an amount
technology_data.unlocks_fluids[#technology_data.unlocks_fluids + 1] = {
class = "fluid",
name = temperature_data.name,
}
end
end
end
end
end
end
end
-- Step 5: If this variant is not produced by anything, unlock with the base fluid
for _, temperature_data in pairs(temperatures) do
if #temperature_data.product_of == 0 and #temperature_data.unlocked_by == 0 then
temperature_data.unlocked_by = table.deep_copy(fluid_data.unlocked_by)
for _, technology_ident in pairs(fluid_data.unlocked_by) do
local technology_data = database.technology[technology_ident.name]
-- Don't use fluid_ident becuase it has an amount
technology_data.unlocks_fluids[#technology_data.unlocks_fluids + 1] = {
class = "fluid",
name = temperature_data.name,
}
end
end
end
end
end
database.fluid = new_fluid_table
end
-- When calling the module directly, call fluid_proc.build
setmetatable(fluid_proc, {
__call = function(_, ...)
return fluid_proc.build(...)
end,
})
return fluid_proc

View File

@ -1,51 +0,0 @@
local constants = require("constants")
local fake_name = constants.fake_fluid_fuel_category
local util = require("scripts.util")
local fuel_category_proc = {}
function fuel_category_proc.build(database)
-- Add the actual fuel categories
for name, prototype in pairs(global.prototypes.fuel_category) do
database.fuel_category[name] = {
class = "fuel_category",
enabled_at_start = true,
fluids = {}, -- Will always be empty
items = util.unique_obj_array({}),
prototype_name = name,
}
util.add_to_dictionary("fuel_category", name, prototype.localised_name)
util.add_to_dictionary("fuel_category_description", name, prototype.localised_description)
end
-- Add our fake fuel category for fluids
database.fuel_category[fake_name] = {
class = "fuel_category",
enabled_at_start = true,
fluids = util.unique_obj_array({}),
items = {}, -- Will always be empty
prototype_name = fake_name,
}
end
function fuel_category_proc.check_fake_category(database)
local category = database.fuel_category[fake_name]
if #category.fluids > 0 then
-- Add translations
util.add_to_dictionary("fuel_category", fake_name, { "fuel-category-name." .. fake_name })
util.add_to_dictionary("fuel_category_description", fake_name, { "fuel-category-description." .. fake_name })
else
-- Remove the category
database.fuel_category[fake_name] = nil
end
end
-- When calling the module directly, call fuel_category_proc.build
setmetatable(fuel_category_proc, {
__call = function(_, ...)
return fuel_category_proc.build(...)
end,
})
return fuel_category_proc

View File

@ -1,34 +0,0 @@
local util = require("scripts.util")
return function(database)
for name, prototype in pairs(global.prototypes.generator) do
local fluid_box = prototype.fluidbox_prototypes[1]
local can_burn = {}
local fuel_categories = {}
if fluid_box.filter then
can_burn = { { class = "fluid", name = fluid_box.filter.name } }
else
fuel_categories = { { class = "fuel_category", name = "burnable-fluid" } }
end
database.entity[name] = {
base_pollution = prototype.emissions_per_second > 0 and prototype.emissions_per_second or nil,
blueprintable = util.is_blueprintable(prototype),
can_burn = can_burn,
class = "entity",
entity_type = { class = "entity_type", name = prototype.type },
fluid_consumption = prototype.fluid_usage_per_tick * 60,
fuel_categories = fuel_categories,
max_energy_production = prototype.max_energy_production,
maximum_temperature = prototype.maximum_temperature,
minimum_temperature = fluid_box.minimum_temperature,
placed_by = util.process_placed_by(prototype),
prototype_name = name,
science_packs = {},
unlocked_by = {},
}
util.add_to_dictionary("entity", name, prototype.localised_name)
util.add_to_dictionary("entity_description", name, prototype.localised_description)
end
end

View File

@ -1,16 +0,0 @@
local util = require("scripts.util")
return function(database)
for name, prototype in pairs(global.prototypes.item_group) do
database.group[name] = {
class = "group",
enabled_at_start = true,
fluids = util.unique_obj_array({}),
items = util.unique_obj_array({}),
prototype_name = name,
recipes = util.unique_obj_array({}),
}
util.add_to_dictionary("group", name, prototype.localised_name)
-- NOTE: Groups do not have descriptions
end
end

View File

@ -1,20 +0,0 @@
local util = require("scripts.util")
return function(database)
for name, prototype in pairs(global.prototypes.item) do
local type = prototype.type
local type_data = database.item_type[type]
if not type_data then
type_data = {
class = "item_type",
items = {},
prototype_name = type,
}
database.item_type[type] = type_data
util.add_to_dictionary("item_type", type, { "item-type." .. type })
util.add_to_dictionary("item_type_description", type, { "item-type-description." .. type })
end
table.insert(type_data.items, { class = "item", name = name })
end
end

View File

@ -1,210 +0,0 @@
local table = require("__flib__.table")
local util = require("scripts.util")
local item_proc = {}
function item_proc.build(database, metadata)
local modules = {}
local place_as_equipment_results = {}
local place_results = {}
local rocket_launch_payloads = {}
for name, prototype in pairs(global.prototypes.item) do
-- Group
local group = prototype.group
local group_data = database.group[group.name]
group_data.items[#group_data.items + 1] = { class = "item", name = name }
-- Rocket launch products
local launch_products = {}
for i, product in ipairs(prototype.rocket_launch_products or {}) do
-- Add to products table w/ amount string
local amount_ident = util.build_amount_ident(product)
launch_products[i] = {
class = product.type,
name = product.name,
amount_ident = amount_ident,
}
-- Add to payloads table
local product_payloads = rocket_launch_payloads[product.name]
local ident = { class = "item", name = name }
if product_payloads then
product_payloads[#product_payloads + 1] = ident
else
rocket_launch_payloads[product.name] = { ident }
end
end
local default_categories =
util.unique_string_array(#launch_products > 0 and table.shallow_copy(metadata.rocket_silo_categories) or {})
local place_as_equipment_result = prototype.place_as_equipment_result
if place_as_equipment_result then
place_as_equipment_result = { class = "equipment", name = place_as_equipment_result.name }
place_as_equipment_results[name] = place_as_equipment_result
end
local place_result = prototype.place_result
if place_result and database.entity[place_result.name] then
place_result = { class = "entity", name = place_result.name }
place_results[name] = place_result
else
place_result = nil
end
local burnt_result = prototype.burnt_result
if burnt_result then
burnt_result = { class = "item", name = burnt_result.name }
end
local equipment_categories = util.unique_obj_array()
local equipment = util.unique_obj_array()
local equipment_grid = prototype.equipment_grid
if equipment_grid then
for _, equipment_category in pairs(equipment_grid.equipment_categories) do
table.insert(equipment_categories, { class = "equipment_category", name = equipment_category })
local category_data = database.equipment_category[equipment_category]
if category_data then
for _, equipment_ident in pairs(category_data.equipment) do
table.insert(equipment, equipment_ident)
local equipment_data = database.equipment[equipment_ident.name]
if equipment_data then
equipment_data.placed_in[#equipment_data.placed_in + 1] = { class = "item", name = name }
end
end
end
end
end
local fuel_value = prototype.fuel_value
local has_fuel_value = prototype.fuel_value > 0
local fuel_acceleration_multiplier = prototype.fuel_acceleration_multiplier
local fuel_emissions_multiplier = prototype.fuel_emissions_multiplier
local fuel_top_speed_multiplier = prototype.fuel_top_speed_multiplier
local module_effects = {}
if prototype.type == "module" then
-- Add to internal list of modules
modules[name] = table.invert(prototype.limitations)
-- Process effects
for effect_name, effect in pairs(prototype.module_effects or {}) do
module_effects[#module_effects + 1] = {
type = "plain",
label = effect_name .. "_bonus",
value = effect.bonus,
formatter = "percent",
}
end
-- Process which beacons this module is compatible with
for beacon_name in pairs(global.prototypes.beacon) do
local beacon_data = database.entity[beacon_name]
local allowed_effects = metadata.beacon_allowed_effects[beacon_name]
local compatible = true
if allowed_effects then
for effect_name in pairs(prototype.module_effects or {}) do
if not allowed_effects[effect_name] then
compatible = false
break
end
end
end
if compatible then
beacon_data.accepted_modules[#beacon_data.accepted_modules + 1] = { class = "item", name = name }
end
end
-- Process which crafters this module is compatible with
for crafter_name in pairs(global.prototypes.crafter) do
local crafter_data = database.entity[crafter_name]
local allowed_effects = metadata.allowed_effects[crafter_name]
local compatible = true
if allowed_effects then
for effect_name in pairs(prototype.module_effects or {}) do
if not allowed_effects[effect_name] then
compatible = false
break
end
end
end
if compatible then
crafter_data.accepted_modules[#crafter_data.accepted_modules + 1] = { class = "item", name = name }
end
end
end
local fuel_category = util.convert_to_ident("fuel_category", prototype.fuel_category)
if fuel_category then
local items = database.fuel_category[fuel_category.name].items
items[#items + 1] = { class = "item", name = name }
end
--- @class ItemData
database.item[name] = {
accepted_equipment = equipment,
affects_recipes = {},
burned_in = {},
burnt_result = burnt_result,
burnt_result_of = {},
class = "item",
enabled_at_start = metadata.gathered_from[name] and true or false,
equipment_categories = equipment_categories,
fuel_acceleration_multiplier = has_fuel_value
and fuel_acceleration_multiplier ~= 1
and fuel_acceleration_multiplier
or nil,
fuel_category = fuel_category,
fuel_emissions_multiplier = has_fuel_value and fuel_emissions_multiplier ~= 1 and fuel_emissions_multiplier
or nil,
fuel_top_speed_multiplier = has_fuel_value and fuel_top_speed_multiplier ~= 1 and fuel_top_speed_multiplier
or nil,
fuel_value = has_fuel_value and fuel_value or nil,
gathered_from = metadata.gathered_from[name],
group = { class = "group", name = group.name },
hidden = prototype.has_flag("hidden"),
ingredient_in = {},
item_type = { class = "item_type", name = prototype.type },
mined_from = {},
module_category = util.convert_to_ident("module_category", prototype.category),
module_effects = module_effects,
place_as_equipment_result = place_as_equipment_result,
place_result = place_result,
product_of = {},
prototype_name = name,
recipe_categories = default_categories,
researched_in = {},
rocket_launch_product_of = {},
rocket_launch_products = launch_products,
science_packs = {},
stack_size = prototype.stack_size,
subgroup = { class = "group", name = prototype.subgroup.name },
unlocked_by = util.unique_obj_array(),
}
util.add_to_dictionary("item", name, prototype.localised_name)
util.add_to_dictionary("item_description", name, prototype.localised_description)
end
-- Add rocket launch payloads to their material tables
for product, payloads in pairs(rocket_launch_payloads) do
local product_data = database.item[product]
product_data.rocket_launch_product_of = table.array_copy(payloads)
for i = 1, #payloads do
local payload = payloads[i]
local payload_data = database.item[payload.name]
local payload_unlocked_by = payload_data.unlocked_by
for j = 1, #payload_unlocked_by do
product_data.unlocked_by[#product_data.unlocked_by + 1] = payload_unlocked_by[j]
end
end
end
metadata.modules = modules
metadata.place_as_equipment_results = place_as_equipment_results
metadata.place_results = place_results
end
-- When calling the module directly, call fluid_proc.build
setmetatable(item_proc, {
__call = function(_, ...)
return item_proc.build(...)
end,
})
return item_proc

View File

@ -1,57 +0,0 @@
local table = require("__flib__.table")
local util = require("scripts.util")
local lab_proc = {}
function lab_proc.build(database)
for name, prototype in pairs(global.prototypes.lab) do
local fuel_categories, fuel_filter = util.process_energy_source(prototype)
database.entity[name] = {
blueprintable = util.is_blueprintable(prototype),
can_burn = {},
class = "entity",
entity_type = { class = "entity_type", name = prototype.type },
fuel_categories = fuel_categories,
fuel_filter = fuel_filter,
hidden = prototype.has_flag("hidden"),
inputs = table.map(prototype.lab_inputs, function(v)
return { class = "item", name = v }
end),
module_slots = prototype.module_inventory_size
and prototype.module_inventory_size > 0
and prototype.module_inventory_size
or nil,
placed_by = util.process_placed_by(prototype),
prototype_name = name,
researching_speed = prototype.researching_speed,
science_packs = {},
size = util.get_size(prototype),
unlocked_by = {},
}
util.add_to_dictionary("entity", name, prototype.localised_name)
util.add_to_dictionary("entity_description", name, prototype.localised_description)
end
end
-- Store labs in science pack items' researched_in
function lab_proc.process_researched_in(database)
for name, prototype in pairs(global.prototypes.lab) do
-- Add to items
for _, item_name in ipairs(prototype.lab_inputs) do
local item_data = database.item[item_name]
if item_data then
item_data.researched_in[#item_data.researched_in + 1] = { class = "entity", name = name }
end
end
end
end
-- When calling the module directly, call lab_proc.build
setmetatable(lab_proc, {
__call = function(_, ...)
return lab_proc.build(...)
end,
})
return lab_proc

View File

@ -1,65 +0,0 @@
local util = require("scripts.util")
local mining_drill_proc = {}
function mining_drill_proc.build(database)
for name, prototype in pairs(global.prototypes.mining_drill) do
for category in pairs(prototype.resource_categories) do
local category_data = database.resource_category[category]
category_data.mining_drills[#category_data.mining_drills + 1] = { class = "entity", name = name }
end
local fuel_categories, fuel_filter = util.process_energy_source(prototype)
database.entity[name] = {
blueprintable = util.is_blueprintable(prototype),
can_burn = {},
class = "entity",
enabled = true,
entity_type = { class = "entity_type", name = prototype.type },
fuel_categories = fuel_categories,
fuel_filter = fuel_filter,
mining_area = math.ceil(prototype.mining_drill_radius * 2),
mining_speed = prototype.mining_speed,
module_slots = prototype.module_inventory_size
and prototype.module_inventory_size > 0
and prototype.module_inventory_size
or nil,
placed_by = util.process_placed_by(prototype),
prototype_name = name,
resource_categories_lookup = prototype.resource_categories,
resource_categories = util.convert_categories(prototype.resource_categories, "resource_category"),
science_packs = {},
size = util.get_size(prototype),
supports_fluid = #prototype.fluidbox_prototypes > 0,
unlocked_by = {},
}
util.add_to_dictionary("entity", name, prototype.localised_name)
util.add_to_dictionary("entity_description", name, prototype.localised_description)
end
end
function mining_drill_proc.add_resources(database)
for name in pairs(global.prototypes.mining_drill) do
local drill_data = database.entity[name]
local can_mine = util.unique_obj_array()
for category in pairs(drill_data.resource_categories_lookup) do
local category_data = database.resource_category[category]
for _, resource_ident in pairs(category_data.resources) do
local resource_data = database.resource[resource_ident.name]
if not resource_data.required_fluid or drill_data.supports_fluid then
can_mine[#can_mine + 1] = resource_ident
end
end
end
drill_data.can_mine = can_mine
end
end
-- When calling the module directly, call fluid_proc.build
setmetatable(mining_drill_proc, {
__call = function(_, ...)
return mining_drill_proc.build(...)
end,
})
return mining_drill_proc

View File

@ -1,53 +0,0 @@
local util = require("scripts.util")
local offshore_pump_proc = {}
function offshore_pump_proc.build(database)
-- Iterate offshore pumps
for name, prototype in pairs(global.prototypes.offshore_pump) do
-- Add to material
local fluid = prototype.fluid
local fluid_data = database.fluid[fluid.name]
if fluid_data then
fluid_data.pumped_by[#fluid_data.pumped_by + 1] = { class = "entity", name = name }
end
database.entity[name] = {
blueprintable = util.is_blueprintable(prototype),
class = "entity",
enabled = true,
entity_type = { class = "entity_type", name = prototype.type },
fluid = { class = "fluid", name = fluid.name },
hidden = prototype.has_flag("hidden"),
placed_by = util.process_placed_by(prototype),
prototype_name = name,
pumping_speed = prototype.pumping_speed * 60,
science_packs = {},
size = util.get_size(prototype),
unlocked_by = {},
}
util.add_to_dictionary("entity", name, prototype.localised_name)
util.add_to_dictionary("entity_description", name, prototype.localised_description)
end
end
function offshore_pump_proc.check_enabled_at_start(database)
for name in pairs(global.prototypes.offshore_pump) do
local pump_data = database.entity[name]
if not pump_data.researched_forces then
local fluid_data = database.fluid[pump_data.fluid.name]
fluid_data.researched_forces = nil
fluid_data.science_packs = {}
fluid_data.unlocked_by = {}
end
end
end
-- When calling the module directly, call fluid_proc.build
setmetatable(offshore_pump_proc, {
__call = function(_, ...)
return offshore_pump_proc.build(...)
end,
})
return offshore_pump_proc

View File

@ -1,16 +0,0 @@
local util = require("scripts.util")
return function(database)
for name, prototype in pairs(global.prototypes.recipe_category) do
database.recipe_category[name] = {
class = "recipe_category",
enabled_at_start = true,
fluids = util.unique_obj_array({}),
items = util.unique_obj_array({}),
prototype_name = name,
recipes = util.unique_obj_array({}),
}
util.add_to_dictionary("recipe_category", name, prototype.localised_name)
util.add_to_dictionary("recipe_category_description", name, prototype.localised_description)
end
end

View File

@ -1,138 +0,0 @@
local math = require("__flib__.math")
local constants = require("constants")
local util = require("scripts.util")
local fluid_proc = require("scripts.database.fluid")
return function(database, metadata)
for name, prototype in pairs(global.prototypes.recipe) do
local category = prototype.category
local group = prototype.group
local enabled_at_start = prototype.enabled
-- Add to recipe category
local category_data = database.recipe_category[category]
category_data.recipes[#category_data.recipes + 1] = { class = "recipe", name = name }
-- Add to group
local group_data = database.group[group.name]
group_data.recipes[#group_data.recipes + 1] = { class = "recipe", name = name }
local data = {
accepted_modules = {},
class = "recipe",
enabled_at_start = enabled_at_start,
energy = prototype.energy,
group = { class = "group", name = group.name },
hidden = prototype.hidden,
made_in = {},
pollution_multiplier = prototype.emissions_multiplier ~= 1 and prototype.emissions_multiplier or nil,
prototype_name = name,
recipe_category = { class = "recipe_category", name = category },
science_packs = {},
subgroup = { class = "group", name = prototype.subgroup.name },
unlocked_by = {},
used_as_fixed_recipe = metadata.fixed_recipes[name],
}
-- Ingredients / products
local fluids = { ingredients = 0, products = 0 }
for lookup_type, io_type in pairs({ ingredient_in = "ingredients", product_of = "products" }) do
local output = {}
for i, material in ipairs(prototype[io_type]) do
local amount_ident = util.build_amount_ident(material)
local material_io_data = {
class = material.type,
name = material.name,
amount_ident = amount_ident,
}
local material_data = database[material.type][material.name]
local lookup_table = material_data[lookup_type]
lookup_table[#lookup_table + 1] = { class = "recipe", name = name }
output[i] = material_io_data
material_data.recipe_categories[#material_data.recipe_categories + 1] = {
class = "recipe_category",
name = category,
}
-- Don't set enabled at start if this is an ignored recipe
local disabled = constants.disabled_categories.recipe_category[category]
if io_type == "products" and (not disabled or disabled ~= 0) then
local subtable = category_data[material.type .. "s"]
subtable[#subtable + 1] = { class = material.type, name = material.name }
-- If this recipe is enabled at start and is not disabled,
-- set enabled at start for its products and their placement results.
if enabled_at_start then
material_data.enabled_at_start = true
for _, property in pairs({ "place_result", "place_as_equipment_result" }) do
local placed_ident = material_data[property]
if placed_ident then
local placed_data = database[placed_ident.class][placed_ident.name]
if placed_data then
placed_data.enabled_at_start = true
end
end
end
end
end
if material.type == "fluid" then
-- Fluid temperatures
local temperature_ident = util.build_temperature_ident(material)
if temperature_ident then
material_io_data.temperature_ident = temperature_ident
fluid_proc.add_temperature(database.fluid[material.name], temperature_ident)
end
-- Add to aggregate
fluids[io_type] = fluids[io_type] + 1
end
end
data[io_type] = output
end
-- Made in
local num_item_ingredients = 0
for _, ingredient in pairs(prototype.ingredients) do
if ingredient.type == "item" then
num_item_ingredients = num_item_ingredients + 1
end
end
for _, crafters in pairs({ global.prototypes.character, global.prototypes.crafter }) do
for crafter_name in pairs(crafters) do
local crafter_data = database.entity[crafter_name]
local fluidbox_counts = metadata.crafter_fluidbox_counts[crafter_name] or { inputs = 0, outputs = 0 }
if
(crafter_data.ingredient_limit or 255) >= num_item_ingredients
and crafter_data.recipe_categories_lookup[category]
and fluidbox_counts.inputs >= fluids.ingredients
and fluidbox_counts.outputs >= fluids.products
then
local crafting_time = math.round(prototype.energy / crafter_data.crafting_speed, 0.01)
data.made_in[#data.made_in + 1] = {
class = "entity",
name = crafter_name,
amount_ident = util.build_amount_ident({ amount = crafting_time, format = "format_seconds_parenthesis" }),
}
crafter_data.can_craft[#crafter_data.can_craft + 1] = { class = "recipe", name = name }
end
end
end
-- Compatible modules
for module_name, module_limitations in pairs(metadata.modules) do
if not next(module_limitations) or module_limitations[name] then
data.accepted_modules[#data.accepted_modules + 1] = { class = "item", name = module_name }
table.insert(database.item[module_name].affects_recipes, { class = "recipe", name = name })
end
end
database.recipe[name] = data
util.add_to_dictionary("recipe", name, prototype.localised_name)
util.add_to_dictionary("recipe_description", name, prototype.localised_description)
end
end

View File

@ -1,15 +0,0 @@
local util = require("scripts.util")
return function(database)
for name, prototype in pairs(global.prototypes.resource_category) do
database.resource_category[name] = {
class = "resource_category",
enabled_at_start = true,
mining_drills = {},
prototype_name = name,
resources = util.unique_obj_array({}),
}
util.add_to_dictionary("resource_category", name, prototype.localised_name)
util.add_to_dictionary("resource_category_description", name, prototype.localised_description)
end
end

View File

@ -1,79 +0,0 @@
local fluid_proc = require("scripts.database.fluid")
local util = require("scripts.util")
return function(database)
--- @type LuaCustomTable<string, LuaEntityPrototype>
local prototypes = global.prototypes.resource
for name, prototype in pairs(prototypes) do
local products = prototype.mineable_properties.products
if products then
for _, product in ipairs(products) do
local product_data = database[product.type][product.name]
if product_data then
product_data.mined_from[#product_data.mined_from + 1] = { class = "resource", name = name }
end
end
end
local required_fluid
local mineable_properties = prototype.mineable_properties
if mineable_properties.required_fluid then
required_fluid = {
class = "fluid",
name = mineable_properties.required_fluid,
-- Ten mining operations per amount consumed, so divide by 10 to get the actual number
amount_ident = util.build_amount_ident({ amount = mineable_properties.fluid_amount / 10 }),
}
else
-- TODO: Validate that it's hand-mineable by checking character mineable categories (requires an API addition)
-- Enable resource items that are hand-minable
for _, product in ipairs(mineable_properties.products or {}) do
if product.type == "item" then
local product_data = database[product.type][product.name]
product_data.enabled_at_start = true
end
end
end
local products = {}
for i, product in pairs(mineable_properties.products or {}) do
products[i] = {
class = product.type,
name = product.name,
amount_ident = util.build_amount_ident(product),
}
-- Fluid temperatures
local temperature_ident = product.type == "fluid" and util.build_temperature_ident(product) or nil
if temperature_ident then
products[i].temperature_ident = temperature_ident
fluid_proc.add_temperature(database.fluid[product.name], temperature_ident)
end
end
local mined_by = {}
local resource_category = prototype.resource_category
for drill_name in pairs(global.prototypes.mining_drill) do
local drill_data = database.entity[drill_name]
if
drill_data.resource_categories_lookup[resource_category]
and (not required_fluid or drill_data.supports_fluid)
then
mined_by[#mined_by + 1] = { class = "entity", name = drill_name }
end
end
local resource_category_data = database.resource_category[resource_category]
resource_category_data.resources[#resource_category_data.resources + 1] = { class = "resource", name = name }
database.resource[name] = {
class = "resource",
mined_by = mined_by,
mining_time = mineable_properties.mining_time,
products = products,
prototype_name = name,
resource_category = { class = "resource_category", name = resource_category },
required_fluid = required_fluid,
}
util.add_to_dictionary("resource", name, prototype.localised_name)
util.add_to_dictionary("resource_description", name, prototype.localised_description)
end
end

View File

@ -1,17 +0,0 @@
local util = require("scripts.util")
return function(database)
--- @type table<string, LuaItemPrototype>
local prototypes = global.prototypes.item
for name, prototype in pairs(prototypes) do
if prototype.type == "tool" then
database.science_pack[name] = {
class = "science_pack",
order = prototype.order,
prototype_name = name,
}
util.add_to_dictionary("science_pack", name, prototype.localised_name)
util.add_to_dictionary("science_pack_description", name, prototype.localised_description)
end
end
end

View File

@ -1,180 +0,0 @@
local math = require("__flib__.math")
local table = require("__flib__.table")
local constants = require("constants")
local util = require("scripts.util")
local function insert_science_packs(database, obj_data, science_packs)
if #science_packs == 0 then
return
end
local existing = obj_data.science_packs
local existing_len = #existing
-- If there are no existing science packs
if #obj_data.science_packs == 0 then
obj_data.science_packs = science_packs
return
end
local existing_highest_ident = existing[existing_len]
local existing_highest_data = database.science_pack[existing_highest_ident.name]
local new_highest_ident = science_packs[#science_packs]
local new_highest_data = database.science_pack[new_highest_ident.name]
-- The object should show when the fewest possible science packs are enabled
if existing_highest_data.order > new_highest_data.order then
obj_data.science_packs = science_packs
end
end
return function(database, metadata)
for name, prototype in pairs(global.prototypes.technology) do
local unlocks_equipment = util.unique_obj_array()
local unlocks_fluids = util.unique_obj_array()
local unlocks_items = util.unique_obj_array()
local unlocks_entities = util.unique_obj_array()
local unlocks_recipes = util.unique_obj_array()
local research_ingredients_per_unit = {}
-- Research units and ingredients per unit
for _, ingredient in ipairs(prototype.research_unit_ingredients) do
research_ingredients_per_unit[#research_ingredients_per_unit + 1] = {
class = ingredient.type,
name = ingredient.name,
amount_ident = util.build_amount_ident({ amount = ingredient.amount }),
}
end
local research_unit_count
local formula = prototype.research_unit_count_formula
if not formula then
research_unit_count = prototype.research_unit_count
end
local science_packs = table.map(prototype.research_unit_ingredients, function(pack)
return { class = "science_pack", name = pack.name }
end)
-- Unlocks recipes, materials, entities
for _, modifier in ipairs(prototype.effects) do
if modifier.type == "unlock-recipe" then
local recipe_data = database.recipe[modifier.recipe]
-- Check if the category should be ignored for recipe availability
local disabled = constants.disabled_categories.recipe_category[recipe_data.recipe_category.name]
if not disabled or disabled ~= 0 then
insert_science_packs(database, recipe_data, science_packs)
recipe_data.unlocked_by[#recipe_data.unlocked_by + 1] = { class = "technology", name = name }
recipe_data.researched_forces = {}
unlocks_recipes[#unlocks_recipes + 1] = { class = "recipe", name = modifier.recipe }
for _, product in pairs(recipe_data.products) do
local product_name = product.name
local product_data = database[product.class][product_name]
local product_ident = { class = product_data.class, name = product_data.prototype_name }
-- For "empty X barrel" recipes, do not unlock the fluid with the recipe
-- This is to avoid fluids getting "unlocked" when they are in reality still 100 hours away
local is_empty_barrel_recipe = string.find(modifier.recipe, "^empty%-.+%-barrel$")
if product_data.class ~= "fluid" or not is_empty_barrel_recipe then
product_data.researched_forces = {}
insert_science_packs(database, product_data, science_packs)
product_data.unlocked_by[#product_data.unlocked_by + 1] = { class = "technology", name = name }
end
-- Materials
if product_data.class == "item" then
unlocks_items[#unlocks_items + 1] = product_ident
elseif product_data.class == "fluid" and not is_empty_barrel_recipe then
unlocks_fluids[#unlocks_fluids + 1] = product_ident
end
-- Entities
local place_result = metadata.place_results[product_name]
if place_result then
local entity_data = database.entity[place_result.name]
if entity_data then
entity_data.researched_forces = {}
insert_science_packs(database, entity_data, science_packs)
entity_data.unlocked_by[#entity_data.unlocked_by + 1] = { class = "technology", name = name }
unlocks_entities[#unlocks_entities + 1] = place_result
end
end
-- Equipment
local place_as_equipment_result = metadata.place_as_equipment_results[product_name]
if place_as_equipment_result then
local equipment_data = database.equipment[place_as_equipment_result.name]
if equipment_data then
equipment_data.researched_forces = {}
insert_science_packs(database, equipment_data, science_packs)
equipment_data.unlocked_by[#equipment_data.unlocked_by + 1] = { class = "technology", name = name }
unlocks_equipment[#unlocks_equipment + 1] = place_as_equipment_result
end
end
end
end
end
end
local level = prototype.level
local max_level = prototype.max_level
database.technology[name] = {
class = "technology",
hidden = prototype.hidden,
max_level = max_level,
min_level = level,
prerequisite_of = {},
prerequisites = {},
prototype_name = name,
researched_forces = {},
research_ingredients_per_unit = research_ingredients_per_unit,
research_unit_count_formula = formula,
research_unit_count = research_unit_count,
research_unit_energy = prototype.research_unit_energy / 60,
science_packs = science_packs,
unlocks_entities = unlocks_entities,
unlocks_equipment = unlocks_equipment,
unlocks_fluids = unlocks_fluids,
unlocks_items = unlocks_items,
unlocks_recipes = unlocks_recipes,
upgrade = prototype.upgrade,
}
-- Assemble name
local localised_name
if level ~= max_level then
localised_name = {
"",
prototype.localised_name,
" (" .. level .. "-" .. (max_level == math.max_uint and "" or max_level) .. ")",
}
else
localised_name = prototype.localised_name
end
util.add_to_dictionary("technology", prototype.name, localised_name)
util.add_to_dictionary("technology_description", name, prototype.localised_description)
end
-- Generate prerequisites and prerequisite_of
for name, technology in pairs(database.technology) do
local prototype = global.prototypes.technology[name]
if prototype.prerequisites then
for prerequisite_name in pairs(prototype.prerequisites) do
technology.prerequisites[#technology.prerequisites + 1] = { class = "technology", name = prerequisite_name }
local prerequisite_data = database.technology[prerequisite_name]
prerequisite_data.prerequisite_of[#prerequisite_data.prerequisite_of + 1] = {
class = "technology",
name = name,
}
end
end
end
end

View File

@ -1,645 +0,0 @@
--[[
DESIGN NOTES:
- Amount strings are not pre-processed, but are generated as part of the format call (allowing for locale differences)
- Multiple caches:
- Base caption
- Base tooltip
- Tooltip contents
- Amount strings
- Control hints
- The output is assembled from these individual caches
- Perhaps the final outputs should be cached as well?
- The idea here is to avoid re-generating the entire caption and tooltip when just the amount or control hints are
different
- Consider moving the show / don't show logic to `util` instead of `formatter`, so it can be used elsewhere
- Per-instance settings:
- show_glyphs
- show_tooltip_details
- amount_only
- is_label: show_glyphs = false, show_tooltip_details = false
]]
local flib_format = require("__flib__.format")
local math = require("__flib__.math")
local table = require("__flib__.table")
local constants = require("constants")
local database = require("scripts.database")
local caches = {}
local formatter = {}
local function build_cache_key(...)
return table.concat(
table.map({ ... }, function(v)
return tostring(v)
end),
"."
)
end
local function expand_string(source, ...)
local arg = { ... }
for i = 1, #arg do
source = string.gsub(source, "__" .. i .. "__", arg[i])
end
return source
end
local function rich_text(key, value, inner)
return "["
.. key
.. "="
.. (key == "color" and constants.colors[value].str or value)
.. "]"
.. inner
.. "[/"
.. key
.. "]"
end
local function sprite(class, name)
return "[img=" .. class .. "/" .. name .. "]"
end
local function control(content, action)
return "\n" .. rich_text("color", "info", rich_text("font", "default-semibold", content .. ":")) .. " " .. action
end
local function number(value)
return flib_format.number(math.round(value, 0.01))
end
local function temperature(value, gui_translations)
return expand_string(gui_translations.format_degrees, number(value))
end
local function area(value, gui_translations)
if type(value) == "number" then
local formatted = number(value)
return expand_string(gui_translations.format_area, formatted, formatted)
else
return expand_string(gui_translations.format_area, number(value.width), number(value.height))
end
end
local function energy(value, gui_translations)
return flib_format.number(value * 60, true, 3) .. gui_translations.si_watt
end
local function energy_storage(value, gui_translations)
return flib_format.number(value, true, 2) .. gui_translations.si_joule
end
local function fuel_value(value, gui_translations)
return flib_format.number(value, true, 3) .. gui_translations.si_joule
end
local function percent(value, gui_translations)
return expand_string(gui_translations.format_percent, number(value * 100))
end
local function seconds(value, gui_translations)
return expand_string(gui_translations.format_seconds, number(value * 60))
end
local function seconds_from_ticks(value, gui_translations)
return seconds(value / 60, gui_translations)
end
local function per_second(value, gui_translations)
return number(value) .. " " .. gui_translations.per_second_suffix
end
local function object(obj, _, player_data, options)
local obj_data = database[obj.class][obj.name]
local obj_options = options and table.shallow_copy(options) or {}
obj_options.amount_ident = obj.amount_ident
local info = formatter(obj_data, player_data, obj_options)
if info then
return info.caption
end
end
local function get_amount_string(amount_ident, player_data, options)
local cache_key = build_cache_key(
"amount_string",
amount_ident.amount,
amount_ident.amount_min,
amount_ident.amount_max,
amount_ident.catalyst_amount,
amount_ident.probability,
amount_ident.format,
options.amount_only,
options.rocket_parts_required
)
local cache = caches[player_data.player_index]
local cached = cache[cache_key]
if cached then
return cached
end
local amount = amount_ident.amount
local output
if options.amount_only then
output = amount_ident.amount and tostring(math.round(amount, 0.1))
or "~" .. math.round((amount_ident.amount_min + amount_ident.amount_max) / 2, 0.1)
else
local gui_translations = player_data.translations.gui
-- Amount
local format_string = gui_translations[amount_ident.format]
if amount then
output = expand_string(format_string, number(amount))
else
output = expand_string(format_string, number(amount_ident.amount_min) .. " - " .. number(amount_ident.amount_max))
end
-- Catalyst amount
local catalyst = amount_ident.catalyst_amount
if catalyst then
output = gui_translations.catalyst_abbrev .. " " .. output
end
-- Probability
local probability = amount_ident.probability
if probability and probability < 1 then
output = math.round(probability * 100, 0.01) .. "% " .. output
end
-- Rocket parts required
-- Hardcoded to always use the `amount` formatter
if options.rocket_parts_required then
output = expand_string(gui_translations.format_amount, options.rocket_parts_required) .. " " .. output
end
end
cache[cache_key] = output
return output
end
local function get_caption(obj_data, obj_properties, player_data, options)
local settings = player_data.settings
local gui_translations = player_data.translations.gui
local prototype_name = obj_data.prototype_name
local name = obj_data.name or prototype_name
local cache = caches[player_data.player_index]
local cache_key =
build_cache_key("caption", obj_data.class, name, obj_properties.enabled, obj_properties.hidden, options.hide_glyph)
local cached = cache[cache_key]
if cached then
return cached
end
local class = obj_data.class
local before = ""
if settings.general.captions.show_glyphs and not options.hide_glyph then
before = rich_text(
"font",
"RecipeBook",
constants.class_to_font_glyph[class] or constants.class_to_font_glyph[class]
) .. " "
end
if obj_properties.hidden then
before = before .. rich_text("font", "default-semibold", gui_translations.hidden_abbrev) .. " "
end
if not obj_properties.enabled then
before = before .. rich_text("font", "default-semibold", gui_translations.disabled_abbrev) .. " "
end
local type = constants.class_to_type[class]
if type then
before = before .. sprite(type, prototype_name) .. " "
end
local after
if settings.general.captions.show_internal_names then
after = name
else
after = player_data.translations[class][name] or name
end
local output = { before = before, after = after }
cache[cache_key] = output
return output
end
local function get_base_tooltip(obj_data, obj_properties, player_data, options)
options = options or {}
local settings = player_data.settings
local gui_translations = player_data.translations.gui
local show_internal_names = settings.general.captions.show_internal_names
local prototype_name = obj_data.prototype_name
local name = obj_data.name or prototype_name
local class = obj_data.class
local type = constants.class_to_type[class]
local catalyst_amount = options.amount_ident and options.amount_ident.catalyst_amount or false
local cache = caches[player_data.player_index]
local cache_key = build_cache_key(
"base_tooltip",
obj_data.class,
name,
obj_properties.enabled,
obj_properties.hidden,
obj_properties.researched,
catalyst_amount
)
local cached = cache[cache_key]
if cached then
return cached
end
local before
if type then
before = sprite(type, prototype_name) .. " "
else
before = ""
end
local name_str
if show_internal_names then
name_str = name
else
name_str = player_data.translations[class][name]
end
local after = rich_text("font", "default-semibold", rich_text("color", "heading", name_str)) .. "\n"
if settings.general.tooltips.show_alternate_name then
local alternate_name
if show_internal_names then
alternate_name = player_data.translations[class][name]
else
alternate_name = name
end
after = after .. rich_text("color", "green", alternate_name) .. "\n"
end
if catalyst_amount then
after = after
.. rich_text("font", "default-semibold", gui_translations.catalyst_amount .. ":")
.. " "
.. number(catalyst_amount)
.. "\n"
end
if settings.general.tooltips.show_descriptions then
local description = player_data.translations[class .. "_description"][name]
if description then
after = after .. description .. "\n"
end
end
after = after .. rich_text("color", "info", gui_translations[class])
if not obj_properties.researched then
after = after .. " | " .. rich_text("color", "unresearched", gui_translations.unresearched)
end
if not obj_properties.enabled then
after = after .. " | " .. gui_translations.disabled
end
if obj_properties.hidden then
after = after .. " | " .. gui_translations.hidden
end
local output = { before = before, after = after }
cache[cache_key] = output
return output
end
local function get_tooltip_deets(obj_data, player_data)
local gui_translations = player_data.translations.gui
local cache = caches[player_data.player_index]
local cache_key = build_cache_key("tooltip_deets", obj_data.class, obj_data.name or obj_data.prototype_name)
local cached = cache[cache_key]
if cached then
return cached
end
local deets_structure = constants.tooltips[obj_data.class]
local output = ""
for _, deet in pairs(deets_structure) do
if deet.source ~= "group" then
local values
local type = deet.type
if type == "plain" then
values = { obj_data[deet.source] }
elseif type == "list" then
values = table.array_copy(obj_data[deet.source] or {})
end
local values_output = ""
for _, value in pairs(values) do
local fmtr = deet.formatter
if fmtr then
value = formatter[fmtr](value, gui_translations, player_data, deet.options)
end
if value then
if type == "plain" then
values_output = values_output .. " " .. value
elseif type == "list" then
values_output = values_output .. "\n " .. value
end
end
end
if #values_output > 0 then
output = output
.. "\n"
.. rich_text("font", "default-semibold", gui_translations[deet.label or deet.source] .. ":")
.. values_output
end
end
end
cache[cache_key] = output
return output
end
local function get_interaction_helps(obj_data, player_data, options)
local gui_translations = player_data.translations.gui
local show_interaction_helps = player_data.settings.general.tooltips.show_interaction_helps
local cache = caches[player_data.player_index]
local cache_key = build_cache_key(
"interaction_helps",
obj_data.class,
obj_data.name or obj_data.prototype_name,
options.blueprint_result and options.blueprint_result.name .. (options.blueprint_result.recipe or "") or nil
)
local cached = cache[cache_key]
if cached then
return cached
end
local helps_output = ""
local interactions = constants.interactions[obj_data.class]
local num_interactions = 0
for _, interaction in pairs(interactions) do
local test = interaction.test
if not test or test(obj_data, options) then
local source = interaction.source
if not source or obj_data[source] then
num_interactions = num_interactions + 1
if show_interaction_helps then
local action = gui_translations[interaction.label or interaction.action]
local input_name = table.reduce(interaction.modifiers, function(acc, modifier)
return acc .. modifier .. "_"
end, "") .. "click"
local button = interaction.button
if button then
button = button .. "_"
else
button = ""
end
local label = rich_text(
"font",
"default-semibold",
rich_text("color", "info", gui_translations[button .. input_name] .. ": ")
)
helps_output = helps_output .. "\n" .. label .. action
end
end
end
end
local output = { output = helps_output, num_interactions = num_interactions }
cache[cache_key] = output
return output
end
local function get_obj_properties(obj_data, player_data, options)
-- Player data
local force = player_data.force
local player_settings = player_data.settings
local show_hidden = player_settings.general.content.show_hidden
local show_unresearched = player_settings.general.content.show_unresearched
local show_disabled = player_settings.general.content.show_disabled
-- Actually get object properties
local researched
if obj_data.enabled_at_start then
researched = true
elseif obj_data.researched_forces then
researched = obj_data.researched_forces[force.index] or false
else
researched = true
end
local enabled = true
-- We have to get the current enabled status from the object itself
-- Recipes are unlocked by "enabling" them, so only check a recipe if it's researched
if obj_data.class == "recipe" and researched then
enabled = player_data.force_recipes[obj_data.prototype_name].enabled
elseif obj_data.class == "technology" then
enabled = player_data.force_technologies[obj_data.prototype_name].enabled
elseif obj_data.enabled ~= nil then
enabled = obj_data.enabled
end
local obj_properties = { hidden = obj_data.hidden or false, researched = researched, enabled = enabled }
-- Determine if we should show this object
local should_show = false
if options.always_show then
should_show = true
elseif
(show_hidden or not obj_properties.hidden)
and (show_unresearched or obj_properties.researched)
and (show_disabled or obj_properties.enabled)
then
-- Indexing the plurals table is much faster than looping through the canonical table
if constants.category_class_plurals[obj_data.class] then
-- Check if this category is enabled
if player_settings.categories[obj_data.class][obj_data.prototype_name] then
should_show = true
end
else
-- Check categories
local good_categories = 0
local has_categories = 0
for _, category in pairs(constants.category_classes) do
local obj_category = obj_data[category]
local obj_categories = obj_data[constants.category_class_plurals[category]]
if obj_category then
has_categories = has_categories + 1
if player_settings.categories[category][obj_category.name] then
good_categories = good_categories + 1
end
elseif obj_categories and #obj_categories > 0 then -- Empty category lists pass by default
has_categories = has_categories + 1
local category_settings = player_settings.categories[category]
if constants.category_all_match[category] then
-- All categories must be enabled
local matched_all = true
for _, category_ident in pairs(obj_categories) do
if not category_settings[category_ident.name] then
matched_all = false
break
end
end
if matched_all then
good_categories = good_categories + 1
end
else
-- At least one category must be enabled
for _, category_ident in pairs(obj_categories) do
if category_settings[category_ident.name] then
good_categories = good_categories + 1
break
end
end
end
end
end
if good_categories == has_categories then
should_show = true
end
end
end
return should_show and obj_properties or false
end
--- @class FormatOptions
local available_options = {
hide_glyphs = false,
base_tooltip_only = false,
label_only = true,
is_label = false,
--- @type AmountIdent|boolean
amount_ident = false,
--- @type number|boolean
rocket_parts_required = false,
amount_only = false,
}
--- @param options FormatOptions
function formatter.format(obj_data, player_data, options)
options = table.deep_merge({ available_options, options or {} })
if options.is_label then
options.hide_glyph = true
options.base_tooltip_only = true
end
local obj_properties = get_obj_properties(obj_data, player_data, options)
if not obj_properties then
return false
end
local amount_ident = options.amount_ident
-- Caption
local caption_output
if amount_ident and options.amount_only then
caption_output = get_amount_string(amount_ident, player_data, options)
else
local caption = get_caption(obj_data, obj_properties, player_data, options)
if amount_ident then
caption_output = caption.before
.. rich_text("font", "default-semibold", get_amount_string(amount_ident, player_data, options))
.. " "
.. caption.after
else
caption_output = caption.before .. caption.after
end
end
-- Tooltip
local base_tooltip = get_base_tooltip(obj_data, obj_properties, player_data, options)
local tooltip_output
if amount_ident and options.amount_only then
tooltip_output = base_tooltip.before
.. rich_text(
"font",
"default-bold",
rich_text("color", "heading", get_amount_string(amount_ident, player_data, {}))
)
.. " "
.. base_tooltip.after
else
tooltip_output = base_tooltip.before .. base_tooltip.after
end
local settings = player_data.settings
if settings.general.tooltips.show_detailed_tooltips and not options.base_tooltip_only then
tooltip_output = tooltip_output .. get_tooltip_deets(obj_data, player_data)
end
local num_interactions = 0
if not options.base_tooltip_only then
local helps_output = get_interaction_helps(obj_data, player_data, options)
tooltip_output = tooltip_output .. helps_output.output
num_interactions = helps_output.num_interactions
end
return {
caption = caption_output,
disabled = not obj_properties.enabled,
hidden = obj_properties.hidden,
num_interactions = num_interactions,
researched = obj_properties.researched,
tooltip = tooltip_output,
}
end
function formatter.create_cache(player_index)
caches[player_index] = {}
end
function formatter.create_all_caches()
for i in pairs(global.players) do
caches[i] = {}
end
end
function formatter.build_player_data(player, player_table)
return {
force = player.force,
force_recipes = player.force.recipes,
force_technologies = player.force.technologies,
player_index = player.index,
settings = player_table.settings,
translations = player_table.translations,
}
end
formatter.area = area
formatter.build_cache_key = build_cache_key
formatter.control = control
formatter.energy = energy
formatter.energy_storage = energy_storage
formatter.expand_string = expand_string
formatter.fuel_value = fuel_value
formatter.number = number
formatter.object = object
formatter.percent = percent
formatter.per_second = per_second
formatter.rich_text = rich_text
formatter.seconds_from_ticks = seconds_from_ticks
formatter.seconds = seconds
formatter.sprite = sprite
formatter.temperature = temperature
setmetatable(formatter, {
__call = function(_, ...)
return formatter.format(...)
end,
})
return formatter

View File

@ -1,62 +0,0 @@
local table = require("__flib__.table")
local constants = require("constants")
local global_data = {}
function global_data.init()
global.forces = {}
global.players = {}
global.prototypes = {}
end
function global_data.build_prototypes()
global.forces = table.shallow_copy(game.forces)
local prototypes = {}
for key, filters in pairs(constants.prototypes.filtered_entities) do
prototypes[key] = table.shallow_copy(game.get_filtered_entity_prototypes(filters))
end
for _, type in pairs(constants.prototypes.straight_conversions) do
prototypes[type] = table.shallow_copy(game[type .. "_prototypes"])
end
global.prototypes = prototypes
end
function global_data.update_sync_data()
global.sync_data = {
active_mods = script.active_mods,
settings = table.map(settings.startup, function(v)
return v
end),
}
end
function global_data.add_force(force)
table.insert(global.forces, force)
end
function global_data.check_should_load()
local sync_data = global.sync_data or { active_mods = {}, settings = {} }
if
global.prototypes
and table.deep_compare(sync_data.active_mods, script.active_mods)
and table.deep_compare(sync_data.settings, settings.startup)
then
for _, prototypes in pairs(global.prototypes) do
for _, prototype in pairs(prototypes) do
if not prototype.valid then
return false
end
end
end
return true
end
return false
end
return global_data

View File

@ -1,304 +0,0 @@
local math = require("__flib__.math")
local on_tick_n = require("__flib__.on-tick-n")
local constants = require("constants")
local database = require("scripts.database")
local gui_util = require("scripts.gui.util")
local util = require("scripts.util")
local actions = {}
--- @param Gui InfoGui
function actions.set_as_active(Gui, _, _)
Gui.player_table.guis.info._active_id = Gui.id
end
--- @param Gui InfoGui
--- @param e on_gui_click
function actions.reset_location(Gui, _, e)
if e.button == defines.mouse_button_type.middle then
Gui.refs.root.force_auto_center()
end
end
--- @param Gui InfoGui
function actions.close(Gui, _, _)
Gui:destroy()
end
--- @param Gui InfoGui
function actions.bring_to_front(Gui, _, _)
if not Gui.state.docked then
Gui.refs.root.bring_to_front()
end
end
--- @param Gui InfoGui
function actions.toggle_search(Gui, _, _)
local state = Gui.state
local refs = Gui.refs
local opened = state.search_opened
state.search_opened = not opened
local search_button = refs.titlebar.search_button
local search_textfield = refs.titlebar.search_textfield
if opened then
search_button.sprite = "utility/search_white"
search_button.style = "frame_action_button"
search_textfield.visible = false
if state.search_query ~= "" then
-- Reset query
search_textfield.text = ""
state.search_query = ""
-- Refresh page
Gui:update_contents()
end
else
-- Show search textfield
search_button.sprite = "utility/search_black"
search_button.style = "flib_selected_frame_action_button"
search_textfield.visible = true
search_textfield.focus()
end
end
--- @param Gui InfoGui
--- @param msg table
--- @param e on_gui_click
function actions.navigate(Gui, msg, e)
-- Update position in history
local delta = msg.delta
local history = Gui.state.history
if e.shift then
if delta < 0 then
history._index = 1
else
history._index = #history
end
else
history._index = math.clamp(history._index + delta, 1, #history)
end
Gui:update_contents()
end
--- @param Gui InfoGui
--- @param msg table
--- @param e on_gui_text_changed
function actions.update_search_query(Gui, msg, e)
local state = Gui.state
local id = msg.id
local query = string.lower(e.element.text)
-- Fuzzy search
if Gui.player_table.settings.general.search.fuzzy_search then
query = string.gsub(query, ".", "%1.*")
end
-- Input sanitization
for pattern, replacement in pairs(constants.input_sanitizers) do
query = string.gsub(query, pattern, replacement)
end
-- Save query
state.search_query = query
-- Remove scheduled update if one exists
if state.update_results_ident then
on_tick_n.remove(state.update_results_ident)
state.update_results_ident = nil
end
if query == "" then
-- Update now
Gui:update_contents({ refresh = true })
else
-- Update in a while
state.update_results_ident = on_tick_n.add(
game.tick + constants.search_timeout,
{ gui = "info", id = id, action = "update_search_results", player_index = e.player_index }
)
end
end
--- @param Gui InfoGui
function actions.update_search_results(Gui, _, _)
-- Update based on query
Gui:update_contents({ refresh = true })
end
--- @param Gui InfoGui
--- @param e on_gui_click
function actions.navigate_to(Gui, _, e)
local context = gui_util.navigate_to(e)
if context then
if e.button == defines.mouse_button_type.middle then
INFO_GUI.build(Gui.player, Gui.player_table, context)
else
Gui:update_contents({ new_context = context })
end
end
end
--- @param Gui InfoGui
--- @param msg table
function actions.navigate_to_plain(Gui, msg, _)
Gui:update_contents({ new_context = msg.context })
end
--- @param Gui InfoGui
function actions.open_in_tech_window(Gui, _, _)
Gui.player_table.flags.technology_gui_open = true
Gui.player.open_technology_gui(Gui:get_context().name)
end
--- @param Gui InfoGui
function actions.go_to_base_fluid(Gui, _, _)
local base_fluid = database.fluid[Gui:get_context().name].prototype_name
Gui:update_contents({ new_context = { class = "fluid", name = base_fluid } })
end
--- @param Gui InfoGui
function actions.toggle_quick_ref(Gui, _, _)
local player = Gui.player
-- Toggle quick ref GUI
local name = Gui:get_context().name
--- @type QuickRefGui?
local QuickRefGui = util.get_gui(player.index, "quick_ref", name)
local to_state = false
if QuickRefGui then
QuickRefGui:destroy()
else
to_state = true
QUICK_REF_GUI.build(player, Gui.player_table, name)
end
-- Update all quick ref buttons
for _, InfoGui in pairs(INFO_GUI.find_open_context(Gui.player_table, Gui:get_context())) do
InfoGui:dispatch({
action = "update_header_button",
button = "quick_ref_button",
to_state = to_state,
})
end
end
--- @param Gui InfoGui
function actions.toggle_favorite(Gui, _, _)
local player_table = Gui.player_table
local favorites = player_table.favorites
local context = Gui:get_context()
local combined_name = context.class .. "." .. context.name
local to_state
if favorites[combined_name] then
to_state = false
favorites[combined_name] = nil
else
-- Copy the table instead of passing a reference
favorites[combined_name] = { class = context.class, name = context.name }
to_state = true
end
for _, InfoGui in pairs(INFO_GUI.find_open_context(Gui.player_table, context)) do
InfoGui:dispatch({ action = "update_header_button", button = "favorite_button", to_state = to_state })
end
local SearchGui = util.get_gui(Gui.player.index, "search")
if SearchGui and SearchGui.refs.window.visible then
SearchGui:dispatch("update_favorites")
end
end
--- @param Gui InfoGui
--- @param msg table
function actions.update_header_button(Gui, msg, _)
local button = Gui.refs.header[msg.button]
if msg.to_state then
button.style = "flib_selected_tool_button"
button.tooltip = constants.header_button_tooltips[msg.button].selected
else
button.style = "tool_button"
button.tooltip = constants.header_button_tooltips[msg.button].unselected
end
end
--- @param Gui InfoGui
--- @param msg table
function actions.open_list(Gui, msg, _)
local list_context = msg.context
local source = msg.source
local list = database[list_context.class][list_context.name][source]
if list and #list > 0 then
local first_obj = list[1]
OPEN_PAGE(Gui.player, Gui.player_table, {
class = first_obj.class,
name = first_obj.name,
list = {
context = list_context,
index = 1,
source = source,
},
})
end
end
--- @param Gui InfoGui
--- @param msg table
function actions.toggle_collapsed(Gui, msg, _)
local context = msg.context
local component_index = msg.component_index
local component_ident = constants.pages[context.class][component_index]
if component_ident then
local state = Gui.state.components[component_index]
if state then
state.collapsed = not state.collapsed
Gui:update_contents({ refresh = true })
end
end
end
--- @param Gui InfoGui
--- @param msg table
function actions.change_tech_level(Gui, msg, _)
local context = Gui:get_context()
local state = Gui.state
local context_data = database[context.class][context.name]
local min = context_data.min_level
local max = context_data.max_level
local new_level = math.clamp(state.selected_tech_level + msg.delta, min, max)
if new_level ~= state.selected_tech_level then
state.selected_tech_level = new_level
Gui:update_contents({ refresh = true })
end
end
--- @param Gui InfoGui
function actions.detach_window(Gui, _, _)
local state = Gui.state
-- Just in case
if not state.docked then
return
end
local context = Gui:get_context()
-- Close this GUI and create a detached one
Gui:destroy()
OPEN_PAGE(Gui.player, Gui.player_table, context)
end
--- @param Gui InfoGui
function actions.print_object(Gui, _, _)
local context = Gui:get_context()
local obj_data = database[context.class][context.name]
if obj_data then
if __DebugAdapter then
__DebugAdapter.print(obj_data)
Gui.player.print("Object data has been printed to the debug console.")
else
log(serpent.block(obj_data))
Gui.player.print("Object data has been printed to the log file.")
end
end
end
return actions

View File

@ -1,653 +0,0 @@
local gui = require("__flib__.gui")
local table = require("__flib__.table")
local constants = require("constants")
local database = require("scripts.database")
local formatter = require("scripts.formatter")
local player_data = require("scripts.player-data")
local util = require("scripts.util")
local components = {
list_box = require("scripts.gui.info.list-box"),
table = require("scripts.gui.info.table"),
}
local function tool_button(sprite, tooltip, ref, action, style_mods)
return {
type = "sprite-button",
style = "tool_button",
style_mods = style_mods,
sprite = sprite,
tooltip = tooltip,
mouse_button_filter = { "left" },
ref = ref,
actions = {
on_click = action,
},
}
end
--- @class InfoGui
local Gui = {}
local actions = require("scripts.gui.info.actions")
function Gui:dispatch(msg, e)
-- Mark this GUI as the active one whenever we do anything
self.player_table.guis.info._active_id = self.id
if type(msg) == "string" then
actions[msg](self, msg, e)
else
actions[msg.action](self, msg, e)
end
end
function Gui:destroy()
self.refs.window.destroy()
self.player_table.guis.info[self.id] = nil
if self.state.docked and not self.state.search_info then
self.player_table.guis.info._relative_id = nil
end
end
function Gui:get_context()
local history = self.state.history
return history[history._index]
end
function Gui:update_contents(options)
options = options or {}
local new_context = options.new_context
local refresh = options.refresh
local state = self.state
local refs = self.refs
-- HISTORY
-- Add new history if needed
local history = state.history
if new_context then
-- Remove all entries after this
for i = history._index + 1, #history do
history[i] = nil
end
-- Insert new entry
local new_index = #history + 1
history[new_index] = new_context
history._index = new_index
-- Limit the length
local max_size = constants.session_history_size
if new_index > max_size then
history._index = max_size
for _ = max_size + 1, new_index do
table.remove(history, 1)
end
end
end
local context = new_context or history[history._index]
if not refresh then
player_data.update_global_history(self.player_table.global_history, context)
local SearchGui = util.get_gui(self.player.index, "search")
if SearchGui then
SearchGui:dispatch("update_history")
end
end
-- COMMON DATA
local obj_data = database[context.class][context.name]
local player_data = formatter.build_player_data(self.player, self.player_table)
local gui_translations = player_data.translations.gui
-- TECH LEVEL
if not refresh and obj_data.research_unit_count_formula then
state.selected_tech_level = player_data.force.technologies[context.name].level
end
-- TITLEBAR
-- Nav buttons
-- Generate tooltips
local history_index = history._index
local history_len = #history
local entries = {}
for i, history_context in ipairs(history) do
local obj_data = database[history_context.class][history_context.name]
local info = formatter(obj_data, player_data, { always_show = true, label_only = true })
local caption = info.caption
if not info.researched then
caption = formatter.rich_text("color", "unresearched", caption)
end
entries[history_len - (i - 1)] = formatter.rich_text(
"font",
"default-semibold",
formatter.rich_text("color", history_index == i and "green" or "invisible", ">")
) .. " " .. caption
end
local entries = table.concat(entries, "\n")
local base_tooltip = formatter.rich_text(
"font",
"default-bold",
formatter.rich_text("color", "heading", gui_translations.session_history)
) .. "\n" .. entries
-- Apply button properties
local nav_backward_button = refs.titlebar.nav_backward_button
if history._index == 1 then
nav_backward_button.enabled = false
nav_backward_button.sprite = "rb_nav_backward_disabled"
else
nav_backward_button.enabled = true
nav_backward_button.sprite = "rb_nav_backward_white"
end
nav_backward_button.tooltip = base_tooltip
.. formatter.control(gui_translations.click, gui_translations.go_backward)
.. formatter.control(gui_translations.shift_click, gui_translations.go_to_the_back)
local nav_forward_button = refs.titlebar.nav_forward_button
if history._index == #history then
nav_forward_button.enabled = false
nav_forward_button.sprite = "rb_nav_forward_disabled"
else
nav_forward_button.enabled = true
nav_forward_button.sprite = "rb_nav_forward_white"
end
nav_forward_button.tooltip = base_tooltip
.. formatter.control(gui_translations.click, gui_translations.go_forward)
.. formatter.control(gui_translations.shift_click, gui_translations.go_to_the_front)
-- Label
local label = refs.titlebar.label
label.caption = gui_translations[context.class]
-- Reset search when moving pages
if not options.refresh and state.search_opened then
state.search_opened = false
local search_button = refs.titlebar.search_button
local search_textfield = refs.titlebar.search_textfield
search_button.sprite = "utility/search_white"
search_button.style = "frame_action_button"
search_textfield.visible = false
if state.search_query ~= "" then
-- Reset query
search_textfield.text = ""
state.search_query = ""
end
end
-- HEADER
-- List navigation
-- List nav is kind of weird because it doesn't respect your settings, but making it respect the settings would be
-- too much work
local list_context = context.list
if list_context then
local source = list_context.context
local source_data = database[source.class][source.name]
local list = source_data[list_context.source]
local list_len = #list
local index = list_context.index
local list_refs = refs.header.list_nav
list_refs.flow.visible = true
-- Labels
local source_info = formatter(source_data, player_data, { always_show = true })
local source_label = list_refs.source_label
source_label.caption = formatter.rich_text("color", "heading", source_info.caption)
.. " - "
.. gui_translations[list_context.source]
local position_label = list_refs.position_label
position_label.caption = " (" .. index .. " / " .. list_len .. ")"
-- Buttons
for delta, button in pairs({ [-1] = list_refs.back_button, [1] = list_refs.forward_button }) do
local new_index = index + delta
if new_index < 1 then
new_index = list_len
elseif new_index > list_len then
new_index = 1
end
local ident = list[new_index]
gui.set_action(button, "on_click", {
gui = "info",
id = self.id,
action = "navigate_to_plain",
context = {
class = ident.class,
name = ident.name,
list = {
context = source,
index = new_index,
source = list_context.source,
},
},
})
end
refs.header.line.visible = true
else
refs.header.list_nav.flow.visible = false
refs.header.line.visible = false
end
-- Label
local title_info = formatter(obj_data, player_data, { always_show = true, is_label = true })
local label = refs.header.label
label.caption = title_info.caption
label.tooltip = title_info.tooltip
label.style = title_info.researched and "rb_toolbar_label" or "rb_unresearched_toolbar_label"
-- Buttons
if context.class == "technology" then
refs.header.open_in_tech_window_button.visible = true
else
refs.header.open_in_tech_window_button.visible = false
end
if context.class == "fluid" and obj_data.temperature_ident then
local base_fluid_button = refs.header.go_to_base_fluid_button
base_fluid_button.visible = true
gui.set_action(base_fluid_button, "on_click", {
gui = "info",
id = self.id,
action = "navigate_to_plain",
context = obj_data.base_fluid,
})
else
refs.header.go_to_base_fluid_button.visible = false
end
if context.class == "recipe" then
local button = refs.header.quick_ref_button
button.visible = true
local is_selected = self.player_table.guis.quick_ref[context.name]
button.style = is_selected and "flib_selected_tool_button" or "tool_button"
button.tooltip = { "gui.rb-" .. (is_selected and "close" or "open") .. "-quick-ref-window" }
else
refs.header.quick_ref_button.visible = false
end
local favorite_button = refs.header.favorite_button
if self.player_table.favorites[context.class .. "." .. context.name] then
favorite_button.style = "flib_selected_tool_button"
favorite_button.tooltip = { "gui.rb-remove-from-favorites" }
else
favorite_button.style = "tool_button"
favorite_button.tooltip = { "gui.rb-add-to-favorites" }
end
-- PAGE
local pane = refs.page_scroll_pane
local page_refs = refs.page_components
local page_settings = self.player_table.settings.pages[context.class]
local i = 0
local visible = false
local component_variables = {
context = context,
gui_id = self.id,
search_query = state.search_query,
selected_tech_level = state.selected_tech_level,
}
-- Add or update relevant components
for _, component_ident in pairs(constants.pages[context.class]) do
i = i + 1
local component = components[component_ident.type]
local component_refs = page_refs[i]
if not component_refs or component_refs.type ~= component_ident.type then
-- Destroy old elements
if component_refs then
component_refs.root.destroy()
end
-- Create new elements
component_refs = component.build(pane, i, component_ident, component_variables)
component_refs.type = component_ident.type
page_refs[i] = component_refs
end
local component_settings = page_settings[component_ident.label or component_ident.source]
if not refresh then
state.components[i] = component.default_state(component_settings)
end
component_variables.component_index = i
component_variables.component_state = state.components[i]
local comp_visible =
component.update(component_ident, component_refs, obj_data, player_data, component_settings, component_variables)
visible = visible or comp_visible
end
-- Destroy extraneous components
for j = i + 1, #page_refs do
page_refs[j].root.destroy()
page_refs[j] = nil
end
-- Show error frame if nothing is visible
if not visible and not state.warning_shown then
state.warning_shown = true
pane.visible = false
refs.page_frame.style = "rb_inside_warning_frame"
refs.page_frame.style.vertically_stretchable = state.docked and state.search_info
refs.warning_flow.visible = true
if state.search_query == "" then
refs.warning_text.caption = { "gui.rb-no-content-warning" }
else
refs.warning_text.caption = { "gui.rb-no-results" }
end
elseif visible and state.warning_shown then
state.warning_shown = false
pane.visible = true
refs.page_frame.style = "inside_shallow_frame"
refs.page_frame.style.vertically_stretchable = state.docked and state.search_info
refs.warning_flow.visible = false
end
end
local index = {}
--- @param player LuaPlayer
--- @param player_table PlayerTable
--- @param context Context
--- @param options table?
function index.build(player, player_table, context, options)
options = options or {}
local id = player_table.guis.info._next_id
player_table.guis.info._next_id = id + 1
local root_elem = options.parent or player.gui.screen
local search_info = root_elem.name == "rb_search_window" or root_elem.name == "rb_visual_search_window"
local relative = options.parent and not search_info
local refs = gui.build(root_elem, {
{
type = "frame",
style_mods = { minimal_width = 430, maximal_width = 600 },
direction = "vertical",
ref = { "window" },
anchor = options.anchor,
actions = {
on_click = { gui = "info", id = id, action = "set_as_active" },
on_closed = { gui = "info", id = id, action = "close" },
},
{
type = "flow",
style = "flib_titlebar_flow",
ref = { "titlebar", "flow" },
actions = {
on_click = not relative and {
gui = search_info and "search" or "info",
id = not search_info and id or nil,
action = "reset_location",
} or nil,
},
util.frame_action_button(
"rb_nav_backward",
nil,
{ "titlebar", "nav_backward_button" },
{ gui = "info", id = id, action = "navigate", delta = -1 }
),
util.frame_action_button(
"rb_nav_forward",
nil,
{ "titlebar", "nav_forward_button" },
{ gui = "info", id = id, action = "navigate", delta = 1 }
),
{
type = "label",
style = "frame_title",
style_mods = { left_margin = 4 },
ignored_by_interaction = true,
ref = { "titlebar", "label" },
},
{
type = "empty-widget",
style = relative and "flib_horizontal_pusher" or "flib_titlebar_drag_handle",
ignored_by_interaction = true,
},
{
type = "textfield",
style_mods = {
top_margin = -3,
right_padding = 3,
width = 120,
},
clear_and_focus_on_right_click = true,
visible = false,
ref = { "titlebar", "search_textfield" },
actions = {
on_text_changed = { gui = "info", id = id, action = "update_search_query" },
},
},
util.frame_action_button(
"utility/search",
{ "gui.rb-search-instruction" },
{ "titlebar", "search_button" },
{ gui = "info", id = id, action = "toggle_search" }
),
options.parent and util.frame_action_button(
"rb_detach",
{ "gui.rb-detach-instruction" },
nil,
{ gui = "info", id = id, action = "detach_window" }
) or {},
util.frame_action_button(
"utility/close",
{ "gui.close" },
{ "titlebar", "close_button" },
{ gui = "info", id = id, action = "close" }
),
},
{
type = "frame",
style = "inside_shallow_frame",
style_mods = { vertically_stretchable = search_info },
direction = "vertical",
ref = { "page_frame" },
action = {
on_click = { gui = "info", id = id, action = "set_as_active" },
},
{
type = "frame",
style = "rb_subheader_frame",
direction = "vertical",
{
type = "flow",
style_mods = { vertical_align = "center" },
visible = false,
ref = { "header", "list_nav", "flow" },
action = {
on_click = { gui = "info", id = id, action = "set_as_active" },
},
tool_button(
"rb_list_nav_backward_black",
{ "gui.rb-go-backward" },
{ "header", "list_nav", "back_button" },
nil,
{ padding = 3 }
),
{ type = "empty-widget", style = "flib_horizontal_pusher" },
{
type = "label",
style = "bold_label",
style_mods = { horizontally_squashable = true },
ref = { "header", "list_nav", "source_label" },
},
{
type = "label",
style = "bold_label",
style_mods = { font_color = constants.colors.info.tbl },
ref = { "header", "list_nav", "position_label" },
},
{ type = "empty-widget", style = "flib_horizontal_pusher" },
tool_button(
"rb_list_nav_forward_black",
{ "gui.rb-go-forward" },
{ "header", "list_nav", "forward_button" },
nil,
{ padding = 3 }
),
},
{
type = "line",
style = "rb_dark_line",
direction = "horizontal",
visible = false,
ref = { "header", "line" },
},
{
type = "flow",
style_mods = { vertical_align = "center" },
{ type = "label", style = "rb_toolbar_label", ref = { "header", "label" } },
{ type = "empty-widget", style = "flib_horizontal_pusher" },
__DebugAdapter and tool_button(nil, "Print", nil, { gui = "info", id = id, action = "print_object" }) or {},
tool_button(
"rb_technology_gui_black",
{ "gui.rb-open-in-technology-window" },
{ "header", "open_in_tech_window_button" },
{ gui = "info", id = id, action = "open_in_tech_window" }
),
tool_button(
"rb_fluid_black",
{ "gui.rb-view-base-fluid" },
{ "header", "go_to_base_fluid_button" },
{ gui = "info", id = id, action = "go_to_base_fluid" }
),
tool_button(
"rb_clipboard_black",
{ "gui.rb-toggle-quick-ref-window" },
{ "header", "quick_ref_button" },
{ gui = "info", id = id, action = "toggle_quick_ref" }
),
tool_button(
"rb_favorite_black",
{ "gui.rb-add-to-favorites" },
{ "header", "favorite_button" },
{ gui = "info", id = id, action = "toggle_favorite" }
),
},
},
{
type = "scroll-pane",
style = "rb_page_scroll_pane",
style_mods = { maximal_height = 900 },
ref = { "page_scroll_pane" },
action = {
on_click = { gui = "info", id = id, action = "set_as_active" },
},
},
{
type = "flow",
style = "rb_warning_flow",
direction = "vertical",
visible = false,
ref = { "warning_flow" },
{
type = "label",
style = "bold_label",
caption = { "gui.rb-no-content-warning" },
ref = { "warning_text" },
},
},
},
},
})
if options.parent then
refs.root = root_elem
else
refs.root = refs.window
refs.root.force_auto_center()
end
if not options.parent or search_info then
refs.titlebar.flow.drag_target = refs.root
end
refs.page_components = {}
--- @class InfoGui
local self = {
id = id,
player = player,
player_table = player_table,
refs = refs,
state = {
components = {},
docked = options.parent and true or false,
history = { _index = 0 },
search_info = search_info,
search_opened = false,
search_query = "",
selected_tech_level = 0,
warning_shown = false,
},
}
index.load(self)
player_table.guis.info[id] = self
player_table.guis.info._active_id = id
if options.anchor then
player_table.guis.info._relative_id = id
end
self:update_contents({ new_context = context })
end
function index.load(self)
setmetatable(self, { __index = Gui })
end
--- Find all info GUIs that are viewing the given context.
--- @param player_table PlayerTable
--- @param context Context
--- @return table<number, InfoGui>
function index.find_open_context(player_table, context)
local open = {}
for id, Gui in pairs(player_table.guis.info) do
if not constants.ignored_info_ids[id] then
local state = Gui.state
local opened_context = state.history[state.history._index]
if opened_context and opened_context.class == context.class and opened_context.name == context.name then
open[id] = Gui
end
end
end
return open
end
-- function root.update_all(player, player_table)
-- for id in pairs(player_table.guis.info) do
-- if not constants.ignored_info_ids[id] then
-- root.update_contents(player, player_table, id, { refresh = true })
-- end
-- end
-- end
-- function root.bring_all_to_front(player_table)
-- for id, gui_data in pairs(player_table.guis.info) do
-- if not constants.ignored_info_ids[id] then
-- if gui_data.state.docked then
-- if gui_data.state.search_info then
-- gui_data.refs.root.bring_to_front()
-- end
-- else
-- gui_data.refs.window.bring_to_front()
-- end
-- end
-- end
-- end
return index

View File

@ -1,190 +0,0 @@
local gui = require("__flib__.gui")
local constants = require("constants")
local database = require("scripts.database")
local formatter = require("scripts.formatter")
local list_box = {}
function list_box.build(parent, index, component, variables)
return gui.build(parent, {
{
type = "flow",
direction = "vertical",
index = index,
ref = { "root" },
action = {
on_click = { gui = "info", id = variables.gui_id, action = "set_as_active" },
},
{
type = "flow",
style_mods = { vertical_align = "center" },
action = {
on_click = { gui = "info", id = variables.gui_id, action = "set_as_active" },
},
{ type = "label", style = "rb_list_box_label", ref = { "label" } },
{ type = "empty-widget", style = "flib_horizontal_pusher" },
{
type = "sprite-button",
style = "mini_button_aligned_to_text_vertically_when_centered",
tooltip = { "gui.rb-open-list-in-new-window" },
sprite = "rb_export_black",
ref = { "open_list_button" },
-- NOTE: Actions are set in the update function
},
{
type = "sprite-button",
style = "mini_button_aligned_to_text_vertically_when_centered",
ref = { "expand_collapse_button" },
-- NOTE: Sprite, tooltip, and action are set in the update function
},
},
{
type = "frame",
style = "deep_frame_in_shallow_frame",
{
type = "scroll-pane",
style = "rb_list_box_scroll_pane",
ref = { "scroll_pane" },
},
},
},
})
end
function list_box.default_state(settings)
return { collapsed = settings.default_state == "collapsed" }
end
function list_box.update(component, refs, context_data, player_data, settings, variables)
-- Scroll pane
local scroll = refs.scroll_pane
local children = scroll.children
-- Settings and variables
local always_show = component.always_show
local context = variables.context
local query = variables.search_query
local search_type = player_data.settings.general.search.search_type
-- Add items
local i = 0 -- The "added" index
local iterator = component.use_pairs and pairs or ipairs
local objects = settings.default_state ~= "hidden" and context_data[component.source] or {}
for _, obj in iterator(objects) do
local translation = player_data.translations[obj.class][obj.name]
-- Match against search string
local matched
if search_type == "both" then
matched = string.find(string.lower(obj.name), query) or string.find(string.lower(translation), query)
elseif search_type == "internal" then
matched = string.find(string.lower(obj.name), query)
elseif search_type == "localised" then
matched = string.find(string.lower(translation), query)
end
if matched then
local obj_data = database[obj.class][obj.name]
local blueprint_result
if context.class == "recipe" and component.source == "made_in" and obj_data.blueprintable then
blueprint_result = { name = obj.name, recipe = context.name }
elseif context.class == "entity" and component.source == "can_craft" and context_data.blueprintable then
blueprint_result = { name = context.name, recipe = obj.name }
end
local info = formatter(obj_data, player_data, {
always_show = always_show,
amount_ident = obj.amount_ident,
blueprint_result = blueprint_result,
rocket_parts_required = obj_data.rocket_parts_required,
})
if info then
i = i + 1
local style = info.researched and "rb_list_box_item" or "rb_unresearched_list_box_item"
local item = children[i]
if item then
item.style = style
item.caption = info.caption
item.tooltip = info.tooltip
item.enabled = info.num_interactions > 0
gui.update_tags(
item,
{ blueprint_result = blueprint_result, context = { class = obj.class, name = obj.name } }
)
else
gui.add(scroll, {
type = "button",
style = style,
caption = info.caption,
tooltip = info.tooltip,
enabled = info.num_interactions > 0,
mouse_button_filter = { "left", "middle" },
tags = {
blueprint_result = blueprint_result,
context = { class = obj.class, name = obj.name },
},
actions = {
on_click = { gui = "info", id = variables.gui_id, action = "navigate_to" },
},
})
end
end
end
end
-- Destroy extraneous items
for j = i + 1, #children do
children[j].destroy()
end
-- Set listbox properties
if i > 0 then
refs.root.visible = true
local translations = player_data.translations.gui
-- Update label caption
refs.label.caption = formatter.expand_string(
translations.list_box_label,
translations[component.source] or component.source,
i
)
-- Update open list button
if i > 1 then
refs.open_list_button.visible = true
gui.set_action(refs.open_list_button, "on_click", {
gui = "info",
id = variables.gui_id,
action = "open_list",
context = variables.context,
source = component.source,
})
else
refs.open_list_button.visible = false
end
-- Update expand/collapse button and height
gui.set_action(refs.expand_collapse_button, "on_click", {
gui = "info",
id = variables.gui_id,
action = "toggle_collapsed",
context = variables.context,
component_index = variables.component_index,
})
if variables.component_state.collapsed then
refs.expand_collapse_button.sprite = "rb_collapsed"
scroll.style.maximal_height = 1
refs.expand_collapse_button.tooltip = { "gui.rb-expand" }
else
refs.expand_collapse_button.sprite = "rb_expanded"
scroll.style.maximal_height = (settings.max_rows or constants.default_max_rows) * 28
refs.expand_collapse_button.tooltip = { "gui.rb-collapse" }
end
else
refs.root.visible = false
end
return i > 0
end
return list_box

View File

@ -1,247 +0,0 @@
local gui = require("__flib__.gui")
local table = require("__flib__.table")
local database = require("scripts.database")
local formatter = require("scripts.formatter")
local table_comp = {}
function table_comp.build(parent, index, component, variables)
local has_label = (component.label or component.source) and true or false
return gui.build(parent, {
{
type = "flow",
style_mods = not has_label and { top_margin = 4 } or nil,
direction = "vertical",
index = index,
ref = { "root" },
action = {
on_click = { gui = "info", id = variables.gui_id, action = "set_as_active" },
},
{
type = "flow",
style_mods = { vertical_align = "center" },
action = {
on_click = { gui = "info", id = variables.gui_id, action = "set_as_active" },
},
visible = has_label,
{ type = "label", style = "rb_list_box_label", ref = { "label" } },
{ type = "empty-widget", style = "flib_horizontal_pusher" },
{
type = "sprite-button",
style = "mini_button_aligned_to_text_vertically_when_centered",
ref = { "expand_collapse_button" },
-- NOTE: Sprite, tooltip, and action are set in the update function
},
},
{
type = "frame",
style = "deep_frame_in_shallow_frame",
action = {
on_click = { gui = "info", id = variables.gui_id, action = "set_as_active" },
},
ref = { "deep_frame" },
{
type = "table",
style = "rb_info_table",
column_count = 2,
ref = { "table" },
-- Dummy elements so the first row doesn't get used
{ type = "empty-widget" },
{ type = "empty-widget" },
},
},
},
})
end
function table_comp.default_state(settings)
return { collapsed = settings.default_state == "collapsed" }
end
function table_comp.update(component, refs, object_data, player_data, settings, variables)
local tbl = refs.table
local children = tbl.children
local gui_translations = player_data.translations.gui
local search_query = variables.search_query
local i = 2
local is_shown = settings.default_state ~= "hidden"
local row_settings = settings.rows
local source_tbl = is_shown and (component.source and object_data[component.source] or component.rows) or {}
for _, row in ipairs(source_tbl) do
local row_name = row.label or row.source
local value = row.value or object_data[row.source]
if value and (not row_settings or row_settings[row_name]) then
local caption = gui_translations[row_name] or row_name
if string.find(string.lower(caption), search_query) then
-- Label
i = i + 1
local label_label = children[i]
if not label_label or not label_label.valid then
label_label = tbl.add({
type = "label",
style = "rb_table_label",
index = i,
})
end
local tooltip = row.label_tooltip
if tooltip then
caption = caption .. " [img=info]"
tooltip = gui_translations[row.label_tooltip]
else
tooltip = ""
end
label_label.caption = caption
label_label.tooltip = tooltip
-- Value
if row.type == "plain" then
local fmt = row.formatter
if fmt then
value = formatter[fmt](value, gui_translations)
end
i = i + 1
local value_label = children[i]
if not value_label or not value_label.valid or value_label.type ~= "label" then
if value_label and value_label.valid then
value_label.destroy()
end
value_label = tbl.add({ type = "label", index = i })
end
value_label.caption = value
elseif row.type == "goto" then
i = i + 1
local button = children[i]
if not button or not button.valid or button.type ~= "button" then
if button and button.valid then
button.destroy()
end
button = tbl.add({
type = "button",
style = "rb_table_button",
mouse_button_filter = { "left", "middle" },
index = i,
})
end
local source_data = database[value.class][value.name]
local options = table.shallow_copy(row.options or {})
options.label_only = true
options.amount_ident = value.amount_ident
options.blueprint_result = value.class == "entity" and source_data.blueprintable and { name = value.name }
or nil
local info = formatter(source_data, player_data, options)
if info then
button.caption = info.caption
button.tooltip = info.tooltip
gui.set_action(button, "on_click", { gui = "info", id = variables.gui_id, action = "navigate_to" })
gui.update_tags(
button,
{ context = { class = value.class, name = value.name }, blueprint_result = options.blueprint_result }
)
else
-- Don't actually show this row
-- This is an ugly way to do it, but whatever
button.destroy()
label_label.destroy()
i = i - 2
end
elseif row.type == "tech_level_selector" then
i = i + 1
local flow = children[i]
if not flow or not flow.valid or flow.type ~= "flow" then
if flow and flow.valid then
flow.destroy()
end
flow = gui.build(tbl, {
{
type = "flow",
style_mods = { vertical_align = "center" },
index = i,
ref = { "flow" },
{
type = "sprite-button",
style = "mini_button_aligned_to_text_vertically_when_centered",
sprite = "rb_minus_black",
mouse_button_filter = { "left" },
actions = {
on_click = { gui = "info", id = variables.gui_id, action = "change_tech_level", delta = -1 },
},
},
{ type = "label", name = "tech_level_label" },
{
type = "sprite-button",
style = "mini_button_aligned_to_text_vertically_when_centered",
sprite = "rb_plus_black",
mouse_button_filter = { "left" },
actions = {
on_click = { gui = "info", id = variables.gui_id, action = "change_tech_level", delta = 1 },
},
},
},
}).flow
end
flow.tech_level_label.caption = formatter.number(variables.selected_tech_level)
elseif row.type == "tech_level_research_unit_count" then
i = i + 1
local value_label = children[i]
if not value_label or value_label.type ~= "label" then
if value_label then
value_label.destroy()
end
value_label = tbl.add({ type = "label", index = i })
end
local tech_level = variables.selected_tech_level
value_label.caption =
formatter[row.formatter](game.evaluate_expression(value, { L = tech_level, l = tech_level }))
end
end
end
end
for j = i + 1, #children do
children[j].destroy()
end
if i > 3 then
refs.root.visible = true
local label_source = component.source or component.label
if label_source then
if component.hide_count then
refs.label.caption = gui_translations[label_source] or label_source
else
refs.label.caption = formatter.expand_string(
gui_translations.list_box_label,
gui_translations[label_source] or label_source,
i / 2 - 1
)
end
end
-- Update expand/collapse button and height
gui.set_action(refs.expand_collapse_button, "on_click", {
gui = "info",
id = variables.gui_id,
action = "toggle_collapsed",
context = variables.context,
component_index = variables.component_index,
})
if variables.component_state.collapsed then
refs.deep_frame.style.maximal_height = 1
refs.expand_collapse_button.sprite = "rb_collapsed"
refs.expand_collapse_button.tooltip = { "gui.rb-expand" }
else
refs.deep_frame.style.maximal_height = 0
refs.expand_collapse_button.sprite = "rb_expanded"
refs.expand_collapse_button.tooltip = { "gui.rb-collapse" }
end
else
refs.root.visible = false
end
return i > 3
end
return table_comp

View File

@ -1,50 +0,0 @@
local gui = require("__flib__.gui")
local gui_util = require("scripts.gui.util")
local actions = {}
--- @param Gui QuickRefGui
function actions.close(Gui, _, _)
Gui:destroy()
end
--- @param Gui QuickRefGui
--- @param e on_gui_click
function actions.reset_location(Gui, _, e)
if e.button == defines.mouse_button_type.middle then
Gui.refs.window.location = { x = 0, y = 0 }
end
end
--- @param Gui QuickRefGui
function actions.bring_to_front(Gui, _, _)
Gui.refs.window.bring_to_front()
end
--- @param Gui QuickRefGui
--- @param e on_gui_click
function actions.handle_button_click(Gui, _, e)
if e.alt then
local button = e.element
local style = button.style.name
if style == "flib_slot_button_green" then
button.style = gui.get_tags(button).previous_style
else
gui.update_tags(button, { previous_style = style })
button.style = "flib_slot_button_green"
end
else
local context = gui_util.navigate_to(e)
if context then
OPEN_PAGE(Gui.player, Gui.player_table, context)
end
end
end
--- @param Gui QuickRefGui
function actions.view_details(Gui, _, _)
OPEN_PAGE(Gui.player, Gui.player_table, { class = "recipe", name = Gui.recipe_name })
end
return actions

View File

@ -1,231 +0,0 @@
local gui = require("__flib__.gui")
local constants = require("constants")
local database = require("scripts.database")
local formatter = require("scripts.formatter")
local util = require("scripts.util")
local function quick_ref_panel(ref)
return {
type = "flow",
direction = "vertical",
ref = { ref, "flow" },
{ type = "label", style = "rb_list_box_label", ref = { ref, "label" } },
{
type = "frame",
style = "rb_slot_table_frame",
ref = { ref, "frame" },
{ type = "table", style = "slot_table", column_count = 5, ref = { ref, "table" } },
},
}
end
--- @class QuickRefGuiRefs
--- @field window LuaGuiElement
--- @field titlebar_flow LuaGuiElement
--- @field label LuaGuiElement
--- @class QuickRefGui
local Gui = {}
local actions = require("scripts.gui.quick-ref.actions")
function Gui:dispatch(msg, e)
if type(msg) == "string" then
actions[msg](self, msg, e)
else
actions[msg.action](self, msg, e)
end
end
function Gui:destroy()
self.refs.window.destroy()
self.player_table.guis.quick_ref[self.recipe_name] = nil
local context = { class = "recipe", name = self.recipe_name }
for _, InfoGui in pairs(INFO_GUI.find_open_context(self.player_table, context)) do
InfoGui:dispatch({
action = "update_header_button",
button = "quick_ref_button",
to_state = false,
})
end
end
function Gui:update_contents()
local refs = self.refs
local show_made_in = self.player_table.settings.general.content.show_made_in_in_quick_ref
local recipe_data = database.recipe[self.recipe_name]
local player_data = formatter.build_player_data(self.player, self.player_table)
-- Label
local recipe_info = formatter(recipe_data, player_data, { always_show = true, is_label = true })
local label = refs.label
label.caption = recipe_info.caption
label.tooltip = recipe_info.tooltip
label.style = recipe_info.researched and "rb_toolbar_label" or "rb_unresearched_toolbar_label"
-- Slot boxes
for _, source in ipairs({ "ingredients", "products", "made_in" }) do
local box = refs[source]
if source == "made_in" and not show_made_in then
box.flow.visible = false
break
else
box.flow.visible = true
end
local table = box.table
local buttons = table.children
local i = 0
for _, object in pairs(recipe_data[source]) do
local object_data = database[object.class][object.name]
local blueprint_result = source == "made_in" and { name = object.name, self.recipe_name } or nil
local object_info = formatter(object_data, player_data, {
always_show = source ~= "made_in",
amount_ident = object.amount_ident,
amount_only = true,
blueprint_result = blueprint_result,
})
if object_info then
i = i + 1
local button_style = object_info.researched and "flib_slot_button_default" or "flib_slot_button_red"
local button = buttons[i]
if button and button.valid then
button.style = button_style
button.sprite = constants.class_to_type[object.class] .. "/" .. object_data.prototype_name
button.tooltip = object_info.tooltip
gui.update_tags(button, {
blueprint_result = blueprint_result,
context = object,
researched = object_data.researched,
})
else
local probability = object.amount_ident.probability
if probability == 1 then
probability = false
end
gui.build(table, {
{
type = "sprite-button",
style = button_style,
sprite = constants.class_to_type[object.class] .. "/" .. object_data.prototype_name,
tooltip = object_info.tooltip,
tags = {
blueprint_result = blueprint_result,
context = object,
researched = object_data.researched,
},
actions = {
on_click = {
gui = "quick_ref",
id = self.recipe_name,
action = "handle_button_click",
source = source,
},
},
{
type = "label",
style = "rb_slot_label",
caption = object_info.caption,
ignored_by_interaction = true,
},
{
type = "label",
style = "rb_slot_label_top",
caption = probability and "%" or "",
ignored_by_interaction = true,
},
},
})
end
end
for j = i + 1, #buttons do
buttons[j].destroy()
end
-- Label
box.label.caption = { "gui.rb-list-box-label", { "gui.rb-" .. string.gsub(source, "_", "-") }, i }
end
end
end
local index = {}
function index.build(player, player_table, recipe_name)
--- @type QuickRefGuiRefs
local refs = gui.build(player.gui.screen, {
{
type = "frame",
direction = "vertical",
ref = { "window" },
{
type = "flow",
style = "flib_titlebar_flow",
ref = { "titlebar_flow" },
actions = {
on_click = { gui = "quick_ref", id = recipe_name, action = "reset_location" },
},
{ type = "label", style = "frame_title", caption = { "gui.rb-recipe" }, ignored_by_interaction = true },
{ type = "empty-widget", style = "flib_titlebar_drag_handle", ignored_by_interaction = true },
util.frame_action_button(
"rb_expand",
{ "gui.rb-view-details" },
nil,
{ gui = "quick_ref", id = recipe_name, action = "view_details" }
),
util.frame_action_button(
"utility/close",
{ "gui.close" },
nil,
{ gui = "quick_ref", id = recipe_name, action = "close" }
),
},
{
type = "frame",
style = "rb_quick_ref_content_frame",
direction = "vertical",
{
type = "frame",
style = "subheader_frame",
{ type = "label", style = "rb_toolbar_label", ref = { "label" } },
{ type = "empty-widget", style = "flib_horizontal_pusher" },
},
{
type = "flow",
style = "rb_quick_ref_content_flow",
direction = "vertical",
quick_ref_panel("ingredients"),
quick_ref_panel("products"),
quick_ref_panel("made_in"),
},
},
},
})
refs.titlebar_flow.drag_target = refs.window
--- @class QuickRefGui
local self = {
player = player,
player_table = player_table,
recipe_name = recipe_name,
refs = refs,
}
index.load(self)
player_table.guis.quick_ref[recipe_name] = self
self:update_contents()
end
function index.load(self)
setmetatable(self, { __index = Gui })
end
return index

View File

@ -1,427 +0,0 @@
local gui = require("__flib__.gui")
local on_tick_n = require("__flib__.on-tick-n")
local table = require("__flib__.table")
local constants = require("constants")
local database = require("scripts.database")
local formatter = require("scripts.formatter")
local gui_util = require("scripts.gui.util")
local util = require("scripts.util")
local actions = {}
--- @param Gui SearchGui
--- @param e on_gui_click
function actions.reset_location(Gui, _, e)
if e.button ~= defines.mouse_button_type.middle then
return
end
if Gui.player_table.settings.general.interface.search_gui_location == "top_left" then
local scale = Gui.player.display_scale
Gui.refs.window.location = table.map(constants.search_gui_top_left_location, function(pos)
return pos * scale
end)
Gui.refs.window.auto_center = false
else
Gui.refs.window.force_auto_center()
end
end
--- @param Gui SearchGui
function actions.close(Gui, _, _)
if not Gui.state.ignore_closed and not Gui.player_table.flags.technology_gui_open then
Gui:close()
end
end
--- @param Gui SearchGui
function actions.toggle_pinned(Gui, _, _)
local player = Gui.player
local refs = Gui.refs
local state = Gui.state
local pin_button = refs.titlebar.pin_button
state.pinned = not state.pinned
if state.pinned then
pin_button.style = "flib_selected_frame_action_button"
pin_button.sprite = "rb_pin_black"
if player.opened == refs.window then
state.ignore_closed = true
player.opened = nil
state.ignore_closed = false
end
else
pin_button.style = "frame_action_button"
pin_button.sprite = "rb_pin_white"
player.opened = refs.window
end
end
--- @param Gui SearchGui
function actions.toggle_settings(Gui, _, _)
local state = Gui.state
local player = Gui.player
state.ignore_closed = true
local SettingsGui = util.get_gui(Gui.player.index, "settings")
if SettingsGui then
SettingsGui:destroy()
else
SETTINGS_GUI.build(player, Gui.player_table)
end
state.ignore_closed = false
local settings_button = Gui.refs.titlebar.settings_button
if Gui.player_table.guis.settings then
settings_button.style = "flib_selected_frame_action_button"
settings_button.sprite = "rb_settings_black"
else
settings_button.style = "frame_action_button"
settings_button.sprite = "rb_settings_white"
if not state.pinned then
player.opened = Gui.refs.window
end
end
end
--- @param Gui SearchGui
function actions.deselect_settings_button(Gui, _, _)
local settings_button = Gui.refs.titlebar.settings_button
settings_button.style = "frame_action_button"
settings_button.sprite = "rb_settings_white"
if not Gui.state.pinned and Gui.refs.window.visible then
Gui.player.opened = Gui.refs.window
end
end
--- @param Gui SearchGui
--- @param e on_gui_text_changed
function actions.update_search_query(Gui, _, e)
local player_table = Gui.player_table
local state = Gui.state
local refs = Gui.refs
local class_filter
local query = string.lower(e.element.text)
if string.find(query, "/") then
-- The `_`s here are technically globals, but whatever
_, _, class_filter, query = string.find(query, "^/(.-)/(.-)$")
if class_filter then
class_filter = string.lower(class_filter)
end
-- Check translations of each class filter
local matched = false
if class_filter then
local gui_translations = player_table.translations.gui
for _, class in pairs(constants.classes) do
if class_filter == string.lower(gui_translations[class]) then
matched = true
class_filter = class
break
end
end
end
-- Invalidate textfield
if not class_filter or not query or not matched then
class_filter = false
query = nil
end
end
-- Remove results update action if there is one
if state.update_results_ident then
on_tick_n.remove(state.update_results_ident)
state.update_results_ident = nil
end
if query then
-- Fuzzy search
if player_table.settings.general.search.fuzzy_search then
query = string.gsub(query, ".", "%1.*")
end
-- Input sanitization
for pattern, replacement in pairs(constants.input_sanitizers) do
query = string.gsub(query, pattern, replacement)
end
-- Save query
state.search_query = query
state.class_filter = class_filter
-- Reset textfield style
refs.search_textfield.style = "rb_search_textfield"
if #query == 0 and not class_filter then
-- Update immediately
actions.update_search_results(Gui)
else
-- Update in a while
state.update_results_ident = on_tick_n.add(
game.tick + constants.search_timeout,
{ gui = "search", action = "update_search_results", player_index = e.player_index }
)
end
else
state.search_query = ""
refs.search_textfield.style = "rb_search_invalid_textfield"
end
end
--- @param Gui SearchGui
function actions.update_search_results(Gui, _, _)
local player = Gui.player
local player_table = Gui.player_table
local state = Gui.state
local refs = Gui.refs
-- Data
local player_data = formatter.build_player_data(player, player_table)
local show_fluid_temperatures = player_table.settings.general.search.show_fluid_temperatures
local search_type = player_table.settings.general.search.search_type
local class_filter = state.class_filter
local query = state.search_query
if state.search_type == "textual" then
-- Update results based on query
local i = 0
local pane = refs.textual_results_pane
local children = pane.children
local max = constants.search_results_limit
if class_filter ~= false and (class_filter or #query >= 2) then
for class in pairs(constants.pages) do
if not class_filter or class_filter == class then
for internal, translation in pairs(player_table.translations[class]) do
-- Match against search string
local matched
if search_type == "both" then
matched = string.find(string.lower(internal), query) or string.find(string.lower(translation), query)
elseif search_type == "internal" then
matched = string.find(string.lower(internal), query)
elseif search_type == "localised" then
matched = string.find(string.lower(translation), query)
end
if matched then
local obj_data = database[class][internal]
-- Check temperature settings
local passed = true
if obj_data.class == "fluid" then
local temperature_ident = obj_data.temperature_ident
if temperature_ident then
local is_range = temperature_ident.min ~= temperature_ident.max
if is_range then
if show_fluid_temperatures ~= "all" then
passed = false
end
else
if show_fluid_temperatures == "off" then
passed = false
end
end
end
end
if passed then
local blueprint_result = class == "entity" and obj_data.blueprintable and { name = internal } or nil
local info = formatter(obj_data, player_data, { blueprint_result = blueprint_result })
if info then
i = i + 1
local style = info.researched and "rb_list_box_item" or "rb_unresearched_list_box_item"
local item = children[i]
if item then
item.style = style
item.caption = info.caption
item.tooltip = info.tooltip
item.enabled = info.num_interactions > 0
gui.update_tags(
item,
{ blueprint_result = blueprint_result, context = { class = class, name = internal } }
)
else
gui.add(pane, {
type = "button",
style = style,
caption = info.caption,
tooltip = info.tooltip,
enabled = info.num_interactions > 0,
mouse_button_filter = { "left", "middle" },
tags = {
blueprint_result = blueprint_result,
context = { class = class, name = internal },
},
actions = {
on_click = { gui = "search", action = "open_object" },
},
})
if i >= max then
break
end
end
end
end
end
end
end
if i >= max then
break
end
end
end
-- Destroy extraneous items
for j = i + 1, #children do
children[j].destroy()
end
elseif state.search_type == "visual" then
refs.objects_frame.visible = true
refs.warning_frame.visible = false
--- @type LuaGuiElement
local group_table = refs.group_table
for _, group_scroll in pairs(refs.objects_frame.children) do
local group_has_results = false
for _, subgroup_table in pairs(group_scroll.children) do
local visible_count = 0
for _, obj_button in pairs(subgroup_table.children) do
local context = gui.get_tags(obj_button).context
local matched
-- Match against class filter
if not class_filter or class_filter == context.class then
local translation = player_data.translations[context.class][context.name]
-- Match against search string
if search_type == "both" then
matched = string.find(string.lower(context.name), query) or string.find(string.lower(translation), query)
elseif search_type == "internal" then
matched = string.find(string.lower(context.name), query)
elseif search_type == "localised" then
matched = string.find(string.lower(translation), query)
end
end
if matched then
obj_button.visible = true
visible_count = visible_count + 1
else
obj_button.visible = false
end
end
if visible_count > 0 then
group_has_results = true
subgroup_table.visible = true
else
subgroup_table.visible = false
end
end
local group_name = group_scroll.name
local group_button = group_table[group_name]
if group_has_results then
group_button.style = "rb_filter_group_button_tab"
group_button.enabled = state.active_group ~= group_scroll.name
if state.active_group == group_name then
group_scroll.visible = true
else
group_scroll.visible = false
end
else
group_scroll.visible = false
group_button.style = "rb_disabled_filter_group_button_tab"
group_button.enabled = false
if state.active_group == group_name then
local matched = false
for _, group_button in pairs(group_table.children) do
if group_button.enabled then
matched = true
actions.change_group(Gui, { group = group_button.name, ignore_last_button = true })
break
end
end
if not matched then
refs.objects_frame.visible = false
refs.warning_frame.visible = true
end
end
end
end
end
end
--- @param Gui SearchGui
--- @param e on_gui_click
function actions.open_object(Gui, _, e)
local context = gui_util.navigate_to(e)
if context then
local attach = Gui.player_table.settings.general.interface.attach_search_results
local sticky = attach and e.button == defines.mouse_button_type.left
local id = sticky and Gui.state.id and Gui.player_table.guis.info[Gui.state.id] and Gui.state.id or nil
local parent = sticky and Gui.refs.window or nil
OPEN_PAGE(Gui.player, Gui.player_table, context, { id = id, parent = parent })
if sticky and not id then
Gui.state.id = Gui.player_table.guis.info._active_id
end
if not sticky and Gui.player_table.settings.general.interface.close_search_gui_after_selection then
actions.close(Gui)
end
end
end
--- @param Gui SearchGui
function actions.change_search_type(Gui)
local state = Gui.state
local refs = Gui.refs
if state.search_type == "textual" then
state.search_type = "visual"
refs.textual_results_pane.visible = false
refs.visual_results_flow.visible = true
if state.needs_visual_update then
state.needs_visual_update = false
Gui:update_visual_contents()
end
elseif state.search_type == "visual" then
state.search_type = "textual"
refs.textual_results_pane.visible = true
refs.visual_results_flow.visible = false
end
actions.update_search_results(Gui)
end
--- @param Gui SearchGui
--- @param msg table
function actions.change_group(Gui, msg)
local last_group = Gui.state.active_group
if not msg.ignore_last_button then
Gui.refs.group_table[last_group].enabled = true
end
Gui.refs.objects_frame[last_group].visible = false
local new_group = msg.group
Gui.refs.group_table[new_group].enabled = false
Gui.refs.objects_frame[new_group].visible = true
Gui.state.active_group = msg.group
end
--- @param Gui SearchGui
function actions.update_favorites(Gui, _, _)
Gui:update_favorites()
end
--- @param Gui SearchGui
function actions.update_history(Gui, _, _)
Gui:update_history()
end
--- @param Gui SearchGui
function actions.delete_favorites(Gui, _, _)
Gui.player_table.favorites = {}
Gui:update_favorites()
end
--- @param Gui SearchGui
function actions.delete_history(Gui, _, _)
Gui.player_table.global_history = {}
Gui:update_history()
end
return actions

View File

@ -1,512 +0,0 @@
local gui = require("__flib__.gui")
local table = require("__flib__.table")
local constants = require("constants")
local database = require("scripts.database")
local formatter = require("scripts.formatter")
local gui_util = require("scripts.gui.util")
local util = require("scripts.util")
--- @class SearchGuiRefs
--- @field window LuaGuiElement
--- @field titlebar SearchGuiTitlebarRefs
--- @field tabbed_pane LuaGuiElement
--- @field search_textfield LuaGuiElement
--- @field textual_results_pane LuaGuiElement
--- @field visual_results_flow LuaGuiElement
--- @field group_table LuaGuiElement
--- @field objects_frame LuaGuiElement
--- @field warning_frame LuaGuiElement
--- @field delete_favorites_button LuaGuiElement
--- @field delete_history_button LuaGuiElement
--- @field favorites_pane LuaGuiElement
--- @field history_pane LuaGuiElement
--- @class SearchGuiTitlebarRefs
--- @field flow LuaGuiElement
--- @field drag_handle LuaGuiElement
--- @field pin_button LuaGuiElement
--- @field settings_button LuaGuiElement
--- @class SearchGui
local Gui = {}
local actions = require("scripts.gui.search.actions")
function Gui:dispatch(msg, e)
if type(msg) == "string" then
actions[msg](self, msg, e)
else
actions[msg.action](self, msg, e)
end
end
function Gui:destroy()
if self.refs.window.valid then
self.refs.window.destroy()
end
self.player_table.guis.search = nil
self.player.set_shortcut_toggled("rb-search", false)
end
function Gui:open()
local refs = self.refs
refs.window.visible = true
refs.window.bring_to_front()
refs.tabbed_pane.selected_tab_index = 1
refs.search_textfield.select_all()
refs.search_textfield.focus()
if not self.state.pinned then
self.player.opened = refs.window
end
-- Workaround to prevent the search GUI from centering itself if the player doesn't manually recenter
if self.player_table.settings.general.interface.search_gui_location ~= "center" then
refs.window.auto_center = false
end
self.player.set_shortcut_toggled("rb-search", true)
if self.state.search_type == "visual" and self.state.needs_visual_update then
self:update_visual_contents()
end
end
function Gui:close()
local window = self.player_table.guis.search.refs.window
window.visible = false
local player = self.player
player.set_shortcut_toggled("rb-search", false)
if player.opened == window then
player.opened = nil
end
end
function Gui:toggle()
if self.refs.window.visible then
self:close()
else
self:open()
end
end
function Gui:update_visual_contents()
self.state.needs_visual_update = false
local player_data = formatter.build_player_data(self.player, self.player_table)
local show_fluid_temperatures = player_data.settings.general.search.show_fluid_temperatures
local groups = {}
for _, objects in pairs(
{ database.item, database.fluid }
-- { database.recipe }
) do
for name, object in pairs(objects) do
-- Create / retrieve group and subgroup
local group = object.group
local group_table = groups[group.name]
if not group_table then
group_table = {
button = {
type = "sprite-button",
name = group.name,
style = "rb_filter_group_button_tab",
sprite = "item-group/" .. group.name,
tooltip = { "item-group-name." .. group.name },
actions = {
on_click = { gui = "search", action = "change_group", group = group.name },
},
},
members = 0,
scroll_pane = {
type = "scroll-pane",
name = group.name,
style = "rb_filter_scroll_pane",
vertical_scroll_policy = "always",
visible = false,
},
subgroups = {},
}
groups[group.name] = group_table
end
local subgroup = object.subgroup
local subgroup_table = group_table.subgroups[subgroup.name]
if not subgroup_table then
subgroup_table = { type = "table", style = "slot_table", column_count = 10 }
group_table.subgroups[subgroup.name] = subgroup_table
table.insert(group_table.scroll_pane, subgroup_table)
end
-- Check fluid temperature
local matched = true
local temperature_ident = object.temperature_ident
if temperature_ident then
local is_range = temperature_ident.min ~= temperature_ident.max
if is_range then
if show_fluid_temperatures ~= "all" then
matched = false
end
else
if show_fluid_temperatures == "off" then
matched = false
end
end
end
if matched then
local blueprint_result = object.place_result and { name = object.place_result.name } or nil
local formatted = formatter(object, player_data, { blueprint_result = blueprint_result })
if formatted then
group_table.members = group_table.members + 1
local style = "default"
if formatted.disabled or formatted.hidden then
style = "grey"
elseif not formatted.researched then
style = "red"
end
-- Create the button
table.insert(subgroup_table, {
type = "sprite-button",
style = "flib_slot_button_" .. style,
sprite = object.class .. "/" .. object.prototype_name,
tooltip = formatted.tooltip,
mouse_button_filter = { "left", "middle", "right" },
tags = {
blueprint_result = blueprint_result,
context = { class = object.class, name = name },
},
actions = {
on_click = { gui = "search", action = "open_object" },
},
temperature_ident and {
type = "label",
style = "rb_slot_label",
caption = temperature_ident.short_string,
ignored_by_interaction = true,
} or nil,
temperature_ident and temperature_ident.short_top_string and {
type = "label",
style = "rb_slot_label_top",
caption = temperature_ident.short_top_string,
ignored_by_interaction = true,
} or nil,
})
end
end
end
end
local group_buttons = {}
local group_scroll_panes = {}
local first_group
for group_name, group in pairs(groups) do
if group.members > 0 then
table.insert(group_buttons, group.button)
table.insert(group_scroll_panes, group.scroll_pane)
if not first_group then
first_group = group_name
end
end
end
if
#self.state.active_group == 0
or not table.for_each(group_buttons, function(button)
return button.name == self.state.active_group
end)
then
self.state.active_group = first_group
end
local refs = self.refs
refs.group_table.clear()
gui.build(refs.group_table, group_buttons)
refs.objects_frame.clear()
gui.build(refs.objects_frame, group_scroll_panes)
self:dispatch({ action = "change_group", group = self.state.active_group, ignore_last_button = true })
self:dispatch("update_search_results")
end
function Gui:update_favorites()
local favorites = self.player_table.favorites
local refs = self.refs
gui_util.update_list_box(
refs.favorites_pane,
favorites,
formatter.build_player_data(self.player, self.player_table),
pairs,
{ always_show = true }
)
refs.delete_favorites_button.enabled = next(favorites) and true or false
for id, InfoGui in pairs(self.player_table.guis.info) do
if not constants.ignored_info_ids[id] then
local context = InfoGui:get_context()
local to_state = favorites[context.class .. "." .. context.name]
InfoGui:dispatch({ action = "update_header_button", button = "favorite_button", to_state = to_state })
end
end
end
function Gui:update_history()
local refs = self.refs
gui_util.update_list_box(
refs.history_pane,
self.player_table.global_history,
formatter.build_player_data(self.player, self.player_table),
ipairs,
{ always_show = true }
)
refs.delete_history_button.enabled = next(self.player_table.global_history) and true or false
end
function Gui:bring_to_front()
self.refs.window.bring_to_front()
end
local index = {}
--- @param player LuaPlayer
--- @param player_table PlayerTable
function index.build(player, player_table)
--- @type SearchGuiRefs
local gui_type = player_table.settings.general.search.default_gui_type
local refs = gui.build(player.gui.screen, {
{
type = "frame",
name = "rb_search_window",
style = "invisible_frame",
visible = false,
ref = { "window" },
actions = {
on_closed = { gui = "search", action = "close" },
},
-- Search frame
{
type = "frame",
direction = "vertical",
{
type = "flow",
style = "flib_titlebar_flow",
ref = { "titlebar", "flow" },
actions = {
on_click = { gui = "search", action = "reset_location" },
},
{
type = "label",
style = "frame_title",
caption = { "gui.rb-search-title" },
ignored_by_interaction = true,
},
{ type = "empty-widget", style = "flib_titlebar_drag_handle", ignored_by_interaction = true },
util.frame_action_button(
"rb_pin",
{ "gui.rb-pin-instruction" },
{ "titlebar", "pin_button" },
{ gui = "search", action = "toggle_pinned" }
),
util.frame_action_button(
"rb_settings",
{ "gui.rb-settings-instruction" },
{ "titlebar", "settings_button" },
{ gui = "search", action = "toggle_settings" }
),
util.frame_action_button(
"utility/close",
{ "gui.close" },
{ "titlebar", "close_button" },
{ gui = "search", action = "close" }
),
},
{
type = "frame",
style = "inside_deep_frame_for_tabs",
direction = "vertical",
ref = { "tab_frame" },
{
type = "tabbed-pane",
style = "tabbed_pane_with_no_side_padding",
style_mods = { maximal_width = 426 },
ref = { "tabbed_pane" },
{
tab = { type = "tab", caption = { "gui.search" } },
content = {
type = "frame",
style = "rb_inside_deep_frame_under_tabs",
direction = "vertical",
{
type = "frame",
style = "rb_subheader_frame",
{
type = "textfield",
style = "flib_widthless_textfield",
style_mods = { horizontally_stretchable = true },
clear_and_focus_on_right_click = true,
ref = { "search_textfield" },
actions = {
on_text_changed = { gui = "search", action = "update_search_query" },
},
},
-- {
-- type = "sprite-button",
-- style = "tool_button",
-- tooltip = { "gui.rb-search-filters" },
-- sprite = "rb_filter",
-- actions = {
-- on_click = { gui = "search", action = "toggle_filters" },
-- },
-- },
{
type = "sprite-button",
style = "tool_button",
tooltip = { "gui.rb-change-search-type" },
sprite = "rb_swap",
actions = {
on_click = { gui = "search", action = "change_search_type" },
},
},
},
{
type = "scroll-pane",
style = "rb_search_results_scroll_pane",
ref = { "textual_results_pane" },
visible = gui_type == "textual",
},
{
type = "flow",
style_mods = { padding = 0, margin = 0, vertical_spacing = 0 },
direction = "vertical",
visible = gui_type == "visual",
ref = { "visual_results_flow" },
{
type = "table",
style = "filter_group_table",
style_mods = { width = 426 },
column_count = 6,
ref = { "group_table" },
},
{
type = "frame",
style = "rb_filter_frame",
{
type = "frame",
style = "deep_frame_in_shallow_frame",
style_mods = { natural_height = 40 * 15, natural_width = 40 * 10 },
ref = { "objects_frame" },
},
{
type = "frame",
style = "rb_warning_frame_in_shallow_frame",
style_mods = { height = 40 * 15, width = 40 * 10 },
ref = { "warning_frame" },
visible = false,
{
type = "flow",
style = "rb_warning_flow",
direction = "vertical",
{ type = "label", style = "bold_label", caption = { "gui.rb-no-results" } },
},
},
},
},
},
},
{
tab = { type = "tab", caption = { "gui.rb-favorites" } },
content = {
type = "frame",
style = "rb_inside_deep_frame_under_tabs",
direction = "vertical",
{
type = "frame",
style = "subheader_frame",
{ type = "empty-widget", style = "flib_horizontal_pusher" },
{
type = "sprite-button",
style = "tool_button_red",
sprite = "utility/trash",
tooltip = { "gui.rb-delete-favorites" },
ref = { "delete_favorites_button" },
actions = {
on_click = { gui = "search", action = "delete_favorites" },
},
},
},
{ type = "scroll-pane", style = "rb_search_results_scroll_pane", ref = { "favorites_pane" } },
},
},
{
tab = { type = "tab", caption = { "gui.rb-history" } },
content = {
type = "frame",
style = "rb_inside_deep_frame_under_tabs",
direction = "vertical",
{
type = "frame",
style = "subheader_frame",
{ type = "empty-widget", style = "flib_horizontal_pusher" },
{
type = "sprite-button",
style = "tool_button_red",
sprite = "utility/trash",
tooltip = { "gui.rb-delete-history" },
ref = { "delete_history_button" },
actions = {
on_click = { gui = "search", action = "delete_history" },
},
},
},
{ type = "scroll-pane", style = "rb_search_results_scroll_pane", ref = { "history_pane" } },
},
},
},
},
},
},
})
refs.titlebar.flow.drag_target = refs.window
if player_table.settings.general.interface.search_gui_location == "top_left" then
refs.window.location = table.map(constants.search_gui_top_left_location, function(pos)
return pos * player.display_scale
end)
else
refs.window.force_auto_center()
end
--- @class SearchGui
local self = {
player = player,
player_table = player_table,
state = {
active_group = "",
ignore_closed = false,
needs_visual_update = true,
search_query = "",
search_type = gui_type,
pinned = false,
},
refs = refs,
}
index.load(self)
player_table.guis.search = self
self:update_favorites()
self:update_history()
if gui_type == "visual" then
self:update_visual_contents()
end
end
function index.load(self)
setmetatable(self, { __index = Gui })
end
return index

View File

@ -1,200 +0,0 @@
local on_tick_n = require("__flib__.on-tick-n")
local constants = require("constants")
local util = require("scripts.util")
local actions = {}
--- @param Gui SettingsGui
function actions.close(Gui, _, _)
Gui:destroy()
local SearchGui = util.get_gui(Gui.player.index, "search")
if SearchGui then
SearchGui:dispatch("deselect_settings_button")
end
end
--- @param Gui SettingsGui
--- @param e on_gui_click
function actions.reset_location(Gui, _, e)
if e.button == defines.mouse_button_type.middle then
Gui.refs.window.force_auto_center()
end
end
--- @param Gui SettingsGui
function actions.toggle_search(Gui, _, _)
local state = Gui.state
local refs = Gui.refs
local opened = state.search_opened
state.search_opened = not opened
local search_button = refs.titlebar.search_button
local search_textfield = refs.titlebar.search_textfield
if opened then
search_button.style = "frame_action_button"
search_button.sprite = "utility/search_white"
search_textfield.visible = false
if state.search_query ~= "" then
-- Reset query
search_textfield.text = ""
state.search_query = ""
-- Immediately refresh page
Gui:update_contents()
end
else
-- Show search textfield
search_button.style = "flib_selected_frame_action_button"
search_button.sprite = "utility/search_black"
search_textfield.visible = true
search_textfield.focus()
end
end
--- @param Gui SettingsGui
--- @param e on_gui_text_changed
function actions.update_search_query(Gui, _, e)
local player_table = Gui.player_table
local state = Gui.state
local query = string.lower(e.element.text)
-- Fuzzy search
if player_table.settings.general.search.fuzzy_search then
query = string.gsub(query, ".", "%1.*")
end
-- Input sanitization
for pattern, replacement in pairs(constants.input_sanitizers) do
query = string.gsub(query, pattern, replacement)
end
-- Save query
state.search_query = query
-- Remove scheduled update if one exists
if state.update_results_ident then
on_tick_n.remove(state.update_results_ident)
state.update_results_ident = nil
end
if query == "" then
-- Update now
actions.update_search_results(Gui)
else
-- Update in a while
state.update_results_ident = on_tick_n.add(
game.tick + constants.search_timeout,
{ gui = "settings", action = "update_search_results", player_index = e.player_index }
)
end
end
--- @param Gui SettingsGui
function actions.update_search_results(Gui, _, _)
Gui:update_contents()
end
--- @param Gui SettingsGui
--- @param msg table
--- @param e on_gui_checked_state_changed|on_gui_selection_state_changed
function actions.change_general_setting(Gui, msg, e)
local type = msg.type
local category = msg.category
local name = msg.name
local setting_ident = constants.general_settings[category][name]
local settings = Gui.player_table.settings.general[category]
local new_value
local element = e.element
-- NOTE: This shouldn't ever happen, but we will avoid a crash just in case!
if not element.valid then
return
end
if type == "bool" then
new_value = element.state
elseif type == "enum" then
local selected_index = element.selected_index
new_value = setting_ident.options[selected_index]
end
-- NOTE: This _also_ shouldn't ever happen, but you can't be too safe!
if new_value ~= nil then
settings[name] = new_value
REFRESH_CONTENTS(Gui.player, Gui.player_table)
-- Update enabled statuses
Gui:update_contents("general")
end
end
--- @param Gui SettingsGui
--- @param e on_gui_selection_state_changed
function actions.change_category(Gui, _, e)
Gui.state.selected_category = e.element.selected_index
Gui:update_contents("categories")
end
--- @param Gui SettingsGui
--- @param msg table
--- @param e on_gui_checked_state_changed
function actions.change_category_setting(Gui, msg, e)
local class = msg.class
local name = msg.name
local category_settings = Gui.player_table.settings.categories[class]
category_settings[name] = e.element.state
REFRESH_CONTENTS(Gui.player, Gui.player_table)
end
--- @param Gui SettingsGui
--- @param e on_gui_selected_tab_changed
function actions.change_page(Gui, _, e)
Gui.state.selected_page = e.element.selected_index
Gui:update_contents("pages")
end
--- @param Gui SettingsGui
--- @param msg table
--- @param e on_gui_selection_state_changed
function actions.change_default_state(Gui, msg, e)
local class = msg.class
local component = msg.component
local component_settings = Gui.player_table.settings.pages[class][component]
if component_settings then
component_settings.default_state = constants.component_states[e.element.selected_index]
end
REFRESH_CONTENTS(Gui.player, Gui.player_table)
end
--- @param Gui SettingsGui
--- @param msg table
--- @param e on_gui_text_changed
function actions.change_max_rows(Gui, msg, e)
local class = msg.class
local component = msg.component
local component_settings = Gui.player_table.settings.pages[class][component]
if component_settings then
component_settings.max_rows = tonumber(e.element.text)
end
REFRESH_CONTENTS(Gui.player, Gui.player_table)
end
--- @param Gui SettingsGui
--- @param msg table
--- @param e on_gui_checked_state_changed
function actions.change_row_visible(Gui, msg, e)
local class = msg.class
local component = msg.component
local row = msg.row
local component_settings = Gui.player_table.settings.pages[class][component]
if component_settings then
component_settings.rows[row] = e.element.state
end
REFRESH_CONTENTS(Gui.player, Gui.player_table)
end
return actions

View File

@ -1,414 +0,0 @@
local gui = require("__flib__.gui")
local table = require("__flib__.table")
local constants = require("constants")
local database = require("scripts.database")
local util = require("scripts.util")
--- @class SettingsGui
local Gui = {}
local actions = require("scripts.gui.settings.actions")
function Gui:dispatch(msg, e)
if type(msg) == "string" then
actions[msg](self, msg, e)
else
actions[msg.action](self, msg, e)
end
end
function Gui:destroy()
self.player_table.guis.settings.refs.window.destroy()
self.player_table.guis.settings = nil
end
function Gui:update_contents(tab)
local refs = self.refs
local state = self.state
local query = state.search_query
local translations = self.player_table.translations
local gui_translations = translations.gui
local actual_settings = self.player_table.settings
-- For simplicity's sake, since there's not _that much_ going on here, we will just destroy and recreate things
-- instead of updating them.
-- GENERAL
if not tab or tab == "general" then
local general_pane = refs.general.pane
general_pane.clear()
for category, settings in pairs(constants.general_settings) do
local actual_category_settings = actual_settings.general[category]
local children = {}
for setting_name, setting_ident in pairs(settings) do
local caption = gui_translations[setting_name] or setting_name
if string.find(string.lower(caption), query) then
local converted_setting_name = string.gsub(setting_name, "_", "-")
local tooltip = ""
if setting_ident.has_tooltip then
tooltip = { "gui.rb-" .. converted_setting_name .. "-description" }
caption = caption .. " [img=info]"
end
local enabled = true
if setting_ident.dependencies then
for _, dependency in pairs(setting_ident.dependencies) do
if actual_settings.general[dependency.category][dependency.name] ~= dependency.value then
enabled = false
break
end
end
end
if setting_ident.type == "bool" then
children[#children + 1] = {
type = "checkbox",
caption = caption,
tooltip = tooltip,
state = actual_category_settings[setting_name],
enabled = enabled,
actions = enabled and {
on_click = {
gui = "settings",
action = "change_general_setting",
type = setting_ident.type,
category = category,
name = setting_name,
},
} or nil,
}
elseif setting_ident.type == "enum" then
children[#children + 1] = {
type = "flow",
style_mods = { vertical_align = "center" },
{ type = "label", caption = caption, tooltip = tooltip },
{ type = "empty-widget", style = "flib_horizontal_pusher" },
{
type = "drop-down",
items = table.map(setting_ident.options, function(option_name)
return { "gui.rb-" .. converted_setting_name .. "-" .. string.gsub(option_name, "_", "-") }
end),
selected_index = table.find(setting_ident.options, actual_category_settings[setting_name]),
enabled = enabled,
actions = enabled and {
on_selection_state_changed = {
gui = "settings",
action = "change_general_setting",
type = setting_ident.type,
category = category,
name = setting_name,
},
} or nil,
},
}
end
end
end
if #children > 0 then
gui.build(general_pane, {
{
type = "frame",
style = "bordered_frame",
direction = "vertical",
caption = gui_translations[category] or category,
children = children,
},
})
end
end
end
-- CATEGORIES
if not tab or tab == "categories" then
local categories_frame = refs.categories.frame
categories_frame.clear()
local selected_class = constants.category_classes[state.selected_category]
local class_settings = actual_settings.categories[selected_class]
local class_translations = translations[selected_class]
local children = {}
for category_name in pairs(database[selected_class]) do
local category_translation = class_translations[category_name] or category_name
if string.find(string.lower(category_translation), query) then
local img_type = constants.class_to_type[selected_class]
if img_type then
category_translation = "[img=" .. img_type .. "/" .. category_name .. "] " .. category_translation
end
children[#children + 1] = {
type = "checkbox",
caption = category_translation,
state = class_settings[category_name],
actions = {
on_checked_state_changed = {
gui = "settings",
action = "change_category_setting",
class = selected_class,
name = category_name,
},
},
}
end
end
if #children > 0 then
gui.build(categories_frame, children)
end
end
-- PAGES
if not tab or tab == "pages" then
local pages_pane = refs.pages.pane
pages_pane.clear()
local selected_page = constants.pages_arr[state.selected_page]
local page_settings = actual_settings.pages[selected_page]
local children = {}
for component_name, component_settings in pairs(page_settings) do
local component_children = {}
component_children[1] = {
type = "flow",
style_mods = { vertical_align = "center" },
{ type = "label", caption = gui_translations.default_state },
{ type = "empty-widget", style = "flib_horizontal_pusher" },
{
type = "drop-down",
items = table.map(constants.component_states, function(option_name)
return { "gui.rb-" .. string.gsub(option_name, "_", "-") }
end),
selected_index = table.find(constants.component_states, component_settings.default_state),
actions = {
on_selection_state_changed = {
gui = "settings",
action = "change_default_state",
class = selected_page,
component = component_name,
},
},
},
}
if component_settings.max_rows then
component_children[#component_children + 1] = {
type = "flow",
style_mods = { vertical_align = "center" },
{ type = "label", caption = gui_translations.max_rows },
{ type = "empty-widget", style = "flib_horizontal_pusher" },
{
type = "textfield",
style_mods = { width = 50, horizontal_align = "center" },
numeric = true,
lose_focus_on_confirm = true,
clear_and_focus_on_right_click = true,
text = tostring(component_settings.max_rows),
actions = {
on_confirmed = {
gui = "settings",
action = "change_max_rows",
class = selected_page,
component = component_name,
},
},
},
}
end
if component_settings.rows then
for row_name, row_state in pairs(component_settings.rows) do
component_children[#component_children + 1] = {
type = "checkbox",
caption = gui_translations[row_name],
state = row_state,
actions = {
on_checked_state_changed = {
gui = "settings",
action = "change_row_visible",
class = selected_page,
component = component_name,
row = row_name,
},
},
}
end
end
children[#children + 1] = {
type = "frame",
style = "bordered_frame",
style_mods = { minimal_width = 300, horizontally_stretchable = true },
direction = "vertical",
caption = gui_translations[component_name] or component_name,
children = component_children,
}
end
gui.build(pages_pane, children)
end
end
local index = {}
local function subpage_set(name, action, include_tooltip, include_bordered_frame, initial_items)
return {
tab = {
type = "tab",
style_mods = { padding = { 7, 10, 8, 10 } },
caption = { "", { "gui.rb-" .. name }, include_tooltip and " [img=info]" or nil },
tooltip = include_tooltip and { "gui.rb-" .. name .. "-description" } or nil,
},
content = {
type = "flow",
style_mods = { horizontal_spacing = 12, padding = { 8, 0, 12, 12 } },
{
type = "list-box",
style = "list_box_in_shallow_frame",
style_mods = { height = 28 * constants.settings_gui_rows, width = 150 },
items = initial_items,
selected_index = 1,
actions = {
on_selection_state_changed = { gui = "settings", action = action },
},
},
{
type = "frame",
style = "flib_shallow_frame_in_shallow_frame",
style_mods = { height = 28 * constants.settings_gui_rows },
{
type = "scroll-pane",
style = "flib_naked_scroll_pane",
style_mods = { padding = 4, vertically_stretchable = true },
vertical_scroll_policy = "always",
ref = { name, "pane" },
include_bordered_frame and {
type = "frame",
style = "bordered_frame",
style_mods = { minimal_width = 300, horizontally_stretchable = true, vertically_stretchable = true },
direction = "vertical",
ref = { name, "frame" },
} or nil,
},
},
},
}
end
--- @param player LuaPlayer
--- @param player_table PlayerTable
function index.build(player, player_table)
local gui_translations = player_table.translations.gui
local refs = gui.build(player.gui.screen, {
{
type = "frame",
name = "rb_settings_window",
direction = "vertical",
ref = { "window" },
actions = {
on_closed = { gui = "settings", action = "close" },
},
{
type = "flow",
style = "flib_titlebar_flow",
ref = { "titlebar", "flow" },
actions = {
on_click = { gui = "settings", action = "reset_location" },
},
{ type = "label", style = "frame_title", caption = { "gui.rb-settings" }, ignored_by_interaction = true },
{ type = "empty-widget", style = "flib_titlebar_drag_handle", ignored_by_interaction = true },
{
type = "textfield",
style_mods = {
top_margin = -3,
right_padding = 3,
width = 120,
},
clear_and_focus_on_right_click = true,
visible = false,
ref = { "titlebar", "search_textfield" },
actions = {
on_text_changed = { gui = "settings", action = "update_search_query" },
},
},
util.frame_action_button(
"utility/search",
{ "gui.rb-search-instruction" },
{ "titlebar", "search_button" },
{ gui = "settings", action = "toggle_search" }
),
util.frame_action_button(
"utility/close",
{ "gui.close" },
{ "titlebar", "close_button" },
{ gui = "settings", action = "close" }
),
},
{
type = "frame",
style = "inside_deep_frame_for_tabs",
direction = "vertical",
{
type = "tabbed-pane",
style = "flib_tabbed_pane_with_no_padding",
{
tab = { type = "tab", caption = { "gui.rb-general" } },
content = {
type = "flow",
style_mods = { padding = 4 },
direction = "vertical",
ref = { "general", "pane" },
},
},
subpage_set(
"categories",
"change_category",
true,
true,
table.map(constants.category_classes, function(class)
return gui_translations[class] or class
end)
),
subpage_set(
"pages",
"change_page",
false,
false,
table.map(constants.pages_arr, function(class)
return gui_translations[class] or class
end)
),
},
},
},
})
refs.window.force_auto_center()
refs.titlebar.flow.drag_target = refs.window
player.opened = refs.window
--- @type SettingsGui
local self = {
player = player,
player_table = player_table,
refs = refs,
state = {
search_opened = false,
search_query = "",
selected_category = 1,
selected_page = 1,
},
}
index.load(self)
player_table.guis.settings = self
self:update_contents()
end
function index.load(self)
setmetatable(self, { __index = Gui })
end
return index

View File

@ -1,125 +0,0 @@
local bounding_box = require("__flib__.bounding-box")
local gui = require("__flib__.gui")
local math = require("__flib__.math")
local table = require("__flib__.table")
local constants = require("constants")
local database = require("scripts.database")
local formatter = require("scripts.formatter")
local gui_util = {}
-- The calling GUI will navigate to the context that is returned, if any
-- Actions that do not open a page will not return a context
function gui_util.navigate_to(e)
local tags = gui.get_tags(e.element)
local context = tags.context
local modifiers = {}
for name, modifier in pairs({ control = e.control, shift = e.shift, alt = e.alt }) do
if modifier then
modifiers[#modifiers + 1] = name
end
end
for _, interaction in pairs(constants.interactions[context.class]) do
if table.deep_compare(interaction.modifiers, modifiers) then
local action = interaction.action
local context_data = database[context.class][context.name]
local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
if action == "view_details" then
return context
elseif action == "view_product_details" and #context_data.products == 1 then
return context_data.products[1]
elseif action == "get_blueprint" then
local blueprint_result = tags.blueprint_result
if blueprint_result then
local cursor_stack = player.cursor_stack
player.clear_cursor()
if cursor_stack and cursor_stack.valid then
local collision_box = game.entity_prototypes[blueprint_result.name].collision_box
local height = bounding_box.height(collision_box)
local width = bounding_box.width(collision_box)
cursor_stack.set_stack({ name = "blueprint", count = 1 })
cursor_stack.set_blueprint_entities({
{
entity_number = 1,
name = blueprint_result.name,
position = {
-- Entities with an even number of tiles to a side need to be set at -0.5 instead of 0
math.ceil(width) % 2 == 0 and -0.5 or 0,
math.ceil(height) % 2 == 0 and -0.5 or 0,
},
recipe = blueprint_result.recipe,
},
})
player.add_to_clipboard(cursor_stack)
player.activate_paste()
end
else
player.create_local_flying_text({
text = { "message.rb-cannot-create-blueprint" },
create_at_cursor = true,
})
player.play_sound({ path = "utility/cannot_build" })
end
elseif action == "open_in_technology_window" then
local player_table = global.players[e.player_index]
player_table.flags.technology_gui_open = true
player.open_technology_gui(context.name)
elseif action == "view_source" then
local source = context_data[interaction.source]
if source then
return source
end
end
end
end
end
function gui_util.update_list_box(pane, source_tbl, player_data, iterator, options)
local i = 0
local children = pane.children
local add = pane.add
for _, obj_ident in iterator(source_tbl) do
local obj_data = database[obj_ident.class][obj_ident.name]
local info = formatter(obj_data, player_data, options)
if info then
i = i + 1
local style = info.researched and "rb_list_box_item" or "rb_unresearched_list_box_item"
local item = children[i]
if item then
item.style = style
item.caption = info.caption
item.tooltip = info.tooltip
item.enabled = info.num_interactions > 0
gui.update_tags(item, { context = { class = obj_ident.class, name = obj_ident.name } })
else
add({
type = "button",
style = style,
caption = info.caption,
tooltip = info.tooltip,
enabled = info.num_interactions > 0,
mouse_button_filter = { "left", "middle" },
tags = {
[script.mod_name] = {
context = { class = obj_ident.class, name = obj_ident.name },
flib = {
on_click = { gui = "search", action = "open_object" },
},
},
},
})
end
end
end
-- Destroy extraneous items
for j = i + 1, #children do
children[j].destroy()
end
end
return gui_util

View File

@ -1,98 +0,0 @@
local on_tick_n = require("__flib__.on-tick-n")
local database = require("scripts.database")
local global_data = require("scripts.global-data")
local player_data = require("scripts.player-data")
return {
-- Migrations from before 3.0 are no longer required
["3.0.0"] = function()
-- NUKE EVERYTHING
global = {}
global_data.init()
global_data.build_prototypes()
database.build()
database.check_forces()
on_tick_n.init()
for i, player in pairs(game.players) do
-- Destroy all old Recipe Book GUIs
for _, window in pairs(player.gui.screen.children) do
if window.get_mod() == "RecipeBook" then
window.destroy()
end
end
-- Re-init player
player_data.init(i)
player_data.refresh(player, global.players[i])
end
end,
["3.0.2"] = function()
global.flags = nil
for _, player_table in pairs(global.players) do
player_table.flags.gui_open = nil
player_table.flags.technology_gui_open = nil
end
end,
["3.2.0"] = function()
for _, player_table in pairs(global.players) do
player_table.guis.info._sticky_id = nil
end
end,
["3.2.2"] = function()
-- Migrate header names
local changes = {
compatible_equipment = "accepted_equipment",
compatible_fuels = "can_burn",
compatible_mining_drills = "mined_by",
compatible_modules = "accepted_modules",
compatible_recipes = "can_craft",
compatible_resources = "can_mine",
}
for _, player_table in pairs(global.players) do
local page_settings = player_table.settings.pages
if page_settings then
for page_name, components in pairs(page_settings) do
local new_components = {}
for name, data in pairs(components) do
new_components[changes[name] or name] = data
end
page_settings[page_name] = new_components
end
end
end
end,
["3.3.0"] = function()
-- Add player and player_table to all GUIs
for i, player_table in pairs(global.players) do
local player = game.get_player(i)
if player and player.valid then
local guis = player_table.guis
if guis.search then
guis.search.player = player
guis.search.player_table = player_table
end
if guis.settings then
guis.settings.player = player
guis.settings.player_table = player_table
end
for recipe_name, quick_ref_gui in pairs(guis.quick_ref) do
quick_ref_gui.player = player
quick_ref_gui.player_table = player_table
quick_ref_gui.recipe_name = recipe_name
end
for id, info_gui in pairs(guis.info) do
if type(info_gui) == "table" then
info_gui.player = player
info_gui.player_table = player_table
info_gui.id = id
end
end
end
end
end,
}

View File

@ -1,235 +0,0 @@
local dictionary = require("__flib__.dictionary-lite")
local table = require("__flib__.table")
local constants = require("constants")
local database = require("scripts.database")
local formatter = require("scripts.formatter")
local util = require("scripts.util")
local player_data = {}
function player_data.init(player_index)
--- @class PlayerTable
local data = {
favorites = {},
flags = {
can_open_gui = false,
show_message_after_translation = false,
technology_gui_open = false,
},
global_history = {},
guis = {
--- @type table<number, InfoGui>
info = { _next_id = 1 },
--- @type table<string, QuickRefGui>
quick_ref = {},
},
--- @type string?
language = nil,
settings = {
general = {},
categories = {},
},
translations = nil, -- Assigned its initial value in player_data.refresh
}
global.players[player_index] = data
end
function player_data.update_settings(player, player_table)
local former_settings = player_table.settings
local settings = {
general = {},
categories = {},
pages = {},
}
-- General settings
for category_name, settings_data in pairs(constants.general_settings) do
local former_category_settings = former_settings.general[category_name] or {}
local category_settings = {}
settings.general[category_name] = category_settings
for setting_name, setting_ident in pairs(settings_data) do
if setting_ident.type == "bool" then
local former_setting = former_category_settings[setting_name]
if former_setting ~= nil then
category_settings[setting_name] = former_setting
else
category_settings[setting_name] = setting_ident.default_value
end
elseif setting_ident.type == "enum" then
local former_setting = former_category_settings[setting_name]
if former_setting ~= nil and table.find(setting_ident.options, former_setting) then
category_settings[setting_name] = former_setting
else
category_settings[setting_name] = setting_ident.default_value
end
end
end
end
-- Categories
for _, category_class_name in pairs(constants.category_classes) do
local former_category_settings = former_settings.categories[category_class_name] or {}
local category_settings = {}
settings.categories[category_class_name] = category_settings
for category_name in pairs(database[category_class_name]) do
local disabled_by_default = constants.disabled_categories[category_class_name][category_name]
local former_setting = former_category_settings[category_name]
if former_setting ~= nil then
category_settings[category_name] = former_setting
else
category_settings[category_name] = not disabled_by_default
end
end
end
-- Pages
-- Default state (normal / collapsed / hidden)
-- Max rows
for class, page_ident in pairs(constants.pages) do
local former_page_settings = (former_settings.pages or {})[class] or {}
local page_settings = {}
settings.pages[class] = page_settings
for i, component_ident in pairs(page_ident) do
local component_name = component_ident.label or component_ident.source or i
local former_component_settings = former_page_settings[component_name] or {}
local component_settings = {
default_state = former_component_settings.default_state or component_ident.default_state or "normal",
}
page_settings[component_name] = component_settings
if component_ident.type == "list_box" then
component_settings.max_rows = former_component_settings.max_rows
or component_ident.max_rows
or constants.default_max_rows
end
-- Default state
-- Row settings for fixed tables
if component_ident.rows then
local former_row_settings = component_settings.rows or {}
local row_settings = {}
component_settings.rows = row_settings
for _, row_ident in pairs(component_ident.rows) do
local row_name = row_ident.label or row_ident.source
local state = former_row_settings[row_name]
if state == nil then
if row_ident.default_state ~= nil then
state = row_ident.default_state
else
state = true
end
end
row_settings[row_name] = state
end
end
end
end
-- Save to `global`
player_table.settings = settings
-- Create or purge memoizer cache
formatter.create_cache(player.index)
end
function player_data.validate_favorites(favorites)
local to_remove = {}
for key, obj in pairs(favorites) do
if not database[obj.class] or not database[obj.class][obj.name] then
table.insert(to_remove, key)
end
end
for _, key in pairs(to_remove) do
favorites[key] = nil
end
end
function player_data.validate_global_history(global_history)
for i = #global_history, 1, -1 do
local entry = global_history[i]
if not (database[entry.class] and database[entry.class][entry.name]) then
table.remove(global_history, i)
global_history[entry.class .. "." .. entry.name] = nil
end
end
end
function player_data.refresh(player, player_table)
-- Destroy GUIs
util.dispatch_all(player.index, "info", "close")
util.dispatch_all(player.index, "quick_ref", "close")
--- @type SearchGui?
local SearchGui = util.get_gui(player.index, "search")
if SearchGui then
SearchGui:destroy()
end
--- @type SettingsGui?
local SettingsGui = util.get_gui(player.index, "settings")
if SettingsGui then
SettingsGui:destroy()
end
-- Set flag
player_table.flags.can_open_gui = false
-- Set shortcut state
player.set_shortcut_toggled("rb-search", false)
player.set_shortcut_available("rb-search", false)
-- Validate favorites
player_data.validate_favorites(player_table.favorites)
-- Validate global history
player_data.validate_global_history(player_table.global_history)
-- Update settings
player_data.update_settings(player, player_table)
-- Run translations
player_table.translations = nil
end
function player_data.remove(player_index)
global.players[player_index] = nil
end
function player_data.check_cursor_stack(player)
local cursor_stack = player.cursor_stack
if cursor_stack and cursor_stack.valid and cursor_stack.valid_for_read and database.item[cursor_stack.name] then
return cursor_stack.name
end
return false
end
function player_data.update_global_history(global_history, new_context)
new_context = table.shallow_copy(new_context)
local ident = new_context.class .. "." .. new_context.name
if global_history[ident] then
for i, context in ipairs(global_history) do
if context.class == new_context.class and context.name == new_context.name then
-- Custom implementation of table.insert and table.remove that does the minimal amount of work needed
global_history[i] = nil
local prev = new_context
local current
for j = 1, i do
current = global_history[j]
global_history[j] = prev
prev = current
end
break
end
end
else
table.insert(global_history, 1, new_context)
global_history[ident] = true
end
for i = constants.global_history_size + 1, #global_history do
local context = global_history[i]
local ident = context.class .. "." .. context.name
global_history[ident] = nil
global_history[i] = nil
end
end
return player_data

View File

@ -1,67 +0,0 @@
local constants = require("constants")
local database = require("scripts.database")
local remote_interface = {}
--- Returns a copy of the given object's information in the Recipe Book database.
--- @param class string One of `crafter`, `entity`, `equipment_category`, `equipment`, `fluid`, `fuel_category`, `group`, `item`, `lab`, `mining_drill`, `offshore_pump`, `recipe_category`, `recipe`, `resource_category`, `resource`, or `technology`.
--- @param name string The name of the object to get data for.
--- @return table? The object's data, or `nil` if the object was not found.
function remote_interface.get_object_data(class, name)
if not class then
error("Remote interface caller did not provide an object class.")
end
if not constants.pages[class] then
error("Remote interface caller provided an invalid class: `" .. class .. "`")
end
if not name then
error("Remote interface caller did not provide an object name.")
end
return database[class][name]
end
--- Opens the given info page in a Recipe Book window.
--- @param player_index uint
--- @param class string One of `crafter`, `entity`, `equipment_category`, `equipment`, `fluid`, `fuel_category`, `group`, `item`, `lab`, `mining_drill`, `offshore_pump`, `recipe_category`, `recipe`, `resource_category`, `resource`, or `technology`.
--- @param name string The name of the object to open.
--- @return boolean did_open Whether or not the page was opened.
function remote_interface.open_page(player_index, class, name)
if not class then
error("Remote interface caller did not provide an object class.")
end
if not constants.pages[class] then
error("Remote interface caller provided an invalid class: `" .. class .. "`")
end
if not name then
error("Remote interface caller did not provide an object name.")
end
local data = database[class][name]
if not data then
return false
end
local player = game.get_player(player_index)
local player_table = global.players[player_index]
if player_table.flags.can_open_gui then
OPEN_PAGE(player, player_table, { class = class, name = name })
return true
else
return false
end
end
--- Returns the current interface version.
---
--- This version will be incremented if breaking changes are made to the interface. Check against this version before calling interface functions to avoid crashing.
---
--- The current interface version is `4`.
--- @return number
function remote_interface.version()
return constants.interface_version
end
return remote_interface

View File

@ -1,264 +0,0 @@
local bounding_box = require("__flib__.bounding-box")
local dictionary = require("__flib__.dictionary-lite")
local format = require("__flib__.format")
local math = require("__flib__.math")
local table = require("__flib__.table")
local constants = require("constants")
local core_util = require("__core__.lualib.util")
local util = {}
--- @return AmountIdent
function util.build_amount_ident(input)
--- @class AmountIdent
return {
amount = input.amount or false,
amount_min = input.amount_min or false,
amount_max = input.amount_max or false,
catalyst_amount = input.catalyst_amount or false,
probability = input.probability or false,
format = input.format or "format_amount",
}
end
-- HACK: Requiring `formatter` in this file causes a dependency loop
local function format_number(value)
return format.number(math.round(value, 0.01))
end
--- @class TemperatureIdent
--- @field string string
--- @field short_string string
--- @field min double
--- @field max double
--- Builds a `TemperatureIdent` based on the fluid input/output parameters.
function util.build_temperature_ident(fluid)
local temperature = fluid.temperature
local temperature_min = fluid.minimum_temperature
local temperature_max = fluid.maximum_temperature
local temperature_string
local short_temperature_string
local short_top_string
if temperature then
temperature_string = format_number(temperature)
short_temperature_string = core_util.format_number(temperature, true)
temperature_min = temperature
temperature_max = temperature
elseif temperature_min and temperature_max then
if temperature_min == math.min_double then
temperature_string = "" .. format_number(temperature_max)
short_temperature_string = "" .. core_util.format_number(temperature_max, true)
elseif temperature_max == math.max_double then
temperature_string = "" .. format_number(temperature_min)
short_temperature_string = "" .. core_util.format_number(temperature_min, true)
else
temperature_string = "" .. format_number(temperature_min) .. "-" .. format_number(temperature_max)
short_temperature_string = core_util.format_number(temperature_min, true)
short_top_string = core_util.format_number(temperature_max, true)
end
end
if temperature_string then
return {
string = temperature_string,
short_string = short_temperature_string,
short_top_string = short_top_string,
min = temperature_min,
max = temperature_max,
}
end
end
--- Get the "sorting number" of a temperature. Will sort in ascending order, with absolute, then min range, then max range.
--- @param temperature_ident TemperatureIdent
function util.get_sorting_number(temperature_ident)
if temperature_ident.min == math.min_double then
return temperature_ident.max + 0.001
elseif temperature_ident.max == math.max_double then
return temperature_ident.min + 0.003
elseif temperature_ident.min ~= temperature_ident.max then
return temperature_ident.min + 0.002
else
return temperature_ident.min
end
end
function util.convert_and_sort(tbl)
for key in pairs(tbl) do
tbl[#tbl + 1] = key
end
table.sort(tbl)
return tbl
end
function util.unique_string_array(initial_tbl)
initial_tbl = initial_tbl or {}
local hash = {}
for _, value in pairs(initial_tbl) do
hash[value] = true
end
return setmetatable(initial_tbl, {
__newindex = function(tbl, key, value)
if not hash[value] then
hash[value] = true
rawset(tbl, key, value)
end
end,
})
end
function util.unique_obj_array(initial_tbl)
local hash = {}
return setmetatable(initial_tbl or {}, {
__newindex = function(tbl, key, value)
if not hash[value.name] then
hash[value.name] = true
rawset(tbl, key, value)
end
end,
})
end
function util.frame_action_button(sprite, tooltip, ref, action)
return {
type = "sprite-button",
style = "frame_action_button",
sprite = sprite .. "_white",
hovered_sprite = sprite .. "_black",
clicked_sprite = sprite .. "_black",
tooltip = tooltip,
mouse_button_filter = { "left" },
ref = ref,
actions = {
on_click = action,
},
}
end
function util.process_placed_by(prototype)
local placed_by = prototype.items_to_place_this
if placed_by then
return table.map(placed_by, function(item_stack)
return {
class = "item",
name = item_stack.name,
amount_ident = util.build_amount_ident({ amount = item_stack.count }),
}
end)
end
end
function util.convert_categories(source_tbl, class)
local categories = {}
for category in pairs(source_tbl) do
categories[#categories + 1] = { class = class, name = category }
end
return categories
end
function util.convert_to_ident(class, source)
if source then
return { class = class, name = source }
end
end
--- @param prototype LuaEntityPrototype
--- @return DisplayResolution?
function util.get_size(prototype)
if prototype.selection_box then
local box = prototype.selection_box
return { height = math.ceil(bounding_box.height(box)), width = math.ceil(bounding_box.width(box)) }
end
end
--- @param prototype LuaEntityPrototype
function util.process_energy_source(prototype)
local burner = prototype.burner_prototype
local fluid_energy_source = prototype.fluid_energy_source_prototype
if burner then
return util.convert_categories(burner.fuel_categories, "fuel_category")
elseif fluid_energy_source then
local filter = fluid_energy_source.fluid_box.filter
if filter then
return {}, { class = "fluid", name = filter.name }
end
return { { class = "fuel_category", name = "burnable-fluid" } }
end
return {}
end
--- Safely retrive the given GUI, checking for validity.
--- @param player_index number
--- @param gui_name string
--- @param gui_key number|string?
function util.get_gui(player_index, gui_name, gui_key)
local player_table = global.players[player_index]
if not player_table then
return
end
local tbl = player_table.guis[gui_name]
if not tbl then
return
end
if gui_key then
tbl = tbl[gui_key]
end
if tbl and tbl.refs.window and tbl.refs.window.valid then
return tbl
end
end
--- Dispatch the given action on all GUIs of the given name.
--- @param player_index number
--- @param gui_name string
--- @param msg string|table
function util.dispatch_all(player_index, gui_name, msg)
local player_table = global.players[player_index]
if not player_table then
return
end
local ignored = gui_name == "info" and constants.ignored_info_ids or {}
for key, Gui in pairs(player_table.guis[gui_name]) do
if not ignored[key] then
Gui:dispatch(msg)
end
end
end
--- Determine if the given prototype is blueprintable
--- @param prototype LuaEntityPrototype
--- @return boolean
function util.is_blueprintable(prototype)
return prototype.has_flag("player-creation")
and not prototype.has_flag("not-selectable-in-game")
and not prototype.has_flag("not-blueprintable")
and not prototype.has_flag("hidden")
end
--- Create a new dictionary only if not in on_load.
--- @param name string
--- @param initial_contents Dictionary?
function util.new_dictionary(name, initial_contents)
if game then
dictionary.new(name, initial_contents)
end
end
--- Add to the dictionary only if not in on_load.
--- @param dict string
--- @param key string
--- @param localised LocalisedString
function util.add_to_dictionary(dict, key, localised)
if game then
-- Fall back to internal key in non-description dictionaries
if not string.find(dict, "description") then
localised = { "?", localised, key }
end
dictionary.add(dict, key, localised)
end
end
return util

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -1,3 +0,0 @@
--- @class Context
--- @field class string
--- @field name string

View File

@ -835,7 +835,7 @@
{
"name": "RecipeBook",
"enabled": true
"enabled": false
},
{

Binary file not shown.

View File

@ -1,6 +1,6 @@
{
"name": "zzzparanoidal",
"version": "1.0.1",
"version": "1.1.1",
"title": "!_Paranoidal",
"factorio_version": "1.1",
"author": "Sovigod",

View File

@ -1404,4 +1404,7 @@ bobmods.lib.tech.add_recipe_unlock("nitinol-processing", "angels-nitinol-pipe-ca
bobmods.lib.tech.add_recipe_unlock("angels-nitinol-smelting-1", "nitinol-pipe-to-ground")
bobmods.lib.tech.remove_recipe_unlock("nitinol-processing", "nitinol-pipe-to-ground")
bobmods.lib.tech.remove_recipe_unlock("angels-nitinol-smelting-1", "angels-nitinol-pipe-to-ground-casting")
bobmods.lib.tech.add_recipe_unlock("nitinol-processing", "angels-nitinol-pipe-to-ground-casting")
bobmods.lib.tech.add_recipe_unlock("nitinol-processing", "angels-nitinol-pipe-to-ground-casting")
--Для сборщика электроники нужны фиол. манипуляторы (AKMF)
bobmods.lib.tech.add_prerequisite("electronics-machine-3", "turbo-inserter")