├── .editorconfig ├── .github └── workflows │ ├── README.md │ └── main.yml ├── .gitignore ├── .lua-format-config.yml ├── .vscode ├── extensions.json └── settings.json ├── CONTRIBUTING.md ├── FUNDING.yml ├── LICENSE ├── README.md ├── review ├── README.md └── modules │ ├── common │ ├── auto-infinite-research.lua │ └── research-queue.lua │ └── dddgamer │ └── admin │ └── admin-open-player-inventory.lua ├── screenshots ├── dddgamer-softmod.jpg ├── dddgamer-softmod_auto-research.png ├── dddgamer-softmod_game-info.jpg ├── dddgamer-softmod_player-list.png └── dddgamer-softmod_task-list.png ├── src ├── README.md ├── config.lua ├── control.lua ├── locale │ ├── en │ │ ├── __MODULE_NAME__.cfg │ │ ├── auto-research.cfg │ │ ├── autodeconstruct.cfg │ │ ├── custom-tech.cfg │ │ ├── death-marker.cfg │ │ ├── evolution.cfg │ │ ├── game-info.cfg │ │ ├── game-time.cfg │ │ ├── global.cfg │ │ ├── no-blueprints.cfg │ │ ├── no-hand-crafting.cfg │ │ ├── player-list.cfg │ │ ├── player-logging.cfg │ │ └── silo.cfg │ └── ru │ │ ├── auto-research.cfg │ │ ├── custom-tech.cfg │ │ ├── death-marker.cfg │ │ ├── evolution.cfg │ │ ├── game-info.cfg │ │ ├── game-time.cfg │ │ ├── global.cfg │ │ ├── no-blueprints.cfg │ │ ├── no-hand-crafting.cfg │ │ ├── player-list.cfg │ │ └── silo.cfg ├── modules │ ├── common │ │ ├── autodeconstruct.lua │ │ ├── custom-tech.lua │ │ ├── death-marker.lua │ │ ├── evolution.lua │ │ ├── floating-health.lua │ │ ├── game-time.lua │ │ ├── no-blueprints.lua │ │ ├── no-hand-crafting.lua │ │ ├── online-player-list.lua │ │ ├── research-queue │ │ │ ├── Research_Queue_Styles.lua │ │ │ └── auto-research.lua │ │ ├── silo.lua │ │ ├── spawn-marker.lua │ │ └── tasks.lua │ ├── dddgamer │ │ ├── death-marker-simple.lua │ │ ├── game-info.lua │ │ ├── player-init.lua │ │ ├── player-logging.lua │ │ ├── spawn-area.lua │ │ └── spawn-starter-ores.lua │ ├── dev │ │ ├── __MODULE_NAME__.lua │ │ ├── color_list.lua │ │ ├── sandbox.lua │ │ ├── spawn-rocket-silo.lua │ │ └── sprite_list.lua │ └── vanilla │ │ ├── player-init.lua │ │ └── silo.lua ├── stdlib │ ├── Event.lua │ ├── GUI.lua │ ├── GUI_Events.lua │ ├── Game.lua │ ├── string.lua │ └── table.lua └── util │ ├── Colors.lua │ ├── Math.lua │ ├── Sprites.lua │ ├── Styles.lua │ └── Time.lua └── tools ├── console-lua-commands.md ├── copy-local.sh ├── maps ├── README.md └── gib-test-map.txt └── templates ├── doc.template.lua ├── gui.template.cfg └── gui.template.lua /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # All files 7 | [*] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 4 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | # Unix-style newlines with a newline ending every file 15 | end_of_line = lf 16 | 17 | # Markdown 18 | [*.md] 19 | max_line_length = off 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.github/workflows/README.md: -------------------------------------------------------------------------------- 1 | # GitHub Action References 2 | 3 | * https://github.com/marketplace/actions/checkout 4 | * https://github.com/marketplace/actions/upload-a-build-artifact 5 | * https://github.com/marketplace/actions/download-a-build-artifact 6 | * https://github.com/marketplace/actions/deploy-to-github-pages 7 | 8 | 9 | # Docs 10 | * [passing-data-between-jobs-in-a-workflow](ttps://docs.github.com/en/actions/advanced-guides/storing-workflow-data-as-artifacts#passing-data-between-jobs-in-a-workflow) 11 | * [dependant jobs](https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#jobsjob_idneeds) 12 | * [Dynamically Define Env Vars](https://github.com/actions/starter-workflows/issues/68#issuecomment-792338408) 13 | * [Env Filed](https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions#environment-files) 14 | * [Supported OS](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources) 15 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # CI/CD for Github Actions 2 | # @author Denis Zholob (deniszholob.com) 3 | # ====================================== # 4 | 5 | name: Package and Release 6 | 7 | # Controls when the workflow will run 8 | on: 9 | # Triggers the workflow on push or pull request events but only for the main branch 10 | push: 11 | branches: [main] 12 | # pull_request: 13 | # branches: [ main ] 14 | 15 | # Allows you to run this workflow manually from the Actions tab 16 | workflow_dispatch: 17 | 18 | jobs: 19 | package: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v2 24 | 25 | - name: Set RELEASE_VERSION env var 26 | shell: bash 27 | run: | 28 | echo "RELEASE_VERSION=$(date +'%Y-%m-%d')" >> $GITHUB_ENV 29 | 30 | - name: Archive Package 31 | uses: actions/upload-artifact@v2 32 | with: 33 | path: src/ 34 | name: dddgamer-softmod-pack-${{env.RELEASE_VERSION}}.zip 35 | 36 | - name: Zip Release 37 | uses: papeloto/action-zip@v1 38 | with: 39 | files: src/ 40 | dest: dist/dddgamer-softmod-pack-${{env.RELEASE_VERSION}}.zip 41 | 42 | # ====================================================================== # 43 | - name: Create Release 44 | uses: ncipollo/release-action@v1 45 | with: 46 | token: ${{ secrets.GITHUB_TOKEN }} 47 | name: dddgamer-softmod-pack-${{env.RELEASE_VERSION}}.zip 48 | tag: Release-${{env.RELEASE_VERSION}} 49 | body: | 50 | DDDGamer's Softmod Pack. 51 | 52 | * **Expand the _Assets_ below.** 53 | * Download the `dddgamer-softmod-pack-${{env.RELEASE_VERSION}}.zip` file. 54 | * See [installation instructions](https://github.com/deniszholob/factorio-softmod-pack#readme) 55 | artifacts: | 56 | ./dist/dddgamer-softmod-pack-${{env.RELEASE_VERSION}}.zip 57 | artifactErrorsFailBuild: true 58 | draft: false # true to create a draft (unpublished) release, false to create a published one. Default: false 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | build 3 | 4 | # IDEs and editors 5 | /.idea 6 | .project 7 | .classpath 8 | .c9/ 9 | *.launch 10 | .settings/ 11 | *.sublime-workspace 12 | 13 | # IDE - VSCode 14 | .vscode/* 15 | !.vscode/settings.json 16 | !.vscode/tasks.json 17 | !.vscode/launch.json 18 | !.vscode/extensions.json 19 | 20 | # System Files 21 | .DS_Store 22 | Thumbs.db 23 | -------------------------------------------------------------------------------- /.lua-format-config.yml: -------------------------------------------------------------------------------- 1 | indent_width: 4 2 | column_limit: 80 3 | keep_simple_control_block_one_line: false 4 | keep_simple_function_one_line: false 5 | break_after_functioncall_lp: true 6 | break_before_functioncall_rp: true 7 | break_after_functiondef_lp: true 8 | break_before_functiondef_rp: true 9 | line_breaks_after_function_body: 2 10 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "koihik.vscode-lua-format", 4 | "sumneko.lua", 5 | "svizzini.factorio-lua-api-autocomplete", 6 | "streetsidesoftware.code-spell-checker", 7 | "pkief.material-icon-theme", 8 | "adrianwilczynski.toggle-hidden" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.github": true, 4 | "**/screenshots/": true, 5 | "**/.editorconfig": true, 6 | "**/.gitignore": true, 7 | "**/.lua-format-config.yml": true, 8 | "**/FUNDING.yml": true, 9 | "**/LICENSE": true 10 | }, 11 | "editor.renderWhitespace": "all", 12 | "editor.rulers": [80], 13 | "explorer.sortOrderLexicographicOptions": "lower", // Case sensitive file ordering in tree 14 | "editor.semanticHighlighting.enabled": true, 15 | "workbench.iconTheme": "material-icon-theme", 16 | "Lua.diagnostics.globals": [ 17 | "game", 18 | "script", 19 | "remote", 20 | "commands", 21 | "settings", 22 | "rcon", 23 | "rendering", 24 | "global", 25 | "defines", 26 | "serpent", 27 | "log", 28 | "localised_print", 29 | "table_size" 30 | ], 31 | "vscode-lua-format.configPath": ".lua-format-config.yml", 32 | "cSpell.words": ["Factorio"], 33 | "Lua.diagnostics.disable": ["undefined-doc-name"] 34 | } 35 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # To contribute 2 | 3 | **If you are working on an existing issue, please claim it with your comment, so there is no duplicate work.** 4 | 5 | ## Hidden Files in VSCode 6 | Some files are hidden in vscode by default, see the `files.exclude` option in the [settings file](.vscode/settings.json) 7 | 8 | There is a [recommended extension](.vscode/extensions.json) `adrianwilczynski.toggle-hidden` that allows to easily toggle hidden files on and off 9 | 10 | 11 | 12 | ## Dev 13 | * The main softmod code is in the [src](./src/) folder 14 | * See the [src/README.md](./src/README.md) details 15 | * You can run the [copy-local.sh](./tools/copy-local.sh) script to sync to factorio scenarios folder 16 | * See [common console commands](https://wiki.factorio.com/Console#Set_evolution_factor) 17 | * See [Useful Factorio commands for testing](./tools/console-lua-commands.lua) 18 | 19 | **Notes:** 20 | * Previous pack versions are saved on separate branches. 21 | * This pack is not finalized, there are still some modules under development that are not listed in the `control.lua` 22 | * A list of existing style can be found in `Factorio/data/core/prototypes/style.lua` 23 | 24 | 25 | ### References 26 | * [Factorio API](http://lua-api.factorio.com/latest/) 27 | * [Factorio Wiki - Multiplayer](https://wiki.factorio.com/Multiplayer) 28 | * [Factorio Wiki - Console](https://wiki.factorio.com/Console) 29 | * [Factorio Wiki - Research](https://wiki.factorio.com/Research) 30 | * [Factorio RElms - Console Commands](https://factorio-realms.com/tutorials/useful_factorio_console_commands) 31 | * [Afforess/Factorio-Stdlib](https://github.com/Afforess/Factorio-Stdlib) 32 | * [Afforess/Factorio-Stdlib Doc](http://afforess.github.io/Factorio-Stdlib/index.html) 33 | * [3RaGaming/3Ra-Enhanced-Vanilla](https://github.com/3RaGaming/3Ra-Enhanced-Vanilla) 34 | * [RedMew](https://github.com/Refactorio/RedMew) 35 | * [Lua Doc](https://www.lua.org/manual/5.3/) 36 | * [Lua tutspoint](https://www.tutorialspoint.com/lua/index.htm) 37 | -------------------------------------------------------------------------------- /FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: deniszholob 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: deniszholob # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DDDGamer's [Factorio](https://www.factorio.com/) v1.1 Softmod Collection (Scenario) [![Build Status](https://github.com/deniszholob/factorio-softmod-pack/actions/workflows/main.yml/badge.svg)](https://github.com/deniszholob/factorio-softmod-pack/actions/workflows/main.yml) 2 | 3 | Contains QOL code to help out in the game such as automatic deconstruction of miners, death markers, tasks, player list, etc... 4 | 5 | **What is a soft mod?** 6 | A modification to the `control.lua` file. 7 | 8 | **control.lua** 9 | 10 | * Factorio folder location: `Factorio/data/base/scenarios/freeplay/` 11 | * Scenario location: `%appdata%/Factorio/scenarios/` 12 | * Purpose: The file sets up the initial game and is downloaded onto all the clients automatically in multiplayer. The original vanilla file tells the game to give you items at the start of the game and gives you pistol + ammo upon respawn. Extension of this functionality brings "limitless possibilities". The Wave defense Scenario is one example of a softmod already packaged with the game. 13 | 14 | # Installation 15 | * Download the softmod pack zipped file (`dddgamer-softmod-pack.zip`) from the 16 | [Latest Release](https://github.com/deniszholob/factorio-softmod-pack/releases/latest) 17 | * See the [installation instructions](https://github.com/deniszholob/factorio-softmod-pack/src/README.md) 18 | 19 | # Support Me 20 | If you find the cheat sheet or the source code useful, consider: 21 | 22 | * Donating Ko-fi: https://ko-fi.com/deniszholob 23 | * Supporting on Patreon: https://www.patreon.com/deniszholob 24 | 25 | 26 | # Screenshots 27 | ![Game Start with softmod pack](screenshots/dddgamer-softmod.jpg) 28 | ![Game Info](screenshots/dddgamer-softmod_game-info.jpg) 29 | ![Player List](screenshots/dddgamer-softmod_player-list.png) 30 | ![Auto Research](screenshots/dddgamer-softmod_auto-research.png) 31 | ![Task List](screenshots/dddgamer-softmod_task-list.png) 32 | -------------------------------------------------------------------------------- /review/README.md: -------------------------------------------------------------------------------- 1 | # Old/WIP/test/reference code that is not to be used in the pack 2 | 3 | 4 | Ref: 5 | 6 | Open inventories 7 | https://github.com/patschi/factorio-transparent-inventory/blob/master/control.lua 8 | 9 | Chat to file 10 | https://mods.factorio.com/mod/ChatToFile 11 | https://github.com/Eastborn/FactorioModding/blob/master/_010_mods/ChatToFile/mod/control.lua 12 | https://github.com/Eastborn/FactorioModding/blob/master/_010_mods/ChatToFile/mod/src/Player.lua 13 | https://github.com/Eastborn/FactorioModding/blob/master/_010_mods/_EastModLib/mod/lib/FileSystem/Files.lua 14 | 15 | -------------------------------------------------------------------------------- /review/modules/common/auto-infinite-research.lua: -------------------------------------------------------------------------------- 1 | -- Auto Infinite Research Soft Module 2 | -- https://mods.factorio.com/mod/MegabaseAutoResearch 3 | -- Automatically research robot worker speed and mining productivity research for ease of megabase researching. 4 | -- The research to be chosen is based on cheapest total cumulative cost. 5 | -- Uses locale __modulename__.cfg 6 | -- @usage require('modules/common/auto-infinite-research') 7 | -- ------------------------------------------------------- -- 8 | -- @author can00336 (https://mods.factorio.com/user/can00336) 9 | -- @author Denis Zholob (DDDGamer) 10 | -- github: https://github.com/deniszholob/factorio-softmod-pack 11 | -- ======================================================= -- 12 | 13 | -- Dependencies -- 14 | -- ======================================================= -- 15 | local mod_gui = require("mod-gui") -- From `Factorio\data\core\lualib` 16 | local GUI = require("stdlib/GUI") 17 | local Colors = require("util/Colors") 18 | 19 | -- Constants -- 20 | -- ======================================================= -- 21 | local AutoInfiniteResearch = {} 22 | local MENU_BTN_NAME = 'btn_menu_auto-infinite-research' 23 | local MASTER_FRAME_NAME = 'frame_auto-infinite-research' 24 | 25 | -- Event Functions -- 26 | -- ======================================================= -- 27 | -- When new player joins add a btn to their button_flow 28 | -- Redraw this softmod's frame 29 | -- @param event on_player_joined_game 30 | function AutoInfiniteResearch.on_player_joined(event) 31 | local player = game.players[event.player_index] 32 | AutoInfiniteResearch.draw_menu_btn(player) 33 | -- AutoInfiniteResearch.draw_master_frame(player) -- dont draw yet, when btn clicked instead 34 | end 35 | 36 | -- When a player leaves clean up their GUI in case this mod gets removed next time 37 | -- @param event on_player_left_game 38 | function AutoInfiniteResearch.on_player_left_game(event) 39 | local player = game.players[event.player_index] 40 | GUI.destroy_element(mod_gui.get_button_flow(player)[MENU_BTN_NAME]) 41 | GUI.destroy_element(mod_gui.get_frame_flow(player)[MASTER_FRAME_NAME]) 42 | end 43 | 44 | -- Toggle gameinfo is called if gui element is gameinfo button 45 | -- @param event on_gui_click 46 | local function on_gui_click(event) 47 | local player = game.players[event.player_index] 48 | local el_name = event.element.name 49 | 50 | if el_name == MENU_BTN_NAME then 51 | -- Call toggle if frame has been created 52 | if(mod_gui.get_frame_flow(player)[MASTER_FRAME_NAME] ~= nil) then 53 | GUI.toggle_element(mod_gui.get_frame_flow(player)[MASTER_FRAME_NAME]) 54 | else -- Call create if it hasnt 55 | draw_gameinfo_frame(player) 56 | end 57 | end 58 | end 59 | 60 | 61 | -- @param event on_research_finished 62 | local function on_research_finished(event) 63 | local research = event.research 64 | local force = research.force 65 | local techs = force.technologies 66 | local wrs = techs["worker-robots-speed-6"].level 67 | local mp = techs["mining-productivity-16"].level 68 | local wrs_costs = 2^(wrs - 5) * 1000 + 50 69 | local mp_costs = 50 * (mp^2 - mp - 210) + 12000 70 | if mp_costs <= wrs_costs then 71 | force.current_research = "mining-productivity-16" 72 | else 73 | force.current_research = "worker-robots-speed-6" 74 | end 75 | end 76 | 77 | -- Event Registration -- 78 | -- ======================================================= -- 79 | Event.register(defines.events.on_player_joined_game, AutoInfiniteResearch.on_player_joined) 80 | Event.register(defines.events.on_player_left_game, AutoInfiniteResearch.on_player_left_game) 81 | -- Event.register(defines.events.on_research_finished, on_research_finished) 82 | 83 | -- Helper Functions -- 84 | -- ======================================================= -- 85 | 86 | -- 87 | -- @tparam LuaPlayer player 88 | function AutoInfiniteResearch.draw_menu_btn(player) 89 | if mod_gui.get_button_flow(player)[MENU_BTN_NAME] == nil then 90 | mod_gui.get_button_flow(player).add( 91 | { 92 | type = "sprite-button", 93 | name = MENU_BTN_NAME, 94 | sprite = "item/space-science-pack", 95 | -- caption = 'Auto Infinite Research', 96 | tooltip = "Auto Infinite Research Settings" 97 | } 98 | ) 99 | end 100 | end 101 | 102 | -- 103 | -- @tparam LuaPlayer player 104 | function AutoInfiniteResearch.draw_master_frame(player) 105 | 106 | -- game.print(serpent.block(infinite_research_list)) 107 | 108 | local master_frame = mod_gui.get_frame_flow(player)[MASTER_FRAME_NAME]; 109 | -- Draw the vertical frame on the left if its not drawn already 110 | if master_frame == nil then 111 | master_frame = mod_gui.get_frame_flow(player).add({type = "frame", name = MASTER_FRAME_NAME, direction = "vertical"}) 112 | end 113 | -- Clear and repopulate infinite research list 114 | GUI.clear_element(master_frame) 115 | for _, tech in pairs(infinite_research_list) do 116 | master_frame.add( 117 | { 118 | type = label 119 | } 120 | ) 121 | end 122 | 123 | 124 | end 125 | 126 | -- 127 | function AutoInfiniteResearch.canResearch(force, tech, config) 128 | if not tech or tech.researched or not tech.enabled then 129 | return false 130 | end 131 | for _, pretech in pairs(tech.prerequisites) do 132 | if not pretech.researched then 133 | return false 134 | end 135 | end 136 | -- if(config) then 137 | -- for _, ingredient in pairs(tech.research_unit_ingredients) do 138 | -- if not config.allowed_ingredients[ingredient.name] then 139 | -- return false 140 | -- end 141 | -- end 142 | -- end 143 | return true 144 | end 145 | 146 | -- @treturn LuaTechnology[] infinite_research_list List of technologies that can be infinite with space science 147 | function AutoInfiniteResearch.get_infinite_research() 148 | local infinite_research_list = {} 149 | for _, tech in pairs(player.force.technologies) do 150 | if tech.research_unit_count_formula then -- Infinite tech 151 | local ingredients = tech.research_unit_ingredients 152 | for _, ingredient in pairs(ingredients) do -- Contains space science 153 | if(ingredient.name == 'space-science-pack') then 154 | infinite_research_list[#infinite_research_list+1] = tech 155 | end 156 | end 157 | end 158 | end 159 | return infinite_research_list 160 | end 161 | 162 | -- 163 | function AutoInfiniteResearch.get_config() 164 | if not global.auto_infinite_research_config then 165 | global.auto_infinite_research_config = {} 166 | end 167 | if not global.auto_research_config[force.name] then 168 | global.auto_research_config[force.name] = {} 169 | end 170 | end 171 | -------------------------------------------------------------------------------- /review/modules/dddgamer/admin/admin-open-player-inventory.lua: -------------------------------------------------------------------------------- 1 | -- Admin Open Player Inventory Soft Module 2 | -- Displays a table of all players with and button to open their inventory 3 | -- Uses locale __modulename__.cfg 4 | -- @usage require('modules/dddgamer/admin/admin-open-player-inventory') 5 | -- ------------------------------------------------------- -- 6 | -- @author Denis Zholob (DDDGamer) 7 | -- github: https://github.com/deniszholob/factorio-softmod-pack 8 | -- ======================================================= -- 9 | 10 | -- Dependencies -- 11 | -- ======================================================= -- 12 | local mod_gui = require("mod-gui") -- From `Factorio\data\core\lualib` 13 | local GUI = require("stdlib/GUI") 14 | local Colors = require("util/Colors") 15 | 16 | -- Constants -- 17 | -- ======================================================= -- 18 | local AdminPlayerInventory = { 19 | MENU_BTN_NAME = 'btn_menu_admin_player_inventory', 20 | MASTER_FRAME_NAME = 'frame_admin_player_inventory', 21 | OWNER = 'DDDGamer', 22 | OWNER_ONLY = true 23 | } 24 | 25 | -- Event Functions -- 26 | -- ======================================================= -- 27 | --- When new player joins add a btn to their button_flow 28 | --- Redraw this softmod's frame 29 | --- Only happens for admins/owner depending on OWNER_ONLY flag 30 | --- @param event on_player_joined_game 31 | function AdminPlayerInventory.on_player_joined(event) 32 | local player = game.players[event.player_index] 33 | if (AdminPlayerInventory.OWNER_ONLY) then 34 | if (player.name == AdminPlayerInventory.OWNER) then 35 | AdminPlayerInventory.draw_menu_btn(player) 36 | AdminPlayerInventory.draw_master_frame(player) 37 | end 38 | elseif (player.admin == true) then 39 | AdminPlayerInventory.draw_menu_btn(player) 40 | AdminPlayerInventory.draw_master_frame(player) 41 | end 42 | end 43 | 44 | 45 | --- When a player leaves clean up their GUI in case this mod gets removed next time 46 | --- @param event on_player_left_game 47 | function AdminPlayerInventory.on_player_left_game(event) 48 | local player = game.players[event.player_index] 49 | GUI.destroy_element( 50 | mod_gui.get_button_flow(player)[AdminPlayerInventory.MENU_BTN_NAME] 51 | ) 52 | GUI.destroy_element( 53 | mod_gui.get_frame_flow(player)[AdminPlayerInventory.MASTER_FRAME_NAME] 54 | ) 55 | end 56 | 57 | 58 | -- Event Registration -- 59 | -- ======================================================= -- 60 | Event.register( 61 | defines.events.on_player_joined_game, AdminPlayerInventory.on_player_joined 62 | ) 63 | Event.register( 64 | defines.events.on_player_left_game, AdminPlayerInventory.on_player_left_game 65 | ) 66 | 67 | -- Helper Functions -- 68 | -- ======================================================= -- 69 | 70 | --- 71 | --- @param player LuaPlayer 72 | function AdminPlayerInventory.draw_menu_btn(player) 73 | if mod_gui.get_button_flow(player)[AdminPlayerInventory.MENU_BTN_NAME] == 74 | nil then 75 | mod_gui.get_button_flow(player).add( 76 | { 77 | type = "sprite-button", 78 | name = AdminPlayerInventory.MENU_BTN_NAME, 79 | sprite = "entity/player", 80 | -- caption = 'Players Inventory', 81 | tooltip = "Acces other players inventory" 82 | } 83 | ) 84 | end 85 | end 86 | 87 | 88 | --- 89 | --- @param player LuaPlayer 90 | function AdminPlayerInventory.draw_master_frame(player) 91 | 92 | end 93 | 94 | -------------------------------------------------------------------------------- /screenshots/dddgamer-softmod.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deniszholob/factorio-softmod-pack/98514e35b9fd55d3d36a5c129cbb2519ff0669c9/screenshots/dddgamer-softmod.jpg -------------------------------------------------------------------------------- /screenshots/dddgamer-softmod_auto-research.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deniszholob/factorio-softmod-pack/98514e35b9fd55d3d36a5c129cbb2519ff0669c9/screenshots/dddgamer-softmod_auto-research.png -------------------------------------------------------------------------------- /screenshots/dddgamer-softmod_game-info.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deniszholob/factorio-softmod-pack/98514e35b9fd55d3d36a5c129cbb2519ff0669c9/screenshots/dddgamer-softmod_game-info.jpg -------------------------------------------------------------------------------- /screenshots/dddgamer-softmod_player-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deniszholob/factorio-softmod-pack/98514e35b9fd55d3d36a5c129cbb2519ff0669c9/screenshots/dddgamer-softmod_player-list.png -------------------------------------------------------------------------------- /screenshots/dddgamer-softmod_task-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deniszholob/factorio-softmod-pack/98514e35b9fd55d3d36a5c129cbb2519ff0669c9/screenshots/dddgamer-softmod_task-list.png -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # DDDGamer's Factorio Softmod Collection (Scenario) 2 | 3 | ## Installation 4 | * Download the softmod pack zipped file (`dddgamer-softmod-pack.zip`) from the 5 | [Latest Release](https://github.com/deniszholob/factorio-softmod-pack/releases/latest) 6 | * Extract to `%appdata%/Factorio/scenarios/` 7 | * *(Optional)* Enable/disable softmod modules in the `control.lua` to your liking 8 | * Launch Factorio 9 | * *(Optional)* Configure any of the softmod modules in the `./modules/` folder to your liking 10 | * Launch Factorio 11 | * Play -> Scenarios -> dddgamer-softmod-pack 12 | 13 | ## Add to an existing save 14 | * Download the softmod pack zipped file (`dddgamer-softmod-pack.zip`) from the 15 | [Latest Release](https://github.com/deniszholob/factorio-softmod-pack/releases/latest) 16 | * Browse to your save file (.zip archive file) 17 | * Local saves are in C:/Users/*[your-username]*/AppData/Roaming/Factorio/saves/ 18 | * Open your save game zip 19 | * (typically `_autosave1.zip` for auto saves on regular game or servers) 20 | * Extract the softmod pack contents into the saved file replacing the control.lua 21 | 22 | ## Files 23 | 24 | ``` 25 | . 26 | ├── locale/ <- Translation strings 27 | ├── modules/ <- The actual softmod modules 28 | ├── stdlib/ <- Factorio "standard library" classes, main one being the Event 29 | ├── util/ <- Contains some utility classes like colors, math, styles. 30 | ├── config.lua <- Just creates a config global for now. 31 | ├── control.lua <- Entry file that loads all the 32 | └── README.MD <- This file 33 | ``` 34 | -------------------------------------------------------------------------------- /src/config.lua: -------------------------------------------------------------------------------- 1 | -- Soft Mod Config File 2 | -- ------------------------------------------------------- -- 3 | -- @author Denis Zholob (DDDGamer) 4 | -- github: https://github.com/deniszholob/factorio-softmod-pack 5 | -- ======================================================= -- 6 | 7 | -- Config Soft Mod here -- 8 | Event.register(Event.core_events.init, function() 9 | global.softmod_config = {} 10 | end) 11 | -------------------------------------------------------------------------------- /src/control.lua: -------------------------------------------------------------------------------- 1 | -- DDDGamer's Factorio Soft Mod Collection 2 | -- See README for more info and credits 3 | -- Import module order DOES MATTER (UI elements get drawn in import order) 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | 9 | -- Notes: 10 | -- * Customize scenario-name in global.cfg for your liking (optional, defaults is Freeplay) 11 | -- * 12 | 13 | -- ============== Import Dependency modules ============== -- 14 | -- ======================================================= -- 15 | 16 | -- "Event" must be first as its a dependency for all others (event wrapper makes is easier to develop) 17 | require('stdlib/Event') 18 | require('stdlib/table') 19 | -- require('stdlib/string') 20 | 21 | -- Import Config 22 | require('config') 23 | 24 | -- ============== Import Soft-Mod Modules ============== -- 25 | -- ======================================================= -- 26 | -- require('modules/dev/sandbox') 27 | 28 | -- == Import Vanilla Modules if needed == -- 29 | -- require('modules/vanilla/silo') 30 | -- require('modules/vanilla/player-init') 31 | 32 | -- == Import Soft Mod Modules == -- 33 | require('modules/dddgamer/player-init') 34 | require('modules/dddgamer/spawn-area') 35 | require('modules/dddgamer/player-logging') 36 | require('modules/dddgamer/game-info') 37 | 38 | require('modules/common/online-player-list') 39 | require('modules/common/evolution') 40 | require('modules/common/game-time') 41 | require('modules/common/silo') 42 | 43 | require('modules/common/spawn-marker') 44 | require('modules/common/death-marker') 45 | require('modules/common/autodeconstruct') 46 | require('modules/common/floating-health') 47 | -- require('modules/common/no-blueprints') 48 | -- require('modules/common/no-hand-crafting') 49 | require('modules/common/custom-tech') 50 | 51 | -- === Can cause problems in multiplayer === --- 52 | -- require('modules/common/research-queue/auto-research') 53 | -- require('modules/common/tasks') -- Has desync problems 54 | 55 | -- ==== Testing === -- 56 | -- require('modules/dev/__MODULE_NAME__') 57 | -- require('modules/dev/color_list') 58 | -- require('modules/dev/sprite_list') 59 | -- require('modules/dev/for-testing') 60 | -- require('modules/dev/spawn-rocket-silo') 61 | -------------------------------------------------------------------------------- /src/locale/en/__MODULE_NAME__.cfg: -------------------------------------------------------------------------------- 1 | [__MODULE_NAME__] 2 | # menu_btn_caption=__MODULE_NAME__ 3 | menu_btn_tooltip=Toggle __MODULE_NAME__ on or off 4 | master_frame_caption=__MODULE_NAME__ Title 5 | 6 | lbl_test=Gui Works! 7 | -------------------------------------------------------------------------------- /src/locale/en/auto-research.cfg: -------------------------------------------------------------------------------- 1 | [auto_research] 2 | announce_completed=[Auto Research] Research completed: __1__ __2__ 3 | announce_multiple_completed=[Auto Research] Multiple technologies researched this tick, announcement temporarily disabled 4 | 5 | [auto_research_gui] 6 | menu_btn_tooltip=Show Auto Research Queue 7 | title=Auto Research 8 | enabled=Enable Auto Research 9 | enabled_tooltip=Automatically start new research 10 | prioritized_only=Only research queued 11 | prioritized_only_tooltip=Only research queued techs and their prerequisites. No queue, no automatic research 12 | allow_switching=Allow switching research 13 | allow_switching_tooltip=Let Auto Research change the current research when you change research queue/settings 14 | announce_completed=Announce completed research 15 | announce_completed_tooltip=Print the name of the technology when research is completed 16 | deprioritize_infinite_tech=Deprioritize infinite tech 17 | deprioritize_infinite_tech_tooltip=Do not research infinite techs before all finite techs have been researched 18 | allowed_ingredients_label=Allowed research ingredients: 19 | prioritized_label=Queued research: 20 | deprioritized_label=Blacklisted research: 21 | none= 22 | search_label=Search: 23 | search_tooltip=Search for technology or item to queue/blacklist research 24 | ingredients_filter_search_results=Ingredients filter results 25 | ingredients_filter_search_results_tooltip=Only show search results that match the allowed ingredient list above 26 | research_strategy=Research strategy: 27 | research_fast=Fast 28 | research_fast_tooltip=Prioritize techs that take the least time to finish 29 | research_slow=Slow 30 | research_slow_tooltip=Prioritize techs that take the most time finish 31 | research_cheap=Cheap 32 | research_cheap_tooltip=Prioritize techs that require the least amount of ingredients 33 | research_expensive=Expensive 34 | research_expensive_tooltip=Prioritize techs that require the most amount of ingredients 35 | research_balanced=Balanced 36 | research_balanced_tooltip=Prioritize techs with a fast/cheap balance 37 | research_random=Random 38 | research_random_tooltip=Prioritize techs in a random order 39 | 40 | [controls] 41 | auto_research_toggle=Toggle Auto Research GUI 42 | 43 | [mod-setting-name] 44 | queued-tech-setting=Default queued techs 45 | blacklisted-tech-setting=Default blacklisted techs 46 | 47 | [mod-setting-description] 48 | queued-tech-setting=List techs separated by commas, to automatically queue them in new games. You must use the tech id, such as "construction-robotics" and not the localized name. 49 | blacklisted-tech-setting=List techs separated by commas, to automatically blacklist them in new games. You must use the tech id, such as "construction-robotics" and not the localized name. 50 | -------------------------------------------------------------------------------- /src/locale/en/autodeconstruct.cfg: -------------------------------------------------------------------------------- 1 | autodeconstruct-err-generic=[autodeconstruct] Error: __1__ 2 | autodeconstruct-err-specific=[autodeconstruct|__1__] Error: __2__ 3 | 4 | autodeconstruct-notify=[autodeconstruct] Notify: __1__ 5 | autodeconstruct-debug=[autodeconstruct.__1__] Debug: __2__ 6 | -------------------------------------------------------------------------------- /src/locale/en/custom-tech.cfg: -------------------------------------------------------------------------------- 1 | [custom_tech] 2 | disable_research= '__1__' research has been disabled 3 | disable_recipe= '__1__' recipe has been disabled 4 | -------------------------------------------------------------------------------- /src/locale/en/death-marker.cfg: -------------------------------------------------------------------------------- 1 | [death_marker] 2 | marker=RIP __1__ 3 | message=Death location [gps=__3__,__4__] for '__1__' has been marked on the map as '__2__' 4 | removed=Your death marker '__1__' has been removed. The corpse has decayed or been looted. 5 | -------------------------------------------------------------------------------- /src/locale/en/evolution.cfg: -------------------------------------------------------------------------------- 1 | [Evolution] 2 | master_frame_caption=Shows current enemy evolution 3 | alert=__1__ has been sighted! 4 | -------------------------------------------------------------------------------- /src/locale/en/game-info.cfg: -------------------------------------------------------------------------------- 1 | [Game_Info] 2 | menu_btn_tooltip=Shows Server Info 3 | master_frame_caption= Info 4 | master_frame_close_btn_caption=Close 5 | master_frame_close_btn_tooltip=Hide this window 6 | -------------------------------------------------------------------------------- /src/locale/en/game-time.cfg: -------------------------------------------------------------------------------- 1 | [Game_Time] 2 | menu_btn_tooltip=Toggle game time on or off 3 | master_frame_caption=Shows game time 4 | -------------------------------------------------------------------------------- /src/locale/en/global.cfg: -------------------------------------------------------------------------------- 1 | scenario-name=Freeplay 2 | description=Your task is to launch a rocket into space. Start from nothing, work your way up with automation and don't forget to protect yourself from the natives.\n[font=default-bold]This is the intended way of playing Factorio.[/font] 3 | msg-intro=This is the Factorio freeplay. Your task is to launch a rocket into space. You will need to research advanced technologies in order to unlock the rocket silo. Start small, work your way up with automation and don't forget to protect yourself from the natives. 4 | 5 | msg-dddgamer-intro=Welcome to DDDGamer's Freeplay scenario with QOL softmods. Discord link: discord.gg/PkyzXzz 6 | mgs-new-player=A new player has entered the arena. Welcome __1__! 7 | msg-player-left=__1__ left. Goodbye __1__ 8 | msg-player-return=__1__ returns, welcome back __1__! 9 | -------------------------------------------------------------------------------- /src/locale/en/no-blueprints.cfg: -------------------------------------------------------------------------------- 1 | [No_Blueprints] 2 | info=Importing Blueprints has been disabled in this Scenario (you can still create new ones) 3 | -------------------------------------------------------------------------------- /src/locale/en/no-hand-crafting.cfg: -------------------------------------------------------------------------------- 1 | [no-hand-craft] 2 | info=Hand crafting has been disabled in this scenario, you must use factories to make your items. 3 | -------------------------------------------------------------------------------- /src/locale/en/player-list.cfg: -------------------------------------------------------------------------------- 1 | [player_list] 2 | btn_tooltip=Shows who is on the server 3 | checkbox_caption=Show Offline 4 | checkbox_tooltip=Toggle b/w showing and hiding offline players 5 | player_tooltip=Click to show on map 6 | player_tooltip_inventory=Open __1__'s inventory 7 | player_tooltip_decon=Player has used deconstruction planner 8 | player_tooltip_mine=Player has mined something 9 | player_tooltip_playtime=Played __1__% of map time 10 | total_players=Total: __1__ / Online: __2__ 11 | -------------------------------------------------------------------------------- /src/locale/en/player-logging.cfg: -------------------------------------------------------------------------------- 1 | [Player_Logging] 2 | online_count= count=__1__ 3 | joined= name=__1__ 4 | left= name=__1__ 5 | mined= name=__1__ 6 | decon= name=__1__ 7 | research=Research Complete: [technology=__1__] 8 | -------------------------------------------------------------------------------- /src/locale/en/silo.cfg: -------------------------------------------------------------------------------- 1 | [silo] 2 | rocket_launched=A rocket has been launched! 3 | rocket_score=Rockets Launched: __1__ 4 | btn_tooltip=Show Rocket Score 5 | -------------------------------------------------------------------------------- /src/locale/ru/auto-research.cfg: -------------------------------------------------------------------------------- 1 | [auto_research] 2 | announce_completed=[Автоисследование] Исследование завершено: __1__ __2__ 3 | announce_multiple_completed=[Автоисследование] Несколько технологий исследовано в этот тик, анонс временно отключен 4 | 5 | [auto_research_gui] 6 | title=Автоисследование 7 | enabled=Включить автоисследование 8 | enabled_tooltip=Автоматически начинать новое исследование 9 | prioritized_only=Исследовать только по очереди 10 | prioritized_only_tooltip=Исследовать только техлоногии, добавленные в очередь, а так же их зависимости. Нет очереди - не исследований. 11 | allow_switching=Разрешить переключение исследований 12 | allow_switching_tooltip=Позволить Автоисследованию менять нынешнюю разработку, когда Вы меняеете очередь\настройки. 13 | announce_completed=Анонсировать завершение разаработки 14 | announce_completed_tooltip=Писать название технологии, когда её исследование завершено. 15 | deprioritize_infinite_tech=Деприоритезировать бесконечные технологии 16 | deprioritize_infinite_tech_tooltip=Не исследовать бесконечные технологии, пока не будут исследованы все конечные технологии. 17 | allowed_ingredients_label=Разрешённые исследовательские ингредиенты: 18 | prioritized_label=Очередь исследований: 19 | deprioritized_label=Чёрный список исследований: 20 | none=<пусто> 21 | search_label=Поиск: 22 | search_tooltip=Искать технологгию или предмет для добавления в очередь\чёрный список 23 | 24 | [controls] 25 | auto_research_toggle=Включить интерфейс Автоисследования 26 | -------------------------------------------------------------------------------- /src/locale/ru/custom-tech.cfg: -------------------------------------------------------------------------------- 1 | [custom_tech] 2 | disable_research= '__1__' исследование было отключено 3 | disable_recipe= '__1__' рецепт был отключен 4 | -------------------------------------------------------------------------------- /src/locale/ru/death-marker.cfg: -------------------------------------------------------------------------------- 1 | [death_marker] 2 | marker=Покойся с Миром __1__ 3 | message=Место смерти '__1__' было отмечено на карте как '__2__' 4 | removed=Ваш маркер смерти '__1__' был удален. Труп разложился или был разграблен. 5 | -------------------------------------------------------------------------------- /src/locale/ru/evolution.cfg: -------------------------------------------------------------------------------- 1 | [Evolution] 2 | master_frame_caption=Показывает эволюцию врага 3 | alert=__1__ был замечен! 4 | -------------------------------------------------------------------------------- /src/locale/ru/game-info.cfg: -------------------------------------------------------------------------------- 1 | [Game_Info] 2 | menu_btn_tooltip=Показывает информацию о сервере 3 | master_frame_caption=Информация 4 | master_frame_close_btn_caption=Закрыть 5 | master_frame_close_btn_tooltip=Скрыть это окно 6 | -------------------------------------------------------------------------------- /src/locale/ru/game-time.cfg: -------------------------------------------------------------------------------- 1 | [Game_Time] 2 | menu_btn_tooltip=Включить или выключить время игры 3 | master_frame_caption=Показывает время игры 4 | -------------------------------------------------------------------------------- /src/locale/ru/global.cfg: -------------------------------------------------------------------------------- 1 | scenario-name=Свободная игра 2 | description=Ваша задача - запустить ракету в космос. Начните с нуля, работайте над автоматизацией и не забудьте защитить себя от местных жителей.\n[font=default-bold]Это основной вид игры в Factorio.[/font] 3 | msg-intro=Это режим свободной игры Factorio. Ваша задача - запустить ракету в космос. Для её запуска потребуется исследовать новые технологии и создать ракетную шахту. Начните с малого, работайте над автоматизацией производства и не забывайте о защите от местных форм жизни. 4 | 5 | msg-dddgamer-intro=Добро пожаловать в сценарий "Свободная игра" от DDDGamer с пкж мягкими модами. Ссылка на Discord: discord.gg/PkyzXzz 6 | mgs-new-player=На арену вышел новый игрок. Добро пожаловать __1__! 7 | msg-player-left=__1__ ушел. Прощай __1__ 8 | msg-player-return=__1__ возвращается, добро пожаловать обратно! __1__! 9 | -------------------------------------------------------------------------------- /src/locale/ru/no-blueprints.cfg: -------------------------------------------------------------------------------- 1 | [No_Blueprints] 2 | info=Импорт Blueprints был отключен в этом сценарии (вы все еще можете создавать новые) 3 | -------------------------------------------------------------------------------- /src/locale/ru/no-hand-crafting.cfg: -------------------------------------------------------------------------------- 1 | [no-hand-craft] 2 | info=В этом сценарии ручное ремесло отключено, вы должны использовать фабрики для изготовления своих предметов. 3 | -------------------------------------------------------------------------------- /src/locale/ru/player-list.cfg: -------------------------------------------------------------------------------- 1 | [player_list] 2 | btn_tooltip=Показывает, кто находится на сервере 3 | checkbox_caption=Показывать Oфлайн 4 | checkbox_tooltip=Переключение между отображением и скрытием офлайн-игроков 5 | player_tooltip=Нажмите, чтобы показать на карте 6 | player_tooltip_inventory=Открыть инвентарь __1__ 7 | player_tooltip_decon=Игрок использовал планировщик разрушения 8 | player_tooltip_mine=Игрок что-то уничтожен 9 | player_tooltip_playtime=Играл __1__% времени на карте 10 | total_players=Все: __1__ / Онлайн: __2__ 11 | -------------------------------------------------------------------------------- /src/locale/ru/silo.cfg: -------------------------------------------------------------------------------- 1 | [silo] 2 | rocket_launched=Ракета запущена! 3 | rocket_score=Запущены ракеты: __1__ 4 | btn_tooltip=Показать счет ракеты 5 | -------------------------------------------------------------------------------- /src/modules/common/autodeconstruct.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright 2017 'mindmix' 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to 6 | deal in the Software without restriction, including without limitation the 7 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | sell copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | SOFTWARE. 19 | 20 | https://forums.factorio.com/viewtopic.php?f=92&t=17566 21 | This version has been modified: 22 | - Runs as a softmod/savemod, utilizing a modified 'factorio stdlib require '/lib/event' 23 | - Does not reference the 'setting' which would be initialized in the data phase. 24 | - @usage require('modules/common/autodeconstruct') 25 | 26 | --]] 27 | 28 | autodeconstruct = autodeconstruct or {} 29 | autodeconstruct.remove_target = true 30 | 31 | -- Find ore resources in a given area 32 | -- @param surface target surface 33 | -- @param position center position 34 | -- @param range range to search around center 35 | -- @param resource_category type of resources to find 36 | -- @return array of resources that match the category 37 | local function find_resources(surface, position, range, resource_category) 38 | local resource_category = resource_category or 'basic-solid' 39 | local top_left = {x = position.x - range, y = position.y - range} 40 | local bottom_right = {x = position.x + range, y = position.y + range} 41 | 42 | local resources = surface.find_entities_filtered{area={top_left, bottom_right}, type='resource'} 43 | categorized = {} 44 | for _, resource in pairs(resources) do 45 | if resource.prototype.resource_category == resource_category then 46 | table.insert(categorized, resource) 47 | end 48 | end 49 | return categorized 50 | end 51 | 52 | -- Find all entities of a certain type on the map. Called only once per map. 53 | -- @param entity_type type of entity to find 54 | -- @return array of matching entities 55 | local function find_all_entities(entity_type) 56 | local surface = game.surfaces['nauvis'] 57 | local entities = {} 58 | for chunk in surface.get_chunks() do 59 | local chunk_area = {lefttop = {x = chunk.x*32, y = chunk.y*32}, rightbottom = {x = chunk.x*32+32, y = chunk.y*32+32}} 60 | local chunk_entities = surface.find_entities_filtered({area = chunk_area, type = entity_type}) 61 | for i = 1, #chunk_entities do 62 | entities[#entities + 1] = chunk_entities[i] 63 | end 64 | end 65 | return entities 66 | end 67 | 68 | -- Find an entity's target (output) 69 | -- @param entity entity to find output for 70 | -- @return LuaEntity target 71 | local function find_target(entity) 72 | if entity.drop_target then 73 | return entity.drop_target 74 | else 75 | local entities = entity.surface.find_entities_filtered{position=entity.drop_position} 76 | if global.debug then msg_all({"autodeconstruct-debug", "found " .. entities[1].name .. " at " .. util.positiontostr(entities[1].position)}) end 77 | return entities[1] 78 | end 79 | end 80 | 81 | -- Find all mining drills with the same target 82 | -- @param entity the target to search for 83 | -- @return array of mining drills 84 | local function find_targeting(entity) 85 | local range = global.max_radius 86 | local position = entity.position 87 | 88 | local top_left = {x = position.x - range, y = position.y - range} 89 | local bottom_right = {x = position.x + range, y = position.y + range} 90 | 91 | local surface = entity.surface 92 | local entities = {} 93 | local targeting = {} 94 | 95 | local entities = surface.find_entities_filtered{area={top_left, bottom_right}, type='mining-drill'} 96 | for i = 1, #entities do 97 | if find_target(entities[i]) == entity then 98 | targeting[#targeting + 1] = entities[i] 99 | end 100 | end 101 | 102 | entities = surface.find_entities_filtered{area={top_left, bottom_right}, type='inserter'} 103 | for i = 1, #entities do 104 | if find_target(entities[i]) == entity then 105 | targeting[#targeting + 1] = entities[i] 106 | end 107 | end 108 | if global.debug then msg_all({"autodeconstruct-debug", "found " .. #targeting .. " targeting"}) end 109 | return targeting 110 | end 111 | 112 | -- Find all mining drills that were mining a certain ore tile 113 | -- @param entity ore entity 114 | -- @return array of mining drills 115 | local function find_drills(entity) 116 | local position = entity.position 117 | local surface = entity.surface 118 | 119 | local top_left = {x = position.x - global.max_radius, y = position.y - global.max_radius} 120 | local bottom_right = {x = position.x + global.max_radius, y = position.y + global.max_radius} 121 | 122 | local entities = {} 123 | local targeting = {} 124 | 125 | local entities = surface.find_entities_filtered{area={top_left, bottom_right}, type='mining-drill'} 126 | if global.debug then msg_all({"autodeconstruct-debug", "found " .. #entities .. " drills"}) end 127 | for i = 1, #entities do 128 | if math.abs(entities[i].position.x - position.x) < entities[i].prototype.mining_drill_radius and math.abs(entities[i].position.y - position.y) < entities[i].prototype.mining_drill_radius then 129 | autodeconstruct.check_drill(entities[i]) 130 | end 131 | end 132 | end 133 | 134 | -- Initialise globals 135 | function autodeconstruct.init_globals() 136 | global.max_radius = 0.99 137 | drill_entities = find_all_entities('mining-drill') 138 | for _, drill_entity in pairs(drill_entities) do 139 | autodeconstruct.check_drill(drill_entity) 140 | end 141 | end 142 | 143 | -- Handle resource depletion 144 | function autodeconstruct.on_resource_depleted(event) 145 | if event.entity.prototype.resource_category ~= 'basic-solid' or event.entity.prototype.infinite_resource ~= false then 146 | if global.debug then msg_all({"autodeconstruct-debug", "on_resource_depleted", game.tick .. " amount " .. event.entity.amount .. " resource_category " .. event.entity.prototype.resource_category .. " infinite_resource " .. (event.entity.prototype.infinite_resource == true and "true" or "false" )}) end 147 | return 148 | end 149 | drill = find_drills(event.entity) 150 | end 151 | 152 | -- Check a mining drill for depletion and order deconstruction if so 153 | -- @param drill mining drill to check 154 | function autodeconstruct.check_drill(drill) 155 | if drill.mining_target ~= nil and drill.mining_target.valid then 156 | if drill.mining_target.amount > 0 then return end -- this should also filter out pumpjacks and infinite resources 157 | end 158 | 159 | local mining_drill_radius = drill.prototype.mining_drill_radius 160 | if mining_drill_radius > global.max_radius then 161 | global.max_radius = mining_drill_radius 162 | end 163 | 164 | if mining_drill_radius == nil then return end 165 | 166 | resources = find_resources(drill.surface, drill.position, mining_drill_radius) 167 | for i = 1, #resources do 168 | if resources[i].amount > 0 then return end 169 | end 170 | if global.debug then msg_all({"autodeconstruct-debug", util.positiontostr(drill.position) .. " found no resources, deconstructing"}) end 171 | autodeconstruct.order_deconstruction(drill) 172 | end 173 | 174 | -- Handle cancelled deconstruction 175 | function autodeconstruct.on_cancelled_deconstruction(event) 176 | if event.player_index ~= nil or event.entity.type ~= 'mining-drill' then return end 177 | if global.debug then msg_all({"autodeconstruct-debug", "on_cancelled_deconstruction", util.positiontostr(event.entity.position) .. " deconstruction timed out, checking again"}) end 178 | autodeconstruct.check_drill(event.entity) 179 | end 180 | 181 | -- Handle placed entity 182 | function autodeconstruct.on_built_entity(event) 183 | if event.created_entity.type ~= 'mining-drill' then return end 184 | if event.created_entity.prototype.mining_drill_radius > global.max_radius then 185 | global.max_radius = event.created_entity.prototype.mining_drill_radius 186 | if global.debug then msg_all({"autodeconstruct-debug", "on_built_entity", "global.max_radius updated to " .. global.max_radius}) end 187 | end 188 | end 189 | 190 | -- Order drill deconstruction 191 | -- @param drill mining drill to deconstruct 192 | function autodeconstruct.order_deconstruction(drill) 193 | if drill.to_be_deconstructed(drill.force) then 194 | if global.debug then msg_all({"autodeconstruct-debug", util.positiontostr(drill.position) .. " already marked"}) end 195 | return 196 | end 197 | 198 | local deconstruct = true 199 | 200 | if drill.fluidbox and #drill.fluidbox > 0 then 201 | deconstruct = false 202 | end 203 | 204 | if next(drill.circuit_connected_entities.red) ~= nil or next(drill.circuit_connected_entities.green) ~= nil then 205 | deconstruct = false 206 | end 207 | if deconstruct == true and drill.minable and drill.prototype.selectable_in_game and drill.has_flag("not-deconstructable") == false then 208 | if drill.order_deconstruction(drill.force) then 209 | if global.debug then msg_all({"autodeconstruct-debug", util.positiontostr(drill.position) .. " " .. drill.name .. " success"}) end 210 | else 211 | msg_all({"autodeconstruct-err-specific", "drill.order_deconstruction", util.positiontostr(drill.position) .. " failed to order deconstruction on " .. drill.name }) 212 | end 213 | if autodeconstruct.remove_target then 214 | target = find_target(drill) 215 | if target ~= nil and target.minable and target.prototype.selectable_in_game then 216 | if target.type == "logistic-container" or target.type == "container" then 217 | targeting = find_targeting(target) 218 | if targeting ~= nil then 219 | for i = 1, #targeting do 220 | if not targeting[i].to_be_deconstructed(targeting[i].force) then return end 221 | end 222 | -- we are the only one targeting 223 | if target.to_be_deconstructed(target.force) then 224 | target.cancel_deconstruction(target.force) 225 | end 226 | if target.order_deconstruction(target.force) then 227 | if global.debug then msg_all({"autodeconstruct-debug", util.positiontostr(target.position) .. " " .. target.name .. " success"}) end 228 | else 229 | msg_all({"autodeconstruct-err-specific", "target.order_deconstruction", util.positiontostr(target.position) .. " failed to order deconstruction on " .. target.name}) 230 | end 231 | end 232 | end 233 | --[[ #TODO: 234 | if target.type == "transport-belt" then 235 | -- find entities with this belt as target 236 | end 237 | --]] 238 | end 239 | end 240 | end 241 | end 242 | 243 | -- Message all players 244 | -- @param message message to send 245 | function msg_all(message) 246 | if message[1] == "autodeconstruct-debug" then 247 | table.insert(message, 2, debug.getinfo(2).name) 248 | end 249 | for _,p in pairs(game.players) do 250 | p.print(message) 251 | end 252 | end 253 | 254 | global.debug = false 255 | remote.add_interface("ad", { 256 | debug = function() 257 | global.debug = not global.debug 258 | end, 259 | init = function() 260 | autodeconstruct.init_globals() 261 | end 262 | }) 263 | 264 | -- typically, this is part of a softmod pack, so let's just assume we got 265 | -- dropped into an existing save, and init on first player join/create 266 | Event.register(Event.core_events.init, function() 267 | local _, err = pcall(autodeconstruct.init_globals) 268 | if err then msg_all({"autodeconstruct-err-generic", err}) end 269 | end) 270 | 271 | Event.register(Event.core_events.configuration_changed, function() 272 | local _, err = pcall(autodeconstruct.init_globals) 273 | if err then msg_all({"autodeconstruct-err-generic", err}) end 274 | end) 275 | 276 | Event.register(defines.events.on_player_joined_game, function() 277 | local _, err = pcall(autodeconstruct.init_globals) 278 | if err then msg_all({"autodeconstruct-err-generic", err}) end 279 | end) 280 | 281 | Event.register(defines.events.on_player_created, function() 282 | local _, err = pcall(autodeconstruct.init_globals) 283 | if err then msg_all({"autodeconstruct-err-generic", err}) end 284 | end) 285 | 286 | Event.register(defines.events.on_cancelled_deconstruction, function(event) 287 | local _, err = pcall(autodeconstruct.on_cancelled_deconstruction, event) 288 | if err then msg_all({"autodeconstruct-err-specific", "on_cancelled_deconstruction", err}) end 289 | end) 290 | 291 | Event.register(defines.events.on_resource_depleted, function(event) 292 | local _, err = pcall(autodeconstruct.on_resource_depleted, event) 293 | if err then msg_all({"autodeconstruct-err-specific", "on_resource_depleted", err}) end 294 | end) 295 | 296 | Event.register(defines.events.on_robot_built_entity, function(event) 297 | local _, err = pcall(autodeconstruct.on_built_entity, event) 298 | if err then msg_all({"autodeconstruct-err-specific", "on_robot_built_entity", err}) end 299 | end) 300 | 301 | Event.register(defines.events.on_built_entity, function(event) 302 | local _, err = pcall(autodeconstruct.on_built_entity, event) 303 | if err then msg_all({"autodeconstruct-err-specific", "on_built_entity", err}) end 304 | end) 305 | -------------------------------------------------------------------------------- /src/modules/common/custom-tech.lua: -------------------------------------------------------------------------------- 1 | -- Custom_Tech Soft Module 2 | -- Disables certain technologies from being researched 3 | -- Reference `factorio/data/base/prototypes/technology/rechnology.lua` 4 | -- for list of tech and recipie names 5 | -- @usage require('modules/common/custom-tech') 6 | -- ------------------------------------------------------- -- 7 | -- @author Denis Zholob (DDDGamer) 8 | -- github: https://github.com/deniszholob/factorio-softmod-pack 9 | -- ======================================================= -- 10 | 11 | -- Dependencies -- 12 | -- ======================================================= -- 13 | 14 | -- Constants -- 15 | -- ======================================================= -- 16 | CustomTech = { 17 | -- Research to disable 18 | DISABLED_RESEARCH_LIST = { 19 | -- 'atomic-bomb', 20 | 'discharge-defense-equipment', 21 | -- 'logistic-system' 22 | -- 'logistics-3' 23 | }, 24 | -- Recipies to disable 25 | DISABLED_RECIPE_LIST = { 26 | -- 'atomic-bomb', 27 | 'discharge-defense-equipment', 28 | -- 'fast-transport-belt', 29 | -- 'express-transport-belt', 30 | -- 'underground-belt', 31 | -- 'fast-underground-belt', 32 | -- 'express-underground-belt', 33 | -- 'splitter', 34 | -- 'fast-splitter', 35 | -- 'express-splitter' 36 | }, 37 | -- Tech to begin researched with (ignored if "RESEARCH_ALL_TECH" is true) 38 | RESEARCH_TECH = { 39 | 'toolbelt', 40 | 'steel-axe', 41 | 'optics', 42 | 'circuit-network', 43 | 'construction-robotics', 44 | 'logistic-robotics', 45 | 'logistic-system', 46 | }, 47 | -- Turn off to only research "RESEARCH_TECH" list above 48 | RESEARCH_ALL_TECH = false, 49 | PRINT_DISABLED_TECH = false, 50 | ENABLE_RESEARCH_QUEUE = true, 51 | } 52 | 53 | -- Event Functions -- 54 | -- ======================================================= -- 55 | 56 | --- Various action when new player joins in game 57 | --- @param event defines.events.on_player_created event 58 | function CustomTech.on_player_created(event) 59 | local player = game.players[event.player_index] 60 | 61 | -- Research to disable 62 | for i, research in ipairs(CustomTech.DISABLED_RESEARCH_LIST) do 63 | player.force.technologies[research].enabled = false 64 | if CustomTech.PRINT_DISABLED_TECH then player.print({'custom_tech.disable_research', research}) end 65 | end 66 | 67 | -- Recipies to disable 68 | for i, recipe in ipairs(CustomTech.DISABLED_RECIPE_LIST) do 69 | player.force.recipes[recipe].enabled = false 70 | if CustomTech.PRINT_DISABLED_TECH then player.print({'custom_tech.disable_recipe', recipe}) end 71 | end 72 | 73 | -- Tech to start already researched with 74 | if(CustomTech.RESEARCH_ALL_TECH) then 75 | player.force.research_all_technologies() 76 | else 77 | for i, research in ipairs(CustomTech.RESEARCH_TECH) do 78 | player.force.technologies[research].researched = true 79 | end 80 | end 81 | 82 | -- Enable Research Queue 83 | if(CustomTech.ENABLE_RESEARCH_QUEUE) then 84 | player.force.research_queue_enabled = true 85 | -- game.difficulty_settings.research_queue_setting = "always" 86 | end 87 | 88 | -- Research all tech 89 | 90 | end 91 | 92 | -- Event Registration -- 93 | -- ======================================================= -- 94 | Event.register(defines.events.on_player_created, CustomTech.on_player_created) 95 | 96 | -- Helper Functions -- 97 | -- ======================================================= -- 98 | -------------------------------------------------------------------------------- /src/modules/common/death-marker.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright 2017-2018 "Kovus" 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation and/or 11 | other materials provided with the distribution. 12 | 3. Neither the name of the copyright holder nor the names of its contributors 13 | may be used to endorse or promote products derived from this software without 14 | specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | death_marker.lua - Create a death marker at player death location. 28 | @usage require('modules/common/deathmarker') 29 | 30 | --]] 31 | DeathMarkers = {} 32 | 33 | function DeathMarkers.init(event) 34 | if not global.death_markers then 35 | global.death_markers = { 36 | counters = {}, 37 | markers = {} 38 | } 39 | end 40 | end 41 | 42 | function DeathMarkers.removeCorpseTag(entity) 43 | local player = game.players[entity.character_corpse_player_index] 44 | if not player then 45 | return 46 | end 47 | 48 | local tick = entity.character_corpse_tick_of_death 49 | 50 | local markers = global.death_markers.markers 51 | for idx = 1, #markers do 52 | local entry = markers[idx] 53 | if entry and entry.player_index == player.index and entry.death_tick == tick then 54 | if entry.tag and entry.tag.valid then 55 | if player.connected then 56 | player.print({'death_marker.removed', entry.tag.text}) 57 | end 58 | entry.tag.destroy() 59 | end 60 | table.remove(markers, idx) 61 | return 62 | end 63 | end 64 | end 65 | 66 | function DeathMarkers.playerDied(event) 67 | local plidx = event.player_index 68 | local player = game.players[plidx] 69 | local position = player.position 70 | local surface = player.surface 71 | local force = player.force 72 | 73 | local counters = global.death_markers.counters 74 | if counters[plidx] then 75 | counters[plidx] = counters[plidx] + 1 76 | else 77 | counters[plidx] = 1 78 | end 79 | 80 | -- cannot localize the marker text, as it's a map entity common to all 81 | -- players, and not a gui element or player-based output message. 82 | local text = table.concat({'RIP ', player.name, ' (', counters[plidx], ')'}) 83 | 84 | local tag = 85 | force.add_chart_tag( 86 | surface, 87 | { 88 | position = position, 89 | text = text, 90 | icon = {type = 'item', name = 'power-armor-mk2'} 91 | } 92 | ) 93 | table.insert( 94 | global.death_markers.markers, 95 | { 96 | tag = tag, 97 | player_index = plidx, 98 | death_tick = event.tick 99 | } 100 | ) 101 | 102 | for index, cplayer in pairs(player.force.connected_players) do 103 | if cplayer.surface == surface then 104 | cplayer.print({'death_marker.message', player.name, text, position.x, position.y}) 105 | end 106 | end 107 | end 108 | 109 | function DeathMarkers.corpseExpired(event) 110 | DeathMarkers.removeCorpseTag(event.corpse) 111 | end 112 | 113 | function DeathMarkers.onMined(event) 114 | if event.entity.valid and event.entity.name == 'character-corpse' then 115 | DeathMarkers.removeCorpseTag(event.entity) 116 | end 117 | end 118 | 119 | -- typically, this is part of a softmod pack, so let's just assume we got 120 | -- dropped into an existing save, and init on first player join/create 121 | Event.register(defines.events.on_player_joined_game, DeathMarkers.init) 122 | Event.register(defines.events.on_player_created, DeathMarkers.init) 123 | Event.register(defines.events.on_pre_player_died, DeathMarkers.playerDied) 124 | Event.register(defines.events.on_character_corpse_expired, DeathMarkers.corpseExpired) 125 | Event.register(defines.events.on_pre_player_mined_item, DeathMarkers.onMined) 126 | -------------------------------------------------------------------------------- /src/modules/common/evolution.lua: -------------------------------------------------------------------------------- 1 | -- Evolution Soft Module 2 | -- __Description__ 3 | -- Uses locale evolution.cfg 4 | -- @usage require('modules/common/evolution') 5 | -- ------------------------------------------------------- -- 6 | -- @author Denis Zholob (DDDGamer) 7 | -- github: https://github.com/deniszholob/factorio-softmod-pack 8 | -- ======================================================= -- 9 | 10 | -- Dependencies -- 11 | -- ======================================================= -- 12 | local GUI = require('stdlib/GUI') 13 | local Styles = require('util/Styles') 14 | local Sprites = require("util/Sprites") 15 | local Time = require("util/Time") 16 | local Math = require("util/Math") 17 | local Colors = require('util/Colors') 18 | 19 | -- Constants -- 20 | -- ======================================================= -- 21 | Evolution = { 22 | MASTER_FRAME_NAME = 'frame_Evolution', 23 | EVOLUTION_FLOW_NAME = 'flw_Evolution', 24 | EVOLUTION_SPRITE_NAME = 'sprite_Evolution', 25 | EVOLUTION_LABEL_NAME = 'lbl_Evolution', 26 | EVOLUTION_PROGRESS_NAME = 'bar_Evolution', 27 | EVOLUTION_SPRITES = { 28 | [0.00] = Sprites.small_biter, 29 | [0.21] = Sprites.medium_biter, 30 | [0.26] = Sprites.small_spitter, 31 | [0.41] = Sprites.medium_spitter, 32 | [0.50] = Sprites.big_biter, 33 | [0.51] = Sprites.big_spitter, 34 | [0.90] = Sprites.behemoth_biter, 35 | [0.91] = Sprites.behemoth_spitter, 36 | }, 37 | EVOLUTION_COLORS = { 38 | [0.00] = Colors.orange, 39 | [0.21] = Colors.salmon, 40 | [0.50] = Colors.blue, 41 | [0.90] = Colors.darkgreen, 42 | }, 43 | get_master_frame = function(player) 44 | return GUI.menu_bar_el(player)[Evolution.MASTER_FRAME_NAME] 45 | end 46 | } 47 | 48 | -- Event Functions -- 49 | -- ======================================================= -- 50 | --- When new player joins add a btn to their menu bar 51 | --- Redraw this softmod's master frame (if desired) 52 | --- @param event defines.events.on_player_joined_game 53 | function Evolution.on_player_joined_game(event) 54 | local player = game.players[event.player_index] 55 | Evolution.draw_master_frame(player) 56 | end 57 | 58 | --- When a player leaves clean up their GUI in case this mod gets removed or changed next time 59 | --- @param event defines.events.on_player_left_game 60 | function Evolution.on_player_left_game(event) 61 | local player = game.players[event.player_index] 62 | GUI.destroy_element(Evolution.get_master_frame(player)) 63 | end 64 | 65 | --- Refresh the game time each second 66 | --- @param event defines.events.on_tick 67 | function Evolution.on_tick(event) 68 | local refresh_period = 1 -- (sec) 69 | if (Time.tick_to_sec(game.tick) % refresh_period == 0) then 70 | for i, player in pairs(game.connected_players) do 71 | Evolution.update_evolution(player) 72 | -- For Testing, artificially add pollution 73 | -- player.surface.pollute(player.position, 100000) 74 | end 75 | end 76 | end 77 | 78 | -- Event Registration -- 79 | -- ======================================================= -- 80 | Event.register(defines.events.on_player_joined_game, Evolution.on_player_joined_game) 81 | Event.register(defines.events.on_player_left_game, Evolution.on_player_left_game) 82 | Event.register(defines.events.on_tick, Evolution.on_tick) 83 | 84 | -- GUI Functions -- 85 | -- ======================================================= -- 86 | 87 | 88 | --- GUI Function 89 | --- Creates the main/master frame where all the GUI content will go in 90 | --- @param player LuaPlayer current player calling the function 91 | function Evolution.draw_master_frame(player) 92 | local master_frame = Evolution.get_master_frame(player) 93 | 94 | if (master_frame == nil) then 95 | master_frame = GUI.add_element( 96 | GUI.menu_bar_el(player), 97 | { 98 | type = 'frame', 99 | name = Evolution.MASTER_FRAME_NAME, 100 | direction = 'vertical', 101 | tooltip = {"Evolution.master_frame_caption"}, 102 | } 103 | ) 104 | -- GUI.element_apply_style(master_frame, Styles.frm_menu_no_pad) 105 | 106 | Evolution.fill_master_frame(master_frame, player) 107 | end 108 | end 109 | 110 | -- GUI Function 111 | --- Fills frame with worst enemy icon and evolution percentage 112 | --- @param container LuaGuiElement parent container to add GUI elements to 113 | --- @param player LuaPlayer player calling the function 114 | function Evolution.fill_master_frame(container, player) 115 | local h_flow = GUI.add_element( container, 116 | { 117 | type = 'flow', 118 | name = Evolution.EVOLUTION_FLOW_NAME, 119 | direction = 'horizontal', 120 | } 121 | ) 122 | h_flow.style.height = 10 123 | 124 | local sprite = GUI.add_element( h_flow, 125 | { 126 | type = 'sprite', 127 | name = Evolution.EVOLUTION_SPRITE_NAME, 128 | tooltip = {"Evolution.master_frame_caption"}, 129 | } 130 | ) 131 | local label = GUI.add_element( h_flow, 132 | { 133 | type = 'label', 134 | name = Evolution.EVOLUTION_LABEL_NAME, 135 | tooltip = {"Evolution.master_frame_caption"}, 136 | } 137 | ) 138 | 139 | local evo_progress_bar = container.add( 140 | { 141 | type = 'progressbar', 142 | name = Evolution.EVOLUTION_PROGRESS_NAME, 143 | tooltip = {"Evolution.master_frame_caption"}, 144 | value = 0.2 145 | } 146 | ) 147 | evo_progress_bar.style.width = 98 148 | evo_progress_bar.style.height = 3 149 | evo_progress_bar.style.top_margin = 14 150 | 151 | GUI.element_apply_style(container, Styles.btn_menu) 152 | GUI.element_apply_style(label, Styles.btn_menu_lbl) 153 | Evolution.update_evolution(player) 154 | end 155 | 156 | --- GUI Function 157 | --- Updates the enemy icon and evolution percentage, if its a new icon, send out alert 158 | --- @param player LuaPlayer current player calling the function 159 | function Evolution.update_evolution(player) 160 | local sprite_evolution = Evolution.get_master_frame(player)[Evolution.EVOLUTION_FLOW_NAME][Evolution.EVOLUTION_SPRITE_NAME] 161 | local lbl_evolution = Evolution.get_master_frame(player)[Evolution.EVOLUTION_FLOW_NAME][Evolution.EVOLUTION_LABEL_NAME] 162 | local evo_progress_bar = Evolution.get_master_frame(player)[Evolution.EVOLUTION_PROGRESS_NAME] 163 | local evolution_stats = Evolution.getEvolutionStats(player) 164 | if(sprite_evolution.sprite ~= evolution_stats.sprite) then 165 | sprite_evolution.sprite = evolution_stats.sprite 166 | player.print({"Evolution.alert", Sprites.getSpriteRichText(evolution_stats.sprite)}) 167 | end 168 | -- sprite_evolution.tooltip = evolution_stats.evolution_percent 169 | lbl_evolution.caption = evolution_stats.evolution_percent 170 | evo_progress_bar.value = evolution_stats.evolution 171 | evo_progress_bar.style.color = evolution_stats.color 172 | end 173 | 174 | -- Logic Functions -- 175 | -- ======================================================= -- 176 | 177 | --- Figures out some evolution stats and returns them (Sprite and evo %) 178 | --- @param player LuaPlayer current player calling the function 179 | function Evolution.getEvolutionStats(player) 180 | local evolution_factor = game.forces["enemy"].evolution_factor; 181 | local spriteIdx = 0; 182 | 183 | -- Figure out what evolution breakpoint we are at 184 | for evolution, sprite in pairs(Evolution.EVOLUTION_SPRITES) do 185 | if(evolution_factor < evolution) then 186 | break 187 | end 188 | spriteIdx = evolution 189 | end 190 | 191 | -- Figure out what evolution breakpoint we are at 192 | local colorIdx = 1 193 | for evo, color in pairs(Evolution.EVOLUTION_COLORS) do 194 | if(evolution_factor < evo) then 195 | break 196 | end 197 | colorIdx = evo 198 | end 199 | 200 | -- return the evolution data 201 | return { 202 | sprite = GUI.get_safe_sprite_name(player, Evolution.EVOLUTION_SPRITES[spriteIdx]), 203 | evolution = evolution_factor, 204 | evolution_percent = string.format('%6.2f', Math.round(evolution_factor * 100, 2)) .. "%", 205 | color = Evolution.EVOLUTION_COLORS[colorIdx] 206 | } 207 | end 208 | -------------------------------------------------------------------------------- /src/modules/common/floating-health.lua: -------------------------------------------------------------------------------- 1 | -- Floating Health Soft Mod 2 | -- Show the health of a player as a small piece of colored text above their head 3 | -- @usage require('modules/common/floating-health') 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | -- Dependencies -- 9 | -- ======================================================= -- 10 | local Colors = require('util/Colors') 11 | 12 | -- Constants -- 13 | -- ======================================================= -- 14 | FloatingHealth = { 15 | --- Max player Health is 250 as of v0.15 (changed from 100 in v0.14) 16 | --- player.character.prototype.max_health 17 | MAX_PLAYER_HP = 250 18 | } 19 | 20 | -- Event Functions -- 21 | -- ======================================================= -- 22 | 23 | --- On tick go through all the players and see if need to display health text 24 | --- @param event defines.events.on_tick 25 | function FloatingHealth.on_tick(event) 26 | -- Show every half second 27 | if game.tick % 30 ~= 0 then 28 | return 29 | end 30 | 31 | -- For every player thats online... 32 | for i, player in pairs(game.connected_players) do 33 | if player.character then 34 | -- Exit if player character doesnt have health 35 | if player.character.health == nil then 36 | return 37 | end 38 | local health = math.ceil(player.character.health) 39 | -- Set up global health var if doesnt exist 40 | if global.player_health == nil then 41 | global.player_health = {} 42 | end 43 | if global.player_health[player.name] == nil then 44 | global.player_health[player.name] = health 45 | end 46 | -- If mismatch b/w global and current hp, display hp text 47 | if global.player_health[player.name] ~= health then 48 | global.player_health[player.name] = health 49 | FloatingHealth.showPlayerHealth(player, health) 50 | end 51 | end 52 | end 53 | end 54 | 55 | 56 | -- Event Registration -- 57 | -- ======================================================= -- 58 | Event.register(defines.events.on_tick, FloatingHealth.on_tick) 59 | 60 | -- Helper Functions -- 61 | -- ======================================================= -- 62 | 63 | --- Draws different color health # above the player based on HP value 64 | --- @param player LuaPlayer 65 | --- @param health integer 66 | function FloatingHealth.showPlayerHealth(player, health) 67 | local max_hp = player.character.prototype.max_health -- or MAX_PLAYER_HP 68 | if health <= FloatingHealth.percentToHp(30, max_hp) then 69 | FloatingHealth.drawFlyingText( 70 | player, Colors.red, 71 | FloatingHealth.hpToPercent(health, max_hp) .. '%' 72 | ) 73 | elseif health <= FloatingHealth.percentToHp(50, max_hp) then 74 | FloatingHealth.drawFlyingText( 75 | player, Colors.yellow, 76 | FloatingHealth.hpToPercent(health, max_hp) .. '%' 77 | ) 78 | elseif health <= FloatingHealth.percentToHp(80, max_hp) then 79 | FloatingHealth.drawFlyingText( 80 | player, Colors.green, 81 | FloatingHealth.hpToPercent(health, max_hp) .. '%' 82 | ) 83 | end 84 | end 85 | 86 | 87 | --- Draws text above the player 88 | --- @param player LuaPlayer 89 | --- @param t_color table text color (rgb) 90 | --- @param t_text table text to display (string) 91 | function FloatingHealth.drawFlyingText(player, t_color, t_text) 92 | player.surface.create_entity { 93 | name = 'flying-text', 94 | color = t_color, 95 | text = t_text, 96 | position = {player.position.x, player.position.y - 2} 97 | } 98 | end 99 | 100 | 101 | --- Returns an HP value from apercentage 102 | --- @param val integer - HP number to convert to Percentage 103 | --- @param max_hp integer - Maximum Hp to calc percentage of 104 | function FloatingHealth.hpToPercent(val, max_hp) 105 | return math.ceil(100 / max_hp * val) 106 | end 107 | 108 | 109 | --- Returns HP as a percentage instead of raw number 110 | --- @param val integer - Percentage number to convert to HP 111 | --- @param max_hp integer - Maximum Hp to calc percentage of 112 | function FloatingHealth.percentToHp(val, max_hp) 113 | return math.ceil(max_hp / 100 * val) 114 | end 115 | 116 | -------------------------------------------------------------------------------- /src/modules/common/game-time.lua: -------------------------------------------------------------------------------- 1 | -- Game Time Soft Module 2 | -- Shows the game time at the top 3 | -- Uses locale game-time.cfg 4 | -- @usage require('modules/common/game-time') 5 | -- ------------------------------------------------------- -- 6 | -- @author Denis Zholob (DDDGamer) 7 | -- github: https://github.com/deniszholob/factorio-softmod-pack 8 | -- ======================================================= -- 9 | 10 | -- Dependencies -- 11 | -- ======================================================= -- 12 | local mod_gui = require("mod-gui") -- From `Factorio\data\core\lualib` 13 | local GUI = require("stdlib/GUI") 14 | local Colors = require("util/Colors") 15 | local Styles = require("util/Styles") 16 | local Math = require("util/Math") 17 | local Time = require("util/Time") 18 | 19 | -- Constants -- 20 | -- ======================================================= -- 21 | 22 | -- Constants -- 23 | -- ======================================================= -- 24 | GameTime = { 25 | MASTER_BUTTON_NAME = 'btn_menu_gametime', 26 | MASTER_FRAME_NAME = 'frame_menu_gametime', 27 | } 28 | 29 | -- Event Functions -- 30 | -- ======================================================= -- 31 | 32 | --- When new player joins add the game time btn to their GUI 33 | --- @param event defines.events.on_player_joined_game 34 | function GameTime.on_player_joined(event) 35 | local player = game.players[event.player_index] 36 | GameTime.draw_gametime_btn(player) 37 | GameTime.draw_gametime_frame(player) 38 | end 39 | 40 | --- On Player Leave 41 | --- Clean up the GUI in case this mod gets removed next time 42 | --- @param event defines.events.on_player_left_game 43 | function GameTime.on_player_leave(event) 44 | local player = game.players[event.player_index] 45 | if mod_gui.get_button_flow(player)[GameTime.MASTER_BUTTON_NAME] ~= nil then 46 | mod_gui.get_button_flow(player)[GameTime.MASTER_BUTTON_NAME].destroy() 47 | end 48 | if mod_gui.get_button_flow(player)[GameTime.MASTER_FRAME_NAME] ~= nil then 49 | mod_gui.get_button_flow(player)[GameTime.MASTER_FRAME_NAME].destroy() 50 | end 51 | end 52 | 53 | --- Toggle playerlist is called if gui element is playerlist button 54 | --- @param event defines.events.on_gui_click 55 | function GameTime.on_gui_click(event) 56 | local player = game.players[event.player_index] 57 | local el_name = event.element.name 58 | 59 | if el_name == GameTime.MASTER_BUTTON_NAME then 60 | GUI.toggle_element(mod_gui.get_button_flow(player)[GameTime.MASTER_FRAME_NAME]) 61 | end 62 | end 63 | 64 | --- Refresh the game time each second 65 | --- @param event defines.events.on_tick 66 | function GameTime.on_tick(event) 67 | local refresh_period = 1 -- (sec) 68 | if (Time.tick_to_sec(game.tick) % refresh_period == 0) then 69 | for i, player in pairs(game.connected_players) do 70 | GameTime.update_time(player) 71 | end 72 | end 73 | end 74 | 75 | -- Event Registration -- 76 | -- ======================================================= -- 77 | Event.register(defines.events.on_gui_click, GameTime.on_gui_click) 78 | Event.register(defines.events.on_player_joined_game, GameTime.on_player_joined) 79 | Event.register(defines.events.on_player_left_game, GameTime.on_player_leave) 80 | Event.register(defines.events.on_tick, GameTime.on_tick) 81 | 82 | -- Helper Functions -- 83 | -- ======================================================= -- 84 | 85 | --- @param player LuaPlayer 86 | function GameTime.update_time(player) 87 | local time_hms = Time.game_time_pased() 88 | local formatted_time = string.format("%s:%02d:%02d", time_hms.h, time_hms.m, time_hms.s) 89 | local frame = mod_gui.get_button_flow(player)[GameTime.MASTER_FRAME_NAME] 90 | local label = frame["lbl_gametime"] 91 | 92 | label.caption = formatted_time 93 | end 94 | 95 | --- Create button for player if doesnt exist already 96 | --- @param player LuaPlayer 97 | function GameTime.draw_gametime_btn(player) 98 | if mod_gui.get_button_flow(player)[GameTime.MASTER_BUTTON_NAME] == nil then 99 | mod_gui.get_button_flow(player).add( 100 | { 101 | type = "sprite-button", 102 | name = GameTime.MASTER_BUTTON_NAME, 103 | sprite = "utility/clock", 104 | tooltip = {"Game_Time.menu_btn_tooltip"} 105 | } 106 | ) 107 | end 108 | end 109 | 110 | --- Create frame for player if doesnt exist already 111 | --- @param player LuaPlayer 112 | function GameTime.draw_gametime_frame(player) 113 | if mod_gui.get_button_flow(player)[GameTime.MASTER_FRAME_NAME] == nil then 114 | local frame = 115 | mod_gui.get_button_flow(player).add({type = "frame", name = GameTime.MASTER_FRAME_NAME, direction = "vertical"}) 116 | 117 | local label = frame.add({ 118 | type = "label", 119 | name = "lbl_gametime", 120 | tooltip = {"Game_Time.master_frame_caption"}, 121 | caption = "", 122 | }) 123 | GUI.element_apply_style(frame, Styles.frm_menu) 124 | GUI.element_apply_style(label, Styles.lbl_menu) 125 | end 126 | 127 | GameTime.update_time(player) 128 | end 129 | -------------------------------------------------------------------------------- /src/modules/common/no-blueprints.lua: -------------------------------------------------------------------------------- 1 | -- No Blueprints Soft Module 2 | -- Uses locale no-blueprints.cfg 3 | -- @usage require('modules/common/no-blueprints') 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | 9 | -- Dependencies -- 10 | -- ======================================================= -- 11 | 12 | -- Constants -- 13 | -- ======================================================= -- 14 | NoBlueprints = { 15 | PERMISSION_GROUP = 'no_blueprints' 16 | } 17 | 18 | -- Event Functions -- 19 | -- ======================================================= -- 20 | 21 | --- Various action when new player joins in game 22 | --- @param event defines.events.on_player_created event 23 | function NoBlueprints.on_player_created(event) 24 | local player = game.players[event.player_index] 25 | NoBlueprints.dissalowBlueprints(player) 26 | player.print({'No_Blueprints.info'}) 27 | end 28 | 29 | -- Event Registration 30 | -- ================== -- 31 | Event.register(defines.events.on_player_created, NoBlueprints.on_player_created) 32 | 33 | -- Helper Functions -- 34 | -- ======================================================= -- 35 | 36 | --- @param player LuaPlayer 37 | function NoBlueprints.dissalowBlueprints(player) 38 | -- Get existing grouip or add one if doesnt exist 39 | local group = 40 | game.permissions.get_group(NoBlueprints.PERMISSION_GROUP) or 41 | game.permissions.create_group(NoBlueprints.PERMISSION_GROUP) 42 | -- Dissalow Hand Crafting (https://lua-api.factorio.com/latest/defines.html) 43 | group.set_allows_action(defines.input_action['import_blueprint'], false) 44 | group.set_allows_action(defines.input_action['import_blueprint_string'], false) 45 | -- group.set_allows_action(defines.input_action['open_blueprint_library_gui'], false) 46 | group.set_allows_action(defines.input_action['grab_blueprint_record'], false) 47 | group.set_allows_action(defines.input_action['open_blueprint_record'], false) 48 | -- Add player to the group 49 | game.permissions.get_group(NoBlueprints.PERMISSION_GROUP).add_player(player) 50 | end 51 | -------------------------------------------------------------------------------- /src/modules/common/no-hand-crafting.lua: -------------------------------------------------------------------------------- 1 | -- No Handcrafting Soft Module 2 | -- Based on arya's kit mod 3 | -- Uses locale no-hand-crafting.cfg 4 | -- @usage require('modules/common/no-hand-crafting') 5 | -- ------------------------------------------------------- -- 6 | -- @author Denis Zholob (DDDGamer) 7 | -- github: https://github.com/deniszholob/factorio-softmod-pack 8 | -- ======================================================= -- 9 | -- Dependencies -- 10 | -- ======================================================= -- 11 | -- Constants -- 12 | -- ======================================================= -- 13 | NoHandCrafting = { 14 | NO_HAND_CRAFT_PERMISSION_GROUP = 'no_hand_craft', 15 | NO_HAND_CRAFT_DEFAULT_SETTINGS = { 16 | --- Clear out inventory b4 giving items, or add the no handcraft kit items to whatever player has already 17 | onlyNoHandCraftKit = false, 18 | --- Gives steam engine instead of solar panel 19 | useSteamInsteadOfSolar = false, 20 | --- Adds an accumulator to be able to craft at night 21 | addAccumulator = true 22 | } 23 | } 24 | 25 | -- Event Functions -- 26 | -- ======================================================= -- 27 | 28 | --- Various action when new player joins in game 29 | --- @param event defines.events.on_player_created event 30 | function NoHandCrafting.on_player_created(event) 31 | local player = game.players[event.player_index] 32 | NoHandCrafting.addNoHandcraftKitItems(player) 33 | NoHandCrafting.disallowHandcrafting(player) 34 | player.print({'no-hand-craft.info'}) 35 | end 36 | 37 | 38 | -- Event Registration 39 | -- ================== -- 40 | Event.register( 41 | defines.events.on_player_created, NoHandCrafting.on_player_created 42 | ) 43 | 44 | -- Helper Functions -- 45 | -- ======================================================= -- 46 | 47 | --- Give player starting items for a no-handcrafting game. 48 | --- @param player LuaPlayer 49 | function NoHandCrafting.addNoHandcraftKitItems(player) 50 | -- Always get the Lvl 3 Assembler as it can craft every item in the game 51 | player.insert {name = 'assembling-machine-3', count = 1} 52 | -- Always include power pole as needed to transmit power 53 | player.insert {name = 'medium-electric-pole', count = 1} 54 | 55 | -- Power (solar or steam) 56 | if NoHandCrafting.NO_HAND_CRAFT_DEFAULT_SETTINGS.useSteamInsteadOfSolar then 57 | player.insert {name = 'offshore-pump', count = 1} 58 | player.insert {name = 'boiler', count = 1} 59 | player.insert {name = 'steam-engine', count = 1} 60 | else 61 | player.insert {name = 'solar-panel', count = 1} 62 | end 63 | 64 | -- Accumulators 65 | if NoHandCrafting.NO_HAND_CRAFT_DEFAULT_SETTINGS.addAccumulator then 66 | player.insert {name = 'accumulator', count = 1} 67 | end 68 | end 69 | 70 | 71 | --- Disable handcrafting permissions for player 72 | --- @param player LuaPlayer 73 | function NoHandCrafting.disallowHandcrafting(player) 74 | -- Get existing grouip or add one if doesnt exist 75 | local group = 76 | game.permissions.get_group(NoHandCrafting.NO_HAND_CRAFT_PERMISSION_GROUP) or 77 | game.permissions.create_group(NoHandCrafting.NO_HAND_CRAFT_PERMISSION_GROUP) 78 | 79 | -- Dissalow Hand Crafting (https://lua-api.factorio.com/latest/defines.html) 80 | group.set_allows_action(defines.input_action['craft'], false) 81 | -- Add player to the group 82 | game.permissions.get_group(NoHandCrafting.NO_HAND_CRAFT_PERMISSION_GROUP) 83 | .add_player(player) 84 | end 85 | 86 | -------------------------------------------------------------------------------- /src/modules/common/research-queue/Research_Queue_Styles.lua: -------------------------------------------------------------------------------- 1 | -- Research Queue Styles Soft Module Stylesheet 2 | -- Holds style definitions 3 | -- @usage local Research_Queue_Styles = require('modules/common/research-queue/Research_Queue_Styles') 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | 9 | -- Dependencies -- 10 | -- ======================================================= -- 11 | local Colors = require('util/Colors') 12 | 13 | -- Constants -- 14 | -- ======================================================= -- 15 | 16 | ResearchQueueStyles = { 17 | auto_research_header_label = { 18 | font_color = {r = .91764705882352941176, g = .85098039215686274509, b = .67450980392156862745}, 19 | font = 'default-large-semibold', 20 | top_padding = 0, 21 | bottom_padding = 0, 22 | left_padding = 0, 23 | right_padding = 6 24 | }, 25 | auto_research_list_flow = { 26 | vertical_spacing = 0 27 | }, 28 | auto_research_tech_flow = { 29 | horizontal_spacing = 0, 30 | resize_row_to_width = true 31 | }, 32 | auto_research_sprite = { 33 | width = 24, 34 | height = 24, 35 | top_padding = 0, 36 | right_padding = 0, 37 | bottom_padding = 0, 38 | left_padding = 0, 39 | horizontally_squashable = true, 40 | vertically_squashable = true, 41 | stretch_image_to_widget_size = true, 42 | }, 43 | auto_research_sprite_button = { 44 | width = 24, 45 | height = 24, 46 | top_padding = 0, 47 | right_padding = 0, 48 | bottom_padding = 0, 49 | left_padding = 0, 50 | clicked_font_color = Colors.darkgrey 51 | }, 52 | auto_research_sprite_button_toggle = { 53 | width = 24, 54 | height = 24, 55 | top_padding = 0, 56 | right_padding = 0, 57 | bottom_padding = 0, 58 | left_padding = 0, 59 | clicked_font_color = Colors.green 60 | }, 61 | auto_research_sprite_button_toggle_pressed = { 62 | width = 24, 63 | height = 24, 64 | top_padding = 0, 65 | right_padding = 0, 66 | bottom_padding = 0, 67 | left_padding = 0, 68 | clicked_font_color = Colors.red 69 | }, 70 | auto_research_tech_label = { 71 | left_padding = 4, 72 | right_padding = 4 73 | }, 74 | scroll_pane = { 75 | top_padding = 5, 76 | bottom_padding = 5, 77 | maximal_height = 127, 78 | minimal_height = 40, 79 | horizontally_stretchable = true, 80 | }, 81 | button_outer_frame = { 82 | top_padding = 0, 83 | right_padding = 0, 84 | bottom_padding = 0, 85 | left_padding = 0 86 | } 87 | } 88 | 89 | return ResearchQueueStyles 90 | -------------------------------------------------------------------------------- /src/modules/common/silo.lua: -------------------------------------------------------------------------------- 1 | -- Silo Soft Module 2 | -- Keeps track of rockets launched 3 | -- Uses locale silo.cfg 4 | -- @usage require('modules/common/silo') 5 | -- ------------------------------------------------------- -- 6 | -- @author Denis Zholob (DDDGamer) 7 | -- github: https://github.com/deniszholob/factorio-softmod-pack 8 | -- ======================================================= -- 9 | 10 | -- Dependencies -- 11 | -- ======================================================= -- 12 | local mod_gui = require('mod-gui') -- From `Factorio\data\core\lualib` 13 | local GUI = require('stdlib/GUI') 14 | local Colors = require('util/Colors') 15 | local Styles = require("util/Styles") 16 | 17 | -- Constants -- 18 | -- ======================================================= -- 19 | Silo = {} 20 | 21 | -- Event Functions -- 22 | -- ======================================================= -- 23 | 24 | --- When new player joins add a silo btn to their GUI that toggles rocket score 25 | --- Redraw the rocket score frame to update with the new player 26 | --- @param event defines.events.on_player_joined_game 27 | function Silo.on_player_joined_game(event) 28 | local player = game.players[event.player_index] 29 | Silo.draw_rocket_score_btn(player) 30 | Silo.draw_rocket_score_frame(player) 31 | end 32 | 33 | --- On Player Leave 34 | --- Clean up the GUI in case this mod gets removed next time 35 | --- Redraw the rocket score frame to update 36 | --- @param event defines.events.on_player_left_game 37 | function Silo.on_player_left_game(event) 38 | local player = game.players[event.player_index] 39 | if mod_gui.get_button_flow(player)['btn_menu_score'] ~= nil then 40 | mod_gui.get_button_flow(player)['btn_menu_score'].destroy() 41 | end 42 | if mod_gui.get_button_flow(player)['frame_menu_score'] ~= nil then 43 | mod_gui.get_button_flow(player)['frame_menu_score'].destroy() 44 | end 45 | end 46 | 47 | --- Toggle rocket score frame is called if gui element is the silo button 48 | --- @param event defines.events.on_gui_click 49 | function Silo.on_gui_click(event) 50 | local player = game.players[event.player_index] 51 | local el_name = event.element.name 52 | 53 | if el_name == 'btn_menu_score' then 54 | GUI.toggle_element(mod_gui.get_button_flow(player)['frame_menu_score']) 55 | end 56 | end 57 | 58 | --- Increment rocket score and refresh the UI 59 | --- @param event defines.events.on_rocket_launched 60 | function Silo.on_rocket_launched(event) 61 | game.print({'silo.rocket_launched'}) 62 | 63 | for i, player in pairs(game.connected_players) do 64 | Silo.update_score(player) 65 | end 66 | end 67 | 68 | -- Event Registration -- 69 | -- ======================================================= -- 70 | Event.register(defines.events.on_player_joined_game, Silo.on_player_joined_game) 71 | Event.register(defines.events.on_player_left_game, Silo.on_player_left_game) 72 | Event.register(defines.events.on_gui_click, Silo.on_gui_click) 73 | Event.register(defines.events.on_rocket_launched, Silo.on_rocket_launched) 74 | 75 | -- Helper Functions -- 76 | -- ======================================================= -- 77 | 78 | --- Draws a small frame next to rocket button to show rocket count 79 | --- @param player LuaPlayer 80 | function Silo.draw_rocket_score_btn(player) 81 | if mod_gui.get_button_flow(player)['btn_menu_score'] == nil then 82 | mod_gui.get_button_flow(player).add( 83 | { 84 | type = 'sprite-button', 85 | name = 'btn_menu_score', 86 | sprite = 'item/rocket-silo', 87 | tooltip = {'silo.btn_tooltip'} 88 | } 89 | ) 90 | end 91 | end 92 | 93 | --- Draws a small frame next to rocket button to show rocket count 94 | --- @param player LuaPlayer 95 | function Silo.draw_rocket_score_frame(player) 96 | local frame = mod_gui.get_button_flow(player)['frame_menu_score'] 97 | if frame == nil then 98 | frame = 99 | mod_gui.get_button_flow(player).add({type = 'frame', name = 'frame_menu_score', direction = 'vertical'}) 100 | 101 | local label = frame.add({type = 'label', name = 'lbl_rockets_launched', caption = ''}) 102 | GUI.element_apply_style(frame, Styles.frm_menu) 103 | GUI.element_apply_style(label, Styles.lbl_menu) 104 | label.style.font_color = Colors.orange 105 | end 106 | 107 | Silo.update_score(player) 108 | 109 | -- Hide if no rockets launched yet 110 | if (player.force.rockets_launched <= 0) then 111 | frame.visible = false 112 | end 113 | end 114 | 115 | --- Refreshes the score for the player 116 | --- @param player LuaPlayer 117 | function Silo.update_score(player) 118 | local frame = mod_gui.get_button_flow(player)['frame_menu_score'] 119 | local label = frame['lbl_rockets_launched'] 120 | local rocket_score = tostring(player.force.rockets_launched) 121 | 122 | label.caption = {'silo.rocket_score', rocket_score} 123 | 124 | -- Show the score on first rocket launch 125 | if(rocket_score == 1) then frame.visible = true end 126 | end 127 | -------------------------------------------------------------------------------- /src/modules/common/spawn-marker.lua: -------------------------------------------------------------------------------- 1 | -- Spawn Marker Module 2 | -- Sets a marker on the map to show the spawn area 3 | -- @usage require('modules/common/spawn-marker') 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | 9 | -- Constants -- 10 | -- ======================================================= -- 11 | 12 | SpawnMarker = {} 13 | 14 | -- Event Functions -- 15 | -- ======================================================= -- 16 | 17 | --- Various action when new player joins in game 18 | --- @param event on_player_created event 19 | function SpawnMarker.on_player_created(event) 20 | local player = game.players[event.player_index] 21 | if (not global.spawn_marked_on_map) then 22 | SpawnMarker.set_map_spawn_marker(player) 23 | global.spawn_marked_on_map = true 24 | end 25 | end 26 | 27 | -- Event Registration -- 28 | -- ======================================================= -- 29 | Event.register(defines.events.on_player_created, SpawnMarker.on_player_created) 30 | 31 | -- Helper Functions -- 32 | -- ======================================================= -- 33 | 34 | --- Set spawn mark on map 35 | --- @param player LuaPlayer 36 | function SpawnMarker.set_map_spawn_marker(player) 37 | local spawn_position = player.force.get_spawn_position(player.surface) 38 | local map_tag = { 39 | position = spawn_position, 40 | text = 'Spawn', 41 | icon = {type = 'item', name = 'heavy-armor'} 42 | } 43 | 44 | -- FIXME: This doesnt work b/c area is not yet charted 45 | -- Adding a chart call before this doesnt fix the problem as it seems to be async. 46 | player.force.add_chart_tag(player.surface, map_tag) 47 | end 48 | -------------------------------------------------------------------------------- /src/modules/dddgamer/death-marker-simple.lua: -------------------------------------------------------------------------------- 1 | -- Simple Death Marker Soft Module 2 | -- Places a marker on the map when player dies 3 | -- @usage require('modules/dddgamer/death-marker-simple') 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | -- Dependencies -- 9 | -- ======================================================= -- 10 | local Time = require('util/Time') 11 | 12 | -- Constants -- 13 | -- ======================================================= -- 14 | DeathMarker = {} 15 | 16 | -- Event Functions -- 17 | -- ======================================================= -- 18 | 19 | --- When a player dies, place a marker on the map of death location 20 | --- @param event defines.events.on_pre_player_died 21 | function DeathMarker.on_player_death(event) 22 | local player = game.players[event.player_index] 23 | local death_hms = Time.tick_to_time_hms(game.tick) 24 | local time = death_hms.h .. ':' .. death_hms.m .. ':' .. death_hms.s 25 | local deathText = player.name .. '-Death@' .. time 26 | local map_tag = { 27 | position = player.position, 28 | text = deathText, 29 | last_user = player 30 | } 31 | player.force.add_chart_tag(player.surface, map_tag) 32 | end 33 | 34 | 35 | -- Event Registration -- 36 | -- ======================================================= -- 37 | if (Event) then 38 | Event.register( 39 | defines.events.on_pre_player_died, DeathMarker.on_player_death 40 | ) 41 | else 42 | script.on_event( 43 | defines.events.on_pre_player_died, DeathMarker.on_player_death 44 | ) 45 | end 46 | -------------------------------------------------------------------------------- /src/modules/dddgamer/game-info.lua: -------------------------------------------------------------------------------- 1 | -- Game Info Soft Module 2 | -- Displays a game info windo containing rules, etc... 3 | -- Uses locale dddgamer-game-info.cfg 4 | -- @usage require('modules/dddgamer/game-info') 5 | -- ------------------------------------------------------- -- 6 | -- @author Denis Zholob (DDDGamer) 7 | -- github: https://github.com/deniszholob/factorio-softmod-pack 8 | -- ======================================================= -- 9 | 10 | -- Dependencies -- 11 | -- ======================================================= -- 12 | local mod_gui = require("mod-gui") -- From `Factorio\data\core\lualib` 13 | local GUI = require('stdlib/GUI') 14 | local Colors = require('util/Colors') 15 | local Math = require('util/Math') 16 | local Time = require('util/Time') 17 | local Styles = require('util/Styles') 18 | 19 | -- Constants -- 20 | -- ======================================================= -- 21 | GameInfo = { 22 | MASTER_BUTTON_NAME = 'btn_menu_game_info', 23 | MASTER_FRAME_NAME = 'frame_game_info', 24 | SECTION_CONTENT = { 25 | { 26 | title = '', 27 | content = { 28 | '* Gameplay: Vanilla with QOL Mods', 29 | -- '* Gameplay: Handcrafting is disabled', 30 | -- '* Gameplay: Handcrafting and Blueprints have been disabled', 31 | '* Chat with the [color=orange]`[/color] Key (Under the [color=orange]ESC[/color] Key)', 32 | '* Join discord for discussion, voice chat and admin support:', 33 | 'https://discord.gg/PkyzXzz', 34 | '* Check the Factorio Cheat Sheet for help:', 35 | 'https://factoriosheatsheet.com/', 36 | '* The softmod/scenario code:', 37 | 'https://github.com/deniszholob/factorio-softmod-pack', 38 | '* Support on kofi:', 39 | 'https://ko-fi.com/deniszholob', 40 | } 41 | }, 42 | { 43 | title = "Train Guidelines", 44 | content = { 45 | '* Trains are [color=orange]RHD[/color] (Right Hand Drive)', 46 | '* Please do not make train roundabouts/loops, junctions/end point stations only', 47 | '* General Train size is [color=orange]2-4-2[/color]', 48 | '* Place junctions 2-4-2 width apart', 49 | '* [color=orange]Color[/color] the trains/stations appropriately', 50 | } 51 | }, 52 | { 53 | title = "Station Naming Guidelines", 54 | content = { 55 | '* L = Load, U = Unload, Q = Queue/Stacker (Exclude "[" and "]" for the following examples):', 56 | '* Resource Trains: [Location/Name]_[L/U]_[Resource-Name]', 57 | '* Taxi Trains: #PAX_[Location]_[Resource-Name]_[ID]', 58 | '* Example Ore: "Mine_L_Iron-Ore_1"', 59 | '* Example PAX: "#PAX_Mine_Copper-Ore_3"', 60 | } 61 | }, 62 | } 63 | } 64 | 65 | -- Event Functions -- 66 | -- ======================================================= -- 67 | 68 | --- When new player joins add the gameinfo btn to their GUI 69 | --- Redraw the gameinfo frame to update with the new player 70 | --- @param event defines.events.on_player_joined_game 71 | function GameInfo.on_player_joined(event) 72 | local player = game.players[event.player_index] 73 | GameInfo.draw_gameinfo_btn(player) 74 | 75 | -- Force a gui refresh in case there where updates 76 | if player.gui.center[GameInfo.MASTER_FRAME_NAME] ~= nil then 77 | player.gui.center[GameInfo.MASTER_FRAME_NAME].destroy() 78 | end 79 | 80 | -- Show readme window (rules) when player (not admin) first joins, but not at later times 81 | if not player.admin and Time.tick_to_min(player.online_time) < 1 then 82 | GameInfo.draw_gameinfo_frame(player) 83 | end 84 | end 85 | 86 | --- On Player Leave 87 | --- Clean up the GUI in case this mod gets removed next time 88 | --- Redraw the gameinfo frame to update 89 | --- @param event defines.events.on_player_left_game 90 | function GameInfo.on_player_leave(event) 91 | local player = game.players[event.player_index] 92 | if player.gui.center[GameInfo.MASTER_FRAME_NAME] ~= nil then 93 | player.gui.center[GameInfo.MASTER_FRAME_NAME].destroy() 94 | end 95 | if mod_gui.get_button_flow(player)[GameInfo.MASTER_BUTTON_NAME] ~= nil then 96 | mod_gui.get_button_flow(player)[GameInfo.MASTER_BUTTON_NAME].destroy() 97 | end 98 | end 99 | 100 | --- Toggle gameinfo is called if gui element is gameinfo button 101 | --- @param event defines.events.on_gui_click 102 | function GameInfo.on_gui_click(event) 103 | local player = game.players[event.player_index] 104 | local el_name = event.element.name 105 | 106 | if el_name == GameInfo.MASTER_BUTTON_NAME or el_name == 'btn_gameinfo_close' then 107 | -- Call toggle if frame has been created 108 | if(player.gui.center[GameInfo.MASTER_FRAME_NAME] ~= nil) then 109 | GUI.destroy_element(player.gui.center[GameInfo.MASTER_FRAME_NAME]) 110 | else -- Call create if it hasnt 111 | GameInfo.draw_gameinfo_frame(player) 112 | end 113 | end 114 | end 115 | 116 | -- Event Registration -- 117 | -- ======================================================= -- 118 | Event.register(defines.events.on_gui_click, GameInfo.on_gui_click) 119 | Event.register(defines.events.on_player_joined_game, GameInfo.on_player_joined) 120 | Event.register(defines.events.on_player_left_game, GameInfo.on_player_leave) 121 | 122 | -- Helper Functions -- 123 | -- ======================================================= -- 124 | --- Create button for player if doesnt exist already 125 | --- @param player LuaPlayer 126 | function GameInfo.draw_gameinfo_btn(player) 127 | if mod_gui.get_button_flow(player)[GameInfo.MASTER_BUTTON_NAME] == nil then 128 | local btn = mod_gui.get_button_flow(player).add( 129 | { 130 | type = 'sprite-button', 131 | name = GameInfo.MASTER_BUTTON_NAME, 132 | -- caption = 'Info', 133 | sprite = 'utility/favourite_server_icon', 134 | tooltip = {"Game_Info.menu_btn_tooltip"} 135 | } 136 | ) 137 | GUI.element_apply_style(btn, Styles.btn_menu) 138 | end 139 | end 140 | 141 | --- Draws a pane on the left listing all of the players currentely on the server 142 | --- @param player LuaPlayer 143 | function GameInfo.draw_gameinfo_frame(player) 144 | local master_frame = player.gui.center[GameInfo.MASTER_FRAME_NAME] 145 | if(master_frame == nil) then 146 | -- Window frame 147 | master_frame = player.gui.center.add({ 148 | type = 'frame', 149 | direction = 'vertical', 150 | name = GameInfo.MASTER_FRAME_NAME, 151 | caption = {'Game_Info.master_frame_caption'}, 152 | }) 153 | -- master_frame.style.scaleable = true 154 | master_frame.style.height = 670 155 | master_frame.style.width = 650 156 | -- master_frame.style.left_padding = 10 157 | -- master_frame.style.right_padding = 10 158 | -- master_frame.style.top_padding = 10 159 | -- master_frame.style.bottom_padding = 10 160 | 161 | -- Add scrollable section to content frame 162 | local scrollable_content_frame = 163 | master_frame.add( 164 | { 165 | type = 'scroll-pane', 166 | vertical_scroll_policy = 'auto-and-reserve-space', 167 | horizontal_scroll_policy = 'never', 168 | style = 'scroll_pane_with_dark_background_under_subheader' 169 | } 170 | ) 171 | scrollable_content_frame.style.vertically_stretchable = true 172 | scrollable_content_frame.style.horizontally_stretchable = true 173 | 174 | -- Content Frame 175 | -- local content_frame = 176 | -- scrollable_content_frame.add( 177 | -- {type = 'frame', direction = 'vertical', name = 'content_frame', style = 'crafting_frame'} 178 | -- ) 179 | -- content_frame.style.horizontally_stretchable = true 180 | -- content_frame.style.vertically_stretchable = true 181 | 182 | scrollable_content_frame.style.left_padding = 10 183 | scrollable_content_frame.style.right_padding = 0 184 | scrollable_content_frame.style.top_padding = 10 185 | scrollable_content_frame.style.bottom_padding = 10 186 | 187 | -- Flow 188 | local mapInfoSection = scrollable_content_frame.add({type = 'flow', direction = 'horizontal'}) 189 | mapInfoSection.style.horizontally_stretchable = true 190 | mapInfoSection.style.bottom_padding = 15 191 | 192 | local text_box = mapInfoSection.add({ 193 | type = "label", 194 | caption = "Map Seed" 195 | }) 196 | local text_box = mapInfoSection.add({ 197 | type = "textfield", 198 | text = player.surface.map_gen_settings.seed 199 | }) 200 | 201 | -- Insert content 202 | for i, section in pairs(GameInfo.SECTION_CONTENT) do 203 | GameInfo.draw_section(scrollable_content_frame, section) 204 | end 205 | 206 | -- Flow 207 | local button_flow = master_frame.add({type = 'flow', direction = 'horizontal'}) 208 | button_flow.style.horizontally_stretchable = true -- Needed for align to work 209 | button_flow.style.horizontal_align = 'left' 210 | 211 | -- Close Button 212 | local close_button = button_flow.add({ 213 | type = 'button', 214 | name = 'btn_gameinfo_close', 215 | caption = {'Game_Info.master_frame_close_btn_caption'}, 216 | tooltip = {'Game_Info.master_frame_close_btn_tooltip'}, 217 | style="red_back_button" 218 | }) 219 | close_button.style.top_margin = 8 220 | end 221 | end 222 | 223 | --- Draws a list of labels from content passed in 224 | --- @param container table gui element to add to 225 | --- @param content any array list of string to display 226 | function GameInfo.draw_static_content(container, content) 227 | -- GUI.clear_element(container) -- Clear the current info before adding new 228 | for i, text in pairs(content) do 229 | -- Regular text 230 | if (string.find(text, 'http', 1) == nil) then 231 | -- Links go into textfields, rest as text 232 | local txt = container.add({type = 'label', name = i, caption = text}) 233 | if (string.find(text, '===', 1) ~= nil) then 234 | txt.style.font_color = Colors.orange 235 | txt.style.font = 'default-bold' 236 | txt.style.horizontal_align = 'center' 237 | end 238 | else 239 | local txt = container.add({type = 'textfield', name = i, text = text}) 240 | txt.style.horizontally_stretchable = true 241 | -- txt.read_only = true 242 | txt.style.width = 500 243 | -- txt.style.color = Colors.grey 244 | end 245 | end 246 | end 247 | 248 | 249 | ---@param container table 250 | ---@param section_content_data table 251 | function GameInfo.draw_section(container, section_content_data) 252 | -- Flow 253 | local section = container.add({type = 'flow', direction = 'vertical'}) 254 | section.style.horizontally_stretchable = true 255 | section.style.bottom_padding = 15 256 | 257 | -- Header flow 258 | local header_flow = section.add({type = 'flow', direction = 'horizontal'}) 259 | header_flow.style.horizontally_stretchable = true -- Needed for align to work 260 | header_flow.style.horizontal_align = 'center' 261 | 262 | -- Section Header Text 263 | if(#section_content_data.title > 0) then 264 | local header = header_flow.add({type = 'label', caption = '=== ' .. section_content_data.title .. ' ==='}) 265 | header.style.font = 'default-bold' 266 | header.style.font_color = Colors.orange 267 | end 268 | 269 | -- Section Contents 270 | GameInfo.draw_static_content(section, section_content_data.content) 271 | end 272 | -------------------------------------------------------------------------------- /src/modules/dddgamer/player-init.lua: -------------------------------------------------------------------------------- 1 | -- Player Init Soft Module 2 | -- Changes spawn and respawn items from vanilla version 3 | -- @usage require('modules/dddgamer/player-init-dddgamer') 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | 9 | -- Dependencies -- 10 | -- ======================================================= -- 11 | local Time = require('util/Time') 12 | local Colors = require('util/Colors') 13 | 14 | -- Constants -- 15 | -- ======================================================= -- 16 | PlayerInit = { 17 | -- Time in Minutes 18 | AGE = { 19 | NOMAD = 20, 20 | IRON = 60, 21 | STEEL = 120 22 | }, 23 | REVEAL_AREA_RADIUS = 256, -- 256 24 | } 25 | 26 | 27 | -- Event Functions -- 28 | -- ======================================================= -- 29 | 30 | --- Various action when new player joins in game 31 | --- @param event defines.events.on_player_created event 32 | function PlayerInit.on_player_created(event) 33 | local player = game.players[event.player_index] 34 | PlayerInit.reveal_area(player) 35 | PlayerInit.addStartingItems(player) 36 | player.print({'msg-dddgamer-intro'}) 37 | 38 | if (player.name == 'DDDGamer') then 39 | local color = Colors.red_sat 40 | player.color = color 41 | player.chat_color = color 42 | end 43 | game.print({'mgs-new-player', player.name}) 44 | end 45 | 46 | --- Give player stuff after they respawn. 47 | --- @param event defines.events.on_player_respawned event 48 | function PlayerInit.on_player_respawned(event) 49 | local player = game.players[event.player_index] 50 | PlayerInit.addBasicItems(player) 51 | end 52 | 53 | --- Alert player left 54 | --- @param event defines.events.on_player_leave event 55 | function PlayerInit.on_player_leave(event) 56 | local player = game.players[event.player_index] 57 | game.print({"msg-player-left", player.name}) 58 | end 59 | 60 | -- Event Registration 61 | -- ======================================================= -- 62 | Event.register(defines.events.on_player_created, PlayerInit.on_player_created) 63 | Event.register(defines.events.on_player_respawned, PlayerInit.on_player_respawned) 64 | Event.register(defines.events.on_player_left_game, PlayerInit.on_player_leave) 65 | 66 | -- Helper Functions -- 67 | -- ======================================================= -- 68 | 69 | --- Give player basic items appropriate with research: gun, ammo 70 | --- @param player LuaPlayer 71 | function PlayerInit.addBasicItems(player) 72 | -- Lets avoid hoarding pistols... 73 | if (PlayerInit.is_military_1_researched(player)) then 74 | player.insert {name = 'submachine-gun', count = 1} 75 | else 76 | player.insert {name = 'pistol', count = 1} 77 | end 78 | 79 | -- Yellow ammo is useless... 80 | if (PlayerInit.is_military_2_researched(player)) then 81 | player.insert {name = 'piercing-rounds-magazine', count = 10} 82 | else 83 | player.insert {name = 'firearm-magazine', count = 10} 84 | end 85 | end 86 | 87 | --- Give player basic starting items. 88 | --- @param player LuaPlayer 89 | function PlayerInit.addStartingItems(player) 90 | -- Always start a new player with these 91 | player.insert {name = 'iron-plate', count = 10} 92 | PlayerInit.addBasicItems(player) 93 | 94 | -- Give different items depending on game time 95 | -- Ex: No need for burner miners late game 96 | if Time.tick_to_min(game.tick) < PlayerInit.AGE.NOMAD then 97 | player.insert {name = 'stone-furnace', count = 1} 98 | player.insert {name = 'burner-mining-drill', count = 3} 99 | player.insert {name = 'wooden-chest', count = 1} 100 | end 101 | end 102 | 103 | --- Reveal area around the player 104 | --- @param player LuaPlayer 105 | function PlayerInit.reveal_area(player) 106 | local pX = player.position.x; 107 | local pY = player.position.y; 108 | local r = PlayerInit.REVEAL_AREA_RADIUS; 109 | player.force.chart( 110 | player.surface, 111 | { 112 | {x = pX - r, y = pY - r}, 113 | {x = pX + r, y = pY + r} 114 | } 115 | ) 116 | end 117 | 118 | --- @param player LuaPlayer 119 | --- @return booleanTrue if steel is researched 120 | function PlayerInit.is_steel_researched(player) 121 | return player.force.technologies['steel-processing'].researched 122 | end 123 | 124 | --- @param player LuaPlayer 125 | --- @return boolean True if Military 1 is researched 126 | function PlayerInit.is_military_1_researched(player) 127 | return player.force.technologies['military'].researched 128 | end 129 | 130 | --- @param player LuaPlayer 131 | --- @return boolean True if Military 2 is researched 132 | function PlayerInit.is_military_2_researched(player) 133 | return player.force.technologies['military-2'].researched 134 | end 135 | -------------------------------------------------------------------------------- /src/modules/dddgamer/player-logging.lua: -------------------------------------------------------------------------------- 1 | -- Player Logging Soft Module 2 | -- Logs who joined/left the server 3 | -- Logs Player count when playes join/leave server 4 | -- Uses locale player-logging.cfg 5 | -- @usage require('modules/dddgamer/player-logging') 6 | -- ------------------------------------------------------- -- 7 | -- @author Denis Zholob (DDDGamer) 8 | -- github: https://github.com/deniszholob/factorio-softmod-pack 9 | -- ======================================================= -- 10 | 11 | -- Dependencies -- 12 | -- ======================================================= -- 13 | local Time = require('util/Time') 14 | require('stdlib/string') 15 | 16 | -- Constants -- 17 | -- ======================================================= -- 18 | PlayerLogging = { 19 | LOG_FILE_NAME = 'player-log.log', 20 | LOG_FILE_INDEX = 0 -- change to 1 for SP/local testing, 0 for servers 21 | } 22 | 23 | --- On player join log player name 24 | --- @param event defines.events.on_player_joined_game 25 | function PlayerLogging.on_player_join(event) 26 | local player = game.players[event.player_index] 27 | -- local time_str = os.date('%I:M:%S %p', os.time()) 28 | -- local text = '(' .. #game.connected_players .. ') "'.. player.name .. '"' 29 | -- local text = '"'.. player.name .. '"' .. ' (' .. #game.connected_players .. ')' 30 | -- PlayerLogging.logInfo('Player Join', text) 31 | PlayerLogging.logInfo('Player Join', '"' .. player.name .. '"') 32 | PlayerLogging.logInfo('Player Count', #game.connected_players) 33 | end 34 | 35 | --- On player left log player name 36 | --- @param event defines.events.on_player_joined_game 37 | function PlayerLogging.on_player_leave(event) 38 | local player = game.players[event.player_index] 39 | -- local time_str = os.date('%Y-%m-%d %I:M:%S %p', os.time()) 40 | -- PlayerLogging.logInfo('Player Left', '(' .. #game.connected_players .. ') "' .. player.name .. '"') 41 | PlayerLogging.logInfo('Player Left', '"' .. player.name .. '"') 42 | PlayerLogging.logInfo('Player Count', #game.connected_players) 43 | end 44 | 45 | --- When new player uses decon planner log it 46 | --- @param event defines.events.on_player_deconstructed_area 47 | function PlayerLogging.on_player_deconstructed_area(event) 48 | local player = game.players[event.player_index] 49 | 50 | -- Player is cancelling the decon planner 51 | if (event.alt) then 52 | return 53 | end 54 | 55 | local decon_points = { 56 | left_top_x = math.floor(event.area.left_top.x), 57 | left_top_y = math.floor(event.area.left_top.y), 58 | right_bottom_x = math.ceil(event.area.right_bottom.x), 59 | right_bottom_y = math.ceil(event.area.right_bottom.y), 60 | } 61 | 62 | local tiles_dx = decon_points.right_bottom_x - decon_points.left_top_x 63 | local tiles_dy = decon_points.right_bottom_y - decon_points.left_top_y 64 | local tiles_total = tiles_dx * tiles_dy 65 | local chunks = tiles_total / 1024 66 | 67 | local text_player = string.format('"%s"', player.name) 68 | local text_tiles = string.format(' | tiles: %d', tiles_total) 69 | local text_chunks = string.format(' | chunks: %d', chunks) 70 | local text_selection = string.format(' | selection: (%d,%d) => (%d,%d)', decon_points.left_top_x, decon_points.left_top_y, decon_points.right_bottom_x, decon_points.right_bottom_y) 71 | local text = text_player .. text_tiles .. text_chunks .. text_selection 72 | 73 | if (Time.new_player_threshold(player)) then 74 | if(chunks > 100) then 75 | game.print('WARNING! ' .. text_player .. ' deconed ' .. chunks .. ' chunks') 76 | end 77 | PlayerLogging.logWarn('Player Decon', text) 78 | else 79 | PlayerLogging.logWarn('Player Decon', text, true) 80 | end 81 | end 82 | 83 | --- When new player mines something log it 84 | --- @param event defines.events.on_player_mined_entity 85 | function PlayerLogging.on_player_mined_entity(event) 86 | local player = game.players[event.player_index] 87 | local entity = event.entity 88 | 89 | -- Simple entities we dont care about 90 | if(PlayerLogging.entityFilter(entity)) then 91 | return 92 | end 93 | 94 | local text = '"' .. player.name .. '" ("' .. entity.name .. '")' 95 | 96 | if (Time.new_player_threshold(player)) then 97 | PlayerLogging.logWarn('Player Decon', text, false) 98 | else 99 | PlayerLogging.logWarn('Player Decon', text, true) 100 | end 101 | end 102 | 103 | --- When research finishes log it and print it 104 | --- @param event defines.events.on_research_finished 105 | function PlayerLogging.on_research_finished(event) 106 | local research_name = event.research.name 107 | local notification = {'Player_Logging.research', research_name} 108 | game.print(notification) 109 | PlayerLogging.logInfo('Research Complete', '"'.. research_name .. '"') 110 | end 111 | 112 | --- Log chat 113 | --- @param event defines.events.on_console_chat 114 | function PlayerLogging.on_console_chat(event) 115 | local player = game.players[event.player_index] 116 | PlayerLogging.logChat(player.name, event.message) 117 | end 118 | 119 | --- @return boolean True if not a basic item(trees, ores, drills, etc.) 120 | function PlayerLogging.entityFilter(entity) 121 | -- game.print('filter' .. entity.name) 122 | return ( 123 | string.contains(entity.name, 'tree') or 124 | string.contains(entity.name, 'rock') or 125 | string.contains(entity.name, 'drill') or 126 | string.contains(entity.name, 'ore') or 127 | string.contains(entity.name, 'stone') or 128 | string.contains(entity.name, 'coal') 129 | ) 130 | end 131 | 132 | 133 | -- Log functions -- 134 | -- ======================================================= -- 135 | 136 | function PlayerLogging.logInfo(name, text) 137 | PlayerLogging.logEvent('INFO', name, text) 138 | end 139 | function PlayerLogging.logWarn(name, text, skip_factorio_log) 140 | PlayerLogging.logEvent('WARN', name, text, skip_factorio_log) 141 | end 142 | function PlayerLogging.logError(name, text) 143 | PlayerLogging.logEvent('ERROR', name, text) 144 | end 145 | function PlayerLogging.logChat(name, text) 146 | PlayerLogging.logEvent('CHAT', name, text, true) 147 | end 148 | function PlayerLogging.logEvent(log_type, event_name, event_text, skip_factorio_log) 149 | local time = Time.game_time_pased_string(); 150 | local log_txt = '\n=== ' .. time .. ' [' ..log_type.. '] ' .. '<' .. event_name .. '>: ' .. event_text 151 | PlayerLogging.log(log_txt, skip_factorio_log) 152 | end 153 | function PlayerLogging.log(log_txt, skip_factorio_log) 154 | if(not skip_factorio_log) then log(log_txt) end 155 | -- https://lua-api.factorio.com/latest/LuaGameScript.html#LuaGameScript.write_file 156 | game.write_file(PlayerLogging.LOG_FILE_NAME, log_txt, true, PlayerLogging.LOG_FILE_INDEX) 157 | end 158 | 159 | Event.register(defines.events.on_player_joined_game, PlayerLogging.on_player_join) 160 | Event.register(defines.events.on_player_left_game, PlayerLogging.on_player_leave) 161 | Event.register(defines.events.on_player_deconstructed_area, PlayerLogging.on_player_deconstructed_area) 162 | Event.register(defines.events.on_player_mined_entity, PlayerLogging.on_player_mined_entity) 163 | Event.register(defines.events.on_research_finished, PlayerLogging.on_research_finished) 164 | Event.register(defines.events.on_console_chat, PlayerLogging.on_console_chat) 165 | -------------------------------------------------------------------------------- /src/modules/dddgamer/spawn-starter-ores.lua: -------------------------------------------------------------------------------- 1 | -- Spawn Starter Ores Soft Module 2 | -- Spans patches of starting ores around spawn 3 | -- Uses locale __modulename__.cfg 4 | -- @usage require('modules/dddgamer/spawn-starter-ores.lua') 5 | -- ------------------------------------------------------- -- 6 | -- @author Denis Zholob (DDDGamer) 7 | -- github: https://github.com/deniszholob/factorio-softmod-pack 8 | -- ======================================================= -- 9 | 10 | -- Dependencies -- 11 | -- ======================================================= -- 12 | 13 | -- Constants -- 14 | -- ======================================================= -- 15 | 16 | -- Event Functions -- 17 | -- ======================================================= -- 18 | 19 | -- Event Registration -- 20 | -- ======================================================= -- 21 | 22 | -- Helper Functions -- 23 | -- ======================================================= -- 24 | -------------------------------------------------------------------------------- /src/modules/dev/__MODULE_NAME__.lua: -------------------------------------------------------------------------------- 1 | -- __MODULE_NAME__ Soft Module 2 | -- __Description__ 3 | -- Uses locale __MODULE_NAME__.cfg 4 | -- @usage require('modules/__folder__/__MODULE_NAME__') 5 | -- @usage local ModuleName = require('modules/__folder__/__MODULE_NAME__') 6 | -- ------------------------------------------------------- -- 7 | -- @author Denis Zholob (DDDGamer) 8 | -- github: https://github.com/deniszholob/factorio-softmod-pack 9 | -- ======================================================= -- 10 | 11 | -- Dependencies -- 12 | -- ======================================================= -- 13 | local GUI = require('stdlib/GUI') 14 | local Styles = require('util/Styles') 15 | 16 | -- Constants -- 17 | -- ======================================================= -- 18 | __MODULE_NAME__ = { 19 | MENU_BTN_NAME = 'btn_menu___MODULE_NAME__', 20 | MASTER_FRAME_NAME = 'frame___MODULE_NAME__', 21 | MASTER_FRAME_LOCATION = GUI.MASTER_FRAME_LOCATIONS.left, 22 | -- Check Factorio prototype definitions in \Factorio\data\core and \Factorio\data\base 23 | SPRITE_NAMES = { 24 | menu = 'utility/questionmark' 25 | }, 26 | get_menu_button = function(player) 27 | return GUI.menu_bar_el(player)[__MODULE_NAME__.MENU_BTN_NAME] 28 | end, 29 | get_master_frame = function(player) 30 | return GUI.master_frame_location_el(player, __MODULE_NAME__.MASTER_FRAME_LOCATION)[__MODULE_NAME__.MASTER_FRAME_NAME] 31 | end 32 | } 33 | 34 | -- Event Functions -- 35 | -- ======================================================= -- 36 | --- When new player joins add a btn to their menu bar 37 | --- Redraw this softmod's master frame (if desired) 38 | --- @param event defines.events.on_player_joined_game 39 | function __MODULE_NAME__.on_player_joined_game(event) 40 | local player = game.players[event.player_index] 41 | __MODULE_NAME__.draw_menu_btn(player) 42 | -- __MODULE_NAME__.draw_master_frame(player) -- Will appear on load, cooment out to load later on button click 43 | end 44 | 45 | --- When a player leaves clean up their GUI in case this mod gets removed or changed next time 46 | --- @param event defines.events.on_player_left_game 47 | function __MODULE_NAME__.on_player_left_game(event) 48 | local player = game.players[event.player_index] 49 | GUI.destroy_element(__MODULE_NAME__.get_menu_button(player)) 50 | GUI.destroy_element(__MODULE_NAME__.get_master_frame(player)) 51 | end 52 | 53 | --- Button Callback (On Click Event) 54 | --- @param event event factorio lua event (on_gui_click) 55 | function __MODULE_NAME__.on_gui_click_btn_menu(event) 56 | local player = game.players[event.player_index] 57 | local master_frame = __MODULE_NAME__.get_master_frame(player) 58 | 59 | if (master_frame ~= nil) then 60 | -- Call toggle if frame has been created 61 | GUI.toggle_element(master_frame) 62 | else 63 | -- Call create if it hasnt 64 | __MODULE_NAME__.draw_master_frame(player) 65 | end 66 | end 67 | 68 | -- Event Registration -- 69 | -- ======================================================= -- 70 | Event.register(defines.events.on_player_joined_game, __MODULE_NAME__.on_player_joined_game) 71 | Event.register(defines.events.on_player_left_game, __MODULE_NAME__.on_player_left_game) 72 | 73 | -- GUI Functions -- 74 | -- ======================================================= -- 75 | 76 | --- GUI Function 77 | --- Draws a button in the menubar to toggle the GUI frame on and off 78 | --- @param player LuaPlayer current player calling the function 79 | function __MODULE_NAME__.draw_menu_btn(player) 80 | local menubar_button = __MODULE_NAME__.get_menu_button(player) 81 | if menubar_button == nil then 82 | GUI.add_sprite_button( 83 | GUI.menu_bar_el(player), 84 | { 85 | type = 'sprite-button', 86 | name = __MODULE_NAME__.MENU_BTN_NAME, 87 | sprite = GUI.get_safe_sprite_name(player, __MODULE_NAME__.SPRITE_NAMES.menu), 88 | -- caption = '__MODULE_NAME__.menu_btn_caption', 89 | tooltip = {'__MODULE_NAME__.menu_btn_tooltip'} 90 | }, 91 | -- On Click callback function 92 | __MODULE_NAME__.on_gui_click_btn_menu 93 | ) 94 | end 95 | end 96 | 97 | --- GUI Function 98 | --- Creates the main/master frame where all the GUI content will go in 99 | --- @param player LuaPlayer current player calling the function 100 | function __MODULE_NAME__.draw_master_frame(player) 101 | local master_frame = __MODULE_NAME__.get_master_frame(player) 102 | 103 | if (master_frame == nil) then 104 | master_frame = 105 | GUI.master_frame_location_el(player, __MODULE_NAME__.MASTER_FRAME_LOCATION).add( 106 | { 107 | type = 'frame', 108 | name = __MODULE_NAME__.MASTER_FRAME_NAME, 109 | direction = 'vertical', 110 | caption = {'__MODULE_NAME__.master_frame_caption'} 111 | } 112 | ) 113 | GUI.element_apply_style(master_frame, Styles.frm_window) 114 | 115 | __MODULE_NAME__.fill_master_frame(master_frame, player) 116 | end 117 | end 118 | 119 | --- GUI Function 120 | --- @param container LuaGuiElement parent container to add GUI elements to 121 | --- @param player LuaPlayer current player calling the function 122 | function __MODULE_NAME__.fill_master_frame(container, player) 123 | -- Your code here... 124 | local lbl_test = 125 | container.add( 126 | { 127 | type = 'label', 128 | caption = {'__MODULE_NAME__.lbl_test'} 129 | } 130 | ) 131 | end 132 | 133 | -- Logic Functions -- 134 | -- ======================================================= -- 135 | -------------------------------------------------------------------------------- /src/modules/dev/color_list.lua: -------------------------------------------------------------------------------- 1 | -- Color_List Soft Module 2 | -- Shows a list of all the colors in the Colors.lua file 3 | -- @usage require('modules/dev/color_list') 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | 9 | -- Dependencies -- 10 | -- ======================================================= -- 11 | local GUI = require('stdlib/GUI') 12 | local Styles = require('util/Styles') 13 | local Colors = require('util/Colors') 14 | 15 | -- Constants -- 16 | -- ======================================================= -- 17 | Color_List = { 18 | MENU_BTN_NAME = 'btn_menu_Color_List', 19 | MASTER_FRAME_NAME = 'frame_Color_List', 20 | MASTER_FRAME_LOCATION = GUI.MASTER_FRAME_LOCATIONS.left, 21 | -- Check Factorio prototype definitions in \Factorio\data\core and \Factorio\data\base 22 | SPRITE_NAMES = { 23 | menu = 'utility/color_effect' 24 | }, 25 | get_menu_button = function(player) 26 | return GUI.menu_bar_el(player)[Color_List.MENU_BTN_NAME] 27 | end, 28 | get_master_frame = function(player) 29 | return GUI.master_frame_location_el(player, Color_List.MASTER_FRAME_LOCATION)[Color_List.MASTER_FRAME_NAME] 30 | end 31 | } 32 | 33 | -- Event Functions -- 34 | -- ======================================================= -- 35 | --- When new player joins add a btn to their menu bar 36 | --- Redraw this softmod's master frame (if desired) 37 | --- @param event defines.events.on_player_joined_game 38 | function Color_List.on_player_joined_game(event) 39 | local player = game.players[event.player_index] 40 | Color_List.draw_menu_btn(player) 41 | Color_List.draw_master_frame(player) -- Will appear on load, cooment out to load later on button click 42 | end 43 | 44 | --- When a player leaves clean up their GUI in case this mod gets removed or changed next time 45 | --- @param event defines.events.on_player_left_game 46 | function Color_List.on_player_left_game(event) 47 | local player = game.players[event.player_index] 48 | GUI.destroy_element(Color_List.get_menu_button(player)) 49 | GUI.destroy_element(Color_List.get_master_frame(player)) 50 | end 51 | 52 | --- Button Callback (On Click Event) 53 | --- @param event event factorio lua event (on_gui_click) 54 | function Color_List.on_gui_click_btn_menu(event) 55 | local player = game.players[event.player_index] 56 | local master_frame = Color_List.get_master_frame(player) 57 | 58 | if (master_frame ~= nil) then 59 | -- Call toggle if frame has been created 60 | GUI.toggle_element(master_frame) 61 | else 62 | -- Call create if it hasnt 63 | Color_List.draw_master_frame(player) 64 | end 65 | end 66 | 67 | -- Event Registration -- 68 | -- ======================================================= -- 69 | Event.register(defines.events.on_player_joined_game, Color_List.on_player_joined_game) 70 | Event.register(defines.events.on_player_left_game, Color_List.on_player_left_game) 71 | 72 | -- GUI Functions -- 73 | -- ======================================================= -- 74 | 75 | --- GUI Function 76 | --- Draws a button in the menubar to toggle the GUI frame on and off 77 | --- @param player LuaPlayer current player calling the function 78 | function Color_List.draw_menu_btn(player) 79 | local menubar_button = Color_List.get_menu_button(player) 80 | if menubar_button == nil then 81 | GUI.add_sprite_button( 82 | GUI.menu_bar_el(player), 83 | { 84 | type = 'sprite-button', 85 | name = Color_List.MENU_BTN_NAME, 86 | sprite = GUI.get_safe_sprite_name(player, Color_List.SPRITE_NAMES.menu), 87 | tooltip = 'Show Colors' 88 | }, 89 | -- On Click callback function 90 | Color_List.on_gui_click_btn_menu 91 | ) 92 | end 93 | end 94 | 95 | --- GUI Function 96 | --- Creates the main/master frame where all the GUI content will go in 97 | --- @param player LuaPlayer current player calling the function 98 | function Color_List.draw_master_frame(player) 99 | local master_frame = Color_List.get_master_frame(player) 100 | 101 | if (master_frame == nil) then 102 | master_frame = 103 | GUI.master_frame_location_el(player, Color_List.MASTER_FRAME_LOCATION).add( 104 | { 105 | type = 'frame', 106 | name = Color_List.MASTER_FRAME_NAME, 107 | direction = 'vertical', 108 | caption = 'Colors' 109 | } 110 | ) 111 | GUI.element_apply_style(master_frame, Styles.frm_window) 112 | 113 | Color_List.fill_master_frame(master_frame, player) 114 | end 115 | end 116 | 117 | --- GUI Function 118 | --- @param container LuaGuiElement parent container to add GUI elements to 119 | --- @param player LuaPlayer current player calling the function 120 | function Color_List.fill_master_frame(container, player) 121 | local scroll_pane = 122 | container.add( 123 | { 124 | type = 'scroll-pane', 125 | name = 'scroll_content', 126 | direction = 'vertical', 127 | vertical_scroll_policy = 'auto', 128 | horizontal_scroll_policy = 'never' 129 | } 130 | ) 131 | for i, color in pairs(Colors) do 132 | scroll_pane.add({type = 'label', caption = i}).style.font_color = color 133 | end 134 | end 135 | 136 | -- Logic Functions -- 137 | -- ======================================================= -- 138 | -------------------------------------------------------------------------------- /src/modules/dev/sandbox.lua: -------------------------------------------------------------------------------- 1 | -- For Testing Soft Module 2 | -- Gives player a bunch of items on creation for testing 3 | -- TODO: Change to chests? 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | 9 | -- Dependencies -- 10 | -- ======================================================= -- 11 | 12 | -- Constants -- 13 | -- ======================================================= -- 14 | DevSandbox = {} 15 | 16 | -- Event Functions -- 17 | -- ======================================================= -- 18 | --- Various action when new player joins in game 19 | --- @param event defines.events.on_player_created event 20 | function DevSandbox.on_player_created(event) 21 | local player = game.players[event.player_index] 22 | player.print('Testing Script, player recieves a buncha items!') 23 | 24 | DevSandbox.unlockTech(player) 25 | 26 | DevSandbox.giveArmorMK2(player) 27 | DevSandbox.giveSolarPowerItems(player) 28 | -- DevSandbox.giveRoboItems(player) 29 | -- DevSandbox.giveMiningItems(player) 30 | -- DevSandbox.giveLogisticItems(player) 31 | -- DevSandbox.giveSpeedItems(player) 32 | -- DevSandbox.giveTrainItems(player) 33 | -- DevSandbox.giveTileItems(player) 34 | DevSandbox.giveMilitaryItems(player) 35 | -- DevSandbox.giveDefenceItems(player) 36 | end 37 | 38 | 39 | -- Event Registration -- 40 | -- ======================================================= -- 41 | Event.register(defines.events.on_player_created, DevSandbox.on_player_created) 42 | 43 | -- Helper Functions -- 44 | -- ======================================================= -- 45 | 46 | --- @param player LuaPlayer 47 | function DevSandbox.unlockTech(player) 48 | player.force.research_all_technologies() 49 | -- player.force.technologies['steel-processing'].researched = true 50 | end 51 | 52 | 53 | --- @param player LuaPlayer 54 | function DevSandbox.giveArmorMK2(player) 55 | local pia = player.get_inventory(defines.inventory.character_armor) 56 | pia.insert({name = 'power-armor-mk2', count = 1}) 57 | local armor = pia.find_item_stack('power-armor-mk2') 58 | 59 | armor.grid.put {name = 'fusion-reactor-equipment'} 60 | armor.grid.put {name = 'fusion-reactor-equipment'} 61 | armor.grid.put {name = 'battery-mk2-equipment'} 62 | armor.grid.put {name = 'battery-mk2-equipment'} 63 | armor.grid.put {name = 'exoskeleton-equipment'} 64 | armor.grid.put {name = 'exoskeleton-equipment'} 65 | armor.grid.put {name = 'exoskeleton-equipment'} 66 | armor.grid.put {name = 'exoskeleton-equipment'} 67 | armor.grid.put {name = 'exoskeleton-equipment'} 68 | armor.grid.put {name = 'exoskeleton-equipment'} 69 | -- armor.grid.put{name='energy-shield-mk2-equipment'} 70 | -- armor.grid.put{name='energy-shield-mk2-equipment'} 71 | armor.grid.put {name = 'personal-roboport-mk2-equipment'} 72 | armor.grid.put {name = 'personal-roboport-mk2-equipment'} 73 | armor.grid.put {name = 'personal-roboport-mk2-equipment'} 74 | armor.grid.put {name = 'personal-roboport-mk2-equipment'} 75 | 76 | player.insert {name = 'fusion-reactor-equipment', count = 2} 77 | player.insert {name = 'personal-roboport-mk2-equipment', count = 5} 78 | player.insert {name = 'exoskeleton-equipment', count = 5} 79 | player.insert {name = 'battery-mk2-equipment', count = 4} 80 | player.insert {name = 'construction-robot', count = 100} 81 | 82 | player.insert {name = 'deconstruction-planner', count = 1} 83 | player.insert {name = 'blueprint', count = 1} 84 | end 85 | 86 | 87 | --- @param player LuaPlayer 88 | function DevSandbox.giveRoboItems(player) 89 | player.insert {name = 'construction-robot', count = 400} 90 | player.insert {name = 'logistic-robot', count = 200} 91 | player.insert {name = 'logistic-chest-storage', count = 100} 92 | player.insert {name = 'logistic-chest-storage', count = 100} 93 | player.insert {name = 'logistic-chest-passive-provider', count = 100} 94 | player.insert {name = 'logistic-chest-buffer', count = 100} 95 | player.insert {name = 'logistic-chest-active-provider', count = 100} 96 | end 97 | 98 | 99 | --- @param player LuaPlayer 100 | function DevSandbox.giveSolarPowerItems(player) 101 | local COUNT = 1 102 | local SOLAR_BP_ITEMS = { 103 | SOLAR_PANELS = 180 * COUNT, 104 | ACCUMULATORS = 151 * COUNT, 105 | LAMPS = 4 * COUNT, 106 | ROBOPORTS = 1 * COUNT, 107 | SUBSTATIONS = 16 * COUNT 108 | } 109 | 110 | player.insert {name = 'solar-panel', count = SOLAR_BP_ITEMS.SOLAR_PANELS} 111 | player.insert {name = 'accumulator', count = SOLAR_BP_ITEMS.ACCUMULATORS} 112 | player.insert {name = 'small-lamp', count = SOLAR_BP_ITEMS.LAMPS} 113 | player.insert {name = 'roboport', count = SOLAR_BP_ITEMS.ROBOPORTS} 114 | player.insert {name = 'substation', count = SOLAR_BP_ITEMS.SUBSTATIONS} 115 | end 116 | 117 | 118 | --- @param player LuaPlayer 119 | function DevSandbox.giveMiningItems(player) 120 | player.insert {name = 'electric-mining-drill', count = 50} 121 | player.insert {name = 'medium-electric-pole', count = 50} 122 | end 123 | 124 | 125 | --- @param player LuaPlayer 126 | function DevSandbox.giveLogisticItems(player) 127 | player.insert {name = 'stack-inserter', count = 50} 128 | player.insert {name = 'express-loader', count = 50} 129 | player.insert {name = 'express-underground-belt', count = 50} 130 | player.insert {name = 'express-splitter', count = 50} 131 | player.insert {name = 'express-transport-belt', count = 400} 132 | end 133 | 134 | 135 | --- @param player LuaPlayer 136 | function DevSandbox.giveSpeedItems(player) 137 | player.insert {name = 'speed-module-3', count = 300} 138 | player.insert {name = 'productivity-module-3', count = 300} 139 | player.insert {name = 'beacon', count = 50} 140 | end 141 | 142 | 143 | --- @param player LuaPlayer 144 | function DevSandbox.giveTrainItems(player) 145 | player.insert {name = 'locomotive', count = 20} 146 | player.insert {name = 'cargo-wagon', count = 20} 147 | player.insert {name = 'fluid-wagon', count = 10} 148 | player.insert {name = 'rail', count = 400} 149 | player.insert {name = 'train-stop', count = 10} 150 | player.insert {name = 'rail-signal', count = 50} 151 | player.insert {name = 'chain-signal', count = 50} 152 | end 153 | 154 | 155 | --- @param player LuaPlayer 156 | function DevSandbox.giveTileItems(player) 157 | player.insert {name = 'stone-brick', count = 200} 158 | player.insert {name = 'concrete', count = 200} 159 | player.insert {name = 'hazard-concrete', count = 100} 160 | player.insert {name = 'refined-concrete', count = 200} 161 | player.insert {name = 'refined-hazard-concrete', count = 100} 162 | end 163 | 164 | 165 | --- @param player LuaPlayer 166 | function DevSandbox.giveMilitaryItems(player) 167 | player.insert {name = 'submachine-gun', count = 1} 168 | player.insert {name = 'uranium-rounds-magazine', count = 100} 169 | 170 | player.insert {name = 'grenade', count = 50} 171 | player.insert {name = 'cluster-grenade', count = 50} 172 | player.insert {name = 'land-mine', count = 50} 173 | 174 | player.insert {name = 'flamethrower', count = 1} 175 | player.insert {name = 'flamethrower-ammo', count = 50} 176 | 177 | player.insert {name = 'combat-shotgun', count = 1} 178 | player.insert {name = 'piercing-shotgun-shell', count = 100} 179 | 180 | player.insert {name = 'tank', count = 1} 181 | player.insert {name = 'uranium-cannon-shell', count = 50} 182 | 183 | player.insert {name = 'radar', count = 20} 184 | end 185 | 186 | 187 | --- @param player LuaPlayer 188 | function DevSandbox.giveDefenceItems(player) 189 | player.insert {name = 'stone-wall', count = 100} 190 | player.insert {name = 'gate', count = 50} 191 | 192 | player.insert {name = 'gun-turret', count = 50} 193 | player.insert {name = 'laser-turret', count = 50} 194 | player.insert {name = 'flamethrower-turret', count = 50} 195 | end 196 | 197 | -------------------------------------------------------------------------------- /src/modules/dev/spawn-rocket-silo.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | rocket_test.lua 3 | 4 | This was created to test the 'score' mod. 5 | Needed a fast way to launch a rocket in a controlled environment. 6 | This generates a space around the player which will create a silo, inserters, 7 | chests, and some related solar power to build & launch a rocket in a short time. 8 | 9 | Copyright 2017-2018 "Kovus" 10 | 11 | Redistribution and use in source and binary forms, with or without modification, 12 | are permitted provided that the following conditions are met: 13 | 14 | 1. Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 2. Redistributions in binary form must reproduce the above copyright notice, 17 | this list of conditions and the following disclaimer in the documentation and/or 18 | other materials provided with the distribution. 19 | 3. Neither the name of the copyright holder nor the names of its contributors 20 | may be used to endorse or promote products derived from this software without 21 | specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 27 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 30 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | --]] 35 | 36 | require 'util' 37 | 38 | function clearSpace() 39 | local radius = 100 40 | local surface = game.surfaces[1] 41 | local grass = get_walkable_tile() 42 | 43 | -- clear trees and landfill in start area 44 | local start_area = {left_top = {0-radius, 0-radius}, right_bottom = {radius, radius}} 45 | for _, e in pairs(surface.find_entities_filtered{area=start_area, type="tree"}) do 46 | e.destroy() 47 | end 48 | for _, e in pairs(surface.find_entities_filtered{area=start_area, type="stone-rock"}) do 49 | e.destroy() 50 | end 51 | for i = -radius, radius, 1 do 52 | for j = -radius, radius, 1 do 53 | if (surface.get_tile(i,j).collides_with("water-tile")) then 54 | surface.set_tiles{{name = grass, position = {i,j}}} 55 | end 56 | end 57 | end 58 | end 59 | 60 | function silo() 61 | local surface = game.surfaces[1] 62 | local player = game.players[1] 63 | local force = player.force 64 | 65 | local silo_location = {x = player.position.x-11, y = player.position.y} 66 | 67 | local silo = surface.create_entity{name="rocket-silo", position=silo_location, force=force} 68 | 69 | silo.get_module_inventory().insert{name='productivity-module-3', count=4} 70 | 71 | local position = {} 72 | local item 73 | -- add a couple substations 74 | position.x = silo_location.x + 8 75 | position.y = silo_location.y 76 | item = surface.create_entity{name="substation", position=position, force=force} 77 | position.x = silo_location.x + 14 78 | position.y = silo_location.y 79 | item = surface.create_entity{name="substation", position=position, force=force} 80 | 81 | -- add chests with items (3 of each type of resource) 82 | for idx=0,2 do 83 | position.x = silo_location.x+5 84 | position.y = silo_location.y-5 + idx 85 | item = surface.create_entity{name="stack-inserter", position=position, direction=defines.direction.east, force=force} 86 | position.x = silo_location.x+6 87 | position.y = silo_location.y-5 + idx 88 | item = surface.create_entity{name="steel-chest", position=position, force=force} 89 | item.insert{name='low-density-structure', count=480} 90 | end 91 | for idx=3,5 do 92 | position.x = silo_location.x+5 93 | position.y = silo_location.y-5 + idx 94 | item = surface.create_entity{name="stack-inserter", position=position, direction=defines.direction.east, force=force} 95 | position.x = silo_location.x+6 96 | position.y = silo_location.y-5 + idx 97 | item = surface.create_entity{name="steel-chest", position=position, force=force} 98 | item.insert{name='rocket-fuel', count=480} 99 | end 100 | for idx=6,8 do 101 | position.x = silo_location.x+5 102 | position.y = silo_location.y-5 + idx 103 | item = surface.create_entity{name="stack-inserter", position=position, direction=defines.direction.east, force=force} 104 | position.x = silo_location.x+6 105 | position.y = silo_location.y-5 + idx 106 | item = surface.create_entity{name="steel-chest", position=position, force=force} 107 | item.insert{name='rocket-control-unit', count=480} 108 | end 109 | for idx=9, 9 do 110 | position.x = silo_location.x+5 111 | position.y = silo_location.y-5 + idx 112 | item = surface.create_entity{name="stack-inserter", position=position, direction=defines.direction.east, force=force} 113 | position.x = silo_location.x+6 114 | position.y = silo_location.y-5 + idx 115 | item = surface.create_entity{name="steel-chest", position=position, force=force} 116 | item.insert{name='satellite', count=2} 117 | end 118 | end 119 | 120 | function solararray() 121 | local array_count = 1 122 | local surface = game.surfaces[1] 123 | local player = game.players[1] 124 | local force = player.force 125 | 126 | local array_start_location = {x = player.position.x+8, y = player.position.y-10} 127 | 128 | -- insert panels 129 | for idx = 0, 6 do 130 | for jdx = 0, 6 do 131 | if idx == 3 and jdx == 3 then 132 | -- skip this. 133 | else 134 | position = {} 135 | position.x = array_start_location.x + (3 * idx) 136 | position.y = array_start_location.y + (3 * jdx) 137 | local panel = surface.create_entity{name="solar-panel", position=position, force=force} 138 | end 139 | end 140 | end 141 | -- insert a substation in the center. 142 | position = {} 143 | position.x = array_start_location.x + 9 144 | position.y = array_start_location.y + 9 145 | local subst = surface.create_entity{name="substation", position=position, force=force} 146 | end 147 | 148 | function accarray() 149 | local array_count = 1 150 | local surface = game.surfaces[1] 151 | local player = game.players[1] 152 | local force = player.force 153 | 154 | local array_start_location = {x = player.position.x+31, y = player.position.y-10} 155 | 156 | -- insert panels 157 | for idx = 0, 8 do 158 | for jdx = 0, 8 do 159 | if idx == 4 and jdx == 4 then 160 | -- skip this. 161 | else 162 | position = {} 163 | position.x = array_start_location.x + (2 * idx) 164 | position.y = array_start_location.y + (2 * jdx) 165 | local panel = surface.create_entity{name="accumulator", position=position, force=force} 166 | end 167 | end 168 | end 169 | -- insert a substation in the center. 170 | position = {} 171 | position.x = array_start_location.x + 8 172 | position.y = array_start_location.y + 8 173 | local subst = surface.create_entity{name="substation", position=position, force=force} 174 | -- insert a substation on the left to connect it up to the solar array 175 | position = {} 176 | position.x = array_start_location.x - 2 177 | position.y = array_start_location.y + 10 178 | local subst = surface.create_entity{name="substation", position=position, force=force} 179 | end 180 | 181 | -- @return the first available walkable tile name in the prototype list (e.g. grass) 182 | function get_walkable_tile() 183 | for name, tile in pairs(game.tile_prototypes) do 184 | if tile.collision_mask['player-layer'] == nil and not tile.items_to_place_this then 185 | return name 186 | end 187 | end 188 | error('No walkable tile in prototype list') 189 | end 190 | 191 | Event.register(defines.events.on_player_joined_game, 192 | function(event) 193 | clearSpace() 194 | silo() 195 | solararray() 196 | accarray() 197 | end) 198 | 199 | -------------------------------------------------------------------------------- /src/modules/dev/sprite_list.lua: -------------------------------------------------------------------------------- 1 | -- Sprite_List Soft Module 2 | -- __Description__ 3 | -- Uses locale Sprite_List.cfg 4 | -- @usage require('modules/__folder__/Sprite_List') 5 | -- @usage local ModuleName = require('modules/__folder__/Sprite_List') 6 | -- ------------------------------------------------------- -- 7 | -- @author Denis Zholob (DDDGamer) 8 | -- github: https://github.com/deniszholob/factorio-softmod-pack 9 | -- ======================================================= -- 10 | 11 | -- Dependencies -- 12 | -- ======================================================= -- 13 | local GUI = require('stdlib/GUI') 14 | local Styles = require('util/Styles') 15 | local Sprites = require('util/Sprites') 16 | 17 | -- Constants -- 18 | -- ======================================================= -- 19 | SpriteList = { 20 | MENU_BTN_NAME = 'btn_menu_Sprite_List', 21 | MASTER_FRAME_NAME = 'frame_Sprite_List', 22 | MASTER_FRAME_LOCATION = GUI.MASTER_FRAME_LOCATIONS.left, 23 | -- Check Factorio prototype definitions in \Factorio\data\core and \Factorio\data\base 24 | SPRITE_NAMES = { 25 | menu = 'utility/train_stop_placement_indicator' 26 | }, 27 | get_menu_button = function(player) 28 | return GUI.menu_bar_el(player)[SpriteList.MENU_BTN_NAME] 29 | end, 30 | get_master_frame = function(player) 31 | return GUI.master_frame_location_el(player, SpriteList.MASTER_FRAME_LOCATION)[SpriteList.MASTER_FRAME_NAME] 32 | end 33 | } 34 | 35 | -- Event Functions -- 36 | -- ======================================================= -- 37 | --- When new player joins add a btn to their menu bar 38 | --- Redraw this softmod's master frame (if desired) 39 | --- @param event defines.events.on_player_joined_game 40 | function SpriteList.on_player_joined_game(event) 41 | local player = game.players[event.player_index] 42 | SpriteList.draw_menu_btn(player) 43 | -- Sprite_List.draw_master_frame(player) -- Will appear on load, cooment out to load later on button click 44 | end 45 | 46 | --- When a player leaves clean up their GUI in case this mod gets removed or changed next time 47 | --- @param event defines.events.on_player_left_game 48 | function SpriteList.on_player_left_game(event) 49 | local player = game.players[event.player_index] 50 | GUI.destroy_element(SpriteList.get_menu_button(player)) 51 | GUI.destroy_element(SpriteList.get_master_frame(player)) 52 | end 53 | 54 | --- Button Callback (On Click Event) 55 | --- @param event event factorio lua event (on_gui_click) 56 | function SpriteList.on_gui_click_btn_menu(event) 57 | local player = game.players[event.player_index] 58 | local master_frame = SpriteList.get_master_frame(player) 59 | 60 | if (master_frame ~= nil) then 61 | -- Call toggle if frame has been created 62 | GUI.toggle_element(master_frame) 63 | else 64 | -- Call create if it hasnt 65 | SpriteList.draw_master_frame(player) 66 | end 67 | end 68 | 69 | -- Event Registration -- 70 | -- ======================================================= -- 71 | Event.register(defines.events.on_player_joined_game, SpriteList.on_player_joined_game) 72 | Event.register(defines.events.on_player_left_game, SpriteList.on_player_left_game) 73 | 74 | -- GUI Functions -- 75 | -- ======================================================= -- 76 | 77 | -- GUI Function 78 | --- Draws a button in the menubar to toggle the GUI frame on and off 79 | --- @param player LuaPlayer current player calling the function 80 | function SpriteList.draw_menu_btn(player) 81 | local menubar_button = SpriteList.get_menu_button(player) 82 | if menubar_button == nil then 83 | GUI.add_sprite_button( 84 | GUI.menu_bar_el(player), 85 | { 86 | type = 'sprite-button', 87 | name = SpriteList.MENU_BTN_NAME, 88 | sprite = GUI.get_safe_sprite_name(player, SpriteList.SPRITE_NAMES.menu), 89 | -- caption = 'Sprite_List.menu_btn_caption', 90 | tooltip = 'List Of Sprites' 91 | }, 92 | -- On Click callback function 93 | SpriteList.on_gui_click_btn_menu 94 | ) 95 | end 96 | end 97 | 98 | --- GUI Function 99 | --- Creates the main/master frame where all the GUI content will go in 100 | --- @param player LuaPlayer current player calling the function 101 | function SpriteList.draw_master_frame(player) 102 | local master_frame = SpriteList.get_master_frame(player) 103 | 104 | if (master_frame == nil) then 105 | master_frame = 106 | GUI.master_frame_location_el(player, SpriteList.MASTER_FRAME_LOCATION).add( 107 | { 108 | type = 'frame', 109 | name = SpriteList.MASTER_FRAME_NAME, 110 | direction = 'vertical', 111 | caption = 'Sprite List' 112 | } 113 | ) 114 | GUI.element_apply_style(master_frame, Styles.frm_window) 115 | 116 | SpriteList.fill_master_frame(master_frame, player) 117 | end 118 | end 119 | 120 | --- GUI Function 121 | --- @param container LuaGuiElement parent container to add GUI elements to 122 | --- @param player LuaPlayer current player calling the function 123 | function SpriteList.fill_master_frame(container, player) 124 | local scroll_pane = 125 | container.add( 126 | { 127 | type = 'scroll-pane', 128 | name = 'scroll_content', 129 | direction = 'vertical', 130 | vertical_scroll_policy = 'auto', 131 | horizontal_scroll_policy = 'never' 132 | } 133 | ) 134 | 135 | -- Selected icons i want to view at top 136 | local icons_to_test = { 137 | Sprites.game_stopped_visualization, 138 | Sprites.crafting_machine_recipe_not_unlocked, 139 | Sprites.clear, 140 | Sprites.rail_path_not_possible, 141 | Sprites.set_bar_slot, 142 | Sprites.remove, 143 | Sprites.trash_bin, 144 | Sprites.too_far, 145 | Sprites.destroyed_icon, 146 | Sprites.color_effect, 147 | Sprites.indication_arrow, 148 | Sprites.hint_arrow_up, 149 | Sprites.hint_arrow_down, 150 | Sprites.speed_up, 151 | Sprites.speed_down, 152 | Sprites.reset, 153 | } 154 | 155 | local counter = 1 156 | while scroll_pane['flow' .. counter] do 157 | scroll_pane['flow' .. counter].destroy() 158 | counter = counter + 1 159 | end 160 | counter = 1 161 | for i, spriteStr in pairs(icons_to_test) do 162 | local flow_name = 'flow' .. math.floor(counter / 10) + 1 -- x entries per "row" 163 | local sprite_flow = scroll_pane[flow_name] 164 | if not sprite_flow then 165 | sprite_flow = scroll_pane.add({type = 'flow', name = flow_name, direction = 'horizontal'}) 166 | end 167 | local btn_sprite = sprite_flow.add({type = 'sprite-button', sprite = GUI.get_safe_sprite_name(player, spriteStr), tooltip = spriteStr}) 168 | GUI.element_apply_style(btn_sprite, Styles.small_button) 169 | counter = counter + 1 170 | end 171 | 172 | -- List all icons 173 | for i, spriteStr in pairs(Sprites) do 174 | local sprite_h_flow = scroll_pane.add({type = 'flow', direction = 'horizontal'}) 175 | sprite_h_flow.add({type = 'sprite-button', sprite = GUI.get_safe_sprite_name(player, spriteStr)}) 176 | -- sprite_h_flow.add({type = 'textfield', text = spriteStr}) -- Sprite name 177 | sprite_h_flow.add({type = 'textfield', text = i}) -- Variable name 178 | sprite_h_flow.add({type = 'sprite', sprite = GUI.get_safe_sprite_name(player, spriteStr)}) 179 | end 180 | end 181 | 182 | -- Logic Functions -- 183 | -- ======================================================= -- 184 | -------------------------------------------------------------------------------- /src/modules/vanilla/player-init.lua: -------------------------------------------------------------------------------- 1 | -- Player Init Soft Module 2 | -- Vanilla code modified with Event registration and structured more 3 | -- @usage require('modules/vanilla/player-init') 4 | -- ------------------------------------------------------- -- 5 | -- @author Factorio Devs 6 | -- @author Denis Zholob (DDDGamer) 7 | -- github: https://github.com/deniszholob/factorio-softmod-pack 8 | -- ======================================================= -- 9 | 10 | -- Event Functions -- 11 | -- ======================================================= -- 12 | 13 | -- Give player starting items. 14 | -- @param event on_player_created event 15 | function on_player_created(event) 16 | local player = game.players[event.player_index] 17 | player.insert {name = 'iron-plate', count = 8} 18 | player.insert {name = 'pistol', count = 1} 19 | player.insert {name = 'firearm-magazine', count = 10} 20 | player.insert {name = 'burner-mining-drill', count = 1} 21 | player.insert {name = 'stone-furnace', count = 1} 22 | reveal_area(player) 23 | showScenarioMsg(player) 24 | end 25 | 26 | -- Give player weapons after they respawn. 27 | -- @param event on_player_respawned event 28 | function on_player_respawned(event) 29 | local player = game.players[event.player_index] 30 | player.insert {name = 'pistol', count = 1} 31 | player.insert {name = 'firearm-magazine', count = 10} 32 | end 33 | 34 | -- Helper Functions -- 35 | -- ======================================================= -- 36 | 37 | -- Reveal area around the player 38 | -- @param player LuaPlayer 39 | function reveal_area(player) 40 | player.force.chart( 41 | player.surface, 42 | { 43 | {player.position.x - 200, player.position.y - 200}, 44 | {player.position.x + 200, player.position.y + 200} 45 | } 46 | ) 47 | end 48 | 49 | -- Shows vanilla game goal 50 | -- @param player LuaPlayer 51 | function showScenarioMsg(player) 52 | if (#game.players <= 1) then 53 | game.show_message_dialog {text = {'msg-intro'}} 54 | else 55 | player.print({'msg-intro'}) 56 | end 57 | end 58 | 59 | -- Event Registration 60 | -- ======================================================= -- 61 | Event.register(defines.events.on_player_created, on_player_created) 62 | Event.register(defines.events.on_player_respawned, on_player_respawned) 63 | -------------------------------------------------------------------------------- /src/modules/vanilla/silo.lua: -------------------------------------------------------------------------------- 1 | -- Silo Soft Module 2 | -- Vanilla code modified with Event registration and structured more 3 | -- @usage require('modules/vanilla/silo')s 4 | -- ------------------------------------------------------- -- 5 | -- @author Factorio Devs 6 | -- @author Denis Zholob (DDDGamer) 7 | -- github: https://github.com/deniszholob/factorio-softmod-pack 8 | -- ======================================================= -- 9 | 10 | -- Dependencies 11 | -- ======================================================= -- 12 | local silo_script = require('silo-script') -- this is in factorio itself 13 | 14 | -- Constants 15 | -- ======================================================= -- 16 | local version = 1 17 | 18 | -- Event Functions -- 19 | -- ======================================================= -- 20 | function on_init() 21 | global.version = version 22 | silo_script.on_init() 23 | end 24 | 25 | function on_configuration_changed(event) 26 | if global.version ~= version then 27 | global.version = version 28 | end 29 | silo_script.on_configuration_changed(event) 30 | end 31 | 32 | function on_player_created(event) 33 | silo_script.on_player_created(event) 34 | end 35 | 36 | function on_rocket_launched(event) 37 | silo_script.on_rocket_launched(event) 38 | end 39 | 40 | function on_gui_click(event) 41 | silo_script.on_gui_click(event) 42 | end 43 | 44 | silo_script.add_remote_interface() 45 | silo_script.add_commands() 46 | 47 | -- Event Registration -- 48 | -- ======================================================= -- 49 | Event.register(Event.core_events.init, on_init) 50 | Event.register(Event.core_events.configuration_changed, on_configuration_changed) 51 | Event.register(defines.events.on_player_created, on_player_created) 52 | Event.register(defines.events.on_player_created, on_rocket_launched) 53 | Event.register(defines.events.on_player_created, on_gui_click) 54 | -------------------------------------------------------------------------------- /src/stdlib/Event.lua: -------------------------------------------------------------------------------- 1 | --- Makes working with events in Factorio a lot more simple. 2 | --

By default, Factorio allows you to register **only one handler** to an event. 3 | --

This module lets you easily register **multiple handlers** to an event. 4 | --

Using this module is as simple as replacing @{LuaBootstrap.on_event|script.on_event} with @{Event.register}. 5 | --

6 | -- Due to the way that Factorio's event system works, it is not recommended to intermingle `script.on_event` and `Event.register` in a mod. 7 | --
This module hooks into Factorio's event system, and using `script.on_event` for the same event will change which events are registered. 8 | --
9 | --
10 | -- This module does not have many of the multiplayer protections that `script.on_event` does. 11 | --
Due to this, great care should be taken when registering events conditionally. 12 | --
13 | -- @module Event 14 | -- @usage require("stdlib/Event") 15 | 16 | local fail_if_missing = require "stdlib/Game"["fail_if_missing"] 17 | 18 | local function is_valid_id(event_id) 19 | if not (type(event_id) == "number" or type(event_id) == "string") then 20 | error("Invalid Event Id, Must be string or int, or array of strings and/or ints, Passed in :"..event_id, 3) 21 | end 22 | if (type(event_id) == "number" and event_id < -3) then 23 | error("event_id must be greater than -3, Passed in: "..event_id, 3) 24 | end 25 | end 26 | 27 | Event = { --luacheck: allow defined top 28 | _registry = {}, 29 | core_events = { 30 | init = -1, 31 | load = -2, 32 | configuration_changed = -3, 33 | init_and_config = {-1, -3}, 34 | _register = function(id) 35 | if id == Event.core_events.init then 36 | script.on_init( 37 | function() 38 | Event.dispatch({name = Event.core_events.init, tick = game.tick}) 39 | end 40 | ) 41 | elseif id == Event.core_events.load then 42 | script.on_load( 43 | function() 44 | Event.dispatch({name = Event.core_events.load, tick = -1}) 45 | end 46 | ) 47 | elseif id == Event.core_events.configuration_changed then 48 | script.on_configuration_changed( 49 | function(event) 50 | event.name = Event.core_events.configuration_changed 51 | event.data = event -- for backwards compatibilty 52 | Event.dispatch(event) 53 | end 54 | ) 55 | end 56 | end 57 | } 58 | } 59 | 60 | --- Registers a handler for the given events. 61 | --

Events dispatch in the order they are registered. 62 | --

An *event ID* can be obtained via @{defines.events}, 63 | -- @{LuaBootstrap.generate_event_name|script.generate_event_name} which is in @{int}, 64 | -- and can be a custom input name which is in @{string}. 65 | --

The `event_ids` parameter takes in either a single, multiple, or mixture of @{defines.events}, @{int}, and @{string}. 66 | -- @usage 67 | -- -- Create an event that prints the current tick every tick. 68 | -- Event.register(defines.events.on_tick, function(event) print event.tick end) 69 | -- -- Create an event that prints the new ID of a train. 70 | -- Event.register(Trains.on_train_id_changed, function(event) print(event.new_id) end) 71 | -- -- Function call chaining 72 | -- Event.register(event1, handler1).register(event2, handler2) 73 | -- @param event_ids (@{defines.events}, @{int}, @{string}, or {@{defines.events}, @{int}, @{string},...}) 74 | -- @tparam function handler the function to call when the given events are triggered 75 | -- @return (@{Event}) Event module object allowing for call chaining 76 | function Event.register(event_ids, handler) 77 | fail_if_missing(event_ids, "missing event_ids argument") 78 | fail_if_missing(handler, "missing handler argument") 79 | 80 | event_ids = (type(event_ids) == "table" and event_ids) or {event_ids} 81 | 82 | for _, event_id in pairs(event_ids) do 83 | is_valid_id(event_id) 84 | 85 | if not Event._registry[event_id] then 86 | Event._registry[event_id] = {} 87 | 88 | if type(event_id) == "string" or event_id >= 0 then 89 | script.on_event(event_id, Event.dispatch) 90 | elseif event_id < 0 then 91 | Event.core_events._register(event_id) 92 | end 93 | end 94 | --If the handler is already registered for this event: remove and insert it to the end. 95 | local _, reg_index = table.find(Event._registry[event_id], function(v) return v == handler end) 96 | if reg_index then 97 | table.remove(Event._registry[event_id], reg_index) 98 | log("Same handler already registered for event "..event_id..", reording it to the bottom") 99 | end 100 | table.insert(Event._registry[event_id], handler) 101 | end 102 | return Event 103 | end 104 | 105 | --- The user should create a table in this format, for a table that will be passed into @{Event.dispatch}. 106 | --

In general, the user should create an event data table that is in a similar format as the one that Factorio returns. 107 | --> The event data table **MUST** have either `name` or `input_name`. 108 | -- @tfield[opt] int|defines.events name unique event ID generated with @{LuaBootstrap.generate_event_name|script.generate_event_name} ***OR*** @{defines.events} 109 | -- @tfield[opt] string input_name custom input name of an event 110 | -- @field[opt] ... any # of additional fields with extra data, which are passed into the handler registered to an event that this table represents 111 | -- @usage 112 | -- -- below code is from Trains module. 113 | -- -- old_id & new_id are additional fields passed into the handler that's registered to Trains.on_train_id_changed event. 114 | -- local event_data = { 115 | -- old_id = renaming.old_id, 116 | -- new_id = renaming.new_id, 117 | -- name = Trains.on_train_id_changed 118 | -- } 119 | -- Event.dispatch(event_data) 120 | -- @table event_data 121 | 122 | --- Calls the handlers that are registered to the given event. 123 | --

Abort calling remaining handlers if any one of them has invalid userdata. 124 | --

Handlers are dispatched in the order they were created. 125 | -- @param event (@{event_data}) the event data table 126 | -- @see https://forums.factorio.com/viewtopic.php?t=32039#p202158 Invalid Event Objects 127 | function Event.dispatch(event) 128 | if event then 129 | local _registry = event.name and Event._registry[event.name] or event.input_name and Event._registry[event.input_name] 130 | if _registry then 131 | --add the tick if it is not present, this only affects calling Event.dispatch manually 132 | --doing the check up here as it should be faster than checking every iteration for a constant value 133 | event.tick = event.tick or _G.game and game.tick or 0 134 | 135 | local force_crc = Event.force_crc 136 | for idx, handler in ipairs(_registry) do 137 | 138 | -- Check for userdata and stop processing further handlers if not valid 139 | for _, val in pairs(event) do 140 | if type(val) == "table" and val.__self and not val.valid then 141 | return 142 | end 143 | end 144 | 145 | setmetatable(event, { __index = { _handler = handler } }) 146 | 147 | -- Call the handler 148 | local success, err = pcall(handler, event) 149 | 150 | -- If the handler errors lets make sure someone notices 151 | if not success then 152 | if _G.game and #game.connected_players > 0 then -- may be nil in on_load 153 | log(err) -- Log the error to factorio-current.log 154 | game.print(err) 155 | else -- no players received the message, force a real error so someone notices 156 | error(err) -- no way to handle errors cleanly when the game is not up 157 | end 158 | -- continue processing the remaning handlers. In most cases they won"t be related to the failed code. 159 | end 160 | 161 | -- force a crc check if option is enabled. This is a debug option and will hamper perfomance if enabled 162 | if (force_crc or event.force_crc) and _G.game then 163 | local msg = "CRC check called for event " .. event.name .. " handler #" .. idx 164 | log(msg) -- log the message to factorio-current.log 165 | game.force_crc() 166 | end 167 | 168 | -- if present stop further handlers for this event 169 | if event.stop_processing then 170 | return 171 | end 172 | end 173 | end 174 | else 175 | error("missing event argument") 176 | end 177 | end 178 | 179 | --- Removes a handler from the given events. 180 | --

When the last handler for an event is removed, stop listening to that event. 181 | --

An *event ID* can be obtained via @{defines.events}, 182 | -- @{LuaBootstrap.generate_event_name|script.generate_event_name} which is in @{int}, 183 | -- and can be a custom input name which is in @{string}. 184 | --

The `event_ids` parameter takes in either a single, multiple, or mixture of @{defines.events}, @{int}, and @{string}. 185 | -- @param event_ids (@{defines.events}, @{int}, @{string}, or {@{defines.events}, @{int}, @{string},...}) 186 | -- @tparam function handler the handler to remove 187 | -- @return (@{Event}) Event module object allowing for call chaining 188 | function Event.remove(event_ids, handler) 189 | fail_if_missing(event_ids, "missing event_ids argument") 190 | fail_if_missing(handler, "missing handler argument") 191 | 192 | event_ids = (type(event_ids) == "table" and event_ids) or {event_ids} 193 | 194 | for _, event_id in pairs(event_ids) do 195 | is_valid_id(event_id) 196 | 197 | if Event._registry[event_id] then 198 | for i = #Event._registry[event_id], 1, -1 do 199 | if Event._registry[event_id][i] == handler then 200 | table.remove(Event._registry[event_id], i) 201 | end 202 | end 203 | if table.size(Event._registry[event_id]) == 0 then 204 | Event._registry[event_id] = nil 205 | script.on_event(event_id, nil) 206 | end 207 | end 208 | end 209 | return Event 210 | end 211 | 212 | --- Removes all handlers from and stops listening to the given events. 213 | --

An *event ID* can be obtained via @{defines.events}, 214 | -- @{LuaBootstrap.generate_event_name|script.generate_event_name} which is in @{int}, 215 | -- and can be a custom input name which is in @{string}. 216 | --

The `event_ids` parameter takes in either a single, multiple, or mixture of @{defines.events}, @{int}, and @{string}. 217 | -- @param event_ids (@{defines.events}, @{int}, @{string}, or {@{defines.events}, @{int}, @{string},...}) 218 | -- @return (@{Event}) Event module object allowing for call chaining 219 | function Event.remove_all(event_ids) 220 | fail_if_missing(event_ids, "missing event_ids argument") 221 | 222 | event_ids = (type(event_ids) == "table" and event_ids) or {event_ids} 223 | 224 | for _, event_id in pairs(event_ids) do 225 | is_valid_id(event_id) 226 | 227 | Event._registry[event_id] = nil 228 | script.on_event(event_id, nil) 229 | end 230 | return Event 231 | end 232 | 233 | return Event 234 | -------------------------------------------------------------------------------- /src/stdlib/GUI.lua: -------------------------------------------------------------------------------- 1 | -- GUI Helper Module 2 | -- @module GUI 3 | -- Common GUI functions 4 | -- @usage local GUI = require('stdlib/GUI') 5 | -- ------------------------------------------------------- -- 6 | -- @author Denis Zholob (DDDGamer) 7 | -- github: https://github.com/deniszholob/factorio-softmod-pack 8 | -- ======================================================= -- 9 | 10 | -- Dependencies -- 11 | -- ======================================================= -- 12 | local mod_gui = require('mod-gui') -- From `Factorio\data\core\lualib` 13 | local GUI_Events = require("stdlib/GUI_Events") 14 | 15 | -- Constants -- 16 | -- ======================================================= -- 17 | GUI = { 18 | MASTER_FRAME_LOCATIONS = { 19 | left = 'left', -- Frame flow 20 | center = 'center', -- gui.center 21 | menu = 'menu', -- Button flow 22 | } 23 | } 24 | 25 | -- Public Functions -- 26 | -- ======================================================= -- 27 | 28 | -- Destroys the children of a GUI element 29 | -- @tparam LuaGuiElement el Element to destroy childen of 30 | function GUI.clear_element(el) 31 | if el ~= nil then 32 | for i, child_el in pairs(el.children) do 33 | child_el.destroy() 34 | end 35 | end 36 | end 37 | 38 | -- Toggles element on off (visibility) 39 | -- @tparam LuaGuiElement el Element to toggle visibility of 40 | function GUI.toggle_element(el) 41 | if el ~= nil then 42 | if (el.visible == nil) then -- game treats nil as true 43 | el.visible = true 44 | end 45 | el.visible = not el.visible or false 46 | end 47 | end 48 | 49 | -- Destroys element if exists 50 | -- @tparam LuaGuiElement el Element 51 | function GUI.destroy_element(el) 52 | if (el ~= nil) then 53 | el.destroy() 54 | end 55 | end 56 | 57 | -- Applies a style to the passed in element 58 | -- @tparam LuaGuiElement el Element 59 | -- @tparam LuaStyle style 60 | function GUI.element_apply_style(el, style) 61 | if style then 62 | for name, value in pairs(style) do 63 | if(el.style)then 64 | el.style[name] = value 65 | else 66 | error('Element doesnt have style ' .. name) 67 | end 68 | end 69 | end 70 | end 71 | 72 | -- Adds an element to the parent element 73 | -- @param Element Definition 74 | -- @tparam LuaGuiElement parent Element 75 | -- @treturn LuaGuiElement el Element 76 | function GUI.add_element(parent, el) 77 | if (parent and parent.el == nil) then 78 | return parent.add(el) 79 | else 80 | error("Parent Element is nil") 81 | end 82 | end 83 | 84 | -- Adds a button to the parent element 85 | -- @tparam LuaGuiElement parent Element 86 | -- @param el_definition element definition 87 | -- @param callback function 88 | -- @treturn LuaGuiElement el 89 | function GUI.add_button(parent, el_definition, callback) 90 | GUI.fail_on_type_mismatch(el_definition, "button") 91 | 92 | -- Create element 93 | local el = GUI.add_element(parent, el_definition) 94 | 95 | GUI.register_if_callback( 96 | callback, 97 | el_definition.name, 98 | GUI_Events.register_on_gui_click 99 | ) 100 | 101 | return el 102 | end 103 | 104 | -- Adds a sprite-button to the parent element 105 | -- @tparam LuaGuiElement parent Element 106 | -- @param el_definition element definition 107 | -- @param callback function 108 | -- @treturn LuaGuiElement el 109 | function GUI.add_sprite_button(parent, el_definition, callback) 110 | GUI.fail_on_type_mismatch(el_definition, "sprite-button") 111 | 112 | -- Create element 113 | local el = GUI.add_element(parent, el_definition) 114 | 115 | GUI.register_if_callback( 116 | callback, 117 | el_definition.name, 118 | GUI_Events.register_on_gui_click 119 | ) 120 | 121 | return el 122 | end 123 | 124 | -- Adds a checkbox to the parent element 125 | -- @tparam LuaGuiElement parent Element 126 | -- @param el_definition element definition 127 | -- @param callback function 128 | -- @treturn LuaGuiElement el 129 | function GUI.add_checkbox(parent, el_definition, callback) 130 | GUI.fail_on_type_mismatch(el_definition, "checkbox") 131 | 132 | -- Create element 133 | local el = GUI.add_element(parent, el_definition) 134 | 135 | GUI.register_if_callback( 136 | callback, 137 | el_definition.name, 138 | GUI_Events.register_on_gui_checked_state_changed 139 | ) 140 | 141 | return el 142 | end 143 | 144 | -- Helper Functions -- 145 | -- ======================================================= -- 146 | 147 | -- Cant register call back without a name, fail if missing 148 | function GUI.register_if_callback(callback, name, register_function) 149 | -- Callback provided 150 | if (callback) then 151 | if (not name) then 152 | -- cant register without a name 153 | error("Element name not defined, callback not registered") 154 | return 155 | elseif (not register_function or not (type(register_function) == "function")) then 156 | -- cant register without a registration function 157 | error( 158 | "Registration function " .. 159 | serpent.block(register_function) .. 160 | " not provided or not a function, its a " .. type(register_function) 161 | ) 162 | return 163 | else 164 | -- Name exists, registration function ok -> register callback 165 | register_function(name, callback) 166 | end 167 | end 168 | end 169 | 170 | -- If types dont match, error out 171 | function GUI.fail_on_type_mismatch(el, type) 172 | if (not el.type == type) then 173 | error("Invalid element definition: element type" .. el.type .. " is not " .. type) 174 | return 175 | end 176 | end 177 | 178 | -- @tparam LuaPlayer player player who owns a gui 179 | -- @tparam string sprite_name name/path of the sprite 180 | -- @treturn string sprite_name if valid path if not a question mark sprite 181 | function GUI.get_safe_sprite_name(player, sprite_name) 182 | if not player.gui.is_valid_sprite_path(sprite_name) then 183 | sprite_name = "utility/questionmark" 184 | end 185 | return sprite_name 186 | end 187 | 188 | 189 | -- @tparam LuaPlayer player player who owns a gui 190 | function GUI.menu_bar_el(player) 191 | return mod_gui.get_button_flow(player) 192 | end 193 | 194 | -- @tparam LuaPlayer player player who owns a gui 195 | function GUI.master_frame_location_el(player, location) 196 | if(location == GUI.MASTER_FRAME_LOCATIONS.left) then 197 | return mod_gui.get_frame_flow(player) 198 | elseif(location == GUI.MASTER_FRAME_LOCATIONS.center) then 199 | return player.gui.center 200 | elseif(location == GUI.MASTER_FRAME_LOCATIONS.menu) then 201 | return mod_gui.get_button_flow(player) 202 | else 203 | error('Inalid location ' .. location) 204 | return nil 205 | end 206 | end 207 | 208 | return GUI 209 | -------------------------------------------------------------------------------- /src/stdlib/GUI_Events.lua: -------------------------------------------------------------------------------- 1 | -- GUI Events Soft Module 2 | -- Handles registration/dispatch of GUI clicks, etc... 3 | -- @usage local ModuleName = require('stdlib/GUI_Events') 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | 9 | -- Dependencies -- 10 | -- ======================================================= -- 11 | 12 | -- Constants -- 13 | -- ======================================================= -- 14 | GUI_Events = {} 15 | 16 | -- Event Functions -- 17 | -- ======================================================= -- 18 | 19 | -- @param event any gui event 20 | -- @param type event type string 21 | function GUI_Events.call_handler(event, event_type) 22 | if not (event and event.element and event.element.valid) then 23 | return 24 | end 25 | 26 | if 27 | (event_type and 28 | (event_type == "on_gui_click" or event_type == "on_gui_checked_state_changed" or 29 | event_type == "on_gui_selection_state_changed")) 30 | then 31 | local config = GUI_Events.getConfig() 32 | local callback = config.callbacks[event_type][event.element.name] 33 | 34 | if callback then 35 | callback(event) 36 | -- else 37 | -- Callback not found -> either error in programming, 38 | -- or simply that event not using the GUI_Events registration 39 | -- game.print("DEBUG: Callback for '" .. event_type .. " | " .. event.element.name .. "' is not registered.") 40 | -- game.print("DEBUG: " .. serpent.block(callback)) 41 | end 42 | end 43 | end 44 | 45 | -- Event Registration -- 46 | -- ======================================================= -- 47 | Event.register( 48 | defines.events.on_gui_click, 49 | function(event) 50 | GUI_Events.call_handler(event, "on_gui_click") 51 | end 52 | ) 53 | Event.register( 54 | defines.events.on_gui_selection_state_changed, 55 | function(event) 56 | GUI_Events.call_handler(event, "on_gui_selection_state_changed") 57 | end 58 | ) 59 | Event.register( 60 | defines.events.on_gui_checked_state_changed, 61 | function(event) 62 | GUI_Events.call_handler(event, "on_gui_checked_state_changed") 63 | end 64 | ) 65 | 66 | -- Helper Functions -- 67 | -- ======================================================= -- 68 | 69 | -- Registers a callback function to be called on_gui_click event 70 | function GUI_Events.register_on_gui_click(el_name, callback) 71 | GUI_Events.register(el_name, callback, true, "on_gui_click") 72 | end 73 | -- Registers a callback function to be called on_gui_checked_state_changed event 74 | function GUI_Events.register_on_gui_checked_state_changed(el_name, callback) 75 | GUI_Events.register(el_name, callback, true, "on_gui_checked_state_changed") 76 | end 77 | -- Registers a callback function to be called on_gui_selection_state_changed event 78 | function GUI_Events.register_on_gui_selection_state_changed(el_name, callback) 79 | GUI_Events.register(el_name, callback, true, "on_gui_selection_state_changed") 80 | end 81 | 82 | -- Generic event registration 83 | function GUI_Events.register(el_name, callback, overwrite, event_type) 84 | -- Invalid callback provided 85 | if (not callback or not (type(callback) == "function")) then 86 | error( 87 | "Element event registration failed: callback " .. 88 | serpent.block(callback) .. " not a function, its a " .. type(callback) 89 | ) 90 | return 91 | end 92 | 93 | -- No element name provided 94 | if (not el_name) then 95 | error("Element event registration failed: name was nil!") 96 | return 97 | end 98 | 99 | if 100 | (event_type and 101 | (event_type == "on_gui_click" or event_type == "on_gui_checked_state_changed" or 102 | event_type == "on_gui_selection_state_changed")) 103 | then 104 | local config = GUI_Events.getConfig() 105 | if (config.callbacks[event_type][el_name] and not overwrite) then 106 | error("Element event registration failed: element callback already exists!") 107 | else 108 | -- game.print("DEBUG: Registered " .. event_type .. " " .. el_name) 109 | config.callbacks[event_type][el_name] = callback 110 | end 111 | end 112 | end 113 | 114 | -- Returns the module config, creates default config if doesnt exist 115 | -- @tparam LuaPlayer player 116 | function GUI_Events.getConfig() 117 | if (not global.gui_events_config) then 118 | global.gui_events_config = { 119 | callbacks = { 120 | on_gui_click = {}, 121 | on_gui_checked_state_changed = {}, 122 | on_gui_selection_state_changed = {} 123 | } 124 | } 125 | end 126 | 127 | return global.gui_events_config 128 | end 129 | 130 | return GUI_Events 131 | -------------------------------------------------------------------------------- /src/stdlib/Game.lua: -------------------------------------------------------------------------------- 1 | --- The game module. 2 | -- @module Game 3 | -- @usage local Game = require('stdlib/Game') 4 | 5 | Game = {} 6 | 7 | --- Print msg if specified var evaluates to false. 8 | -- @tparam Mixed var variable to evaluate 9 | -- @tparam[opt="missing value"] string msg message 10 | function Game.fail_if_missing(var, msg) 11 | if not var then 12 | error((msg .. var) or "Missing value", 3) 13 | end 14 | return false 15 | end 16 | 17 | return Game 18 | -------------------------------------------------------------------------------- /src/stdlib/string.lua: -------------------------------------------------------------------------------- 1 | --- Extends Lua 5.2 string. 2 | -- @module string 3 | -- @see string 4 | -- @usage require('stdlib/string') 5 | 6 | -- luacheck: globals string (Allow mutating string) 7 | 8 | --- Returns a copy of the string with any leading or trailing whitespace from the string removed. 9 | -- @tparam string s the string to remove leading or trailing whitespace from 10 | -- @treturn string a copy of the string without leading or trailing whitespace 11 | function string.trim(s) 12 | return (s:gsub("^%s*(.-)%s*$", "%1")) 13 | end 14 | 15 | --- Tests if a string starts with a given substring. 16 | -- @tparam string s the string to check for the start substring 17 | -- @tparam string start the substring to test for 18 | -- @treturn boolean true if the start substring was found in the string 19 | function string.starts_with(s, start) 20 | return string.find(s, start, 1, true) == 1 21 | end 22 | 23 | --- Tests if a string ends with a given substring. 24 | -- @tparam string s the string to check for the end substring 25 | -- @tparam string ends the substring to test for 26 | -- @treturn boolean true if the end substring was found in the string 27 | function string.ends_with(s, ends) 28 | return #s >= #ends and string.find(s, ends, #s - #ends + 1, true) and true or false 29 | end 30 | 31 | --- Tests if a string contains a given substring. 32 | -- @tparam string s the string to check for the substring 33 | -- @tparam string contains the substring to test for 34 | -- @treturn boolean true if the substring was found in the string 35 | function string.contains(s, contains) 36 | return s and string.find(s, contains) ~= nil 37 | end 38 | 39 | --- Tests whether a string is empty. 40 | -- @tparam string s the string to test 41 | -- @treturn boolean true if the string is empty 42 | function string.is_empty(s) 43 | return s == nil or s == '' 44 | end 45 | 46 | --- Splits a string into an array. 47 | -- *Note:* Empty split substrings are not included in the resulting table. 48 | --

For example, `string.split("foo.bar...", ".", false)` results in the table `{"foo", "bar"}`. 49 | -- @tparam string s the string to split 50 | -- @tparam[opt="."] string sep the separator to use. 51 | -- @tparam[opt=false] boolean pattern whether to interpret the separator as a lua pattern or plaintext for the string split 52 | -- @treturn {string,...} an array of strings 53 | function string.split(s, sep, pattern) 54 | sep = sep or "." 55 | sep = sep ~= "" and sep or "." 56 | sep = not pattern and string.gsub(sep, "([^%w])", "%%%1") or sep 57 | 58 | local fields = {} 59 | local start_idx, end_idx = string.find(s, sep) 60 | local last_find = 1 61 | while start_idx do 62 | local substr = string.sub(s, last_find, start_idx - 1) 63 | if string.len(substr) > 0 then 64 | table.insert(fields, string.sub(s, last_find, start_idx - 1)) 65 | end 66 | last_find = end_idx + 1 67 | start_idx, end_idx = string.find(s, sep, end_idx + 1) 68 | end 69 | local substr = string.sub(s, last_find) 70 | if string.len(substr) > 0 then 71 | table.insert(fields, string.sub(s, last_find)) 72 | end 73 | return fields 74 | end 75 | -------------------------------------------------------------------------------- /src/util/Colors.lua: -------------------------------------------------------------------------------- 1 | -- Colors Module 2 | -- Collection of common colors 3 | -- @usage local Colors = require('util/Colors') 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | 9 | Colors = { 10 | black = { r=0, g=0, b=0 }, 11 | darkgrey = { r=65, g=65, b=65 }, 12 | grey = { r=130, g=130, b=130 }, 13 | lightgrey = { r=190, g=190, b=190 }, 14 | white = { r=255, g=255, b=255 }, 15 | 16 | darkgreen = { r=0, g=130, b=0 }, 17 | green = {r=25, g=255, b=51 }, 18 | lightgreen = { r=130, g=255, b=130 }, 19 | 20 | cyan = { r=20, g=220, b=190 }, 21 | 22 | darkblue = { r=30, g=30, b=180 }, 23 | blue = { r=30, g=130, b=255 }, 24 | lightblue = { r=60, g=180, b=255 }, 25 | 26 | darkpurple = { r=160, g=50, b=255 }, 27 | purple = { r=179, g=102, b=255 }, 28 | violet = { r=130, g=130, b=255 }, 29 | 30 | pink = { r=255, g=0, b=255 }, 31 | lightpink = { r=255, g=160, b=255 }, 32 | salmon = { r=255, g=90, b=200 }, 33 | 34 | darkred = { r=160, g=0, b=0 }, 35 | red_sat = { r=255, g=0, b=25 }, 36 | red = { r=255, g=50, b=50 }, 37 | text_red = { r=230, g=39, b=0 }, 38 | lightred = { r=255, g=130, b=120 }, 39 | 40 | darkorange = { r=242, g=70, b=13 }, 41 | orange = { r=255, g=140, b=25 }, 42 | text_orange = { r=194, g=84, b=0 }, 43 | yellow = { r=255, g=255, b=0 }, 44 | lightyellow = { r=255, g=255, b=120 }, 45 | brown = { r=0.6, g=0.4, b=0.1 }, 46 | } 47 | 48 | return Colors 49 | -------------------------------------------------------------------------------- /src/util/Math.lua: -------------------------------------------------------------------------------- 1 | -- Math Helper Module 2 | -- Common Math functions 3 | -- @usage local Math = require('util/Math') 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | 9 | Math = {} 10 | 11 | -- Rounding function 12 | -- Example Math.round(11.11111, 1) = 11.1 13 | -- @param number - decimal number to round 14 | -- @param precision - amount of decimal point to round to 15 | function Math.round(number, precision) 16 | return math.floor(number * math.pow(10, precision) + 0.5) / math.pow(10, precision) 17 | end 18 | 19 | -- Function for line generation 20 | -- TODO: Doesn't always do diagonals 21 | -- @see: https://iq.opengenus.org/bresenham-line-drawining-algorithm/ 22 | function Math.bresenhamLine(pointStart, pointEnd) 23 | local locations = {} 24 | 25 | local x1 = pointStart.x 26 | local y1 = pointStart.y 27 | local x2 = pointEnd.x 28 | local y2 = pointEnd.y 29 | 30 | if(x2 < x1) then 31 | local xTemp = x1 32 | local yTemp = y1 33 | x1 = x2 34 | y1 = y2 35 | x2 = xTemp 36 | y2 = yTemp 37 | end 38 | 39 | 40 | if(x2 == x1) then 41 | if(y2 < y1) then 42 | local xTemp = x1 43 | local yTemp = y1 44 | x1 = x2 45 | y1 = y2 46 | x2 = xTemp 47 | y2 = yTemp 48 | end 49 | end 50 | 51 | 52 | local dx = x2 - x1 53 | local dy = y2 - y1 54 | 55 | local x = x1 56 | local y = y1 57 | 58 | if(dx > dy) then 59 | table.insert(locations, {x, y}) 60 | local m = 2 * dy - dx 61 | 62 | for i = 1, dx do 63 | x = x + 1 64 | if(m < 0) then 65 | m = m + 2 * dy 66 | else 67 | y = y + 1 68 | m = m + 2*dy - 2*dx 69 | end 70 | table.insert(locations, {x, y}) 71 | end 72 | else 73 | table.insert(locations, {x, y}) 74 | local m = 2 * dx - dy 75 | 76 | for i = 1, dy do 77 | y = y + 1 78 | if(m < 0) then 79 | m = m + 2 * dx 80 | else 81 | x = x + 1 82 | m = m + 2*dx - 2*dy 83 | end 84 | table.insert(locations, {x, y}) 85 | end 86 | end 87 | return locations 88 | end 89 | 90 | 91 | 92 | -- Function for line generation 93 | -- function Math.bresenhamLine1(pointStart, pointEnd) 94 | -- local locations = {} 95 | 96 | -- local x1 = pointStart.x 97 | -- local y1 = pointStart.y 98 | -- local x2 = pointEnd.x 99 | -- local y2 = pointEnd.y 100 | 101 | -- local dx = x2 - x1 102 | -- local dy = y2 - y1 103 | 104 | -- local x = x1 105 | -- local y - y1 106 | 107 | 108 | -- if(x2 < x1) then 109 | -- local xTemp = x1 110 | -- local yTemp = y1 111 | -- x1 = x2 112 | -- y1 = y2 113 | -- x2 = xTemp 114 | -- y2 = yTemp 115 | -- end 116 | 117 | -- local m = 2 * (y2 - y1) 118 | -- local err = m - (x2 - x1) 119 | 120 | -- local y = y1 121 | -- for x = x1, x2, 1 do 122 | -- -- Add slope to increment angle formed 123 | -- err = err + m 124 | -- -- Slope error reached limit, time to increment y and update slope error. 125 | -- if(err >= 0) then 126 | -- y = y + 1 127 | -- err = err - 2 * (x2 - x1) 128 | -- end 129 | -- table.insert(locations, {x, y}) 130 | -- end 131 | -- return locations 132 | -- end 133 | 134 | -- function Math.locationsLine(pointStart, pointEnd) 135 | -- game.print("x1, y1, x2, y2") 136 | -- game.print(pointStart) 137 | -- game.print(pointEnd) 138 | -- local locations = {} 139 | 140 | -- local x1 = pointStart.x 141 | -- local y1 = pointStart.y 142 | -- local x2 = pointEnd.x 143 | -- local y2 = pointEnd.y 144 | 145 | -- game.print(string.format("dx, dy, m, d")) 146 | -- local dx = x2 - x1 147 | -- game.print(string.format("dx: %d", dx)) 148 | -- local dy = y2 - y1 149 | -- game.print(string.format("dy: %d", dy)) 150 | 151 | -- if(dx == 0) do 152 | -- for x = xLow, xHigh, 1 do 153 | -- local y = m * x + b 154 | -- table.insert(locations, {x, y}) 155 | -- end 156 | -- else 157 | -- local m = dy / dx 158 | -- game.print(string.format("m: %d", m)) 159 | -- local b = y1 - m * x1 160 | -- game.print(string.format("b: %d", b)) 161 | 162 | -- local xLow = x1 163 | -- local xHigh = x2 164 | 165 | -- if(x2 < x1) then 166 | -- xlow = x2 167 | -- xHigh = x1 168 | -- end 169 | 170 | -- for x = xLow, xHigh, 1 do 171 | -- local y = m * x + b 172 | -- table.insert(locations, {x, y}) 173 | -- end 174 | -- end 175 | -- return locations 176 | -- end 177 | 178 | 179 | return Math 180 | -------------------------------------------------------------------------------- /src/util/Styles.lua: -------------------------------------------------------------------------------- 1 | -- Styles Soft Module 2 | -- Collection of common styles 3 | -- @usage local Styles = require('util/Styles') 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | 9 | -- Dependencies -- 10 | -- ======================================================= -- 11 | -- local Colors = require('util/Colors') 12 | 13 | -- Constants -- 14 | -- ======================================================= -- 15 | 16 | Styles = { 17 | btn_menu = { 18 | padding = 0, 19 | margin = 0, 20 | height = 38, 21 | }, 22 | btn_menu_lbl = { 23 | font = 'default-bold', 24 | padding = 5, 25 | }, 26 | -- Match label size, etc.. the style of sprite buttons 27 | lbl_menu = { 28 | font = 'default-bold', 29 | top_padding = 1, 30 | -- bottom_padding = 0, 31 | -- left_padding = 4, 32 | -- right_padding = 4, 33 | }, 34 | frm_menu = { 35 | -- top_padding = 0, 36 | -- bottom_padding = 0, 37 | -- left_padding = 0, 38 | -- right_padding = 0, 39 | -- height = 24, 40 | height = 38, 41 | }, 42 | frm_menu_no_pad = { 43 | padding = 0, 44 | margin = 0, 45 | height = 38, 46 | }, 47 | clear_padding_margin = { 48 | padding = 0, 49 | margin = 0, 50 | }, 51 | frm_window = { 52 | maximal_height = 650, 53 | minimal_width = 200 54 | }, 55 | small_button = { 56 | width = 24, 57 | height = 24, 58 | top_padding = 0, 59 | right_padding = 0, 60 | bottom_padding = 0, 61 | left_padding = 0, 62 | }, 63 | small_symbol_button = { 64 | width = 24, 65 | height = 24, 66 | top_padding = 0, 67 | right_padding = 0, 68 | bottom_padding = 0, 69 | left_padding = 0, 70 | font = 'default-listbox', 71 | }, 72 | txt_clr_yellow = { 73 | font_color = Colors.yellow, 74 | }, 75 | txt_clr_orange = { 76 | font_color = Colors.orange, 77 | }, 78 | txt_clr_blue = { 79 | font_color = Colors.lightblue, 80 | }, 81 | txt_clr_red = { 82 | font_color = Colors.red, 83 | }, 84 | txt_clr_green = { 85 | font_color = Colors.green, 86 | }, 87 | txt_clr_disabled = { 88 | font_color = Colors.darkgrey, 89 | }, 90 | 91 | } 92 | 93 | return Styles 94 | -------------------------------------------------------------------------------- /src/util/Time.lua: -------------------------------------------------------------------------------- 1 | -- Time Helper Module 2 | -- Common Time functions 3 | -- @usage local Time = require('util/Time') 4 | -- ------------------------------------------------------- -- 5 | -- @author Denis Zholob (DDDGamer) 6 | -- github: https://github.com/deniszholob/factorio-softmod-pack 7 | -- ======================================================= -- 8 | 9 | Time = { 10 | NEW_PLAYER_TIME = 30, -- minutes 11 | NEW_PLAYER_GAME_TIME = 8 -- hrs 12 | } 13 | 14 | -- Returns hours converted from game ticks 15 | -- @param t - Factorio game tick 16 | function Time.tick_to_day(t) 17 | return Time.tick_to_hour(t) / 24 18 | end 19 | 20 | -- Returns hours converted from game ticks 21 | -- @param t - Factorio game tick 22 | function Time.tick_to_hour(t) 23 | return Time.tick_to_sec(t) / 3600 24 | end 25 | 26 | -- Returns minutes converted from game ticks 27 | -- @param t - Factorio game tick 28 | function Time.tick_to_min(t) 29 | return Time.tick_to_sec(t) / 60 30 | end 31 | 32 | -- Returns seconds converted from game ticks 33 | -- @param t - Factorio game tick 34 | function Time.tick_to_sec(t) 35 | -- return game.speed * (t / 60) 36 | return (t / 60) 37 | end 38 | 39 | -- Returns a time string in h:m:s format 40 | -- @param t - Factorio game tick 41 | -- @return hms object 42 | function Time.tick_to_time_hms(t) 43 | local total_sec = Time.tick_to_sec(t) 44 | return { 45 | h = math.floor(total_sec / 3600), 46 | m = math.floor(total_sec % 3600 / 60), 47 | s = math.floor(total_sec % 60) 48 | } 49 | end 50 | 51 | -- Returns a time object representing time passed in game 52 | -- @return hms object 53 | function Time.game_time_pased() 54 | return Time.tick_to_time_hms(game.tick) 55 | end 56 | 57 | -- Returns formatted time string in hhh:mm:ss format representing time passed in game 58 | -- @return hms string 59 | function Time.game_time_pased_string() 60 | local tms = Time.game_time_pased() 61 | return string.format('%03d:%02d:%02d', tms.h, tms.m, tms.s) 62 | end 63 | 64 | -- Potential griefers are new players mid/late game 65 | -- @param player LuaPLayer 66 | function Time.new_player_threshold(player) 67 | if ( 68 | not player.admin and 69 | Time.tick_to_hour(game.tick) < Time.NEW_PLAYER_GAME_TIME and 70 | Time.tick_to_min(player.online_time) < Time.NEW_PLAYER_TIME 71 | ) then 72 | return true 73 | end 74 | return false 75 | end 76 | 77 | return Time 78 | -------------------------------------------------------------------------------- /tools/console-lua-commands.md: -------------------------------------------------------------------------------- 1 | ```lua 2 | 3 | -- Reveal Map 4 | /c 5 | game.players[1].force.chart( 6 | game.players[1].surface, 7 | { 8 | {game.players[1].position.x - 300, game.players[1].position.y - 300}, 9 | {game.players[1].position.x + 300, game.players[1].position.y + 300} 10 | } 11 | ) 12 | 13 | -- Set enemy evolution 14 | /c 15 | game.forces["enemy"].evolution_factor=0.5 16 | 17 | -- Print technologies 18 | /c 19 | for i, tech in pairs(game.players[1].force.technologies) do 20 | game.print(tech) 21 | end 22 | 23 | -- Write techs to a file 24 | /c local list = {} 25 | for _, tech in pairs(game.player.force.technologies) do 26 | if tech.research_unit_count_formula then 27 | list[#list+1] = tech.name .. '\t|\t' .. tech.level .. '\t|\t' .. tech.research_unit_count .. '\t|\t' .. tech.research_unit_count_formula .. '\t|\t' .. tech.research_unit_energy 28 | end 29 | end 30 | game.write_file("techs.lua", serpent.block(list) .. "\n", true) 31 | 32 | -- Unlock tech research 33 | /c 34 | game.players[1].force.technologies['mining-productivity-16'].researched=true 35 | 36 | -- Print research ingredients 37 | /c 38 | game.print(serpent.block(game.players[1].force.technologies['mining-productivity-16'].research_unit_ingredients)) 39 | 40 | 41 | -- Set current research 42 | /c game.players[1].force.current_research = "mining-productivity-16" 43 | 44 | 45 | ``` 46 | -------------------------------------------------------------------------------- /tools/copy-local.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Usage: bash tools/copy-local.sh 3 | # Be carefull about editing in factorio folder, as this will overwrite anything there 4 | 5 | FACTORIO_DIR="$APPDATA/Factorio/scenarios" 6 | RELEASE_FILE_NAME="dddgamer-softmod-pack-dev" 7 | 8 | echo "===== Current dir:" 9 | pwd #output: your-path-to-this-repository/factorio-softmod-pack 10 | # ls -al 11 | 12 | echo "Remove previous contents" 13 | rm -rfv "$FACTORIO_DIR/$RELEASE_FILE_NAME" 14 | 15 | echo "===== Copy scr folder to factorio scenario folder" 16 | # Copies everything including dot files/folders 17 | cp -rfv "./src" "$FACTORIO_DIR/$RELEASE_FILE_NAME" 18 | 19 | echo "===== Copied folder contents:" 20 | ls -al "$FACTORIO_DIR/$RELEASE_FILE_NAME" 21 | -------------------------------------------------------------------------------- /tools/maps/README.md: -------------------------------------------------------------------------------- 1 | # Factorio map strings 2 | 3 | Copy and pase into the import when making a new game 4 | -------------------------------------------------------------------------------- /tools/maps/gib-test-map.txt: -------------------------------------------------------------------------------- 1 | >>>eNpjZGBkUAZiIGiwB2EOluT8xBwGhgMOILx61Sp7ruT8goLUI 2 | t38olRkYc7kotKUVN38TFTFqXmpuZW6SYnFqTATwaZmFuXnoZvAW 3 | lySn4cqUlKUmloM0XQArJG7tCgxL7M0F10vA+MEO7+zDS1yDCD8v 4 | 55B4f9/EAayHgD9AsIMjA1gkxiBYlDAJJGcn1dSlJ+jW5xaUpKZl 5 | 26VWFphlZSZWMxhoGdqAAKy6Cpy8zOLS0qLUlGVsSbnZKalMTAoO 6 | AKxE9g2RsZqkXXuD6um2DNCbNNzgDI+QEUOJMFEPGEMPwecUiowh 7 | gmSOcZg8BmJAbG0BGgFVBWHA4IBkWwBSTIy9r7duuD7sQt2jH9Wf 8 | rzkm5Rgz2joKvLug9E6O6AkO8gLTHBi1kwQ2AnzCgPMzAf2UKmb9 9 | oxnz4DAG3tGVpAOERDhYAEkDngzMzAK8AFZC3qAhIIMA8xpdjBjR 10 | BwY08DgG8wnj2GMy/bo/gAGhA3IcDkQcQJEgC2Eu4wRwnTod2B0k 11 | IfJSiKUAPUbMSC7IQXhw5Mwaw8j2Y/mEMyIQPYHmoiKA5Zo4AJZm 12 | AInXjDDXQMMzwvsMJ7DfAdGZhADpOoLUAzCA8nAjILQAg7g4IbJQ 13 | tIGw+nNh2YCAGntxjg=<<< 14 | -------------------------------------------------------------------------------- /tools/templates/doc.template.lua: -------------------------------------------------------------------------------- 1 | -- __MODULE_NAME__ Soft Module 2 | -- __Description__ 3 | -- Uses locale __MODULE_NAME__.cfg 4 | -- @usage require('modules/__folder__/__MODULE_NAME__') 5 | -- @usage local ModuleName = require('modules/__folder__/__MODULE_NAME__') 6 | -- ------------------------------------------------------- -- 7 | -- @author Denis Zholob (DDDGamer) 8 | -- github: https://github.com/deniszholob/factorio-softmod-pack 9 | -- ======================================================= -- 10 | 11 | -- Dependencies -- 12 | -- ======================================================= -- 13 | 14 | -- Constants -- 15 | -- ======================================================= -- 16 | 17 | -- Event Functions -- 18 | -- ======================================================= -- 19 | 20 | -- Event Registration -- 21 | -- ======================================================= -- 22 | 23 | -- Helper Functions -- 24 | -- ======================================================= -- 25 | -------------------------------------------------------------------------------- /tools/templates/gui.template.cfg: -------------------------------------------------------------------------------- 1 | [__MODULE_NAME__] 2 | # menu_btn_caption=__MODULE_NAME__ 3 | menu_btn_tooltip=Toggle __MODULE_NAME__ on or off 4 | master_frame_caption=__MODULE_NAME__ Title 5 | 6 | lbl_test=Gui Works! 7 | -------------------------------------------------------------------------------- /tools/templates/gui.template.lua: -------------------------------------------------------------------------------- 1 | -- __MODULE_NAME__ Soft Module 2 | -- __Description__ 3 | -- Uses locale __MODULE_NAME__.cfg 4 | -- @usage require('modules/__folder__/__MODULE_NAME__') 5 | -- @usage local ModuleName = require('modules/__folder__/__MODULE_NAME__') 6 | -- ------------------------------------------------------- -- 7 | -- @author Denis Zholob (DDDGamer) 8 | -- github: https://github.com/deniszholob/factorio-softmod-pack 9 | -- ======================================================= -- 10 | 11 | -- Dependencies -- 12 | -- ======================================================= -- 13 | local GUI = require('stdlib/GUI') 14 | 15 | -- Constants -- 16 | -- ======================================================= -- 17 | __MODULE_NAME__ = { 18 | MENU_BTN_NAME = 'btn_menu___MODULE_NAME__', 19 | MASTER_FRAME_NAME = 'frame___MODULE_NAME__', 20 | MASTER_FRAME_LOCATION = GUI.MASTER_FRAME_LOCATIONS.left, 21 | -- Check Factorio prototype definitions in \Factorio\data\core and \Factorio\data\base 22 | SPRITE_NAMES = { 23 | menu = 'utility/questionmark' 24 | }, 25 | get_menu_button = function(player) 26 | return GUI.menu_bar_el(player)[__MODULE_NAME__.MENU_BTN_NAME] 27 | end, 28 | get_master_frame = function(player) 29 | return GUI.master_frame_location_el(player, __MODULE_NAME__.MASTER_FRAME_LOCATION)[__MODULE_NAME__.MASTER_FRAME_NAME] 30 | end 31 | } 32 | 33 | -- Event Functions -- 34 | -- ======================================================= -- 35 | -- When new player joins add a btn to their menu bar 36 | -- Redraw this softmod's master frame (if desired) 37 | -- @param event on_player_joined_game 38 | function __MODULE_NAME__.on_player_joined_game(event) 39 | local player = game.players[event.player_index] 40 | __MODULE_NAME__.draw_menu_btn(player) 41 | -- __MODULE_NAME__.draw_master_frame(player) -- Will appear on load, cooment out to load later on button click 42 | end 43 | 44 | -- When a player leaves clean up their GUI in case this mod gets removed or changed next time 45 | -- @param event on_player_left_game 46 | function __MODULE_NAME__.on_player_left_game(event) 47 | local player = game.players[event.player_index] 48 | GUI.destroy_element(__MODULE_NAME__.get_menu_button(player)) 49 | GUI.destroy_element(__MODULE_NAME__.get_master_frame(player)) 50 | end 51 | 52 | -- Button Callback (On Click Event) 53 | -- @param event factorio lua event (on_gui_click) 54 | function __MODULE_NAME__.on_gui_click_btn_menu(event) 55 | local player = game.players[event.player_index] 56 | local master_frame = __MODULE_NAME__.get_master_frame(player) 57 | 58 | if (master_frame ~= nil) then 59 | -- Call toggle if frame has been created 60 | GUI.toggle_element(master_frame) 61 | else 62 | -- Call create if it hasnt 63 | __MODULE_NAME__.draw_master_frame(player) 64 | end 65 | end 66 | 67 | -- Event Registration -- 68 | -- ======================================================= -- 69 | Event.register(defines.events.on_player_joined_game, __MODULE_NAME__.on_player_joined_game) 70 | Event.register(defines.events.on_player_left_game, __MODULE_NAME__.on_player_left_game) 71 | 72 | -- GUI Functions -- 73 | -- ======================================================= -- 74 | 75 | -- GUI Function 76 | -- Draws a button in the menubar to toggle the GUI frame on and off 77 | -- @tparam LuaPlayer player current player calling the function 78 | function __MODULE_NAME__.draw_menu_btn(player) 79 | local menubar_button = __MODULE_NAME__.get_menu_button(player) 80 | if menubar_button == nil then 81 | GUI.add_sprite_button( 82 | GUI.menu_bar_el(player), 83 | { 84 | type = 'sprite-button', 85 | name = __MODULE_NAME__.MENU_BTN_NAME, 86 | sprite = GUI.get_safe_sprite_name(player, __MODULE_NAME__.SPRITE_NAMES.menu), 87 | -- caption = '__MODULE_NAME__.menu_btn_caption', 88 | tooltip = {'__MODULE_NAME__.menu_btn_tooltip'} 89 | }, 90 | -- On Click callback function 91 | __MODULE_NAME__.on_gui_click_btn_menu 92 | ) 93 | end 94 | end 95 | 96 | -- GUI Function 97 | -- Creates the main/master frame where all the GUI content will go in 98 | -- @tparam LuaPlayer player current player calling the function 99 | function __MODULE_NAME__.draw_master_frame(player) 100 | local master_frame = __MODULE_NAME__.get_master_frame(player) 101 | 102 | if (master_frame == nil) then 103 | master_frame = 104 | GUI.master_frame_location_el(player, __MODULE_NAME__.MASTER_FRAME_LOCATION).add( 105 | { 106 | type = 'frame', 107 | name = __MODULE_NAME__.MASTER_FRAME_NAME, 108 | direction = 'vertical', 109 | caption = {'__MODULE_NAME__.master_frame_caption'} 110 | } 111 | ) 112 | 113 | __MODULE_NAME__.fill_master_frame(master_frame, player) 114 | end 115 | end 116 | 117 | -- GUI Function 118 | -- @tparam LuaGuiElement container parent container to add GUI elements to 119 | -- @tparam LuaPlayer player current player calling the function 120 | function __MODULE_NAME__.fill_master_frame(container, player) 121 | -- Your code here... 122 | local lbl_test = 123 | container.add( 124 | { 125 | type = 'label', 126 | caption = {'__MODULE_NAME__.lbl_test'} 127 | } 128 | ) 129 | end 130 | 131 | -- Logic Functions -- 132 | -- ======================================================= -- 133 | --------------------------------------------------------------------------------